5 Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
7 Permission is hereby granted, free of charge, to any person obtaining a copy of
8 this software and associated documentation files (the "Software"), to deal in
9 the Software without restriction, including without limitation the rights to
10 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11 of the Software, and to permit persons to whom the Software is furnished to do
12 so, subject to the following conditions:
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
17 The Software shall be used for Good, not Evil.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 JSLINT is a global function. It takes two parameters.
31 var myResult = JSLINT(source, option);
33 The first parameter is either a string or an array of strings. If it is a
34 string, it will be split on '\n' or '\r'. If it is an array of strings, it
35 is assumed that each string represents one line. The source can be a
36 JavaScript text, or HTML text, or a JSON text, or a CSS text.
38 The second parameter is an optional object of options which control the
39 operation of JSLINT. Most of the options are booleans: They are all
40 optional and have a default value of false. One of the options, predef,
41 can be an array of names, which will be used to declare global variables,
42 or an object whose keys are used as global names, with a boolean value
43 that determines if they are assignable.
45 If it checks out, JSLINT returns true. Otherwise, it returns false.
47 If false, you can inspect JSLINT.errors to find out the problems.
48 JSLINT.errors is an array of objects containing these properties:
51 line : The line (relative to 0) at which the lint was found
52 character : The character (relative to 0) at which the lint was found
54 evidence : The text line in which the problem occurred
55 raw : The raw message before the details were inserted
62 If a fatal error was found, a null will be the last element of the
65 You can request a Function Report, which shows all of the functions
66 and the parameters and vars that they use. This can be used to find
67 implied global variables and other problems. The report is in HTML and
68 can be inserted in an HTML <body>.
70 var myReport = JSLINT.report(errors_only);
72 If errors_only is true, then the report will be limited to only errors.
74 You can request a data structure which contains JSLint's results.
76 var myData = JSLINT.data();
78 It returns a structure with this form:
142 Empty arrays will not be included.
144 You can obtain the parse tree that JSLint constructed while parsing. The
145 latest tree is kept in JSLINT.tree. A nice stringication can be produced
148 JSON.stringify(JSLINT.tree, [
149 'value', 'arity', 'name', 'first',
150 'second', 'third', 'block', 'else'
156 JSLint provides three directives. They look like slashstar comments, and
157 allow for setting options, declaring global variables, and establishing a
158 set of allowed property names.
160 These directives respect function scope.
164 The jslint directive is a special comment that can set one or more options.
165 The current option set is
167 adsafe true, if ADsafe rules should be enforced
168 bitwise true, if bitwise operators should not be allowed
169 browser true, if the standard browser globals should be predefined
170 cap true, if upper case HTML should be allowed
171 'continue' true, if the continuation statement should be tolerated
172 css true, if CSS workarounds should be tolerated
173 debug true, if debugger statements should be allowed
174 devel true, if logging should be allowed (console, alert, etc.)
175 es5 true, if ES5 syntax should be allowed
176 evil true, if eval should be allowed
177 forin true, if for in statements need not filter
178 fragment true, if HTML fragments should be allowed
179 indent the indentation factor
180 maxerr the maximum number of errors to allow
181 maxlen the maximum length of a source line
182 newcap true, if constructor names must be capitalized
183 nomen true, if names should be checked
184 on true, if HTML event handlers should be allowed
185 onevar true, if only one var statement per function should be allowed
186 passfail true, if the scan should stop on first error
187 plusplus true, if increment/decrement should not be allowed
188 regexp true, if the . should not be allowed in regexp literals
189 rhino true, if the Rhino environment globals should be predefined
190 undef true, if variables should be declared before used
191 safe true, if use of some browser features should be restricted
192 windows true, if MS Windows-specigic globals should be predefined
193 strict true, require the "use strict"; pragma
194 sub true, if all forms of subscript notation are tolerated
195 white true, if strict whitespace rules apply
196 widget true if the Yahoo Widgets globals should be predefined
203 evil: true, nomen: false, onevar: false, regexp: false, strict: true
207 The properties directive declares an exclusive list of property names.
208 Any properties named in the program that are not in the list will
214 /*properties "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "'",
215 "(begin)", "(breakage)", "(context)", "(error)", "(global)",
216 "(identifier)", "(line)", "(loopage)", "(name)", "(onevar)", "(params)",
217 "(scope)", "(statement)", "(token)", "(verb)", ")", "*", "+", "-", "\/",
218 ";", "<", "<=", "==", "===", ">", ">=", ADSAFE, ActiveXObject,
219 Array, Boolean, COM, CScript, Canvas, CustomAnimation, Date, Debug, E,
220 Enumerator, Error, EvalError, FadeAnimation, Flash, FormField, Frame,
221 Function, HotKey, Image, JSON, LN10, LN2, LOG10E, LOG2E, MAX_VALUE,
222 MIN_VALUE, Math, MenuItem, MoveAnimation, NEGATIVE_INFINITY, Number,
223 Object, Option, PI, POSITIVE_INFINITY, Point, RangeError, Rectangle,
224 ReferenceError, RegExp, ResizeAnimation, RotateAnimation, SQRT1_2,
225 SQRT2, ScrollBar, String, Style, SyntaxError, System, Text, TextArea,
226 Timer, TypeError, URIError, URL, VBArray, WScript, Web, Window, XMLDOM,
227 XMLHttpRequest, "\\", a, a_function, a_label, a_not_allowed,
228 a_not_defined, a_scope, abbr, acronym, activeborder, activecaption,
229 address, adsafe, adsafe_a, adsafe_autocomplete, adsafe_bad_id,
230 adsafe_div, adsafe_fragment, adsafe_go, adsafe_html, adsafe_id,
231 adsafe_id_go, adsafe_lib, adsafe_lib_second, adsafe_missing_id,
232 adsafe_name_a, adsafe_placement, adsafe_prefix_a, adsafe_script,
233 adsafe_source, adsafe_subscript_a, adsafe_tag, alert, aliceblue, all,
234 already_defined, and, animator, antiquewhite, appleScript, applet,
235 apply, approved, appworkspace, aqua, aquamarine, area, arguments, arity,
236 article, aside, assign, assign_exception,
237 assignment_function_expression, at, attribute_case_a, audio,
238 autocomplete, avoid_a, azure, b, background, "background-attachment",
239 "background-color", "background-image", "background-position",
240 "background-repeat", bad_assignment, bad_color_a, bad_constructor,
241 bad_entity, bad_html, bad_id_a, bad_in_a, bad_invocation, bad_name_a,
242 bad_new, bad_number, bad_operand, bad_type, bad_url, bad_wrap, base,
243 bdo, beep, beige, big, bisque, bitwise, black, blanchedalmond, block,
244 blockquote, blue, blueviolet, body, border, "border-bottom",
245 "border-bottom-color", "border-bottom-style", "border-bottom-width",
246 "border-collapse", "border-color", "border-left", "border-left-color",
247 "border-left-style", "border-left-width", "border-right",
248 "border-right-color", "border-right-style", "border-right-width",
249 "border-spacing", "border-style", "border-top", "border-top-color",
250 "border-top-style", "border-top-width", "border-width", bottom, br,
251 braille, brown, browser, burlywood, button, buttonface, buttonhighlight,
252 buttonshadow, buttontext, bytesToUIString, c, cadetblue, call, callee,
253 caller, canvas, cap, caption, "caption-side", captiontext, center,
254 charAt, charCodeAt, character, chartreuse, chocolate, chooseColor,
255 chooseFile, chooseFolder, cite, clear, clearInterval, clearTimeout,
256 clip, closeWidget, closure, cm, code, col, colgroup, color, combine_var,
257 command, comments, concat, conditional_assignment, confirm, confusing_a,
258 confusing_regexp, console, constructor, constructor_name_a, content,
259 continue, control_a, convertPathToHFS, convertPathToPlatform, coral,
260 cornflowerblue, cornsilk, "counter-increment", "counter-reset", create,
261 crimson, css, cursor, cyan, d, dangerous_comment, dangling_a, darkblue,
262 darkcyan, darkgoldenrod, darkgray, darkgreen, darkkhaki, darkmagenta,
263 darkolivegreen, darkorange, darkorchid, darkred, darksalmon,
264 darkseagreen, darkslateblue, darkslategray, darkturquoise, darkviolet,
265 data, datalist, dd, debug, decodeURI, decodeURIComponent, deeppink,
266 deepskyblue, defineClass, del, deleted, deserialize, details, devel,
267 dfn, dialog, dimgray, dir, direction, display, disrupt, div, dl,
268 document, dodgerblue, dt, duplicate_a, edge, edition, else, em, embed,
269 embossed, empty, "empty-cells", empty_block, empty_case, empty_class,
270 encodeURI, encodeURIComponent, entityify, errors, es5, escape, eval,
271 event, evidence, evil, ex, exception, exec, expected_a,
272 expected_a_at_b_c, expected_a_b, expected_a_b_from_c_d, expected_at_a,
273 expected_attribute_a, expected_attribute_value_a, expected_class_a,
274 expected_fraction_a, expected_id_a, expected_identifier_a,
275 expected_identifier_a_reserved, expected_lang_a, expected_linear_a,
276 expected_media_a, expected_name_a, expected_nonstandard_style_attribute,
277 expected_number_a, expected_operator_a, expected_percent_a,
278 expected_positive_a, expected_pseudo_a, expected_selector_a,
279 expected_small_a, expected_space_a_b, expected_string_a,
280 expected_style_attribute, expected_style_pattern, expected_tagname_a,
281 fieldset, figure, filesystem, filter, firebrick, first, float, floor,
282 floralwhite, focusWidget, font, "font-family", "font-size",
283 "font-size-adjust", "font-stretch", "font-style", "font-variant",
284 "font-weight", footer, for_if, forestgreen, forin, form, fragment,
285 frame, frames, frameset, from, fromCharCode, fuchsia, fud, funct,
286 function, function_block, function_eval, function_loop,
287 function_statement, function_strict, functions, g, gainsboro, gc,
288 get_set, ghostwhite, global, globals, gold, goldenrod, gray, graytext,
289 green, greenyellow, h1, h2, h3, h4, h5, h6, handheld, hasOwnProperty,
290 head, header, height, help, hgroup, highlight, highlighttext, history,
291 honeydew, hotpink, hr, "hta:application", html, html_confusion_a,
292 html_handlers, i, iTunes, id, identifier, identifier_function, iframe,
293 img, immed, implied_evil, implieds, in, inactiveborder, inactivecaption,
294 inactivecaptiontext, include, indent, indexOf, indianred, indigo,
295 infix_in, infobackground, infotext, init, input, ins, insecure_a,
296 isAlpha, isApplicationRunning, isArray, isDigit, isFinite, isNaN, ivory,
297 join, jslint, json, kbd, keygen, keys, khaki, konfabulatorVersion,
298 label, label_a_b, labeled, lang, lavender, lavenderblush, lawngreen,
299 lbp, leading_decimal_a, led, left, legend, lemonchiffon, length,
300 "letter-spacing", li, lib, lightblue, lightcoral, lightcyan,
301 lightgoldenrodyellow, lightgreen, lightpink, lightsalmon, lightseagreen,
302 lightskyblue, lightslategray, lightsteelblue, lightyellow, lime,
303 limegreen, line, "line-height", linen, link, "list-style",
304 "list-style-image", "list-style-position", "list-style-type", load,
305 loadClass, location, log, m, magenta, map, margin, "margin-bottom",
306 "margin-left", "margin-right", "margin-top", mark, "marker-offset",
307 maroon, match, "max-height", "max-width", maxerr, maxlen, md5,
308 mediumaquamarine, mediumblue, mediumorchid, mediumpurple,
309 mediumseagreen, mediumslateblue, mediumspringgreen, mediumturquoise,
310 mediumvioletred, member, menu, menutext, message, meta, meter,
311 midnightblue, "min-height", "min-width", mintcream, missing_a,
312 missing_a_after_b, missing_option, missing_property, missing_space_a_b,
313 missing_url, missing_use_strict, mistyrose, mixed, mm, moccasin, mode,
314 move_invocation, move_var, name, name_function, nav, navajowhite,
315 navigator, navy, nested_comment, newcap, next, noframes, nomen,
316 noscript, not, not_a_constructor, not_a_defined, not_a_function, not_a_label,
317 not_a_scope, not_greater, nud, object, ol, oldlace, olive, olivedrab,
318 on, onevar, opacity, open, openURL, opera, optgroup, option, orange,
319 orangered, orchid, outer, outline, "outline-color", "outline-style",
320 "outline-width", output, overflow, "overflow-x", "overflow-y", p,
321 padding, "padding-bottom", "padding-left", "padding-right",
322 "padding-top", "page-break-after", "page-break-before", palegoldenrod,
323 palegreen, paleturquoise, palevioletred, papayawhip, param,
324 parameter_a_get_b, parameter_set_a, paren, parent, parseFloat, parseInt,
325 passfail, pc, peachpuff, peru, pink, play, plum, plusplus, pop,
326 popupMenu, position, postcomments, postscript, powderblue, pre, predef,
327 preferenceGroups, preferences, prev, print, progress, projection,
328 prompt, prototype, pt, purple, push, px, q, quit, quote, quotes, radix,
329 random, range, raw, readFile, readUrl, read_only, reason, red,
330 redefinition_a, regexp, reloadWidget, replace, report, reserved,
331 reserved_a, resolvePath, resumeUpdates, rhino, right, rosybrown,
332 royalblue, rp, rt, ruby, runCommand, runCommandInBg, saddlebrown, safe,
333 salmon, samp, sandybrown, saveAs, savePreferences, scanned_a_b, screen,
334 script, scrollbar, seagreen, seal, search, seashell, second, section,
335 select, serialize, setInterval, setTimeout, shift,
336 showWidgetPreferences, sienna, silver, skyblue, slash_equal, slateblue,
337 slategray, sleep, slice, small, snow, sort, source, span, spawn, speak,
338 speech, split, springgreen, src, stack, statement_block, steelblue,
339 stopping, strange_loop, strict, strong, style, styleproperty, sub,
340 subscript, substr, sup, supplant, suppressUpdates, sync, system, table,
341 "table-layout", tag_a_in_b, tan, tbody, td, teal, tellWidget, test,
342 "text-align", "text-decoration", "text-indent", "text-shadow",
343 "text-transform", textarea, tfoot, th, thead, third, thistle,
344 threeddarkshadow, threedface, threedhighlight, threedlightshadow,
345 threedshadow, thru, time, title, toLowerCase, toString, toUpperCase,
346 toint32, token, tomato, too_long, too_many, top, tr, trailing_decimal_a,
347 tree, tt, tty, turquoise, tv, type, u, ul, unclosed, unclosed_comment,
348 unclosed_regexp, undef, unescape, unescaped_a, unexpected_a,
349 unexpected_char_a_b, unexpected_comment, unexpected_member_a,
350 unexpected_space_a_b, "unicode-bidi", unnecessary_initialize,
351 unnecessary_use, unreachable_a_b, unrecognized_style_attribute_a,
352 unrecognized_tag_a, unsafe, unused, unwatch, updateNow, url, urls,
353 use_array, use_braces, use_object, used_before_a, value, valueOf, var,
354 var_a_not, version, "vertical-align", video, violet, visibility, was,
355 watch, weird_assignment, weird_condition, weird_new, weird_program,
356 weird_relation, weird_ternary, wheat, white, "white-space", whitesmoke,
357 widget, width, window, windowframe, windows, windowtext, "word-spacing",
358 "word-wrap", wrap, wrap_immediate, wrap_regexp, write_is_wrong,
359 yahooCheckLogin, yahooLogin, yahooLogout, yellow, yellowgreen,
364 The global directive is used to declare global variables that can
365 be accessed by the program. If a declaration is true, then the variable
366 is writeable. Otherwise, it is read-only.
369 // We build the application inside a function so that we produce only a single
370 // global variable. That function will be invoked immediately, and its return
371 // value is the JSLINT function itself. That function is also an object that
372 // can contain data and other functions.
374 var JSLINT = (function () {
377 var adsafe_id, // The widget's ADsafe id.
378 adsafe_may, // The widget may load approved scripts.
379 adsafe_top, // At the top of the widget script.
380 adsafe_went, // ADSAFE.go has been called.
381 anonname, // The guessed name for anonymous functions.
382 approved, // ADsafe approved urls.
384 // These are operators that should not be used with the ! operator.
402 // These are property names that should not be permitted in the safe subset.
417 // browser contains a set of global names that are commonly provided by a
418 // web browser environment. self and window are intentially excluded because
419 // of the high likelihood for misue.
422 clearInterval : false,
423 clearTimeout : false,
437 XMLHttpRequest : false
440 // bundle contains the text messages.
443 a_function: "'{a}' is a function.",
444 a_label: "'{a}' is a statement label.",
445 a_not_allowed: "'{a}' is not allowed.",
446 a_not_defined: "'{a}' is not defined.",
447 a_scope: "'{a}' used out of scope.",
448 adsafe: "ADsafe violation.",
449 adsafe_a: "ADsafe violation: '{a}'.",
450 adsafe_autocomplete: "ADsafe autocomplete violation.",
451 adsafe_bad_id: "ADSAFE violation: bad id.",
452 adsafe_div: "ADsafe violation: Wrap the widget in a div.",
453 adsafe_fragment: "ADSAFE: Use the fragment option.",
454 adsafe_go: "ADsafe violation: Missing ADSAFE.go.",
455 adsafe_html: "Currently, ADsafe does not operate on whole HTML documents. It operates on <div> fragments and .js files.",
456 adsafe_id: "ADsafe violation: id does not match.",
457 adsafe_id_go: "ADsafe violation: Missing ADSAFE.id or ADSAFE.go.",
458 adsafe_lib: "ADsafe lib violation.",
459 adsafe_lib_second: "ADsafe: The second argument to lib must be a function.",
460 adsafe_missing_id: "ADSAFE violation: missing ID_.",
461 adsafe_name_a: "ADsafe name violation: '{a}'.",
462 adsafe_placement: "ADsafe script placement violation.",
463 adsafe_prefix_a: "ADsafe violation: An id must have a '{a}' prefix",
464 adsafe_script: "ADsafe script violation.",
465 adsafe_source: "ADsafe unapproved script source.",
466 adsafe_subscript_a: "ADsafe subscript '{a}'.",
467 adsafe_tag: "ADsafe violation: Disallowed tag '{a}'.",
468 already_defined: "'{a}' is already defined.",
469 and: "The '&&' subexpression should be wrapped in parens.",
470 assign_exception: "Do not assign to the exception parameter.",
471 assignment_function_expression: "Expected an assignment or function call and instead saw an expression.",
472 attribute_case_a: "Attribute '{a}' not all lower case.",
473 avoid_a: "Avoid '{a}'.",
474 bad_assignment: "Bad assignment.",
475 bad_color_a: "Bad hex color '{a}'.",
476 bad_constructor: "Bad constructor.",
477 bad_entity: "Bad entity.",
478 bad_html: "Bad HTML string",
479 bad_id_a: "Bad id: '{a}'.",
480 bad_in_a: "Bad for in variable '{a}'.",
481 bad_invocation: "Bad invocation.",
482 bad_name_a: "Bad name: '{a}'.",
483 bad_new: "Do not use 'new' for side effects.",
484 bad_number: "Bad number '{a}'.",
485 bad_operand: "Bad operand.",
486 bad_type: "Bad type.",
487 bad_url: "Bad url string.",
488 bad_wrap: "Do not wrap function literals in parens unless they are to be immediately invoked.",
489 combine_var: "Combine this with the previous 'var' statement.",
490 conditional_assignment: "Expected a conditional expression and instead saw an assignment.",
491 confusing_a: "Confusing use of '{a}'.",
492 confusing_regexp: "Confusing regular expression.",
493 constructor_name_a: "A constructor name '{a}' should start with an uppercase letter.",
494 control_a: "Unexpected control character '{a}'.",
495 css: "A css file should begin with @charset 'UTF-8';",
496 dangling_a: "Unexpected dangling '_' in '{a}'.",
497 dangerous_comment: "Dangerous comment.",
498 deleted: "Only properties should be deleted.",
499 duplicate_a: "Duplicate '{a}'.",
500 empty_block: "Empty block.",
501 empty_case: "Empty case.",
502 empty_class: "Empty class.",
503 evil: "eval is evil.",
504 expected_a: "Expected '{a}'.",
505 expected_a_b: "Expected '{a}' and instead saw '{b}'.",
506 expected_a_b_from_c_d: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
507 expected_at_a: "Expected an at-rule, and instead saw @{a}.",
508 expected_a_at_b_c: "Expected '{a}' at column {b}, not column {c}.",
509 expected_attribute_a: "Expected an attribute, and instead saw [{a}].",
510 expected_attribute_value_a: "Expected an attribute value and instead saw '{a}'.",
511 expected_class_a: "Expected a class, and instead saw .{a}.",
512 expected_fraction_a: "Expected a number between 0 and 1 and instead saw '{a}'",
513 expected_id_a: "Expected an id, and instead saw #{a}.",
514 expected_identifier_a: "Expected an identifier and instead saw '{a}'.",
515 expected_identifier_a_reserved: "Expected an identifier and instead saw '{a}' (a reserved word).",
516 expected_linear_a: "Expected a linear unit and instead saw '{a}'.",
517 expected_lang_a: "Expected a lang code, and instead saw :{a}.",
518 expected_media_a: "Expected a CSS media type, and instead saw '{a}'.",
519 expected_name_a: "Expected a name and instead saw '{a}'.",
520 expected_nonstandard_style_attribute: "Expected a non-standard style attribute and instead saw '{a}'.",
521 expected_number_a: "Expected a number and instead saw '{a}'.",
522 expected_operator_a: "Expected an operator and instead saw '{a}'.",
523 expected_percent_a: "Expected a percentage and instead saw '{a}'",
524 expected_positive_a: "Expected a positive number and instead saw '{a}'",
525 expected_pseudo_a: "Expected a pseudo, and instead saw :{a}.",
526 expected_selector_a: "Expected a CSS selector, and instead saw {a}.",
527 expected_small_a: "Expected a small number and instead saw '{a}'",
528 expected_space_a_b: "Expected exactly one space between '{a}' and '{b}'.",
529 expected_string_a: "Expected a string and instead saw {a}.",
530 expected_style_attribute: "Excepted a style attribute, and instead saw '{a}'.",
531 expected_style_pattern: "Expected a style pattern, and instead saw '{a}'.",
532 expected_tagname_a: "Expected a tagName, and instead saw {a}.",
533 for_if: "The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.",
534 function_block: "Function statements should not be placed in blocks. " +
535 "Use a function expression or move the statement to the top of " +
536 "the outer function.",
537 function_eval: "The Function constructor is eval.",
538 function_loop: "Don't make functions within a loop.",
539 function_statement: "Function statements are not invocable. " +
540 "Wrap the whole function invocation in parens.",
541 function_strict: "Use the function form of \"use strict\".",
542 get_set: "get/set are ES5 features.",
543 html_confusion_a: "HTML confusion in regular expression '<{a}'.",
544 html_handlers: "Avoid HTML event handlers.",
545 identifier_function: "Expected an identifier in an assignment and instead saw a function invocation.",
546 implied_evil: "Implied eval is evil. Pass a function instead of a string.",
547 infix_in: "Unexpected 'in'. Compare with undefined, or use the hasOwnProperty method instead.",
548 insecure_a: "Insecure '{a}'.",
549 isNaN: "Use the isNaN function to compare with NaN.",
550 label_a_b: "Label '{a}' on '{b}' statement.",
551 lang: "lang is deprecated.",
552 leading_decimal_a: "A leading decimal point can be confused with a dot: '.{a}'.",
553 missing_a: "Missing '{a}'.",
554 missing_a_after_b: "Missing '{a}' after '{b}'.",
555 missing_option: "Missing option value.",
556 missing_property: "Missing property name.",
557 missing_space_a_b: "Missing space between '{a}' and '{b}'.",
558 missing_url: "Missing url.",
559 missing_use_strict: "Missing \"use strict\" statement.",
560 mixed: "Mixed spaces and tabs.",
561 move_invocation: "Move the invocation into the parens that contain the function.",
562 move_var: "Move 'var' declarations to the top of the function.",
563 name_function: "Missing name in function statement.",
564 nested_comment: "Nested comment.",
566 not_a_constructor: "Do not use {a} as a constructor.",
567 not_a_defined: "'{a}' has not been fully defined yet.",
568 not_a_function: "'{a}' is not a function.",
569 not_a_label: "'{a}' is not a label.",
570 not_a_scope: "'{a}' is out of scope.",
571 not_greater: "'{a}' should not be greater than '{b}'.",
572 parameter_a_get_b: "Unexpected parameter '{a}' in get {b} function.",
573 parameter_set_a: "Expected parameter (value) in set {a} function.",
574 radix: "Missing radix parameter.",
575 read_only: "Read only.",
576 redefinition_a: "Redefinition of '{a}'.",
577 reserved_a: "Reserved name '{a}'.",
578 scanned_a_b: "{a} ({b}% scanned).",
579 slash_equal: "A regular expression literal can be confused with '/='.",
580 statement_block: "Expected to see a statement and instead saw a block.",
581 stopping: "Stopping. ",
582 strange_loop: "Strange loop.",
583 strict: "Strict violation.",
584 subscript: "['{a}'] is better written in dot notation.",
585 tag_a_in_b: "A '<{a}>' must be within '<{b}>'.",
586 too_long: "Line too long.",
587 too_many: "Too many errors.",
588 trailing_decimal_a: "A trailing decimal point can be confused with a dot: '.{a}'.",
589 type: "type is unnecessary.",
590 unclosed: "Unclosed string.",
591 unclosed_comment: "Unclosed comment.",
592 unclosed_regexp: "Unclosed regular expression.",
593 unescaped_a: "Unescaped '{a}'.",
594 unexpected_a: "Unexpected '{a}'.",
595 unexpected_char_a_b: "Unexpected character '{a}' in {b}.",
596 unexpected_comment: "Unexpected comment.",
597 unexpected_member_a: "Unexpected property '{a}'.",
598 unexpected_space_a_b: "Unexpected space between '{a}' and '{b}'.",
599 unnecessary_initialize: "It is not necessary to initialize '{a}' to 'undefined'.",
600 unnecessary_use: "Unnecessary \"use strict\".",
601 unreachable_a_b: "Unreachable '{a}' after '{b}'.",
602 unrecognized_style_attribute_a: "Unrecognized style attribute '{a}'.",
603 unrecognized_tag_a: "Unrecognized tag '<{a}>'.",
604 unsafe: "Unsafe character.",
605 url: "JavaScript URL.",
606 use_array: "Use the array literal notation [].",
607 use_braces: "Spaces are hard to count. Use {{a}}.",
608 use_object: "Use the object literal notation {}.",
609 used_before_a: "'{a}' was used before it was defined.",
610 var_a_not: "Variable {a} was not declared correctly.",
611 weird_assignment: "Weird assignment.",
612 weird_condition: "Weird condition.",
613 weird_new: "Weird construction. Delete 'new'.",
614 weird_program: "Weird program.",
615 weird_relation: "Weird relation.",
616 weird_ternary: "Weird ternary.",
617 wrap_immediate: "Wrap an immediate function invocation in parentheses " +
618 "to assist the reader in understanding that the expression " +
619 "is the result of a function, and not the function itself.",
620 wrap_regexp: "Wrap the /regexp/ literal in parens to disambiguate the slash operator.",
621 write_is_wrong: "document.write can be a form of eval."
629 "antiquewhite" : true,
636 "blanchedalmond" : true,
645 "cornflowerblue" : true,
651 "darkgoldenrod" : true,
655 "darkmagenta" : true,
656 "darkolivegreen" : true,
661 "darkseagreen" : true,
662 "darkslateblue" : true,
663 "darkslategray" : true,
664 "darkturquoise" : true,
667 "deepskyblue" : true,
671 "floralwhite" : true,
672 "forestgreen" : true,
680 "greenyellow" : true,
688 "lavenderblush" : true,
690 "lemonchiffon" : true,
694 "lightgoldenrodyellow" : true,
697 "lightsalmon" : true,
698 "lightseagreen" : true,
699 "lightskyblue" : true,
700 "lightslategray" : true,
701 "lightsteelblue" : true,
702 "lightyellow" : true,
708 "mediumaquamarine" : true,
710 "mediumorchid" : true,
711 "mediumpurple" : true,
712 "mediumseagreen" : true,
713 "mediumslateblue" : true,
714 "mediumspringgreen" : true,
715 "mediumturquoise" : true,
716 "mediumvioletred" : true,
717 "midnightblue" : true,
721 "navajowhite" : true,
729 "palegoldenrod" : true,
731 "paleturquoise" : true,
732 "palevioletred" : true,
743 "saddlebrown" : true,
754 "springgreen" : true,
766 "yellowgreen" : true,
768 "activeborder" : true,
769 "activecaption" : true,
770 "appworkspace" : true,
773 "buttonhighlight" : true,
774 "buttonshadow" : true,
776 "captiontext" : true,
779 "highlighttext" : true,
780 "inactiveborder" : true,
781 "inactivecaption" : true,
782 "inactivecaptiontext" : true,
783 "infobackground" : true,
788 "threeddarkshadow" : true,
790 "threedhighlight" : true,
791 "threedlightshadow" : true,
792 "threedshadow" : true,
794 "windowframe" : true,
836 funct, // The current function
839 'closure', 'exception', 'global', 'label', 'outer', 'unused', 'var'
842 functions, // All of the functions
843 global, // The global scope
850 area: {empty: true, parent: ' map '},
855 base: {empty: true, parent: ' head '},
859 body: {parent: ' html noframes '},
862 canvas: {parent: ' body p div th td '},
863 caption: {parent: ' table '},
867 col: {empty: true, parent: ' table colgroup '},
868 colgroup: {parent: ' table '},
869 command: {parent: ' menu '},
871 dd: {parent: ' dl '},
879 dt: {parent: ' dl '},
887 frame: {empty: true, parent: ' frameset '},
888 frameset: {parent: ' html frameset '},
895 head: {parent: ' html '},
900 {empty: true, parent: ' head '},
905 input: {empty: true},
910 legend: {parent: ' details fieldset figure '},
911 li: {parent: ' dir menu ol ul '},
912 link: {empty: true, parent: ' head '},
916 meta: {empty: true, parent: ' head noframes noscript '},
919 noframes: {parent: ' html body '},
920 noscript: {parent: ' body head noframes '},
923 optgroup: {parent: ' select '},
924 option: {parent: ' optgroup select '},
927 param: {empty: true, parent: ' applet object '},
935 script: {empty: true, parent: ' body div frame head iframe p pre span '},
942 style: {parent: ' head ', empty: true},
946 tbody: {parent: ' table '},
947 td: {parent: ' tr '},
949 tfoot: {parent: ' table '},
950 th: {parent: ' tr '},
951 thead: {parent: ' table '},
953 title: {parent: ' head '},
954 tr: {parent: ' table tbody thead tfoot '},
963 implied, // Implied globals
973 predefined, // Global variables defined by option
1001 scope, // The current scope
1011 // standard contains the global names that are provided by the
1012 // ECMAScript standard.
1019 decodeURIComponent : false,
1021 encodeURIComponent : false,
1026 hasOwnProperty : false,
1036 ReferenceError : false,
1039 SyntaxError : false,
1052 NEGATIVE_INFINITY : true,
1054 POSITIVE_INFINITY : true,
1067 // widget contains the global names which are provided to a Yahoo
1068 // (fna Konfabulator) widget.
1075 bytesToUIString : true,
1079 chooseFolder : true,
1082 convertPathToHFS : true,
1083 convertPathToPlatform : true,
1084 CustomAnimation : true,
1086 FadeAnimation : true,
1096 isApplicationRunning : true,
1098 konfabulatorVersion : true,
1102 MoveAnimation : true,
1107 preferenceGroups : true,
1113 reloadWidget : true,
1114 ResizeAnimation : true,
1116 resumeUpdates : true,
1117 RotateAnimation : true,
1119 runCommandInBg : true,
1121 savePreferences : true,
1124 showWidgetPreferences : true,
1128 suppressUpdates : true,
1141 XMLHttpRequest : true,
1142 yahooCheckLogin : true,
1148 ActiveXObject: false,
1157 // xmode is used to adapt to the exceptions in html parsing.
1158 // It can have these states:
1159 // false .js script file
1170 // Regular expressions. Some of these are stupidly long.
1172 // unsafe comment or string
1173 ax = /@cc|<\/?|script|\]\s*\]|<\s*!|</i,
1174 // unsafe characters that are silently deleted by one or more browsers
1175 cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
1177 tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jslint|properties|members|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,
1179 hx = /^\s*(['"=>\/&#]|<(?:\/|\!(?:--)?)?|[a-zA-Z][a-zA-Z0-9_\-:]*|[0-9]+|--)/,
1180 // characters in strings that need escapement
1181 nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
1182 nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
1184 ox = /[>&]|<[\/!]?|--/,
1188 ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
1190 jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,
1192 ux = /&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i,
1194 sx = /^\s*([{:#%.=,>+\[\]@()"';]|\*=?|\$=|\|=|\^=|~=|[a-zA-Z_][a-zA-Z0-9_\-]*|[0-9]+|<\/|\/\*)/,
1195 ssx = /^\s*([@#!"'};:\-%.=,+\[\]()*_]|[a-zA-Z][a-zA-Z0-9._\-]*|\/\*?|\d+(?:\.\d+)?|<\/)/,
1196 // attributes characters
1197 qx = /[^a-zA-Z0-9+\-_\/ ]/,
1198 // query characters for ids
1199 dx = /[\[\]\/\\"'*<>.&:(){}+=#]/,
1209 function return_this() {
1213 function F() {} // Used by Object.create
1215 // Provide critical ES5 functions to ES3.
1217 if (typeof Array.prototype.filter !== 'function') {
1218 Array.prototype.filter = function (f) {
1219 var i, length = this.length, result = [];
1220 for (i = 0; i < length; i += 1) {
1222 result.push(f(this[i]));
1230 if (typeof Array.isArray !== 'function') {
1231 Array.isArray = function (o) {
1232 return Object.prototype.toString.apply(o) === '[object Array]';
1236 if (typeof Object.create !== 'function') {
1237 Object.create = function (o) {
1243 if (typeof Object.keys !== 'function') {
1244 Object.keys = function (o) {
1247 if (Object.prototype.hasOwnProperty.call(o, k)) {
1255 // Substandard methods
1257 if (typeof String.prototype.entityify !== 'function') {
1258 String.prototype.entityify = function () {
1260 .replace(/&/g, '&')
1261 .replace(/</g, '<')
1262 .replace(/>/g, '>');
1266 if (typeof String.prototype.isAlpha !== 'function') {
1267 String.prototype.isAlpha = function () {
1268 return (this >= 'a' && this <= 'z\uffff') ||
1269 (this >= 'A' && this <= 'Z\uffff');
1273 if (typeof String.prototype.isDigit !== 'function') {
1274 String.prototype.isDigit = function () {
1275 return (this >= '0' && this <= '9');
1279 if (typeof String.prototype.supplant !== 'function') {
1280 String.prototype.supplant = function (o) {
1281 return this.replace(/\{([^{}]*)\}/g, function (a, b) {
1283 return typeof r === 'string' || typeof r === 'number' ? r : a;
1288 if (typeof String.prototype.name !== 'function') {
1289 String.prototype.name = function () {
1291 // If the string looks like an identifier, then we can return it as is.
1292 // If the string contains no control characters, no quote characters, and no
1293 // backslash characters, then we can simply slap some quotes around it.
1294 // Otherwise we must also replace the offending characters with safe
1297 if (ix.test(this)) {
1300 if (nx.test(this)) {
1301 return '"' + this.replace(nxg, function (a) {
1306 return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
1309 return '"' + this + '"';
1314 function combine(t, o) {
1317 if (Object.prototype.hasOwnProperty.call(o, n)) {
1326 combine(predefined, rhino);
1329 combine(predefined, devel);
1331 if (option.browser) {
1332 combine(predefined, browser);
1334 if (option.windows) {
1335 combine(predefined, windows);
1337 if (option.widget) {
1338 combine(predefined, widget);
1344 // Produce an error warning.
1346 function quit(message, line, character) {
1348 name: 'JSLintError',
1350 character: character,
1351 message: bundle.scanned_a_b.supplant({
1353 b: Math.floor((line / lines.length) * 100)
1358 function warn(message, offender, a, b, c, d) {
1359 var character, line, warning;
1360 offender = offender || nexttoken; // `~
1361 line = offender.line || 0;
1362 character = offender.from || 0;
1366 evidence: lines[line - 1] || '',
1368 character: character,
1369 a: a || offender.value,
1374 warning.reason = message.supplant(warning);
1375 JSLINT.errors.push(warning);
1376 if (option.passfail) {
1377 quit(bundle.stopping, line, character);
1380 if (warnings >= option.maxerr) {
1381 quit(bundle.too_many, line, character);
1386 function warn_at(message, line, character, a, b, c, d) {
1387 return warn(message, {
1393 function fail(message, offender, a, b, c, d) {
1394 var warning = warn(message, offender, a, b, c, d);
1395 quit(bundle.stopping, warning.line, warning.character);
1398 function fail_at(message, line, character, a, b, c, d) {
1399 return fail(message, {
1405 function expected_at(at) {
1406 if (option.white && nexttoken.from !== at) {
1407 warn(bundle.expected_a_at_b_c, nexttoken, nexttoken.value, at,
1412 function aint(it, name, expected) {
1414 if (it[name] !== expected) {
1415 warn(bundle.expected_a_b, it, expected, it[name]);
1424 // lexical analysis and token construction
1426 var lex = (function lex() {
1427 var character, comments, from, line, source_row, older_token = {};
1429 // Private lex methods
1431 function collect_comment(comment, quote, at) {
1432 if (older_token.line !== line) {
1434 comments.push(comment);
1436 comments = [comment];
1439 if (older_token.postcomments) {
1440 older_token.postcomments.push(comment);
1442 older_token.postcomments = [comment];
1447 function next_line() {
1449 if (line >= lines.length) {
1453 source_row = lines[line];
1455 at = source_row.search(/ \t/);
1457 warn_at(bundle.mixed, line, at + 1);
1459 source_row = source_row.replace(/\t/g, tab);
1460 at = source_row.search(cx);
1462 warn_at(bundle.unsafe, line, at);
1464 if (option.maxlen && option.maxlen < source_row.length) {
1465 warn_at(bundle.too_long, line, source_row.length);
1470 // Produce a token object. The token inherits from a syntax symbol.
1472 function it(type, value, quote) {
1474 if (type === '(string)' || type === '(range)') {
1475 if (jx.test(value)) {
1476 warn_at(bundle.url, line, from);
1479 the_token = Object.create(syntax[(
1480 type === '(punctuator)' ||
1481 (type === '(identifier)' && Object.prototype.hasOwnProperty.call(syntax, value)) ?
1484 )] || syntax['(error)']);
1485 if (type === '(identifier)') {
1486 the_token.identifier = true;
1487 if (value === '__iterator__' || value === '__proto__') {
1488 fail_at(bundle.reserved_a, line, from, value);
1489 } else if (option.nomen &&
1490 (value.charAt(0) === '_' ||
1491 value.charAt(value.length - 1) === '_')) {
1492 warn_at(bundle.dangling_a, line, from, value);
1495 if (value !== undefined) {
1496 the_token.value = value;
1499 the_token.quote = quote;
1502 the_token.comments = comments;
1505 the_token.line = line;
1506 the_token.from = from;
1507 the_token.thru = character;
1508 the_token.prev = older_token;
1511 ('(,=:[!&|?{};'.indexOf(id.charAt(id.length - 1)) >= 0) ||
1514 older_token.next = the_token;
1515 older_token = the_token;
1519 // Public lex methods
1522 init: function (source) {
1523 if (typeof source === 'string') {
1525 .replace(/\r\n/g, '\n')
1526 .replace(/\r/g, '\n')
1536 range: function (begin, end) {
1539 if (source_row.charAt(0) !== begin) {
1540 fail_at(bundle.expected_a_b, line, character, begin, source_row.charAt(0));
1543 source_row = source_row.slice(1);
1545 c = source_row.charAt(0);
1548 fail_at(bundle.missing_a, line, character, c);
1551 source_row = source_row.slice(1);
1553 return it('(range)', value);
1556 warn_at(bundle.unexpected_a, line, character, c);
1563 // token -- this is called by advance to get the next token.
1565 token: function () {
1566 var b, c, captures, digit, depth, flag, high, i, j, length, low, quote, t;
1569 var exec = x.exec(source_row), first;
1571 length = exec[0].length;
1573 c = first.charAt(0);
1574 source_row = source_row.substr(length);
1575 from = character + length - first.length;
1576 character += length;
1581 function string(x) {
1585 var i = parseInt(source_row.substr(j + 1, n), 16);
1587 if (i >= 32 && i <= 126 &&
1588 i !== 34 && i !== 92 && i !== 39) {
1589 warn_at(bundle.unexpected_a, line, character, '\\');
1592 c = String.fromCharCode(i);
1595 if (json_mode && x !== '"') {
1596 warn_at(bundle.expected_a, line, character, '"');
1599 if (xquote === x || (xmode === 'scriptstring' && !xquote)) {
1600 return it('(punctuator)', x);
1605 while (j >= source_row.length) {
1607 if (xmode !== 'html' || !next_line()) {
1608 fail_at(bundle.unclosed, line, from);
1611 c = source_row.charAt(j);
1614 source_row = source_row.substr(j + 1);
1615 return it('(string)', r, x);
1618 if (c === '\n' || c === '\r') {
1621 warn_at(bundle.control_a,
1622 line, character + j, source_row.slice(0, j));
1623 } else if (c === xquote) {
1624 warn_at(bundle.bad_html, line, character + j);
1625 } else if (c === '<') {
1626 if (option.safe && xmode === 'html') {
1627 warn_at(bundle.adsafe_a, line, character + j, c);
1628 } else if (source_row.charAt(j + 1) === '/' && (xmode || option.safe)) {
1629 warn_at(bundle.expected_a_b, line, character,
1631 } else if (source_row.charAt(j + 1) === '!' && (xmode || option.safe)) {
1632 warn_at(bundle.unexpected_a, line, character, '<!');
1634 } else if (c === '\\') {
1635 if (xmode === 'html') {
1637 warn_at(bundle.adsafe_a, line, character + j, c);
1639 } else if (xmode === 'styleproperty') {
1642 c = source_row.charAt(j);
1644 warn_at(bundle.unexpected_a, line, character, '\\');
1649 c = source_row.charAt(j);
1652 warn_at(bundle.bad_html, line, character + j);
1660 warn_at(bundle.unexpected_a, line, character, '\\\'');
1683 warn_at(bundle.unexpected_a, line, character, '\\v');
1689 warn_at(bundle.unexpected_a, line, character, '\\x');
1694 warn_at(bundle.unexpected_a, line, character, '\\');
1705 while (!source_row) {
1710 while (xmode === 'outer') {
1711 i = source_row.search(ox);
1716 source_row = source_row.slice(i);
1720 return it('(end)', '');
1724 t = match(rx[xmode] || tx);
1728 while (source_row && source_row < '!') {
1729 source_row = source_row.substr(1);
1732 if (xmode === 'html') {
1733 return it('(error)', source_row.charAt(0));
1735 fail_at(bundle.unexpected_a,
1736 line, character, source_row.substr(0, 1));
1743 if (c.isAlpha() || c === '_' || c === '$') {
1744 return it('(identifier)', t);
1750 if (xmode !== 'style' &&
1751 xmode !== 'styleproperty' &&
1752 source_row.substr(0, 1).isAlpha()) {
1753 warn_at(bundle.expected_space_a_b,
1754 line, character, c, source_row.charAt(0));
1757 digit = t.substr(1, 1);
1758 if (digit.isDigit()) {
1759 if (token.id !== '.' && xmode !== 'styleproperty') {
1760 warn_at(bundle.unexpected_a,
1761 line, character, t);
1763 } else if (json_mode && (digit === 'x' || digit === 'X')) {
1764 warn_at(bundle.unexpected_a, line, character, '0x');
1767 if (t.substr(t.length - 1) === '.') {
1768 warn_at(bundle.trailing_decimal_a, line,
1771 if (xmode !== 'style') {
1773 if (!isFinite(digit)) {
1774 warn_at(bundle.bad_number, line, character, t);
1778 return it('(number)', t);
1791 if (comments_off || src || (xmode && xmode !== 'script')) {
1792 warn_at(bundle.unexpected_comment, line, character);
1793 } else if (xmode === 'script' && /<\source_row*\//i.test(source_row)) {
1794 warn_at(bundle.unexpected_a, line, character, '<\/');
1795 } else if ((option.safe || xmode === 'script') && ax.test(source_row)) {
1796 warn_at(bundle.dangerous_comment, line, character);
1798 collect_comment(source_row);
1805 if (comments_off || src || (xmode && xmode !== 'script' && xmode !== 'style' && xmode !== 'styleproperty')) {
1806 warn_at(bundle.unexpected_comment, line, character);
1808 if (option.safe && ax.test(source_row)) {
1809 warn_at(bundle.dangerous_comment, line, character);
1812 i = source_row.search(lx);
1816 collect_comment(source_row);
1818 fail_at(bundle.unclosed_comment, line, character);
1820 if (option.safe && ax.test(source_row)) {
1821 warn_at(bundle.dangerous_comment, line, character);
1826 if (source_row.substr(i, 1) === '/') {
1827 fail_at(bundle.nested_comment, line, character);
1829 collect_comment(source_row.substr(0, i));
1830 source_row = source_row.substr(i + 2);
1837 if (token.id === '/=') {
1850 c = source_row.charAt(length);
1854 fail_at(bundle.unclosed_regexp, line, from);
1858 warn_at(bundle.unescaped_a,
1859 line, from + length, '/');
1861 c = source_row.substr(0, length - 1);
1862 flag = Object.create(regexp_flag);
1863 while (flag[source_row.charAt(length)] === true) {
1864 flag[source_row.charAt(length)] = false;
1867 if (source_row.charAt(length).isAlpha()) {
1868 fail_at(bundle.unexpected_a,
1869 line, from, source_row.charAt(length));
1871 character += length;
1872 source_row = source_row.substr(length);
1873 quote = source_row.charAt(0);
1874 if (quote === '/' || quote === '*') {
1875 fail_at(bundle.confusing_regexp,
1878 return it('(regexp)', c);
1880 c = source_row.charAt(length);
1882 warn_at(bundle.control_a,
1883 line, from + length, String(c));
1884 } else if (c === '<') {
1886 bundle.unexpected_a,
1897 if (source_row.charAt(length) === '?') {
1899 switch (source_row.charAt(length)) {
1907 bundle.expected_a_b,
1911 source_row.charAt(length)
1923 warn_at(bundle.unescaped_a,
1924 line, from + length, ')');
1931 while (source_row.charAt(length) === ' ') {
1936 warn_at(bundle.use_braces,
1937 line, from + length, j);
1941 c = source_row.charAt(length);
1944 if (option.regexp) {
1945 warn_at(bundle.insecure_a,
1946 line, from + length, c);
1947 } else if (source_row.charAt(length) === ']') {
1948 fail_at(bundle.unescaped_a,
1949 line, from + length, '^');
1954 warn_at(bundle.empty_class, line,
1959 c = source_row.charAt(length);
1964 warn_at(bundle.unescaped_a,
1965 line, from + length, c);
1972 warn_at(bundle.unescaped_a,
1973 line, from + length, '-');
1979 warn_at(bundle.unescaped_a,
1980 line, from + length - 1, '-');
1984 c = source_row.charAt(length);
1992 } else if (c === '<') {
1994 bundle.unexpected_a,
2004 warn_at(bundle.unescaped_a,
2005 line, from + length - 1, '/');
2009 if (xmode === 'script') {
2010 c = source_row.charAt(length);
2011 if (c === '!' || c === '/') {
2013 bundle.html_confusion_a,
2028 if (option.regexp) {
2029 warn_at(bundle.insecure_a, line,
2039 warn_at(bundle.unescaped_a, line,
2043 if (xmode === 'script') {
2044 c = source_row.charAt(length);
2045 if (c === '!' || c === '/') {
2047 bundle.html_confusion_a,
2057 switch (source_row.charAt(length)) {
2062 if (source_row.charAt(length) === '?') {
2068 c = source_row.charAt(length);
2069 if (c < '0' || c > '9') {
2071 bundle.expected_number_a,
2080 c = source_row.charAt(length);
2081 if (c < '0' || c > '9') {
2085 low = +c + (low * 10);
2091 c = source_row.charAt(length);
2092 if (c >= '0' && c <= '9') {
2096 c = source_row.charAt(length);
2097 if (c < '0' || c > '9') {
2101 high = +c + (high * 10);
2105 if (source_row.charAt(length) !== '}') {
2107 bundle.expected_a_b,
2116 if (source_row.charAt(length) === '?') {
2132 c = source_row.substr(0, length - 1);
2133 character += length;
2134 source_row = source_row.substr(length);
2135 return it('(regexp)', c);
2137 return it('(punctuator)', t);
2145 i = source_row.indexOf('--');
2149 i = source_row.indexOf('<!');
2151 fail_at(bundle.nested_comment,
2152 line, character + i);
2155 fail_at(bundle.unclosed_comment, length, c);
2158 length = source_row.indexOf('<!');
2159 if (length >= 0 && length < i) {
2160 fail_at(bundle.nested_comment,
2161 line, character + length);
2164 if (source_row.charAt(i + 2) !== '>') {
2165 fail_at(bundle.expected_a, line, character, '-->');
2168 source_row = source_row.slice(i + 3);
2171 if (xmode === 'html' || xmode === 'styleproperty') {
2173 c = source_row.charAt(0);
2174 if ((c < '0' || c > '9') &&
2175 (c < 'a' || c > 'f') &&
2176 (c < 'A' || c > 'F')) {
2180 source_row = source_row.substr(1);
2183 if (t.length !== 4 && t.length !== 7) {
2184 warn_at(bundle.bad_color_a, line,
2187 return it('(color)', t);
2189 return it('(punctuator)', t);
2192 if (xmode === 'outer' && c === '&') {
2194 source_row = source_row.substr(1);
2196 c = source_row.charAt(0);
2198 source_row = source_row.substr(1);
2202 if (!((c >= '0' && c <= '9') ||
2203 (c >= 'a' && c <= 'z') ||
2205 fail_at(bundle.bad_entity, line, from + length,
2211 return it('(punctuator)', t);
2220 function add_label(t, type) {
2222 if (option.safe && funct['(global)'] &&
2223 typeof predefined[t] !== 'boolean') {
2224 warn(bundle.adsafe_a, token, t);
2225 } else if (t === 'hasOwnProperty') {
2226 warn(bundle.bad_name_a, token, t);
2229 // Define t in the current function in the current scope.
2231 if (Object.prototype.hasOwnProperty.call(funct, t) && !funct['(global)']) {
2232 warn(funct[t] === true ?
2233 bundle.used_before_a :
2234 bundle.already_defined,
2238 if (funct['(global)']) {
2239 if (global[t] === false) {
2240 warn(bundle.read_only);
2243 if (Object.prototype.hasOwnProperty.call(implied, t)) {
2244 warn(bundle.used_before_a, nexttoken, t);
2253 function peek(distance) {
2255 // Peek ahead to a future token. The distance is how far ahead to look. The
2256 // default is the next token.
2258 var found, slot = 0;
2260 distance = distance || 0;
2261 while (slot <= distance) {
2262 found = lookahead[slot];
2264 found = lookahead[slot] = lex.token();
2272 function discard(it) {
2274 // The token will not be included in the parse tree, so move the comments
2275 // that are attached to the token to tokens that are in the tree.
2279 if (it.postcomments) {
2280 next = it.next || peek();
2281 next.comments = next.comments ?
2282 next.comments.concat(it.postcomments) :
2287 while (prev.postcomments === null) {
2290 if (prev.postcomments) {
2291 prev.postcomments = prev.postcomments.concat(it.comments);
2293 prev.postcomments = it.comments;
2297 it.postcomments = null;
2301 function advance(id, match) {
2303 // Produce the next token, also looking for programming errors.
2307 // In indentation checking was requested, then inspect all of the line breakings.
2308 // The var statement is tricky because the names might be aligned or not. We
2309 // look at the first line break after the var to determine the programmer's
2312 if (var_mode && nexttoken.line !== token.line) {
2313 if ((var_mode !== indent || !nexttoken.edge) &&
2314 nexttoken.from === indent.at -
2315 (nexttoken.edge ? option.indent : 0)) {
2318 dent.at -= option.indent;
2319 if (dent === var_mode) {
2330 // If the token is an edge.
2332 if (nexttoken.edge) {
2333 if (nexttoken.edge === 'label') {
2335 } else if (nexttoken.edge === 'case') {
2336 expected_at(indent.at - option.indent);
2337 } else if (indent.mode !== 'array' || nexttoken.line !== token.line) {
2338 expected_at(indent.at);
2341 // If the token is not an edge, but is the first token on the line.
2343 } else if (nexttoken.line !== token.line &&
2344 nexttoken.from < indent.at + (indent.mode ===
2345 'expression' ? 0 : option.indent)) {
2346 expected_at(indent.at + option.indent);
2348 } else if (nexttoken.line !== token.line) {
2349 if (nexttoken.edge) {
2350 expected_at(indent.at);
2353 if (indent.mode === 'statement' || indent.mode === 'var') {
2354 expected_at(indent.at + option.indent);
2355 } else if (nexttoken.from < indent.at + (indent.mode ===
2356 'expression' ? 0 : option.indent)) {
2357 expected_at(indent.at + option.indent);
2365 if (nexttoken.id === '.') {
2366 warn(bundle.trailing_decimal_a);
2370 if (nexttoken.id === '-' || nexttoken.id === '--') {
2371 warn(bundle.confusing_a);
2375 if (nexttoken.id === '+' || nexttoken.id === '++') {
2376 warn(bundle.confusing_a);
2380 if (token.arity === 'string' || token.identifier) {
2381 anonname = token.value;
2384 if (id && nexttoken.id !== id) {
2386 warn(bundle.expected_a_b_from_c_d, nexttoken, id,
2387 match.id, match.line, nexttoken.value);
2388 } else if (!nexttoken.identifier || nexttoken.value !== id) {
2389 warn(bundle.expected_a_b, nexttoken, id, nexttoken.value);
2394 nexttoken = lookahead.shift() || lex.token();
2395 if (token.id === '(end)') {
2401 function directive() {
2402 var command = this.id,
2404 old_comments_off = comments_off,
2405 old_option_white = option.white,
2407 comments_off = true;
2408 option.white = false;
2409 if (lookahead.length > 0 || this.postcomments || nexttoken.comments) {
2410 warn(bundle.unexpected_a, this);
2413 case '/*properties':
2415 command = '/*properties';
2422 warn(bundle.adsafe_a, this);
2427 warn(bundle.adsafe_a, this);
2435 if (nexttoken.id === '*/') {
2438 if (nexttoken.id !== ',') {
2443 if (nexttoken.arity !== 'string' && !nexttoken.identifier) {
2444 fail(bundle.unexpected_a, nexttoken);
2446 name = nexttoken.value;
2450 if (nexttoken.id === ':') {
2452 switch (nexttoken.id) {
2454 if (typeof scope[name] === 'object' ||
2455 global[name] === false) {
2456 fail(bundle.unexpected_a);
2458 global[name] = true;
2462 if (typeof scope[name] === 'object') {
2463 fail(bundle.unexpected_a);
2465 global[name] = false;
2469 fail(bundle.unexpected_a);
2472 if (typeof scope[name] === 'object') {
2473 fail(bundle.unexpected_a);
2475 global[name] = false;
2479 if (nexttoken.id !== ':') {
2480 fail(bundle.expected_a_b, nexttoken, ':', nexttoken.value);
2485 value = +nexttoken.value;
2486 if (typeof value !== 'number' ||
2487 !isFinite(value) || value < 0 ||
2488 Math.floor(value) !== value) {
2489 fail(bundle.expected_small_a);
2492 old_option_white = true;
2494 option.indent = value;
2497 value = +nexttoken.value;
2498 if (typeof value !== 'number' ||
2501 Math.floor(value) !== value) {
2502 fail(bundle.expected_small_a, nexttoken);
2504 option.maxerr = value;
2507 value = +nexttoken.value;
2508 if (typeof value !== 'number' || !isFinite(value) || value < 0 ||
2509 Math.floor(value) !== value) {
2510 fail(bundle.expected_small_a);
2512 option.maxlen = value;
2515 if (nexttoken.id === 'true') {
2516 old_option_white = true;
2517 } else if (nexttoken.id === 'false') {
2518 old_option_white = false;
2520 fail(bundle.unexpected_a);
2524 if (nexttoken.id === 'true') {
2525 option[name] = true;
2526 } else if (nexttoken.id === 'false') {
2527 option[name] = false;
2529 fail(bundle.unexpected_a);
2534 case '/*properties':
2535 properties[name] = true;
2538 fail(bundle.unexpected_a);
2541 if (command === '/*jslint') {
2544 comments_off = old_comments_off;
2546 option.white = old_option_white;
2550 // Indentation intention
2552 function edge(mode) {
2553 nexttoken.edge = !indent || (indent.open && (mode || true));
2557 function step_in(mode) {
2559 if (typeof mode === 'number') {
2565 } else if (!indent) {
2573 open = mode === 'var' ||
2574 (nexttoken.line !== token.line && mode !== 'statement');
2576 at: (open || mode === 'control' ?
2577 was.at + option.indent : was.at) +
2578 (was.wrap ? option.indent : 0),
2583 if (mode === 'var' && open) {
2589 function step_out(id, t) {
2591 if (indent && indent.open) {
2592 indent.at -= option.indent;
2598 indent = indent.was;
2602 // Functions for conformance of whitespace.
2604 function one_space(left, right) {
2605 left = left || token;
2606 right = right || nexttoken;
2607 if (right.id !== '(end)' && option.white &&
2608 (token.line !== right.line ||
2609 token.thru + 1 !== right.from)) {
2610 warn(bundle.expected_space_a_b, right, token.value, right.value);
2614 function one_space_only(left, right) {
2615 left = left || token;
2616 right = right || nexttoken;
2617 if (right.id !== '(end)' && (left.line !== right.line ||
2618 (option.white && left.thru + 1 !== right.from))) {
2619 warn(bundle.expected_space_a_b, right, left.value, right.value);
2623 function no_space(left, right) {
2624 left = left || token;
2625 right = right || nexttoken;
2626 if ((option.white || xmode === 'styleproperty' || xmode === 'style') &&
2627 left.thru !== right.from && left.line === right.line) {
2628 warn(bundle.unexpected_space_a_b, right, left.value, right.value);
2632 function no_space_only(left, right) {
2633 left = left || token;
2634 right = right || nexttoken;
2635 if (right.id !== '(end)' && (left.line !== right.line ||
2636 (option.white && left.thru !== right.from))) {
2637 warn(bundle.unexpected_space_a_b, right, left.value, right.value);
2641 function spaces(left, right) {
2643 left = left || token;
2644 right = right || nexttoken;
2645 if (left.thru === right.from && left.line === right.line) {
2646 warn(bundle.missing_space_a_b, right, left.value, right.value);
2652 if (nexttoken.id !== ',') {
2653 warn_at(bundle.expected_a_b, token.line, token.thru, ',', nexttoken.value);
2665 function semicolon() {
2666 if (nexttoken.id !== ';') {
2667 warn_at(bundle.expected_a_b, token.line, token.thru, ';', nexttoken.value);
2674 if (semicolon_coda[nexttoken.id] !== true) {
2680 function use_strict() {
2681 if (nexttoken.value === 'use strict') {
2683 warn(bundle.unnecessary_use);
2689 option.newcap = true;
2690 option.undef = true;
2698 function are_similar(a, b) {
2702 if (Array.isArray(a)) {
2703 if (Array.isArray(b) && a.length === b.length) {
2705 for (i = 0; i < a.length; i += 1) {
2706 if (!are_similar(a[i], b[i])) {
2714 if (Array.isArray(b)) {
2717 if (a.arity === b.arity && a.value === b.value) {
2722 return are_similar(a.first, b.first);
2724 return are_similar(a.first, b.first) &&
2725 are_similar(a.second, b.second);
2727 return are_similar(a.first, b.first) &&
2728 are_similar(a.second, b.second) &&
2729 are_similar(a.third, b.third);
2737 if (a.id === '.' && b.id === '[' && b.arity === 'infix') {
2738 return a.second.value === b.second.value && b.second.arity === 'string';
2739 } else if (a.id === '[' && a.arity === 'infix' && b.id === '.') {
2740 return a.second.value === b.second.value && a.second.arity === 'string';
2747 // This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
2748 // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
2749 // like .nud except that it is only used on the first token of a statement.
2750 // Having .fud makes it much easier to define statement-oriented languages like
2751 // JavaScript. I retained Pratt's nomenclature.
2753 // .nud Null denotation
2754 // .fud First null denotation
2755 // .led Left denotation
2756 // lbp Left binding power
2757 // rbp Right binding power
2759 // They are elements of the parsing method called Top Down Operator Precedence.
2761 function expression(rbp, initial) {
2763 // rbp is the right binding power.
2764 // initial indicates that this is the first expression of a statement.
2767 if (nexttoken.id === '(end)') {
2768 fail(bundle.unexpected_a, token, nexttoken.id);
2771 if (option.safe && typeof predefined[token.value] === 'boolean' &&
2772 (nexttoken.id !== '(' && nexttoken.id !== '.')) {
2773 warn(bundle.adsafe, token);
2776 anonname = 'anonymous';
2777 funct['(verb)'] = token.value;
2779 if (initial === true && token.fud) {
2785 if (nexttoken.arity === 'number' && token.id === '.') {
2786 warn(bundle.leading_decimal_a, token,
2791 fail(bundle.expected_identifier_a, token, token.id);
2794 while (rbp < nexttoken.lbp) {
2797 left = token.led(left);
2799 fail(bundle.expected_operator_a, token, token.id);
2807 // Functional constructors for making the symbols that will be inherited by
2810 function symbol(s, p) {
2812 if (!x || typeof x !== 'object') {
2824 return symbol(s, 0);
2828 function postscript(x) {
2829 x.postscript = true;
2833 function ultimate(s) {
2834 var x = symbol(s, 0);
2840 return postscript(x);
2844 function stmt(s, f) {
2846 x.identifier = x.reserved = true;
2851 function labeled_stmt(s, f) {
2856 function disrupt_stmt(s, f) {
2862 function reserve_name(x) {
2863 var c = x.id.charAt(0);
2864 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
2865 x.identifier = x.reserved = true;
2871 function prefix(s, f) {
2872 var x = symbol(s, 150);
2874 x.nud = (typeof f === 'function') ? f : function () {
2875 if (s === 'typeof') {
2880 this.first = expression(150);
2881 this.arity = 'prefix';
2882 if (this.id === '++' || this.id === '--') {
2883 if (option.plusplus) {
2884 warn(bundle.unexpected_a, this);
2885 } else if ((!this.first.identifier || this.first.reserved) &&
2886 this.first.id !== '.' && this.first.id !== '[') {
2887 warn(bundle.bad_operand, this);
2896 function type(s, arity, nud) {
2906 function reserve(s, f) {
2908 x.identifier = x.reserved = true;
2909 if (typeof f === 'function') {
2916 function reservevar(s, v) {
2917 return reserve(s, function () {
2918 if (typeof v === 'function') {
2926 function infix(s, p, f, w) {
2927 var x = symbol(s, p);
2929 x.led = function (left) {
2930 this.arity = 'infix';
2932 spaces(prevtoken, token);
2935 if (typeof f === 'function') {
2936 return f(left, this);
2939 this.second = expression(p);
2946 function expected_relation(node, message) {
2948 warn(message || bundle.conditional_assignment, node);
2953 function expected_condition(node, message) {
2957 if (node.arity !== 'infix') {
2958 warn(message || bundle.weird_condition, node);
2973 warn(message || bundle.weird_condition, node);
2979 function check_relation(node) {
2980 switch (node.arity) {
2985 warn(bundle.unexpected_a, node);
2988 warn(bundle.confusing_a, node);
2994 warn(bundle.unexpected_a, node);
2997 if (node.id === 'NaN') {
2998 warn(bundle.isNaN, node);
3005 function relation(s, eqeq) {
3006 var x = infix(s, 100, function (left, that) {
3007 check_relation(left);
3009 warn(bundle.expected_a_b, that, eqeq, that.id);
3011 var right = expression(100);
3012 if (are_similar(left, right) ||
3013 ((left.arity === 'string' || left.arity === 'number') &&
3014 (right.arity === 'string' || right.arity === 'number'))) {
3015 warn(bundle.weird_relation, that);
3018 that.second = check_relation(right);
3025 function assignop(s, bit) {
3026 var x = infix(s, 20, function (left, that) {
3028 if (option.bitwise && bit) {
3029 warn(bundle.unexpected_a, that);
3032 if (funct[left.value] === false) {
3033 warn(bundle.read_only, left);
3034 } else if (left['function']) {
3035 warn(bundle.a_function, left);
3040 if (typeof predefined[l.value] === 'boolean') {
3041 warn(bundle.adsafe, l);
3047 if (left === syntax['function']) {
3048 warn(bundle.identifier_function, token);
3050 if (left.id === '.' || left.id === '[') {
3051 if (!left.first || left.first.value === 'arguments') {
3052 warn(bundle.bad_assignment, that);
3054 that.second = expression(19);
3055 if (that.id === '=' && are_similar(that.first, that.second)) {
3056 warn(bundle.weird_assignment, that);
3059 } else if (left.identifier && !left.reserved) {
3060 if (funct[left.value] === 'exception') {
3061 warn(bundle.assign_exception, left);
3063 that.second = expression(19);
3064 if (that.id === '=' && are_similar(that.first, that.second)) {
3065 warn(bundle.weird_assignment, that);
3070 fail(bundle.bad_assignment, that);
3077 function bitwise(s, p) {
3078 return infix(s, p, function (left, that) {
3079 if (option.bitwise) {
3080 warn(bundle.unexpected_a, that);
3083 that.second = expression(p);
3089 function suffix(s, f) {
3090 var x = symbol(s, 150);
3091 x.led = function (left) {
3092 no_space_only(prevtoken, token);
3093 if (option.plusplus) {
3094 warn(bundle.unexpected_a, this);
3095 } else if ((!left.identifier || left.reserved) &&
3096 left.id !== '.' && left.id !== '[') {
3097 warn(bundle.bad_operand, this);
3100 this.arity = 'suffix';
3107 function optional_identifier() {
3108 if (nexttoken.identifier) {
3110 if (option.safe && banned[token.value]) {
3111 warn(bundle.adsafe_a, token);
3112 } else if (token.reserved && !option.es5) {
3113 warn(bundle.expected_identifier_a_reserved, token);
3120 function identifier() {
3121 var i = optional_identifier();
3125 if (token.id === 'function' && nexttoken.id === '(') {
3126 warn(bundle.name_function);
3128 fail(bundle.expected_identifier_a);
3133 function statement(no_indent) {
3135 // Usually a statement starts a line. Exceptions include the var statement in the
3136 // initialization part of a for statement, and an if after an else.
3138 var label, old_scope = scope, the_statement;
3140 // We don't like the empty statement.
3142 if (nexttoken.id === ';') {
3143 warn(bundle.unexpected_a);
3148 // Is this a labeled statement?
3150 if (nexttoken.identifier && !nexttoken.reserved && peek().id === ':') {
3157 scope = Object.create(old_scope);
3158 add_label(label.value, 'label');
3159 if (nexttoken.labeled !== true) {
3160 warn(bundle.label_a_b, nexttoken, label.value, nexttoken.value);
3162 if (jx.test(label.value + ':')) {
3163 warn(bundle.url, label);
3165 nexttoken.label = label;
3168 // Parse the statement.
3171 step_in('statement');
3172 the_statement = expression(0, true);
3173 if (the_statement) {
3175 // Look for the final semicolon.
3177 if (the_statement.arity === 'statement') {
3178 if (the_statement.id === 'switch' ||
3179 (the_statement.block && the_statement.id !== 'do')) {
3186 // If this is an expression statement, determine if it is acceptble.
3189 // statments. If it is to be used at all, new should only be used to make
3190 // objects, not side effects. The expression statements we do like do
3191 // assignment or invocation or delete.
3193 if (the_statement.id === '(') {
3194 if (the_statement.first.id === 'new') {
3195 warn(bundle.bad_new);
3197 } else if (!the_statement.assign &&
3198 the_statement.id !== 'delete' &&
3199 the_statement.id !== '++' &&
3200 the_statement.id !== '--') {
3201 warn(bundle.assignment_function_expression, token);
3208 return the_statement;
3212 function statements() {
3213 var array = [], disruptor, the_statement;
3215 // A disrupt statement may not be followed by any other statement.
3216 // If the last statement is disrupt, then the sequence is disrupt.
3218 while (nexttoken.postscript !== true) {
3219 if (nexttoken.id === ';') {
3220 warn(bundle.unexpected_a, nexttoken);
3224 warn(bundle.unreachable_a_b, nexttoken, nexttoken.value,
3228 the_statement = statement();
3229 if (the_statement) {
3230 array.push(the_statement);
3231 if (the_statement.disrupt) {
3232 disruptor = the_statement;
3233 array.disrupt = true;
3242 function block(ordinary) {
3244 // array block is array sequence of statements wrapped in braces.
3245 // ordinary is false for function bodies and try blocks.
3246 // ordinary is true for if statements, while, etc.
3250 old_inblock = in_block,
3252 old_strict_mode = strict_mode;
3254 in_block = ordinary;
3255 scope = Object.create(scope);
3257 if (nexttoken.id === '{') {
3260 if (!ordinary && !use_strict() && !old_strict_mode &&
3261 option.strict && funct['(context)']['(global)']) {
3262 warn(bundle.missing_use_strict);
3264 array = statements();
3265 strict_mode = old_strict_mode;
3266 step_out('}', curly);
3268 } else if (!ordinary) {
3269 fail(bundle.expected_a_b, nexttoken, '{', nexttoken.value);
3271 warn(bundle.expected_a_b, nexttoken, '{', nexttoken.value);
3272 array = [statement()];
3273 array.disrupt = array[0].disrupt;
3275 funct['(verb)'] = null;
3277 in_block = old_inblock;
3278 if (ordinary && array.length === 0) {
3279 warn(bundle.empty_block);
3285 function tally_member(name) {
3286 if (properties && typeof properties[name] !== 'boolean') {
3287 warn(bundle.unexpected_member_a, token, name);
3289 if (typeof member[name] === 'number') {
3297 function note_implied(token) {
3298 var name = token.value, line = token.line, a = implied[name];
3299 if (typeof a === 'function') {
3305 } else if (a[a.length - 1] !== line) {
3311 // ECMAScript parser
3313 syntax['(identifier)'] = {
3314 type: '(identifier)',
3318 var variable = this.value,
3319 site = scope[variable];
3320 if (typeof site === 'function') {
3324 // The name is in scope and defined in the current function.
3326 if (funct === site) {
3328 // Change 'unused' to 'var', and reject labels.
3330 switch (funct[variable]) {
3332 warn(bundle.unexpected_a, token);
3333 funct[variable] = 'var';
3336 funct[variable] = 'var';
3339 funct[variable] = 'function';
3340 this['function'] = true;
3343 this['function'] = true;
3346 warn(bundle.a_label, token, variable);
3350 // The name is not defined in the function. If we are in the global scope,
3351 // then we have an undefined variable.
3353 } else if (funct['(global)']) {
3354 if (typeof global[variable] === 'boolean') {
3355 funct[variable] = global[variable];
3358 warn(bundle.not_a_defined, token, variable);
3360 note_implied(token);
3364 // If the name is already defined in the current
3365 // function, but not as outer, then there is a scope error.
3368 switch (funct[variable]) {
3373 warn(bundle.a_scope, token, variable);
3376 warn(bundle.a_label, token, variable);
3384 // If the name is defined in an outer function, make an outer entry, and if
3385 // it was unused, make it var.
3387 if (typeof site === 'boolean') {
3388 funct[variable] = site;
3389 functions[0][variable] = true;
3390 } else if (site === null) {
3391 warn(bundle.a_not_allowed, token, variable);
3392 note_implied(token);
3393 } else if (typeof site !== 'object') {
3395 warn(bundle.a_not_defined, token, variable);
3397 funct[variable] = true;
3399 note_implied(token);
3401 switch (site[variable]) {
3404 this['function'] = true;
3405 site[variable] = 'closure';
3406 funct[variable] = site['(global)'] ? false : 'outer';
3410 site[variable] = 'closure';
3411 funct[variable] = site['(global)'] ? true : 'outer';
3415 funct[variable] = site['(global)'] ? true : 'outer';
3418 warn(bundle.not_a_defined, token);
3421 warn(bundle.a_label, token, variable);
3430 fail(bundle.expected_operator_a);
3434 // Build the syntax table by declaring the syntactic elements of the language.
3436 type('(number)', 'number', return_this);
3437 type('(string)', 'string', return_this);
3438 type('(regexp)', 'regexp', return_this);
3439 type('(color)', 'color');
3440 type('(range)', 'range');
3442 ultimate('(begin)');
3444 ultimate('(error)');
3445 postscript(delim('</'));
3449 postscript(delim('}'));
3452 postscript(delim('"'));
3453 postscript(delim('\''));
3461 postscript(reserve('case'));
3463 postscript(reserve('default'));
3465 reservevar('arguments', function (x) {
3466 if (strict_mode && funct['(global)']) {
3467 warn(bundle.strict, x);
3468 } else if (option.safe) {
3469 warn(bundle.adsafe, x);
3472 reservevar('eval', function (x) {
3474 warn(bundle.adsafe, x);
3477 reservevar('false');
3478 reservevar('Infinity');
3481 reservevar('this', function (x) {
3482 if (strict_mode && ((funct['(statement)'] &&
3483 funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) {
3484 warn(bundle.strict, x);
3485 } else if (option.safe) {
3486 warn(bundle.adsafe, x);
3490 reservevar('undefined');
3495 assignop('/=').nud = function () {
3496 fail(bundle.slash_equal);
3499 assignop('&=', true);
3500 assignop('|=', true);
3501 assignop('^=', true);
3502 assignop('<<=', true);
3503 assignop('>>=', true);
3504 assignop('>>>=', true);
3505 infix('?', 30, function (left, that) {
3506 that.first = expected_condition(expected_relation(left));
3507 that.second = expression(0);
3512 that.third = expression(10);
3513 that.arity = 'ternary';
3514 if (are_similar(that.second, that.third)) {
3515 warn(bundle.weird_ternary, that);
3520 infix('||', 40, function (left, that) {
3521 function paren_check(that) {
3522 if (that.id === '&&' && !that.paren) {
3523 warn(bundle.and, that);
3528 that.first = paren_check(expected_condition(expected_relation(left)));
3529 that.second = paren_check(expected_relation(expression(40)));
3530 if (are_similar(that.first, that.second)) {
3531 warn(bundle.weird_condition, that);
3535 infix('&&', 50, function (left, that) {
3536 that.first = expected_condition(expected_relation(left));
3537 that.second = expected_relation(expression(50));
3538 if (are_similar(that.first, that.second)) {
3539 warn(bundle.weird_condition, that);
3543 prefix('void', function () {
3544 this.first = expression(0);
3545 if (this.first.arity !== 'number' || this.first.value) {
3546 warn(bundle.unexpected_a, this);
3554 relation('==', '===');
3556 relation('!=', '!==');
3564 bitwise('>>>', 120);
3565 infix('in', 120, function (left, that) {
3566 warn(bundle.infix_in, that);
3568 that.right = expression(130);
3571 infix('instanceof', 120);
3572 infix('+', 130, function (left, that) {
3574 if (left.arity === 'number') {
3575 warn(bundle.unexpected_a, left);
3576 } else if (left.arity === 'string') {
3577 warn(bundle.expected_a_b, left, 'String', '\'\'');
3580 var right = expression(130);
3582 if (right.arity === 'number') {
3583 warn(bundle.unexpected_a, right);
3584 } else if (right.arity === 'string') {
3585 warn(bundle.expected_a_b, right, 'String', '\'\'');
3588 if (left.arity === right.arity &&
3589 (left.arity === 'string' || left.arity === 'number')) {
3590 left.value += right.value;
3591 left.thru = right.thru;
3592 if (left.arity === 'string' && jx.test(left.value)) {
3593 warn(bundle.url, left);
3600 that.second = right;
3604 prefix('+++', function () {
3605 warn(bundle.confusing_a, token);
3606 this.first = expression(150);
3607 this.arity = 'prefix';
3610 infix('+++', 130, function (left) {
3611 warn(bundle.confusing_a, token);
3613 this.second = expression(130);
3616 infix('-', 130, function (left, that) {
3617 if ((left.arity === 'number' && left.value === 0) || left.arity === 'string') {
3618 warn(bundle.unexpected_a, left);
3620 var right = expression(130);
3621 if ((right.arity === 'number' && right.value === 0) || right.arity === 'string') {
3622 warn(bundle.unexpected_a, left);
3624 if (left.arity === right.arity && left.arity === 'number') {
3625 left.value -= right.value;
3626 left.thru = right.thru;
3632 that.second = right;
3636 prefix('---', function () {
3637 warn(bundle.confusing_a, token);
3638 this.first = expression(150);
3639 this.arity = 'prefix';
3642 infix('---', 130, function (left) {
3643 warn(bundle.confusing_a, token);
3645 this.second = expression(130);
3648 infix('*', 140, function (left, that) {
3649 if ((left.arity === 'number' && (left.value === 0 || left.value === 1)) || left.arity === 'string') {
3650 warn(bundle.unexpected_a, left);
3652 var right = expression(140);
3653 if ((right.arity === 'number' && (right.value === 0 || right.value === 1)) || right.arity === 'string') {
3654 warn(bundle.unexpected_a, right);
3656 if (left.arity === right.arity && left.arity === 'number') {
3657 left.value *= right.value;
3658 left.thru = right.thru;
3664 that.second = right;
3667 infix('/', 140, function (left, that) {
3668 if ((left.arity === 'number' && left.value === 0) || left.arity === 'string') {
3669 warn(bundle.unexpected_a, left);
3671 var right = expression(140);
3672 if ((right.arity === 'number' && (right.value === 0 || right.value === 1)) || right.arity === 'string') {
3673 warn(bundle.unexpected_a, right);
3675 if (left.arity === right.arity && left.arity === 'number') {
3676 left.value /= right.value;
3677 left.thru = right.thru;
3683 that.second = right;
3686 infix('%', 140, function (left, that) {
3687 if ((left.arity === 'number' && (left.value === 0 || left.value === 1)) || left.arity === 'string') {
3688 warn(bundle.unexpected_a, left);
3690 var right = expression(140);
3691 if ((right.arity === 'number' && (right.value === 0 || right.value === 1)) || right.arity === 'string') {
3692 warn(bundle.unexpected_a, right);
3694 if (left.arity === right.arity && left.arity === 'number') {
3695 left.value %= right.value;
3696 left.thru = right.thru;
3702 that.second = right;
3711 prefix('delete', function () {
3713 var p = expression(0);
3714 if (!p || (p.id !== '.' && p.id !== '[')) {
3715 warn(bundle.deleted);
3722 prefix('~', function () {
3724 if (option.bitwise) {
3725 warn(bundle.unexpected_a, this);
3730 prefix('!', function () {
3732 this.first = expression(150);
3733 this.arity = 'prefix';
3734 if (bang[this.first.id] === true) {
3735 warn(bundle.confusing_a, this);
3740 prefix('new', function () {
3742 var c = expression(160), i, p;
3744 if (c.id !== 'function') {
3748 warn(bundle.use_object, token);
3751 if (nexttoken.id === '(') {
3755 if (nexttoken.id !== ')') {
3756 p.second = expression(0);
3757 if (p.second.arity !== 'number' || !p.second.value) {
3758 expected_condition(p.second, bundle.use_array);
3763 while (nexttoken.id !== ')' && nexttoken.id !== '(end)') {
3765 warn(bundle.use_array, p);
3771 warn(bundle.use_array, token);
3777 warn(bundle.use_array, token);
3784 warn(bundle.not_a_constructor, c);
3788 warn(bundle.function_eval);
3795 if (c.id !== 'function') {
3796 i = c.value.substr(0, 1);
3797 if (option.newcap && (i < 'A' || i > 'Z')) {
3798 warn(bundle.constructor_name_a, token);
3803 if (c.id !== '.' && c.id !== '[' && c.id !== '(') {
3804 warn(bundle.bad_constructor, token);
3808 warn(bundle.weird_new, this);
3810 if (nexttoken.id !== '(') {
3811 warn(bundle.missing_a, nexttoken, '()');
3816 infix('(', 160, function (left, that) {
3817 if (indent && indent.mode === 'expression') {
3818 no_space(prevtoken, token);
3820 no_space_only(prevtoken, token);
3822 if (!left.immed && left.id === 'function') {
3823 warn(bundle.wrap_immediate);
3827 if (left.identifier) {
3828 if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
3829 if (left.value !== 'Number' && left.value !== 'String' &&
3830 left.value !== 'Boolean' && left.value !== 'Date') {
3831 if (left.value === 'Math' || left.value === 'JSON') {
3832 warn(bundle.not_a_function, left);
3833 } else if (left.value === 'Object') {
3834 warn(bundle.use_object, token);
3835 } else if (left.value === 'Array' || option.newcap) {
3836 warn(bundle.missing_a, left, 'new');
3840 } else if (left.id === '.') {
3841 if (option.safe && left.first.value === 'Math' &&
3842 left.second === 'random') {
3843 warn(bundle.adsafe, left);
3848 if (nexttoken.id !== ')') {
3852 p.push(expression(10));
3853 if (nexttoken.id !== ',') {
3860 step_out(')', that);
3861 if (typeof left === 'object') {
3862 if (left.value === 'parseInt' && p.length === 1) {
3863 warn(bundle.radix, left);
3866 if (left.value === 'eval' || left.value === 'Function' ||
3867 left.value === 'execScript') {
3868 warn(bundle.evil, left);
3869 } else if (p[0] && p[0].arity === 'string' &&
3870 (left.value === 'setTimeout' ||
3871 left.value === 'setInterval')) {
3872 warn(bundle.implied_evil, left);
3875 if (!left.identifier && left.id !== '.' && left.id !== '[' &&
3876 left.id !== '(' && left.id !== '&&' && left.id !== '||' &&
3878 warn(bundle.bad_invocation, left);
3886 prefix('(', function () {
3887 step_in('expression');
3891 if (nexttoken.id === 'function') {
3892 nexttoken.immed = true;
3894 var value = expression(0);
3897 step_out(')', this);
3899 if (value.id === 'function') {
3900 if (nexttoken.id === '(') {
3901 warn(bundle.move_invocation);
3903 warn(bundle.bad_wrap, this);
3909 infix('.', 170, function (left, that) {
3910 no_space(prevtoken, token);
3912 var m = identifier();
3913 if (typeof m === 'string') {
3917 that.second = token;
3918 if (left && left.value === 'arguments' &&
3919 (m === 'callee' || m === 'caller')) {
3920 warn(bundle.avoid_a, left, 'arguments.' + m);
3921 } else if (!option.evil && left && left.value === 'document' &&
3922 (m === 'write' || m === 'writeln')) {
3923 warn(bundle.write_is_wrong, left);
3924 } else if (option.adsafe) {
3925 if (!adsafe_top && left.value === 'ADSAFE') {
3926 if (m === 'id' || m === 'lib') {
3927 warn(bundle.adsafe, that);
3928 } else if (m === 'go') {
3929 if (xmode !== 'script') {
3930 warn(bundle.adsafe, that);
3931 } else if (adsafe_went || nexttoken.id !== '(' ||
3932 peek(0).arity !== 'string' ||
3933 peek(0).value !== adsafe_id ||
3934 peek(1).id !== ',') {
3935 fail(bundle.adsafe_a, that, 'go');
3943 if (!option.evil && (m === 'eval' || m === 'execScript')) {
3945 } else if (option.safe) {
3947 if (banned[m] === true) {
3948 warn(bundle.adsafe_a, token, m);
3950 if (typeof predefined[left.value] !== 'boolean' ||
3951 nexttoken.id === '(') {
3954 if (standard_member[m] === true) {
3955 if (nexttoken.id === '.') {
3956 warn(bundle.adsafe, that);
3960 if (nexttoken.id !== '.') {
3961 warn(bundle.adsafe, that);
3969 if (typeof m === 'string') {
3977 infix('[', 170, function (left, that) {
3978 no_space_only(prevtoken, token);
3982 var e = expression(0), s;
3983 if (e.arity === 'string') {
3984 if (option.safe && banned[e.value] === true) {
3985 warn(bundle.adsafe_a, e);
3986 } else if (!option.evil &&
3987 (e.value === 'eval' || e.value === 'execScript')) {
3988 warn(bundle.evil, e);
3989 } else if (option.safe &&
3990 (e.value.charAt(0) === '_' || e.value.charAt(0) === '-')) {
3991 warn(bundle.adsafe_subscript_a, e);
3993 tally_member(e.value);
3994 if (!option.sub && ix.test(e.value)) {
3995 s = syntax[e.value];
3996 if (!s || !s.reserved) {
3997 warn(bundle.subscript, e);
4000 } else if (e.arity !== 'number' || e.value < 0) {
4002 warn(bundle.adsafe_subscript_a, e);
4005 step_out(']', that);
4007 no_space(prevtoken, token);
4013 prefix('[', function () {
4014 this.arity = 'prefix';
4017 while (nexttoken.id !== '(end)') {
4018 while (nexttoken.id === ',') {
4019 warn(bundle.unexpected_a, nexttoken);
4023 if (nexttoken.id === ']') {
4027 this.first.push(expression(10));
4028 if (nexttoken.id === ',') {
4030 if (nexttoken.id === ']' && !option.es5) {
4031 warn(bundle.unexpected_a, token);
4038 step_out(']', this);
4044 function property_name() {
4045 var id = optional_identifier(true);
4047 if (nexttoken.arity === 'string') {
4048 id = nexttoken.value;
4051 warn(bundle.adsafe_a);
4052 } else if (id.charAt(0) === '_' ||
4053 id.charAt(id.length - 1) === '_') {
4054 warn(bundle.dangling_a);
4058 } else if (nexttoken.arity === 'number') {
4059 id = nexttoken.value.toString();
4067 function function_params() {
4068 var id, paren = nexttoken, params = [];
4073 if (nexttoken.id === ')') {
4075 step_out(')', paren);
4083 add_label(id, 'parameter');
4084 if (nexttoken.id === ',') {
4088 step_out(')', paren);
4096 function do_function(func, name) {
4097 var old_properties = properties,
4098 old_option = option,
4099 old_global = global,
4102 '(name)' : name || '"' + anonname + '"',
4103 '(line)' : nexttoken.line,
4104 '(context)' : funct,
4110 properties = old_properties && Object.create(old_properties);
4111 option = Object.create(old_option);
4112 global = Object.create(old_global);
4113 scope = Object.create(old_scope);
4114 token.funct = funct;
4115 functions.push(funct);
4117 add_label(name, 'function');
4119 func.name = name || '';
4120 func.first = funct['(params)'] = function_params();
4122 func.block = block(false);
4123 funct = funct['(context)'];
4124 properties = old_properties;
4125 option = old_option;
4126 global = old_global;
4131 prefix('{', function () {
4132 var get, i, j, name, p, set, seen = {}, t;
4133 this.arity = 'prefix';
4136 while (nexttoken.id !== '}') {
4138 // JSLint recognizes the ES5 extension for get/set in object literals,
4139 // but requires that they be used in pairs.
4142 if (nexttoken.value === 'get' && peek().id !== ':') {
4144 warn(bundle.get_set);
4150 i = property_name();
4152 fail(bundle.missing_property);
4154 do_function(get, '');
4155 if (funct['(loopage)']) {
4156 warn(bundle.function_loop, t);
4160 warn(bundle.parameter_a_get_b, t, p[0], i);
4168 j = property_name();
4170 fail(bundle.expected_a_b, token, i, j);
4172 do_function(set, '');
4174 if (!p || p.length !== 1 || p[0] !== 'value') {
4175 warn(bundle.parameter_set_a, t, i);
4177 name.first = [get, set];
4180 i = property_name();
4181 if (typeof i !== 'string') {
4182 fail(bundle.missing_property);
4187 name.first = expression(10);
4189 this.first.push(name);
4190 if (seen[i] === true) {
4191 warn(bundle.duplicate_a, nexttoken, i);
4195 if (nexttoken.id !== ',') {
4200 if (nexttoken.id !== ',') {
4203 warn(bundle.unexpected_a, nexttoken);
4205 if (nexttoken.id === '}' && !option.es5) {
4206 warn(bundle.unexpected_a, token);
4209 step_out('}', this);
4214 stmt('{', function () {
4216 warn(bundle.statement_block);
4217 this.arity = 'statement';
4218 this.block = statements();
4219 this.disrupt = this.block.disrupt;
4225 stmt('/*properties', directive);
4226 stmt('/*members', directive);
4227 stmt('/*jslint', directive);
4228 stmt('/*global', directive);
4232 stmt('var', function () {
4234 // JavaScript does not have block scope. It only has function scope. So,
4235 // declaring a variable in a block can have unexpected consequences.
4237 // var.first will contain an array, the array containing name tokens
4238 // and assignment tokens.
4240 var assign, id, name;
4242 if (funct['(onevar)'] && option.onevar) {
4243 warn(bundle.combine_var);
4244 } else if (!funct['(global)']) {
4245 funct['(onevar)'] = true;
4247 this.arity = 'statement';
4253 if (funct['(global)'] && predefined[id] === false) {
4254 warn(bundle.redefinition_a, token, id);
4256 add_label(id, 'error');
4258 if (nexttoken.id === '=') {
4260 assign.first = name;
4264 if (nexttoken.id === 'undefined') {
4265 warn(bundle.unnecessary_initialize, token, id);
4267 if (peek(0).id === '=' && nexttoken.identifier) {
4268 fail(bundle.var_a_not);
4270 assign.second = expression(0);
4271 assign.arity = 'infix';
4272 this.first.push(assign);
4274 this.first.push(name);
4276 funct[id] = 'unused';
4277 if (nexttoken.id !== ',') {
4281 if (var_mode && nexttoken.line === token.line &&
4282 this.first.length === 1) {
4284 indent.open = false;
4285 indent.at -= option.indent;
4295 stmt('function', function () {
4298 warn(bundle.function_block, token);
4300 var i = identifier();
4302 add_label(i, 'unction');
4305 do_function(this, i, true);
4306 if (nexttoken.id === '(' && nexttoken.line === token.line) {
4307 fail(bundle.function_statement);
4309 this.arity = 'statement';
4313 prefix('function', function () {
4315 var i = optional_identifier();
4319 do_function(this, i);
4320 if (funct['(loopage)']) {
4321 warn(bundle.function_loop);
4323 this.arity = 'function';
4327 stmt('if', function () {
4335 this.arity = 'statement';
4336 this.first = expected_condition(expected_relation(expression(0)));
4341 this.block = block(true);
4342 if (nexttoken.id === 'else') {
4347 this['else'] = nexttoken.id === 'if' || nexttoken.id === 'switch' ?
4348 statement(true) : block(true);
4349 if (this['else'].disrupt && this.block.disrupt) {
4350 this.disrupt = true;
4356 stmt('try', function () {
4358 // try.first The catch variable
4359 // try.second The catch clause
4360 // try.third The finally clause
4361 // try.block The try block
4364 if (option.adsafe) {
4365 warn(bundle.adsafe_a, this);
4368 this.arity = 'statement';
4369 this.block = block(false);
4370 if (nexttoken.id === 'catch') {
4382 scope = Object.create(s);
4383 e = nexttoken.value;
4385 if (!nexttoken.identifier) {
4386 warn(bundle.expected_identifier_a, nexttoken);
4388 add_label(e, 'exception');
4395 this.second = block(false);
4399 if (nexttoken.id === 'finally') {
4406 this.third = block(false);
4408 fail(bundle.expected_a_b, nexttoken, 'catch', nexttoken.value);
4414 labeled_stmt('while', function () {
4417 funct['(breakage)'] += 1;
4418 funct['(loopage)'] += 1;
4424 this.arity = 'statement';
4425 this.first = expected_relation(expression(0));
4426 if (this.first.id !== 'true') {
4427 expected_condition(this.first, bundle.unexpected_a);
4433 this.block = block(true);
4434 if (this.block.disrupt) {
4435 warn(bundle.strange_loop, prevtoken);
4437 funct['(breakage)'] -= 1;
4438 funct['(loopage)'] -= 1;
4444 labeled_stmt('switch', function () {
4446 // switch.first the switch expression
4447 // switch.second the array of cases. A case is 'case' or 'default' token:
4448 // case.first the array of case expressions
4449 // case.second the array of statements
4450 // If all of the arrays of statements are disrupt, then the switch is disrupt.
4453 the_case = nexttoken,
4455 funct['(breakage)'] += 1;
4461 this.arity = 'statement';
4462 this.first = expected_condition(expected_relation(expression(0)));
4464 step_out(')', the_case);
4470 while (nexttoken.id === 'case') {
4471 the_case = nexttoken;
4472 the_case.first = [];
4478 particular = expression(0);
4479 the_case.first.push(particular);
4480 if (particular.id === 'NaN') {
4481 warn(bundle.unexpected_a, particular);
4486 if (nexttoken.id !== 'case') {
4495 the_case.second = statements();
4496 if (the_case.second && the_case.second.length > 0) {
4497 particular = the_case.second[the_case.second.length - 1];
4498 if (particular.disrupt) {
4499 if (particular.id === 'break') {
4503 warn(bundle.missing_a_after_b, nexttoken, 'break', 'case');
4506 warn(bundle.empty_case);
4508 this.second.push(the_case);
4510 if (this.second.length === 0) {
4511 warn(bundle.missing_a, nexttoken, 'case');
4513 if (nexttoken.id === 'default') {
4515 the_case = nexttoken;
4523 the_case.second = statements();
4524 if (the_case.second && the_case.second.length > 0) {
4525 particular = the_case.second[the_case.second.length - 1];
4526 if (unbroken && particular.disrupt && particular.id !== 'break') {
4527 this.disrupt = true;
4530 this.second.push(the_case);
4532 funct['(breakage)'] -= 1;
4534 step_out('}', this);
4538 stmt('debugger', function () {
4539 if (!option.debug) {
4540 warn(bundle.unexpected_a, this);
4542 this.arity = 'statement';
4546 labeled_stmt('do', function () {
4547 funct['(breakage)'] += 1;
4548 funct['(loopage)'] += 1;
4550 this.arity = 'statement';
4551 this.block = block(true);
4552 if (this.block.disrupt) {
4553 warn(bundle.strange_loop, prevtoken);
4565 this.first = expected_condition(expected_relation(expression(0)), bundle.unexpected_a);
4569 funct['(breakage)'] -= 1;
4570 funct['(loopage)'] -= 1;
4574 labeled_stmt('for', function () {
4575 var blok, filter, ok = false, paren = nexttoken, the_in, value;
4576 this.arity = 'statement';
4577 funct['(breakage)'] += 1;
4578 funct['(loopage)'] += 1;
4582 spaces(this, paren);
4584 if (nexttoken.id === 'var') {
4585 fail(bundle.move_var);
4588 if (peek(0).id === 'in') {
4590 switch (funct[value.value]) {
4592 funct[value.value] = 'var';
4597 warn(bundle.bad_in_a, value);
4602 the_in.first = value;
4603 the_in.second = expression(20);
4604 step_out(')', paren);
4606 this.first = the_in;
4608 if (!option.forin) {
4609 if (blok.length === 1 && typeof blok[0] === 'object' &&
4610 blok[0].value === 'if' && !blok[0]['else']) {
4611 filter = blok[0].first;
4612 while (filter.id === '&&') {
4613 filter = filter.first;
4615 switch (filter.id) {
4618 ok = filter.first.id === '[' ? (
4619 filter.first.first.value === the_in.second.value &&
4620 filter.first.second.value === the_in.first.value
4622 filter.first.id === 'typeof' &&
4623 filter.first.first.id === '[' &&
4624 filter.first.first.first.value === the_in.second.value &&
4625 filter.first.first.second.value === the_in.first.value
4629 ok = filter.first.id === '.' && ((
4630 filter.first.first.value === the_in.second.value &&
4631 filter.first.second.value === 'hasOwnProperty' &&
4632 filter.second[0].value === the_in.first.value
4634 filter.first.first.value === 'ADSAFE' &&
4635 filter.first.second.value === 'has' &&
4636 filter.second[0].value === the_in.second.value &&
4637 filter.second[1].value === the_in.first.value
4639 filter.first.first.id === '.' &&
4640 filter.first.first.first.id === '.' &&
4641 filter.first.first.first.first.value === 'Object' &&
4642 filter.first.first.first.second.value === 'prototype' &&
4643 filter.first.first.second.value === 'hasOwnProperty' &&
4644 filter.first.second.value === 'call' &&
4645 filter.second[0].value === the_in.second.value &&
4646 filter.second[1].value === the_in.first.value
4652 warn(bundle.for_if, this);
4656 if (nexttoken.id !== ';') {
4660 this.first.push(expression(0, 'for'));
4661 if (nexttoken.id !== ',') {
4668 if (nexttoken.id !== ';') {
4670 this.second = expected_relation(expression(0));
4671 if (this.second.id !== 'true') {
4672 expected_condition(this.second, bundle.unexpected_a);
4676 if (nexttoken.id === ';') {
4677 fail(bundle.expected_a_b, nexttoken, ')', ';');
4679 if (nexttoken.id !== ')') {
4683 this.third.push(expression(0, 'for'));
4684 if (nexttoken.id !== ',') {
4691 step_out(')', paren);
4697 warn(bundle.strange_loop, prevtoken);
4700 funct['(breakage)'] -= 1;
4701 funct['(loopage)'] -= 1;
4706 disrupt_stmt('break', function () {
4707 var v = nexttoken.value;
4708 this.arity = 'statement';
4709 if (funct['(breakage)'] === 0) {
4710 warn(bundle.unexpected_a, this);
4712 if (nexttoken.identifier && token.line === nexttoken.line) {
4714 if (funct[v] !== 'label') {
4715 warn(bundle.not_a_label, nexttoken);
4716 } else if (scope[v] !== funct) {
4717 warn(bundle.not_a_scope, nexttoken);
4719 this.first = nexttoken;
4726 disrupt_stmt('continue', function () {
4727 if (!option['continue']) {
4728 warn(bundle.unexpected_a, this);
4730 var v = nexttoken.value;
4731 this.arity = 'statement';
4732 if (funct['(breakage)'] === 0) {
4733 warn(bundle.unexpected_a, this);
4735 if (nexttoken.identifier && token.line === nexttoken.line) {
4737 if (funct[v] !== 'label') {
4738 warn(bundle.not_a_label, nexttoken);
4739 } else if (scope[v] !== funct) {
4740 warn(bundle.not_a_scope, nexttoken);
4742 this.first = nexttoken;
4749 disrupt_stmt('return', function () {
4750 this.arity = 'statement';
4751 if (nexttoken.id !== ';' && nexttoken.line === token.line) {
4753 if (nexttoken.id === '/' || nexttoken.id === '(regexp)') {
4754 warn(bundle.wrap_regexp);
4756 this.first = expression(20);
4762 disrupt_stmt('throw', function () {
4763 this.arity = 'statement';
4765 this.first = expression(20);
4770 // Superfluous reserved words
4780 // Harmony reserved words
4784 reserve('implements');
4785 reserve('interface');
4788 reserve('protected');
4795 function json_value() {
4797 function json_object() {
4798 var o = {}, t = nexttoken;
4800 if (nexttoken.id !== '}') {
4801 while (nexttoken.id !== '(end)') {
4802 while (nexttoken.id === ',') {
4803 warn(bundle.unexpected_a, nexttoken);
4806 if (nexttoken.arity !== 'string') {
4807 warn(bundle.expected_string_a);
4809 if (o[nexttoken.value] === true) {
4810 warn(bundle.duplicate_a);
4811 } else if (nexttoken.value === '__proto__') {
4812 warn(bundle.dangling_a);
4814 o[nexttoken.value] = true;
4819 if (nexttoken.id !== ',') {
4823 if (nexttoken.id === '}') {
4824 warn(bundle.unexpected_a, token);
4832 function json_array() {
4835 if (nexttoken.id !== ']') {
4836 while (nexttoken.id !== '(end)') {
4837 while (nexttoken.id === ',') {
4838 warn(bundle.unexpected_a, nexttoken);
4842 if (nexttoken.id !== ',') {
4846 if (nexttoken.id === ']') {
4847 warn(bundle.unexpected_a, token);
4855 switch (nexttoken.id) {
4872 advance('(number)');
4875 fail(bundle.unexpected_a);
4882 function css_name() {
4883 if (nexttoken.identifier) {
4890 function css_number() {
4891 if (nexttoken.id === '-') {
4895 if (nexttoken.arity === 'number') {
4896 advance('(number)');
4902 function css_string() {
4903 if (nexttoken.arity === 'string') {
4909 function css_color() {
4910 var i, number, t, value;
4911 if (nexttoken.identifier) {
4912 value = nexttoken.value;
4913 if (value === 'rgb' || value === 'rgba') {
4917 for (i = 0; i < 3; i += 1) {
4921 number = nexttoken.value;
4922 if (nexttoken.arity !== 'number' || number < 0) {
4923 warn(bundle.expected_positive_a, nexttoken);
4927 if (nexttoken.id === '%') {
4930 warn(bundle.expected_percent_a, token, number);
4934 warn(bundle.expected_small_a, token, number);
4939 if (value === 'rgba') {
4941 number = +nexttoken.value;
4942 if (nexttoken.arity !== 'number' || number < 0 || number > 1) {
4943 warn(bundle.expected_fraction_a, nexttoken);
4946 if (nexttoken.id === '%') {
4947 warn(bundle.unexpected_a);
4953 } else if (css_colorData[nexttoken.value] === true) {
4957 } else if (nexttoken.id === '(color)') {
4965 function css_length() {
4966 if (nexttoken.id === '-') {
4970 if (nexttoken.arity === 'number') {
4972 if (nexttoken.arity !== 'string' &&
4973 css_lengthData[nexttoken.value] === true) {
4976 } else if (+token.value !== 0) {
4977 warn(bundle.expected_linear_a);
4985 function css_line_height() {
4986 if (nexttoken.id === '-') {
4990 if (nexttoken.arity === 'number') {
4992 if (nexttoken.arity !== 'string' &&
4993 css_lengthData[nexttoken.value] === true) {
5003 function css_width() {
5004 if (nexttoken.identifier) {
5005 switch (nexttoken.value) {
5013 return css_length();
5018 function css_margin() {
5019 if (nexttoken.identifier) {
5020 if (nexttoken.value === 'auto') {
5025 return css_length();
5029 function css_attr() {
5030 if (nexttoken.identifier && nexttoken.value === 'attr') {
5033 if (!nexttoken.identifier) {
5034 warn(bundle.expected_name_a);
5044 function css_comma_list() {
5045 while (nexttoken.id !== ';') {
5046 if (!css_name() && !css_string()) {
5047 warn(bundle.expected_name_a);
5049 if (nexttoken.id !== ',') {
5057 function css_counter() {
5058 if (nexttoken.identifier && nexttoken.value === 'counter') {
5062 if (nexttoken.id === ',') {
5064 if (nexttoken.arity !== 'string') {
5065 warn(bundle.expected_string_a);
5072 if (nexttoken.identifier && nexttoken.value === 'counters') {
5075 if (!nexttoken.identifier) {
5076 warn(bundle.expected_name_a);
5079 if (nexttoken.id === ',') {
5081 if (nexttoken.arity !== 'string') {
5082 warn(bundle.expected_string_a);
5086 if (nexttoken.id === ',') {
5088 if (nexttoken.arity !== 'string') {
5089 warn(bundle.expected_string_a);
5100 function css_shape() {
5102 if (nexttoken.identifier && nexttoken.value === 'rect') {
5105 for (i = 0; i < 4; i += 1) {
5106 if (!css_length()) {
5107 warn(bundle.expected_number_a);
5118 function css_url() {
5120 if (nexttoken.identifier && nexttoken.value === 'url') {
5121 nexttoken = lex.range('(', ')');
5122 url = nexttoken.value;
5124 if (c === '"' || c === '\'') {
5125 if (url.slice(-1) !== c) {
5126 warn(bundle.bad_url);
5128 url = url.slice(1, -1);
5129 if (url.indexOf(c) >= 0) {
5130 warn(bundle.bad_url);
5135 warn(bundle.missing_url);
5137 if (option.safe && ux.test(url)) {
5138 fail(bundle.adsafe_a, nexttoken, url);
5148 css_any = [css_url, function () {
5150 if (nexttoken.identifier) {
5151 switch (nexttoken.value.toLowerCase()) {
5156 warn(bundle.unexpected_a);
5163 if (nexttoken.id === ';' || nexttoken.id === '!' ||
5164 nexttoken.id === '(end)' || nexttoken.id === '}') {
5173 css_border_style = [
5174 'none', 'dashed', 'dotted', 'double', 'groove',
5175 'hidden', 'inset', 'outset', 'ridge', 'solid'
5179 'auto', 'always', 'avoid', 'left', 'right'
5196 'auto', 'hidden', 'scroll', 'visible'
5199 css_attribute_data = {
5201 true, 'background-attachment', 'background-color',
5202 'background-image', 'background-position', 'background-repeat'
5204 'background-attachment': ['scroll', 'fixed'],
5205 'background-color': ['transparent', css_color],
5206 'background-image': ['none', css_url],
5207 'background-position': [
5208 2, [css_length, 'top', 'bottom', 'left', 'right', 'center']
5210 'background-repeat': [
5211 'repeat', 'repeat-x', 'repeat-y', 'no-repeat'
5213 'border': [true, 'border-color', 'border-style', 'border-width'],
5215 true, 'border-bottom-color', 'border-bottom-style',
5216 'border-bottom-width'
5218 'border-bottom-color': css_color,
5219 'border-bottom-style': css_border_style,
5220 'border-bottom-width': css_width,
5221 'border-collapse': ['collapse', 'separate'],
5222 'border-color': ['transparent', 4, css_color],
5224 true, 'border-left-color', 'border-left-style', 'border-left-width'
5226 'border-left-color': css_color,
5227 'border-left-style': css_border_style,
5228 'border-left-width': css_width,
5230 true, 'border-right-color', 'border-right-style',
5231 'border-right-width'
5233 'border-right-color': css_color,
5234 'border-right-style': css_border_style,
5235 'border-right-width': css_width,
5236 'border-spacing': [2, css_length],
5237 'border-style': [4, css_border_style],
5239 true, 'border-top-color', 'border-top-style', 'border-top-width'
5241 'border-top-color': css_color,
5242 'border-top-style': css_border_style,
5243 'border-top-width': css_width,
5244 'border-width': [4, css_width],
5245 bottom: [css_length, 'auto'],
5246 'caption-side' : ['bottom', 'left', 'right', 'top'],
5247 clear: ['both', 'left', 'none', 'right'],
5248 clip: [css_shape, 'auto'],
5251 'open-quote', 'close-quote', 'no-open-quote', 'no-close-quote',
5252 css_string, css_url, css_counter, css_attr
5254 'counter-increment': [
5261 css_url, 'auto', 'crosshair', 'default', 'e-resize', 'help', 'move',
5262 'n-resize', 'ne-resize', 'nw-resize', 'pointer', 's-resize',
5263 'se-resize', 'sw-resize', 'w-resize', 'text', 'wait'
5265 direction: ['ltr', 'rtl'],
5267 'block', 'compact', 'inline', 'inline-block', 'inline-table',
5268 'list-item', 'marker', 'none', 'run-in', 'table', 'table-caption',
5269 'table-cell', 'table-column', 'table-column-group',
5270 'table-footer-group', 'table-header-group', 'table-row',
5273 'empty-cells': ['show', 'hide'],
5274 'float': ['left', 'none', 'right'],
5276 'caption', 'icon', 'menu', 'message-box', 'small-caption',
5277 'status-bar', true, 'font-size', 'font-style', 'font-weight',
5280 'font-family': css_comma_list,
5282 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large',
5283 'xx-large', 'larger', 'smaller', css_length
5285 'font-size-adjust': ['none', css_number],
5287 'normal', 'wider', 'narrower', 'ultra-condensed',
5288 'extra-condensed', 'condensed', 'semi-condensed',
5289 'semi-expanded', 'expanded', 'extra-expanded'
5292 'normal', 'italic', 'oblique'
5295 'normal', 'small-caps'
5298 'normal', 'bold', 'bolder', 'lighter', css_number
5300 height: [css_length, 'auto'],
5301 left: [css_length, 'auto'],
5302 'letter-spacing': ['normal', css_length],
5303 'line-height': ['normal', css_line_height],
5305 true, 'list-style-image', 'list-style-position', 'list-style-type'
5307 'list-style-image': ['none', css_url],
5308 'list-style-position': ['inside', 'outside'],
5309 'list-style-type': [
5310 'circle', 'disc', 'square', 'decimal', 'decimal-leading-zero',
5311 'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha',
5312 'lower-latin', 'upper-alpha', 'upper-latin', 'hebrew', 'katakana',
5313 'hiragana-iroha', 'katakana-oroha', 'none'
5315 margin: [4, css_margin],
5316 'margin-bottom': css_margin,
5317 'margin-left': css_margin,
5318 'margin-right': css_margin,
5319 'margin-top': css_margin,
5320 'marker-offset': [css_length, 'auto'],
5321 'max-height': [css_length, 'none'],
5322 'max-width': [css_length, 'none'],
5323 'min-height': css_length,
5324 'min-width': css_length,
5325 opacity: css_number,
5326 outline: [true, 'outline-color', 'outline-style', 'outline-width'],
5327 'outline-color': ['invert', css_color],
5329 'dashed', 'dotted', 'double', 'groove', 'inset', 'none',
5330 'outset', 'ridge', 'solid'
5332 'outline-width': css_width,
5333 overflow: css_overflow,
5334 'overflow-x': css_overflow,
5335 'overflow-y': css_overflow,
5336 padding: [4, css_length],
5337 'padding-bottom': css_length,
5338 'padding-left': css_length,
5339 'padding-right': css_length,
5340 'padding-top': css_length,
5341 'page-break-after': css_break,
5342 'page-break-before': css_break,
5343 position: ['absolute', 'fixed', 'relative', 'static'],
5344 quotes: [8, css_string],
5345 right: [css_length, 'auto'],
5346 'table-layout': ['auto', 'fixed'],
5347 'text-align': ['center', 'justify', 'left', 'right'],
5348 'text-decoration': [
5349 'none', 'underline', 'overline', 'line-through', 'blink'
5351 'text-indent': css_length,
5352 'text-shadow': ['none', 4, [css_color, css_length]],
5353 'text-transform': ['capitalize', 'uppercase', 'lowercase', 'none'],
5354 top: [css_length, 'auto'],
5355 'unicode-bidi': ['normal', 'embed', 'bidi-override'],
5357 'baseline', 'bottom', 'sub', 'super', 'top', 'text-top', 'middle',
5358 'text-bottom', css_length
5360 visibility: ['visible', 'hidden', 'collapse'],
5362 'normal', 'nowrap', 'pre', 'pre-line', 'pre-wrap', 'inherit'
5364 width: [css_length, 'auto'],
5365 'word-spacing': ['normal', css_length],
5366 'word-wrap': ['break-word', 'normal'],
5367 'z-index': ['auto', css_number]
5370 function style_attribute() {
5372 while (nexttoken.id === '*' || nexttoken.id === '#' ||
5373 nexttoken.value === '_') {
5375 warn(bundle.unexpected_a);
5379 if (nexttoken.id === '-') {
5381 warn(bundle.unexpected_a);
5384 if (!nexttoken.identifier) {
5385 warn(bundle.expected_nonstandard_style_attribute);
5390 if (!nexttoken.identifier) {
5391 warn(bundle.expected_style_attribute);
5393 if (Object.prototype.hasOwnProperty.call(css_attribute_data, nexttoken.value)) {
5394 v = css_attribute_data[nexttoken.value];
5398 warn(bundle.unrecognized_style_attribute_a);
5408 function style_value(v) {
5420 if (nexttoken.identifier && nexttoken.value === v) {
5427 if (i >= v.length) {
5434 } else if (typeof vi === 'number') {
5443 if (style_value(vi)) {
5458 for (i = start; i < v.length; i += 1) {
5460 if (style_value(css_attribute_data[v[i]])) {
5474 function style_child() {
5475 if (nexttoken.arity === 'number') {
5477 if (nexttoken.value === 'n' && nexttoken.identifier) {
5480 if (nexttoken.id === '+') {
5484 advance('(number)');
5489 if (nexttoken.identifier &&
5490 (nexttoken.value === 'odd' || nexttoken.value === 'even')) {
5495 warn(bundle.unexpected_a);
5498 function substyle() {
5501 if (nexttoken.id === '}' || nexttoken.id === '(end)' ||
5502 (xquote && nexttoken.id === xquote)) {
5505 while (nexttoken.id === ';') {
5506 warn(bundle.unexpected_a);
5509 v = style_attribute();
5511 if (nexttoken.identifier && nexttoken.value === 'inherit') {
5514 if (!style_value(v)) {
5515 warn(bundle.unexpected_a);
5519 if (nexttoken.id === '!') {
5522 if (nexttoken.identifier && nexttoken.value === 'important') {
5525 warn(bundle.expected_a_b,
5526 nexttoken, 'important', nexttoken.value);
5529 if (nexttoken.id === '}' || nexttoken.id === xquote) {
5530 warn(bundle.expected_a_b, nexttoken, ';', nexttoken.value);
5537 function style_selector() {
5538 if (nexttoken.identifier) {
5539 if (!Object.prototype.hasOwnProperty.call(html_tag, option.cap ?
5540 nexttoken.value.toLowerCase() : nexttoken.value)) {
5541 warn(bundle.expected_tagname_a);
5545 switch (nexttoken.id) {
5553 switch (nexttoken.value) {
5562 case 'first-letter':
5564 case 'first-of-type':
5568 case 'last-of-type':
5570 case 'only-of-type':
5579 if (!nexttoken.identifier) {
5580 warn(bundle.expected_lang_a);
5585 case 'nth-last-child':
5586 case 'nth-last-of-type':
5596 if (nexttoken.id === ':' && peek(0).value === 'not') {
5603 warn(bundle.expected_pseudo_a);
5608 if (!nexttoken.identifier) {
5609 warn(bundle.expected_id_a);
5618 if (!nexttoken.identifier) {
5619 warn(bundle.expected_class_a);
5625 if (!nexttoken.identifier) {
5626 warn(bundle.expected_attribute_a);
5629 if (nexttoken.id === '=' || nexttoken.value === '~=' ||
5630 nexttoken.value === '$=' ||
5631 nexttoken.value === '|=' ||
5632 nexttoken.id === '*=' ||
5633 nexttoken.id === '^=') {
5635 if (nexttoken.arity !== 'string') {
5636 warn(bundle.expected_string_a);
5643 fail(bundle.expected_selector_a);
5648 function style_pattern() {
5649 if (nexttoken.id === '{') {
5650 warn(bundle.expected_style_pattern);
5654 if (nexttoken.id === '</' || nexttoken.id === '{' ||
5655 nexttoken.id === '(end)') {
5658 if (nexttoken.id === ',') {
5664 function style_list() {
5665 while (nexttoken.id !== '</' && nexttoken.id !== '(end)') {
5667 xmode = 'styleproperty';
5668 if (nexttoken.id === ';') {
5681 while (nexttoken.id === '@') {
5684 if (nexttoken.identifier) {
5685 switch (nexttoken.value) {
5689 warn(bundle.expected_a_b,
5690 nexttoken, 'url', nexttoken.value);
5698 if (!nexttoken.identifier || css_media[nexttoken.value] === true) {
5699 fail(bundle.expected_media_a);
5702 if (nexttoken.id !== ',') {
5712 warn(bundle.expected_at_a);
5715 warn(bundle.expected_at_a);
5724 function do_begin(n) {
5725 if (n !== 'html' && !option.fragment) {
5726 if (n === 'div' && option.adsafe) {
5727 fail(bundle.adsafe_fragment);
5729 fail(bundle.expected_a_b, token, 'html', n);
5732 if (option.adsafe) {
5734 fail(bundle.adsafe_html, token);
5736 if (option.fragment) {
5738 fail(bundle.adsafe_div, token);
5741 fail(bundle.adsafe_fragment, token);
5744 option.browser = true;
5748 function do_attribute(n, a, v) {
5751 u = typeof v === 'string' ? v.toUpperCase() : '';
5752 if (ids[u] === true) {
5753 warn(bundle.duplicate_a, nexttoken, v);
5755 if (!/^[A-Za-z][A-Za-z0-9._:\-]*$/.test(v)) {
5756 warn(bundle.bad_id_a, nexttoken, v);
5757 } else if (option.adsafe) {
5759 if (v.slice(0, adsafe_id.length) !== adsafe_id) {
5760 warn(bundle.adsafe_prefix_a, nexttoken, adsafe_id);
5761 } else if (!/^[A-Z]+_[A-Z]+$/.test(v)) {
5762 warn(bundle.adsafe_bad_id);
5766 if (!/^[A-Z]+_$/.test(v)) {
5767 warn(bundle.adsafe_bad_id);
5773 warn(bundle.unexpected_char_a_b, token, v.charAt(x), a);
5776 } else if (a === 'class' || a === 'type' || a === 'name') {
5779 warn(bundle.unexpected_char_a_b, token, v.charAt(x), a);
5782 } else if (a === 'href' || a === 'background' ||
5783 a === 'content' || a === 'data' ||
5784 a.indexOf('src') >= 0 || a.indexOf('url') >= 0) {
5785 if (option.safe && ux.test(v)) {
5786 fail(bundle.bad_url, nexttoken, v);
5789 } else if (a === 'for') {
5790 if (option.adsafe) {
5792 if (v.slice(0, adsafe_id.length) !== adsafe_id) {
5793 warn(bundle.adsafe_prefix_a, nexttoken, adsafe_id);
5794 } else if (!/^[A-Z]+_[A-Z]+$/.test(v)) {
5795 warn(bundle.adsafe_bad_id);
5798 warn(bundle.adsafe_bad_id);
5801 } else if (a === 'name') {
5802 if (option.adsafe && v.indexOf('_') >= 0) {
5803 warn(bundle.adsafe_name_a, nexttoken, v);
5808 function do_tag(n, a) {
5809 var i, t = html_tag[n], script, x;
5813 bundle.unrecognized_tag_a,
5815 n === n.toLowerCase() ? n : n + ' (capitalization error)'
5818 if (stack.length > 0) {
5820 fail(bundle.unexpected_a, token, n);
5824 if (x.indexOf(' ' + stack[stack.length - 1].name + ' ') < 0) {
5825 fail(bundle.tag_a_in_b, token, n, x);
5827 } else if (!option.adsafe && !option.fragment) {
5831 fail(bundle.tag_a_in_b, token, n, 'body');
5834 } while (stack[i].name !== 'body');
5839 if (option.adsafe && stack.length === 1 && !adsafe_id) {
5840 warn(bundle.adsafe_missing_id);
5847 warn(bundle.lang, token);
5849 if (option.adsafe && stack.length !== 1) {
5850 warn(bundle.adsafe_placement, token);
5853 if (option.adsafe && (!adsafe_may || !approved[a.src])) {
5854 warn(bundle.adsafe_source, token);
5857 warn(bundle.type, token);
5860 step_in(nexttoken.from);
5864 script = statements();
5866 // JSLint is also the static analyzer for ADsafe. See www.ADsafe.org.
5868 if (option.adsafe) {
5870 fail(bundle.adsafe_script, token);
5872 if (script.length !== 1 ||
5873 aint(script[0], 'id', '(') ||
5874 aint(script[0].first, 'id', '.') ||
5875 aint(script[0].first.first, 'value', 'ADSAFE') ||
5876 aint(script[0].second[0], 'value', adsafe_id)) {
5877 fail(bundle.adsafe_id_go);
5879 switch (script[0].first.second.value) {
5881 if (adsafe_may || script[0].second.length !== 1) {
5882 fail(bundle.adsafe_id, nexttoken);
5888 fail(bundle.adsafe_id);
5890 if (script[0].second.length !== 2 ||
5891 aint(script[0].second[1], 'id', 'function') ||
5892 script[0].second[1].first.length !== 2 ||
5893 aint(script[0].second[1].first[0], 'value', 'dom') ||
5894 aint(script[0].second[1].first[1], 'value', 'lib')) {
5895 fail(bundle.adsafe_go, nexttoken);
5900 fail(bundle.adsafe_id_go);
5907 if (!nexttoken.identifier && nexttoken.value !== 'script') {
5908 warn(bundle.expected_a_b, nexttoken, 'script', nexttoken.value);
5919 if (!nexttoken.identifier && nexttoken.value !== 'style') {
5920 warn(bundle.expected_a_b, nexttoken, 'style', nexttoken.value);
5939 if (option.adsafe && a.autocomplete !== 'off') {
5940 warn(bundle.adsafe_autocomplete);
5944 warn(bundle.bad_type);
5958 if (option.adsafe) {
5959 warn(bundle.adsafe_tag, nexttoken, n);
5966 function closetag(n) {
5967 return '</' + n + '>';
5971 var a, attributes, e, n, q, t, v, w = option.white, wmode;
5976 switch (nexttoken.value) {
5982 if (!t.identifier) {
5983 warn(bundle.bad_name_a, t);
5987 n = n.toLowerCase();
5996 if (typeof v !== 'object') {
5997 fail(bundle.unrecognized_tag_a, t, n);
6002 if (nexttoken.id === '/') {
6004 if (nexttoken.id !== '>') {
6005 warn(bundle.expected_a_b, nexttoken, '>', nexttoken.value);
6009 if (nexttoken.id && nexttoken.id.substr(0, 1) === '>') {
6012 if (!nexttoken.identifier) {
6013 if (nexttoken.id === '(end)' || nexttoken.id === '(error)') {
6014 warn(bundle.expected_a_b, nexttoken, '>', nexttoken.value);
6016 warn(bundle.bad_name_a);
6018 option.white = true;
6020 a = nexttoken.value;
6023 if (!option.cap && a !== a.toLowerCase()) {
6024 warn(bundle.attribute_case_a, token);
6026 a = a.toLowerCase();
6028 if (Object.prototype.hasOwnProperty.call(attributes, a)) {
6029 warn(bundle.duplicate_a, token, a);
6031 if (a.slice(0, 2) === 'on') {
6033 warn(bundle.html_handlers);
6035 xmode = 'scriptstring';
6038 if (q !== '"' && q !== '\'') {
6039 fail(bundle.expected_a_b, nexttoken, '"', nexttoken.value);
6042 wmode = option.white;
6043 option.white = false;
6047 option.white = wmode;
6048 if (nexttoken.id !== q) {
6049 fail(bundle.expected_a_b, nexttoken, q, nexttoken.value);
6055 } else if (a === 'style') {
6056 xmode = 'scriptstring';
6059 if (q !== '"' && q !== '\'') {
6060 fail(bundle.expected_a_b, nexttoken, '"', nexttoken.value);
6062 xmode = 'styleproperty';
6071 if (nexttoken.id === '=') {
6073 v = nexttoken.value;
6074 if (!nexttoken.identifier &&
6075 nexttoken.id !== '"' &&
6076 nexttoken.id !== '\'' &&
6077 nexttoken.arity !== 'string' &&
6078 nexttoken.arity !== 'number' &&
6079 nexttoken.id !== '(color)') {
6080 warn(bundle.expected_attribute_value_a, token, a);
6088 do_attribute(n, a, v);
6090 do_tag(n, attributes);
6100 if (!nexttoken.identifier) {
6101 warn(bundle.bad_name_a);
6103 n = nexttoken.value;
6105 n = n.toLowerCase();
6109 fail(bundle.unexpected_a, nexttoken, closetag(n));
6113 fail(bundle.unexpected_a, nexttoken, closetag(n));
6116 fail(bundle.expected_a_b,
6117 nexttoken, closetag(t.name), closetag(n));
6119 if (nexttoken.id !== '>') {
6120 fail(bundle.expected_a_b, nexttoken, '>', nexttoken.value);
6127 warn(bundle.adsafe_a);
6132 if (nexttoken.id === '>' || nexttoken.id === '(end)') {
6135 if (nexttoken.value.indexOf('--') >= 0) {
6136 fail(bundle.unexpected_a, nexttoken, '--');
6138 if (nexttoken.value.indexOf('<') >= 0) {
6139 fail(bundle.unexpected_a, nexttoken, '<');
6141 if (nexttoken.value.indexOf('>') >= 0) {
6142 fail(bundle.unexpected_a, nexttoken, '>');
6151 if (nexttoken.id === '(end)') {
6152 fail(bundle.missing_a, nexttoken,
6153 '</' + stack[stack.length - 1].value + '>');
6158 if (stack && stack.length === 0 && (option.adsafe ||
6159 !option.fragment || nexttoken.id === '(end)')) {
6163 if (nexttoken.id !== '(end)') {
6164 fail(bundle.unexpected_a);
6169 // The actual JSLINT function itself.
6171 var itself = function (the_source, the_option) {
6172 var i, keys, predef;
6175 predefined = Object.create(standard);
6177 option = Object.create(the_option);
6178 predef = option.predef;
6180 if (Array.isArray(predef)) {
6181 for (i = 0; i < predef.length; i += 1) {
6182 predefined[predef[i]] = true;
6184 } else if (typeof predef === 'object') {
6185 keys = Object.keys(predef);
6186 for (i = 0; i < keys.length; i += 1) {
6187 predefined[keys[i]] = !!predef[keys];
6191 if (option.adsafe) {
6196 option['continue'] =
6206 option.windows = false;
6210 option.undef = true;
6213 predefined['eval'] =
6214 predefined.Function =
6215 predefined.Object = null;
6218 predefined.lib = false;
6223 option.indent = +option.indent || 0;
6224 option.maxerr = option.maxerr || 50;
6226 adsafe_may = adsafe_top = adsafe_went = false;
6228 if (option.approved) {
6229 for (i = 0; i < option.approved.length; i += 1) {
6230 approved[option.approved[i]] = option.approved[i];
6233 approved.test = 'test';
6236 for (i = 0; i < option.indent; i += 1) {
6239 global = Object.create(predefined);
6243 '(name)': '(global)',
6248 functions = [funct];
6250 comments_off = false;
6262 strict_mode = false;
6267 lex.init(the_source);
6269 prevtoken = token = nexttoken = syntax['(begin)'];
6274 if (nexttoken.arity === 'number') {
6275 fail(bundle.unexpected_a);
6276 } else if (nexttoken.value.charAt(0) === '<') {
6278 if (option.adsafe && !adsafe_went) {
6279 warn(bundle.adsafe_go, this);
6282 switch (nexttoken.id) {
6295 if (token.id !== '@' || !nexttoken.identifier ||
6296 nexttoken.value !== 'charset' || token.line !== 1 ||
6301 if (nexttoken.arity !== 'string' &&
6302 nexttoken.value !== 'UTF-8') {
6311 if (option.adsafe && option.fragment) {
6312 fail(bundle.expected_a_b,
6313 nexttoken, '<div>', nexttoken.value);
6316 // If the first token is predef semicolon, ignore it. This is sometimes used when
6317 // files are intended to be appended to files that may be sloppy. predef sloppy
6318 // file may be depending on semicolon insertion on its last line.
6321 if (nexttoken.id === ';') {
6324 if (nexttoken.value === 'use strict') {
6325 warn(bundle.function_strict);
6329 JSLINT.tree = statements();
6330 if (option.adsafe && (JSLINT.tree.length !== 1 ||
6331 aint(JSLINT.tree[0], 'id', '(') ||
6332 aint(JSLINT.tree[0].first, 'id', '.') ||
6333 aint(JSLINT.tree[0].first.first, 'value', 'ADSAFE') ||
6334 aint(JSLINT.tree[0].first.second, 'value', 'lib') ||
6335 JSLINT.tree[0].second.length !== 2 ||
6336 JSLINT.tree[0].second[0].arity !== 'string' ||
6337 aint(JSLINT.tree[0].second[1], 'id', 'function'))) {
6338 fail(bundle.adsafe_lib);
6340 if (JSLINT.tree.disrupt) {
6341 warn(bundle.weird_program, prevtoken);
6349 JSLINT.errors.push({
6351 line : e.line || nexttoken.line,
6352 character : e.character || nexttoken.from
6356 return JSLINT.errors.length === 0;
6362 itself.data = function () {
6363 var data = {functions: []},
6374 if (itself.errors.length) {
6375 data.errors = itself.errors;
6382 for (name in implied) {
6383 if (Object.prototype.hasOwnProperty.call(implied, name)) {
6390 if (implieds.length > 0) {
6391 data.implieds = implieds;
6394 if (urls.length > 0) {
6398 globals = Object.keys(functions[0]).filter(function (value) {
6399 return value.charAt(0) !== '(' ? value : undefined;
6401 if (globals.length > 0) {
6402 data.globals = globals;
6405 for (i = 1; i < functions.length; i += 1) {
6406 the_function = functions[i];
6408 for (j = 0; j < functionicity.length; j += 1) {
6409 function_data[functionicity[j]] = [];
6411 for (name in the_function) {
6412 if (Object.prototype.hasOwnProperty.call(the_function, name)) {
6413 if (name.charAt(0) !== '(') {
6414 kind = the_function[name];
6415 if (kind === 'unction') {
6417 } else if (typeof kind === 'boolean') {
6420 if (Array.isArray(function_data[kind])) {
6421 function_data[kind].push(name);
6422 if (kind === 'unused') {
6425 line: the_function['(line)'],
6426 'function': the_function['(name)']
6433 for (j = 0; j < functionicity.length; j += 1) {
6434 if (function_data[functionicity[j]].length === 0) {
6435 delete function_data[functionicity[j]];
6438 function_data.name = the_function['(name)'];
6439 function_data.param = the_function['(params)'];
6440 function_data.line = the_function['(line)'];
6441 data.functions.push(function_data);
6444 if (unused.length > 0) {
6445 data.unused = unused;
6449 for (name in member) {
6450 if (typeof member[name] === 'number') {
6451 data.member = member;
6460 itself.report = function (errors_only) {
6461 var data = itself.data();
6463 var err, evidence, i, j, key, keys, length, mem = '', name, names,
6464 output = [], snippets, the_function, warning;
6466 function detail(h, array) {
6467 var comma_needed, i, singularity;
6469 output.push('<div><i>' + h + '</i> ');
6470 array = array.sort();
6471 for (i = 0; i < array.length; i += 1) {
6472 if (array[i] !== singularity) {
6473 singularity = array[i];
6474 output.push((comma_needed ? ', ' : '') + singularity);
6475 comma_needed = true;
6478 output.push('</div>');
6482 if (data.errors || data.implieds || data.unused) {
6484 output.push('<div id=errors><i>Error:</i>');
6486 for (i = 0; i < data.errors.length; i += 1) {
6487 warning = data.errors[i];
6489 evidence = warning.evidence || '';
6490 output.push('<p>Problem' + (isFinite(warning.line) ? ' at line ' +
6491 warning.line + ' character ' + warning.character : '') +
6492 ': ' + warning.reason.entityify() +
6493 '</p><p class=evidence>' +
6494 (evidence && (evidence.length > 80 ? evidence.slice(0, 77) + '...' :
6495 evidence).entityify()) + '</p>');
6500 if (data.implieds) {
6502 for (i = 0; i < data.implieds.length; i += 1) {
6503 snippets[i] = '<code>' + data.implieds[i].name + '</code> <i>' +
6504 data.implieds[i].line + '</i>';
6506 output.push('<p><i>Implied global:</i> ' + snippets.join(', ') + '</p>');
6511 for (i = 0; i < data.unused.length; i += 1) {
6512 snippets[i] = '<code><u>' + data.unused[i].name + '</u></code> <i>' +
6513 data.unused[i].line + ' </i> <small>' +
6514 data.unused[i]['function'] + '</small>';
6516 output.push('<p><i>Unused variable:</i> ' + snippets.join(', ') + '</p>');
6519 output.push('<p>JSON: bad.</p>');
6521 output.push('</div>');
6526 output.push('<br><div id=functions>');
6529 detail("URLs<br>", data.urls, '<br>');
6532 if (xmode === 'style') {
6533 output.push('<p>CSS.</p>');
6534 } else if (data.json && !err) {
6535 output.push('<p>JSON: good.</p>');
6536 } else if (data.globals) {
6537 output.push('<div><i>Global</i> ' +
6538 data.globals.sort().join(', ') + '</div>');
6540 output.push('<div><i>No new global variables introduced.</i></div>');
6543 for (i = 0; i < data.functions.length; i += 1) {
6544 the_function = data.functions[i];
6546 if (the_function.param) {
6547 for (j = 0; j < the_function.param.length; j += 1) {
6548 names[j] = the_function.param[j].value;
6551 output.push('<br><div class=function><i>' + the_function.line + '</i> ' +
6552 (the_function.name || '') + '(' + names.join(', ') + ')</div>');
6553 detail('<big><b>Unused</b></big>', the_function.unused);
6554 detail('Closure', the_function.closure);
6555 detail('Variable', the_function['var']);
6556 detail('Exception', the_function.exception);
6557 detail('Outer', the_function.outer);
6558 detail('Global', the_function.global);
6559 detail('Label', the_function.label);
6563 keys = Object.keys(data.member);
6566 mem = '<br><pre id=properties>/*properties ';
6568 for (i = 0; i < keys.length; i += 1) {
6571 if (length + name.length > 72) {
6572 output.push(mem + '<br>');
6576 length += name.length + 2;
6577 if (data.member[key] === 1) {
6578 name = '<i>' + name + '</i>';
6580 if (i < keys.length - 1) {
6585 output.push(mem + '<br>*/</pre>');
6587 output.push('</div>');
6590 return output.join('');
6592 itself.jslint = itself;
6594 itself.edition = '2011-03-07';