4 // Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // The Software shall be used for Good, not Evil.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 // WARNING: JSLint will hurt your feelings.
28 // JSLINT is a global function. It takes two parameters.
30 // var myResult = JSLINT(source, option);
32 // The first parameter is either a string or an array of strings. If it is a
33 // string, it will be split on '\n' or '\r'. If it is an array of strings, it
34 // is assumed that each string represents one line. The source can be a
35 // JavaScript text, or HTML text, or a JSON text, or a CSS text.
37 // The second parameter is an optional object of options that control the
38 // operation of JSLINT. Most of the options are booleans: They are all
39 // optional and have a default value of false. One of the options, predef,
40 // can be an array of names, which will be used to declare global variables,
41 // or an object whose keys are used as global names, with a boolean value
42 // that determines if they are assignable.
44 // If it checks out, JSLINT returns true. Otherwise, it returns false.
46 // If false, you can inspect JSLINT.errors to find out the problems.
47 // JSLINT.errors is an array of objects containing these properties:
50 // line : The line (relative to 0) at which the lint was found
51 // character : The character (relative to 0) at which the lint was found
52 // reason : The problem
53 // evidence : The text line in which the problem occurred
54 // raw : The raw message before the details were inserted
55 // a : The first detail
56 // b : The second detail
57 // c : The third detail
58 // d : The fourth detail
61 // If a stopping error was found, a null will be the last element of the
62 // JSLINT.errors array. A stopping error means that JSLint was not confident
63 // enough to continue. It does not necessarily mean that the error was
64 // especially heinous.
66 // You can request a Function Report, which shows all of the functions
67 // and the parameters and vars that they use. This can be used to find
68 // implied global variables and other problems. The report is in HTML and
69 // can be inserted in an HTML <body>.
71 // var myReport = JSLINT.report(errors_only);
73 // If errors_only is true, then the report will be limited to only errors.
75 // You can request a data structure that contains JSLint's results.
77 // var myData = JSLINT.data();
79 // It returns a structure with this form:
138 // Empty arrays will not be included.
140 // You can obtain the parse tree that JSLint constructed while parsing. The
141 // latest tree is kept in JSLINT.tree. A nice stringication can be produced
144 // JSON.stringify(JSLINT.tree, [
145 // 'string', 'arity', 'name', 'first',
146 // 'second', 'third', 'block', 'else'
149 // JSLint provides three directives. They look like slashstar comments, and
150 // allow for setting options, declaring global variables, and establishing a
151 // set of allowed property names.
153 // These directives respect function scope.
155 // The jslint directive is a special comment that can set one or more options.
156 // The current option set is
158 // adsafe true, if ADsafe rules should be enforced
159 // bitwise true, if bitwise operators should be allowed
160 // browser true, if the standard browser globals should be predefined
161 // cap true, if upper case HTML should be allowed
162 // confusion true, if types can be used inconsistently
163 // 'continue' true, if the continuation statement should be tolerated
164 // css true, if CSS workarounds should be tolerated
165 // debug true, if debugger statements should be allowed
166 // devel true, if logging should be allowed (console, alert, etc.)
167 // eqeq true, if == should be allowed
168 // es5 true, if ES5 syntax should be allowed
169 // evil true, if eval should be allowed
170 // forin true, if for in statements need not filter
171 // fragment true, if HTML fragments should be allowed
172 // indent the indentation factor
173 // maxerr the maximum number of errors to allow
174 // maxlen the maximum length of a source line
175 // newcap true, if constructor names capitalization is ignored
176 // node true, if Node.js globals should be predefined
177 // nomen true, if names may have dangling _
178 // on true, if HTML event handlers should be allowed
179 // passfail true, if the scan should stop on first error
180 // plusplus true, if increment/decrement should be allowed
181 // properties true, if all property names must be declared with /*properties*/
182 // regexp true, if the . should be allowed in regexp literals
183 // rhino true, if the Rhino environment globals should be predefined
184 // undef true, if variables can be declared out of order
185 // unparam true, if unused parameters should be tolerated
186 // safe true, if use of some browser features should be restricted
187 // sloppy true, if the 'use strict'; pragma is optional
188 // sub true, if all forms of subscript notation are tolerated
189 // vars true, if multiple var statements per function should be allowed
190 // white true, if sloppy whitespace is tolerated
191 // widget true if the Yahoo Widgets globals should be predefined
192 // windows true, if MS Windows-specific globals should be predefined
197 evil: true, nomen: true, regexp: true
200 // The properties directive declares an exclusive list of property names.
201 // Any properties named in the program that are not in the list will
202 // produce a warning.
207 '\b': string, '\t': string, '\n': string, '\f': string, '\r': string,
208 '!=': boolean, '!==': boolean, '"': string, '%': boolean, '\'': string,
209 '(begin)', '(breakage)': number, '(complexity)',
210 '(confusion)': boolean, '(context)': object,
211 '(error)', '(identifier)', '(line)': number, '(loopage)': number, '(name)',
212 '(old_property_type)', '(params)', '(return_type)', '(scope)': object,
213 '(statement)', '(token)', '(vars)', '(verb)', '*': boolean, '+': boolean,
214 '-': boolean, '/': *, '<': boolean, '<=': boolean, '==': boolean,
215 '===': boolean, '>': boolean, '>=': boolean, ADSAFE: boolean, Array,
216 Date, E: string, Function, LN10: string, LN2: string, LOG10E: string,
217 LOG2E: string, MAX_VALUE: string, MIN_VALUE: string,
218 NEGATIVE_INFINITY: string, Object, PI: string, POSITIVE_INFINITY: string,
219 SQRT1_2: string, SQRT2: string, '\\': string, a: object, a_label: string,
220 a_not_allowed: string, a_not_defined: string, a_scope: string,
221 abbr: object, acronym: object, address: object, adsafe, adsafe_a: string,
222 adsafe_autocomplete: string, adsafe_bad_id: string, adsafe_div: string,
223 adsafe_fragment: string, adsafe_go: string, adsafe_html: string,
224 adsafe_id: string, adsafe_id_go: string, adsafe_lib: string,
225 adsafe_lib_second: string, adsafe_missing_id: string,
226 adsafe_name_a: string, adsafe_placement: string, adsafe_prefix_a: string,
227 adsafe_script: string, adsafe_source: string, adsafe_subscript_a: string,
228 adsafe_tag: string, all: boolean, already_defined: string, and: string,
229 applet: object, apply: string, approved: array, area: object,
230 arity: string, article: object, aside: object, assign: boolean,
231 assign_exception: string, assignment_function_expression: string,
232 at: number, attribute_case_a: string, audio: object, autocomplete: string,
233 avoid_a: string, b: *, background: array, 'background-attachment': array,
234 'background-color': array, 'background-image': array,
235 'background-position': array, 'background-repeat': array,
236 bad_assignment: string, bad_color_a: string, bad_constructor: string,
237 bad_entity: string, bad_html: string, bad_id_a: string, bad_in_a: string,
238 bad_invocation: string, bad_name_a: string, bad_new: string,
239 bad_number: string, bad_operand: string, bad_type: string, bad_url: string,
240 bad_wrap: string, base: object, bdo: object, big: object, bind: string,
241 bitwise: boolean, block: array, blockquote: object, body: object,
242 border: array, 'border-bottom': array, 'border-bottom-color',
243 'border-bottom-style': array, 'border-bottom-width',
244 'border-collapse': array, 'border-color': array, 'border-left': array,
245 'border-left-color', 'border-left-style': array, 'border-left-width',
246 'border-right': array, 'border-right-color', 'border-right-style': array,
247 'border-right-width', 'border-spacing': array, 'border-style': array,
248 'border-top': array, 'border-top-color', 'border-top-style': array,
249 'border-top-width', 'border-width': array, bottom: array, br: object,
250 braille: boolean, browser: boolean, button: object, c, call: string,
251 canvas: object, cap, caption: object, 'caption-side': array, ceil: string,
252 center: object, charAt: *, charCodeAt: *, character, cite: object,
253 clear: array, clip: array, closure, cm: boolean, code: object, col: object,
254 colgroup: object, color, combine_var: string, command: object, comment,
255 comments: array, concat: string, conditional_assignment: string,
256 confusing_a: string, confusing_regexp: string, confusion: boolean,
257 constructor: string, constructor_name_a: string, content: array, continue,
258 control_a: string, 'counter-increment': array, 'counter-reset': array,
259 create: *, css: string, cursor: array, d, dangerous_comment: string,
260 dangling_a: string, data: function object, datalist: object, dd: object,
261 debug, defineProperties: string, defineProperty: string, del: object,
262 deleted: string, details: object, devel: boolean, dfn: object,
263 dialog: object, dir: object, direction: array, display: array,
264 disrupt: boolean, div: object, dl: object, dt: object, duplicate_a: string,
265 edge: string, edition: string, else, em: *, embed: object,
266 embossed: boolean, empty: boolean, 'empty-cells': array,
267 empty_block: string, empty_case: string, empty_class: string,
268 entityify: function, eqeq, errors: array, es5: string, eval, every: string,
269 evidence, evil: string, ex: boolean, exception, exec: *,
270 expected_a: string, expected_a_at_b_c: string, expected_a_b: string,
271 expected_a_b_from_c_d: string, expected_at_a: string,
272 expected_attribute_a: string, expected_attribute_value_a: string,
273 expected_class_a: string, expected_fraction_a: string,
274 expected_id_a: string, expected_identifier_a: string,
275 expected_identifier_a_reserved: string, expected_lang_a: string,
276 expected_linear_a: string, expected_media_a: string,
277 expected_name_a: string, expected_nonstandard_style_attribute: string,
278 expected_number_a: string, expected_operator_a: string,
279 expected_percent_a: string, expected_positive_a: string,
280 expected_pseudo_a: string, expected_selector_a: string,
281 expected_small_a: string, expected_space_a_b: string,
282 expected_string_a: string, expected_style_attribute: string,
283 expected_style_pattern: string, expected_tagname_a: string,
284 expected_type_a: string, f: string, fieldset: object, figure: object,
285 filter: *, first: *, float: array, floor: *, font: *, 'font-family',
286 'font-size': array, 'font-size-adjust': array, 'font-stretch': array,
287 'font-style': array, 'font-variant': array, 'font-weight': array,
288 footer: object, forEach: *, for_if: string, forin, form: object, fragment,
289 frame: object, frameset: object, freeze: string, from: number,
290 fromCharCode: function, fud: function, funct: object, function,
291 function_block: string, function_eval: string, function_loop: string,
292 function_statement: string, function_strict: string, functions: array,
293 getDate: string, getDay: string, getFullYear: string, getHours: string,
294 getMilliseconds: string, getMinutes: string, getMonth: string,
295 getOwnPropertyDescriptor: string, getOwnPropertyNames: string,
296 getPrototypeOf: string, getSeconds: string, getTime: string,
297 getTimezoneOffset: string, getUTCDate: string, getUTCDay: string,
298 getUTCFullYear: string, getUTCHours: string, getUTCMilliseconds: string,
299 getUTCMinutes: string, getUTCMonth: string, getUTCSeconds: string,
300 getYear: string, global, globals, h1: object, h2: object, h3: object,
301 h4: object, h5: object, h6: object, handheld: boolean, hasOwnProperty: *,
302 head: object, header: object, height: array, hgroup: object, hr: object,
303 'hta:application': object, html: *, html_confusion_a: string,
304 html_handlers: string, i: object, id: string, identifier: boolean,
305 identifier_function: string, iframe: object, img: object, immed: boolean,
306 implied_evil: string, in: boolean, indent: number, indexOf: *,
307 infix_in: string, init: function, input: object, ins: object,
308 insecure_a: string, isAlpha: function, isArray: function boolean,
309 isDigit: function, isExtensible: string, isFrozen: string, isNaN: string,
310 isPrototypeOf: string, isSealed: string, join: *, jslint: function boolean,
311 json: boolean, kbd: object, keygen: object, keys: *, label: object,
312 label_a_b: string, labeled: boolean, lang: string, lastIndex: string,
313 lastIndexOf: *, lbp: number, leading_decimal_a: string, led: function,
314 left: array, legend: object, length: *, 'letter-spacing': array,
315 li: object, lib: boolean, line: number, 'line-height': array, link: object,
316 'list-style': array, 'list-style-image': array,
317 'list-style-position': array, 'list-style-type': array, map: *,
318 margin: array, 'margin-bottom', 'margin-left', 'margin-right',
319 'margin-top', mark: object, 'marker-offset': array, match: function,
320 'max-height': array, 'max-width': array, maxerr: number, maxlen: number,
321 member: object, menu: object, message, meta: object, meter: object,
322 'min-height': function, 'min-width': function, missing_a: string,
323 missing_a_after_b: string, missing_option: string,
324 missing_property: string, missing_space_a_b: string, missing_url: string,
325 missing_use_strict: string, mixed: string, mm: boolean, mode: string,
326 move_invocation: string, move_var: string, n: string, name: string,
327 name_function: string, nav: object, nested_comment: string,
328 newcap: boolean, next, node: boolean, noframes: object, nomen,
329 noscript: object, not: string, not_a_constructor: string,
330 not_a_defined: string, not_a_function: string, not_a_label: string,
331 not_a_scope: string, not_greater: string, now: string, nud: function,
332 number: number, object: object, ol: object, on, opacity, open: boolean,
333 optgroup: object, option: object, outer: regexp, outline: array,
334 'outline-color': array, 'outline-style': array, 'outline-width',
335 output: object, overflow: array, 'overflow-x': array, 'overflow-y': array,
336 p: object, padding: array, 'padding-bottom': function,
337 'padding-left': function, 'padding-right': function,
338 'padding-top': function, 'page-break-after': array,
339 'page-break-before': array, param: object, parameter_a_get_b: string,
340 parameter_set_a: string, params: array, paren: boolean, parent: string,
341 parse: string, passfail, pc: boolean, plusplus, pop: *, position: array,
342 postscript: boolean, pre: object, predef, prev, preventExtensions: string,
343 print: boolean, progress: object, projection: boolean, properties: boolean,
344 propertyIsEnumerable: string, prototype: string, pt: boolean, push: *,
345 px: boolean, q: object, quote, quotes: array, r: string, radix: string,
346 range: function, raw, read_only: string, reason, redefinition_a: string,
347 reduce: string, reduceRight: string, regexp, replace: function,
348 report: function, reserved: boolean, reserved_a: string, reverse: string,
349 rhino: boolean, right: array, rp: object, rt: object, ruby: object,
350 safe: boolean, samp: object, scanned_a_b: string, screen: boolean,
351 script: object, seal: string, search: function, second: *, section: object,
352 select: object, setDate: string, setDay: string, setFullYear: string,
353 setHours: string, setMilliseconds: string, setMinutes: string,
354 setMonth: string, setSeconds: string, setTime: string,
355 setTimezoneOffset: string, setUTCDate: string, setUTCDay: string,
356 setUTCFullYear: string, setUTCHours: string, setUTCMilliseconds: string,
357 setUTCMinutes: string, setUTCMonth: string, setUTCSeconds: string,
358 setYear: string, shift: *, slash_equal: string, slice: string, sloppy,
359 small: object, some: string, sort: *, source: object, span: object,
360 speech: boolean, splice: string, split: function, src,
361 statement_block: string, stopping: string, strange_loop: string,
362 strict: string, string: string, stringify: string, strong: object, style: *,
363 styleproperty: regexp, sub: object, subscript: string, substr: *,
364 substring: string, sup: object, supplant: function, t: string,
365 table: object, 'table-layout': array, tag_a_in_b: string, tbody: object,
366 td: object, test: *, 'text-align': array, 'text-decoration': array,
367 'text-indent': function, 'text-shadow': array, 'text-transform': array,
368 textarea: object, tfoot: object, th: object, thead: object, third: array,
369 thru: number, time: object, title: object, toDateString: string,
370 toExponential: string, toFixed: string, toISOString: string,
371 toJSON: string, toLocaleDateString: string, toLocaleLowerCase: string,
372 toLocaleString: string, toLocaleTimeString: string,
373 toLocaleUpperCase: string, toLowerCase: *, toPrecision: string,
374 toString: function, toTimeString: string, toUTCString: string,
375 toUpperCase: *, token: function, too_long: string, too_many: string,
376 top: array, tr: object, trailing_decimal_a: string, tree: string,
377 trim: string, tt: object, tty: boolean, tv: boolean, type: string,
378 type_confusion_a_b: string, u: object, ul: object, unclosed: string,
379 unclosed_comment: string, unclosed_regexp: string, undef: boolean,
380 undefined, unescaped_a: string, unexpected_a: string,
381 unexpected_char_a_b: string, unexpected_comment: string,
382 unexpected_property_a: string, unexpected_space_a_b: string,
383 'unicode-bidi': array, unnecessary_initialize: string,
384 unnecessary_use: string, unparam, unreachable_a_b: string,
385 unrecognized_style_attribute_a: string, unrecognized_tag_a: string,
386 unsafe: string, unshift: string, unused: array, url: string, urls: array,
387 use_array: string, use_braces: string, use_charAt: string,
388 use_object: string, use_or: string, use_param: string,
389 used_before_a: string, valueOf: string, var: object,
390 var_a_not: string, vars, 'vertical-align': array, video: object,
391 visibility: array, was: object, weird_assignment: string,
392 weird_condition: string, weird_new: string, weird_program: string,
393 weird_relation: string, weird_ternary: string, white: boolean,
394 'white-space': array, widget: boolean, width: array, windows: boolean,
395 'word-spacing': array, 'word-wrap': array, wrap: boolean,
396 wrap_immediate: string, wrap_regexp: string, write_is_wrong: string,
397 writeable: boolean, 'z-index': array
400 // The global directive is used to declare global variables that can
401 // be accessed by the program. If a declaration is true, then the variable
402 // is writeable. Otherwise, it is read-only.
404 // We build the application inside a function so that we produce only a single
405 // global variable. That function will be invoked immediately, and its return
406 // value is the JSLINT function itself. That function is also an object that
407 // can contain data and other functions.
409 var JSLINT
= (function () {
412 function array_to_object(array
, value
) {
414 for (i
= 0; i
< array
.length
; i
+= 1) {
415 object
[array
[i
]] = value
;
421 var adsafe_id
, // The widget's ADsafe id.
422 adsafe_may
, // The widget may load approved scripts.
423 adsafe_top
, // At the top of the widget script.
424 adsafe_went
, // ADSAFE.go has been called.
425 anonname
, // The guessed name for anonymous functions.
426 approved
, // ADsafe approved urls.
428 // These are operators that should not be used with the ! operator.
446 // These are property names that should not be permitted in the safe subset.
448 banned
= array_to_object([
449 'arguments', 'callee', 'caller', 'constructor', 'eval', 'prototype',
450 'stack', 'unwatch', 'valueOf', 'watch'
452 begin
, // The root token
454 // browser contains a set of global names that are commonly provided by a
455 // web browser environment.
457 browser
= array_to_object([
458 'clearInterval', 'clearTimeout', 'document', 'event', 'frames',
459 'history', 'Image', 'localStorage', 'location', 'name', 'navigator',
460 'Option', 'parent', 'screen', 'sessionStorage', 'setInterval',
461 'setTimeout', 'Storage', 'window', 'XMLHttpRequest'
464 // bundle contains the text messages.
467 a_label
: "'{a}' is a statement label.",
468 a_not_allowed
: "'{a}' is not allowed.",
469 a_not_defined
: "'{a}' is not defined.",
470 a_scope
: "'{a}' used out of scope.",
471 adsafe_a
: "ADsafe violation: '{a}'.",
472 adsafe_autocomplete
: "ADsafe autocomplete violation.",
473 adsafe_bad_id
: "ADSAFE violation: bad id.",
474 adsafe_div
: "ADsafe violation: Wrap the widget in a div.",
475 adsafe_fragment
: "ADSAFE: Use the fragment option.",
476 adsafe_go
: "ADsafe violation: Misformed ADSAFE.go.",
477 adsafe_html
: "Currently, ADsafe does not operate on whole HTML " +
478 "documents. It operates on <div> fragments and .js files.",
479 adsafe_id
: "ADsafe violation: id does not match.",
480 adsafe_id_go
: "ADsafe violation: Missing ADSAFE.id or ADSAFE.go.",
481 adsafe_lib
: "ADsafe lib violation.",
482 adsafe_lib_second
: "ADsafe: The second argument to lib must be a function.",
483 adsafe_missing_id
: "ADSAFE violation: missing ID_.",
484 adsafe_name_a
: "ADsafe name violation: '{a}'.",
485 adsafe_placement
: "ADsafe script placement violation.",
486 adsafe_prefix_a
: "ADsafe violation: An id must have a '{a}' prefix",
487 adsafe_script
: "ADsafe script violation.",
488 adsafe_source
: "ADsafe unapproved script source.",
489 adsafe_subscript_a
: "ADsafe subscript '{a}'.",
490 adsafe_tag
: "ADsafe violation: Disallowed tag '{a}'.",
491 already_defined
: "'{a}' is already defined.",
492 and
: "The '&&' subexpression should be wrapped in parens.",
493 assign_exception
: "Do not assign to the exception parameter.",
494 assignment_function_expression
: "Expected an assignment or " +
495 "function call and instead saw an expression.",
496 attribute_case_a
: "Attribute '{a}' not all lower case.",
497 avoid_a
: "Avoid '{a}'.",
498 bad_assignment
: "Bad assignment.",
499 bad_color_a
: "Bad hex color '{a}'.",
500 bad_constructor
: "Bad constructor.",
501 bad_entity
: "Bad entity.",
502 bad_html
: "Bad HTML string",
503 bad_id_a
: "Bad id: '{a}'.",
504 bad_in_a
: "Bad for in variable '{a}'.",
505 bad_invocation
: "Bad invocation.",
506 bad_name_a
: "Bad name: '{a}'.",
507 bad_new
: "Do not use 'new' for side effects.",
508 bad_number
: "Bad number '{a}'.",
509 bad_operand
: "Bad operand.",
510 bad_type
: "Bad type.",
511 bad_url
: "Bad url string.",
512 bad_wrap
: "Do not wrap function literals in parens unless they " +
513 "are to be immediately invoked.",
514 combine_var
: "Combine this with the previous 'var' statement.",
515 conditional_assignment
: "Expected a conditional expression and " +
516 "instead saw an assignment.",
517 confusing_a
: "Confusing use of '{a}'.",
518 confusing_regexp
: "Confusing regular expression.",
519 constructor_name_a
: "A constructor name '{a}' should start with " +
520 "an uppercase letter.",
521 control_a
: "Unexpected control character '{a}'.",
522 css
: "A css file should begin with @charset 'UTF-8';",
523 dangling_a
: "Unexpected dangling '_' in '{a}'.",
524 dangerous_comment
: "Dangerous comment.",
525 deleted
: "Only properties should be deleted.",
526 duplicate_a
: "Duplicate '{a}'.",
527 empty_block
: "Empty block.",
528 empty_case
: "Empty case.",
529 empty_class
: "Empty class.",
530 es5
: "This is an ES5 feature.",
531 evil
: "eval is evil.",
532 expected_a
: "Expected '{a}'.",
533 expected_a_b
: "Expected '{a}' and instead saw '{b}'.",
534 expected_a_b_from_c_d
: "Expected '{a}' to match '{b}' from line " +
535 "{c} and instead saw '{d}'.",
536 expected_at_a
: "Expected an at-rule, and instead saw @{a}.",
537 expected_a_at_b_c
: "Expected '{a}' at column {b}, not column {c}.",
538 expected_attribute_a
: "Expected an attribute, and instead saw [{a}].",
539 expected_attribute_value_a
: "Expected an attribute value and " +
540 "instead saw '{a}'.",
541 expected_class_a
: "Expected a class, and instead saw .{a}.",
542 expected_fraction_a
: "Expected a number between 0 and 1 and " +
544 expected_id_a
: "Expected an id, and instead saw #{a}.",
545 expected_identifier_a
: "Expected an identifier and instead saw '{a}'.",
546 expected_identifier_a_reserved
: "Expected an identifier and " +
547 "instead saw '{a}' (a reserved word).",
548 expected_linear_a
: "Expected a linear unit and instead saw '{a}'.",
549 expected_lang_a
: "Expected a lang code, and instead saw :{a}.",
550 expected_media_a
: "Expected a CSS media type, and instead saw '{a}'.",
551 expected_name_a
: "Expected a name and instead saw '{a}'.",
552 expected_nonstandard_style_attribute
: "Expected a non-standard " +
553 "style attribute and instead saw '{a}'.",
554 expected_number_a
: "Expected a number and instead saw '{a}'.",
555 expected_operator_a
: "Expected an operator and instead saw '{a}'.",
556 expected_percent_a
: "Expected a percentage and instead saw '{a}'",
557 expected_positive_a
: "Expected a positive number and instead saw '{a}'",
558 expected_pseudo_a
: "Expected a pseudo, and instead saw :{a}.",
559 expected_selector_a
: "Expected a CSS selector, and instead saw {a}.",
560 expected_small_a
: "Expected a small number and instead saw '{a}'",
561 expected_space_a_b
: "Expected exactly one space between '{a}' and '{b}'.",
562 expected_string_a
: "Expected a string and instead saw {a}.",
563 expected_style_attribute
: "Excepted a style attribute, and instead saw '{a}'.",
564 expected_style_pattern
: "Expected a style pattern, and instead saw '{a}'.",
565 expected_tagname_a
: "Expected a tagName, and instead saw {a}.",
566 expected_type_a
: "Expected a type, and instead saw {a}.",
567 for_if
: "The body of a for in should be wrapped in an if " +
568 "statement to filter unwanted properties from the prototype.",
569 function_block
: "Function statements should not be placed in blocks. " +
570 "Use a function expression or move the statement to the top of " +
571 "the outer function.",
572 function_eval
: "The Function constructor is eval.",
573 function_loop
: "Don't make functions within a loop.",
574 function_statement
: "Function statements are not invocable. " +
575 "Wrap the whole function invocation in parens.",
576 function_strict
: "Use the function form of 'use strict'.",
577 html_confusion_a
: "HTML confusion in regular expression '<{a}'.",
578 html_handlers
: "Avoid HTML event handlers.",
579 identifier_function
: "Expected an identifier in an assignment " +
580 "and instead saw a function invocation.",
581 implied_evil
: "Implied eval is evil. Pass a function instead of a string.",
582 infix_in
: "Unexpected 'in'. Compare with undefined, or use the " +
583 "hasOwnProperty method instead.",
584 insecure_a
: "Insecure '{a}'.",
585 isNaN
: "Use the isNaN function to compare with NaN.",
586 label_a_b
: "Label '{a}' on '{b}' statement.",
587 lang
: "lang is deprecated.",
588 leading_decimal_a
: "A leading decimal point can be confused with a dot: '.{a}'.",
589 missing_a
: "Missing '{a}'.",
590 missing_a_after_b
: "Missing '{a}' after '{b}'.",
591 missing_option
: "Missing option value.",
592 missing_property
: "Missing property name.",
593 missing_space_a_b
: "Missing space between '{a}' and '{b}'.",
594 missing_url
: "Missing url.",
595 missing_use_strict
: "Missing 'use strict' statement.",
596 mixed
: "Mixed spaces and tabs.",
597 move_invocation
: "Move the invocation into the parens that " +
598 "contain the function.",
599 move_var
: "Move 'var' declarations to the top of the function.",
600 name_function
: "Missing name in function statement.",
601 nested_comment
: "Nested comment.",
603 not_a_constructor
: "Do not use {a} as a constructor.",
604 not_a_defined
: "'{a}' has not been fully defined yet.",
605 not_a_function
: "'{a}' is not a function.",
606 not_a_label
: "'{a}' is not a label.",
607 not_a_scope
: "'{a}' is out of scope.",
608 not_greater
: "'{a}' should not be greater than '{b}'.",
609 parameter_a_get_b
: "Unexpected parameter '{a}' in get {b} function.",
610 parameter_set_a
: "Expected parameter (value) in set {a} function.",
611 radix
: "Missing radix parameter.",
612 read_only
: "Read only.",
613 redefinition_a
: "Redefinition of '{a}'.",
614 reserved_a
: "Reserved name '{a}'.",
615 scanned_a_b
: "{a} ({b}% scanned).",
616 slash_equal
: "A regular expression literal can be confused with '/='.",
617 statement_block
: "Expected to see a statement and instead saw a block.",
618 stopping
: "Stopping. ",
619 strange_loop
: "Strange loop.",
620 strict
: "Strict violation.",
621 subscript
: "['{a}'] is better written in dot notation.",
622 tag_a_in_b
: "A '<{a}>' must be within '<{b}>'.",
623 too_long
: "Line too long.",
624 too_many
: "Too many errors.",
625 trailing_decimal_a
: "A trailing decimal point can be confused " +
626 "with a dot: '.{a}'.",
627 type
: "type is unnecessary.",
628 type_confusion_a_b
: "Type confusion: {a} and {b}.",
629 unclosed
: "Unclosed string.",
630 unclosed_comment
: "Unclosed comment.",
631 unclosed_regexp
: "Unclosed regular expression.",
632 unescaped_a
: "Unescaped '{a}'.",
633 unexpected_a
: "Unexpected '{a}'.",
634 unexpected_char_a_b
: "Unexpected character '{a}' in {b}.",
635 unexpected_comment
: "Unexpected comment.",
636 unexpected_property_a
: "Unexpected /*property*/ '{a}'.",
637 unexpected_space_a_b
: "Unexpected space between '{a}' and '{b}'.",
638 unnecessary_initialize
: "It is not necessary to initialize '{a}' " +
640 unnecessary_use
: "Unnecessary 'use strict'.",
641 unreachable_a_b
: "Unreachable '{a}' after '{b}'.",
642 unrecognized_style_attribute_a
: "Unrecognized style attribute '{a}'.",
643 unrecognized_tag_a
: "Unrecognized tag '<{a}>'.",
644 unsafe
: "Unsafe character.",
645 url
: "JavaScript URL.",
646 use_array
: "Use the array literal notation [].",
647 use_braces
: "Spaces are hard to count. Use {{a}}.",
648 use_charAt
: "Use the charAt method.",
649 use_object
: "Use the object literal notation {}.",
650 use_or
: "Use the || operator.",
651 use_param
: "Use a named parameter.",
652 used_before_a
: "'{a}' was used before it was defined.",
653 var_a_not
: "Variable {a} was not declared correctly.",
654 weird_assignment
: "Weird assignment.",
655 weird_condition
: "Weird condition.",
656 weird_new
: "Weird construction. Delete 'new'.",
657 weird_program
: "Weird program.",
658 weird_relation
: "Weird relation.",
659 weird_ternary
: "Weird ternary.",
660 wrap_immediate
: "Wrap an immediate function invocation in parentheses " +
661 "to assist the reader in understanding that the expression " +
662 "is the result of a function, and not the function itself.",
663 wrap_regexp
: "Wrap the /regexp/ literal in parens to " +
664 "disambiguate the slash operator.",
665 write_is_wrong
: "document.write can be a form of eval."
671 css_colorData
= array_to_object([
672 "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
673 "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
674 "burlywood", "cadetblue", "chartreuse", "chocolate", "coral",
675 "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue",
676 "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki",
677 "darkmagenta", "darkolivegreen", "darkorange", "darkorchid",
678 "darkred", "darksalmon", "darkseagreen", "darkslateblue",
679 "darkslategray", "darkturquoise", "darkviolet", "deeppink",
680 "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite",
681 "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold",
682 "goldenrod", "gray", "green", "greenyellow", "honeydew", "hotpink",
683 "indianred", "indigo", "ivory", "khaki", "lavender",
684 "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
685 "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgreen",
686 "lightpink", "lightsalmon", "lightseagreen", "lightskyblue",
687 "lightslategray", "lightsteelblue", "lightyellow", "lime",
688 "limegreen", "linen", "magenta", "maroon", "mediumaquamarine",
689 "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen",
690 "mediumslateblue", "mediumspringgreen", "mediumturquoise",
691 "mediumvioletred", "midnightblue", "mintcream", "mistyrose",
692 "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab",
693 "orange", "orangered", "orchid", "palegoldenrod", "palegreen",
694 "paleturquoise", "palevioletred", "papayawhip", "peachpuff",
695 "peru", "pink", "plum", "powderblue", "purple", "red", "rosybrown",
696 "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen",
697 "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray",
698 "snow", "springgreen", "steelblue", "tan", "teal", "thistle",
699 "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke",
700 "yellow", "yellowgreen",
702 "activeborder", "activecaption", "appworkspace", "background",
703 "buttonface", "buttonhighlight", "buttonshadow", "buttontext",
704 "captiontext", "graytext", "highlight", "highlighttext",
705 "inactiveborder", "inactivecaption", "inactivecaptiontext",
706 "infobackground", "infotext", "menu", "menutext", "scrollbar",
707 "threeddarkshadow", "threedface", "threedhighlight",
708 "threedlightshadow", "threedshadow", "window", "windowframe",
741 devel
= array_to_object([
742 'alert', 'confirm', 'console', 'Debug', 'opera', 'prompt'
757 funct
, // The current function, including the labels used
758 // in the function, as well as (verb), (context),
759 // (statement), (name), (params), (complexity),
760 // (loopage), (breakage), (vars)
763 'closure', 'exception', 'global', 'label', 'outer', 'undef',
767 functions
, // All of the functions
768 global_funct
, // The global body
769 global_scope
, // The global scope
776 area
: {empty
: true, parent
: ' map '},
781 base
: {empty
: true, parent
: ' head '},
785 body
: {parent
: ' html noframes '},
788 canvas
: {parent
: ' body p div th td '},
789 caption
: {parent
: ' table '},
793 col
: {empty
: true, parent
: ' table colgroup '},
794 colgroup
: {parent
: ' table '},
795 command
: {parent
: ' menu '},
797 dd
: {parent
: ' dl '},
805 dt
: {parent
: ' dl '},
813 frame
: {empty
: true, parent
: ' frameset '},
814 frameset
: {parent
: ' html frameset '},
821 head
: {parent
: ' html '},
826 {empty
: true, parent
: ' head '},
831 input
: {empty
: true},
836 legend
: {parent
: ' details fieldset figure '},
837 li
: {parent
: ' dir menu ol ul '},
838 link
: {empty
: true, parent
: ' head '},
842 meta
: {empty
: true, parent
: ' head noframes noscript '},
845 noframes
: {parent
: ' html body '},
846 noscript
: {parent
: ' body head noframes '},
849 optgroup
: {parent
: ' select '},
850 option
: {parent
: ' optgroup select '},
853 param
: {empty
: true, parent
: ' applet object '},
861 script
: {empty
: true, parent
: ' body div frame head iframe p pre span '},
868 style
: {parent
: ' head ', empty
: true},
872 tbody
: {parent
: ' table '},
873 td
: {parent
: ' tr '},
875 tfoot
: {parent
: ' table '},
876 th
: {parent
: ' tr '},
877 thead
: {parent
: ' table '},
879 title
: {parent
: ' head '},
880 tr
: {parent
: ' table tbody thead tfoot '},
891 is_type
= array_to_object([
892 '*', 'array', 'boolean', 'function', 'number', 'object',
895 itself
, // JSLint itself
897 lex
, // the tokenizer
901 node
= array_to_object([
902 'Buffer', 'clearInterval', 'clearTimeout', 'console', 'exports',
903 'global', 'module', 'process', 'querystring', 'require',
904 'setInterval', 'setTimeout', '__dirname', '__filename'
907 numbery
= array_to_object(['indexOf', 'lastIndexOf', 'search'], true),
911 predefined
, // Global variables defined by option
915 regexp_flag
= array_to_object(['g', 'i', 'm'], true),
916 rhino
= array_to_object([
917 'defineClass', 'deserialize', 'gc', 'help', 'load', 'loadClass',
918 'print', 'quit', 'readFile', 'readUrl', 'runCommand', 'seal',
919 'serialize', 'spawn', 'sync', 'toint32', 'version'
922 scope
, // An object containing an object for each variable in scope
923 semicolon_coda
= array_to_object([';', '"', '\'', ')'], true),
927 // standard contains the global names that are provided by the
928 // ECMAScript standard.
930 standard
= array_to_object([
931 'Array', 'Boolean', 'Date', 'decodeURI', 'decodeURIComponent',
932 'encodeURI', 'encodeURIComponent', 'Error', 'eval', 'EvalError',
933 'Function', 'isFinite', 'isNaN', 'JSON', 'Math', 'Number', 'Object',
934 'parseInt', 'parseFloat', 'RangeError', 'ReferenceError', 'RegExp',
935 'String', 'SyntaxError', 'TypeError', 'URIError'
938 standard_property_type
= {
944 MAX_VALUE
: 'number',
945 MIN_VALUE
: 'number',
946 NEGATIVE_INFINITY
: 'number',
948 POSITIVE_INFINITY
: 'number',
952 bind
: 'function function',
954 ceil
: 'function number',
955 charAt
: 'function string',
957 constructor : 'function object',
958 create
: 'function object',
959 defineProperty
: 'function object',
960 defineProperties
: 'function object',
961 every
: 'function boolean',
962 exec
: 'function array',
963 filter
: 'function array',
964 floor
: 'function number',
965 forEach
: 'function',
966 freeze
: 'function object',
967 getDate
: 'function number',
968 getDay
: 'function number',
969 getFullYear
: 'function number',
970 getHours
: 'function number',
971 getMilliseconds
: 'function number',
972 getMinutes
: 'function number',
973 getMonth
: 'function number',
974 getOwnPropertyDescriptor
976 getOwnPropertyNames
: 'function array',
977 getPrototypeOf
: 'function object',
978 getSeconds
: 'function number',
979 getTime
: 'function number',
980 getTimezoneOffset
: 'function number',
981 getUTCDate
: 'function number',
982 getUTCDay
: 'function number',
983 getUTCFullYear
: 'function number',
984 getUTCHours
: 'function number',
985 getUTCMilliseconds
: 'function number',
986 getUTCMinutes
: 'function number',
987 getUTCMonth
: 'function number',
988 getUTCSeconds
: 'function number',
989 getYear
: 'function number',
990 hasOwnProperty
: 'function boolean',
991 indexOf
: 'function number',
992 isExtensible
: 'function boolean',
993 isFrozen
: 'function boolean',
994 isPrototypeOf
: 'function boolean',
995 isSealed
: 'function boolean',
996 join
: 'function string',
997 keys
: 'function array',
998 lastIndexOf
: 'function number',
999 lastIndex
: 'number',
1001 map
: 'function array',
1002 now
: 'function number',
1005 preventExtensions
: 'function object',
1006 propertyIsEnumerable
: 'function boolean',
1007 prototype : 'object',
1008 push
: 'function number',
1009 reduce
: 'function',
1010 reduceRight
: 'function',
1011 reverse
: 'function',
1012 seal
: 'function object',
1013 setDate
: 'function',
1014 setDay
: 'function',
1015 setFullYear
: 'function',
1016 setHours
: 'function',
1017 setMilliseconds
: 'function',
1018 setMinutes
: 'function',
1019 setMonth
: 'function',
1020 setSeconds
: 'function',
1021 setTime
: 'function',
1022 setTimezoneOffset
: 'function',
1023 setUTCDate
: 'function',
1024 setUTCDay
: 'function',
1025 setUTCFullYear
: 'function',
1026 setUTCHours
: 'function',
1027 setUTCMilliseconds
: 'function',
1028 setUTCMinutes
: 'function',
1029 setUTCMonth
: 'function',
1030 setUTCSeconds
: 'function',
1031 setYear
: 'function',
1034 some
: 'function boolean',
1036 splice
: 'function',
1037 stringify
: 'function string',
1038 substr
: 'function string',
1039 substring
: 'function string',
1040 test
: 'function boolean',
1041 toDateString
: 'function string',
1042 toExponential
: 'function string',
1043 toFixed
: 'function string',
1044 toJSON
: 'function',
1045 toISOString
: 'function string',
1046 toLocaleDateString
: 'function string',
1047 toLocaleLowerCase
: 'function string',
1048 toLocaleUpperCase
: 'function string',
1049 toLocaleString
: 'function string',
1050 toLocaleTimeString
: 'function string',
1051 toLowerCase
: 'function string',
1052 toPrecision
: 'function string',
1053 toTimeString
: 'function string',
1054 toUpperCase
: 'function string',
1055 toUTCString
: 'function string',
1056 trim
: 'function string',
1057 unshift
: 'function number',
1058 valueOf
: 'function'
1069 // widget contains the global names which are provided to a Yahoo
1070 // (fna Konfabulator) widget.
1072 widget
= array_to_object([
1073 'alert', 'animator', 'appleScript', 'beep', 'bytesToUIString',
1074 'Canvas', 'chooseColor', 'chooseFile', 'chooseFolder',
1075 'closeWidget', 'COM', 'convertPathToHFS', 'convertPathToPlatform',
1076 'CustomAnimation', 'escape', 'FadeAnimation', 'filesystem', 'Flash',
1077 'focusWidget', 'form', 'FormField', 'Frame', 'HotKey', 'Image',
1078 'include', 'isApplicationRunning', 'iTunes', 'konfabulatorVersion',
1079 'log', 'md5', 'MenuItem', 'MoveAnimation', 'openURL', 'play',
1080 'Point', 'popupMenu', 'preferenceGroups', 'preferences', 'print',
1081 'prompt', 'random', 'Rectangle', 'reloadWidget', 'ResizeAnimation',
1082 'resolvePath', 'resumeUpdates', 'RotateAnimation', 'runCommand',
1083 'runCommandInBg', 'saveAs', 'savePreferences', 'screen',
1084 'ScrollBar', 'showWidgetPreferences', 'sleep', 'speak', 'Style',
1085 'suppressUpdates', 'system', 'tellWidget', 'Text', 'TextArea',
1086 'Timer', 'unescape', 'updateNow', 'URL', 'Web', 'widget', 'Window',
1087 'XMLDOM', 'XMLHttpRequest', 'yahooCheckLogin', 'yahooLogin',
1091 windows
= array_to_object([
1092 'ActiveXObject', 'CScript', 'Debug', 'Enumerator', 'System',
1093 'VBArray', 'WScript'
1096 // xmode is used to adapt to the exceptions in html parsing.
1097 // It can have these states:
1098 // '' .js script file
1109 // Regular expressions. Some of these are stupidly long.
1111 // unsafe comment or string
1112 ax
= /@cc|<\/?|script|\]\s*\]|<\s*!|</i,
1113 // carriage return, or carriage return linefeed
1116 // unsafe characters that are silently deleted by one or more browsers
1117 cx
= /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
1118 // query characters for ids
1119 dx
= /[\[\]\/\\"'*<>.&:(){}+=#]/,
1121 hx
= /^\s*(['"=>\/&#]|<(?:\/|\!(?:--)?)?|[a-zA-Z][a-zA-Z0-9_\-:]*|[0-9]+|--)/,
1123 ix
= /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
1125 jx
= /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,
1128 // characters in strings that need escapement
1129 nx
= /[\u0000-\u001f'\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
1131 ox
= /[>&]|<[\/!]?|--/,
1132 // attributes characters
1133 qx
= /[^a-zA-Z0-9+\-_\/ ]/,
1135 sx
= /^\s*([{:#%.=,>+\[\]@()"';]|\*=?|\$=|\|=|\^=|~=|[a-zA-Z_][a-zA-Z0-9_\-]*|[0-9]+|<\/|\/\*)/,
1136 ssx
= /^\s*([@#!"'};:\-%.=,+\[\]()*_]|[a-zA-Z][a-zA-Z0-9._\-]*|\/\*?|\d+(?:\.\d+)?|<\/)/,
1138 tx
= /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jslint|properties|property|members?|globals?)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,
1140 ux
= /&|\+|\u00AD|\.\.|\/\*|%[^;]|base64|url|expression|data|mailto/i,
1150 function return_this() {
1154 function F() {} // Used by Object.create
1156 // Provide critical ES5 functions to ES3.
1158 if (typeof Array
.prototype.filter
!== 'function') {
1159 Array
.prototype.filter = function (f
) {
1160 var i
, length
= this.length
, result
= [], value
;
1161 for (i
= 0; i
< length
; i
+= 1) {
1174 if (typeof Array
.prototype.forEach
!== 'function') {
1175 Array
.prototype.forEach = function (f
) {
1176 var i
, length
= this.length
;
1177 for (i
= 0; i
< length
; i
+= 1) {
1186 if (typeof Array
.isArray
!== 'function') {
1187 Array
.isArray = function (o
) {
1188 return Object
.prototype.toString
.apply(o
) === '[object Array]';
1192 if (!Object
.prototype.hasOwnProperty
.call(Object
, 'create')) {
1193 Object
.create = function (o
) {
1199 if (typeof Object
.keys
!== 'function') {
1200 Object
.keys = function (o
) {
1201 var array
= [], key
;
1203 if (Object
.prototype.hasOwnProperty
.call(o
, key
)) {
1211 if (typeof String
.prototype.entityify
!== 'function') {
1212 String
.prototype.entityify = function () {
1214 .replace(/&/g
, '&')
1215 .replace(/</g
, '<')
1216 .replace(/>/g
, '>');
1220 if (typeof String
.prototype.isAlpha
!== 'function') {
1221 String
.prototype.isAlpha = function () {
1222 return (this >= 'a' && this <= 'z\uffff') ||
1223 (this >= 'A' && this <= 'Z\uffff');
1227 if (typeof String
.prototype.isDigit
!== 'function') {
1228 String
.prototype.isDigit = function () {
1229 return (this >= '0' && this <= '9');
1233 if (typeof String
.prototype.supplant
!== 'function') {
1234 String
.prototype.supplant = function (o
) {
1235 return this.replace(/\{([^{}]*)\}/g, function (a
, b
) {
1236 var replacement
= o
[b
];
1237 return typeof replacement
=== 'string' ||
1238 typeof replacement
=== 'number' ? replacement
: a
;
1244 function sanitize(a
) {
1246 // Escapify a troublesome character.
1248 return escapes
[a
] ||
1249 '\\u' + ('0000' + a
.charCodeAt().toString(16)).slice(-4);
1253 function add_to_predefined(group
) {
1254 Object
.keys(group
).forEach(function (name
) {
1255 predefined
[name
] = group
[name
];
1263 add_to_predefined(rhino
);
1264 option
.rhino
= false;
1267 add_to_predefined(devel
);
1268 option
.devel
= false;
1270 if (option
.browser
) {
1271 add_to_predefined(browser
);
1272 option
.browser
= false;
1274 if (option
.windows
) {
1275 add_to_predefined(windows
);
1276 option
.windows
= false;
1279 add_to_predefined(node
);
1280 option
.node
= false;
1283 if (option
.widget
) {
1284 add_to_predefined(widget
);
1285 option
.widget
= false;
1289 option
.confusion
= true;
1294 // Produce an error warning.
1296 function quit(message
, line
, character
) {
1298 name
: 'JSLintError',
1300 character
: character
,
1301 message
: bundle
.scanned_a_b
.supplant({
1303 b
: Math
.floor((line
/ lines
.length
) * 100)
1308 function warn(message
, offender
, a
, b
, c
, d
) {
1309 var character
, line
, warning
;
1310 offender
= offender
|| next_token
; // `~
1311 line
= offender
.line
|| 0;
1312 character
= offender
.from || 0;
1315 raw
: bundle
[message
] || message
,
1316 evidence
: lines
[line
- 1] || '',
1318 character
: character
,
1319 a
: a
|| (offender
.id
=== '(number)' ?
1320 String(offender
.number
) : offender
.string
),
1325 warning
.reason
= warning
.raw
.supplant(warning
);
1326 JSLINT
.errors
.push(warning
);
1327 if (option
.passfail
) {
1328 quit(bundle
.stopping
, line
, character
);
1331 if (warnings
>= option
.maxerr
) {
1332 quit(bundle
.too_many
, line
, character
);
1337 function warn_at(message
, line
, character
, a
, b
, c
, d
) {
1338 return warn(message
, {
1344 function stop(message
, offender
, a
, b
, c
, d
) {
1345 var warning
= warn(message
, offender
, a
, b
, c
, d
);
1346 quit(bundle
.stopping
, warning
.line
, warning
.character
);
1349 function stop_at(message
, line
, character
, a
, b
, c
, d
) {
1350 return stop(message
, {
1356 function expected_at(at
) {
1357 if (!option
.white
&& next_token
.from !== at
) {
1358 warn('expected_a_at_b_c', next_token
, '', at
,
1363 function aint(it
, name
, expected
) {
1364 if (it
[name
] !== expected
) {
1365 warn('expected_a_b', it
, expected
, it
[name
]);
1373 // lexical analysis and token construction
1375 lex
= (function lex() {
1376 var character
, c
, from, length
, line
, pos
, source_row
;
1378 // Private lex methods
1380 function collect_comment(comment
, quote
, line
, at
) {
1381 var comment_object
= {
1387 if (comments_off
|| src
|| (xmode
&& xmode
!== 'script' &&
1388 xmode
!== 'style' && xmode
!== 'styleproperty')) {
1389 warn_at('unexpected_comment', line
, character
);
1390 } else if (xmode
=== 'script' && /<\//i.test(source_row
)) {
1391 warn_at('unexpected_a', line
, character
, '<\/');
1392 } else if (option
.safe
&& ax
.test(comment
)) {
1393 warn_at('dangerous_comment', line
, at
);
1395 if (older_token
.comments
) {
1396 older_token
.comments
.push(comment_object
);
1398 older_token
.comments
= [comment_object
];
1400 JSLINT
.comments
.push(comment_object
);
1403 function next_line() {
1405 if (line
>= lines
.length
) {
1409 source_row
= lines
[line
];
1411 at
= source_row
.search(/ \t/);
1413 warn_at('mixed', line
, at
+ 1);
1415 source_row
= source_row
.replace(/\t/g, tab
);
1416 at
= source_row
.search(cx
);
1418 warn_at('unsafe', line
, at
);
1420 if (option
.maxlen
&& option
.maxlen
< source_row
.length
) {
1421 warn_at('too_long', line
, source_row
.length
);
1426 // Produce a token object. The token inherits from a syntax symbol.
1428 function it(type
, value
, quote
) {
1430 if (type
=== '(string)' || type
=== '(range)') {
1431 if (jx
.test(value
)) {
1432 warn_at('url', line
, from);
1435 the_token
= Object
.create(syntax
[(
1436 type
=== '(punctuator)' ||
1437 (type
=== '(identifier)' &&
1438 Object
.prototype.hasOwnProperty
.call(syntax
, value
)) ?
1441 )] || syntax
['(error)']);
1442 if (type
=== '(identifier)') {
1443 the_token
.identifier
= true;
1444 if (value
=== '__iterator__' || value
=== '__proto__') {
1445 stop_at('reserved_a', line
, from, value
);
1446 } else if (!option
.nomen
&&
1447 (value
.charAt(0) === '_' ||
1448 value
.charAt(value
.length
- 1) === '_')) {
1449 warn_at('dangling_a', line
, from, value
);
1452 if (type
=== '(number)') {
1453 the_token
.number
= +value
;
1454 } else if (value
!== undefined) {
1455 the_token
.string
= String(value
);
1458 the_token
.quote
= quote
;
1460 the_token
.line
= line
;
1461 the_token
.from = from;
1462 the_token
.thru
= character
;
1463 the_token
.prev
= older_token
;
1466 ('(,=:[!&|?{};'.indexOf(id
.charAt(id
.length
- 1)) >= 0) ||
1469 older_token
.next
= the_token
;
1470 older_token
= the_token
;
1475 var exec
= x
.exec(source_row
), first
;
1477 length
= exec
[0].length
;
1479 c
= first
.charAt(0);
1480 source_row
= source_row
.slice(length
);
1481 from = character
+ length
- first
.length
;
1482 character
+= length
;
1487 function string(x
) {
1488 var c
, pos
= 0, r
= '';
1491 var i
= parseInt(source_row
.substr(pos
+ 1, n
), 16);
1493 if (i
>= 32 && i
<= 126 &&
1494 i
!== 34 && i
!== 92 && i
!== 39) {
1495 warn_at('unexpected_a', line
, character
, '\\');
1498 c
= String
.fromCharCode(i
);
1501 if (json_mode
&& x
!== '"') {
1502 warn_at('expected_a', line
, character
, '"');
1505 if (xquote
=== x
|| (xmode
=== 'scriptstring' && !xquote
)) {
1506 return it('(punctuator)', x
);
1510 while (pos
>= source_row
.length
) {
1512 if (xmode
!== 'html' || !next_line()) {
1513 stop_at('unclosed', line
, from);
1516 c
= source_row
.charAt(pos
);
1519 source_row
= source_row
.slice(pos
+ 1);
1520 return it('(string)', r
, x
);
1523 if (c
=== '\n' || c
=== '\r') {
1526 warn_at('control_a',
1527 line
, character
+ pos
, source_row
.slice(0, pos
));
1528 } else if (c
=== xquote
) {
1529 warn_at('bad_html', line
, character
+ pos
);
1530 } else if (c
=== '<') {
1531 if (option
.safe
&& xmode
=== 'html') {
1532 warn_at('adsafe_a', line
, character
+ pos
, c
);
1533 } else if (source_row
.charAt(pos
+ 1) === '/' && (xmode
|| option
.safe
)) {
1534 warn_at('expected_a_b', line
, character
,
1536 } else if (source_row
.charAt(pos
+ 1) === '!' && (xmode
|| option
.safe
)) {
1537 warn_at('unexpected_a', line
, character
, '<!');
1539 } else if (c
=== '\\') {
1540 if (xmode
=== 'html') {
1542 warn_at('adsafe_a', line
, character
+ pos
, c
);
1544 } else if (xmode
=== 'styleproperty') {
1547 c
= source_row
.charAt(pos
);
1549 warn_at('unexpected_a', line
, character
, '\\');
1554 c
= source_row
.charAt(pos
);
1558 warn_at('es5', line
, character
);
1564 warn_at('bad_html', line
, character
+ pos
);
1568 warn_at('unexpected_a', line
, character
, '\\\'');
1576 warn_at('unexpected_a', line
, character
, '\\v');
1582 warn_at('unexpected_a', line
, character
, '\\x');
1588 if (typeof c
!== 'string') {
1589 warn_at('unexpected_a', line
, character
, '\\');
1600 function number(snippet
) {
1602 if (xmode
!== 'style' && xmode
!== 'styleproperty' &&
1603 source_row
.charAt(0).isAlpha()) {
1604 warn_at('expected_space_a_b',
1605 line
, character
, c
, source_row
.charAt(0));
1608 digit
= snippet
.charAt(1);
1609 if (digit
.isDigit()) {
1610 if (token
.id
!== '.' && xmode
!== 'styleproperty') {
1611 warn_at('unexpected_a', line
, character
, snippet
);
1613 } else if (json_mode
&& (digit
=== 'x' || digit
=== 'X')) {
1614 warn_at('unexpected_a', line
, character
, '0x');
1617 if (snippet
.slice(snippet
.length
- 1) === '.') {
1618 warn_at('trailing_decimal_a', line
, character
, snippet
);
1620 if (xmode
!== 'style') {
1622 if (!isFinite(digit
)) {
1623 warn_at('bad_number', line
, character
, snippet
);
1627 return it('(number)', snippet
);
1642 c
= source_row
.charAt(length
);
1646 stop_at('unclosed_regexp', line
, from);
1650 warn_at('unescaped_a',
1651 line
, from + length
, '/');
1653 c
= source_row
.slice(0, length
- 1);
1654 flag
= Object
.create(regexp_flag
);
1655 while (flag
[source_row
.charAt(length
)] === true) {
1656 flag
[source_row
.charAt(length
)] = false;
1659 if (source_row
.charAt(length
).isAlpha()) {
1660 stop_at('unexpected_a',
1661 line
, from, source_row
.charAt(length
));
1663 character
+= length
;
1664 source_row
= source_row
.slice(length
);
1665 quote
= source_row
.charAt(0);
1666 if (quote
=== '/' || quote
=== '*') {
1667 stop_at('confusing_regexp',
1670 return it('(regexp)', c
);
1672 c
= source_row
.charAt(length
);
1674 warn_at('control_a',
1675 line
, from + length
, String(c
));
1676 } else if (c
=== '<') {
1678 bundle
.unexpected_a
,
1689 if (source_row
.charAt(length
) === '?') {
1691 switch (source_row
.charAt(length
)) {
1699 bundle
.expected_a_b
,
1703 source_row
.charAt(length
)
1715 warn_at('unescaped_a',
1716 line
, from + length
, ')');
1723 while (source_row
.charAt(length
) === ' ') {
1728 warn_at('use_braces',
1729 line
, from + length
, pos
);
1733 c
= source_row
.charAt(length
);
1736 if (!option
.regexp
) {
1737 warn_at('insecure_a',
1738 line
, from + length
, c
);
1739 } else if (source_row
.charAt(length
) === ']') {
1740 stop_at('unescaped_a',
1741 line
, from + length
, '^');
1746 warn_at('empty_class', line
,
1751 c
= source_row
.charAt(length
);
1756 warn_at('unescaped_a',
1757 line
, from + length
, c
);
1764 warn_at('unescaped_a',
1765 line
, from + length
, '-');
1771 warn_at('unescaped_a',
1772 line
, from + length
- 1, '-');
1776 c
= source_row
.charAt(length
);
1784 } else if (c
=== '<') {
1786 bundle
.unexpected_a
,
1796 warn_at('unescaped_a',
1797 line
, from + length
- 1, '/');
1801 if (xmode
=== 'script') {
1802 c
= source_row
.charAt(length
);
1803 if (c
=== '!' || c
=== '/') {
1805 bundle
.html_confusion_a
,
1820 if (!option
.regexp
) {
1821 warn_at('insecure_a', line
,
1831 warn_at('unescaped_a', line
,
1835 if (xmode
=== 'script') {
1836 c
= source_row
.charAt(length
);
1837 if (c
=== '!' || c
=== '/') {
1839 bundle
.html_confusion_a
,
1849 switch (source_row
.charAt(length
)) {
1854 if (source_row
.charAt(length
) === '?') {
1860 c
= source_row
.charAt(length
);
1861 if (c
< '0' || c
> '9') {
1863 bundle
.expected_number_a
,
1872 c
= source_row
.charAt(length
);
1873 if (c
< '0' || c
> '9') {
1877 low
= +c
+ (low
* 10);
1883 c
= source_row
.charAt(length
);
1884 if (c
>= '0' && c
<= '9') {
1888 c
= source_row
.charAt(length
);
1889 if (c
< '0' || c
> '9') {
1893 high
= +c
+ (high
* 10);
1897 if (source_row
.charAt(length
) !== '}') {
1899 bundle
.expected_a_b
,
1908 if (source_row
.charAt(length
) === '?') {
1924 c
= source_row
.slice(0, length
- 1);
1925 character
+= length
;
1926 source_row
= source_row
.slice(length
);
1927 return it('(regexp)', c
);
1930 // Public lex methods
1933 init: function (source
) {
1934 if (typeof source
=== 'string') {
1936 .replace(crlfx
, '\n')
1947 range: function (begin
, end
) {
1950 if (source_row
.charAt(0) !== begin
) {
1951 stop_at('expected_a_b', line
, character
, begin
,
1952 source_row
.charAt(0));
1955 source_row
= source_row
.slice(1);
1957 c
= source_row
.charAt(0);
1960 stop_at('missing_a', line
, character
, c
);
1963 source_row
= source_row
.slice(1);
1965 return it('(range)', value
);
1968 warn_at('unexpected_a', line
, character
, c
);
1975 // token -- this is called by advance to get the next token.
1977 token: function () {
1978 var c
, i
, quote
, snippet
;
1981 while (!source_row
) {
1986 while (xmode
=== 'outer') {
1987 i
= source_row
.search(ox
);
1992 source_row
= source_row
.slice(i
);
1996 return it('(end)', '');
2000 snippet
= match(rx
[xmode
] || tx
);
2004 while (source_row
&& source_row
< '!') {
2005 source_row
= source_row
.slice(1);
2008 if (xmode
=== 'html') {
2009 return it('(error)', source_row
.charAt(0));
2011 stop_at('unexpected_a',
2012 line
, character
, source_row
.charAt(0));
2019 c
= snippet
.charAt(0);
2020 if (c
.isAlpha() || c
=== '_' || c
=== '$') {
2021 return it('(identifier)', snippet
);
2027 return number(snippet
);
2035 return string(snippet
);
2040 collect_comment(source_row
, '//', line
, character
);
2049 i
= source_row
.search(lx
);
2053 collect_comment(source_row
, quote
, line
, character
);
2056 stop_at('unclosed_comment', line
, character
);
2059 collect_comment(source_row
.slice(0, i
), quote
, character
, line
);
2061 if (source_row
.charAt(i
) === '/') {
2062 stop_at('nested_comment', line
, character
);
2064 source_row
= source_row
.slice(i
+ 2);
2071 if (token
.id
=== '/=') {
2078 return prereg
? regexp() : it('(punctuator)', snippet
);
2086 i
= source_row
.indexOf('--');
2090 i
= source_row
.indexOf('<!');
2092 stop_at('nested_comment',
2093 line
, character
+ i
);
2096 stop_at('unclosed_comment', length
, c
);
2099 length
= source_row
.indexOf('<!');
2100 if (length
>= 0 && length
< i
) {
2101 stop_at('nested_comment',
2102 line
, character
+ length
);
2105 if (source_row
.charAt(i
+ 2) !== '>') {
2106 stop_at('expected_a', line
, character
, '-->');
2109 source_row
= source_row
.slice(i
+ 3);
2112 if (xmode
=== 'html' || xmode
=== 'styleproperty') {
2114 c
= source_row
.charAt(0);
2115 if ((c
< '0' || c
> '9') &&
2116 (c
< 'a' || c
> 'f') &&
2117 (c
< 'A' || c
> 'F')) {
2121 source_row
= source_row
.slice(1);
2124 if (snippet
.length
!== 4 && snippet
.length
!== 7) {
2125 warn_at('bad_color_a', line
,
2126 from + length
, snippet
);
2128 return it('(color)', snippet
);
2130 return it('(punctuator)', snippet
);
2133 if (xmode
=== 'outer' && c
=== '&') {
2135 source_row
= source_row
.slice(1);
2137 c
= source_row
.charAt(0);
2139 source_row
= source_row
.slice(1);
2143 if (!((c
>= '0' && c
<= '9') ||
2144 (c
>= 'a' && c
<= 'z') ||
2146 stop_at('bad_entity', line
, from + length
,
2152 return it('(punctuator)', snippet
);
2161 function add_label(token
, kind
, name
) {
2163 // Define the symbol in the current function in the current scope.
2165 name
= name
|| token
.string
;
2167 // Global variables cannot be created in the safe subset. If a global variable
2168 // already exists, do nothing. If it is predefined, define it.
2170 if (funct
=== global_funct
) {
2172 warn('adsafe_a', token
, name
);
2174 if (typeof global_funct
[name
] !== 'string') {
2175 token
.writeable
= typeof predefined
[name
] === 'boolean' ?
2176 predefined
[name
] : true;
2177 token
.funct
= funct
;
2178 global_scope
[name
] = token
;
2180 if (kind
=== 'becoming') {
2184 // Ordinary variables.
2188 // Warn if the variable already exists.
2190 if (typeof funct
[name
] === 'string') {
2191 if (funct
[name
] === 'undef') {
2192 if (!option
.undef
) {
2193 warn('used_before_a', token
, name
);
2197 warn('already_defined', token
, name
);
2201 // Add the symbol to the current function.
2203 token
.funct
= funct
;
2204 token
.writeable
= true;
2205 scope
[name
] = token
;
2212 function peek(distance
) {
2214 // Peek ahead to a future token. The distance is how far ahead to look. The
2215 // default is the next token.
2217 var found
, slot
= 0;
2219 distance
= distance
|| 0;
2220 while (slot
<= distance
) {
2221 found
= lookahead
[slot
];
2223 found
= lookahead
[slot
] = lex
.token();
2231 function discard(it
) {
2233 // The token will not be included in the parse tree, so move the comments
2234 // that are attached to the token to tokens that are in the tree.
2239 while (prev
.comments
=== null) {
2242 if (prev
.comments
) {
2243 prev
.comments
= prev
.comments
.concat(it
.comments
);
2245 prev
.comments
= it
.comments
;
2252 function advance(id
, match
) {
2254 // Produce the next token, also looking for programming errors.
2258 // In indentation checking was requested, then inspect all of the line breakings.
2259 // The var statement is tricky because the names might be aligned or not. We
2260 // look at the first line break after the var to determine the programmer's
2263 if (var_mode
&& next_token
.line
!== token
.line
) {
2264 if ((var_mode
!== indent
|| !next_token
.edge
) &&
2265 next_token
.from === indent
.at
-
2266 (next_token
.edge
? option
.indent
: 0)) {
2269 dent
.at
-= option
.indent
;
2270 if (dent
=== var_mode
) {
2281 // If the token is an edge.
2283 if (next_token
.edge
) {
2284 if (next_token
.edge
=== 'label') {
2286 } else if (next_token
.edge
=== 'case') {
2287 expected_at(indent
.at
- option
.indent
);
2288 } else if (indent
.mode
!== 'array' || next_token
.line
!== token
.line
) {
2289 expected_at(indent
.at
);
2292 // If the token is not an edge, but is the first token on the line.
2294 } else if (next_token
.line
!== token
.line
) {
2295 if (next_token
.from < indent
.at
+ (indent
.mode
===
2296 'expression' ? 0 : option
.indent
)) {
2297 expected_at(indent
.at
+ option
.indent
);
2301 } else if (next_token
.line
!== token
.line
) {
2302 if (next_token
.edge
) {
2303 expected_at(indent
.at
);
2306 if (indent
.mode
=== 'statement' || indent
.mode
=== 'var') {
2307 expected_at(indent
.at
+ option
.indent
);
2308 } else if (next_token
.from < indent
.at
+ (indent
.mode
===
2309 'expression' ? 0 : option
.indent
)) {
2310 expected_at(indent
.at
+ option
.indent
);
2318 if (next_token
.id
=== '.') {
2319 warn('trailing_decimal_a');
2323 if (next_token
.id
=== '-' || next_token
.id
=== '--') {
2324 warn('confusing_a');
2328 if (next_token
.id
=== '+' || next_token
.id
=== '++') {
2329 warn('confusing_a');
2333 if (token
.id
=== '(string)' || token
.identifier
) {
2334 anonname
= token
.string
;
2337 if (id
&& next_token
.id
!== id
) {
2339 warn('expected_a_b_from_c_d', next_token
, id
,
2340 match
.id
, match
.line
, next_token
.string
);
2341 } else if (!next_token
.identifier
|| next_token
.string
!== id
) {
2342 warn('expected_a_b', next_token
, id
, next_token
.string
);
2347 next_token
= lookahead
.shift() || lex
.token();
2348 if (token
.id
=== '(end)') {
2354 function do_safe() {
2355 if (option
.adsafe
) {
2360 option
['continue'] =
2374 option
.windows
= false;
2377 delete predefined
.Array
;
2378 delete predefined
.Date
;
2379 delete predefined
.Function
;
2380 delete predefined
.Object
;
2381 delete predefined
['eval'];
2391 function do_globals() {
2392 var name
, writeable
;
2394 if (next_token
.id
!== '(string)' && !next_token
.identifier
) {
2397 name
= next_token
.string
;
2400 if (next_token
.id
=== ':') {
2402 switch (next_token
.id
) {
2404 writeable
= predefined
[name
] !== false;
2411 stop('unexpected_a');
2414 predefined
[name
] = writeable
;
2415 if (next_token
.id
!== ',') {
2423 function do_jslint() {
2425 while (next_token
.id
=== '(string)' || next_token
.identifier
) {
2426 name
= next_token
.string
;
2428 if (next_token
.id
!== ':') {
2429 stop('expected_a_b', next_token
, ':', next_token
.string
);
2434 value
= next_token
.number
;
2435 if (!isFinite(value
) || value
< 0 || Math
.floor(value
) !== value
) {
2436 stop('expected_small_a');
2438 option
.indent
= value
;
2441 value
= +next_token
.string
;
2442 value
= next_token
.number
;
2443 if (!isFinite(value
) || value
<= 0 || Math
.floor(value
) !== value
) {
2444 stop('expected_small_a');
2446 option
.maxerr
= value
;
2449 value
= next_token
.number
;
2450 if (!isFinite(value
) || value
<= 0 || Math
.floor(value
) !== value
) {
2451 stop('expected_small_a');
2453 option
.maxlen
= value
;
2456 if (next_token
.id
=== 'true') {
2457 option
[name
] = true;
2458 } else if (next_token
.id
=== 'false') {
2459 option
[name
] = false;
2461 stop('unexpected_a');
2465 option
.adsafe
= option
.safe
= true;
2474 if (next_token
.id
=== ',') {
2482 function do_properties() {
2484 option
.properties
= true;
2485 if (!funct
['(old_property_type)']) {
2486 funct
['(old_property_type)'] = property_type
;
2487 property_type
= Object
.create(property_type
);
2490 if (next_token
.id
!== '(string)' && !next_token
.identifier
) {
2493 name
= next_token
.string
;
2496 if (next_token
.id
=== ':') {
2498 if (next_token
.id
=== 'function') {
2499 advance('function');
2500 if (is_type
[next_token
.string
] === true) {
2501 type
= 'function ' + next_token
.string
;
2507 type
= next_token
.string
;
2508 if (is_type
[type
] !== true) {
2509 warn('expected_type_a', next_token
);
2515 property_type
[name
] = type
;
2516 if (next_token
.id
!== ',') {
2524 function directive() {
2525 var command
= this.id
,
2526 old_comments_off
= comments_off
,
2527 old_indent
= indent
;
2528 comments_off
= true;
2530 if (next_token
.line
=== token
.line
&& next_token
.from === token
.thru
) {
2531 warn('missing_space_a_b', next_token
, token
.string
, next_token
.string
);
2533 if (lookahead
.length
> 0 || next_token
.comments
) {
2534 warn('unexpected_a', this);
2537 case '/*properties':
2545 warn('adsafe_a', this);
2552 warn('adsafe_a', this);
2557 stop('unexpected_a', this);
2559 comments_off
= old_comments_off
;
2561 indent
= old_indent
;
2565 // Indentation intention
2567 function edge(mode
) {
2568 next_token
.edge
= indent
? indent
.open
&& (mode
|| 'edge') : '';
2572 function step_in(mode
) {
2574 if (typeof mode
=== 'number') {
2580 } else if (!indent
) {
2588 open
= mode
=== 'var' ||
2589 (next_token
.line
!== token
.line
&& mode
!== 'statement');
2591 at
: (open
|| mode
=== 'control' ?
2592 was
.at
+ option
.indent
: was
.at
) +
2593 (was
.wrap
? option
.indent
: 0),
2598 if (mode
=== 'var' && open
) {
2604 function step_out(id
, symbol
) {
2606 if (indent
&& indent
.open
) {
2607 indent
.at
-= option
.indent
;
2610 advance(id
, symbol
);
2613 indent
= indent
.was
;
2617 // Functions for conformance of whitespace.
2619 function one_space(left
, right
) {
2620 left
= left
|| token
;
2621 right
= right
|| next_token
;
2622 if (right
.id
!== '(end)' && !option
.white
&&
2623 (token
.line
!== right
.line
||
2624 token
.thru
+ 1 !== right
.from)) {
2625 warn('expected_space_a_b', right
, token
.string
, right
.string
);
2629 function one_space_only(left
, right
) {
2630 left
= left
|| token
;
2631 right
= right
|| next_token
;
2632 if (right
.id
!== '(end)' && (left
.line
!== right
.line
||
2633 (!option
.white
&& left
.thru
+ 1 !== right
.from))) {
2634 warn('expected_space_a_b', right
, left
.string
, right
.string
);
2638 function no_space(left
, right
) {
2639 left
= left
|| token
;
2640 right
= right
|| next_token
;
2641 if ((!option
.white
|| xmode
=== 'styleproperty' || xmode
=== 'style') &&
2642 left
.thru
!== right
.from && left
.line
=== right
.line
) {
2643 warn('unexpected_space_a_b', right
, left
.string
, right
.string
);
2647 function no_space_only(left
, right
) {
2648 left
= left
|| token
;
2649 right
= right
|| next_token
;
2650 if (right
.id
!== '(end)' && (left
.line
!== right
.line
||
2651 (!option
.white
&& left
.thru
!== right
.from))) {
2652 warn('unexpected_space_a_b', right
, left
.string
, right
.string
);
2656 function spaces(left
, right
) {
2657 if (!option
.white
) {
2658 left
= left
|| token
;
2659 right
= right
|| next_token
;
2660 if (left
.thru
=== right
.from && left
.line
=== right
.line
) {
2661 warn('missing_space_a_b', right
, left
.string
, right
.string
);
2667 if (next_token
.id
!== ',') {
2668 warn_at('expected_a_b', token
.line
, token
.thru
, ',', next_token
.string
);
2670 if (!option
.white
) {
2680 function semicolon() {
2681 if (next_token
.id
!== ';') {
2682 warn_at('expected_a_b', token
.line
, token
.thru
, ';', next_token
.string
);
2684 if (!option
.white
) {
2689 if (semicolon_coda
[next_token
.id
] !== true) {
2695 function use_strict() {
2696 if (next_token
.string
=== 'use strict') {
2698 warn('unnecessary_use');
2704 option
.newcap
= false;
2705 option
.undef
= false;
2713 function are_similar(a
, b
) {
2717 if (Array
.isArray(a
)) {
2718 if (Array
.isArray(b
) && a
.length
=== b
.length
) {
2720 for (i
= 0; i
< a
.length
; i
+= 1) {
2721 if (!are_similar(a
[i
], b
[i
])) {
2729 if (Array
.isArray(b
)) {
2732 if (a
.id
=== '(number)' && b
.id
=== '(number)') {
2733 return a
.number
=== b
.number
;
2735 if (a
.arity
=== b
.arity
&& a
.string
=== b
.string
) {
2740 return a
.id
=== b
.id
&& are_similar(a
.first
, b
.first
);
2742 return are_similar(a
.first
, b
.first
) &&
2743 are_similar(a
.second
, b
.second
);
2745 return are_similar(a
.first
, b
.first
) &&
2746 are_similar(a
.second
, b
.second
) &&
2747 are_similar(a
.third
, b
.third
);
2755 if (a
.id
=== '.' && b
.id
=== '[' && b
.arity
=== 'infix') {
2756 return a
.second
.string
=== b
.second
.string
&& b
.second
.id
=== '(string)';
2757 } else if (a
.id
=== '[' && a
.arity
=== 'infix' && b
.id
=== '.') {
2758 return a
.second
.string
=== b
.second
.string
&& a
.second
.id
=== '(string)';
2765 // This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
2766 // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
2767 // like .nud except that it is only used on the first token of a statement.
2768 // Having .fud makes it much easier to define statement-oriented languages like
2769 // JavaScript. I retained Pratt's nomenclature.
2771 // .nud Null denotation
2772 // .fud First null denotation
2773 // .led Left denotation
2774 // lbp Left binding power
2775 // rbp Right binding power
2777 // They are elements of the parsing method called Top Down Operator Precedence.
2779 function expression(rbp
, initial
) {
2781 // rbp is the right binding power.
2782 // initial indicates that this is the first expression of a statement.
2785 if (next_token
.id
=== '(end)') {
2786 stop('unexpected_a', token
, next_token
.id
);
2789 if (option
.safe
&& scope
[token
.string
] &&
2790 scope
[token
.string
] === global_scope
[token
.string
] &&
2791 (next_token
.id
!== '(' && next_token
.id
!== '.')) {
2792 warn('adsafe_a', token
);
2795 anonname
= 'anonymous';
2796 funct
['(verb)'] = token
.string
;
2798 if (initial
=== true && token
.fud
) {
2804 if (next_token
.id
=== '(number)' && token
.id
=== '.') {
2805 warn('leading_decimal_a', token
,
2810 stop('expected_identifier_a', token
, token
.id
);
2813 while (rbp
< next_token
.lbp
) {
2816 left
= token
.led(left
);
2818 stop('expected_operator_a', token
, token
.id
);
2826 // Functional constructors for making the symbols that will be inherited by
2829 function symbol(s
, p
) {
2831 if (!x
|| typeof x
!== 'object') {
2843 return symbol(s
, 0);
2847 function postscript(x
) {
2848 x
.postscript
= true;
2852 function ultimate(s
) {
2853 var x
= symbol(s
, 0);
2859 return postscript(x
);
2863 function stmt(s
, f
) {
2865 x
.identifier
= x
.reserved
= true;
2870 function labeled_stmt(s
, f
) {
2875 function disrupt_stmt(s
, f
) {
2881 function reserve_name(x
) {
2882 var c
= x
.id
.charAt(0);
2883 if ((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z')) {
2884 x
.identifier
= x
.reserved
= true;
2890 function prefix(s
, f
, type
) {
2891 var x
= symbol(s
, 150);
2893 x
.nud
= (typeof f
=== 'function') ? f : function () {
2894 if (s
=== 'typeof') {
2899 this.first
= expression(150);
2900 this.arity
= 'prefix';
2901 if (this.id
=== '++' || this.id
=== '--') {
2902 if (!option
.plusplus
) {
2903 warn('unexpected_a', this);
2904 } else if ((!this.first
.identifier
|| this.first
.reserved
) &&
2905 this.first
.id
!== '.' && this.first
.id
!== '[') {
2906 warn('bad_operand', this);
2916 function type(s
, t
, nud
) {
2918 x
.arity
= x
.type
= t
;
2926 function get_type(one
) {
2928 if (typeof one
!== 'object') {
2930 } if (one
.id
=== '.') {
2931 type
= property_type
[one
.second
.string
];
2932 return typeof type
=== 'string' ? type
: '';
2934 return ((one
.identifier
&& scope
[one
.string
]) || one
).type
;
2939 function set_type(one
, type
) {
2940 if (type
&& typeof one
=== 'object') {
2941 if (one
.id
=== '.') {
2942 property_type
[one
.second
.string
] = type
;
2944 ((one
.identifier
&& scope
[one
.string
]) || one
).type
= type
;
2951 function conform_type(one
, two
) {
2953 // This takes a type string or a token, or two tokens.
2955 var one_type
= get_type(one
),
2956 two_type
= get_type(two
),
2961 if (one_type
=== two_type
|| one_type
=== '*') {
2962 return two_type
!== '*' ? two_type
: '';
2963 } else if (one_type
=== 'function' &&
2964 two_type
.slice(0, 8) === 'function') {
2965 return set_type(one
, two_type
);
2966 } else if (two_type
=== 'function' &&
2967 one_type
.slice(0, 8) === 'function') {
2968 return set_type(two
, one_type
);
2970 if (two_type
!== '*' && !option
.confusion
) {
2971 if (typeof one
=== 'string') {
2972 one_string
= one_type
;
2973 } else if (one
.id
=== '.') {
2974 one_string
= '.' + one
.second
.string
+ ': ' + one_type
;
2976 one_string
= '\'' + (one
.number
|| one
.string
) + '\': ' + one_type
;
2978 if (two
.id
=== '.') {
2979 two_string
= '.' + two
.second
.string
+ ': ' + two_type
;
2981 two_string
= '\'' + (two
.number
|| two
.string
) + '\': ' + two_type
;
2983 warn('type_confusion_a_b', two
, one_string
, two_string
);
2987 } else if (one_type
!== '*') {
2988 return set_type(two
, one_type
);
2990 } else if (two_type
&& two_type
!== '*') {
2991 return set_type(one
, two_type
);
2996 function reserve(s
, f
) {
2998 x
.identifier
= x
.reserved
= true;
2999 if (typeof f
=== 'function') {
3006 function constant(name
, type
) {
3007 var x
= reserve(name
);
3010 x
.nud
= return_this
;
3015 function reservevar(s
, v
) {
3016 return reserve(s
, function () {
3017 if (typeof v
=== 'function') {
3025 function infix(s
, p
, f
, type
, w
) {
3026 var x
= symbol(s
, p
);
3028 x
.led = function (left
) {
3029 this.arity
= 'infix';
3031 spaces(prev_token
, token
);
3034 if (!option
.bitwise
&& this.bitwise
) {
3035 warn('unexpected_a', this);
3037 if (typeof f
=== 'function') {
3038 return f(left
, this);
3041 this.second
= expression(p
);
3051 function expected_relation(node
, message
) {
3053 warn(message
|| bundle
.conditional_assignment
, node
);
3058 function expected_condition(node
, message
) {
3062 if (node
.arity
!== 'infix') {
3063 warn(message
|| bundle
.weird_condition
, node
);
3078 warn(message
|| bundle
.weird_condition
, node
);
3081 if (node
.first
.id
=== '.' && numbery
[node
.first
.second
.string
] === true) {
3082 warn(message
|| bundle
.weird_condition
, node
);
3089 function check_relation(node
) {
3090 switch (node
.arity
) {
3095 warn('unexpected_a', node
);
3098 warn('confusing_a', node
);
3104 warn('unexpected_a', node
);
3107 if (node
.id
=== 'NaN') {
3108 warn('isnan', node
);
3115 function relation(s
, eqeq
) {
3116 return infix(s
, 100, function (left
, that
) {
3117 check_relation(left
);
3118 if (eqeq
&& !option
.eqeq
) {
3119 warn('expected_a_b', that
, eqeq
, that
.id
);
3121 var right
= expression(100);
3122 if (are_similar(left
, right
) ||
3123 ((left
.id
=== '(string)' || left
.id
=== '(number)') &&
3124 (right
.id
=== '(string)' || right
.id
=== '(number)'))) {
3125 warn('weird_relation', that
);
3128 that
.second
= check_relation(right
);
3129 conform_type(left
, that
.second
, that
);
3135 function assignop(s
, op
) {
3136 var x
= infix(s
, 20, function (left
, that
) {
3139 if (left
.identifier
) {
3140 if (scope
[left
.string
]) {
3141 if (scope
[left
.string
].writeable
=== false) {
3142 warn('read_only', left
);
3147 } else if (option
.safe
) {
3150 if (typeof predefined
[l
.string
] === 'boolean') {
3151 warn('adsafe_a', l
);
3156 if (left
=== syntax
['function']) {
3157 warn('identifier_function', token
);
3159 if (left
.id
=== '.' || left
.id
=== '[') {
3160 if (!left
.first
|| left
.first
.string
=== 'arguments') {
3161 warn('bad_assignment', that
);
3163 } else if (left
.identifier
&& !left
.reserved
) {
3164 if (funct
[left
.string
] === 'exception') {
3165 warn('assign_exception', left
);
3168 that
.second
= expression(19);
3169 if (that
.id
=== '=' && are_similar(that
.first
, that
.second
)) {
3170 warn('weird_assignment', that
);
3173 conform_type(left
, that
);
3174 conform_type(that
, that
.second
);
3176 conform_type(left
, that
.second
);
3182 if (syntax
[op
].type
) {
3183 x
.type
= syntax
[op
].type
;
3185 if (syntax
[op
].bitwise
) {
3193 function bitwise(s
, p
) {
3194 var x
= infix(s
, p
, 'number');
3200 function suffix(s
) {
3201 var x
= symbol(s
, 150);
3202 x
.led = function (left
) {
3203 no_space_only(prev_token
, token
);
3204 if (!option
.plusplus
) {
3205 warn('unexpected_a', this);
3206 } else if ((!left
.identifier
|| left
.reserved
) &&
3207 left
.id
!== '.' && left
.id
!== '[') {
3208 warn('bad_operand', this);
3211 this.arity
= 'suffix';
3218 function optional_identifier() {
3219 if (next_token
.identifier
) {
3221 if (option
.safe
&& banned
[token
.string
]) {
3222 warn('adsafe_a', token
);
3223 } else if (token
.reserved
&& !option
.es5
) {
3224 warn('expected_identifier_a_reserved', token
);
3226 return token
.string
;
3231 function identifier() {
3232 var i
= optional_identifier();
3234 stop(token
.id
=== 'function' && next_token
.id
=== '(' ?
3235 'name_function' : 'expected_identifier_a');
3241 function statement() {
3243 var label
, old_scope
= scope
, the_statement
;
3245 // We don't like the empty statement.
3247 if (next_token
.id
=== ';') {
3248 warn('unexpected_a');
3253 // Is this a labeled statement?
3255 if (next_token
.identifier
&& !next_token
.reserved
&& peek().id
=== ':') {
3262 scope
= Object
.create(old_scope
);
3263 add_label(label
, 'label');
3264 if (next_token
.labeled
!== true) {
3265 warn('label_a_b', next_token
, label
.string
, next_token
.string
);
3266 } else if (jx
.test(label
.string
+ ':')) {
3268 } else if (funct
=== global_funct
) {
3269 stop('unexpected_a', token
);
3271 next_token
.label
= label
;
3274 // Parse the statement.
3277 step_in('statement');
3278 the_statement
= expression(0, true);
3279 if (the_statement
) {
3281 // Look for the final semicolon.
3283 if (the_statement
.arity
=== 'statement') {
3284 if (the_statement
.id
=== 'switch' ||
3285 (the_statement
.block
&& the_statement
.id
!== 'do')) {
3292 // If this is an expression statement, determine if it is acceptable.
3295 // statments. If it is to be used at all, new should only be used to make
3296 // objects, not side effects. The expression statements we do like do
3297 // assignment or invocation or delete.
3299 if (the_statement
.id
=== '(') {
3300 if (the_statement
.first
.id
=== 'new') {
3303 } else if (!the_statement
.assign
&&
3304 the_statement
.id
!== 'delete' &&
3305 the_statement
.id
!== '++' &&
3306 the_statement
.id
!== '--') {
3307 warn('assignment_function_expression', token
);
3314 return the_statement
;
3318 function statements() {
3319 var array
= [], disruptor
, the_statement
;
3321 // A disrupt statement may not be followed by any other statement.
3322 // If the last statement is disrupt, then the sequence is disrupt.
3324 while (next_token
.postscript
!== true) {
3325 if (next_token
.id
=== ';') {
3326 warn('unexpected_a', next_token
);
3329 if (next_token
.string
=== 'use strict') {
3330 if (!node_js
|| funct
!== global_funct
|| array
.length
> 0) {
3331 warn('function_strict');
3336 warn('unreachable_a_b', next_token
, next_token
.string
,
3340 the_statement
= statement();
3341 if (the_statement
) {
3342 array
.push(the_statement
);
3343 if (the_statement
.disrupt
) {
3344 disruptor
= the_statement
;
3345 array
.disrupt
= true;
3354 function block(ordinary
) {
3356 // array block is array sequence of statements wrapped in braces.
3357 // ordinary is false for function bodies and try blocks.
3358 // ordinary is true for if statements, while, etc.
3362 old_inblock
= in_block
,
3364 old_strict_mode
= strict_mode
;
3366 in_block
= ordinary
;
3367 scope
= Object
.create(scope
);
3369 if (next_token
.id
=== '{') {
3372 if (!ordinary
&& !use_strict() && !old_strict_mode
&&
3373 !option
.sloppy
&& funct
['(context)'] === global_funct
) {
3374 warn('missing_use_strict');
3376 array
= statements();
3377 strict_mode
= old_strict_mode
;
3378 step_out('}', curly
);
3380 } else if (!ordinary
) {
3381 stop('expected_a_b', next_token
, '{', next_token
.string
);
3383 warn('expected_a_b', next_token
, '{', next_token
.string
);
3384 array
= [statement()];
3385 array
.disrupt
= array
[0].disrupt
;
3387 funct
['(verb)'] = null;
3389 in_block
= old_inblock
;
3390 if (ordinary
&& array
.length
=== 0) {
3391 warn('empty_block');
3397 function tally_property(name
) {
3398 if (option
.properties
&& typeof property_type
[name
] !== 'string') {
3399 warn('unexpected_property_a', token
, name
);
3401 if (typeof member
[name
] === 'number') {
3409 // ECMAScript parser
3411 syntax
['(identifier)'] = {
3415 var name
= this.string
,
3416 variable
= scope
[name
],
3420 // If the variable is not in scope, then we may have an undeclared variable.
3421 // Check the predefined list. If it was predefined, create the global
3424 if (typeof variable
!== 'object') {
3425 writeable
= predefined
[name
];
3426 if (typeof writeable
=== 'boolean') {
3427 global_scope
[name
] = variable
= {
3429 writeable
: writeable
,
3432 global_funct
[name
] = 'var';
3434 // But if the variable is not in scope, and is not predefined, and if we are not
3435 // in the global scope, then we have an undefined variable error.
3438 if (!option
.undef
) {
3439 warn('used_before_a', token
);
3441 scope
[name
] = variable
= {
3446 funct
[name
] = 'undef';
3450 site
= variable
.funct
;
3452 // The name is in scope and defined in the current function.
3454 if (funct
=== site
) {
3456 // Change 'unused' to 'var', and reject labels.
3458 switch (funct
[name
]) {
3460 warn('unexpected_a', token
);
3461 funct
[name
] = 'var';
3464 funct
[name
] = 'var';
3467 funct
[name
] = 'parameter';
3470 funct
[name
] = 'function';
3473 warn('a_label', token
, name
);
3477 // If the name is already defined in the current
3478 // function, but not as outer, then there is a scope error.
3481 switch (funct
[name
]) {
3486 warn('a_scope', token
, name
);
3489 warn('a_label', token
, name
);
3496 // If the name is defined in an outer function, make an outer entry, and if
3497 // it was unused, make it var.
3499 switch (site
[name
]) {
3507 site
[name
] = 'closure';
3508 funct
[name
] = site
=== global_funct
? 'global' : 'outer';
3511 site
[name
] = 'parameter';
3512 funct
[name
] = 'outer';
3515 funct
[name
] = 'undef';
3518 warn('a_label', token
, name
);
3526 stop('expected_operator_a');
3530 // Build the syntax table by declaring the syntactic elements.
3532 type('(array)', 'array');
3533 type('(color)', 'color');
3534 type('(function)', 'function');
3535 type('(number)', 'number', return_this
);
3536 type('(object)', 'object');
3537 type('(string)', 'string', return_this
);
3538 type('(boolean)', 'boolean', return_this
);
3539 type('(range)', 'range');
3540 type('(regexp)', 'regexp', return_this
);
3542 ultimate('(begin)');
3544 ultimate('(error)');
3545 postscript(delim('</'));
3549 postscript(delim('}'));
3552 postscript(delim('"'));
3553 postscript(delim('\''));
3560 postscript(reserve('case'));
3562 postscript(reserve('default'));
3566 reservevar('arguments', function (x
) {
3567 if (strict_mode
&& funct
=== global_funct
) {
3569 } else if (option
.safe
) {
3570 warn('adsafe_a', x
);
3573 reservevar('eval', function (x
) {
3575 warn('adsafe_a', x
);
3578 constant('false', 'boolean');
3579 constant('Infinity', 'number');
3580 constant('NaN', 'number');
3581 constant('null', '');
3582 reservevar('this', function (x
) {
3583 if (strict_mode
&& ((funct
['(statement)'] &&
3584 funct
['(name)'].charAt(0) > 'Z') || funct
=== global_funct
)) {
3586 } else if (option
.safe
) {
3587 warn('adsafe_a', x
);
3590 constant('true', 'boolean');
3591 constant('undefined', '');
3593 infix('?', 30, function (left
, that
) {
3594 that
.first
= expected_condition(expected_relation(left
));
3595 that
.second
= expression(0);
3597 var colon
= next_token
;
3601 that
.third
= expression(10);
3602 that
.arity
= 'ternary';
3603 set_type(that
, conform_type(that
.second
, that
.third
));
3604 if (are_similar(that
.second
, that
.third
)) {
3605 warn('weird_ternary', colon
);
3606 } else if (are_similar(that
.first
, that
.second
)) {
3607 warn('use_or', that
);
3612 infix('||', 40, function (left
, that
) {
3613 function paren_check(that
) {
3614 if (that
.id
=== '&&' && !that
.paren
) {
3620 that
.first
= paren_check(expected_condition(expected_relation(left
)));
3621 that
.second
= paren_check(expected_relation(expression(40)));
3622 if (are_similar(that
.first
, that
.second
)) {
3623 warn('weird_condition', that
);
3628 infix('&&', 50, function (left
, that
) {
3629 that
.first
= expected_condition(expected_relation(left
));
3630 that
.second
= expected_relation(expression(50));
3631 if (are_similar(that
.first
, that
.second
)) {
3632 warn('weird_condition', that
);
3637 prefix('void', function () {
3638 this.first
= expression(0);
3639 this.arity
= 'prefix';
3640 if (this.first
.id
!== '(number)' || this.first
.string
) {
3641 warn('unexpected_a', this);
3644 this.type
= 'undefined';
3652 relation('==', '===');
3654 relation('!=', '!==');
3663 bitwise('>>>', 120);
3665 infix('in', 120, function (left
, that
) {
3666 warn('infix_in', that
);
3668 that
.right
= expression(130);
3671 infix('instanceof', 120, null, 'boolean');
3672 infix('+', 130, function (left
, that
) {
3673 if (left
.id
=== '(number)') {
3674 if (left
.number
=== 0) {
3675 warn('unexpected_a', left
, '0');
3677 } else if (left
.id
=== '(string)') {
3678 if (left
.string
=== '') {
3679 warn('expected_a_b', left
, 'String', '\'\'');
3682 var right
= expression(130);
3683 if (right
.id
=== '(number)') {
3684 if (right
.number
=== 0) {
3685 warn('unexpected_a', right
, '0');
3687 } else if (right
.id
=== '(string)') {
3688 if (right
.string
=== '') {
3689 warn('expected_a_b', right
, 'String', '\'\'');
3692 if (left
.id
=== right
.id
) {
3693 if (left
.id
=== '(string)' || left
.id
=== '(number)') {
3694 if (left
.id
=== '(string)') {
3695 left
.string
+= right
.string
;
3696 if (jx
.test(left
.string
)) {
3700 left
.number
+= right
.number
;
3702 left
.thru
= right
.thru
;
3709 that
.second
= right
;
3710 set_type(that
, conform_type(left
, right
));
3714 prefix('+++', function () {
3715 warn('confusing_a', token
);
3716 this.first
= expression(150);
3717 this.arity
= 'prefix';
3720 infix('+++', 130, function (left
) {
3721 warn('confusing_a', token
);
3723 this.second
= expression(130);
3726 infix('-', 130, function (left
, that
) {
3727 if ((left
.id
=== '(number)' && left
.number
=== 0) || left
.id
=== '(string)') {
3728 warn('unexpected_a', left
);
3730 var right
= expression(130);
3731 if ((right
.id
=== '(number)' && right
.number
=== 0) || right
.id
=== '(string)') {
3732 warn('unexpected_a', left
);
3734 if (left
.id
=== right
.id
&& left
.id
=== '(number)') {
3735 left
.number
-= right
.number
;
3736 left
.thru
= right
.thru
;
3742 that
.second
= right
;
3746 prefix('---', function () {
3747 warn('confusing_a', token
);
3748 this.first
= expression(150);
3749 this.arity
= 'prefix';
3752 infix('---', 130, function (left
) {
3753 warn('confusing_a', token
);
3755 this.second
= expression(130);
3758 infix('*', 140, function (left
, that
) {
3759 if ((left
.id
=== '(number)' && (left
.number
=== 0 || left
.number
=== 1)) || left
.id
=== '(string)') {
3760 warn('unexpected_a', left
);
3762 var right
= expression(140);
3763 if ((right
.id
=== '(number)' && (right
.number
=== 0 || right
.number
=== 1)) || right
.id
=== '(string)') {
3764 warn('unexpected_a', right
);
3766 if (left
.id
=== right
.id
&& left
.id
=== '(number)') {
3767 left
.number
*= right
.number
;
3768 left
.thru
= right
.thru
;
3774 that
.second
= right
;
3777 infix('/', 140, function (left
, that
) {
3778 if ((left
.id
=== '(number)' && left
.number
=== 0) || left
.id
=== '(string)') {
3779 warn('unexpected_a', left
);
3781 var right
= expression(140);
3782 if ((right
.id
=== '(number)' && (right
.number
=== 0 || right
.number
=== 1)) || right
.id
=== '(string)') {
3783 warn('unexpected_a', right
);
3785 if (left
.id
=== right
.id
&& left
.id
=== '(number)') {
3786 left
.number
/= right
.number
;
3787 left
.thru
= right
.thru
;
3793 that
.second
= right
;
3796 infix('%', 140, function (left
, that
) {
3797 if ((left
.id
=== '(number)' && (left
.number
=== 0 || left
.number
=== 1)) || left
.id
=== '(string)') {
3798 warn('unexpected_a', left
);
3800 var right
= expression(140);
3801 if ((right
.id
=== '(number)' && right
.number
=== 0) || right
.id
=== '(string)') {
3802 warn('unexpected_a', right
);
3804 if (left
.id
=== right
.id
&& left
.id
=== '(number)') {
3805 left
.number
%= right
.number
;
3806 left
.thru
= right
.thru
;
3812 that
.second
= right
;
3821 prefix('delete', function () {
3823 var p
= expression(0);
3824 if (!p
|| (p
.id
!== '.' && p
.id
!== '[')) {
3832 prefix('~', function () {
3834 if (!option
.bitwise
) {
3835 warn('unexpected_a', this);
3840 prefix('!', function () {
3842 this.first
= expected_condition(expression(150));
3843 this.arity
= 'prefix';
3844 if (bang
[this.first
.id
] === true) {
3845 warn('confusing_a', this);
3849 prefix('typeof', null, 'string');
3850 prefix('new', function () {
3852 var c
= expression(160), n
, p
, v
;
3854 if (c
.id
!== 'function') {
3858 warn('use_object', token
);
3861 if (next_token
.id
=== '(') {
3865 if (next_token
.id
!== ')') {
3868 if (get_type(n
) !== 'number' || next_token
.id
=== ',') {
3869 warn('use_array', p
);
3871 while (next_token
.id
=== ',') {
3873 p
.second
.push(expression(0));
3876 warn('use_array', token
);
3882 warn('use_array', token
);
3889 warn('not_a_constructor', c
);
3893 warn('function_eval');
3900 if (c
.id
!== 'function') {
3901 v
= c
.string
.charAt(0);
3902 if (!option
.newcap
&& (v
< 'A' || v
> 'Z')) {
3903 warn('constructor_name_a', token
);
3908 if (c
.id
!== '.' && c
.id
!== '[' && c
.id
!== '(') {
3909 warn('bad_constructor', token
);
3913 warn('weird_new', this);
3915 if (next_token
.id
!== '(') {
3916 warn('missing_a', next_token
, '()');
3921 infix('(', 160, function (left
, that
) {
3923 if (indent
&& indent
.mode
=== 'expression') {
3924 no_space(prev_token
, token
);
3926 no_space_only(prev_token
, token
);
3928 if (!left
.immed
&& left
.id
=== 'function') {
3929 warn('wrap_immediate');
3932 if (left
.identifier
) {
3933 if (left
.string
=== 'String') {
3934 conform_type('string', that
);
3935 } else if (left
.string
=== 'Number') {
3936 conform_type('number', that
);
3937 } else if (left
.string
=== 'Boolean') {
3938 conform_type('boolean', that
);
3940 set_type(that
, conform_type('function', left
).slice(9));
3942 } else if (left
.id
=== '.') {
3943 switch (left
.second
.string
) {
3946 set_type(that
, conform_type('function', left
.first
).slice(9));
3950 conform_type(that
, left
.first
);
3954 conform_type('function', left
);
3957 set_type(that
, conform_type('function', left
).slice(9));
3960 set_type(that
, conform_type('function', left
).slice(9));
3962 if (left
.identifier
) {
3963 if (left
.string
.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
3964 if (left
.string
!== 'Number' && left
.string
!== 'String' &&
3965 left
.string
!== 'Boolean' && left
.string
!== 'Date') {
3966 if (left
.string
=== 'Math' || left
.string
=== 'JSON') {
3967 warn('not_a_function', left
);
3968 } else if (left
.string
=== 'Object') {
3969 warn('use_object', token
);
3970 } else if (left
.string
=== 'Array' || !option
.newcap
) {
3971 warn('missing_a', left
, 'new');
3975 } else if (left
.id
=== '.') {
3976 if (option
.safe
&& left
.first
.string
=== 'Math' &&
3977 left
.second
=== 'random') {
3978 warn('adsafe_a', left
);
3979 } else if (left
.second
.string
=== 'split' &&
3980 left
.first
.id
=== '(string)') {
3981 warn('use_array', left
.second
);
3985 if (next_token
.id
!== ')') {
3989 p
.push(expression(10));
3990 if (next_token
.id
!== ',') {
3997 step_out(')', that
);
3998 if (typeof left
=== 'object') {
3999 if (left
.string
=== 'parseInt' && p
.length
=== 1) {
4000 warn('radix', left
);
4003 if (left
.string
=== 'eval' || left
.string
=== 'Function' ||
4004 left
.string
=== 'execScript') {
4006 } else if (p
[0] && p
[0].id
=== '(string)' &&
4007 (left
.string
=== 'setTimeout' ||
4008 left
.string
=== 'setInterval')) {
4009 warn('implied_evil', left
);
4012 if (!left
.identifier
&& left
.id
!== '.' && left
.id
!== '[' &&
4013 left
.id
!== '(' && left
.id
!== '&&' && left
.id
!== '||' &&
4015 warn('bad_invocation', left
);
4023 prefix('(', function () {
4024 step_in('expression');
4028 if (next_token
.id
=== 'function') {
4029 next_token
.immed
= true;
4031 var value
= expression(0);
4034 step_out(')', this);
4036 if (value
.id
=== 'function') {
4037 if (next_token
.id
=== '(') {
4038 warn('move_invocation');
4040 warn('bad_wrap', this);
4046 infix('.', 170, function (left
, that
) {
4047 no_space(prev_token
, token
);
4049 var name
= identifier(), type
;
4050 if (typeof name
=== 'string') {
4051 tally_property(name
);
4054 that
.second
= token
;
4055 if (left
&& left
.string
=== 'arguments' &&
4056 (name
=== 'callee' || name
=== 'caller')) {
4057 warn('avoid_a', left
, 'arguments.' + name
);
4058 } else if (!option
.evil
&& left
&& left
.string
=== 'document' &&
4059 (name
=== 'write' || name
=== 'writeln')) {
4060 warn('write_is_wrong', left
);
4061 } else if (option
.adsafe
) {
4062 if (!adsafe_top
&& left
.string
=== 'ADSAFE') {
4063 if (name
=== 'id' || name
=== 'lib') {
4064 warn('adsafe_a', that
);
4065 } else if (name
=== 'go') {
4066 if (xmode
!== 'script') {
4067 warn('adsafe_a', that
);
4068 } else if (adsafe_went
|| next_token
.id
!== '(' ||
4069 peek(0).id
!== '(string)' ||
4070 peek(0).string
!== adsafe_id
||
4071 peek(1).id
!== ',') {
4072 stop('adsafe_a', that
, 'go');
4080 if (!option
.evil
&& (name
=== 'eval' || name
=== 'execScript')) {
4082 } else if (option
.safe
) {
4084 if (banned
[name
] === true) {
4085 warn('adsafe_a', token
, name
);
4087 if (typeof predefined
[left
.string
] !== 'boolean' || //// check for writeable
4088 next_token
.id
=== '(') {
4091 if (next_token
.id
!== '.') {
4092 warn('adsafe_a', that
);
4097 token
.second
= name
;
4099 name
= identifier();
4100 if (typeof name
=== 'string') {
4101 tally_property(name
);
4105 type
= property_type
[name
];
4106 if (type
&& typeof type
=== 'string' && type
!== '*') {
4112 infix('[', 170, function (left
, that
) {
4114 no_space_only(prev_token
, token
);
4119 switch (get_type(e
)) {
4121 if (e
.id
=== '(number)' && left
.id
=== 'arguments') {
4122 warn('use_param', left
);
4124 conform_type('array', left
);
4127 if (e
.id
=== '(string)') {
4128 if (option
.safe
&& (banned
[e
.string
] ||
4129 e
.string
.charAt(0) === '_' || e
.string
.slice(-1) === '_')) {
4130 warn('adsafe_subscript_a', e
);
4131 } else if (!option
.evil
&&
4132 (e
.string
=== 'eval' || e
.string
=== 'execScript')) {
4134 } else if (!option
.sub
&& ix
.test(e
.string
)) {
4135 s
= syntax
[e
.string
];
4136 if (!s
|| !s
.reserved
) {
4137 warn('subscript', e
);
4140 tally_property(e
.string
);
4141 } else if (option
.safe
&& e
.id
!== 'typeof') {
4142 warn('adsafe_subscript_a', e
);
4144 conform_type('object', left
);
4147 switch (get_type(left
)) {
4149 conform_type('number', e
);
4152 conform_type('string', e
);
4155 if (!option
.confusion
) {
4156 warn('use_charAt', that
);
4158 set_type(that
, 'string');
4162 warn('adsafe_subscript_a', e
);
4167 warn('adsafe_subscript_a', e
);
4170 step_out(']', that
);
4172 no_space(prev_token
, token
);
4178 prefix('[', function () {
4179 this.arity
= 'prefix';
4181 set_type(this, 'array');
4183 while (next_token
.id
!== '(end)') {
4184 while (next_token
.id
=== ',') {
4185 warn('unexpected_a', next_token
);
4189 if (next_token
.id
=== ']') {
4192 indent
.wrap
= false;
4194 this.first
.push(expression(10));
4195 if (next_token
.id
=== ',') {
4197 if (next_token
.id
=== ']' && !option
.es5
) {
4198 warn('unexpected_a', token
);
4205 step_out(']', this);
4211 function property_name() {
4212 var id
= optional_identifier(true);
4214 if (next_token
.id
=== '(string)') {
4215 id
= next_token
.string
;
4219 } else if (id
.charAt(0) === '_' ||
4220 id
.charAt(id
.length
- 1) === '_') {
4225 } else if (next_token
.id
=== '(number)') {
4226 id
= next_token
.number
.toString();
4234 function function_params() {
4235 var id
, paren
= next_token
, params
= [];
4240 if (next_token
.id
=== ')') {
4242 step_out(')', paren
);
4250 add_label(token
, option
.unparam
? 'parameter' : 'unparam');
4251 if (next_token
.id
=== ',') {
4255 step_out(')', paren
);
4263 function complexity(exp
) {
4266 if (Array
.isArray(exp
)) {
4267 exp
.forEach(function (tok
) {
4268 score
+= complexity(tok
);
4271 switch (exp
.arity
) {
4275 score
+= complexity(exp
.first
) + complexity(exp
.block
) +
4276 complexity(exp
['else']) + 1;
4280 if (exp
.first
.id
!== 'true' && exp
.first
.number
!== 1) {
4283 score
+= complexity(exp
.first
) + complexity(exp
.block
);
4286 if (exp
.second
!== undefined &&
4287 exp
.second
.id
!== 'true' &&
4288 exp
.second
.number
!== 1) {
4291 score
+= complexity(exp
.first
) + complexity(exp
.second
) +
4292 complexity(exp
.third
) + complexity(exp
.block
);
4295 score
+= complexity(exp
.first
) +
4296 complexity(exp
.second
) + exp
.second
.length
;
4297 if (exp
.second
[exp
.second
.length
- 1].id
=== 'default') {
4308 score
+= complexity(exp
.first
) + complexity(exp
.second
) +
4309 complexity(exp
.third
) + complexity(exp
.block
);
4314 score
+= complexity(exp
.first
);
4318 score
+= complexity(exp
.first
) + complexity(exp
.second
);
4319 if (exp
.id
=== '&&' || exp
.id
=== '||') {
4324 score
+= complexity(exp
.first
) + complexity(exp
.second
) + complexity(exp
.third
);
4333 function do_function(func
, name
) {
4334 var old_funct
= funct
,
4335 old_option
= option
,
4338 '(name)' : name
|| '\'' + (anonname
|| '').replace(nx
, sanitize
) + '\'',
4339 '(line)' : next_token
.line
,
4340 '(context)' : old_funct
,
4346 option
= Object
.create(old_option
);
4347 scope
= Object
.create(old_scope
);
4348 functions
.push(funct
);
4351 add_label(func
, 'function', name
);
4353 func
.writeable
= false;
4354 func
.first
= funct
['(params)'] = function_params();
4356 func
.block
= block(false);
4357 set_type(func
, funct
['(return_type)'] ?
4358 'function ' + funct
['(return_type)'] :
4360 if (funct
['(old_property_type)']) {
4361 property_type
= funct
['(old_property_type)'];
4362 delete funct
['(old_property_type)'];
4364 funct
['(complexity)'] = complexity(func
.block
) + 1;
4365 if (option
.confusion
) {
4366 funct
['(confusion)'] = true;
4369 option
= old_option
;
4375 assignop('+=', '+');
4376 assignop('-=', '-');
4377 assignop('*=', '*');
4378 assignop('/=', '/').nud = function () {
4379 stop('slash_equal');
4381 assignop('%=', '%');
4382 assignop('&=', '&');
4383 assignop('|=', '|');
4384 assignop('^=', '^');
4385 assignop('<<=', '<<');
4386 assignop('>>=', '>>');
4387 assignop('>>>=', '>>>');
4390 prefix('{', function () {
4391 var get, i
, j
, name
, p
, set, seen
= {}, type
;
4392 this.arity
= 'prefix';
4394 set_type(this, 'object');
4396 while (next_token
.id
!== '}') {
4397 indent
.wrap
= false;
4399 // JSLint recognizes the ES5 extension for get/set in object literals,
4400 // but requires that they be used in pairs.
4403 if (next_token
.string
=== 'get' && peek().id
!== ':') {
4411 i
= property_name();
4413 stop('missing_property');
4417 if (funct
['(loopage)']) {
4418 warn('function_loop', get);
4422 warn('parameter_a_get_b', p
[0], p
[0].string
, i
);
4431 j
= property_name();
4433 stop('expected_a_b', token
, i
, j
|| next_token
.string
);
4437 if (!p
|| p
.length
!== 1) {
4438 stop('parameter_set_a', set, 'value');
4439 } else if (p
[0].string
!== 'value') {
4440 stop('expected_a_b', p
[0], 'value', p
[0].string
);
4442 name
.first
= [get, set];
4445 i
= property_name();
4446 if (typeof i
!== 'string') {
4447 stop('missing_property');
4452 name
.first
= expression(10);
4453 type
= property_type
[i
];
4455 name
.type
= conform_type(type
, name
.first
);
4457 type
= get_type(name
.first
);
4458 if (type
&& type
!== '*') {
4459 property_type
[i
] = name
.type
= type
;
4463 this.first
.push(name
);
4464 if (seen
[i
] === true) {
4465 warn('duplicate_a', next_token
, i
);
4469 if (next_token
.id
!== ',') {
4474 if (next_token
.id
!== ',') {
4477 warn('unexpected_a', next_token
);
4479 if (next_token
.id
=== '}' && !option
.es5
) {
4480 warn('unexpected_a', token
);
4483 step_out('}', this);
4488 stmt('{', function () {
4490 warn('statement_block');
4491 this.arity
= 'statement';
4492 this.block
= statements();
4493 this.disrupt
= this.block
.disrupt
;
4499 stmt('/*global', directive
);
4500 stmt('/*globals', directive
);
4501 stmt('/*jslint', directive
);
4502 stmt('/*member', directive
);
4503 stmt('/*members', directive
);
4504 stmt('/*property', directive
);
4505 stmt('/*properties', directive
);
4507 stmt('var', function () {
4509 // JavaScript does not have block scope. It only has function scope. So,
4510 // declaring a variable in a block can have unexpected consequences.
4512 // var.first will contain an array, the array containing name tokens
4513 // and assignment tokens.
4515 var assign
, id
, name
;
4517 if (funct
['(vars)'] && !option
.vars
) {
4518 warn('combine_var');
4519 } else if (funct
!== global_funct
) {
4520 funct
['(vars)'] = true;
4522 this.arity
= 'statement';
4528 add_label(name
, 'becoming');
4530 if (next_token
.id
=== '=') {
4531 assign
= next_token
;
4532 assign
.first
= name
;
4536 if (next_token
.id
=== 'undefined') {
4537 warn('unnecessary_initialize', token
, id
);
4539 if (peek(0).id
=== '=' && next_token
.identifier
) {
4542 assign
.second
= expression(0);
4543 assign
.arity
= 'infix';
4544 this.first
.push(assign
);
4545 conform_type(name
, assign
.second
);
4547 this.first
.push(name
);
4549 if (funct
[id
] === 'becoming') {
4550 funct
[id
] = 'unused';
4552 if (next_token
.id
!== ',') {
4556 indent
.wrap
= false;
4557 if (var_mode
&& next_token
.line
=== token
.line
&&
4558 this.first
.length
=== 1) {
4560 indent
.open
= false;
4561 indent
.at
-= option
.indent
;
4571 stmt('function', function () {
4574 warn('function_block', token
);
4576 var name
= next_token
, id
= identifier();
4577 add_label(name
, 'unction');
4579 do_function(this, id
);
4580 if (next_token
.id
=== '(' && next_token
.line
=== token
.line
) {
4581 stop('function_statement');
4583 this.arity
= 'statement';
4587 prefix('function', function () {
4589 var id
= optional_identifier();
4595 do_function(this, id
);
4596 if (funct
['(loopage)']) {
4597 warn('function_loop');
4599 this.arity
= 'function';
4603 stmt('if', function () {
4604 var paren
= next_token
;
4611 this.arity
= 'statement';
4612 this.first
= expected_condition(expected_relation(expression(0)));
4614 step_out(')', paren
);
4617 this.block
= block(true);
4618 if (next_token
.id
=== 'else') {
4623 this['else'] = next_token
.id
=== 'if' || next_token
.id
=== 'switch' ?
4624 statement(true) : block(true);
4625 if (this['else'].disrupt
&& this.block
.disrupt
) {
4626 this.disrupt
= true;
4632 stmt('try', function () {
4634 // try.first The catch variable
4635 // try.second The catch clause
4636 // try.third The finally clause
4637 // try.block The try block
4639 var exception_variable
, old_scope
, paren
;
4640 if (option
.adsafe
) {
4641 warn('adsafe_a', this);
4644 this.arity
= 'statement';
4645 this.block
= block(false);
4646 if (next_token
.id
=== 'catch') {
4658 scope
= Object
.create(old_scope
);
4659 exception_variable
= next_token
.string
;
4660 this.first
= exception_variable
;
4661 if (!next_token
.identifier
) {
4662 warn('expected_identifier_a', next_token
);
4664 add_label(next_token
, 'exception');
4668 step_out(')', paren
);
4671 this.second
= block(false);
4674 if (next_token
.id
=== 'finally') {
4680 this.third
= block(false);
4681 } else if (!this.second
) {
4682 stop('expected_a_b', next_token
, 'catch', next_token
.string
);
4687 labeled_stmt('while', function () {
4689 var paren
= next_token
;
4690 funct
['(breakage)'] += 1;
4691 funct
['(loopage)'] += 1;
4697 this.arity
= 'statement';
4698 this.first
= expected_relation(expression(0));
4699 if (this.first
.id
!== 'true') {
4700 expected_condition(this.first
, bundle
.unexpected_a
);
4703 step_out(')', paren
);
4706 this.block
= block(true);
4707 if (this.block
.disrupt
) {
4708 warn('strange_loop', prev_token
);
4710 funct
['(breakage)'] -= 1;
4711 funct
['(loopage)'] -= 1;
4717 labeled_stmt('switch', function () {
4719 // switch.first the switch expression
4720 // switch.second the array of cases. A case is 'case' or 'default' token:
4721 // case.first the array of case expressions
4722 // case.second the array of statements
4723 // If all of the arrays of statements are disrupt, then the switch is disrupt.
4727 the_case
= next_token
,
4730 function find_duplicate_case(value
) {
4731 if (are_similar(particular
, value
)) {
4732 warn('duplicate_a', value
);
4736 funct
['(breakage)'] += 1;
4742 this.arity
= 'statement';
4743 this.first
= expected_condition(expected_relation(expression(0)));
4745 step_out(')', the_case
);
4751 while (next_token
.id
=== 'case') {
4752 the_case
= next_token
;
4753 cases
.forEach(find_duplicate_case
);
4754 the_case
.first
= [];
4755 the_case
.arity
= 'case';
4761 particular
= expression(0);
4762 cases
.forEach(find_duplicate_case
);
4763 cases
.push(particular
);
4764 the_case
.first
.push(particular
);
4765 if (particular
.id
=== 'NaN') {
4766 warn('unexpected_a', particular
);
4771 if (next_token
.id
!== 'case') {
4780 the_case
.second
= statements();
4781 if (the_case
.second
&& the_case
.second
.length
> 0) {
4782 particular
= the_case
.second
[the_case
.second
.length
- 1];
4783 if (particular
.disrupt
) {
4784 if (particular
.id
=== 'break') {
4788 warn('missing_a_after_b', next_token
, 'break', 'case');
4793 this.second
.push(the_case
);
4795 if (this.second
.length
=== 0) {
4796 warn('missing_a', next_token
, 'case');
4798 if (next_token
.id
=== 'default') {
4800 the_case
= next_token
;
4801 the_case
.arity
= 'case';
4809 the_case
.second
= statements();
4810 if (the_case
.second
&& the_case
.second
.length
> 0) {
4811 particular
= the_case
.second
[the_case
.second
.length
- 1];
4812 if (unbroken
&& particular
.disrupt
&& particular
.id
!== 'break') {
4813 this.disrupt
= true;
4816 this.second
.push(the_case
);
4818 funct
['(breakage)'] -= 1;
4820 step_out('}', this);
4824 stmt('debugger', function () {
4825 if (!option
.debug
) {
4826 warn('unexpected_a', this);
4828 this.arity
= 'statement';
4832 labeled_stmt('do', function () {
4833 funct
['(breakage)'] += 1;
4834 funct
['(loopage)'] += 1;
4836 this.arity
= 'statement';
4837 this.block
= block(true);
4838 if (this.block
.disrupt
) {
4839 warn('strange_loop', prev_token
);
4844 var paren
= next_token
;
4851 this.first
= expected_condition(expected_relation(expression(0)), bundle
.unexpected_a
);
4853 step_out(')', paren
);
4855 funct
['(breakage)'] -= 1;
4856 funct
['(loopage)'] -= 1;
4860 labeled_stmt('for', function () {
4862 var blok
, filter
, ok
= false, paren
= next_token
, the_in
, value
;
4863 this.arity
= 'statement';
4864 funct
['(breakage)'] += 1;
4865 funct
['(loopage)'] += 1;
4869 spaces(this, paren
);
4871 if (next_token
.id
=== 'var') {
4875 if (peek(0).id
=== 'in') {
4877 switch (funct
[value
.string
]) {
4879 funct
[value
.string
] = 'var';
4885 warn('bad_in_a', value
);
4887 conform_type('string', value
);
4889 the_in
= next_token
;
4891 the_in
.first
= value
;
4892 the_in
.second
= expression(20);
4893 conform_type('object', the_in
.second
);
4894 step_out(')', paren
);
4896 this.first
= the_in
;
4898 if (!option
.forin
) {
4899 if (blok
.length
=== 1 && typeof blok
[0] === 'object' &&
4900 blok
[0].string
=== 'if' && !blok
[0]['else']) {
4901 filter
= blok
[0].first
;
4902 while (filter
.id
=== '&&') {
4903 filter
= filter
.first
;
4905 switch (filter
.id
) {
4908 ok
= filter
.first
.id
=== '[' ? (
4909 filter
.first
.first
.string
=== the_in
.second
.string
&&
4910 filter
.first
.second
.string
=== the_in
.first
.string
4912 filter
.first
.id
=== 'typeof' &&
4913 filter
.first
.first
.id
=== '[' &&
4914 filter
.first
.first
.first
.string
=== the_in
.second
.string
&&
4915 filter
.first
.first
.second
.string
=== the_in
.first
.string
4919 ok
= filter
.first
.id
=== '.' && ((
4920 filter
.first
.first
.string
=== the_in
.second
.string
&&
4921 filter
.first
.second
.string
=== 'hasOwnProperty' &&
4922 filter
.second
[0].string
=== the_in
.first
.string
4924 filter
.first
.first
.string
=== 'ADSAFE' &&
4925 filter
.first
.second
.string
=== 'has' &&
4926 filter
.second
[0].string
=== the_in
.second
.string
&&
4927 filter
.second
[1].string
=== the_in
.first
.string
4929 filter
.first
.first
.id
=== '.' &&
4930 filter
.first
.first
.first
.id
=== '.' &&
4931 filter
.first
.first
.first
.first
.string
=== 'Object' &&
4932 filter
.first
.first
.first
.second
.string
=== 'prototype' &&
4933 filter
.first
.first
.second
.string
=== 'hasOwnProperty' &&
4934 filter
.first
.second
.string
=== 'call' &&
4935 filter
.second
[0].string
=== the_in
.second
.string
&&
4936 filter
.second
[1].string
=== the_in
.first
.string
4942 warn('for_if', this);
4946 if (next_token
.id
!== ';') {
4950 this.first
.push(expression(0, 'for'));
4951 if (next_token
.id
!== ',') {
4958 if (next_token
.id
!== ';') {
4960 this.second
= expected_relation(expression(0));
4961 if (this.second
.id
!== 'true') {
4962 expected_condition(this.second
, bundle
.unexpected_a
);
4966 if (next_token
.id
=== ';') {
4967 stop('expected_a_b', next_token
, ')', ';');
4969 if (next_token
.id
!== ')') {
4973 this.third
.push(expression(0, 'for'));
4974 if (next_token
.id
!== ',') {
4981 step_out(')', paren
);
4987 warn('strange_loop', prev_token
);
4990 funct
['(breakage)'] -= 1;
4991 funct
['(loopage)'] -= 1;
4995 disrupt_stmt('break', function () {
4996 var label
= next_token
.string
;
4997 this.arity
= 'statement';
4998 if (funct
['(breakage)'] === 0) {
4999 warn('unexpected_a', this);
5001 if (next_token
.identifier
&& token
.line
=== next_token
.line
) {
5003 if (funct
[label
] !== 'label') {
5004 warn('not_a_label', next_token
);
5005 } else if (scope
[label
].funct
!== funct
) {
5006 warn('not_a_scope', next_token
);
5008 this.first
= next_token
;
5014 disrupt_stmt('continue', function () {
5015 if (!option
['continue']) {
5016 warn('unexpected_a', this);
5018 var label
= next_token
.string
;
5019 this.arity
= 'statement';
5020 if (funct
['(breakage)'] === 0) {
5021 warn('unexpected_a', this);
5023 if (next_token
.identifier
&& token
.line
=== next_token
.line
) {
5025 if (funct
[label
] !== 'label') {
5026 warn('not_a_label', next_token
);
5027 } else if (scope
[label
].funct
!== funct
) {
5028 warn('not_a_scope', next_token
);
5030 this.first
= next_token
;
5036 disrupt_stmt('return', function () {
5037 if (funct
=== global_funct
) {
5038 warn('unexpected_a', this);
5040 this.arity
= 'statement';
5041 if (next_token
.id
!== ';' && next_token
.line
=== token
.line
) {
5043 if (next_token
.id
=== '/' || next_token
.id
=== '(regexp)') {
5044 warn('wrap_regexp');
5046 this.first
= expression(20);
5047 funct
['(return_type)'] = conform_type(funct
['(return_type)'], this.first
);
5052 disrupt_stmt('throw', function () {
5053 this.arity
= 'statement';
5055 this.first
= expression(20);
5060 // Superfluous reserved words
5070 // Harmony reserved words
5074 reserve('implements');
5075 reserve('interface');
5078 reserve('protected');
5085 function json_value() {
5087 function json_object() {
5088 var brace
= next_token
, object
= {};
5090 if (next_token
.id
!== '}') {
5091 while (next_token
.id
!== '(end)') {
5092 while (next_token
.id
=== ',') {
5093 warn('unexpected_a', next_token
);
5096 if (next_token
.id
!== '(string)') {
5097 warn('expected_string_a');
5099 if (object
[next_token
.string
] === true) {
5100 warn('duplicate_a');
5101 } else if (next_token
.string
=== '__proto__') {
5104 object
[next_token
.string
] = true;
5109 if (next_token
.id
!== ',') {
5113 if (next_token
.id
=== '}') {
5114 warn('unexpected_a', token
);
5119 advance('}', brace
);
5122 function json_array() {
5123 var bracket
= next_token
;
5125 if (next_token
.id
!== ']') {
5126 while (next_token
.id
!== '(end)') {
5127 while (next_token
.id
=== ',') {
5128 warn('unexpected_a', next_token
);
5132 if (next_token
.id
!== ',') {
5136 if (next_token
.id
=== ']') {
5137 warn('unexpected_a', token
);
5142 advance(']', bracket
);
5145 switch (next_token
.id
) {
5162 advance('(number)');
5165 stop('unexpected_a');
5172 function css_name() {
5173 if (next_token
.identifier
) {
5180 function css_number() {
5181 if (next_token
.id
=== '-') {
5185 if (next_token
.id
=== '(number)') {
5186 advance('(number)');
5192 function css_string() {
5193 if (next_token
.id
=== '(string)') {
5199 function css_color() {
5200 var i
, number
, paren
, value
;
5201 if (next_token
.identifier
) {
5202 value
= next_token
.string
;
5203 if (value
=== 'rgb' || value
=== 'rgba') {
5207 for (i
= 0; i
< 3; i
+= 1) {
5211 number
= next_token
.number
;
5212 if (next_token
.id
!== '(string)' || number
< 0) {
5213 warn('expected_positive_a', next_token
);
5217 if (next_token
.id
=== '%') {
5220 warn('expected_percent_a', token
, number
);
5224 warn('expected_small_a', token
, number
);
5229 if (value
=== 'rgba') {
5231 number
= next_token
.number
;
5232 if (next_token
.id
!== '(string)' || number
< 0 || number
> 1) {
5233 warn('expected_fraction_a', next_token
);
5236 if (next_token
.id
=== '%') {
5237 warn('unexpected_a');
5241 advance(')', paren
);
5243 } else if (css_colorData
[next_token
.string
] === true) {
5247 } else if (next_token
.id
=== '(color)') {
5255 function css_length() {
5256 if (next_token
.id
=== '-') {
5260 if (next_token
.id
=== '(number)') {
5262 if (next_token
.id
!== '(string)' &&
5263 css_lengthData
[next_token
.string
] === true) {
5266 } else if (+token
.number
!== 0) {
5267 warn('expected_linear_a');
5275 function css_line_height() {
5276 if (next_token
.id
=== '-') {
5280 if (next_token
.id
=== '(number)') {
5282 if (next_token
.id
!== '(string)' &&
5283 css_lengthData
[next_token
.string
] === true) {
5293 function css_width() {
5294 if (next_token
.identifier
) {
5295 switch (next_token
.string
) {
5303 return css_length();
5308 function css_margin() {
5309 if (next_token
.identifier
) {
5310 if (next_token
.string
=== 'auto') {
5315 return css_length();
5319 function css_attr() {
5320 if (next_token
.identifier
&& next_token
.string
=== 'attr') {
5323 if (!next_token
.identifier
) {
5324 warn('expected_name_a');
5334 function css_comma_list() {
5335 while (next_token
.id
!== ';') {
5336 if (!css_name() && !css_string()) {
5337 warn('expected_name_a');
5339 if (next_token
.id
!== ',') {
5347 function css_counter() {
5348 if (next_token
.identifier
&& next_token
.string
=== 'counter') {
5352 if (next_token
.id
=== ',') {
5354 if (next_token
.id
!== '(string)') {
5355 warn('expected_string_a');
5362 if (next_token
.identifier
&& next_token
.string
=== 'counters') {
5365 if (!next_token
.identifier
) {
5366 warn('expected_name_a');
5369 if (next_token
.id
=== ',') {
5371 if (next_token
.id
!== '(string)') {
5372 warn('expected_string_a');
5376 if (next_token
.id
=== ',') {
5378 if (next_token
.id
!== '(string)') {
5379 warn('expected_string_a');
5390 function css_shape() {
5392 if (next_token
.identifier
&& next_token
.string
=== 'rect') {
5395 for (i
= 0; i
< 4; i
+= 1) {
5396 if (!css_length()) {
5397 warn('expected_number_a');
5408 function css_url() {
5410 if (next_token
.identifier
&& next_token
.string
=== 'url') {
5411 next_token
= lex
.range('(', ')');
5412 url
= next_token
.string
;
5414 if (c
=== '"' || c
=== '\'') {
5415 if (url
.slice(-1) !== c
) {
5418 url
= url
.slice(1, -1);
5419 if (url
.indexOf(c
) >= 0) {
5425 warn('missing_url');
5427 if (option
.safe
&& ux
.test(url
)) {
5428 stop('adsafe_a', next_token
, url
);
5438 css_any
= [css_url
, function () {
5440 if (next_token
.identifier
) {
5441 switch (next_token
.string
.toLowerCase()) {
5446 warn('unexpected_a');
5453 if (next_token
.id
=== ';' || next_token
.id
=== '!' ||
5454 next_token
.id
=== '(end)' || next_token
.id
=== '}') {
5463 css_border_style
= [
5464 'none', 'dashed', 'dotted', 'double', 'groove',
5465 'hidden', 'inset', 'outset', 'ridge', 'solid'
5469 'auto', 'always', 'avoid', 'left', 'right'
5486 'auto', 'hidden', 'scroll', 'visible'
5489 css_attribute_data
= {
5491 true, 'background-attachment', 'background-color',
5492 'background-image', 'background-position', 'background-repeat'
5494 'background-attachment': ['scroll', 'fixed'],
5495 'background-color': ['transparent', css_color
],
5496 'background-image': ['none', css_url
],
5497 'background-position': [
5498 2, [css_length
, 'top', 'bottom', 'left', 'right', 'center']
5500 'background-repeat': [
5501 'repeat', 'repeat-x', 'repeat-y', 'no-repeat'
5503 'border': [true, 'border-color', 'border-style', 'border-width'],
5505 true, 'border-bottom-color', 'border-bottom-style',
5506 'border-bottom-width'
5508 'border-bottom-color': css_color
,
5509 'border-bottom-style': css_border_style
,
5510 'border-bottom-width': css_width
,
5511 'border-collapse': ['collapse', 'separate'],
5512 'border-color': ['transparent', 4, css_color
],
5514 true, 'border-left-color', 'border-left-style', 'border-left-width'
5516 'border-left-color': css_color
,
5517 'border-left-style': css_border_style
,
5518 'border-left-width': css_width
,
5520 true, 'border-right-color', 'border-right-style',
5521 'border-right-width'
5523 'border-right-color': css_color
,
5524 'border-right-style': css_border_style
,
5525 'border-right-width': css_width
,
5526 'border-spacing': [2, css_length
],
5527 'border-style': [4, css_border_style
],
5529 true, 'border-top-color', 'border-top-style', 'border-top-width'
5531 'border-top-color': css_color
,
5532 'border-top-style': css_border_style
,
5533 'border-top-width': css_width
,
5534 'border-width': [4, css_width
],
5535 bottom
: [css_length
, 'auto'],
5536 'caption-side' : ['bottom', 'left', 'right', 'top'],
5537 clear
: ['both', 'left', 'none', 'right'],
5538 clip
: [css_shape
, 'auto'],
5541 'open-quote', 'close-quote', 'no-open-quote', 'no-close-quote',
5542 css_string
, css_url
, css_counter
, css_attr
5544 'counter-increment': [
5551 css_url
, 'auto', 'crosshair', 'default', 'e-resize', 'help', 'move',
5552 'n-resize', 'ne-resize', 'nw-resize', 'pointer', 's-resize',
5553 'se-resize', 'sw-resize', 'w-resize', 'text', 'wait'
5555 direction
: ['ltr', 'rtl'],
5557 'block', 'compact', 'inline', 'inline-block', 'inline-table',
5558 'list-item', 'marker', 'none', 'run-in', 'table', 'table-caption',
5559 'table-cell', 'table-column', 'table-column-group',
5560 'table-footer-group', 'table-header-group', 'table-row',
5563 'empty-cells': ['show', 'hide'],
5564 'float': ['left', 'none', 'right'],
5566 'caption', 'icon', 'menu', 'message-box', 'small-caption',
5567 'status-bar', true, 'font-size', 'font-style', 'font-weight',
5570 'font-family': css_comma_list
,
5572 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large',
5573 'xx-large', 'larger', 'smaller', css_length
5575 'font-size-adjust': ['none', css_number
],
5577 'normal', 'wider', 'narrower', 'ultra-condensed',
5578 'extra-condensed', 'condensed', 'semi-condensed',
5579 'semi-expanded', 'expanded', 'extra-expanded'
5582 'normal', 'italic', 'oblique'
5585 'normal', 'small-caps'
5588 'normal', 'bold', 'bolder', 'lighter', css_number
5590 height
: [css_length
, 'auto'],
5591 left
: [css_length
, 'auto'],
5592 'letter-spacing': ['normal', css_length
],
5593 'line-height': ['normal', css_line_height
],
5595 true, 'list-style-image', 'list-style-position', 'list-style-type'
5597 'list-style-image': ['none', css_url
],
5598 'list-style-position': ['inside', 'outside'],
5599 'list-style-type': [
5600 'circle', 'disc', 'square', 'decimal', 'decimal-leading-zero',
5601 'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha',
5602 'lower-latin', 'upper-alpha', 'upper-latin', 'hebrew', 'katakana',
5603 'hiragana-iroha', 'katakana-oroha', 'none'
5605 margin
: [4, css_margin
],
5606 'margin-bottom': css_margin
,
5607 'margin-left': css_margin
,
5608 'margin-right': css_margin
,
5609 'margin-top': css_margin
,
5610 'marker-offset': [css_length
, 'auto'],
5611 'max-height': [css_length
, 'none'],
5612 'max-width': [css_length
, 'none'],
5613 'min-height': css_length
,
5614 'min-width': css_length
,
5615 opacity
: css_number
,
5616 outline
: [true, 'outline-color', 'outline-style', 'outline-width'],
5617 'outline-color': ['invert', css_color
],
5619 'dashed', 'dotted', 'double', 'groove', 'inset', 'none',
5620 'outset', 'ridge', 'solid'
5622 'outline-width': css_width
,
5623 overflow
: css_overflow
,
5624 'overflow-x': css_overflow
,
5625 'overflow-y': css_overflow
,
5626 padding
: [4, css_length
],
5627 'padding-bottom': css_length
,
5628 'padding-left': css_length
,
5629 'padding-right': css_length
,
5630 'padding-top': css_length
,
5631 'page-break-after': css_break
,
5632 'page-break-before': css_break
,
5633 position
: ['absolute', 'fixed', 'relative', 'static'],
5634 quotes
: [8, css_string
],
5635 right
: [css_length
, 'auto'],
5636 'table-layout': ['auto', 'fixed'],
5637 'text-align': ['center', 'justify', 'left', 'right'],
5638 'text-decoration': [
5639 'none', 'underline', 'overline', 'line-through', 'blink'
5641 'text-indent': css_length
,
5642 'text-shadow': ['none', 4, [css_color
, css_length
]],
5643 'text-transform': ['capitalize', 'uppercase', 'lowercase', 'none'],
5644 top
: [css_length
, 'auto'],
5645 'unicode-bidi': ['normal', 'embed', 'bidi-override'],
5647 'baseline', 'bottom', 'sub', 'super', 'top', 'text-top', 'middle',
5648 'text-bottom', css_length
5650 visibility
: ['visible', 'hidden', 'collapse'],
5652 'normal', 'nowrap', 'pre', 'pre-line', 'pre-wrap', 'inherit'
5654 width
: [css_length
, 'auto'],
5655 'word-spacing': ['normal', css_length
],
5656 'word-wrap': ['break-word', 'normal'],
5657 'z-index': ['auto', css_number
]
5660 function style_attribute() {
5662 while (next_token
.id
=== '*' || next_token
.id
=== '#' ||
5663 next_token
.string
=== '_') {
5665 warn('unexpected_a');
5669 if (next_token
.id
=== '-') {
5671 warn('unexpected_a');
5674 if (!next_token
.identifier
) {
5675 warn('expected_nonstandard_style_attribute');
5680 if (!next_token
.identifier
) {
5681 warn('expected_style_attribute');
5683 if (Object
.prototype.hasOwnProperty
.call(css_attribute_data
, next_token
.string
)) {
5684 v
= css_attribute_data
[next_token
.string
];
5688 warn('unrecognized_style_attribute_a');
5698 function style_value(v
) {
5700 /*jslint confusion: true */
5713 if (next_token
.identifier
&& next_token
.string
=== v
) {
5720 if (i
>= v
.length
) {
5725 if (typeof vi
=== 'boolean') {
5727 } else if (typeof vi
=== 'number') {
5736 if (style_value(vi
)) {
5751 for (i
= start
; i
< v
.length
; i
+= 1) {
5753 if (style_value(css_attribute_data
[v
[i
]])) {
5767 function style_child() {
5768 if (next_token
.id
=== '(number)') {
5770 if (next_token
.string
=== 'n' && next_token
.identifier
) {
5773 if (next_token
.id
=== '+') {
5777 advance('(number)');
5782 if (next_token
.identifier
&&
5783 (next_token
.string
=== 'odd' || next_token
.string
=== 'even')) {
5788 warn('unexpected_a');
5791 function substyle() {
5794 if (next_token
.id
=== '}' || next_token
.id
=== '(end)' ||
5795 (xquote
&& next_token
.id
=== xquote
)) {
5798 while (next_token
.id
=== ';') {
5799 warn('unexpected_a');
5802 v
= style_attribute();
5804 if (next_token
.identifier
&& next_token
.string
=== 'inherit') {
5807 if (!style_value(v
)) {
5808 warn('unexpected_a');
5812 if (next_token
.id
=== '!') {
5815 if (next_token
.identifier
&& next_token
.string
=== 'important') {
5818 warn('expected_a_b',
5819 next_token
, 'important', next_token
.string
);
5822 if (next_token
.id
=== '}' || next_token
.id
=== xquote
) {
5823 warn('expected_a_b', next_token
, ';', next_token
.string
);
5830 function style_selector() {
5831 if (next_token
.identifier
) {
5832 if (!Object
.prototype.hasOwnProperty
.call(html_tag
, option
.cap
?
5833 next_token
.string
.toLowerCase() : next_token
.string
)) {
5834 warn('expected_tagname_a');
5838 switch (next_token
.id
) {
5846 switch (next_token
.string
) {
5855 case 'first-letter':
5857 case 'first-of-type':
5861 case 'last-of-type':
5863 case 'only-of-type':
5872 if (!next_token
.identifier
) {
5873 warn('expected_lang_a');
5878 case 'nth-last-child':
5879 case 'nth-last-of-type':
5889 if (next_token
.id
=== ':' && peek(0).string
=== 'not') {
5896 warn('expected_pseudo_a');
5901 if (!next_token
.identifier
) {
5902 warn('expected_id_a');
5911 if (!next_token
.identifier
) {
5912 warn('expected_class_a');
5918 if (!next_token
.identifier
) {
5919 warn('expected_attribute_a');
5922 if (next_token
.id
=== '=' || next_token
.string
=== '~=' ||
5923 next_token
.string
=== '$=' ||
5924 next_token
.string
=== '|=' ||
5925 next_token
.id
=== '*=' ||
5926 next_token
.id
=== '^=') {
5928 if (next_token
.id
!== '(string)') {
5929 warn('expected_string_a');
5936 stop('expected_selector_a');
5941 function style_pattern() {
5942 if (next_token
.id
=== '{') {
5943 warn('expected_style_pattern');
5947 if (next_token
.id
=== '</' || next_token
.id
=== '{' ||
5948 next_token
.id
=== '(end)') {
5951 if (next_token
.id
=== ',') {
5957 function style_list() {
5958 while (next_token
.id
!== '</' && next_token
.id
!== '(end)') {
5960 xmode
= 'styleproperty';
5961 if (next_token
.id
=== ';') {
5974 while (next_token
.id
=== '@') {
5977 if (next_token
.identifier
) {
5978 switch (next_token
.string
) {
5982 warn('expected_a_b',
5983 next_token
, 'url', next_token
.string
);
5991 if (!next_token
.identifier
|| css_media
[next_token
.string
] === true) {
5992 stop('expected_media_a');
5995 if (next_token
.id
!== ',') {
6005 warn('expected_at_a');
6008 warn('expected_at_a');
6017 function do_begin(n
) {
6018 if (n
!== 'html' && !option
.fragment
) {
6019 if (n
=== 'div' && option
.adsafe
) {
6020 stop('adsafe_fragment');
6022 stop('expected_a_b', token
, 'html', n
);
6025 if (option
.adsafe
) {
6027 stop('adsafe_html', token
);
6029 if (option
.fragment
) {
6031 stop('adsafe_div', token
);
6034 stop('adsafe_fragment', token
);
6037 option
.browser
= true;
6040 function do_attribute(a
, v
) {
6043 u
= typeof v
=== 'string' ? v
.toUpperCase() : '';
6044 if (ids
[u
] === true) {
6045 warn('duplicate_a', next_token
, v
);
6047 if (!/^[A-Za-z][A-Za-z0-9._:\-]*$/.test(v
)) {
6048 warn('bad_id_a', next_token
, v
);
6049 } else if (option
.adsafe
) {
6051 if (v
.slice(0, adsafe_id
.length
) !== adsafe_id
) {
6052 warn('adsafe_prefix_a', next_token
, adsafe_id
);
6053 } else if (!/^[A-Z]+_[A-Z]+$/.test(v
)) {
6054 warn('adsafe_bad_id');
6058 if (!/^[A-Z]+_$/.test(v
)) {
6059 warn('adsafe_bad_id');
6065 warn('unexpected_char_a_b', token
, v
.charAt(x
), a
);
6068 } else if (a
=== 'class' || a
=== 'type' || a
=== 'name') {
6071 warn('unexpected_char_a_b', token
, v
.charAt(x
), a
);
6074 } else if (a
=== 'href' || a
=== 'background' ||
6075 a
=== 'content' || a
=== 'data' ||
6076 a
.indexOf('src') >= 0 || a
.indexOf('url') >= 0) {
6077 if (option
.safe
&& ux
.test(v
)) {
6078 stop('bad_url', next_token
, v
);
6081 } else if (a
=== 'for') {
6082 if (option
.adsafe
) {
6084 if (v
.slice(0, adsafe_id
.length
) !== adsafe_id
) {
6085 warn('adsafe_prefix_a', next_token
, adsafe_id
);
6086 } else if (!/^[A-Z]+_[A-Z]+$/.test(v
)) {
6087 warn('adsafe_bad_id');
6090 warn('adsafe_bad_id');
6093 } else if (a
=== 'name') {
6094 if (option
.adsafe
&& v
.indexOf('_') >= 0) {
6095 warn('adsafe_name_a', next_token
, v
);
6100 function do_tag(name
, attribute
) {
6101 var i
, tag
= html_tag
[name
], script
, x
;
6105 bundle
.unrecognized_tag_a
,
6107 name
=== name
.toLowerCase() ? name
: name
+ ' (capitalization error)'
6110 if (stack
.length
> 0) {
6111 if (name
=== 'html') {
6112 stop('unexpected_a', token
, name
);
6116 if (x
.indexOf(' ' + stack
[stack
.length
- 1].name
+ ' ') < 0) {
6117 stop('tag_a_in_b', token
, name
, x
);
6119 } else if (!option
.adsafe
&& !option
.fragment
) {
6123 stop('tag_a_in_b', token
, name
, 'body');
6126 } while (stack
[i
].name
!== 'body');
6131 if (option
.adsafe
&& stack
.length
=== 1 && !adsafe_id
) {
6132 warn('adsafe_missing_id');
6138 if (attribute
.lang
) {
6139 warn('lang', token
);
6141 if (option
.adsafe
&& stack
.length
!== 1) {
6142 warn('adsafe_placement', token
);
6144 if (attribute
.src
) {
6145 if (option
.adsafe
&& (!adsafe_may
|| !approved
[attribute
.src
])) {
6146 warn('adsafe_source', token
);
6148 if (attribute
.type
) {
6149 warn('type', token
);
6152 step_in(next_token
.from);
6156 script
= statements();
6158 // JSLint is also the static analyzer for ADsafe. See www.ADsafe.org.
6160 if (option
.adsafe
) {
6162 stop('adsafe_script', token
);
6164 if (script
.length
!== 1 ||
6165 aint(script
[0], 'id', '(') ||
6166 aint(script
[0].first
, 'id', '.') ||
6167 aint(script
[0].first
.first
, 'string', 'ADSAFE') ||
6168 aint(script
[0].second
[0], 'string', adsafe_id
)) {
6169 stop('adsafe_id_go');
6171 switch (script
[0].first
.second
.string
) {
6173 if (adsafe_may
|| adsafe_went
||
6174 script
[0].second
.length
!== 1) {
6175 stop('adsafe_id', next_token
);
6183 if (script
[0].second
.length
!== 2 ||
6184 aint(script
[0].second
[1], 'id', 'function') ||
6185 !script
[0].second
[1].first
||
6186 script
[0].second
[1].first
.length
!== 2 ||
6187 aint(script
[0].second
[1].first
[0], 'string', 'dom') ||
6188 aint(script
[0].second
[1].first
[1], 'string', 'lib')) {
6189 stop('adsafe_go', next_token
);
6194 stop('adsafe_id_go');
6201 if (!next_token
.identifier
&& next_token
.string
!== 'script') {
6202 warn('expected_a_b', next_token
, 'script', next_token
.string
);
6213 if (!next_token
.identifier
&& next_token
.string
!== 'style') {
6214 warn('expected_a_b', next_token
, 'style', next_token
.string
);
6220 switch (attribute
.type
) {
6232 if (option
.adsafe
&& attribute
.autocomplete
!== 'off') {
6233 warn('adsafe_autocomplete');
6251 if (option
.adsafe
) {
6252 warn('adsafe_tag', next_token
, name
);
6259 function closetag(name
) {
6260 return '</' + name
+ '>';
6265 /*jslint confusion: true */
6267 var attribute
, attributes
, is_empty
, name
, old_white
= option
.white
,
6268 quote
, tag_name
, tag
, wmode
;
6273 switch (next_token
.string
) {
6278 tag_name
= next_token
;
6279 if (!tag_name
.identifier
) {
6280 warn('bad_name_a', tag_name
);
6282 name
= tag_name
.string
;
6284 name
= name
.toLowerCase();
6286 tag_name
.name
= name
;
6292 tag
= html_tag
[name
];
6293 if (typeof tag
!== 'object') {
6294 stop('unrecognized_tag_a', tag_name
, name
);
6296 is_empty
= tag
.empty
;
6297 tag_name
.type
= name
;
6299 if (next_token
.id
=== '/') {
6301 if (next_token
.id
!== '>') {
6302 warn('expected_a_b', next_token
, '>', next_token
.string
);
6306 if (next_token
.id
&& next_token
.id
.charAt(0) === '>') {
6309 if (!next_token
.identifier
) {
6310 if (next_token
.id
=== '(end)' || next_token
.id
=== '(error)') {
6311 warn('expected_a_b', next_token
, '>', next_token
.string
);
6315 option
.white
= false;
6317 attribute
= next_token
.string
;
6318 option
.white
= old_white
;
6320 if (!option
.cap
&& attribute
!== attribute
.toLowerCase()) {
6321 warn('attribute_case_a', token
);
6323 attribute
= attribute
.toLowerCase();
6325 if (Object
.prototype.hasOwnProperty
.call(attributes
, attribute
)) {
6326 warn('duplicate_a', token
, attribute
);
6328 if (attribute
.slice(0, 2) === 'on') {
6330 warn('html_handlers');
6332 xmode
= 'scriptstring';
6334 quote
= next_token
.id
;
6335 if (quote
!== '"' && quote
!== '\'') {
6336 stop('expected_a_b', next_token
, '"', next_token
.string
);
6339 wmode
= option
.white
;
6340 option
.white
= true;
6344 option
.white
= wmode
;
6345 if (next_token
.id
!== quote
) {
6346 stop('expected_a_b', next_token
, quote
, next_token
.string
);
6352 } else if (attribute
=== 'style') {
6353 xmode
= 'scriptstring';
6355 quote
= next_token
.id
;
6356 if (quote
!== '"' && quote
!== '\'') {
6357 stop('expected_a_b', next_token
, '"', next_token
.string
);
6359 xmode
= 'styleproperty';
6368 if (next_token
.id
=== '=') {
6370 tag
= next_token
.string
;
6371 if (!next_token
.identifier
&&
6372 next_token
.id
!== '"' &&
6373 next_token
.id
!== '\'' &&
6374 next_token
.id
!== '(string)' &&
6375 next_token
.id
!== '(string)' &&
6376 next_token
.id
!== '(color)') {
6377 warn('expected_attribute_value_a', token
, attribute
);
6384 attributes
[attribute
] = tag
;
6385 do_attribute(attribute
, tag
);
6387 do_tag(name
, attributes
);
6389 stack
.push(tag_name
);
6397 if (!next_token
.identifier
) {
6400 name
= next_token
.string
;
6402 name
= name
.toLowerCase();
6406 stop('unexpected_a', next_token
, closetag(name
));
6408 tag_name
= stack
.pop();
6410 stop('unexpected_a', next_token
, closetag(name
));
6412 if (tag_name
.name
!== name
) {
6413 stop('expected_a_b',
6414 next_token
, closetag(tag_name
.name
), closetag(name
));
6416 if (next_token
.id
!== '>') {
6417 stop('expected_a_b', next_token
, '>', next_token
.string
);
6429 if (next_token
.id
=== '>' || next_token
.id
=== '(end)') {
6432 if (next_token
.string
.indexOf('--') >= 0) {
6433 stop('unexpected_a', next_token
, '--');
6435 if (next_token
.string
.indexOf('<') >= 0) {
6436 stop('unexpected_a', next_token
, '<');
6438 if (next_token
.string
.indexOf('>') >= 0) {
6439 stop('unexpected_a', next_token
, '>');
6448 if (next_token
.id
=== '(end)') {
6449 stop('missing_a', next_token
,
6450 '</' + stack
[stack
.length
- 1].string
+ '>');
6455 if (stack
&& stack
.length
=== 0 && (option
.adsafe
||
6456 !option
.fragment
|| next_token
.id
=== '(end)')) {
6460 if (next_token
.id
!== '(end)') {
6461 stop('unexpected_a');
6466 // The actual JSLINT function itself.
6468 itself
= function JSLint(the_source
, the_option
) {
6470 var i
, predef
, tree
;
6471 JSLINT
.comments
= [];
6474 begin
= older_token
= prev_token
= token
= next_token
=
6475 Object
.create(syntax
['(begin)']);
6477 add_to_predefined(standard
);
6478 property_type
= Object
.create(standard_property_type
);
6480 option
= Object
.create(the_option
);
6481 predef
= option
.predef
;
6483 if (Array
.isArray(predef
)) {
6484 for (i
= 0; i
< predef
.length
; i
+= 1) {
6485 predefined
[predef
[i
]] = true;
6487 } else if (typeof predef
=== 'object') {
6488 add_to_predefined(predef
);
6495 option
.indent
= +option
.indent
|| 0;
6496 option
.maxerr
= option
.maxerr
|| 50;
6498 adsafe_may
= adsafe_top
= adsafe_went
= false;
6500 if (option
.approved
) {
6501 for (i
= 0; i
< option
.approved
.length
; i
+= 1) {
6502 approved
[option
.approved
[i
]] = option
.approved
[i
];
6505 approved
.test
= 'test';
6508 for (i
= 0; i
< option
.indent
; i
+= 1) {
6511 global_scope
= scope
= {};
6512 global_funct
= funct
= {
6517 functions
= [funct
];
6519 comments_off
= false;
6530 strict_mode
= false;
6535 lex
.init(the_source
);
6541 if (next_token
.id
=== '(number)') {
6542 stop('unexpected_a');
6543 } else if (next_token
.string
.charAt(0) === '<') {
6545 if (option
.adsafe
&& !adsafe_went
) {
6546 warn('adsafe_go', this);
6549 switch (next_token
.id
) {
6562 if (token
.id
!== '@' || !next_token
.identifier
||
6563 next_token
.string
!== 'charset' || token
.line
!== 1 ||
6568 if (next_token
.id
!== '(string)' &&
6569 next_token
.string
!== 'UTF-8') {
6578 if (option
.adsafe
&& option
.fragment
) {
6579 stop('expected_a_b',
6580 next_token
, '<div>', next_token
.string
);
6583 // If the first token is predef semicolon, ignore it. This is sometimes used when
6584 // files are intended to be appended to files that may be sloppy. predef sloppy
6585 // file may be depending on semicolon insertion on its last line.
6588 if (next_token
.id
=== ';' && !node_js
) {
6592 tree
= statements();
6594 JSLINT
.tree
= begin
;
6595 if (option
.adsafe
&& (tree
.length
!== 1 ||
6596 aint(tree
[0], 'id', '(') ||
6597 aint(tree
[0].first
, 'id', '.') ||
6598 aint(tree
[0].first
.first
, 'string', 'ADSAFE') ||
6599 aint(tree
[0].first
.second
, 'string', 'lib') ||
6600 tree
[0].second
.length
!== 2 ||
6601 tree
[0].second
[0].id
!== '(string)' ||
6602 aint(tree
[0].second
[1], 'id', 'function'))) {
6606 warn('weird_program', prev_token
);
6614 JSLINT
.errors
.push({
6616 line
: e
.line
|| next_token
.line
,
6617 character
: e
.character
|| next_token
.from
6621 return JSLINT
.errors
.length
=== 0;
6627 itself
.data = function () {
6628 var data
= {functions
: []},
6639 if (itself
.errors
.length
) {
6640 data
.errors
= itself
.errors
;
6647 if (urls
.length
> 0) {
6651 globals
= Object
.keys(global_scope
).filter(function (value
) {
6652 return value
.charAt(0) !== '(' && typeof standard
[value
] !== 'boolean';
6654 if (globals
.length
> 0) {
6655 data
.globals
= globals
;
6658 for (i
= 1; i
< functions
.length
; i
+= 1) {
6659 the_function
= functions
[i
];
6661 for (j
= 0; j
< functionicity
.length
; j
+= 1) {
6662 function_data
[functionicity
[j
]] = [];
6664 for (name
in the_function
) {
6665 if (Object
.prototype.hasOwnProperty
.call(the_function
, name
)) {
6666 if (name
.charAt(0) !== '(') {
6667 kind
= the_function
[name
];
6668 if (kind
=== 'unction' || kind
=== 'unparam') {
6671 if (Array
.isArray(function_data
[kind
])) {
6672 function_data
[kind
].push(name
);
6673 if (kind
=== 'unused') {
6676 line
: the_function
['(line)'],
6677 'function': the_function
['(name)']
6679 } else if (kind
=== 'undef') {
6682 line
: the_function
['(line)'],
6683 'function': the_function
['(name)']
6690 for (j
= 0; j
< functionicity
.length
; j
+= 1) {
6691 if (function_data
[functionicity
[j
]].length
=== 0) {
6692 delete function_data
[functionicity
[j
]];
6695 function_data
.name
= the_function
['(name)'];
6696 function_data
.params
= the_function
['(params)'];
6697 function_data
.line
= the_function
['(line)'];
6698 function_data
['(complexity)'] = the_function
['(complexity)'];
6699 data
.functions
.push(function_data
);
6702 if (unused
.length
> 0) {
6703 data
.unused
= unused
;
6705 if (undef
.length
> 0) {
6706 data
['undefined'] = undef
;
6710 for (name
in member
) {
6711 if (typeof member
[name
] === 'number') {
6712 data
.member
= member
;
6721 itself
.report = function (errors_only
) {
6722 var data
= itself
.data(), err
, evidence
, i
, italics
, j
, key
, keys
, length
,
6723 mem
= '', name
, names
, output
= [], snippets
, the_function
, type
,
6726 function detail(h
, value
) {
6727 var comma_needed
, singularity
;
6728 if (Array
.isArray(value
)) {
6729 output
.push('<div><i>' + h
+ '</i> ');
6730 value
.sort().forEach(function (item
) {
6731 if (item
!== singularity
) {
6733 output
.push((comma_needed
? ', ' : '') + singularity
);
6734 comma_needed
= true;
6737 output
.push('</div>');
6739 output
.push('<div><i>' + h
+ '</i> ' + value
+ '</div>');
6743 if (data
.errors
|| data
.unused
|| data
['undefined']) {
6745 output
.push('<div id=errors><i>Error:</i>');
6747 for (i
= 0; i
< data
.errors
.length
; i
+= 1) {
6748 warning
= data
.errors
[i
];
6750 evidence
= warning
.evidence
|| '';
6751 output
.push('<p>Problem' + (isFinite(warning
.line
) ?
6752 ' at line ' + String(warning
.line
) + ' character ' +
6753 String(warning
.character
) : '') +
6754 ': ' + warning
.reason
.entityify() +
6755 '</p><p class=evidence>' +
6756 (evidence
&& (evidence
.length
> 80 ? evidence
.slice(0, 77) + '...' :
6757 evidence
).entityify()) + '</p>');
6762 if (data
['undefined']) {
6764 for (i
= 0; i
< data
['undefined'].length
; i
+= 1) {
6765 snippets
[i
] = '<code><u>' + data
['undefined'][i
].name
+ '</u></code> <i>' +
6766 String(data
['undefined'][i
].line
) + ' </i> <small>' +
6767 data
['undefined'][i
]['function'] + '</small>';
6769 output
.push('<p><i>Undefined variable:</i> ' + snippets
.join(', ') + '</p>');
6773 for (i
= 0; i
< data
.unused
.length
; i
+= 1) {
6774 snippets
[i
] = '<code><u>' + data
.unused
[i
].name
+ '</u></code> <i>' +
6775 String(data
.unused
[i
].line
) + ' </i> <small>' +
6776 data
.unused
[i
]['function'] + '</small>';
6778 output
.push('<p><i>Unused variable:</i> ' + snippets
.join(', ') + '</p>');
6781 output
.push('<p>JSON: bad.</p>');
6783 output
.push('</div>');
6788 output
.push('<br><div id=functions>');
6791 detail("URLs<br>", data
.urls
, '<br>');
6794 if (xmode
=== 'style') {
6795 output
.push('<p>CSS.</p>');
6796 } else if (data
.json
&& !err
) {
6797 output
.push('<p>JSON: good.</p>');
6798 } else if (data
.globals
) {
6799 output
.push('<div><i>Global</i> ' +
6800 data
.globals
.sort().join(', ') + '</div>');
6802 output
.push('<div><i>No new global variables introduced.</i></div>');
6805 for (i
= 0; i
< data
.functions
.length
; i
+= 1) {
6806 the_function
= data
.functions
[i
];
6808 if (the_function
.params
) {
6809 for (j
= 0; j
< the_function
.params
.length
; j
+= 1) {
6810 names
[j
] = the_function
.params
[j
].string
;
6813 output
.push('<br><div class=function><i>' +
6814 String(the_function
.line
) + '</i> ' +
6815 the_function
.name
.entityify() +
6816 '(' + names
.join(', ') + ')</div>');
6817 detail('<big><b>Undefined</b></big>', the_function
['undefined']);
6818 detail('<big><b>Unused</b></big>', the_function
.unused
);
6819 detail('Closure', the_function
.closure
);
6820 detail('Variable', the_function
['var']);
6821 detail('Exception', the_function
.exception
);
6822 detail('Outer', the_function
.outer
);
6823 detail('Global', the_function
.global
);
6824 detail('Label', the_function
.label
);
6825 detail('Complexity', the_function
['(complexity)']);
6829 keys
= Object
.keys(data
.member
);
6832 output
.push('<br><pre id=properties>/*properties<br>');
6836 if (option
.confusion
) {
6837 for (i
= 0; i
< keys
.length
; i
+= 1) {
6839 if (typeof standard_property_type
[key
] !== 'string') {
6840 name
= ix
.test(key
) ? key
:
6841 '\'' + key
.entityify().replace(nx
, sanitize
) + '\'';
6842 if (data
.member
[key
] === 1) {
6843 name
= '<i>' + name
+ '</i>';
6847 if (i
< keys
.length
- 1) {
6850 if (mem
.length
+ name
.length
- (italics
* 7) > 80) {
6851 output
.push(mem
+ '<br>');
6860 for (i
= 0; i
< keys
.length
; i
+= 1) {
6862 type
= property_type
[key
];
6863 if (typeof type
!== 'string') {
6866 if (standard_property_type
[key
] !== type
) {
6867 name
= ix
.test(key
) ? key
:
6868 '\'' + key
.entityify().replace(nx
, sanitize
) + '\'';
6869 length
+= name
.length
+ 2;
6870 if (data
.member
[key
] === 1) {
6871 name
= '<i>' + name
+ '</i>';
6876 name
+= ': ' + type
;
6878 if (i
< keys
.length
- 1) {
6881 if (mem
.length
+ name
.length
- (italics
* 7) > 80) {
6882 output
.push(mem
+ '<br>');
6891 output
.push(mem
+ '<br>*/</pre>');
6893 output
.push('</div>');
6896 return output
.join('');
6898 itself
.jslint
= itself
;
6900 itself
.edition
= '2011-07-04';