]>
git.r.bdr.sh - rbdr/dotfiles/blob - vim/ftplugin/javascript/jslint/jslint-core.js
4 // Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // The Software shall be used for Good, not Evil.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 // WARNING: JSLint will hurt your feelings.
28 // JSLINT is a global function. It takes two parameters.
30 // var myResult = JSLINT(source, option);
32 // The first parameter is either a string or an array of strings. If it is a
33 // string, it will be split on '\n' or '\r'. If it is an array of strings, it
34 // is assumed that each string represents one line. The source can be a
35 // JavaScript text, or HTML text, or a JSON text, or a CSS text.
37 // The second parameter is an optional object of options that control the
38 // operation of JSLINT. Most of the options are booleans: They are all
39 // optional and have a default value of false. One of the options, predef,
40 // can be an array of names, which will be used to declare global variables,
41 // or an object whose keys are used as global names, with a boolean value
42 // that determines if they are assignable.
44 // If it checks out, JSLINT returns true. Otherwise, it returns false.
46 // If false, you can inspect JSLINT.errors to find out the problems.
47 // JSLINT.errors is an array of objects containing these properties:
50 // line : The line (relative to 0) at which the lint was found
51 // character : The character (relative to 0) at which the lint was found
52 // reason : The problem
53 // evidence : The text line in which the problem occurred
54 // raw : The raw message before the details were inserted
55 // a : The first detail
56 // b : The second detail
57 // c : The third detail
58 // d : The fourth detail
61 // If a stopping error was found, a null will be the last element of the
62 // JSLINT.errors array. A stopping error means that JSLint was not confident
63 // enough to continue. It does not necessarily mean that the error was
64 // especially heinous.
66 // You can request a Function Report, which shows all of the functions
67 // and the parameters and vars that they use. This can be used to find
68 // implied global variables and other problems. The report is in HTML and
69 // can be inserted in an HTML <body>.
71 // var myReport = JSLINT.report(errors_only);
73 // If errors_only is true, then the report will be limited to only errors.
75 // You can request a data structure that contains JSLint's results.
77 // var myData = JSLINT.data();
79 // It returns a structure with this form:
138 // Empty arrays will not be included.
140 // You can obtain the parse tree that JSLint constructed while parsing. The
141 // latest tree is kept in JSLINT.tree. A nice stringication can be produced
144 // JSON.stringify(JSLINT.tree, [
145 // 'string', 'arity', 'name', 'first',
146 // 'second', 'third', 'block', 'else'
149 // JSLint provides three directives. They look like slashstar comments, and
150 // allow for setting options, declaring global variables, and establishing a
151 // set of allowed property names.
153 // These directives respect function scope.
155 // The jslint directive is a special comment that can set one or more options.
156 // The current option set is
158 // anon true, if the space may be omitted in anonymous function declarations
159 // bitwise true, if bitwise operators should be allowed
160 // browser true, if the standard browser globals should be predefined
161 // cap true, if upper case HTML should be allowed
162 // 'continue' true, if the continuation statement should be tolerated
163 // css true, if CSS workarounds should be tolerated
164 // debug true, if debugger statements should be allowed
165 // devel true, if logging should be allowed (console, alert, etc.)
166 // eqeq true, if == should be allowed
167 // es5 true, if ES5 syntax should be allowed
168 // evil true, if eval should be allowed
169 // forin true, if for in statements need not filter
170 // fragment true, if HTML fragments should be allowed
171 // indent the indentation factor
172 // maxerr the maximum number of errors to allow
173 // maxlen the maximum length of a source line
174 // newcap true, if constructor names capitalization is ignored
175 // node true, if Node.js globals should be predefined
176 // nomen true, if names may have dangling _
177 // on true, if HTML event handlers should be allowed
178 // passfail true, if the scan should stop on first error
179 // plusplus true, if increment/decrement should be allowed
180 // properties true, if all property names must be declared with /*properties*/
181 // regexp true, if the . should be allowed in regexp literals
182 // rhino true, if the Rhino environment globals should be predefined
183 // undef true, if variables can be declared out of order
184 // unparam true, if unused parameters should be tolerated
185 // sloppy true, if the 'use strict'; pragma is optional
186 // sub true, if all forms of subscript notation are tolerated
187 // vars true, if multiple var statements per function should be allowed
188 // white true, if sloppy whitespace is tolerated
189 // widget true if the Yahoo Widgets globals should be predefined
190 // windows true, if MS Windows-specific globals should be predefined
195 evil: true, nomen: true, regexp: true
198 // The properties directive declares an exclusive list of property names.
199 // Any properties named in the program that are not in the list will
200 // produce a warning.
205 '\b', '\t', '\n', '\f', '\r', '!=', '!==', '"', '%', '\'', '(arguments)',
206 '(begin)', '(breakage)', '(context)', '(error)', '(identifier)', '(line)',
207 '(loopage)', '(name)', '(params)', '(scope)', '(token)', '(vars)', '(verb)',
208 '*', '+', '-', '/', '<', '<=', '==', '===', '>', '>=', ADSAFE,
209 Array, Date, Function, Object, '\\', a, a_label, a_not_allowed,
210 a_not_defined, a_scope, abbr, acronym, address, adsafe, adsafe_a,
211 adsafe_autocomplete, adsafe_bad_id, adsafe_div, adsafe_fragment, adsafe_go,
212 adsafe_html, adsafe_id, adsafe_id_go, adsafe_lib, adsafe_lib_second,
213 adsafe_missing_id, adsafe_name_a, adsafe_placement, adsafe_prefix_a,
214 adsafe_script, adsafe_source, adsafe_subscript_a, adsafe_tag, all,
215 already_defined, and, anon, applet, apply, approved, area, arity, article,
216 aside, assign, assign_exception, assignment_function_expression, at,
217 attribute_case_a, audio, autocomplete, avoid_a, b, background,
218 'background-attachment', 'background-color', 'background-image',
219 'background-position', 'background-repeat', bad_assignment, bad_color_a,
220 bad_constructor, bad_entity, bad_html, bad_id_a, bad_in_a, bad_invocation,
221 bad_name_a, bad_new, bad_number, bad_operand, bad_style, bad_type, bad_url_a,
222 bad_wrap, base, bdo, big, bitwise, block, blockquote, body, border,
223 'border-bottom', 'border-bottom-color', 'border-bottom-left-radius',
224 'border-bottom-right-radius', 'border-bottom-style', 'border-bottom-width',
225 'border-collapse', 'border-color', 'border-left', 'border-left-color',
226 'border-left-style', 'border-left-width', 'border-radius', 'border-right',
227 'border-right-color', 'border-right-style', 'border-right-width',
228 'border-spacing', 'border-style', 'border-top', 'border-top-color',
229 'border-top-left-radius', 'border-top-right-radius', 'border-top-style',
230 'border-top-width', 'border-width', bottom, br, braille, browser, button, c,
231 call, canvas, cap, caption, 'caption-side', center, charAt, charCodeAt,
232 character, cite, clear, clip, closure, cm, code, col, colgroup, color,
233 combine_var, command, conditional_assignment, confusing_a, confusing_regexp,
234 constructor_name_a, content, continue, control_a, 'counter-increment',
235 'counter-reset', create, css, cursor, d, dangerous_comment, dangling_a, data,
236 datalist, dd, debug, del, deleted, details, devel, dfn, dialog, dir,
237 direction, display, disrupt, div, dl, dt, duplicate_a, edge, edition, else,
238 em, embed, embossed, empty, 'empty-cells', empty_block, empty_case,
239 empty_class, entityify, eqeq, errors, es5, eval, evidence, evil, ex,
240 exception, exec, expected_a, expected_a_at_b_c, expected_a_b,
241 expected_a_b_from_c_d, expected_at_a, expected_attribute_a,
242 expected_attribute_value_a, expected_class_a, expected_fraction_a,
243 expected_id_a, expected_identifier_a, expected_identifier_a_reserved,
244 expected_lang_a, expected_linear_a, expected_media_a, expected_name_a,
245 expected_nonstandard_style_attribute, expected_number_a, expected_operator_a,
246 expected_percent_a, expected_positive_a, expected_pseudo_a,
247 expected_selector_a, expected_small_a, expected_space_a_b, expected_string_a,
248 expected_style_attribute, expected_style_pattern, expected_tagname_a,
249 expected_type_a, f, fieldset, figure, filter, first, flag, float, floor,
250 font, 'font-family', 'font-size', 'font-size-adjust', 'font-stretch',
251 'font-style', 'font-variant', 'font-weight', footer, forEach, for_if, forin,
252 form, fragment, frame, frameset, from, fromCharCode, fud, funct, function,
253 function_block, function_eval, function_loop, function_statement,
254 function_strict, functions, global, globals, h1, h2, h3, h4, h5, h6,
255 handheld, hasOwnProperty, head, header, height, hgroup, hr,
256 'hta:application', html, html_confusion_a, html_handlers, i, id, identifier,
257 identifier_function, iframe, img, immed, implied_evil, in, indent, indexOf,
258 infix_in, init, input, ins, insecure_a, isAlpha, isArray, isDigit, isNaN,
259 join, jslint, json, kbd, keygen, keys, label, label_a_b, labeled, lang, lbp,
260 leading_decimal_a, led, left, legend, length, 'letter-spacing', li, lib,
261 line, 'line-height', link, 'list-style', 'list-style-image',
262 'list-style-position', 'list-style-type', map, margin, 'margin-bottom',
263 'margin-left', 'margin-right', 'margin-top', mark, 'marker-offset', match,
264 'max-height', 'max-width', maxerr, maxlen, member, menu, message, meta,
265 meter, 'min-height', 'min-width', missing_a, missing_a_after_b,
266 missing_option, missing_property, missing_space_a_b, missing_url,
267 missing_use_strict, mixed, mm, mode, move_invocation, move_var, n, name,
268 name_function, nav, nested_comment, newcap, node, noframes, nomen, noscript,
269 not, not_a_constructor, not_a_defined, not_a_function, not_a_label,
270 not_a_scope, not_greater, nud, number, object, octal_a, ol, on, opacity,
271 open, optgroup, option, outer, outline, 'outline-color', 'outline-style',
272 'outline-width', output, overflow, 'overflow-x', 'overflow-y', p, padding,
273 'padding-bottom', 'padding-left', 'padding-right', 'padding-top',
274 'page-break-after', 'page-break-before', param, parameter_a_get_b,
275 parameter_arguments_a, parameter_set_a, params, paren, parent, passfail, pc,
276 plusplus, pop, position, postscript, pre, predef, print, progress,
277 projection, properties, prototype, pt, push, px, q, quote, quotes, r, radix,
278 range, raw, read_only, reason, redefinition_a, regexp, replace, report,
279 reserved, reserved_a, rhino, right, rp, rt, ruby, safe, samp, scanned_a_b,
280 screen, script, search, second, section, select, shift, slash_equal, slice,
281 sloppy, small, sort, source, span, speech, split, src, statement_block,
282 stopping, strange_loop, strict, string, strong, style, styleproperty, sub,
283 subscript, substr, sup, supplant, t, table, 'table-layout', tag_a_in_b,
284 tbody, td, test, 'text-align', 'text-decoration', 'text-indent',
285 'text-shadow', 'text-transform', textarea, tfoot, th, thead, third, thru,
286 time, title, toLowerCase, toString, toUpperCase, token, too_long, too_many,
287 top, tr, trailing_decimal_a, tree, tt, tty, tv, type, u, ul, unclosed,
288 unclosed_comment, unclosed_regexp, undef, undefined, unescaped_a,
289 unexpected_a, unexpected_char_a_b, unexpected_comment, unexpected_else,
290 unexpected_property_a, unexpected_space_a_b, 'unicode-bidi',
291 unnecessary_initialize, unnecessary_use, unparam, unreachable_a_b,
292 unrecognized_style_attribute_a, unrecognized_tag_a, unsafe, unused, url,
293 urls, use_array, use_braces, use_charAt, use_object, use_or, use_param,
294 used_before_a, var, var_a_not, vars, 'vertical-align', video, visibility,
295 was, weird_assignment, weird_condition, weird_new, weird_program,
296 weird_relation, weird_ternary, white, 'white-space', widget, width, windows,
297 'word-spacing', 'word-wrap', wrap, wrap_immediate, wrap_regexp,
298 write_is_wrong, writeable, 'z-index'
301 // The global directive is used to declare global variables that can
302 // be accessed by the program. If a declaration is true, then the variable
303 // is writeable. Otherwise, it is read-only.
305 // We build the application inside a function so that we produce only a single
306 // global variable. That function will be invoked immediately, and its return
307 // value is the JSLINT function itself. That function is also an object that
308 // can contain data and other functions.
310 var JSLINT
= (function () {
313 function array_to_object(array
, value
) {
315 // Make an object from an array of keys and a common value.
317 var i
, length
= array
.length
, object
= {};
318 for (i
= 0; i
< length
; i
+= 1) {
319 object
[array
[i
]] = value
;
325 var adsafe_id
, // The widget's ADsafe id.
326 adsafe_may
, // The widget may load approved scripts.
327 adsafe_top
, // At the top of the widget script.
328 adsafe_went
, // ADSAFE.go has been called.
364 anonname
, // The guessed name for anonymous functions.
365 approved
, // ADsafe approved urls.
367 // These are operators that should not be used with the ! operator.
385 // These are property names that should not be permitted in the safe subset.
387 banned
= array_to_object([
388 'arguments', 'callee', 'caller', 'constructor', 'eval', 'prototype',
389 'stack', 'unwatch', 'valueOf', 'watch'
391 begin
, // The root token
393 // browser contains a set of global names that are commonly provided by a
394 // web browser environment.
396 browser
= array_to_object([
397 'clearInterval', 'clearTimeout', 'document', 'event', 'frames',
398 'history', 'Image', 'localStorage', 'location', 'name', 'navigator',
399 'Option', 'parent', 'screen', 'sessionStorage', 'setInterval',
400 'setTimeout', 'Storage', 'window', 'XMLHttpRequest'
403 // bundle contains the text messages.
406 a_label: "'{a}' is a statement label.",
407 a_not_allowed: "'{a}' is not allowed.",
408 a_not_defined: "'{a}' is not defined.",
409 a_scope: "'{a}' used out of scope.",
410 adsafe_a: "ADsafe violation: '{a}'.",
411 adsafe_autocomplete: "ADsafe autocomplete violation.",
412 adsafe_bad_id: "ADSAFE violation: bad id.",
413 adsafe_div: "ADsafe violation: Wrap the widget in a div.",
414 adsafe_fragment: "ADSAFE: Use the fragment option.",
415 adsafe_go: "ADsafe violation: Misformed ADSAFE.go.",
416 adsafe_html: "Currently, ADsafe does not operate on whole HTML " +
417 "documents. It operates on <div> fragments and .js files.",
418 adsafe_id: "ADsafe violation: id does not match.",
419 adsafe_id_go: "ADsafe violation: Missing ADSAFE.id or ADSAFE.go.",
420 adsafe_lib: "ADsafe lib violation.",
421 adsafe_lib_second: "ADsafe: The second argument to lib must be a function.",
422 adsafe_missing_id: "ADSAFE violation: missing ID_.",
423 adsafe_name_a: "ADsafe name violation: '{a}'.",
424 adsafe_placement: "ADsafe script placement violation.",
425 adsafe_prefix_a: "ADsafe violation: An id must have a '{a}' prefix",
426 adsafe_script: "ADsafe script violation.",
427 adsafe_source: "ADsafe unapproved script source.",
428 adsafe_subscript_a: "ADsafe subscript '{a}'.",
429 adsafe_tag: "ADsafe violation: Disallowed tag '{a}'.",
430 already_defined: "'{a}' is already defined.",
431 and: "The '&&' subexpression should be wrapped in parens.",
432 assign_exception: "Do not assign to the exception parameter.",
433 assignment_function_expression: "Expected an assignment or " +
434 "function call and instead saw an expression.",
435 attribute_case_a: "Attribute '{a}' not all lower case.",
436 avoid_a: "Avoid '{a}'.",
437 bad_assignment: "Bad assignment.",
438 bad_color_a: "Bad hex color '{a}'.",
439 bad_constructor: "Bad constructor.",
440 bad_entity: "Bad entity.",
441 bad_html: "Bad HTML string",
442 bad_id_a: "Bad id: '{a}'.",
443 bad_in_a: "Bad for in variable '{a}'.",
444 bad_invocation: "Bad invocation.",
445 bad_name_a: "Bad name: '{a}'.",
446 bad_new: "Do not use 'new' for side effects.",
447 bad_number: "Bad number '{a}'.",
448 bad_operand: "Bad operand.",
449 bad_style: "Bad style.",
450 bad_type: "Bad type.",
451 bad_url_a: "Bad url '{a}'.",
452 bad_wrap: "Do not wrap function literals in parens unless they " +
453 "are to be immediately invoked.",
454 combine_var: "Combine this with the previous 'var' statement.",
455 conditional_assignment: "Expected a conditional expression and " +
456 "instead saw an assignment.",
457 confusing_a: "Confusing use of '{a}'.",
458 confusing_regexp: "Confusing regular expression.",
459 constructor_name_a: "A constructor name '{a}' should start with " +
460 "an uppercase letter.",
461 control_a: "Unexpected control character '{a}'.",
462 css: "A css file should begin with @charset 'UTF-8';",
463 dangling_a: "Unexpected dangling '_' in '{a}'.",
464 dangerous_comment: "Dangerous comment.",
465 deleted: "Only properties should be deleted.",
466 duplicate_a: "Duplicate '{a}'.",
467 empty_block: "Empty block.",
468 empty_case: "Empty case.",
469 empty_class: "Empty class.",
470 es5: "This is an ES5 feature.",
471 evil: "eval is evil.",
472 expected_a: "Expected '{a}'.",
473 expected_a_b: "Expected '{a}' and instead saw '{b}'.",
474 expected_a_b_from_c_d: "Expected '{a}' to match '{b}' from line " +
475 "{c} and instead saw '{d}'.",
476 expected_at_a: "Expected an at-rule, and instead saw @{a}.",
477 expected_a_at_b_c: "Expected '{a}' at column {b}, not column {c}.",
478 expected_attribute_a: "Expected an attribute, and instead saw [{a}].",
479 expected_attribute_value_a: "Expected an attribute value and " +
480 "instead saw '{a}'.",
481 expected_class_a: "Expected a class, and instead saw .{a}.",
482 expected_fraction_a: "Expected a number between 0 and 1 and " +
484 expected_id_a: "Expected an id, and instead saw #{a}.",
485 expected_identifier_a: "Expected an identifier and instead saw '{a}'.",
486 expected_identifier_a_reserved: "Expected an identifier and " +
487 "instead saw '{a}' (a reserved word).",
488 expected_linear_a: "Expected a linear unit and instead saw '{a}'.",
489 expected_lang_a: "Expected a lang code, and instead saw :{a}.",
490 expected_media_a: "Expected a CSS media type, and instead saw '{a}'.",
491 expected_name_a: "Expected a name and instead saw '{a}'.",
492 expected_nonstandard_style_attribute: "Expected a non-standard " +
493 "style attribute and instead saw '{a}'.",
494 expected_number_a: "Expected a number and instead saw '{a}'.",
495 expected_operator_a: "Expected an operator and instead saw '{a}'.",
496 expected_percent_a: "Expected a percentage and instead saw '{a}'",
497 expected_positive_a: "Expected a positive number and instead saw '{a}'",
498 expected_pseudo_a: "Expected a pseudo, and instead saw :{a}.",
499 expected_selector_a: "Expected a CSS selector, and instead saw {a}.",
500 expected_small_a: "Expected a small positive integer and instead saw '{a}'",
501 expected_space_a_b: "Expected exactly one space between '{a}' and '{b}'.",
502 expected_string_a: "Expected a string and instead saw {a}.",
503 expected_style_attribute: "Excepted a style attribute, and instead saw '{a}'.",
504 expected_style_pattern: "Expected a style pattern, and instead saw '{a}'.",
505 expected_tagname_a: "Expected a tagName, and instead saw {a}.",
506 expected_type_a: "Expected a type, and instead saw {a}.",
507 for_if: "The body of a for in should be wrapped in an if " +
508 "statement to filter unwanted properties from the prototype.",
509 function_block: "Function statements should not be placed in blocks. " +
510 "Use a function expression or move the statement to the top of " +
511 "the outer function.",
512 function_eval: "The Function constructor is eval.",
513 function_loop: "Don't make functions within a loop.",
514 function_statement: "Function statements are not invocable. " +
515 "Wrap the whole function invocation in parens.",
516 function_strict: "Use the function form of 'use strict'.",
517 html_confusion_a: "HTML confusion in regular expression '<{a}'.",
518 html_handlers: "Avoid HTML event handlers.",
519 identifier_function: "Expected an identifier in an assignment " +
520 "and instead saw a function invocation.",
521 implied_evil: "Implied eval is evil. Pass a function instead of a string.",
522 infix_in: "Unexpected 'in'. Compare with undefined, or use the " +
523 "hasOwnProperty method instead.",
524 insecure_a: "Insecure '{a}'.",
525 isNaN: "Use the isNaN function to compare with NaN.",
526 label_a_b: "Label '{a}' on '{b}' statement.",
527 lang: "lang is deprecated.",
528 leading_decimal_a: "A leading decimal point can be confused with a dot: '.{a}'.",
529 missing_a: "Missing '{a}'.",
530 missing_a_after_b: "Missing '{a}' after '{b}'.",
531 missing_option: "Missing option value.",
532 missing_property: "Missing property name.",
533 missing_space_a_b: "Missing space between '{a}' and '{b}'.",
534 missing_url: "Missing url.",
535 missing_use_strict: "Missing 'use strict' statement.",
536 mixed: "Mixed spaces and tabs.",
537 move_invocation: "Move the invocation into the parens that " +
538 "contain the function.",
539 move_var: "Move 'var' declarations to the top of the function.",
540 name_function: "Missing name in function statement.",
541 nested_comment: "Nested comment.",
543 not_a_constructor: "Do not use {a} as a constructor.",
544 not_a_defined: "'{a}' has not been fully defined yet.",
545 not_a_function: "'{a}' is not a function.",
546 not_a_label: "'{a}' is not a label.",
547 not_a_scope: "'{a}' is out of scope.",
548 not_greater: "'{a}' should not be greater than '{b}'.",
549 octal_a: "Don't use octal: '{a}'. Use '\\u....' instead.",
550 parameter_arguments_a: "Do not mutate parameter '{a}' when using 'arguments'.",
551 parameter_a_get_b: "Unexpected parameter '{a}' in get {b} function.",
552 parameter_set_a: "Expected parameter (value) in set {a} function.",
553 radix: "Missing radix parameter.",
554 read_only: "Read only.",
555 redefinition_a: "Redefinition of '{a}'.",
556 reserved_a: "Reserved name '{a}'.",
557 scanned_a_b: "{a} ({b}% scanned).",
558 slash_equal: "A regular expression literal can be confused with '/='.",
559 statement_block: "Expected to see a statement and instead saw a block.",
560 stopping: "Stopping. ",
561 strange_loop: "Strange loop.",
562 strict: "Strict violation.",
563 subscript: "['{a}'] is better written in dot notation.",
564 tag_a_in_b: "A '<{a}>' must be within '<{b}>'.",
565 too_long: "Line too long.",
566 too_many: "Too many errors.",
567 trailing_decimal_a: "A trailing decimal point can be confused " +
568 "with a dot: '.{a}'.",
569 type: "type is unnecessary.",
570 unclosed: "Unclosed string.",
571 unclosed_comment: "Unclosed comment.",
572 unclosed_regexp: "Unclosed regular expression.",
573 unescaped_a: "Unescaped '{a}'.",
574 unexpected_a: "Unexpected '{a}'.",
575 unexpected_char_a_b: "Unexpected character '{a}' in {b}.",
576 unexpected_comment: "Unexpected comment.",
577 unexpected_else: "Unexpected 'else' after 'return'.",
578 unexpected_property_a: "Unexpected /*property*/ '{a}'.",
579 unexpected_space_a_b: "Unexpected space between '{a}' and '{b}'.",
580 unnecessary_initialize: "It is not necessary to initialize '{a}' " +
582 unnecessary_use: "Unnecessary 'use strict'.",
583 unreachable_a_b: "Unreachable '{a}' after '{b}'.",
584 unrecognized_style_attribute_a: "Unrecognized style attribute '{a}'.",
585 unrecognized_tag_a: "Unrecognized tag '<{a}>'.",
586 unsafe: "Unsafe character.",
587 url: "JavaScript URL.",
588 use_array: "Use the array literal notation [].",
589 use_braces: "Spaces are hard to count. Use {{a}}.",
590 use_charAt: "Use the charAt method.",
591 use_object: "Use the object literal notation {}.",
592 use_or: "Use the || operator.",
593 use_param: "Use a named parameter.",
594 used_before_a: "'{a}' was used before it was defined.",
595 var_a_not: "Variable {a} was not declared correctly.",
596 weird_assignment: "Weird assignment.",
597 weird_condition: "Weird condition.",
598 weird_new: "Weird construction. Delete 'new'.",
599 weird_program: "Weird program.",
600 weird_relation: "Weird relation.",
601 weird_ternary: "Weird ternary.",
602 wrap_immediate: "Wrap an immediate function invocation in parentheses " +
603 "to assist the reader in understanding that the expression " +
604 "is the result of a function, and not the function itself.",
605 wrap_regexp: "Wrap the /regexp/ literal in parens to " +
606 "disambiguate the slash operator.",
607 write_is_wrong: "document.write can be a form of eval."
613 css_colorData
= array_to_object([
614 "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
615 "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
616 "burlywood", "cadetblue", "chartreuse", "chocolate", "coral",
617 "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue",
618 "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki",
619 "darkmagenta", "darkolivegreen", "darkorange", "darkorchid",
620 "darkred", "darksalmon", "darkseagreen", "darkslateblue",
621 "darkslategray", "darkturquoise", "darkviolet", "deeppink",
622 "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite",
623 "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold",
624 "goldenrod", "gray", "green", "greenyellow", "honeydew", "hotpink",
625 "indianred", "indigo", "ivory", "khaki", "lavender",
626 "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
627 "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgreen",
628 "lightpink", "lightsalmon", "lightseagreen", "lightskyblue",
629 "lightslategray", "lightsteelblue", "lightyellow", "lime",
630 "limegreen", "linen", "magenta", "maroon", "mediumaquamarine",
631 "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen",
632 "mediumslateblue", "mediumspringgreen", "mediumturquoise",
633 "mediumvioletred", "midnightblue", "mintcream", "mistyrose",
634 "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab",
635 "orange", "orangered", "orchid", "palegoldenrod", "palegreen",
636 "paleturquoise", "palevioletred", "papayawhip", "peachpuff",
637 "peru", "pink", "plum", "powderblue", "purple", "red", "rosybrown",
638 "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen",
639 "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray",
640 "snow", "springgreen", "steelblue", "tan", "teal", "thistle",
641 "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke",
642 "yellow", "yellowgreen",
644 "activeborder", "activecaption", "appworkspace", "background",
645 "buttonface", "buttonhighlight", "buttonshadow", "buttontext",
646 "captiontext", "graytext", "highlight", "highlighttext",
647 "inactiveborder", "inactivecaption", "inactivecaptiontext",
648 "infobackground", "infotext", "menu", "menutext", "scrollbar",
649 "threeddarkshadow", "threedface", "threedhighlight",
650 "threedlightshadow", "threedshadow", "window", "windowframe",
683 devel
= array_to_object([
684 'alert', 'confirm', 'console', 'Debug', 'opera', 'prompt', 'WSH'
699 funct
, // The current function, including the labels used in
700 // the function, as well as (breakage),
701 // (context), (loopage), (name), (params), (token),
705 'closure', 'exception', 'global', 'label', 'outer', 'undef',
709 functions
, // All of the functions
710 global_funct
, // The global body
711 global_scope
, // The global scope
718 area: {empty: true, parent: ' map '},
723 base: {empty: true, parent: ' head '},
727 body: {parent: ' html noframes '},
730 canvas: {parent: ' body p div th td '},
731 caption: {parent: ' table '},
735 col: {empty: true, parent: ' table colgroup '},
736 colgroup: {parent: ' table '},
737 command: {parent: ' menu '},
739 dd: {parent: ' dl '},
747 dt: {parent: ' dl '},
755 frame: {empty: true, parent: ' frameset '},
756 frameset: {parent: ' html frameset '},
763 head: {parent: ' html '},
768 {empty: true, parent: ' head '},
773 input: {empty: true},
778 legend: {parent: ' details fieldset figure '},
779 li: {parent: ' dir menu ol ul '},
780 link: {empty: true, parent: ' head '},
784 meta: {empty: true, parent: ' head noframes noscript '},
787 noframes: {parent: ' html body '},
788 noscript: {parent: ' body head noframes '},
791 optgroup: {parent: ' select '},
792 option: {parent: ' optgroup select '},
795 param: {empty: true, parent: ' applet object '},
803 script: {empty: true, parent: ' body div frame head iframe p pre span '},
810 style: {parent: ' head ', empty: true},
814 tbody: {parent: ' table '},
815 td: {parent: ' tr '},
817 tfoot: {parent: ' table '},
818 th: {parent: ' tr '},
819 thead: {parent: ' table '},
821 title: {parent: ' head '},
822 tr: {parent: ' table tbody thead tfoot '},
833 itself
, // JSLint itself
835 lex
, // the tokenizer
838 node
= array_to_object([
839 'Buffer', 'clearInterval', 'clearTimeout', 'console', 'exports',
840 'global', 'module', 'process', 'querystring', 'require',
841 'setInterval', 'setTimeout', '__dirname', '__filename'
844 numbery
= array_to_object(['indexOf', 'lastIndexOf', 'search'], true),
847 predefined
, // Global variables defined by option
851 regexp_flag
= array_to_object(['g', 'i', 'm'], true),
852 return_this
= function return_this() {
855 rhino
= array_to_object([
856 'defineClass', 'deserialize', 'gc', 'help', 'load', 'loadClass',
857 'print', 'quit', 'readFile', 'readUrl', 'runCommand', 'seal',
858 'serialize', 'spawn', 'sync', 'toint32', 'version'
861 scope
, // An object containing an object for each variable in scope
862 semicolon_coda
= array_to_object([';', '"', '\'', ')'], true),
866 // standard contains the global names that are provided by the
867 // ECMAScript standard.
869 standard
= array_to_object([
870 'Array', 'Boolean', 'Date', 'decodeURI', 'decodeURIComponent',
871 'encodeURI', 'encodeURIComponent', 'Error', 'eval', 'EvalError',
872 'Function', 'isFinite', 'isNaN', 'JSON', 'Math', 'Number',
873 'Object', 'parseInt', 'parseFloat', 'RangeError', 'ReferenceError',
874 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError'
885 // widget contains the global names which are provided to a Yahoo
886 // (fna Konfabulator) widget.
888 widget
= array_to_object([
889 'alert', 'animator', 'appleScript', 'beep', 'bytesToUIString',
890 'Canvas', 'chooseColor', 'chooseFile', 'chooseFolder',
891 'closeWidget', 'COM', 'convertPathToHFS', 'convertPathToPlatform',
892 'CustomAnimation', 'escape', 'FadeAnimation', 'filesystem', 'Flash',
893 'focusWidget', 'form', 'FormField', 'Frame', 'HotKey', 'Image',
894 'include', 'isApplicationRunning', 'iTunes', 'konfabulatorVersion',
895 'log', 'md5', 'MenuItem', 'MoveAnimation', 'openURL', 'play',
896 'Point', 'popupMenu', 'preferenceGroups', 'preferences', 'print',
897 'prompt', 'random', 'Rectangle', 'reloadWidget', 'ResizeAnimation',
898 'resolvePath', 'resumeUpdates', 'RotateAnimation', 'runCommand',
899 'runCommandInBg', 'saveAs', 'savePreferences', 'screen',
900 'ScrollBar', 'showWidgetPreferences', 'sleep', 'speak', 'Style',
901 'suppressUpdates', 'system', 'tellWidget', 'Text', 'TextArea',
902 'Timer', 'unescape', 'updateNow', 'URL', 'Web', 'widget', 'Window',
903 'XMLDOM', 'XMLHttpRequest', 'yahooCheckLogin', 'yahooLogin',
907 windows
= array_to_object([
908 'ActiveXObject', 'CScript', 'Debug', 'Enumerator', 'System',
909 'VBArray', 'WScript', 'WSH'
912 // xmode is used to adapt to the exceptions in html parsing.
913 // It can have these states:
914 // '' .js script file
925 // Regular expressions. Some of these are stupidly long.
927 // unsafe comment or string
928 ax
= /@cc|<\/?|script|\]\s*\]|<\s*!|</i,
929 // carriage return, carriage return linefeed, or linefeed
931 // unsafe characters that are silently deleted by one or more browsers
932 cx
= /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
933 // query characters for ids
934 dx
= /[\[\]\/\\"'*<>.&:(){}+=#]/,
936 hx
= /^\s*(['"=>\/&#]|<(?:\/|\!(?:--)?)?|[a-zA-Z][a-zA-Z0-9_\-:]*|[0-9]+|--)/,
938 ix
= /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
940 jx
= /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,
943 // characters in strings that need escapement
944 nx
= /[\u0000-\u001f'\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
946 ox
= /[>&]|<[\/!]?|--/,
947 // attributes characters
948 qx
= /[^a
-zA
-Z0
-9+\-_
\/ ]/,
950 sx
= /^\s*([{}:#%.=,>+\[\]@()"';]|[*$\^~]=|[a-zA-Z_][a-zA-Z0-9_\-]*|[0-9]+|<\/|\/\*)/,
951 ssx
= /^\s*([@#!"'};:\-%.=,+\[\]()*_]|[a-zA-Z][a-zA-Z0-9._\-]*|\/\*?|\d+(?:\.\d+)?|<\/)/,
953 tx
= /^\s*([(){}\[\]\?.,:;'"~#@`]|={1,3}|\/(\*(jslint|properties|property|members?|globals?)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|[\^%]=?|&[&=]?|\|[|=]?|>{1,3}=?|<(?:[\/=!]|\!(\[|--)?|<=?)?|\!={0,2}|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+(?:[xX][0-9a-fA-F]+|\.[0-9]*)?(?:[eE][+\-]?[0-9]+)?)/,
955 ux
= /&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto|script/i,
965 function F() {} // Used by Object.create
967 // Provide critical ES5 functions to ES3.
969 if (typeof Array
.prototype.filter
!== 'function') {
970 Array
.prototype.filter = function (f
) {
971 var i
, length
= this.length
, result
= [], value
;
972 for (i
= 0; i
< length
; i
+= 1) {
985 if (typeof Array
.prototype.forEach
!== 'function') {
986 Array
.prototype.forEach = function (f
) {
987 var i
, length
= this.length
;
988 for (i
= 0; i
< length
; i
+= 1) {
997 if (typeof Array
.isArray
!== 'function') {
998 Array
.isArray = function (o
) {
999 return Object
.prototype.toString
.apply(o
) === '[object Array]';
1003 if (!Object
.prototype.hasOwnProperty
.call(Object
, 'create')) {
1004 Object
.create = function (o
) {
1010 if (typeof Object
.keys
!== 'function') {
1011 Object
.keys = function (o
) {
1012 var array
= [], key
;
1014 if (Object
.prototype.hasOwnProperty
.call(o
, key
)) {
1022 if (typeof String
.prototype.entityify
!== 'function') {
1023 String
.prototype.entityify = function () {
1025 .replace(/&/g
, '&')
1026 .replace(/</g
, '<')
1027 .replace(/>/g
, '>');
1031 if (typeof String
.prototype.isAlpha
!== 'function') {
1032 String
.prototype.isAlpha = function () {
1033 return (this >= 'a' && this <= 'z\uffff') ||
1034 (this >= 'A' && this <= 'Z\uffff');
1038 if (typeof String
.prototype.isDigit
!== 'function') {
1039 String
.prototype.isDigit = function () {
1040 return (this >= '0' && this <= '9');
1044 if (typeof String
.prototype.supplant
!== 'function') {
1045 String
.prototype.supplant = function (o
) {
1046 return this.replace(/\{([^{}]*)\}/g, function (a
, b
) {
1047 var replacement
= o
[b
];
1048 return typeof replacement
=== 'string' ||
1049 typeof replacement
=== 'number' ? replacement : a
;
1055 function sanitize(a
) {
1057 // Escapify a troublesome character.
1059 return escapes
[a
] ||
1060 '\\u' + ('0000' + a
.charCodeAt().toString(16)).slice(-4);
1064 function add_to_predefined(group
) {
1065 Object
.keys(group
).forEach(function (name
) {
1066 predefined
[name
] = group
[name
];
1074 add_to_predefined(rhino
);
1075 option
.rhino
= false;
1078 add_to_predefined(devel
);
1079 option
.devel
= false;
1081 if (option
.browser
) {
1082 add_to_predefined(browser
);
1083 option
.browser
= false;
1085 if (option
.windows
) {
1086 add_to_predefined(windows
);
1087 option
.windows
= false;
1090 add_to_predefined(node
);
1091 option
.node
= false;
1094 if (option
.widget
) {
1095 add_to_predefined(widget
);
1096 option
.widget
= false;
1102 // Produce an error warning.
1104 function artifact(tok
) {
1108 return tok
.number
|| tok
.string
;
1111 function quit(message
, line
, character
) {
1113 name: 'JSLintError',
1115 character: character
,
1116 message: bundle
.scanned_a_b
.supplant({
1118 b: Math
.floor((line
/ lines
.length
) * 100)
1123 function warn(message
, offender
, a
, b
, c
, d
) {
1124 var character
, line
, warning
;
1125 offender
= offender
|| next_token
; // ~~
1126 line
= offender
.line
|| 0;
1127 character
= offender
.from || 0;
1130 raw: bundle
[message
] || message
,
1131 evidence: lines
[line
- 1] || '',
1133 character: character
,
1134 a: a
|| (offender
.id
=== '(number)'
1135 ? String(offender
.number
)
1141 warning
.reason
= warning
.raw
.supplant(warning
);
1142 JSLINT
.errors
.push(warning
);
1143 if (option
.passfail
) {
1144 quit(bundle
.stopping
, line
, character
);
1147 if (warnings
>= option
.maxerr
) {
1148 quit(bundle
.too_many
, line
, character
);
1153 function warn_at(message
, line
, character
, a
, b
, c
, d
) {
1154 return warn(message
, {
1160 function stop(message
, offender
, a
, b
, c
, d
) {
1161 var warning
= warn(message
, offender
, a
, b
, c
, d
);
1162 quit(bundle
.stopping
, warning
.line
, warning
.character
);
1165 function stop_at(message
, line
, character
, a
, b
, c
, d
) {
1166 return stop(message
, {
1172 function expected_at(at
) {
1173 if (!option
.white
&& next_token
.from !== at
) {
1174 warn('expected_a_at_b_c', next_token
, '', at
,
1179 function aint(it
, name
, expected
) {
1180 if (it
[name
] !== expected
) {
1181 warn('expected_a_b', it
, expected
, it
[name
]);
1188 // lexical analysis and token construction
1190 lex
= (function lex() {
1191 var character
, c
, from, length
, line
, pos
, source_row
;
1193 // Private lex methods
1195 function next_line() {
1197 if (line
>= lines
.length
) {
1201 source_row
= lines
[line
];
1203 at
= source_row
.search(/ \t/);
1205 warn_at('mixed', line
, at
+ 1);
1207 source_row
= source_row
.replace(/\t/g, tab
);
1208 at
= source_row
.search(cx
);
1210 warn_at('unsafe', line
, at
);
1212 if (option
.maxlen
&& option
.maxlen
< source_row
.length
) {
1213 warn_at('too_long', line
, source_row
.length
);
1218 // Produce a token object. The token inherits from a syntax symbol.
1220 function it(type
, value
) {
1222 if (type
=== '(string)' || type
=== '(range)') {
1223 if (jx
.test(value
)) {
1224 warn_at('url', line
, from);
1227 the_token
= Object
.create(syntax
[(
1228 type
=== '(punctuator)' || (type
=== '(identifier)' &&
1229 Object
.prototype.hasOwnProperty
.call(syntax
, value
))
1232 )] || syntax
['(error)']);
1233 if (type
=== '(identifier)') {
1234 the_token
.identifier
= true;
1235 if (value
=== '__iterator__' || value
=== '__proto__') {
1236 stop_at('reserved_a', line
, from, value
);
1237 } else if (!option
.nomen
&&
1238 (value
.charAt(0) === '_' ||
1239 value
.charAt(value
.length
- 1) === '_')) {
1240 warn_at('dangling_a', line
, from, value
);
1243 if (type
=== '(number)') {
1244 the_token
.number
= +value
;
1245 } else if (value
!== undefined) {
1246 the_token
.string
= String(value
);
1248 the_token
.line
= line
;
1249 the_token
.from = from;
1250 the_token
.thru
= character
;
1253 ('(,=:[!&|?{};'.indexOf(id
.charAt(id
.length
- 1)) >= 0) ||
1254 id
=== 'return' || id
=== 'case'
1260 var exec
= x
.exec(source_row
), first
;
1262 length
= exec
[0].length
;
1264 c
= first
.charAt(0);
1265 source_row
= source_row
.slice(length
);
1266 from = character
+ length
- first
.length
;
1267 character
+= length
;
1272 function string(x
) {
1273 var c
, pos
= 0, r
= '', result
;
1276 var i
= parseInt(source_row
.substr(pos
+ 1, n
), 16);
1278 if (i
>= 32 && i
<= 126 &&
1279 i
!== 34 && i
!== 92 && i
!== 39) {
1280 warn_at('unexpected_a', line
, character
, '\\');
1283 c
= String
.fromCharCode(i
);
1286 if (json_mode
&& x
!== '"') {
1287 warn_at('expected_a', line
, character
, '"');
1290 if (xquote
=== x
|| (xmode
=== 'scriptstring' && !xquote
)) {
1291 return it('(punctuator)', x
);
1295 while (pos
>= source_row
.length
) {
1297 if (xmode
!== 'html' || !next_line()) {
1298 stop_at('unclosed', line
, from);
1301 c
= source_row
.charAt(pos
);
1304 source_row
= source_row
.slice(pos
+ 1);
1305 result
= it('(string)', r
);
1310 if (c
=== '\n' || c
=== '\r') {
1313 warn_at('control_a', line
, character
+ pos
,
1314 source_row
.slice(0, pos
));
1315 } else if (c
=== xquote
) {
1316 warn_at('bad_html', line
, character
+ pos
);
1317 } else if (c
=== '<') {
1318 if (option
.safe
&& xmode
=== 'html') {
1319 warn_at('adsafe_a', line
, character
+ pos
, c
);
1320 } else if (source_row
.charAt(pos
+ 1) === '/' && (xmode
|| option
.safe
)) {
1321 warn_at('expected_a_b', line
, character
,
1323 } else if (source_row
.charAt(pos
+ 1) === '!' && (xmode
|| option
.safe
)) {
1324 warn_at('unexpected_a', line
, character
, '<!');
1326 } else if (c
=== '\\') {
1327 if (xmode
=== 'html') {
1329 warn_at('adsafe_a', line
, character
+ pos
, c
);
1331 } else if (xmode
=== 'styleproperty') {
1334 c
= source_row
.charAt(pos
);
1336 warn_at('unexpected_a', line
, character
, '\\');
1341 c
= source_row
.charAt(pos
);
1345 warn_at('es5', line
, character
);
1351 warn_at('bad_html', line
, character
+ pos
);
1355 warn_at('unexpected_a', line
, character
, '\\\'');
1363 warn_at('unexpected_a', line
, character
, '\\v');
1369 warn_at('unexpected_a', line
, character
, '\\x');
1374 if (typeof descapes
[c
] !== 'string') {
1375 warn_at(c
>= '0' && c
<= '7' ? 'octal_a' : 'unexpected_a',
1376 line
, character
, '\\' + c
);
1389 function number(snippet
) {
1391 if (xmode
!== 'style' && xmode
!== 'styleproperty' &&
1392 source_row
.charAt(0).isAlpha()) {
1393 warn_at('expected_space_a_b',
1394 line
, character
, c
, source_row
.charAt(0));
1397 digit
= snippet
.charAt(1);
1398 if (digit
.isDigit()) {
1399 if (token
.id
!== '.' && xmode
!== 'styleproperty') {
1400 warn_at('unexpected_a', line
, character
, snippet
);
1402 } else if (json_mode
&& (digit
=== 'x' || digit
=== 'X')) {
1403 warn_at('unexpected_a', line
, character
, '0x');
1406 if (snippet
.slice(snippet
.length
- 1) === '.') {
1407 warn_at('trailing_decimal_a', line
, character
, snippet
);
1409 if (xmode
!== 'style') {
1411 if (!isFinite(digit
)) {
1412 warn_at('bad_number', line
, character
, snippet
);
1416 return it('(number)', snippet
);
1419 function comment(snippet
) {
1420 if (comments_off
|| src
|| (xmode
&& xmode
!== 'script' &&
1421 xmode
!== 'style' && xmode
!== 'styleproperty')) {
1422 warn_at('unexpected_comment', line
, character
);
1423 } else if (xmode
=== 'script' && /<\//i.test(source_row
)) {
1424 warn_at('unexpected_a', line
, character
, '<\/');
1425 } else if (option
.safe
&& ax
.test(snippet
)) {
1426 warn_at('dangerous_comment', line
, character
);
1445 c
= source_row
.charAt(length
);
1449 stop_at('unclosed_regexp', line
, from);
1453 warn_at('unescaped_a', line
, from + length
, '/');
1455 c
= source_row
.slice(0, length
- 1);
1456 potential
= Object
.create(regexp_flag
);
1458 letter
= source_row
.charAt(length
);
1459 if (potential
[letter
] !== true) {
1462 potential
[letter
] = false;
1466 if (source_row
.charAt(length
).isAlpha()) {
1467 stop_at('unexpected_a', line
, from, source_row
.charAt(length
));
1469 character
+= length
;
1470 source_row
= source_row
.slice(length
);
1471 quote
= source_row
.charAt(0);
1472 if (quote
=== '/' || quote
=== '*') {
1473 stop_at('confusing_regexp', line
, from);
1475 result
= it('(regexp)', c
);
1479 c
= source_row
.charAt(length
);
1481 warn_at('control_a', line
, from + length
, String(c
));
1482 } else if (c
=== '<') {
1483 warn_at(bundle
.unexpected_a
, line
, from + length
, '\\');
1490 if (source_row
.charAt(length
) === '?') {
1492 switch (source_row
.charAt(length
)) {
1499 warn_at(bundle
.expected_a_b
, line
, from + length
,
1500 ':', source_row
.charAt(length
));
1511 warn_at('unescaped_a', line
, from + length
, ')');
1518 while (source_row
.charAt(length
) === ' ') {
1523 warn_at('use_braces', line
, from + length
, pos
);
1527 c
= source_row
.charAt(length
);
1530 if (!option
.regexp
) {
1531 warn_at('insecure_a', line
, from + length
, c
);
1532 } else if (source_row
.charAt(length
) === ']') {
1533 stop_at('unescaped_a', line
, from + length
, '^');
1538 warn_at('empty_class', line
, from + length
- 1);
1542 c
= source_row
.charAt(length
);
1547 warn_at('unescaped_a', line
, from + length
, c
);
1554 warn_at('unescaped_a', line
, from + length
, '-');
1560 warn_at('unescaped_a', line
, from + length
- 1, '-');
1564 c
= source_row
.charAt(length
);
1566 warn_at(bundle
.control_a
, line
, from + length
, String(c
));
1567 } else if (c
=== '<') {
1568 warn_at(bundle
.unexpected_a
, line
, from + length
, '\\');
1574 warn_at('unescaped_a', line
, from + length
- 1, '/');
1578 if (xmode
=== 'script') {
1579 c
= source_row
.charAt(length
);
1580 if (c
=== '!' || c
=== '/') {
1581 warn_at(bundle
.html_confusion_a
, line
,
1593 if (!option
.regexp
) {
1594 warn_at('insecure_a', line
, from + length
, c
);
1603 warn_at('unescaped_a', line
, from + length
, c
);
1606 if (xmode
=== 'script') {
1607 c
= source_row
.charAt(length
);
1608 if (c
=== '!' || c
=== '/') {
1609 warn_at(bundle
.html_confusion_a
, line
, from + length
, c
);
1615 switch (source_row
.charAt(length
)) {
1620 if (source_row
.charAt(length
) === '?') {
1626 c
= source_row
.charAt(length
);
1627 if (c
< '0' || c
> '9') {
1628 warn_at(bundle
.expected_number_a
, line
,
1634 c
= source_row
.charAt(length
);
1635 if (c
< '0' || c
> '9') {
1639 low
= +c
+ (low
* 10);
1645 c
= source_row
.charAt(length
);
1646 if (c
>= '0' && c
<= '9') {
1650 c
= source_row
.charAt(length
);
1651 if (c
< '0' || c
> '9') {
1655 high
= +c
+ (high
* 10);
1659 if (source_row
.charAt(length
) !== '}') {
1660 warn_at(bundle
.expected_a_b
, line
, from + length
,
1665 if (source_row
.charAt(length
) === '?') {
1669 warn_at(bundle
.not_greater
, line
, from + length
,
1676 c
= source_row
.slice(0, length
- 1);
1677 character
+= length
;
1678 source_row
= source_row
.slice(length
);
1679 return it('(regexp)', c
);
1682 // Public lex methods
1685 init: function (source
) {
1686 if (typeof source
=== 'string') {
1687 lines
= source
.split(crlfx
);
1696 range: function (begin
, end
) {
1699 if (source_row
.charAt(0) !== begin
) {
1700 stop_at('expected_a_b', line
, character
, begin
,
1701 source_row
.charAt(0));
1704 source_row
= source_row
.slice(1);
1706 c
= source_row
.charAt(0);
1709 stop_at('missing_a', line
, character
, c
);
1712 source_row
= source_row
.slice(1);
1714 return it('(range)', value
);
1717 warn_at('unexpected_a', line
, character
, c
);
1724 // token -- this is called by advance to get the next token.
1726 token: function () {
1730 while (!source_row
) {
1735 while (xmode
=== 'outer') {
1736 i
= source_row
.search(ox
);
1741 source_row
= source_row
.slice(i
);
1745 return it('(end)', '');
1749 snippet
= match(rx
[xmode
] || tx
);
1752 if (source_row
.charAt(0) === ' ') {
1753 if (!option
.white
) {
1754 warn_at('unexpected_a', line
, character
,
1760 stop_at('unexpected_a', line
, character
,
1761 source_row
.charAt(0));
1768 c
= snippet
.charAt(0);
1769 if (c
.isAlpha() || c
=== '_' || c
=== '$') {
1770 return it('(identifier)', snippet
);
1776 return number(snippet
);
1784 return string(snippet
);
1789 comment(source_row
);
1797 i
= source_row
.search(lx
);
1801 comment(source_row
);
1803 stop_at('unclosed_comment', line
, character
);
1806 comment(source_row
.slice(0, i
));
1808 if (source_row
.charAt(i
) === '/') {
1809 stop_at('nested_comment', line
, character
);
1811 source_row
= source_row
.slice(i
+ 2);
1818 if (token
.id
=== '/=') {
1827 : it('(punctuator)', snippet
);
1835 i
= source_row
.indexOf('--');
1839 i
= source_row
.indexOf('<!');
1841 stop_at('nested_comment',
1842 line
, character
+ i
);
1845 stop_at('unclosed_comment', length
, c
);
1848 length
= source_row
.indexOf('<!');
1849 if (length
>= 0 && length
< i
) {
1850 stop_at('nested_comment',
1851 line
, character
+ length
);
1854 if (source_row
.charAt(i
+ 2) !== '>') {
1855 stop_at('expected_a', line
, character
, '-->');
1858 source_row
= source_row
.slice(i
+ 3);
1861 if (xmode
=== 'html' || xmode
=== 'styleproperty') {
1863 c
= source_row
.charAt(0);
1864 if ((c
< '0' || c
> '9') &&
1865 (c
< 'a' || c
> 'f') &&
1866 (c
< 'A' || c
> 'F')) {
1870 source_row
= source_row
.slice(1);
1873 if (snippet
.length
!== 4 && snippet
.length
!== 7) {
1874 warn_at('bad_color_a', line
,
1875 from + length
, snippet
);
1877 return it('(color)', snippet
);
1879 return it('(punctuator)', snippet
);
1882 if (xmode
=== 'outer' && c
=== '&') {
1884 source_row
= source_row
.slice(1);
1886 c
= source_row
.charAt(0);
1888 source_row
= source_row
.slice(1);
1892 if (!((c
>= '0' && c
<= '9') ||
1893 (c
>= 'a' && c
<= 'z') ||
1895 stop_at('bad_entity', line
, from + length
,
1901 return it('(punctuator)', snippet
);
1910 function add_label(token
, kind
, name
) {
1912 // Define the symbol in the current function in the current scope.
1914 name
= name
|| token
.string
;
1916 // Global variables cannot be created in the safe subset. If a global variable
1917 // already exists, do nothing. If it is predefined, define it.
1919 if (funct
=== global_funct
) {
1921 warn('adsafe_a', token
, name
);
1923 if (typeof global_funct
[name
] !== 'string') {
1924 token
.writeable
= typeof predefined
[name
] === 'boolean'
1927 token
.funct
= funct
;
1928 global_scope
[name
] = token
;
1930 if (kind
=== 'becoming') {
1934 // Ordinary variables.
1938 // Warn if the variable already exists.
1940 if (typeof funct
[name
] === 'string') {
1941 if (funct
[name
] === 'undef') {
1942 if (!option
.undef
) {
1943 warn('used_before_a', token
, name
);
1947 warn('already_defined', token
, name
);
1951 // Add the symbol to the current function.
1953 token
.funct
= funct
;
1954 token
.writeable
= true;
1955 scope
[name
] = token
;
1962 function peek(distance
) {
1964 // Peek ahead to a future token. The distance is how far ahead to look. The
1965 // default is the next token.
1967 var found
, slot
= 0;
1969 distance
= distance
|| 0;
1970 while (slot
<= distance
) {
1971 found
= lookahead
[slot
];
1973 found
= lookahead
[slot
] = lex
.token();
1981 function advance(id
, match
) {
1983 // Produce the next token, also looking for programming errors.
1987 // If indentation checking was requested, then inspect all of the line breakings.
1988 // The var statement is tricky because the names might be aligned or not. We
1989 // look at the first line break after the var to determine the programmer's
1992 if (var_mode
&& next_token
.line
!== token
.line
) {
1993 if ((var_mode
!== indent
|| !next_token
.edge
) &&
1994 next_token
.from === indent
.at
-
1995 (next_token
.edge
? option
.indent : 0)) {
1998 dent
.at
-= option
.indent
;
1999 if (dent
=== var_mode
) {
2008 if (next_token
.id
=== '?' && indent
.mode
=== ':' &&
2009 token
.line
!== next_token
.line
) {
2010 indent
.at
-= option
.indent
;
2014 // If the token is an edge.
2016 if (next_token
.edge
) {
2017 if (next_token
.edge
=== 'label') {
2019 } else if (next_token
.edge
=== 'case' || indent
.mode
=== 'statement') {
2020 expected_at(indent
.at
- option
.indent
);
2021 } else if (indent
.mode
!== 'array' || next_token
.line
!== token
.line
) {
2022 expected_at(indent
.at
);
2025 // If the token is not an edge, but is the first token on the line.
2027 } else if (next_token
.line
!== token
.line
) {
2028 if (next_token
.from < indent
.at
+ (indent
.mode
===
2029 'expression' ? 0 : option
.indent
)) {
2030 expected_at(indent
.at
+ option
.indent
);
2034 } else if (next_token
.line
!== token
.line
) {
2035 if (next_token
.edge
) {
2036 expected_at(indent
.at
);
2039 if (indent
.mode
=== 'statement' || indent
.mode
=== 'var') {
2040 expected_at(indent
.at
+ option
.indent
);
2041 } else if (next_token
.from < indent
.at
+ (indent
.mode
===
2042 'expression' ? 0 : option
.indent
)) {
2043 expected_at(indent
.at
+ option
.indent
);
2051 if (next_token
.id
=== '.') {
2052 warn('trailing_decimal_a');
2056 if (next_token
.id
=== '-' || next_token
.id
=== '--') {
2057 warn('confusing_a');
2061 if (next_token
.id
=== '+' || next_token
.id
=== '++') {
2062 warn('confusing_a');
2066 if (token
.id
=== '(string)' || token
.identifier
) {
2067 anonname
= token
.string
;
2070 if (id
&& next_token
.id
!== id
) {
2072 warn('expected_a_b_from_c_d', next_token
, id
,
2073 match
.id
, match
.line
, artifact());
2074 } else if (!next_token
.identifier
|| next_token
.string
!== id
) {
2075 warn('expected_a_b', next_token
, id
, artifact());
2080 next_token
= lookahead
.shift() || lex
.token();
2084 function advance_identifier(string
) {
2085 if (next_token
.identifier
&& next_token
.string
=== string
) {
2088 warn('expected_a_b', next_token
, string
, artifact());
2093 function do_safe() {
2094 if (option
.adsafe
) {
2099 option
['continue'] =
2113 option
.windows
= false;
2116 delete predefined
.Array
;
2117 delete predefined
.Date
;
2118 delete predefined
.Function
;
2119 delete predefined
.Object
;
2120 delete predefined
['eval'];
2130 function do_globals() {
2131 var name
, writeable
;
2133 if (next_token
.id
!== '(string)' && !next_token
.identifier
) {
2136 name
= next_token
.string
;
2139 if (next_token
.id
=== ':') {
2141 switch (next_token
.id
) {
2143 writeable
= predefined
[name
] !== false;
2150 stop('unexpected_a');
2153 predefined
[name
] = writeable
;
2154 if (next_token
.id
!== ',') {
2162 function do_jslint() {
2164 while (next_token
.id
=== '(string)' || next_token
.identifier
) {
2165 name
= next_token
.string
;
2166 if (!allowed_option
[name
]) {
2167 stop('unexpected_a');
2170 if (next_token
.id
!== ':') {
2171 stop('expected_a_b', next_token
, ':', artifact());
2174 if (typeof allowed_option
[name
] === 'number') {
2175 value
= next_token
.number
;
2176 if (value
> allowed_option
[name
] || value
<= 0 ||
2177 Math
.floor(value
) !== value
) {
2178 stop('expected_small_a');
2180 option
[name
] = value
;
2182 if (next_token
.id
=== 'true') {
2183 option
[name
] = true;
2184 } else if (next_token
.id
=== 'false') {
2185 option
[name
] = false;
2187 stop('unexpected_a');
2191 if (next_token
.id
=== ',') {
2199 function do_properties() {
2201 option
.properties
= true;
2203 if (next_token
.id
!== '(string)' && !next_token
.identifier
) {
2206 name
= next_token
.string
;
2208 if (next_token
.id
=== ':') {
2211 if (next_token
.id
!== '(string)' && !next_token
.identifier
) {
2217 if (next_token
.id
!== ',') {
2225 directive
= function directive() {
2226 var command
= this.id
,
2227 old_comments_off
= comments_off
,
2228 old_indent
= indent
;
2229 comments_off
= true;
2231 if (next_token
.line
=== token
.line
&& next_token
.from === token
.thru
) {
2232 warn('missing_space_a_b', next_token
, artifact(token
), artifact());
2234 if (lookahead
.length
> 0) {
2235 warn('unexpected_a', this);
2238 case '/*properties':
2246 warn('adsafe_a', this);
2253 warn('adsafe_a', this);
2258 stop('unexpected_a', this);
2260 comments_off
= old_comments_off
;
2262 indent
= old_indent
;
2266 // Indentation intention
2268 function edge(mode
) {
2269 next_token
.edge
= indent
? indent
.open
&& (mode
|| 'edge') : '';
2273 function step_in(mode
) {
2275 if (typeof mode
=== 'number') {
2281 } else if (!indent
) {
2287 } else if (mode
=== 'statement') {
2294 open
= mode
=== 'var' || next_token
.line
!== token
.line
;
2296 at: (open
|| mode
=== 'control'
2297 ? indent
.at
+ option
.indent
2298 : indent
.at
) + (indent
.wrap
? option
.indent : 0),
2303 if (mode
=== 'var' && open
) {
2309 function step_out(id
, symbol
) {
2311 if (indent
&& indent
.open
) {
2312 indent
.at
-= option
.indent
;
2315 advance(id
, symbol
);
2318 indent
= indent
.was
;
2322 // Functions for conformance of whitespace.
2324 function one_space(left
, right
) {
2325 left
= left
|| token
;
2326 right
= right
|| next_token
;
2327 if (right
.id
!== '(end)' && !option
.white
&&
2328 (token
.line
!== right
.line
||
2329 token
.thru
+ 1 !== right
.from)) {
2330 warn('expected_space_a_b', right
, artifact(token
), artifact(right
));
2334 function one_space_only(left
, right
) {
2335 left
= left
|| token
;
2336 right
= right
|| next_token
;
2337 if (right
.id
!== '(end)' && (left
.line
!== right
.line
||
2338 (!option
.white
&& left
.thru
+ 1 !== right
.from))) {
2339 warn('expected_space_a_b', right
, artifact(left
), artifact(right
));
2343 function no_space(left
, right
) {
2344 left
= left
|| token
;
2345 right
= right
|| next_token
;
2346 if ((!option
.white
|| xmode
=== 'styleproperty' || xmode
=== 'style') &&
2347 left
.thru
!== right
.from && left
.line
=== right
.line
) {
2348 warn('unexpected_space_a_b', right
, artifact(left
), artifact(right
));
2352 function no_space_only(left
, right
) {
2353 left
= left
|| token
;
2354 right
= right
|| next_token
;
2355 if (right
.id
!== '(end)' && (left
.line
!== right
.line
||
2356 (!option
.white
&& left
.thru
!== right
.from))) {
2357 warn('unexpected_space_a_b', right
, artifact(left
), artifact(right
));
2361 function spaces(left
, right
) {
2362 if (!option
.white
) {
2363 left
= left
|| token
;
2364 right
= right
|| next_token
;
2365 if (left
.thru
=== right
.from && left
.line
=== right
.line
) {
2366 warn('missing_space_a_b', right
, artifact(left
), artifact(right
));
2372 if (next_token
.id
!== ',') {
2373 warn_at('expected_a_b', token
.line
, token
.thru
, ',', artifact());
2375 if (!option
.white
) {
2384 function semicolon() {
2385 if (next_token
.id
!== ';') {
2386 warn_at('expected_a_b', token
.line
, token
.thru
, ';', artifact());
2388 if (!option
.white
) {
2392 if (semicolon_coda
[next_token
.id
] !== true) {
2398 function use_strict() {
2399 if (next_token
.string
=== 'use strict') {
2401 warn('unnecessary_use');
2407 option
.newcap
= false;
2408 option
.undef
= false;
2415 function are_similar(a
, b
) {
2419 if (Array
.isArray(a
)) {
2420 if (Array
.isArray(b
) && a
.length
=== b
.length
) {
2422 for (i
= 0; i
< a
.length
; i
+= 1) {
2423 if (!are_similar(a
[i
], b
[i
])) {
2431 if (Array
.isArray(b
)) {
2434 if (a
.id
=== '(number)' && b
.id
=== '(number)') {
2435 return a
.number
=== b
.number
;
2437 if (a
.arity
=== b
.arity
&& a
.string
=== b
.string
) {
2442 return a
.id
=== b
.id
&& are_similar(a
.first
, b
.first
);
2444 return are_similar(a
.first
, b
.first
) &&
2445 are_similar(a
.second
, b
.second
);
2447 return are_similar(a
.first
, b
.first
) &&
2448 are_similar(a
.second
, b
.second
) &&
2449 are_similar(a
.third
, b
.third
);
2457 if (a
.id
=== '.' && b
.id
=== '[' && b
.arity
=== 'infix') {
2458 return a
.second
.string
=== b
.second
.string
&& b
.second
.id
=== '(string)';
2460 if (a
.id
=== '[' && a
.arity
=== 'infix' && b
.id
=== '.') {
2461 return a
.second
.string
=== b
.second
.string
&& a
.second
.id
=== '(string)';
2468 // This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
2469 // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
2470 // like .nud except that it is only used on the first token of a statement.
2471 // Having .fud makes it much easier to define statement-oriented languages like
2472 // JavaScript. I retained Pratt's nomenclature.
2474 // .nud Null denotation
2475 // .fud First null denotation
2476 // .led Left denotation
2477 // lbp Left binding power
2478 // rbp Right binding power
2480 // They are elements of the parsing method called Top Down Operator Precedence.
2482 function expression(rbp
, initial
) {
2484 // rbp is the right binding power.
2485 // initial indicates that this is the first expression of a statement.
2488 if (next_token
.id
=== '(end)') {
2489 stop('unexpected_a', token
, next_token
.id
);
2492 if (option
.safe
&& scope
[token
.string
] &&
2493 scope
[token
.string
] === global_scope
[token
.string
] &&
2494 (next_token
.id
!== '(' && next_token
.id
!== '.')) {
2495 warn('adsafe_a', token
);
2498 anonname
= 'anonymous';
2499 funct
['(verb)'] = token
.string
;
2501 if (initial
=== true && token
.fud
) {
2507 if (next_token
.id
=== '(number)' && token
.id
=== '.') {
2508 warn('leading_decimal_a', token
, artifact());
2512 stop('expected_identifier_a', token
, token
.id
);
2514 while (rbp
< next_token
.lbp
) {
2517 left
= token
.led(left
);
2519 stop('expected_operator_a', token
, token
.id
);
2527 // Functional constructors for making the symbols that will be inherited by
2530 function symbol(s
, p
) {
2532 if (!x
|| typeof x
!== 'object') {
2542 function postscript(x
) {
2543 x
.postscript
= true;
2547 function ultimate(s
) {
2548 var x
= symbol(s
, 0);
2554 return postscript(x
);
2558 function stmt(s
, f
) {
2560 x
.identifier
= x
.reserved
= true;
2565 function labeled_stmt(s
, f
) {
2570 function disrupt_stmt(s
, f
) {
2576 function reserve_name(x
) {
2577 var c
= x
.id
.charAt(0);
2578 if ((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z')) {
2579 x
.identifier
= x
.reserved
= true;
2585 function prefix(s
, f
) {
2586 var x
= symbol(s
, 150);
2588 x
.nud
= typeof f
=== 'function'
2591 if (s
=== 'typeof') {
2596 this.first
= expression(150);
2597 this.arity
= 'prefix';
2598 if (this.id
=== '++' || this.id
=== '--') {
2599 if (!option
.plusplus
) {
2600 warn('unexpected_a', this);
2601 } else if ((!this.first
.identifier
|| this.first
.reserved
) &&
2602 this.first
.id
!== '.' && this.first
.id
!== '[') {
2603 warn('bad_operand', this);
2612 function type(s
, t
, nud
) {
2622 function reserve(s
, f
) {
2624 x
.identifier
= x
.reserved
= true;
2625 if (typeof f
=== 'function') {
2632 function constant(name
) {
2633 var x
= reserve(name
);
2635 x
.nud
= return_this
;
2640 function reservevar(s
, v
) {
2641 return reserve(s
, function () {
2642 if (typeof v
=== 'function') {
2650 function infix(s
, p
, f
, w
) {
2651 var x
= symbol(s
, p
);
2653 x
.led = function (left
) {
2654 this.arity
= 'infix';
2656 spaces(prev_token
, token
);
2659 if (!option
.bitwise
&& this.bitwise
) {
2660 warn('unexpected_a', this);
2662 if (typeof f
=== 'function') {
2663 return f(left
, this);
2666 this.second
= expression(p
);
2672 function expected_relation(node
, message
) {
2674 warn(message
|| bundle
.conditional_assignment
, node
);
2679 function expected_condition(node
, message
) {
2683 if (node
.arity
!== 'infix') {
2684 warn(message
|| bundle
.weird_condition
, node
);
2699 warn(message
|| bundle
.weird_condition
, node
);
2702 if (node
.first
.id
=== '.' && numbery
[node
.first
.second
.string
] === true) {
2703 warn(message
|| bundle
.weird_condition
, node
);
2710 function check_relation(node
) {
2711 switch (node
.arity
) {
2716 warn('unexpected_a', node
);
2719 warn('confusing_a', node
);
2725 warn('unexpected_a', node
);
2728 if (node
.id
=== 'NaN') {
2729 warn('isNaN', node
);
2736 function relation(s
, eqeq
) {
2737 return infix(s
, 100, function (left
, that
) {
2738 check_relation(left
);
2739 if (eqeq
&& !option
.eqeq
) {
2740 warn('expected_a_b', that
, eqeq
, that
.id
);
2742 var right
= expression(100);
2743 if (are_similar(left
, right
) ||
2744 ((left
.id
=== '(string)' || left
.id
=== '(number)') &&
2745 (right
.id
=== '(string)' || right
.id
=== '(number)'))) {
2746 warn('weird_relation', that
);
2749 that
.second
= check_relation(right
);
2755 function assignop(s
, op
) {
2756 var x
= infix(s
, 20, function (left
, that
) {
2759 if (left
.identifier
) {
2760 if (scope
[left
.string
]) {
2761 if (scope
[left
.string
].writeable
=== false) {
2762 warn('read_only', left
);
2767 if (funct
['(params)']) {
2768 funct
['(params)'].forEach(function (value
) {
2769 if (value
.string
=== left
.string
) {
2770 value
.assign
= true;
2774 } else if (option
.safe
) {
2777 if (typeof predefined
[l
.string
] === 'boolean') {
2778 warn('adsafe_a', l
);
2783 if (left
=== syntax
['function']) {
2784 warn('identifier_function', token
);
2786 if (left
.id
=== '.' || left
.id
=== '[') {
2787 if (!left
.first
|| left
.first
.string
=== 'arguments') {
2788 warn('bad_assignment', that
);
2790 } else if (left
.identifier
) {
2791 if (!left
.reserved
&& funct
[left
.string
] === 'exception') {
2792 warn('assign_exception', left
);
2795 warn('bad_assignment', that
);
2797 that
.second
= expression(19);
2798 if (that
.id
=== '=' && are_similar(that
.first
, that
.second
)) {
2799 warn('weird_assignment', that
);
2805 if (syntax
[op
].bitwise
) {
2813 function bitwise(s
, p
) {
2814 var x
= infix(s
, p
, 'number');
2820 function suffix(s
) {
2821 var x
= symbol(s
, 150);
2822 x
.led = function (left
) {
2823 no_space_only(prev_token
, token
);
2824 if (!option
.plusplus
) {
2825 warn('unexpected_a', this);
2826 } else if ((!left
.identifier
|| left
.reserved
) &&
2827 left
.id
!== '.' && left
.id
!== '[') {
2828 warn('bad_operand', this);
2831 this.arity
= 'suffix';
2838 function optional_identifier() {
2839 if (next_token
.identifier
) {
2841 if (option
.safe
&& banned
[token
.string
]) {
2842 warn('adsafe_a', token
);
2843 } else if (token
.reserved
&& !option
.es5
) {
2844 warn('expected_identifier_a_reserved', token
);
2846 return token
.string
;
2851 function identifier() {
2852 var i
= optional_identifier();
2854 stop(token
.id
=== 'function' && next_token
.id
=== '('
2856 : 'expected_identifier_a');
2862 function statement() {
2864 var label
, old_scope
= scope
, the_statement
;
2866 // We don't like the empty statement.
2868 if (next_token
.id
=== ';') {
2869 warn('unexpected_a');
2874 // Is this a labeled statement?
2876 if (next_token
.identifier
&& !next_token
.reserved
&& peek().id
=== ':') {
2881 scope
= Object
.create(old_scope
);
2882 add_label(label
, 'label');
2883 if (next_token
.labeled
!== true) {
2884 warn('label_a_b', next_token
, label
.string
, artifact());
2885 } else if (jx
.test(label
.string
+ ':')) {
2887 } else if (funct
=== global_funct
) {
2888 stop('unexpected_a', token
);
2890 next_token
.label
= label
;
2893 // Parse the statement.
2895 if (token
.id
!== 'else') {
2898 step_in('statement');
2899 the_statement
= expression(0, true);
2900 if (the_statement
) {
2902 // Look for the final semicolon.
2904 if (the_statement
.arity
=== 'statement') {
2905 if (the_statement
.id
=== 'switch' ||
2906 (the_statement
.block
&& the_statement
.id
!== 'do')) {
2913 // If this is an expression statement, determine if it is acceptable.
2916 // statments. If it is to be used at all, new should only be used to make
2917 // objects, not side effects. The expression statements we do like do
2918 // assignment or invocation or delete.
2920 if (the_statement
.id
=== '(') {
2921 if (the_statement
.first
.id
=== 'new') {
2924 } else if (!the_statement
.assign
&&
2925 the_statement
.id
!== 'delete' &&
2926 the_statement
.id
!== '++' &&
2927 the_statement
.id
!== '--') {
2928 warn('assignment_function_expression', token
);
2935 return the_statement
;
2939 function statements() {
2940 var array
= [], disruptor
, the_statement
;
2942 // A disrupt statement may not be followed by any other statement.
2943 // If the last statement is disrupt, then the sequence is disrupt.
2945 while (next_token
.postscript
!== true) {
2946 if (next_token
.id
=== ';') {
2947 warn('unexpected_a', next_token
);
2950 if (next_token
.string
=== 'use strict') {
2951 if ((!node_js
&& xmode
!== 'script') || funct
!== global_funct
|| array
.length
> 0) {
2952 warn('function_strict');
2957 warn('unreachable_a_b', next_token
, next_token
.string
,
2961 the_statement
= statement();
2962 if (the_statement
) {
2963 array
.push(the_statement
);
2964 if (the_statement
.disrupt
) {
2965 disruptor
= the_statement
;
2966 array
.disrupt
= true;
2975 function block(ordinary
) {
2977 // array block is array sequence of statements wrapped in braces.
2978 // ordinary is false for function bodies and try blocks.
2979 // ordinary is true for if statements, while, etc.
2983 old_in_block
= in_block
,
2985 old_strict_mode
= strict_mode
;
2987 in_block
= ordinary
;
2988 scope
= Object
.create(scope
);
2990 if (next_token
.id
=== '{') {
2993 if (!ordinary
&& !use_strict() && !old_strict_mode
&&
2994 !option
.sloppy
&& funct
['(context)'] === global_funct
) {
2995 warn('missing_use_strict');
2997 array
= statements();
2998 strict_mode
= old_strict_mode
;
2999 step_out('}', curly
);
3000 } else if (!ordinary
) {
3001 stop('expected_a_b', next_token
, '{', artifact());
3003 warn('expected_a_b', next_token
, '{', artifact());
3004 array
= [statement()];
3005 array
.disrupt
= array
[0].disrupt
;
3007 funct
['(verb)'] = null;
3009 in_block
= old_in_block
;
3010 if (ordinary
&& array
.length
=== 0) {
3011 warn('empty_block');
3017 function tally_property(name
) {
3018 if (option
.properties
&& typeof property
[name
] !== 'number') {
3019 warn('unexpected_property_a', token
, name
);
3021 if (typeof property
[name
] === 'number') {
3022 property
[name
] += 1;
3029 // ECMAScript parser
3031 syntax
['(identifier)'] = {
3036 var name
= this.string
,
3037 variable
= scope
[name
],
3041 // If the variable is not in scope, then we may have an undeclared variable.
3042 // Check the predefined list. If it was predefined, create the global
3045 if (typeof variable
!== 'object') {
3046 writeable
= predefined
[name
];
3047 if (typeof writeable
=== 'boolean') {
3048 global_scope
[name
] = variable
= {
3050 writeable: writeable
,
3053 global_funct
[name
] = 'var';
3055 // But if the variable is not in scope, and is not predefined, and if we are not
3056 // in the global scope, then we have an undefined variable error.
3059 if (!option
.undef
) {
3060 warn('used_before_a', token
);
3062 scope
[name
] = variable
= {
3067 funct
[name
] = 'undef';
3071 site
= variable
.funct
;
3073 // The name is in scope and defined in the current function.
3075 if (funct
=== site
) {
3077 // Change 'unused' to 'var', and reject labels.
3079 switch (funct
[name
]) {
3081 warn('unexpected_a', token
);
3082 funct
[name
] = 'var';
3085 funct
[name
] = 'var';
3088 funct
[name
] = 'parameter';
3091 funct
[name
] = 'function';
3094 warn('a_label', token
, name
);
3098 // If the name is already defined in the current
3099 // function, but not as outer, then there is a scope error.
3102 switch (funct
[name
]) {
3107 warn('a_scope', token
, name
);
3110 warn('a_label', token
, name
);
3117 // If the name is defined in an outer function, make an outer entry, and if
3118 // it was unused, make it var.
3120 switch (site
[name
]) {
3128 site
[name
] = 'closure';
3129 funct
[name
] = site
=== global_funct
3134 site
[name
] = 'parameter';
3135 funct
[name
] = 'outer';
3138 funct
[name
] = 'undef';
3141 warn('a_label', token
, name
);
3149 stop('expected_operator_a');
3153 // Build the syntax table by declaring the syntactic elements.
3155 type('(array)', 'array');
3156 type('(color)', 'color');
3157 type('(function)', 'function');
3158 type('(number)', 'number', return_this
);
3159 type('(object)', 'object');
3160 type('(string)', 'string', return_this
);
3161 type('(boolean)', 'boolean', return_this
);
3162 type('(range)', 'range');
3163 type('(regexp)', 'regexp', return_this
);
3165 ultimate('(begin)');
3167 ultimate('(error)');
3168 postscript(symbol('</'));
3172 postscript(symbol('}'));
3175 postscript(symbol('"'));
3176 postscript(symbol('\''));
3183 postscript(reserve('case'));
3185 postscript(reserve('default'));
3189 reservevar('arguments', function (x
) {
3190 if (strict_mode
&& funct
=== global_funct
) {
3192 } else if (option
.safe
) {
3193 warn('adsafe_a', x
);
3195 funct
['(arguments)'] = true;
3197 reservevar('eval', function (x
) {
3199 warn('adsafe_a', x
);
3202 constant('false', 'boolean');
3203 constant('Infinity', 'number');
3204 constant('NaN', 'number');
3205 constant('null', '');
3206 reservevar('this', function (x
) {
3208 warn('adsafe_a', x
);
3209 } else if (strict_mode
&& funct
['(token)'].arity
=== 'statement' &&
3210 funct
['(name)'].charAt(0) > 'Z') {
3214 constant('true', 'boolean');
3215 constant('undefined', '');
3217 infix('?', 30, function (left
, that
) {
3219 that
.first
= expected_condition(expected_relation(left
));
3220 that
.second
= expression(0);
3223 var colon
= next_token
;
3227 that
.third
= expression(10);
3228 that
.arity
= 'ternary';
3229 if (are_similar(that
.second
, that
.third
)) {
3230 warn('weird_ternary', colon
);
3231 } else if (are_similar(that
.first
, that
.second
)) {
3232 warn('use_or', that
);
3238 infix('||', 40, function (left
, that
) {
3239 function paren_check(that
) {
3240 if (that
.id
=== '&&' && !that
.paren
) {
3246 that
.first
= paren_check(expected_condition(expected_relation(left
)));
3247 that
.second
= paren_check(expected_relation(expression(40)));
3248 if (are_similar(that
.first
, that
.second
)) {
3249 warn('weird_condition', that
);
3254 infix('&&', 50, function (left
, that
) {
3255 that
.first
= expected_condition(expected_relation(left
));
3256 that
.second
= expected_relation(expression(50));
3257 if (are_similar(that
.first
, that
.second
)) {
3258 warn('weird_condition', that
);
3263 prefix('void', function () {
3264 this.first
= expression(0);
3265 this.arity
= 'prefix';
3267 warn('expected_a_b', this, 'undefined', 'void');
3268 } else if (this.first
.number
!== 0) {
3269 warn('expected_a_b', this.first
, '0', artifact(this.first
));
3278 relation('==', '===');
3280 relation('!=', '!==');
3289 bitwise('>>>', 120);
3291 infix('in', 120, function (left
, that
) {
3292 warn('infix_in', that
);
3294 that
.right
= expression(130);
3297 infix('instanceof', 120);
3298 infix('+', 130, function (left
, that
) {
3299 if (left
.id
=== '(number)') {
3300 if (left
.number
=== 0) {
3301 warn('unexpected_a', left
, '0');
3303 } else if (left
.id
=== '(string)') {
3304 if (left
.string
=== '') {
3305 warn('expected_a_b', left
, 'String', '\'\'');
3308 var right
= expression(130);
3309 if (right
.id
=== '(number)') {
3310 if (right
.number
=== 0) {
3311 warn('unexpected_a', right
, '0');
3313 } else if (right
.id
=== '(string)') {
3314 if (right
.string
=== '') {
3315 warn('expected_a_b', right
, 'String', '\'\'');
3318 if (left
.id
=== right
.id
) {
3319 if (left
.id
=== '(string)' || left
.id
=== '(number)') {
3320 if (left
.id
=== '(string)') {
3321 left
.string
+= right
.string
;
3322 if (jx
.test(left
.string
)) {
3326 left
.number
+= right
.number
;
3328 left
.thru
= right
.thru
;
3333 that
.second
= right
;
3337 prefix('+++', function () {
3338 warn('confusing_a', token
);
3339 this.first
= expression(150);
3340 this.arity
= 'prefix';
3343 infix('+++', 130, function (left
) {
3344 warn('confusing_a', token
);
3346 this.second
= expression(130);
3349 infix('-', 130, function (left
, that
) {
3350 if ((left
.id
=== '(number)' && left
.number
=== 0) || left
.id
=== '(string)') {
3351 warn('unexpected_a', left
);
3353 var right
= expression(130);
3354 if ((right
.id
=== '(number)' && right
.number
=== 0) || right
.id
=== '(string)') {
3355 warn('unexpected_a', right
);
3357 if (left
.id
=== right
.id
&& left
.id
=== '(number)') {
3358 left
.number
-= right
.number
;
3359 left
.thru
= right
.thru
;
3363 that
.second
= right
;
3367 prefix('---', function () {
3368 warn('confusing_a', token
);
3369 this.first
= expression(150);
3370 this.arity
= 'prefix';
3373 infix('---', 130, function (left
) {
3374 warn('confusing_a', token
);
3376 this.second
= expression(130);
3379 infix('*', 140, function (left
, that
) {
3380 if ((left
.id
=== '(number)' && (left
.number
=== 0 || left
.number
=== 1)) || left
.id
=== '(string)') {
3381 warn('unexpected_a', left
);
3383 var right
= expression(140);
3384 if ((right
.id
=== '(number)' && (right
.number
=== 0 || right
.number
=== 1)) || right
.id
=== '(string)') {
3385 warn('unexpected_a', right
);
3387 if (left
.id
=== right
.id
&& left
.id
=== '(number)') {
3388 left
.number
*= right
.number
;
3389 left
.thru
= right
.thru
;
3393 that
.second
= right
;
3396 infix('/', 140, function (left
, that
) {
3397 if ((left
.id
=== '(number)' && left
.number
=== 0) || left
.id
=== '(string)') {
3398 warn('unexpected_a', left
);
3400 var right
= expression(140);
3401 if ((right
.id
=== '(number)' && (right
.number
=== 0 || right
.number
=== 1)) || right
.id
=== '(string)') {
3402 warn('unexpected_a', right
);
3404 if (left
.id
=== right
.id
&& left
.id
=== '(number)') {
3405 left
.number
/= right
.number
;
3406 left
.thru
= right
.thru
;
3410 that
.second
= right
;
3413 infix('%', 140, function (left
, that
) {
3414 if ((left
.id
=== '(number)' && (left
.number
=== 0 || left
.number
=== 1)) || left
.id
=== '(string)') {
3415 warn('unexpected_a', left
);
3417 var right
= expression(140);
3418 if ((right
.id
=== '(number)' && right
.number
=== 0) || right
.id
=== '(string)') {
3419 warn('unexpected_a', right
);
3421 if (left
.id
=== right
.id
&& left
.id
=== '(number)') {
3422 left
.number
%= right
.number
;
3423 left
.thru
= right
.thru
;
3427 that
.second
= right
;
3436 prefix('delete', function () {
3438 var p
= expression(0);
3439 if (!p
|| (p
.id
!== '.' && p
.id
!== '[')) {
3447 prefix('~', function () {
3449 if (!option
.bitwise
) {
3450 warn('unexpected_a', this);
3455 prefix('!', function () {
3457 this.first
= expected_condition(expression(150));
3458 this.arity
= 'prefix';
3459 if (bang
[this.first
.id
] === true || this.first
.assign
) {
3460 warn('confusing_a', this);
3464 prefix('typeof', null);
3465 prefix('new', function () {
3467 var c
= expression(160), n
, p
, v
;
3469 if (c
.id
!== 'function') {
3473 warn('use_object', token
);
3476 if (next_token
.id
=== '(') {
3480 if (next_token
.id
!== ')') {
3483 if (n
.id
!== '(number)' || next_token
.id
=== ',') {
3484 warn('use_array', p
);
3486 while (next_token
.id
=== ',') {
3488 p
.second
.push(expression(0));
3491 warn('use_array', token
);
3496 warn('use_array', token
);
3503 warn('not_a_constructor', c
);
3507 warn('function_eval');
3515 if (c
.id
!== 'function') {
3516 v
= c
.string
.charAt(0);
3517 if (!option
.newcap
&& (v
< 'A' || v
> 'Z')) {
3518 warn('constructor_name_a', token
);
3523 if (c
.id
!== '.' && c
.id
!== '[' && c
.id
!== '(') {
3524 warn('bad_constructor', token
);
3528 warn('weird_new', this);
3530 if (next_token
.id
!== '(') {
3531 warn('missing_a', next_token
, '()');
3536 infix('(', 160, function (left
, that
) {
3538 if (indent
&& indent
.mode
=== 'expression') {
3539 no_space(prev_token
, token
);
3541 no_space_only(prev_token
, token
);
3543 if (!left
.immed
&& left
.id
=== 'function') {
3544 warn('wrap_immediate');
3547 if (left
.identifier
) {
3548 if (left
.string
.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
3549 if (left
.string
!== 'Number' && left
.string
!== 'String' &&
3550 left
.string
!== 'Boolean' && left
.string
!== 'Date') {
3551 if (left
.string
=== 'Math' || left
.string
=== 'JSON') {
3552 warn('not_a_function', left
);
3553 } else if (left
.string
=== 'Object') {
3554 warn('use_object', token
);
3555 } else if (left
.string
=== 'Array' || !option
.newcap
) {
3556 warn('missing_a', left
, 'new');
3560 } else if (left
.id
=== '.') {
3561 if (option
.safe
&& left
.first
.string
=== 'Math' &&
3562 left
.second
=== 'random') {
3563 warn('adsafe_a', left
);
3564 } else if (left
.second
.string
=== 'split' &&
3565 left
.first
.id
=== '(string)') {
3566 warn('use_array', left
.second
);
3570 if (next_token
.id
!== ')') {
3574 p
.push(expression(10));
3575 if (next_token
.id
!== ',') {
3582 step_out(')', that
);
3583 if (typeof left
=== 'object') {
3584 if (left
.string
=== 'parseInt' && p
.length
=== 1) {
3585 warn('radix', left
);
3588 if (left
.string
=== 'eval' || left
.string
=== 'Function' ||
3589 left
.string
=== 'execScript') {
3591 } else if (p
[0] && p
[0].id
=== '(string)' &&
3592 (left
.string
=== 'setTimeout' ||
3593 left
.string
=== 'setInterval')) {
3594 warn('implied_evil', left
);
3597 if (!left
.identifier
&& left
.id
!== '.' && left
.id
!== '[' &&
3598 left
.id
!== '(' && left
.id
!== '&&' && left
.id
!== '||' &&
3600 warn('bad_invocation', left
);
3608 prefix('(', function () {
3609 step_in('expression');
3612 if (next_token
.id
=== 'function') {
3613 next_token
.immed
= true;
3615 var value
= expression(0);
3618 step_out(')', this);
3619 if (value
.id
=== 'function') {
3620 switch (next_token
.id
) {
3622 warn('move_invocation');
3626 warn('unexpected_a');
3629 warn('bad_wrap', this);
3635 infix('.', 170, function (left
, that
) {
3636 no_space(prev_token
, token
);
3638 var name
= identifier();
3639 if (typeof name
=== 'string') {
3640 tally_property(name
);
3643 that
.second
= token
;
3644 if (left
&& left
.string
=== 'arguments' &&
3645 (name
=== 'callee' || name
=== 'caller')) {
3646 warn('avoid_a', left
, 'arguments.' + name
);
3647 } else if (!option
.evil
&& left
&& left
.string
=== 'document' &&
3648 (name
=== 'write' || name
=== 'writeln')) {
3649 warn('write_is_wrong', left
);
3650 } else if (option
.adsafe
) {
3651 if (!adsafe_top
&& left
.string
=== 'ADSAFE') {
3652 if (name
=== 'id' || name
=== 'lib') {
3653 warn('adsafe_a', that
);
3654 } else if (name
=== 'go') {
3655 if (xmode
!== 'script') {
3656 warn('adsafe_a', that
);
3657 } else if (adsafe_went
|| next_token
.id
!== '(' ||
3658 peek(0).id
!== '(string)' ||
3659 peek(0).string
!== adsafe_id
||
3660 peek(1).id
!== ',') {
3661 stop('adsafe_a', that
, 'go');
3669 if (!option
.evil
&& (name
=== 'eval' || name
=== 'execScript')) {
3671 } else if (option
.safe
) {
3673 if (banned
[name
] === true) {
3674 warn('adsafe_a', token
, name
);
3676 if (typeof predefined
[left
.string
] !== 'boolean' || //// check for writeable
3677 next_token
.id
=== '(') {
3680 if (next_token
.id
!== '.') {
3681 warn('adsafe_a', that
);
3686 token
.second
= name
;
3688 name
= identifier();
3689 if (typeof name
=== 'string') {
3690 tally_property(name
);
3697 infix('[', 170, function (left
, that
) {
3699 no_space_only(prev_token
, token
);
3706 if (e
.id
=== '(number)' && left
.id
=== 'arguments') {
3707 warn('use_param', left
);
3711 if (option
.safe
&& (banned
[e
.string
] ||
3712 e
.string
.charAt(0) === '_' || e
.string
.slice(-1) === '_')) {
3713 warn('adsafe_subscript_a', e
);
3714 } else if (!option
.evil
&&
3715 (e
.string
=== 'eval' || e
.string
=== 'execScript')) {
3717 } else if (!option
.sub
&& ix
.test(e
.string
)) {
3718 s
= syntax
[e
.string
];
3719 if (!s
|| !s
.reserved
) {
3720 warn('subscript', e
);
3723 tally_property(e
.string
);
3727 warn('adsafe_subscript_a', e
);
3730 step_out(']', that
);
3731 no_space(prev_token
, token
);
3737 prefix('[', function () {
3738 this.arity
= 'prefix';
3741 while (next_token
.id
!== '(end)') {
3742 while (next_token
.id
=== ',') {
3743 warn('unexpected_a', next_token
);
3746 if (next_token
.id
=== ']') {
3749 indent
.wrap
= false;
3751 this.first
.push(expression(10));
3752 if (next_token
.id
=== ',') {
3754 if (next_token
.id
=== ']' && !option
.es5
) {
3755 warn('unexpected_a', token
);
3762 step_out(']', this);
3767 function property_name() {
3768 var id
= optional_identifier(true);
3770 if (next_token
.id
=== '(string)') {
3771 id
= next_token
.string
;
3775 } else if (id
.charAt(0) === '_' ||
3776 id
.charAt(id
.length
- 1) === '_') {
3781 } else if (next_token
.id
=== '(number)') {
3782 id
= next_token
.number
.toString();
3790 function function_params() {
3791 var id
, paren
= next_token
, params
= [];
3795 if (next_token
.id
=== ')') {
3797 step_out(')', paren
);
3804 add_label(token
, option
.unparam
? 'parameter' : 'unparam');
3805 if (next_token
.id
=== ',') {
3809 step_out(')', paren
);
3817 function do_function(func
, name
) {
3818 var old_funct
= funct
,
3819 old_option
= option
,
3822 '(name)' : name
|| '\'' + (anonname
|| '').replace(nx
, sanitize
) + '\'',
3823 '(line)' : next_token
.line
,
3824 '(context)' : old_funct
,
3830 option
= Object
.create(old_option
);
3831 scope
= Object
.create(old_scope
);
3832 functions
.push(funct
);
3835 add_label(func
, 'function', name
);
3837 func
.writeable
= false;
3838 func
.first
= funct
['(params)'] = function_params();
3840 func
.block
= block(false);
3841 if (funct
['(arguments)']) {
3842 func
.first
.forEach(function (value
) {
3844 warn('parameter_arguments_a', value
, value
.string
);
3849 option
= old_option
;
3855 assignop('+=', '+');
3856 assignop('-=', '-');
3857 assignop('*=', '*');
3858 assignop('/=', '/').nud = function () {
3859 stop('slash_equal');
3861 assignop('%=', '%');
3862 assignop('&=', '&');
3863 assignop('|=', '|');
3864 assignop('^=', '^');
3865 assignop('<<=', '<<');
3866 assignop('>>=', '>>');
3867 assignop('>>>=', '>>>');
3870 prefix('{', function () {
3871 var get, i
, j
, name
, p
, set, seen
= {};
3872 this.arity
= 'prefix';
3875 while (next_token
.id
!== '}') {
3876 indent
.wrap
= false;
3878 // JSLint recognizes the ES5 extension for get/set in object literals,
3879 // but requires that they be used in pairs.
3882 if (next_token
.string
=== 'get' && peek().id
!== ':') {
3890 i
= property_name();
3892 stop('missing_property');
3896 if (funct
['(loopage)']) {
3897 warn('function_loop', get);
3901 warn('parameter_a_get_b', p
[0], p
[0].string
, i
);
3910 j
= property_name();
3912 stop('expected_a_b', token
, i
, j
|| next_token
.string
);
3915 if (set.block
.length
=== 0) {
3916 warn('missing_a', token
, 'throw');
3919 if (!p
|| p
.length
!== 1) {
3920 stop('parameter_set_a', set, 'value');
3921 } else if (p
[0].string
!== 'value') {
3922 stop('expected_a_b', p
[0], 'value', p
[0].string
);
3924 name
.first
= [get, set];
3927 i
= property_name();
3928 if (typeof i
!== 'string') {
3929 stop('missing_property');
3933 name
.first
= expression(10);
3935 this.first
.push(name
);
3936 if (seen
[i
] === true) {
3937 warn('duplicate_a', next_token
, i
);
3941 if (next_token
.id
!== ',') {
3946 if (next_token
.id
!== ',') {
3949 warn('unexpected_a', next_token
);
3951 if (next_token
.id
=== '}' && !option
.es5
) {
3952 warn('unexpected_a', token
);
3955 step_out('}', this);
3959 stmt('{', function () {
3960 warn('statement_block');
3961 this.arity
= 'statement';
3962 this.block
= statements();
3963 this.disrupt
= this.block
.disrupt
;
3968 stmt('/*global', directive
);
3969 stmt('/*globals', directive
);
3970 stmt('/*jslint', directive
);
3971 stmt('/*member', directive
);
3972 stmt('/*members', directive
);
3973 stmt('/*property', directive
);
3974 stmt('/*properties', directive
);
3976 stmt('var', function () {
3978 // JavaScript does not have block scope. It only has function scope. So,
3979 // declaring a variable in a block can have unexpected consequences.
3981 // var.first will contain an array, the array containing name tokens
3982 // and assignment tokens.
3984 var assign
, id
, name
;
3986 if (funct
['(vars)'] && !option
.vars
) {
3987 warn('combine_var');
3988 } else if (funct
!== global_funct
) {
3989 funct
['(vars)'] = true;
3991 this.arity
= 'statement';
3997 add_label(name
, 'becoming');
3999 if (next_token
.id
=== '=') {
4000 assign
= next_token
;
4001 assign
.first
= name
;
4005 if (next_token
.id
=== 'undefined') {
4006 warn('unnecessary_initialize', token
, id
);
4008 if (peek(0).id
=== '=' && next_token
.identifier
) {
4011 assign
.second
= expression(0);
4012 assign
.arity
= 'infix';
4013 this.first
.push(assign
);
4015 this.first
.push(name
);
4017 if (funct
[id
] === 'becoming') {
4018 funct
[id
] = 'unused';
4020 if (next_token
.id
!== ',') {
4024 indent
.wrap
= false;
4025 if (var_mode
&& next_token
.line
=== token
.line
&&
4026 this.first
.length
=== 1) {
4028 indent
.open
= false;
4029 indent
.at
-= option
.indent
;
4039 stmt('function', function () {
4042 warn('function_block', token
);
4044 var name
= next_token
, id
= identifier();
4045 add_label(name
, 'unction');
4047 this.arity
= 'statement';
4048 do_function(this, id
);
4049 if (next_token
.id
=== '(' && next_token
.line
=== token
.line
) {
4050 stop('function_statement');
4055 prefix('function', function () {
4059 var id
= optional_identifier();
4065 do_function(this, id
);
4066 if (funct
['(loopage)']) {
4067 warn('function_loop');
4069 switch (next_token
.id
) {
4079 if (peek().string
!== 'bind' || peek(1).id
!== '(') {
4080 warn('unexpected_a');
4084 stop('unexpected_a');
4086 this.arity
= 'function';
4090 stmt('if', function () {
4091 var paren
= next_token
;
4097 this.arity
= 'statement';
4098 this.first
= expected_condition(expected_relation(expression(0)));
4100 step_out(')', paren
);
4102 this.block
= block(true);
4103 if (next_token
.id
=== 'else') {
4107 this['else'] = next_token
.id
=== 'if' || next_token
.id
=== 'switch'
4110 if (this['else'].disrupt
&& this.block
.disrupt
) {
4111 this.disrupt
= true;
4117 stmt('try', function () {
4119 // try.first The catch variable
4120 // try.second The catch clause
4121 // try.third The finally clause
4122 // try.block The try block
4124 var exception_variable
, old_scope
, paren
;
4125 if (option
.adsafe
) {
4126 warn('adsafe_a', this);
4129 this.arity
= 'statement';
4130 this.block
= block(false);
4131 if (next_token
.id
=== 'catch') {
4141 scope
= Object
.create(old_scope
);
4142 exception_variable
= next_token
.string
;
4143 this.first
= exception_variable
;
4144 if (!next_token
.identifier
) {
4145 warn('expected_identifier_a', next_token
);
4147 add_label(next_token
, 'exception');
4151 step_out(')', paren
);
4153 this.second
= block(false);
4156 if (next_token
.id
=== 'finally') {
4160 this.third
= block(false);
4161 } else if (!this.second
) {
4162 stop('expected_a_b', next_token
, 'catch', artifact());
4167 labeled_stmt('while', function () {
4169 var paren
= next_token
;
4170 funct
['(breakage)'] += 1;
4171 funct
['(loopage)'] += 1;
4176 this.arity
= 'statement';
4177 this.first
= expected_relation(expression(0));
4178 if (this.first
.id
!== 'true') {
4179 expected_condition(this.first
, bundle
.unexpected_a
);
4182 step_out(')', paren
);
4184 this.block
= block(true);
4185 if (this.block
.disrupt
) {
4186 warn('strange_loop', prev_token
);
4188 funct
['(breakage)'] -= 1;
4189 funct
['(loopage)'] -= 1;
4195 labeled_stmt('switch', function () {
4197 // switch.first the switch expression
4198 // switch.second the array of cases. A case is 'case' or 'default' token:
4199 // case.first the array of case expressions
4200 // case.second the array of statements
4201 // If all of the arrays of statements are disrupt, then the switch is disrupt.
4204 old_in_block
= in_block
,
4206 the_case
= next_token
,
4209 function find_duplicate_case(value
) {
4210 if (are_similar(particular
, value
)) {
4211 warn('duplicate_a', value
);
4215 funct
['(breakage)'] += 1;
4220 this.arity
= 'statement';
4221 this.first
= expected_condition(expected_relation(expression(0)));
4223 step_out(')', the_case
);
4229 while (next_token
.id
=== 'case') {
4230 the_case
= next_token
;
4231 cases
.forEach(find_duplicate_case
);
4232 the_case
.first
= [];
4233 the_case
.arity
= 'case';
4239 particular
= expression(0);
4240 cases
.forEach(find_duplicate_case
);
4241 cases
.push(particular
);
4242 the_case
.first
.push(particular
);
4243 if (particular
.id
=== 'NaN') {
4244 warn('unexpected_a', particular
);
4248 if (next_token
.id
!== 'case') {
4256 the_case
.second
= statements();
4257 if (the_case
.second
&& the_case
.second
.length
> 0) {
4258 particular
= the_case
.second
[the_case
.second
.length
- 1];
4259 if (particular
.disrupt
) {
4260 if (particular
.id
=== 'break') {
4264 warn('missing_a_after_b', next_token
, 'break', 'case');
4269 this.second
.push(the_case
);
4271 if (this.second
.length
=== 0) {
4272 warn('missing_a', next_token
, 'case');
4274 if (next_token
.id
=== 'default') {
4276 the_case
= next_token
;
4277 the_case
.arity
= 'case';
4283 the_case
.second
= statements();
4284 if (the_case
.second
&& the_case
.second
.length
> 0) {
4285 particular
= the_case
.second
[the_case
.second
.length
- 1];
4286 if (unbroken
&& particular
.disrupt
&& particular
.id
!== 'break') {
4287 this.disrupt
= true;
4290 this.second
.push(the_case
);
4292 funct
['(breakage)'] -= 1;
4294 step_out('}', this);
4295 in_block
= old_in_block
;
4299 stmt('debugger', function () {
4300 if (!option
.debug
) {
4301 warn('unexpected_a', this);
4303 this.arity
= 'statement';
4307 labeled_stmt('do', function () {
4308 funct
['(breakage)'] += 1;
4309 funct
['(loopage)'] += 1;
4311 this.arity
= 'statement';
4312 this.block
= block(true);
4313 if (this.block
.disrupt
) {
4314 warn('strange_loop', prev_token
);
4318 var paren
= next_token
;
4324 this.first
= expected_condition(expected_relation(expression(0)), bundle
.unexpected_a
);
4326 step_out(')', paren
);
4327 funct
['(breakage)'] -= 1;
4328 funct
['(loopage)'] -= 1;
4332 labeled_stmt('for', function () {
4334 var blok
, filter
, ok
= false, paren
= next_token
, value
;
4335 this.arity
= 'statement';
4336 funct
['(breakage)'] += 1;
4337 funct
['(loopage)'] += 1;
4339 if (next_token
.id
=== ';') {
4349 spaces(this, paren
);
4351 if (next_token
.id
=== 'var') {
4355 if (peek(0).id
=== 'in') {
4358 switch (funct
[value
.string
]) {
4360 funct
[value
.string
] = 'var';
4366 warn('bad_in_a', value
);
4371 this.second
= expression(20);
4372 step_out(')', paren
);
4374 if (!option
.forin
) {
4375 if (blok
.length
=== 1 && typeof blok
[0] === 'object' &&
4376 blok
[0].string
=== 'if' && !blok
[0]['else']) {
4377 filter
= blok
[0].first
;
4378 while (filter
.id
=== '&&') {
4379 filter
= filter
.first
;
4381 switch (filter
.id
) {
4384 ok
= filter
.first
.id
=== '['
4385 ? filter
.first
.first
.string
=== this.second
.string
&&
4386 filter
.first
.second
.string
=== this.first
.string
4387 : filter
.first
.id
=== 'typeof' &&
4388 filter
.first
.first
.id
=== '[' &&
4389 filter
.first
.first
.first
.string
=== this.second
.string
&&
4390 filter
.first
.first
.second
.string
=== this.first
.string
;
4393 ok
= filter
.first
.id
=== '.' && ((
4394 filter
.first
.first
.string
=== this.second
.string
&&
4395 filter
.first
.second
.string
=== 'hasOwnProperty' &&
4396 filter
.second
[0].string
=== this.first
.string
4398 filter
.first
.first
.string
=== 'ADSAFE' &&
4399 filter
.first
.second
.string
=== 'has' &&
4400 filter
.second
[0].string
=== this.second
.string
&&
4401 filter
.second
[1].string
=== this.first
.string
4403 filter
.first
.first
.id
=== '.' &&
4404 filter
.first
.first
.first
.id
=== '.' &&
4405 filter
.first
.first
.first
.first
.string
=== 'Object' &&
4406 filter
.first
.first
.first
.second
.string
=== 'prototype' &&
4407 filter
.first
.first
.second
.string
=== 'hasOwnProperty' &&
4408 filter
.first
.second
.string
=== 'call' &&
4409 filter
.second
[0].string
=== this.second
.string
&&
4410 filter
.second
[1].string
=== this.first
.string
4416 warn('for_if', this);
4423 this.first
.push(expression(0, 'for'));
4424 if (next_token
.id
!== ',') {
4431 this.second
= expected_relation(expression(0));
4432 if (this.second
.id
!== 'true') {
4433 expected_condition(this.second
, bundle
.unexpected_a
);
4436 if (next_token
.id
=== ';') {
4437 stop('expected_a_b', next_token
, ')', ';');
4442 this.third
.push(expression(0, 'for'));
4443 if (next_token
.id
!== ',') {
4449 step_out(')', paren
);
4455 warn('strange_loop', prev_token
);
4458 funct
['(breakage)'] -= 1;
4459 funct
['(loopage)'] -= 1;
4463 disrupt_stmt('break', function () {
4464 var label
= next_token
.string
;
4465 this.arity
= 'statement';
4466 if (funct
['(breakage)'] === 0) {
4467 warn('unexpected_a', this);
4469 if (next_token
.identifier
&& token
.line
=== next_token
.line
) {
4471 if (funct
[label
] !== 'label') {
4472 warn('not_a_label', next_token
);
4473 } else if (scope
[label
].funct
!== funct
) {
4474 warn('not_a_scope', next_token
);
4476 this.first
= next_token
;
4482 disrupt_stmt('continue', function () {
4483 if (!option
['continue']) {
4484 warn('unexpected_a', this);
4486 var label
= next_token
.string
;
4487 this.arity
= 'statement';
4488 if (funct
['(breakage)'] === 0) {
4489 warn('unexpected_a', this);
4491 if (next_token
.identifier
&& token
.line
=== next_token
.line
) {
4493 if (funct
[label
] !== 'label') {
4494 warn('not_a_label', next_token
);
4495 } else if (scope
[label
].funct
!== funct
) {
4496 warn('not_a_scope', next_token
);
4498 this.first
= next_token
;
4504 disrupt_stmt('return', function () {
4505 if (funct
=== global_funct
&& xmode
!== 'scriptstring') {
4506 warn('unexpected_a', this);
4508 this.arity
= 'statement';
4509 if (next_token
.id
!== ';' && next_token
.line
=== token
.line
) {
4511 if (next_token
.id
=== '/' || next_token
.id
=== '(regexp)') {
4512 warn('wrap_regexp');
4514 this.first
= expression(20);
4516 if (peek(0).id
=== '}' && peek(1).id
=== 'else') {
4517 warn('unexpected_else', this);
4522 disrupt_stmt('throw', function () {
4523 this.arity
= 'statement';
4525 this.first
= expression(20);
4530 // Superfluous reserved words
4540 // Harmony reserved words
4542 reserve('implements');
4543 reserve('interface');
4547 reserve('protected');
4555 function json_value() {
4557 function json_object() {
4558 var brace
= next_token
, object
= {};
4560 if (next_token
.id
!== '}') {
4561 while (next_token
.id
!== '(end)') {
4562 while (next_token
.id
=== ',') {
4563 warn('unexpected_a', next_token
);
4566 if (next_token
.id
!== '(string)') {
4567 warn('expected_string_a');
4569 if (object
[next_token
.string
] === true) {
4570 warn('duplicate_a');
4571 } else if (next_token
.string
=== '__proto__') {
4574 object
[next_token
.string
] = true;
4579 if (next_token
.id
!== ',') {
4583 if (next_token
.id
=== '}') {
4584 warn('unexpected_a', token
);
4589 advance('}', brace
);
4592 function json_array() {
4593 var bracket
= next_token
;
4595 if (next_token
.id
!== ']') {
4596 while (next_token
.id
!== '(end)') {
4597 while (next_token
.id
=== ',') {
4598 warn('unexpected_a', next_token
);
4602 if (next_token
.id
!== ',') {
4606 if (next_token
.id
=== ']') {
4607 warn('unexpected_a', token
);
4612 advance(']', bracket
);
4615 switch (next_token
.id
) {
4632 advance('(number)');
4635 stop('unexpected_a');
4642 function css_name() {
4643 if (next_token
.identifier
) {
4650 function css_number() {
4651 if (next_token
.id
=== '-') {
4655 if (next_token
.id
=== '(number)') {
4656 advance('(number)');
4662 function css_string() {
4663 if (next_token
.id
=== '(string)') {
4669 function css_color() {
4670 var i
, number
, paren
, value
;
4671 if (next_token
.identifier
) {
4672 value
= next_token
.string
;
4673 if (value
=== 'rgb' || value
=== 'rgba') {
4677 for (i
= 0; i
< 3; i
+= 1) {
4681 number
= next_token
.number
;
4682 if (next_token
.id
!== '(number)' || number
< 0) {
4683 warn('expected_positive_a', next_token
);
4687 if (next_token
.id
=== '%') {
4690 warn('expected_percent_a', token
, number
);
4694 warn('expected_small_a', token
, number
);
4699 if (value
=== 'rgba') {
4701 number
= next_token
.number
;
4702 if (next_token
.id
!== '(number)' || number
< 0 || number
> 1) {
4703 warn('expected_fraction_a', next_token
);
4706 if (next_token
.id
=== '%') {
4707 warn('unexpected_a');
4711 advance(')', paren
);
4714 if (css_colorData
[next_token
.string
] === true) {
4718 } else if (next_token
.id
=== '(color)') {
4726 function css_length() {
4727 if (next_token
.id
=== '-') {
4731 if (next_token
.id
=== '(number)') {
4733 if (next_token
.id
!== '(string)' &&
4734 css_lengthData
[next_token
.string
] === true) {
4737 } else if (+token
.number
!== 0) {
4738 warn('expected_linear_a');
4746 function css_line_height() {
4747 if (next_token
.id
=== '-') {
4751 if (next_token
.id
=== '(number)') {
4753 if (next_token
.id
!== '(string)' &&
4754 css_lengthData
[next_token
.string
] === true) {
4764 function css_width() {
4765 if (next_token
.identifier
) {
4766 switch (next_token
.string
) {
4774 return css_length();
4779 function css_margin() {
4780 if (next_token
.identifier
) {
4781 if (next_token
.string
=== 'auto') {
4786 return css_length();
4790 function css_attr() {
4791 if (next_token
.identifier
&& next_token
.string
=== 'attr') {
4794 if (!next_token
.identifier
) {
4795 warn('expected_name_a');
4805 function css_comma_list() {
4806 while (next_token
.id
!== ';') {
4807 if (!css_name() && !css_string()) {
4808 warn('expected_name_a');
4810 if (next_token
.id
!== ',') {
4818 function css_counter() {
4819 if (next_token
.identifier
&& next_token
.string
=== 'counter') {
4823 if (next_token
.id
=== ',') {
4825 if (next_token
.id
!== '(string)') {
4826 warn('expected_string_a');
4833 if (next_token
.identifier
&& next_token
.string
=== 'counters') {
4836 if (!next_token
.identifier
) {
4837 warn('expected_name_a');
4840 if (next_token
.id
=== ',') {
4842 if (next_token
.id
!== '(string)') {
4843 warn('expected_string_a');
4847 if (next_token
.id
=== ',') {
4849 if (next_token
.id
!== '(string)') {
4850 warn('expected_string_a');
4861 function css_radius() {
4862 return css_length() && (next_token
.id
!== '(number)' || css_length());
4866 function css_shape() {
4868 if (next_token
.identifier
&& next_token
.string
=== 'rect') {
4871 for (i
= 0; i
< 4; i
+= 1) {
4872 if (!css_length()) {
4873 warn('expected_number_a');
4884 function css_url() {
4886 if (next_token
.identifier
&& next_token
.string
=== 'url') {
4887 next_token
= lex
.range('(', ')');
4888 url
= next_token
.string
;
4890 if (c
=== '"' || c
=== '\'') {
4891 if (url
.slice(-1) !== c
) {
4894 url
= url
.slice(1, -1);
4895 if (url
.indexOf(c
) >= 0) {
4901 warn('missing_url');
4914 css_any
= [css_url
, function () {
4916 if (next_token
.identifier
) {
4917 switch (next_token
.string
.toLowerCase()) {
4922 warn('unexpected_a');
4929 if (next_token
.id
=== ';' || next_token
.id
=== '!' ||
4930 next_token
.id
=== '(end)' || next_token
.id
=== '}') {
4939 function font_face() {
4940 advance_identifier('font-family');
4942 if (!css_name() && !css_string()) {
4943 stop('expected_name_a');
4946 advance_identifier('src');
4949 if (next_token
.string
=== 'local') {
4950 advance_identifier('local');
4952 if (ux
.test(next_token
.string
)) {
4956 if (!css_name() && !css_string()) {
4957 stop('expected_name_a');
4960 } else if (!css_url()) {
4961 stop('expected_a_b', next_token
, 'url', artifact());
4963 if (next_token
.id
!== ',') {
4972 css_border_style
= [
4973 'none', 'dashed', 'dotted', 'double', 'groove',
4974 'hidden', 'inset', 'outset', 'ridge', 'solid'
4978 'auto', 'always', 'avoid', 'left', 'right'
4995 'auto', 'hidden', 'scroll', 'visible'
4998 css_attribute_data
= {
5000 true, 'background-attachment', 'background-color',
5001 'background-image', 'background-position', 'background-repeat'
5003 'background-attachment': ['scroll', 'fixed'],
5004 'background-color': ['transparent', css_color
],
5005 'background-image': ['none', css_url
],
5006 'background-position': [
5007 2, [css_length
, 'top', 'bottom', 'left', 'right', 'center']
5009 'background-repeat': [
5010 'repeat', 'repeat-x', 'repeat-y', 'no-repeat'
5012 'border': [true, 'border-color', 'border-style', 'border-width'],
5014 true, 'border-bottom-color', 'border-bottom-style',
5015 'border-bottom-width'
5017 'border-bottom-color': css_color
,
5018 'border-bottom-left-radius': css_radius
,
5019 'border-bottom-right-radius': css_radius
,
5020 'border-bottom-style': css_border_style
,
5021 'border-bottom-width': css_width
,
5022 'border-collapse': ['collapse', 'separate'],
5023 'border-color': ['transparent', 4, css_color
],
5025 true, 'border-left-color', 'border-left-style', 'border-left-width'
5027 'border-left-color': css_color
,
5028 'border-left-style': css_border_style
,
5029 'border-left-width': css_width
,
5030 'border-radius': function () {
5031 function count(separator
) {
5036 if (!css_length()) {
5039 while (next_token
.id
=== '(number)') {
5040 if (!css_length()) {
5051 return count() && (next_token
.id
!== '/' || count('/'));
5054 true, 'border-right-color', 'border-right-style',
5055 'border-right-width'
5057 'border-right-color': css_color
,
5058 'border-right-style': css_border_style
,
5059 'border-right-width': css_width
,
5060 'border-spacing': [2, css_length
],
5061 'border-style': [4, css_border_style
],
5063 true, 'border-top-color', 'border-top-style', 'border-top-width'
5065 'border-top-color': css_color
,
5066 'border-top-left-radius': css_radius
,
5067 'border-top-right-radius': css_radius
,
5068 'border-top-style': css_border_style
,
5069 'border-top-width': css_width
,
5070 'border-width': [4, css_width
],
5071 bottom: [css_length
, 'auto'],
5072 'caption-side' : ['bottom', 'left', 'right', 'top'],
5073 clear: ['both', 'left', 'none', 'right'],
5074 clip: [css_shape
, 'auto'],
5077 'open-quote', 'close-quote', 'no-open-quote', 'no-close-quote',
5078 css_string
, css_url
, css_counter
, css_attr
5080 'counter-increment': [
5087 css_url
, 'auto', 'crosshair', 'default', 'e-resize', 'help', 'move',
5088 'n-resize', 'ne-resize', 'nw-resize', 'pointer', 's-resize',
5089 'se-resize', 'sw-resize', 'w-resize', 'text', 'wait'
5091 direction: ['ltr', 'rtl'],
5093 'block', 'compact', 'inline', 'inline-block', 'inline-table',
5094 'list-item', 'marker', 'none', 'run-in', 'table', 'table-caption',
5095 'table-cell', 'table-column', 'table-column-group',
5096 'table-footer-group', 'table-header-group', 'table-row',
5099 'empty-cells': ['show', 'hide'],
5100 'float': ['left', 'none', 'right'],
5102 'caption', 'icon', 'menu', 'message-box', 'small-caption',
5103 'status-bar', true, 'font-size', 'font-style', 'font-weight',
5106 'font-family': css_comma_list
,
5108 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large',
5109 'xx-large', 'larger', 'smaller', css_length
5111 'font-size-adjust': ['none', css_number
],
5113 'normal', 'wider', 'narrower', 'ultra-condensed',
5114 'extra-condensed', 'condensed', 'semi-condensed',
5115 'semi-expanded', 'expanded', 'extra-expanded'
5118 'normal', 'italic', 'oblique'
5121 'normal', 'small-caps'
5124 'normal', 'bold', 'bolder', 'lighter', css_number
5126 height: [css_length
, 'auto'],
5127 left: [css_length
, 'auto'],
5128 'letter-spacing': ['normal', css_length
],
5129 'line-height': ['normal', css_line_height
],
5131 true, 'list-style-image', 'list-style-position', 'list-style-type'
5133 'list-style-image': ['none', css_url
],
5134 'list-style-position': ['inside', 'outside'],
5135 'list-style-type': [
5136 'circle', 'disc', 'square', 'decimal', 'decimal-leading-zero',
5137 'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha',
5138 'lower-latin', 'upper-alpha', 'upper-latin', 'hebrew', 'katakana',
5139 'hiragana-iroha', 'katakana-oroha', 'none'
5141 margin: [4, css_margin
],
5142 'margin-bottom': css_margin
,
5143 'margin-left': css_margin
,
5144 'margin-right': css_margin
,
5145 'margin-top': css_margin
,
5146 'marker-offset': [css_length
, 'auto'],
5147 'max-height': [css_length
, 'none'],
5148 'max-width': [css_length
, 'none'],
5149 'min-height': css_length
,
5150 'min-width': css_length
,
5151 opacity: css_number
,
5152 outline: [true, 'outline-color', 'outline-style', 'outline-width'],
5153 'outline-color': ['invert', css_color
],
5155 'dashed', 'dotted', 'double', 'groove', 'inset', 'none',
5156 'outset', 'ridge', 'solid'
5158 'outline-width': css_width
,
5159 overflow: css_overflow
,
5160 'overflow-x': css_overflow
,
5161 'overflow-y': css_overflow
,
5162 padding: [4, css_length
],
5163 'padding-bottom': css_length
,
5164 'padding-left': css_length
,
5165 'padding-right': css_length
,
5166 'padding-top': css_length
,
5167 'page-break-after': css_break
,
5168 'page-break-before': css_break
,
5169 position: ['absolute', 'fixed', 'relative', 'static'],
5170 quotes: [8, css_string
],
5171 right: [css_length
, 'auto'],
5172 'table-layout': ['auto', 'fixed'],
5173 'text-align': ['center', 'justify', 'left', 'right'],
5174 'text-decoration': [
5175 'none', 'underline', 'overline', 'line-through', 'blink'
5177 'text-indent': css_length
,
5178 'text-shadow': ['none', 4, [css_color
, css_length
]],
5179 'text-transform': ['capitalize', 'uppercase', 'lowercase', 'none'],
5180 top: [css_length
, 'auto'],
5181 'unicode-bidi': ['normal', 'embed', 'bidi-override'],
5183 'baseline', 'bottom', 'sub', 'super', 'top', 'text-top', 'middle',
5184 'text-bottom', css_length
5186 visibility: ['visible', 'hidden', 'collapse'],
5188 'normal', 'nowrap', 'pre', 'pre-line', 'pre-wrap', 'inherit'
5190 width: [css_length
, 'auto'],
5191 'word-spacing': ['normal', css_length
],
5192 'word-wrap': ['break-word', 'normal'],
5193 'z-index': ['auto', css_number
]
5196 function style_attribute() {
5198 while (next_token
.id
=== '*' || next_token
.id
=== '#' ||
5199 next_token
.string
=== '_') {
5201 warn('unexpected_a');
5205 if (next_token
.id
=== '-') {
5207 warn('unexpected_a');
5210 if (!next_token
.identifier
) {
5211 warn('expected_nonstandard_style_attribute');
5216 if (!next_token
.identifier
) {
5217 warn('expected_style_attribute');
5219 if (Object
.prototype.hasOwnProperty
.call(css_attribute_data
,
5220 next_token
.string
)) {
5221 v
= css_attribute_data
[next_token
.string
];
5225 warn('unrecognized_style_attribute_a');
5234 function style_value(v
) {
5246 if (next_token
.identifier
&& next_token
.string
=== v
) {
5253 if (i
>= v
.length
) {
5258 if (typeof vi
=== 'boolean') {
5260 } else if (typeof vi
=== 'number') {
5269 if (style_value(vi
)) {
5284 for (i
= start
; i
< v
.length
; i
+= 1) {
5286 if (style_value(css_attribute_data
[v
[i
]])) {
5300 function style_child() {
5301 if (next_token
.id
=== '(number)') {
5303 if (next_token
.string
=== 'n' && next_token
.identifier
) {
5306 if (next_token
.id
=== '+') {
5310 advance('(number)');
5315 if (next_token
.identifier
&&
5316 (next_token
.string
=== 'odd' || next_token
.string
=== 'even')) {
5320 warn('unexpected_a');
5323 function substyle() {
5326 if (next_token
.id
=== '}' || next_token
.id
=== '(end)' ||
5327 (xquote
&& next_token
.id
=== xquote
)) {
5330 v
= style_attribute();
5332 if (next_token
.identifier
&& next_token
.string
=== 'inherit') {
5335 if (!style_value(v
)) {
5336 warn('unexpected_a');
5340 if (next_token
.id
=== '!') {
5343 if (next_token
.identifier
&& next_token
.string
=== 'important') {
5346 warn('expected_a_b',
5347 next_token
, 'important', artifact());
5350 if (next_token
.id
=== '}' || next_token
.id
=== xquote
) {
5351 warn('expected_a_b', next_token
, ';', artifact());
5358 function style_selector() {
5359 if (next_token
.identifier
) {
5360 if (!Object
.prototype.hasOwnProperty
.call(html_tag
, option
.cap
5361 ? next_token
.string
.toLowerCase()
5362 : next_token
.string
)) {
5363 warn('expected_tagname_a');
5367 switch (next_token
.id
) {
5375 switch (next_token
.string
) {
5384 case 'first-letter':
5386 case 'first-of-type':
5390 case 'last-of-type':
5392 case 'only-of-type':
5396 advance_identifier(next_token
.string
);
5399 advance_identifier('lang');
5401 if (!next_token
.identifier
) {
5402 warn('expected_lang_a');
5407 case 'nth-last-child':
5408 case 'nth-last-of-type':
5410 advance_identifier(next_token
.string
);
5416 advance_identifier('not');
5418 if (next_token
.id
=== ':' && peek(0).string
=== 'not') {
5425 warn('expected_pseudo_a');
5430 if (!next_token
.identifier
) {
5431 warn('expected_id_a');
5440 if (!next_token
.identifier
) {
5441 warn('expected_class_a');
5447 if (!next_token
.identifier
) {
5448 warn('expected_attribute_a');
5451 if (next_token
.id
=== '=' || next_token
.string
=== '~=' ||
5452 next_token
.string
=== '$=' ||
5453 next_token
.string
=== '|=' ||
5454 next_token
.id
=== '*=' ||
5455 next_token
.id
=== '^=') {
5457 if (next_token
.id
!== '(string)') {
5458 warn('expected_string_a');
5465 stop('expected_selector_a');
5470 function style_pattern() {
5471 if (next_token
.id
=== '{') {
5472 warn('expected_style_pattern');
5476 if (next_token
.id
=== '</' || next_token
.id
=== '{' ||
5477 next_token
.id
=== '}' || next_token
.id
=== '(end)') {
5480 if (next_token
.id
=== ',') {
5486 function style_list() {
5487 while (next_token
.id
!== '}' && next_token
.id
!== '</' &&
5488 next_token
.id
!== '(end)') {
5490 xmode
= 'styleproperty';
5491 if (next_token
.id
=== ';') {
5504 while (next_token
.id
=== '@') {
5507 switch (next_token
.string
) {
5509 advance_identifier('import');
5511 warn('expected_a_b',
5512 next_token
, 'url', artifact());
5518 advance_identifier('media');
5520 if (!next_token
.identifier
|| css_media
[next_token
.string
] !== true) {
5521 stop('expected_media_a');
5524 if (next_token
.id
!== ',') {
5534 advance_identifier('font-face');
5540 stop('expected_at_a');
5549 function do_begin(n
) {
5550 if (n
!== 'html' && !option
.fragment
) {
5551 if (n
=== 'div' && option
.adsafe
) {
5552 stop('adsafe_fragment');
5554 stop('expected_a_b', token
, 'html', n
);
5557 if (option
.adsafe
) {
5559 stop('adsafe_html', token
);
5561 if (option
.fragment
) {
5563 stop('adsafe_div', token
);
5566 stop('adsafe_fragment', token
);
5569 option
.browser
= true;
5572 function do_attribute(a
, v
) {
5575 u
= typeof v
=== 'string' ? v
.toUpperCase() : '';
5576 if (ids
[u
] === true) {
5577 warn('duplicate_a', next_token
, v
);
5579 if (!/^[A-Za-z][A-Za-z0-9._:\-]*$/.test(v
)) {
5580 warn('bad_id_a', next_token
, v
);
5581 } else if (option
.adsafe
) {
5583 if (v
.slice(0, adsafe_id
.length
) !== adsafe_id
) {
5584 warn('adsafe_prefix_a', next_token
, adsafe_id
);
5585 } else if (!/^[A-Z]+_[A-Z]+$/.test(v
)) {
5586 warn('adsafe_bad_id');
5590 if (!/^[A-Z]+_$/.test(v
)) {
5591 warn('adsafe_bad_id');
5597 warn('unexpected_char_a_b', token
, v
.charAt(x
), a
);
5600 } else if (a
=== 'class' || a
=== 'type' || a
=== 'name') {
5603 warn('unexpected_char_a_b', token
, v
.charAt(x
), a
);
5606 } else if (a
=== 'href' || a
=== 'background' ||
5607 a
=== 'content' || a
=== 'data' ||
5608 a
.indexOf('src') >= 0 || a
.indexOf('url') >= 0) {
5609 if (option
.safe
&& ux
.test(v
)) {
5610 stop('bad_url_a', next_token
, v
);
5613 } else if (a
=== 'for') {
5614 if (option
.adsafe
) {
5616 if (v
.slice(0, adsafe_id
.length
) !== adsafe_id
) {
5617 warn('adsafe_prefix_a', next_token
, adsafe_id
);
5618 } else if (!/^[A-Z]+_[A-Z]+$/.test(v
)) {
5619 warn('adsafe_bad_id');
5622 warn('adsafe_bad_id');
5625 } else if (a
=== 'name') {
5626 if (option
.adsafe
&& v
.indexOf('_') >= 0) {
5627 warn('adsafe_name_a', next_token
, v
);
5632 function do_tag(name
, attribute
) {
5633 var i
, tag
= html_tag
[name
], script
, x
;
5637 bundle
.unrecognized_tag_a
,
5639 name
=== name
.toLowerCase()
5641 : name
+ ' (capitalization error)'
5644 if (stack
.length
> 0) {
5645 if (name
=== 'html') {
5646 stop('unexpected_a', token
, name
);
5650 if (x
.indexOf(' ' + stack
[stack
.length
- 1].name
+ ' ') < 0) {
5651 stop('tag_a_in_b', token
, name
, x
);
5653 } else if (!option
.adsafe
&& !option
.fragment
) {
5657 stop('tag_a_in_b', token
, name
, 'body');
5660 } while (stack
[i
].name
!== 'body');
5665 if (option
.adsafe
&& stack
.length
=== 1 && !adsafe_id
) {
5666 warn('adsafe_missing_id');
5672 if (attribute
.lang
) {
5673 warn('lang', token
);
5675 if (option
.adsafe
&& stack
.length
!== 1) {
5676 warn('adsafe_placement', token
);
5678 if (attribute
.src
) {
5679 if (option
.adsafe
&& (!adsafe_may
|| !approved
[attribute
.src
])) {
5680 warn('adsafe_source', token
);
5683 step_in(next_token
.from);
5687 script
= statements();
5689 // JSLint is also the static analyzer for ADsafe. See www.ADsafe.org.
5691 if (option
.adsafe
) {
5693 stop('adsafe_script', token
);
5695 if (script
.length
!== 1 ||
5696 aint(script
[0], 'id', '(') ||
5697 aint(script
[0].first
, 'id', '.') ||
5698 aint(script
[0].first
.first
, 'string', 'ADSAFE') ||
5699 aint(script
[0].second
[0], 'string', adsafe_id
)) {
5700 stop('adsafe_id_go');
5702 switch (script
[0].first
.second
.string
) {
5704 if (adsafe_may
|| adsafe_went
||
5705 script
[0].second
.length
!== 1) {
5706 stop('adsafe_id', next_token
);
5714 if (script
[0].second
.length
!== 2 ||
5715 aint(script
[0].second
[1], 'id', 'function') ||
5716 !script
[0].second
[1].first
||
5717 aint(script
[0].second
[1].first
[0], 'string', 'dom') ||
5718 script
[0].second
[1].first
.length
> 2 ||
5719 (script
[0].second
[1].first
.length
=== 2 &&
5720 aint(script
[0].second
[1].first
[1], 'string', 'lib'))) {
5721 stop('adsafe_go', next_token
);
5726 stop('adsafe_id_go');
5733 advance_identifier('script');
5742 advance_identifier('style');
5745 switch (attribute
.type
) {
5757 if (option
.adsafe
&& attribute
.autocomplete
!== 'off') {
5758 warn('adsafe_autocomplete');
5776 if (option
.adsafe
) {
5777 warn('adsafe_tag', next_token
, name
);
5784 function closetag(name
) {
5785 return '</' + name
+ '>';
5789 var attribute
, attributes
, is_empty
, name
, old_white
= option
.white
,
5790 quote
, tag_name
, tag
, wmode
;
5795 switch (next_token
.string
) {
5800 tag_name
= next_token
;
5801 name
= tag_name
.string
;
5802 advance_identifier(name
);
5804 name
= name
.toLowerCase();
5806 tag_name
.name
= name
;
5811 tag
= html_tag
[name
];
5812 if (typeof tag
!== 'object') {
5813 stop('unrecognized_tag_a', tag_name
, name
);
5815 is_empty
= tag
.empty
;
5816 tag_name
.type
= name
;
5818 if (next_token
.id
=== '/') {
5820 if (next_token
.id
!== '>') {
5821 warn('expected_a_b', next_token
, '>', artifact());
5825 if (next_token
.id
&& next_token
.id
.charAt(0) === '>') {
5828 if (!next_token
.identifier
) {
5829 if (next_token
.id
=== '(end)' || next_token
.id
=== '(error)') {
5830 warn('expected_a_b', next_token
, '>', artifact());
5834 option
.white
= false;
5836 attribute
= next_token
.string
;
5837 option
.white
= old_white
;
5839 if (!option
.cap
&& attribute
!== attribute
.toLowerCase()) {
5840 warn('attribute_case_a', token
);
5842 attribute
= attribute
.toLowerCase();
5844 if (Object
.prototype.hasOwnProperty
.call(attributes
, attribute
)) {
5845 warn('duplicate_a', token
, attribute
);
5847 if (attribute
.slice(0, 2) === 'on') {
5849 warn('html_handlers');
5851 xmode
= 'scriptstring';
5853 quote
= next_token
.id
;
5854 if (quote
!== '"' && quote
!== '\'') {
5855 stop('expected_a_b', next_token
, '"', artifact());
5858 wmode
= option
.white
;
5859 option
.white
= true;
5863 option
.white
= wmode
;
5864 if (next_token
.id
!== quote
) {
5865 stop('expected_a_b', next_token
, quote
, artifact());
5871 } else if (attribute
=== 'style') {
5872 xmode
= 'scriptstring';
5874 quote
= next_token
.id
;
5875 if (quote
!== '"' && quote
!== '\'') {
5876 stop('expected_a_b', next_token
, '"', artifact());
5878 xmode
= 'styleproperty';
5887 if (next_token
.id
=== '=') {
5889 tag
= next_token
.string
;
5890 if (!next_token
.identifier
&&
5891 next_token
.id
!== '"' &&
5892 next_token
.id
!== '\'' &&
5893 next_token
.id
!== '(string)' &&
5894 next_token
.id
!== '(string)' &&
5895 next_token
.id
!== '(color)') {
5896 warn('expected_attribute_value_a', token
, attribute
);
5903 attributes
[attribute
] = tag
;
5904 do_attribute(attribute
, tag
);
5906 do_tag(name
, attributes
);
5908 stack
.push(tag_name
);
5916 if (!next_token
.identifier
) {
5919 name
= next_token
.string
;
5921 name
= name
.toLowerCase();
5925 stop('unexpected_a', next_token
, closetag(name
));
5927 tag_name
= stack
.pop();
5929 stop('unexpected_a', next_token
, closetag(name
));
5931 if (tag_name
.name
!== name
) {
5932 stop('expected_a_b',
5933 next_token
, closetag(tag_name
.name
), closetag(name
));
5935 if (next_token
.id
!== '>') {
5936 stop('expected_a_b', next_token
, '>', artifact());
5948 if (next_token
.id
=== '>' || next_token
.id
=== '(end)') {
5951 if (next_token
.string
.indexOf('--') >= 0) {
5952 stop('unexpected_a', next_token
, '--');
5954 if (next_token
.string
.indexOf('<') >= 0) {
5955 stop('unexpected_a', next_token
, '<');
5957 if (next_token
.string
.indexOf('>') >= 0) {
5958 stop('unexpected_a', next_token
, '>');
5967 if (next_token
.id
=== '(end)') {
5968 stop('missing_a', next_token
,
5969 '</' + stack
[stack
.length
- 1].string
+ '>');
5974 if (stack
&& stack
.length
=== 0 && (option
.adsafe
||
5975 !option
.fragment
|| next_token
.id
=== '(end)')) {
5979 if (next_token
.id
!== '(end)') {
5980 stop('unexpected_a');
5985 // The actual JSLINT function itself.
5987 itself
= function JSLint(the_source
, the_option
) {
5989 var i
, predef
, tree
;
5992 begin
= prev_token
= token
= next_token
=
5993 Object
.create(syntax
['(begin)']);
5995 add_to_predefined(standard
);
5998 option
= Object
.create(the_option
);
5999 predef
= option
.predef
;
6001 if (Array
.isArray(predef
)) {
6002 for (i
= 0; i
< predef
.length
; i
+= 1) {
6003 predefined
[predef
[i
]] = true;
6005 } else if (typeof predef
=== 'object') {
6006 add_to_predefined(predef
);
6013 option
.indent
= +option
.indent
|| 4;
6014 option
.maxerr
= +option
.maxerr
|| 50;
6016 adsafe_may
= adsafe_top
= adsafe_went
= false;
6018 if (option
.approved
) {
6019 for (i
= 0; i
< option
.approved
.length
; i
+= 1) {
6020 approved
[option
.approved
[i
]] = option
.approved
[i
];
6023 approved
.test
= 'test';
6026 for (i
= 0; i
< option
.indent
; i
+= 1) {
6029 global_scope
= scope
= {};
6030 global_funct
= funct
= {
6035 functions
= [funct
];
6037 comments_off
= false;
6047 strict_mode
= false;
6052 lex
.init(the_source
);
6058 if (next_token
.id
=== '(number)') {
6059 stop('unexpected_a');
6060 } else if (next_token
.string
.charAt(0) === '<') {
6062 if (option
.adsafe
&& !adsafe_went
) {
6063 warn('adsafe_go', this);
6066 switch (next_token
.id
) {
6079 if (token
.id
!== '@' || !next_token
.identifier
||
6080 next_token
.string
!== 'charset' || token
.line
!== 1 ||
6085 if (next_token
.id
!== '(string)' &&
6086 next_token
.string
!== 'UTF-8') {
6095 if (option
.adsafe
&& option
.fragment
) {
6096 stop('expected_a_b',
6097 next_token
, '<div>', artifact());
6100 // If the first token is a semicolon, ignore it. This is sometimes used when
6101 // files are intended to be appended to files that may be sloppy. A sloppy
6102 // file may be depending on semicolon insertion on its last line.
6105 if (next_token
.id
=== ';' && !node_js
) {
6109 tree
= statements();
6111 JSLINT
.tree
= begin
;
6112 // infer_types(tree);
6113 if (option
.adsafe
&& (tree
.length
!== 1 ||
6114 aint(tree
[0], 'id', '(') ||
6115 aint(tree
[0].first
, 'id', '.') ||
6116 aint(tree
[0].first
.first
, 'string', 'ADSAFE') ||
6117 aint(tree
[0].first
.second
, 'string', 'lib') ||
6118 tree
[0].second
.length
!== 2 ||
6119 tree
[0].second
[0].id
!== '(string)' ||
6120 aint(tree
[0].second
[1], 'id', 'function'))) {
6124 warn('weird_program', prev_token
);
6132 JSLINT
.errors
.push({
6134 line : e
.line
|| next_token
.line
,
6135 character : e
.character
|| next_token
.from
6139 return JSLINT
.errors
.length
=== 0;
6145 itself
.data = function () {
6146 var data
= {functions: []},
6157 if (itself
.errors
.length
) {
6158 data
.errors
= itself
.errors
;
6165 if (urls
.length
> 0) {
6169 globals
= Object
.keys(global_scope
).filter(function (value
) {
6170 return value
.charAt(0) !== '(' && typeof standard
[value
] !== 'boolean';
6172 if (globals
.length
> 0) {
6173 data
.globals
= globals
;
6176 for (i
= 1; i
< functions
.length
; i
+= 1) {
6177 the_function
= functions
[i
];
6179 for (j
= 0; j
< functionicity
.length
; j
+= 1) {
6180 function_data
[functionicity
[j
]] = [];
6182 for (name
in the_function
) {
6183 if (Object
.prototype.hasOwnProperty
.call(the_function
, name
)) {
6184 if (name
.charAt(0) !== '(') {
6185 kind
= the_function
[name
];
6186 if (kind
=== 'unction' || kind
=== 'unparam') {
6189 if (Array
.isArray(function_data
[kind
])) {
6190 function_data
[kind
].push(name
);
6191 if (kind
=== 'unused') {
6194 line: the_function
['(line)'],
6195 'function': the_function
['(name)']
6197 } else if (kind
=== 'undef') {
6200 line: the_function
['(line)'],
6201 'function': the_function
['(name)']
6208 for (j
= 0; j
< functionicity
.length
; j
+= 1) {
6209 if (function_data
[functionicity
[j
]].length
=== 0) {
6210 delete function_data
[functionicity
[j
]];
6213 function_data
.name
= the_function
['(name)'];
6214 function_data
.params
= the_function
['(params)'];
6215 function_data
.line
= the_function
['(line)'];
6216 data
.functions
.push(function_data
);
6219 if (unused
.length
> 0) {
6220 data
.unused
= unused
;
6222 if (undef
.length
> 0) {
6223 data
['undefined'] = undef
;
6227 for (name
in property
) {
6228 if (typeof property
[name
] === 'number') {
6229 data
.member
= property
;
6238 itself
.report = function (errors_only
) {
6239 var data
= itself
.data(), err
, evidence
, i
, italics
, j
, key
, keys
,
6240 length
, mem
= '', name
, names
, not_first
, output
= [], snippets
,
6241 the_function
, warning
;
6243 function detail(h
, value
) {
6244 var comma_needed
, singularity
;
6245 if (Array
.isArray(value
)) {
6246 output
.push('<div><i>' + h
+ '</i> ');
6247 value
.sort().forEach(function (item
) {
6248 if (item
!== singularity
) {
6250 output
.push((comma_needed
? ', ' : '') + singularity
);
6251 comma_needed
= true;
6254 output
.push('</div>');
6256 output
.push('<div><i>' + h
+ '</i> ' + value
+ '</div>');
6260 if (data
.errors
|| data
.unused
|| data
['undefined']) {
6262 output
.push('<div id=errors><i>Error:</i>');
6264 for (i
= 0; i
< data
.errors
.length
; i
+= 1) {
6265 warning
= data
.errors
[i
];
6267 evidence
= warning
.evidence
|| '';
6268 output
.push('<p>Problem' + (isFinite(warning
.line
)
6269 ? ' at line ' + String(warning
.line
) +
6270 ' character ' + String(warning
.character
)
6272 ': ' + warning
.reason
.entityify() +
6273 '</p><p class=evidence>' +
6274 (evidence
&& (evidence
.length
> 80
6275 ? evidence
.slice(0, 77) + '...'
6276 : evidence
).entityify()) + '</p>');
6281 if (data
['undefined']) {
6283 for (i
= 0; i
< data
['undefined'].length
; i
+= 1) {
6284 snippets
[i
] = '<code><u>' + data
['undefined'][i
].name
+ '</u></code> <i>' +
6285 String(data
['undefined'][i
].line
) + ' </i> <small>' +
6286 data
['undefined'][i
]['function'] + '</small>';
6288 output
.push('<p><i>Undefined variable:</i> ' + snippets
.join(', ') + '</p>');
6292 for (i
= 0; i
< data
.unused
.length
; i
+= 1) {
6293 snippets
[i
] = '<code><u>' + data
.unused
[i
].name
+ '</u></code> <i>' +
6294 String(data
.unused
[i
].line
) + ' </i> <small>' +
6295 data
.unused
[i
]['function'] + '</small>';
6297 output
.push('<p><i>Unused variable:</i> ' + snippets
.join(', ') + '</p>');
6300 output
.push('<p>JSON: bad.</p>');
6302 output
.push('</div>');
6307 output
.push('<br><div id=functions>');
6310 detail("URLs<br>", data
.urls
, '<br>');
6313 if (xmode
=== 'style') {
6314 output
.push('<p>CSS.</p>');
6315 } else if (data
.json
&& !err
) {
6316 output
.push('<p>JSON: good.</p>');
6317 } else if (data
.globals
) {
6318 output
.push('<div><i>Global</i> ' +
6319 data
.globals
.sort().join(', ') + '</div>');
6321 output
.push('<div><i>No new global variables introduced.</i></div>');
6324 for (i
= 0; i
< data
.functions
.length
; i
+= 1) {
6325 the_function
= data
.functions
[i
];
6327 if (the_function
.params
) {
6328 for (j
= 0; j
< the_function
.params
.length
; j
+= 1) {
6329 names
[j
] = the_function
.params
[j
].string
;
6332 output
.push('<br><div class=function><i>' +
6333 String(the_function
.line
) + '</i> ' +
6334 the_function
.name
.entityify() +
6335 '(' + names
.join(', ') + ')</div>');
6336 detail('<big><b>Undefined</b></big>', the_function
['undefined']);
6337 detail('<big><b>Unused</b></big>', the_function
.unused
);
6338 detail('Closure', the_function
.closure
);
6339 detail('Variable', the_function
['var']);
6340 detail('Exception', the_function
.exception
);
6341 detail('Outer', the_function
.outer
);
6342 detail('Global', the_function
.global
);
6343 detail('Label', the_function
.label
);
6347 keys
= Object
.keys(data
.member
);
6350 output
.push('<br><pre id=properties>/*properties<br>');
6355 for (i
= 0; i
< keys
.length
; i
+= 1) {
6357 if (data
.member
[key
] > 0) {
6363 : '\'' + key
.entityify().replace(nx
, sanitize
) + '\'';
6364 length
+= name
.length
+ 2;
6365 if (data
.member
[key
] === 1) {
6366 name
= '<i>' + name
+ '</i>';
6370 if (mem
.length
+ name
.length
- (italics
* 7) > 80) {
6371 output
.push(mem
+ '<br>');
6380 output
.push(mem
+ '<br>*/</pre>');
6382 output
.push('</div>');
6385 return output
.join('');
6387 itself
.jslint
= itself
;
6389 itself
.edition
= '2012-02-23';