/[projects]/misc/horsensspejder-web/jquery/jquery-ui-1.10.3/external/jshint.js
ViewVC logotype

Contents of /misc/horsensspejder-web/jquery/jquery-ui-1.10.3/external/jshint.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2125 - (show annotations) (download) (as text)
Wed Mar 12 19:30:05 2014 UTC (10 years, 3 months ago) by torben
File MIME type: application/javascript
File size: 171200 byte(s)
initial import
1 /*!
2 * JSHint, by JSHint Community.
3 *
4 * This file (and this file only) is licensed under the same slightly modified
5 * MIT license that JSLint is. It stops evil-doers everywhere.
6 *
7 * JSHint is a derivative work of JSLint:
8 *
9 * Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining
12 * a copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom
16 * the Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * The Software shall be used for Good, not Evil.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 * DEALINGS IN THE SOFTWARE.
30 *
31 */
32
33 /*
34 JSHINT is a global function. It takes two parameters.
35
36 var myResult = JSHINT(source, option);
37
38 The first parameter is either a string or an array of strings. If it is a
39 string, it will be split on '\n' or '\r'. If it is an array of strings, it
40 is assumed that each string represents one line. The source can be a
41 JavaScript text or a JSON text.
42
43 The second parameter is an optional object of options which control the
44 operation of JSHINT. Most of the options are booleans: They are all
45 optional and have a default value of false. One of the options, predef,
46 can be an array of names, which will be used to declare global variables,
47 or an object whose keys are used as global names, with a boolean value
48 that determines if they are assignable.
49
50 If it checks out, JSHINT returns true. Otherwise, it returns false.
51
52 If false, you can inspect JSHINT.errors to find out the problems.
53 JSHINT.errors is an array of objects containing these members:
54
55 {
56 line : The line (relative to 1) at which the lint was found
57 character : The character (relative to 1) at which the lint was found
58 reason : The problem
59 evidence : The text line in which the problem occurred
60 raw : The raw message before the details were inserted
61 a : The first detail
62 b : The second detail
63 c : The third detail
64 d : The fourth detail
65 }
66
67 If a fatal error was found, a null will be the last element of the
68 JSHINT.errors array.
69
70 You can request a data structure which contains JSHint's results.
71
72 var myData = JSHINT.data();
73
74 It returns a structure with this form:
75
76 {
77 errors: [
78 {
79 line: NUMBER,
80 character: NUMBER,
81 reason: STRING,
82 evidence: STRING
83 }
84 ],
85 functions: [
86 name: STRING,
87 line: NUMBER,
88 character: NUMBER,
89 last: NUMBER,
90 lastcharacter: NUMBER,
91 param: [
92 STRING
93 ],
94 closure: [
95 STRING
96 ],
97 var: [
98 STRING
99 ],
100 exception: [
101 STRING
102 ],
103 outer: [
104 STRING
105 ],
106 unused: [
107 STRING
108 ],
109 global: [
110 STRING
111 ],
112 label: [
113 STRING
114 ]
115 ],
116 globals: [
117 STRING
118 ],
119 member: {
120 STRING: NUMBER
121 },
122 unused: [
123 {
124 name: STRING,
125 line: NUMBER
126 }
127 ],
128 implieds: [
129 {
130 name: STRING,
131 line: NUMBER
132 }
133 ],
134 urls: [
135 STRING
136 ],
137 json: BOOLEAN
138 }
139
140 Empty arrays will not be included.
141
142 */
143
144 /*jshint
145 evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
146 undef: true, maxlen: 100, indent: 4, quotmark: double, unused: true
147 */
148
149 /*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
150 "(breakage)", "(character)", "(context)", "(error)", "(explicitNewcap)", "(global)",
151 "(identifier)", "(last)", "(lastcharacter)", "(line)", "(loopage)", "(metrics)",
152 "(name)", "(onevar)", "(params)", "(scope)", "(statement)", "(verb)", "(tokens)", "(catch)",
153 "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
154 "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
155 __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio,
156 Autocompleter, Asset, Boolean, Builder, Buffer, Browser, Blob, COM, CScript, Canvas,
157 CustomAnimation, Class, Control, ComplexityCount, Chain, Color, Cookie, Core, DataView, Date,
158 Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMEvent, DOMReady, DOMParser,
159 Drag, E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
160 Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
161 FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey,
162 HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement,
163 HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement,
164 HTMLDivElement, HTMLDListElement, HTMLFieldSetElement,
165 HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement,
166 HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement,
167 HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement,
168 HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement,
169 HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement,
170 HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement,
171 HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement,
172 HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement,
173 HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement,
174 HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement,
175 HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement,
176 Iframe, IframeShim, Image, importScripts, Int16Array, Int32Array, Int8Array,
177 Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
178 MAX_VALUE, MIN_VALUE, Map, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort,
179 MoveAnimation, MooTools, MutationObserver, NaN, Native, NEGATIVE_INFINITY, Node, NodeFilter,
180 Number, Object, ObjectRange,
181 Option, Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype,
182 RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation, Set,
183 SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
184 ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
185 Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables,
186 SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
187 Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL,
188 VBArray, WeakMap, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer,
189 XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult,
190 "\\", a, abs, addEventListener, address, alert, apply, applicationCache, arguments, arity,
191 asi, atob, b, basic, basicToken, bitwise, blacklist, block, blur, boolOptions, boss,
192 browser, btoa, c, call, callee, caller, camelcase, cases, charAt, charCodeAt, character,
193 clearInterval, clearTimeout, close, closed, closure, comment, complexityCount, condition,
194 confirm, console, constructor, content, couch, create, css, curly, d, data, datalist, dd, debug,
195 decodeURI, decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
196 dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent, elem,
197 eqeq, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,
198 ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus, forEach,
199 forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,
200 g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict,
201 hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,
202 indent, indexOf, init, ins, internals, instanceOf, isAlpha, isApplicationRunning, isArray,
203 isDigit, isFinite, isNaN, iterator, java, join, jshint,
204 JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastcharacter, lastsemic, laxbreak,
205 laxcomma, latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
206 log, loopfunc, m, match, max, maxcomplexity, maxdepth, maxerr, maxlen, maxstatements, maxparams,
207 member, message, meta, module, moveBy, moveTo, mootools, multistr, name, navigator, new, newcap,
208 nestedBlockDepth, noarg, node, noempty, nomen, nonew, nonstandard, nud, onbeforeunload, onblur,
209 onerror, onevar, onecase, onfocus, onload, onresize, onunload, open, openDatabase, openURL,
210 opener, opera, options, outer, param, parent, parseFloat, parseInt, passfail, plusplus,
211 postMessage, pop, predef, print, process, prompt, proto, prototype, prototypejs, provides, push,
212 quit, quotmark, range, raw, reach, reason, regexp, readFile, readUrl, regexdash,
213 removeEventListener, replace, report, require, reserved, resizeBy, resizeTo, resolvePath,
214 resumeUpdates, respond, rhino, right, runCommand, scroll, scope, screen, scripturl, scrollBy,
215 scrollTo, scrollbar, search, seal, self, send, serialize, sessionStorage, setInterval, setTimeout,
216 setter, setterToken, shift, slice, smarttabs, sort, spawn, split, statement, statementCount, stack,
217 status, start, strict, sub, substr, supernew, shadow, supplant, sum, sync, test, toLowerCase,
218 toString, toUpperCase, toint32, token, tokens, top, trailing, type, typeOf, Uint16Array,
219 Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis, value, valueOf, var, vars,
220 version, verifyMaxParametersPerFunction, verifyMaxStatementsPerFunction,
221 verifyMaxComplexityPerFunction, verifyMaxNestedBlockDepthPerFunction, WebSocket, withstmt, white,
222 window, windows, Worker, worker, wsh, yui, YUI, Y, YUI_config*/
223
224 /*global exports: false */
225
226 // We build the application inside a function so that we produce only a single
227 // global variable. That function will be invoked immediately, and its return
228 // value is the JSHINT function itself.
229
230 var JSHINT = (function () {
231 "use strict";
232
233 var anonname, // The guessed name for anonymous functions.
234
235 // These are operators that should not be used with the ! operator.
236
237 bang = {
238 "<" : true,
239 "<=" : true,
240 "==" : true,
241 "===": true,
242 "!==": true,
243 "!=" : true,
244 ">" : true,
245 ">=" : true,
246 "+" : true,
247 "-" : true,
248 "*" : true,
249 "/" : true,
250 "%" : true
251 },
252
253 // These are the JSHint boolean options.
254 boolOptions = {
255 asi : true, // if automatic semicolon insertion should be tolerated
256 bitwise : true, // if bitwise operators should not be allowed
257 boss : true, // if advanced usage of assignments should be allowed
258 browser : true, // if the standard browser globals should be predefined
259 camelcase : true, // if identifiers should be required in camel case
260 couch : true, // if CouchDB globals should be predefined
261 curly : true, // if curly braces around all blocks should be required
262 debug : true, // if debugger statements should be allowed
263 devel : true, // if logging globals should be predefined (console,
264 // alert, etc.)
265 dojo : true, // if Dojo Toolkit globals should be predefined
266 eqeqeq : true, // if === should be required
267 eqnull : true, // if == null comparisons should be tolerated
268 es5 : true, // if ES5 syntax should be allowed
269 esnext : true, // if es.next specific syntax should be allowed
270 evil : true, // if eval should be allowed
271 expr : true, // if ExpressionStatement should be allowed as Programs
272 forin : true, // if for in statements must filter
273 funcscope : true, // if only function scope should be used for scope tests
274 globalstrict: true, // if global "use strict"; should be allowed (also
275 // enables 'strict')
276 immed : true, // if immediate invocations must be wrapped in parens
277 iterator : true, // if the `__iterator__` property should be allowed
278 jquery : true, // if jQuery globals should be predefined
279 lastsemic : true, // if semicolons may be ommitted for the trailing
280 // statements inside of a one-line blocks.
281 latedef : true, // if the use before definition should not be tolerated
282 laxbreak : true, // if line breaks should not be checked
283 laxcomma : true, // if line breaks should not be checked around commas
284 loopfunc : true, // if functions should be allowed to be defined within
285 // loops
286 mootools : true, // if MooTools globals should be predefined
287 multistr : true, // allow multiline strings
288 newcap : true, // if constructor names must be capitalized
289 noarg : true, // if arguments.caller and arguments.callee should be
290 // disallowed
291 node : true, // if the Node.js environment globals should be
292 // predefined
293 noempty : true, // if empty blocks should be disallowed
294 nonew : true, // if using `new` for side-effects should be disallowed
295 nonstandard : true, // if non-standard (but widely adopted) globals should
296 // be predefined
297 nomen : true, // if names should be checked
298 onevar : true, // if only one var statement per function should be
299 // allowed
300 onecase : true, // if one case switch statements should be allowed
301 passfail : true, // if the scan should stop on first error
302 plusplus : true, // if increment/decrement should not be allowed
303 proto : true, // if the `__proto__` property should be allowed
304 prototypejs : true, // if Prototype and Scriptaculous globals should be
305 // predefined
306 regexdash : true, // if unescaped first/last dash (-) inside brackets
307 // should be tolerated
308 regexp : true, // if the . should not be allowed in regexp literals
309 rhino : true, // if the Rhino environment globals should be predefined
310 undef : true, // if variables should be declared before used
311 unused : true, // if variables should be always used
312 scripturl : true, // if script-targeted URLs should be tolerated
313 shadow : true, // if variable shadowing should be tolerated
314 smarttabs : true, // if smarttabs should be tolerated
315 // (http://www.emacswiki.org/emacs/SmartTabs)
316 strict : true, // require the "use strict"; pragma
317 sub : true, // if all forms of subscript notation are tolerated
318 supernew : true, // if `new function () { ... };` and `new Object;`
319 // should be tolerated
320 trailing : true, // if trailing whitespace rules apply
321 validthis : true, // if 'this' inside a non-constructor function is valid.
322 // This is a function scoped option only.
323 withstmt : true, // if with statements should be allowed
324 white : true, // if strict whitespace rules apply
325 worker : true, // if Web Worker script symbols should be allowed
326 wsh : true, // if the Windows Scripting Host environment globals
327 // should be predefined
328 yui : true // YUI variables should be predefined
329 },
330
331 // These are the JSHint options that can take any value
332 // (we use this object to detect invalid options)
333 valOptions = {
334 maxlen : false,
335 indent : false,
336 maxerr : false,
337 predef : false,
338 quotmark : false, //'single'|'double'|true
339 scope : false,
340 maxstatements: false, // {int} max statements per function
341 maxdepth : false, // {int} max nested block depth per function
342 maxparams : false, // {int} max params per function
343 maxcomplexity: false // {int} max cyclomatic complexity per function
344 },
345
346 // These are JSHint boolean options which are shared with JSLint
347 // where the definition in JSHint is opposite JSLint
348 invertedOptions = {
349 bitwise : true,
350 forin : true,
351 newcap : true,
352 nomen : true,
353 plusplus : true,
354 regexp : true,
355 undef : true,
356 white : true,
357
358 // Inverted and renamed, use JSHint name here
359 eqeqeq : true,
360 onevar : true
361 },
362
363 // These are JSHint boolean options which are shared with JSLint
364 // where the name has been changed but the effect is unchanged
365 renamedOptions = {
366 eqeq : "eqeqeq",
367 vars : "onevar",
368 windows : "wsh"
369 },
370
371
372 // browser contains a set of global names which are commonly provided by a
373 // web browser environment.
374 browser = {
375 ArrayBuffer : false,
376 ArrayBufferView : false,
377 Audio : false,
378 Blob : false,
379 addEventListener : false,
380 applicationCache : false,
381 atob : false,
382 blur : false,
383 btoa : false,
384 clearInterval : false,
385 clearTimeout : false,
386 close : false,
387 closed : false,
388 DataView : false,
389 DOMParser : false,
390 defaultStatus : false,
391 document : false,
392 event : false,
393 FileReader : false,
394 Float32Array : false,
395 Float64Array : false,
396 FormData : false,
397 focus : false,
398 frames : false,
399 getComputedStyle : false,
400 HTMLElement : false,
401 HTMLAnchorElement : false,
402 HTMLBaseElement : false,
403 HTMLBlockquoteElement : false,
404 HTMLBodyElement : false,
405 HTMLBRElement : false,
406 HTMLButtonElement : false,
407 HTMLCanvasElement : false,
408 HTMLDirectoryElement : false,
409 HTMLDivElement : false,
410 HTMLDListElement : false,
411 HTMLFieldSetElement : false,
412 HTMLFontElement : false,
413 HTMLFormElement : false,
414 HTMLFrameElement : false,
415 HTMLFrameSetElement : false,
416 HTMLHeadElement : false,
417 HTMLHeadingElement : false,
418 HTMLHRElement : false,
419 HTMLHtmlElement : false,
420 HTMLIFrameElement : false,
421 HTMLImageElement : false,
422 HTMLInputElement : false,
423 HTMLIsIndexElement : false,
424 HTMLLabelElement : false,
425 HTMLLayerElement : false,
426 HTMLLegendElement : false,
427 HTMLLIElement : false,
428 HTMLLinkElement : false,
429 HTMLMapElement : false,
430 HTMLMenuElement : false,
431 HTMLMetaElement : false,
432 HTMLModElement : false,
433 HTMLObjectElement : false,
434 HTMLOListElement : false,
435 HTMLOptGroupElement : false,
436 HTMLOptionElement : false,
437 HTMLParagraphElement : false,
438 HTMLParamElement : false,
439 HTMLPreElement : false,
440 HTMLQuoteElement : false,
441 HTMLScriptElement : false,
442 HTMLSelectElement : false,
443 HTMLStyleElement : false,
444 HTMLTableCaptionElement : false,
445 HTMLTableCellElement : false,
446 HTMLTableColElement : false,
447 HTMLTableElement : false,
448 HTMLTableRowElement : false,
449 HTMLTableSectionElement : false,
450 HTMLTextAreaElement : false,
451 HTMLTitleElement : false,
452 HTMLUListElement : false,
453 HTMLVideoElement : false,
454 history : false,
455 Int16Array : false,
456 Int32Array : false,
457 Int8Array : false,
458 Image : false,
459 length : false,
460 localStorage : false,
461 location : false,
462 MessageChannel : false,
463 MessageEvent : false,
464 MessagePort : false,
465 moveBy : false,
466 moveTo : false,
467 MutationObserver : false,
468 name : false,
469 Node : false,
470 NodeFilter : false,
471 navigator : false,
472 onbeforeunload : true,
473 onblur : true,
474 onerror : true,
475 onfocus : true,
476 onload : true,
477 onresize : true,
478 onunload : true,
479 open : false,
480 openDatabase : false,
481 opener : false,
482 Option : false,
483 parent : false,
484 print : false,
485 removeEventListener : false,
486 resizeBy : false,
487 resizeTo : false,
488 screen : false,
489 scroll : false,
490 scrollBy : false,
491 scrollTo : false,
492 sessionStorage : false,
493 setInterval : false,
494 setTimeout : false,
495 SharedWorker : false,
496 status : false,
497 top : false,
498 Uint16Array : false,
499 Uint32Array : false,
500 Uint8Array : false,
501 WebSocket : false,
502 window : false,
503 Worker : false,
504 XMLHttpRequest : false,
505 XMLSerializer : false,
506 XPathEvaluator : false,
507 XPathException : false,
508 XPathExpression : false,
509 XPathNamespace : false,
510 XPathNSResolver : false,
511 XPathResult : false
512 },
513
514 couch = {
515 "require" : false,
516 respond : false,
517 getRow : false,
518 emit : false,
519 send : false,
520 start : false,
521 sum : false,
522 log : false,
523 exports : false,
524 module : false,
525 provides : false
526 },
527
528 declared, // Globals that were declared using /*global ... */ syntax.
529
530 devel = {
531 alert : false,
532 confirm : false,
533 console : false,
534 Debug : false,
535 opera : false,
536 prompt : false
537 },
538
539 dojo = {
540 dojo : false,
541 dijit : false,
542 dojox : false,
543 define : false,
544 "require" : false
545 },
546
547 funct, // The current function
548
549 functionicity = [
550 "closure", "exception", "global", "label",
551 "outer", "unused", "var"
552 ],
553
554 functions, // All of the functions
555
556 global, // The global scope
557 implied, // Implied globals
558 inblock,
559 indent,
560 jsonmode,
561
562 jquery = {
563 "$" : false,
564 jQuery : false
565 },
566
567 lines,
568 lookahead,
569 member,
570 membersOnly,
571
572 mootools = {
573 "$" : false,
574 "$$" : false,
575 Asset : false,
576 Browser : false,
577 Chain : false,
578 Class : false,
579 Color : false,
580 Cookie : false,
581 Core : false,
582 Document : false,
583 DomReady : false,
584 DOMEvent : false,
585 DOMReady : false,
586 Drag : false,
587 Element : false,
588 Elements : false,
589 Event : false,
590 Events : false,
591 Fx : false,
592 Group : false,
593 Hash : false,
594 HtmlTable : false,
595 Iframe : false,
596 IframeShim : false,
597 InputValidator : false,
598 instanceOf : false,
599 Keyboard : false,
600 Locale : false,
601 Mask : false,
602 MooTools : false,
603 Native : false,
604 Options : false,
605 OverText : false,
606 Request : false,
607 Scroller : false,
608 Slick : false,
609 Slider : false,
610 Sortables : false,
611 Spinner : false,
612 Swiff : false,
613 Tips : false,
614 Type : false,
615 typeOf : false,
616 URI : false,
617 Window : false
618 },
619
620 nexttoken,
621
622 node = {
623 __filename : false,
624 __dirname : false,
625 Buffer : false,
626 console : false,
627 exports : true, // In Node it is ok to exports = module.exports = foo();
628 GLOBAL : false,
629 global : false,
630 module : false,
631 process : false,
632 require : false,
633 setTimeout : false,
634 clearTimeout : false,
635 setInterval : false,
636 clearInterval : false
637 },
638
639 noreach,
640 option,
641 predefined, // Global variables defined by option
642 prereg,
643 prevtoken,
644
645 prototypejs = {
646 "$" : false,
647 "$$" : false,
648 "$A" : false,
649 "$F" : false,
650 "$H" : false,
651 "$R" : false,
652 "$break" : false,
653 "$continue" : false,
654 "$w" : false,
655 Abstract : false,
656 Ajax : false,
657 Class : false,
658 Enumerable : false,
659 Element : false,
660 Event : false,
661 Field : false,
662 Form : false,
663 Hash : false,
664 Insertion : false,
665 ObjectRange : false,
666 PeriodicalExecuter: false,
667 Position : false,
668 Prototype : false,
669 Selector : false,
670 Template : false,
671 Toggle : false,
672 Try : false,
673 Autocompleter : false,
674 Builder : false,
675 Control : false,
676 Draggable : false,
677 Draggables : false,
678 Droppables : false,
679 Effect : false,
680 Sortable : false,
681 SortableObserver : false,
682 Sound : false,
683 Scriptaculous : false
684 },
685
686 quotmark,
687
688 rhino = {
689 defineClass : false,
690 deserialize : false,
691 gc : false,
692 help : false,
693 importPackage: false,
694 "java" : false,
695 load : false,
696 loadClass : false,
697 print : false,
698 quit : false,
699 readFile : false,
700 readUrl : false,
701 runCommand : false,
702 seal : false,
703 serialize : false,
704 spawn : false,
705 sync : false,
706 toint32 : false,
707 version : false
708 },
709
710 scope, // The current scope
711 stack,
712
713 // standard contains the global names that are provided by the
714 // ECMAScript standard.
715 standard = {
716 Array : false,
717 Boolean : false,
718 Date : false,
719 decodeURI : false,
720 decodeURIComponent : false,
721 encodeURI : false,
722 encodeURIComponent : false,
723 Error : false,
724 "eval" : false,
725 EvalError : false,
726 Function : false,
727 hasOwnProperty : false,
728 isFinite : false,
729 isNaN : false,
730 JSON : false,
731 Map : false,
732 Math : false,
733 NaN : false,
734 Number : false,
735 Object : false,
736 parseInt : false,
737 parseFloat : false,
738 RangeError : false,
739 ReferenceError : false,
740 RegExp : false,
741 Set : false,
742 String : false,
743 SyntaxError : false,
744 TypeError : false,
745 URIError : false,
746 WeakMap : false
747 },
748
749 // widely adopted global names that are not part of ECMAScript standard
750 nonstandard = {
751 escape : false,
752 unescape : false
753 },
754
755 directive,
756 syntax = {},
757 tab,
758 token,
759 unuseds,
760 urls,
761 useESNextSyntax,
762 warnings,
763
764 worker = {
765 importScripts : true,
766 postMessage : true,
767 self : true
768 },
769
770 wsh = {
771 ActiveXObject : true,
772 Enumerator : true,
773 GetObject : true,
774 ScriptEngine : true,
775 ScriptEngineBuildVersion : true,
776 ScriptEngineMajorVersion : true,
777 ScriptEngineMinorVersion : true,
778 VBArray : true,
779 WSH : true,
780 WScript : true,
781 XDomainRequest : true
782 },
783
784 yui = {
785 YUI : false,
786 Y : false,
787 YUI_config : false
788 };
789 // Regular expressions. Some of these are stupidly long.
790 var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
791 (function () {
792 /*jshint maxlen:300 */
793
794 // unsafe comment or string
795 ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
796
797 // unsafe characters that are silently deleted by one or more browsers
798 cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
799
800 // token
801 tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/=(?!(\S*\/[gim]?))|\/(\*(jshint|jslint|members?|global)?|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/;
802
803 // characters in strings that need escapement
804 nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
805 nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
806
807 // star slash
808 lx = /\*\//;
809
810 // identifier
811 ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
812
813 // javascript url
814 jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;
815
816 // catches /* falls through */ comments
817 ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
818 }());
819
820 function F() {} // Used by Object.create
821
822 function is_own(object, name) {
823 // The object.hasOwnProperty method fails when the property under consideration
824 // is named 'hasOwnProperty'. So we have to use this more convoluted form.
825 return Object.prototype.hasOwnProperty.call(object, name);
826 }
827
828 function checkOption(name, t) {
829 if (valOptions[name] === undefined && boolOptions[name] === undefined) {
830 warning("Bad option: '" + name + "'.", t);
831 }
832 }
833
834 function isString(obj) {
835 return Object.prototype.toString.call(obj) === "[object String]";
836 }
837
838 // Provide critical ES5 functions to ES3.
839
840 if (typeof Array.isArray !== "function") {
841 Array.isArray = function (o) {
842 return Object.prototype.toString.apply(o) === "[object Array]";
843 };
844 }
845
846 if (!Array.prototype.forEach) {
847 Array.prototype.forEach = function (fn, scope) {
848 var len = this.length;
849
850 for (var i = 0; i < len; i++) {
851 fn.call(scope || this, this[i], i, this);
852 }
853 };
854 }
855
856 if (!Array.prototype.indexOf) {
857 Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
858 if (this === null || this === undefined) {
859 throw new TypeError();
860 }
861
862 var t = new Object(this);
863 var len = t.length >>> 0;
864
865 if (len === 0) {
866 return -1;
867 }
868
869 var n = 0;
870 if (arguments.length > 0) {
871 n = Number(arguments[1]);
872 if (n != n) { // shortcut for verifying if it's NaN
873 n = 0;
874 } else if (n !== 0 && n != Infinity && n != -Infinity) {
875 n = (n > 0 || -1) * Math.floor(Math.abs(n));
876 }
877 }
878
879 if (n >= len) {
880 return -1;
881 }
882
883 var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
884 for (; k < len; k++) {
885 if (k in t && t[k] === searchElement) {
886 return k;
887 }
888 }
889
890 return -1;
891 };
892 }
893
894 if (typeof Object.create !== "function") {
895 Object.create = function (o) {
896 F.prototype = o;
897 return new F();
898 };
899 }
900
901 if (typeof Object.keys !== "function") {
902 Object.keys = function (o) {
903 var a = [], k;
904 for (k in o) {
905 if (is_own(o, k)) {
906 a.push(k);
907 }
908 }
909 return a;
910 };
911 }
912
913 // Non standard methods
914
915 function isAlpha(str) {
916 return (str >= "a" && str <= "z\uffff") ||
917 (str >= "A" && str <= "Z\uffff");
918 }
919
920 function isDigit(str) {
921 return (str >= "0" && str <= "9");
922 }
923
924 function isIdentifier(token, value) {
925 if (!token)
926 return false;
927
928 if (!token.identifier || token.value !== value)
929 return false;
930
931 return true;
932 }
933
934 function supplant(str, data) {
935 return str.replace(/\{([^{}]*)\}/g, function (a, b) {
936 var r = data[b];
937 return typeof r === "string" || typeof r === "number" ? r : a;
938 });
939 }
940
941 function combine(t, o) {
942 var n;
943 for (n in o) {
944 if (is_own(o, n) && !is_own(JSHINT.blacklist, n)) {
945 t[n] = o[n];
946 }
947 }
948 }
949
950 function updatePredefined() {
951 Object.keys(JSHINT.blacklist).forEach(function (key) {
952 delete predefined[key];
953 });
954 }
955
956 function assume() {
957 if (option.couch) {
958 combine(predefined, couch);
959 }
960
961 if (option.rhino) {
962 combine(predefined, rhino);
963 }
964
965 if (option.prototypejs) {
966 combine(predefined, prototypejs);
967 }
968
969 if (option.node) {
970 combine(predefined, node);
971 option.globalstrict = true;
972 }
973
974 if (option.devel) {
975 combine(predefined, devel);
976 }
977
978 if (option.dojo) {
979 combine(predefined, dojo);
980 }
981
982 if (option.browser) {
983 combine(predefined, browser);
984 }
985
986 if (option.nonstandard) {
987 combine(predefined, nonstandard);
988 }
989
990 if (option.jquery) {
991 combine(predefined, jquery);
992 }
993
994 if (option.mootools) {
995 combine(predefined, mootools);
996 }
997
998 if (option.worker) {
999 combine(predefined, worker);
1000 }
1001
1002 if (option.wsh) {
1003 combine(predefined, wsh);
1004 }
1005
1006 if (option.esnext) {
1007 useESNextSyntax();
1008 }
1009
1010 if (option.globalstrict && option.strict !== false) {
1011 option.strict = true;
1012 }
1013
1014 if (option.yui) {
1015 combine(predefined, yui);
1016 }
1017 }
1018
1019
1020 // Produce an error warning.
1021 function quit(message, line, chr) {
1022 var percentage = Math.floor((line / lines.length) * 100);
1023
1024 throw {
1025 name: "JSHintError",
1026 line: line,
1027 character: chr,
1028 message: message + " (" + percentage + "% scanned).",
1029 raw: message
1030 };
1031 }
1032
1033 function isundef(scope, m, t, a) {
1034 return JSHINT.undefs.push([scope, m, t, a]);
1035 }
1036
1037 function warning(m, t, a, b, c, d) {
1038 var ch, l, w;
1039 t = t || nexttoken;
1040 if (t.id === "(end)") { // `~
1041 t = token;
1042 }
1043 l = t.line || 0;
1044 ch = t.from || 0;
1045 w = {
1046 id: "(error)",
1047 raw: m,
1048 evidence: lines[l - 1] || "",
1049 line: l,
1050 character: ch,
1051 scope: JSHINT.scope,
1052 a: a,
1053 b: b,
1054 c: c,
1055 d: d
1056 };
1057 w.reason = supplant(m, w);
1058 JSHINT.errors.push(w);
1059 if (option.passfail) {
1060 quit("Stopping. ", l, ch);
1061 }
1062 warnings += 1;
1063 if (warnings >= option.maxerr) {
1064 quit("Too many errors.", l, ch);
1065 }
1066 return w;
1067 }
1068
1069 function warningAt(m, l, ch, a, b, c, d) {
1070 return warning(m, {
1071 line: l,
1072 from: ch
1073 }, a, b, c, d);
1074 }
1075
1076 function error(m, t, a, b, c, d) {
1077 warning(m, t, a, b, c, d);
1078 }
1079
1080 function errorAt(m, l, ch, a, b, c, d) {
1081 return error(m, {
1082 line: l,
1083 from: ch
1084 }, a, b, c, d);
1085 }
1086
1087 // Tracking of "internal" scripts, like eval containing a static string
1088 function addInternalSrc(elem, src) {
1089 var i;
1090 i = {
1091 id: "(internal)",
1092 elem: elem,
1093 value: src
1094 };
1095 JSHINT.internals.push(i);
1096 return i;
1097 }
1098
1099
1100 // lexical analysis and token construction
1101
1102 var lex = (function lex() {
1103 var character, from, line, s;
1104
1105 // Private lex methods
1106
1107 function nextLine() {
1108 var at,
1109 match,
1110 tw; // trailing whitespace check
1111
1112 if (line >= lines.length)
1113 return false;
1114
1115 character = 1;
1116 s = lines[line];
1117 line += 1;
1118
1119 // If smarttabs option is used check for spaces followed by tabs only.
1120 // Otherwise check for any occurence of mixed tabs and spaces.
1121 // Tabs and one space followed by block comment is allowed.
1122 if (option.smarttabs) {
1123 // negative look-behind for "//"
1124 match = s.match(/(\/\/)? \t/);
1125 at = match && !match[1] ? 0 : -1;
1126 } else {
1127 at = s.search(/ \t|\t [^\*]/);
1128 }
1129
1130 if (at >= 0)
1131 warningAt("Mixed spaces and tabs.", line, at + 1);
1132
1133 s = s.replace(/\t/g, tab);
1134 at = s.search(cx);
1135
1136 if (at >= 0)
1137 warningAt("Unsafe character.", line, at);
1138
1139 if (option.maxlen && option.maxlen < s.length)
1140 warningAt("Line too long.", line, s.length);
1141
1142 // Check for trailing whitespaces
1143 tw = option.trailing && s.match(/^(.*?)\s+$/);
1144 if (tw && !/^\s+$/.test(s)) {
1145 warningAt("Trailing whitespace.", line, tw[1].length + 1);
1146 }
1147 return true;
1148 }
1149
1150 // Produce a token object. The token inherits from a syntax symbol.
1151
1152 function it(type, value) {
1153 var i, t;
1154
1155 function checkName(name) {
1156 if (!option.proto && name === "__proto__") {
1157 warningAt("The '{a}' property is deprecated.", line, from, name);
1158 return;
1159 }
1160
1161 if (!option.iterator && name === "__iterator__") {
1162 warningAt("'{a}' is only available in JavaScript 1.7.", line, from, name);
1163 return;
1164 }
1165
1166 // Check for dangling underscores unless we're in Node
1167 // environment and this identifier represents built-in
1168 // Node globals with underscores.
1169
1170 var hasDangling = /^(_+.*|.*_+)$/.test(name);
1171
1172 if (option.nomen && hasDangling && name !== "_") {
1173 if (option.node && token.id !== "." && /^(__dirname|__filename)$/.test(name))
1174 return;
1175
1176 warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", name);
1177 return;
1178 }
1179
1180 // Check for non-camelcase names. Names like MY_VAR and
1181 // _myVar are okay though.
1182
1183 if (option.camelcase) {
1184 if (name.replace(/^_+/, "").indexOf("_") > -1 && !name.match(/^[A-Z0-9_]*$/)) {
1185 warningAt("Identifier '{a}' is not in camel case.", line, from, value);
1186 }
1187 }
1188 }
1189
1190 if (type === "(color)" || type === "(range)") {
1191 t = {type: type};
1192 } else if (type === "(punctuator)" ||
1193 (type === "(identifier)" && is_own(syntax, value))) {
1194 t = syntax[value] || syntax["(error)"];
1195 } else {
1196 t = syntax[type];
1197 }
1198
1199 t = Object.create(t);
1200
1201 if (type === "(string)" || type === "(range)") {
1202 if (!option.scripturl && jx.test(value)) {
1203 warningAt("Script URL.", line, from);
1204 }
1205 }
1206
1207 if (type === "(identifier)") {
1208 t.identifier = true;
1209 checkName(value);
1210 }
1211
1212 t.value = value;
1213 t.line = line;
1214 t.character = character;
1215 t.from = from;
1216 i = t.id;
1217 if (i !== "(endline)") {
1218 prereg = i &&
1219 (("(,=:[!&|?{};".indexOf(i.charAt(i.length - 1)) >= 0) ||
1220 i === "return" ||
1221 i === "case");
1222 }
1223 return t;
1224 }
1225
1226 // Public lex methods
1227 return {
1228 init: function (source) {
1229 if (typeof source === "string") {
1230 lines = source
1231 .replace(/\r\n/g, "\n")
1232 .replace(/\r/g, "\n")
1233 .split("\n");
1234 } else {
1235 lines = source;
1236 }
1237
1238 // If the first line is a shebang (#!), make it a blank and move on.
1239 // Shebangs are used by Node scripts.
1240 if (lines[0] && lines[0].substr(0, 2) === "#!")
1241 lines[0] = "";
1242
1243 line = 0;
1244 nextLine();
1245 from = 1;
1246 },
1247
1248 range: function (begin, end) {
1249 var c, value = "";
1250 from = character;
1251 if (s.charAt(0) !== begin) {
1252 errorAt("Expected '{a}' and instead saw '{b}'.",
1253 line, character, begin, s.charAt(0));
1254 }
1255 for (;;) {
1256 s = s.slice(1);
1257 character += 1;
1258 c = s.charAt(0);
1259 switch (c) {
1260 case "":
1261 errorAt("Missing '{a}'.", line, character, c);
1262 break;
1263 case end:
1264 s = s.slice(1);
1265 character += 1;
1266 return it("(range)", value);
1267 case "\\":
1268 warningAt("Unexpected '{a}'.", line, character, c);
1269 }
1270 value += c;
1271 }
1272
1273 },
1274
1275
1276 // token -- this is called by advance to get the next token
1277 token: function () {
1278 var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n;
1279
1280 function match(x) {
1281 var r = x.exec(s), r1;
1282
1283 if (r) {
1284 l = r[0].length;
1285 r1 = r[1];
1286 c = r1.charAt(0);
1287 s = s.substr(l);
1288 from = character + l - r1.length;
1289 character += l;
1290 return r1;
1291 }
1292 }
1293
1294 function string(x) {
1295 var c, j, r = "", allowNewLine = false;
1296
1297 if (jsonmode && x !== "\"") {
1298 warningAt("Strings must use doublequote.",
1299 line, character);
1300 }
1301
1302 if (option.quotmark) {
1303 if (option.quotmark === "single" && x !== "'") {
1304 warningAt("Strings must use singlequote.",
1305 line, character);
1306 } else if (option.quotmark === "double" && x !== "\"") {
1307 warningAt("Strings must use doublequote.",
1308 line, character);
1309 } else if (option.quotmark === true) {
1310 quotmark = quotmark || x;
1311 if (quotmark !== x) {
1312 warningAt("Mixed double and single quotes.",
1313 line, character);
1314 }
1315 }
1316 }
1317
1318 function esc(n) {
1319 var i = parseInt(s.substr(j + 1, n), 16);
1320 j += n;
1321 if (i >= 32 && i <= 126 &&
1322 i !== 34 && i !== 92 && i !== 39) {
1323 warningAt("Unnecessary escapement.", line, character);
1324 }
1325 character += n;
1326 c = String.fromCharCode(i);
1327 }
1328
1329 j = 0;
1330
1331 unclosedString:
1332 for (;;) {
1333 while (j >= s.length) {
1334 j = 0;
1335
1336 var cl = line, cf = from;
1337 if (!nextLine()) {
1338 errorAt("Unclosed string.", cl, cf);
1339 break unclosedString;
1340 }
1341
1342 if (allowNewLine) {
1343 allowNewLine = false;
1344 } else {
1345 warningAt("Unclosed string.", cl, cf);
1346 }
1347 }
1348
1349 c = s.charAt(j);
1350 if (c === x) {
1351 character += 1;
1352 s = s.substr(j + 1);
1353 return it("(string)", r, x);
1354 }
1355
1356 if (c < " ") {
1357 if (c === "\n" || c === "\r") {
1358 break;
1359 }
1360 warningAt("Control character in string: {a}.",
1361 line, character + j, s.slice(0, j));
1362 } else if (c === "\\") {
1363 j += 1;
1364 character += 1;
1365 c = s.charAt(j);
1366 n = s.charAt(j + 1);
1367 switch (c) {
1368 case "\\":
1369 case "\"":
1370 case "/":
1371 break;
1372 case "\'":
1373 if (jsonmode) {
1374 warningAt("Avoid \\'.", line, character);
1375 }
1376 break;
1377 case "b":
1378 c = "\b";
1379 break;
1380 case "f":
1381 c = "\f";
1382 break;
1383 case "n":
1384 c = "\n";
1385 break;
1386 case "r":
1387 c = "\r";
1388 break;
1389 case "t":
1390 c = "\t";
1391 break;
1392 case "0":
1393 c = "\0";
1394 // Octal literals fail in strict mode
1395 // check if the number is between 00 and 07
1396 // where 'n' is the token next to 'c'
1397 if (n >= 0 && n <= 7 && directive["use strict"]) {
1398 warningAt(
1399 "Octal literals are not allowed in strict mode.",
1400 line, character);
1401 }
1402 break;
1403 case "u":
1404 esc(4);
1405 break;
1406 case "v":
1407 if (jsonmode) {
1408 warningAt("Avoid \\v.", line, character);
1409 }
1410 c = "\v";
1411 break;
1412 case "x":
1413 if (jsonmode) {
1414 warningAt("Avoid \\x-.", line, character);
1415 }
1416 esc(2);
1417 break;
1418 case "":
1419 // last character is escape character
1420 // always allow new line if escaped, but show
1421 // warning if option is not set
1422 allowNewLine = true;
1423 if (option.multistr) {
1424 if (jsonmode) {
1425 warningAt("Avoid EOL escapement.", line, character);
1426 }
1427 c = "";
1428 character -= 1;
1429 break;
1430 }
1431 warningAt("Bad escapement of EOL. Use option multistr if needed.",
1432 line, character);
1433 break;
1434 case "!":
1435 if (s.charAt(j - 2) === "<")
1436 break;
1437 /*falls through*/
1438 default:
1439 warningAt("Bad escapement.", line, character);
1440 }
1441 }
1442 r += c;
1443 character += 1;
1444 j += 1;
1445 }
1446 }
1447
1448 for (;;) {
1449 if (!s) {
1450 return it(nextLine() ? "(endline)" : "(end)", "");
1451 }
1452
1453 t = match(tx);
1454
1455 if (!t) {
1456 t = "";
1457 c = "";
1458 while (s && s < "!") {
1459 s = s.substr(1);
1460 }
1461 if (s) {
1462 errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
1463 s = "";
1464 }
1465 } else {
1466
1467 // identifier
1468
1469 if (isAlpha(c) || c === "_" || c === "$") {
1470 return it("(identifier)", t);
1471 }
1472
1473 // number
1474
1475 if (isDigit(c)) {
1476 if (!isFinite(Number(t))) {
1477 warningAt("Bad number '{a}'.",
1478 line, character, t);
1479 }
1480 if (isAlpha(s.substr(0, 1))) {
1481 warningAt("Missing space after '{a}'.",
1482 line, character, t);
1483 }
1484 if (c === "0") {
1485 d = t.substr(1, 1);
1486 if (isDigit(d)) {
1487 if (token.id !== ".") {
1488 warningAt("Don't use extra leading zeros '{a}'.",
1489 line, character, t);
1490 }
1491 } else if (jsonmode && (d === "x" || d === "X")) {
1492 warningAt("Avoid 0x-. '{a}'.",
1493 line, character, t);
1494 }
1495 }
1496 if (t.substr(t.length - 1) === ".") {
1497 warningAt(
1498 "A trailing decimal point can be confused with a dot '{a}'.", line, character, t);
1499 }
1500 return it("(number)", t);
1501 }
1502 switch (t) {
1503
1504 // string
1505
1506 case "\"":
1507 case "'":
1508 return string(t);
1509
1510 // // comment
1511
1512 case "//":
1513 s = "";
1514 token.comment = true;
1515 break;
1516
1517 // /* comment
1518
1519 case "/*":
1520 for (;;) {
1521 i = s.search(lx);
1522 if (i >= 0) {
1523 break;
1524 }
1525 if (!nextLine()) {
1526 errorAt("Unclosed comment.", line, character);
1527 }
1528 }
1529 s = s.substr(i + 2);
1530 token.comment = true;
1531 break;
1532
1533 // /*members /*jshint /*global
1534
1535 case "/*members":
1536 case "/*member":
1537 case "/*jshint":
1538 case "/*jslint":
1539 case "/*global":
1540 case "*/":
1541 return {
1542 value: t,
1543 type: "special",
1544 line: line,
1545 character: character,
1546 from: from
1547 };
1548
1549 case "":
1550 break;
1551 // /
1552 case "/":
1553 if (s.charAt(0) === "=") {
1554 errorAt("A regular expression literal can be confused with '/='.",
1555 line, from);
1556 }
1557
1558 if (prereg) {
1559 depth = 0;
1560 captures = 0;
1561 l = 0;
1562 for (;;) {
1563 b = true;
1564 c = s.charAt(l);
1565 l += 1;
1566 switch (c) {
1567 case "":
1568 errorAt("Unclosed regular expression.", line, from);
1569 return quit("Stopping.", line, from);
1570 case "/":
1571 if (depth > 0) {
1572 warningAt("{a} unterminated regular expression " +
1573 "group(s).", line, from + l, depth);
1574 }
1575 c = s.substr(0, l - 1);
1576 q = {
1577 g: true,
1578 i: true,
1579 m: true
1580 };
1581 while (q[s.charAt(l)] === true) {
1582 q[s.charAt(l)] = false;
1583 l += 1;
1584 }
1585 character += l;
1586 s = s.substr(l);
1587 q = s.charAt(0);
1588 if (q === "/" || q === "*") {
1589 errorAt("Confusing regular expression.",
1590 line, from);
1591 }
1592 return it("(regexp)", c);
1593 case "\\":
1594 c = s.charAt(l);
1595 if (c < " ") {
1596 warningAt(
1597 "Unexpected control character in regular expression.", line, from + l);
1598 } else if (c === "<") {
1599 warningAt(
1600 "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1601 }
1602 l += 1;
1603 break;
1604 case "(":
1605 depth += 1;
1606 b = false;
1607 if (s.charAt(l) === "?") {
1608 l += 1;
1609 switch (s.charAt(l)) {
1610 case ":":
1611 case "=":
1612 case "!":
1613 l += 1;
1614 break;
1615 default:
1616 warningAt(
1617 "Expected '{a}' and instead saw '{b}'.", line, from + l, ":", s.charAt(l));
1618 }
1619 } else {
1620 captures += 1;
1621 }
1622 break;
1623 case "|":
1624 b = false;
1625 break;
1626 case ")":
1627 if (depth === 0) {
1628 warningAt("Unescaped '{a}'.",
1629 line, from + l, ")");
1630 } else {
1631 depth -= 1;
1632 }
1633 break;
1634 case " ":
1635 q = 1;
1636 while (s.charAt(l) === " ") {
1637 l += 1;
1638 q += 1;
1639 }
1640 if (q > 1) {
1641 warningAt(
1642 "Spaces are hard to count. Use {{a}}.", line, from + l, q);
1643 }
1644 break;
1645 case "[":
1646 c = s.charAt(l);
1647 if (c === "^") {
1648 l += 1;
1649 if (s.charAt(l) === "]") {
1650 errorAt("Unescaped '{a}'.",
1651 line, from + l, "^");
1652 }
1653 }
1654 if (c === "]") {
1655 warningAt("Empty class.", line,
1656 from + l - 1);
1657 }
1658 isLiteral = false;
1659 isInRange = false;
1660 klass:
1661 do {
1662 c = s.charAt(l);
1663 l += 1;
1664 switch (c) {
1665 case "[":
1666 case "^":
1667 warningAt("Unescaped '{a}'.",
1668 line, from + l, c);
1669 if (isInRange) {
1670 isInRange = false;
1671 } else {
1672 isLiteral = true;
1673 }
1674 break;
1675 case "-":
1676 if (isLiteral && !isInRange) {
1677 isLiteral = false;
1678 isInRange = true;
1679 } else if (isInRange) {
1680 isInRange = false;
1681 } else if (s.charAt(l) === "]") {
1682 isInRange = true;
1683 } else {
1684 if (option.regexdash !== (l === 2 || (l === 3 &&
1685 s.charAt(1) === "^"))) {
1686 warningAt("Unescaped '{a}'.",
1687 line, from + l - 1, "-");
1688 }
1689 isLiteral = true;
1690 }
1691 break;
1692 case "]":
1693 if (isInRange && !option.regexdash) {
1694 warningAt("Unescaped '{a}'.",
1695 line, from + l - 1, "-");
1696 }
1697 break klass;
1698 case "\\":
1699 c = s.charAt(l);
1700 if (c < " ") {
1701 warningAt(
1702 "Unexpected control character in regular expression.", line, from + l);
1703 } else if (c === "<") {
1704 warningAt(
1705 "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1706 }
1707 l += 1;
1708
1709 // \w, \s and \d are never part of a character range
1710 if (/[wsd]/i.test(c)) {
1711 if (isInRange) {
1712 warningAt("Unescaped '{a}'.",
1713 line, from + l, "-");
1714 isInRange = false;
1715 }
1716 isLiteral = false;
1717 } else if (isInRange) {
1718 isInRange = false;
1719 } else {
1720 isLiteral = true;
1721 }
1722 break;
1723 case "/":
1724 warningAt("Unescaped '{a}'.",
1725 line, from + l - 1, "/");
1726
1727 if (isInRange) {
1728 isInRange = false;
1729 } else {
1730 isLiteral = true;
1731 }
1732 break;
1733 case "<":
1734 if (isInRange) {
1735 isInRange = false;
1736 } else {
1737 isLiteral = true;
1738 }
1739 break;
1740 default:
1741 if (isInRange) {
1742 isInRange = false;
1743 } else {
1744 isLiteral = true;
1745 }
1746 }
1747 } while (c);
1748 break;
1749 case ".":
1750 if (option.regexp) {
1751 warningAt("Insecure '{a}'.", line,
1752 from + l, c);
1753 }
1754 break;
1755 case "]":
1756 case "?":
1757 case "{":
1758 case "}":
1759 case "+":
1760 case "*":
1761 warningAt("Unescaped '{a}'.", line,
1762 from + l, c);
1763 }
1764 if (b) {
1765 switch (s.charAt(l)) {
1766 case "?":
1767 case "+":
1768 case "*":
1769 l += 1;
1770 if (s.charAt(l) === "?") {
1771 l += 1;
1772 }
1773 break;
1774 case "{":
1775 l += 1;
1776 c = s.charAt(l);
1777 if (c < "0" || c > "9") {
1778 warningAt(
1779 "Expected a number and instead saw '{a}'.", line, from + l, c);
1780 break; // No reason to continue checking numbers.
1781 }
1782 l += 1;
1783 low = +c;
1784 for (;;) {
1785 c = s.charAt(l);
1786 if (c < "0" || c > "9") {
1787 break;
1788 }
1789 l += 1;
1790 low = +c + (low * 10);
1791 }
1792 high = low;
1793 if (c === ",") {
1794 l += 1;
1795 high = Infinity;
1796 c = s.charAt(l);
1797 if (c >= "0" && c <= "9") {
1798 l += 1;
1799 high = +c;
1800 for (;;) {
1801 c = s.charAt(l);
1802 if (c < "0" || c > "9") {
1803 break;
1804 }
1805 l += 1;
1806 high = +c + (high * 10);
1807 }
1808 }
1809 }
1810 if (s.charAt(l) !== "}") {
1811 warningAt(
1812 "Expected '{a}' and instead saw '{b}'.", line, from + l, "}", c);
1813 } else {
1814 l += 1;
1815 }
1816 if (s.charAt(l) === "?") {
1817 l += 1;
1818 }
1819 if (low > high) {
1820 warningAt(
1821 "'{a}' should not be greater than '{b}'.", line, from + l, low, high);
1822 }
1823 }
1824 }
1825 }
1826 c = s.substr(0, l - 1);
1827 character += l;
1828 s = s.substr(l);
1829 return it("(regexp)", c);
1830 }
1831 return it("(punctuator)", t);
1832
1833 // punctuator
1834
1835 case "#":
1836 return it("(punctuator)", t);
1837 default:
1838 return it("(punctuator)", t);
1839 }
1840 }
1841 }
1842 }
1843 };
1844 }());
1845
1846
1847 function addlabel(t, type, token) {
1848 if (t === "hasOwnProperty") {
1849 warning("'hasOwnProperty' is a really bad name.");
1850 }
1851
1852 // Define t in the current function in the current scope.
1853 if (type === "exception") {
1854 if (is_own(funct["(context)"], t)) {
1855 if (funct[t] !== true && !option.node) {
1856 warning("Value of '{a}' may be overwritten in IE.", nexttoken, t);
1857 }
1858 }
1859 }
1860
1861 if (is_own(funct, t) && !funct["(global)"]) {
1862 if (funct[t] === true) {
1863 if (option.latedef)
1864 warning("'{a}' was used before it was defined.", nexttoken, t);
1865 } else {
1866 if (!option.shadow && type !== "exception") {
1867 warning("'{a}' is already defined.", nexttoken, t);
1868 }
1869 }
1870 }
1871
1872 funct[t] = type;
1873
1874 if (token) {
1875 funct["(tokens)"][t] = token;
1876 }
1877
1878 if (funct["(global)"]) {
1879 global[t] = funct;
1880 if (is_own(implied, t)) {
1881 if (option.latedef)
1882 warning("'{a}' was used before it was defined.", nexttoken, t);
1883 delete implied[t];
1884 }
1885 } else {
1886 scope[t] = funct;
1887 }
1888 }
1889
1890
1891 function doOption() {
1892 var nt = nexttoken;
1893 var o = nt.value;
1894 var quotmarkValue = option.quotmark;
1895 var predef = {};
1896 var b, obj, filter, t, tn, v, minus;
1897
1898 switch (o) {
1899 case "*/":
1900 error("Unbegun comment.");
1901 break;
1902 case "/*members":
1903 case "/*member":
1904 o = "/*members";
1905 if (!membersOnly) {
1906 membersOnly = {};
1907 }
1908 obj = membersOnly;
1909 option.quotmark = false;
1910 break;
1911 case "/*jshint":
1912 case "/*jslint":
1913 obj = option;
1914 filter = boolOptions;
1915 break;
1916 case "/*global":
1917 obj = predef;
1918 break;
1919 default:
1920 error("What?");
1921 }
1922
1923 t = lex.token();
1924
1925 loop:
1926 for (;;) {
1927 minus = false;
1928 for (;;) {
1929 if (t.type === "special" && t.value === "*/") {
1930 break loop;
1931 }
1932 if (t.id !== "(endline)" && t.id !== ",") {
1933 break;
1934 }
1935 t = lex.token();
1936 }
1937
1938 if (o === "/*global" && t.value === "-") {
1939 minus = true;
1940 t = lex.token();
1941 }
1942
1943 if (t.type !== "(string)" && t.type !== "(identifier)" && o !== "/*members") {
1944 error("Bad option.", t);
1945 }
1946
1947 v = lex.token();
1948 if (v.id === ":") {
1949 v = lex.token();
1950
1951 if (obj === membersOnly) {
1952 error("Expected '{a}' and instead saw '{b}'.", t, "*/", ":");
1953 }
1954
1955 if (o === "/*jshint") {
1956 checkOption(t.value, t);
1957 }
1958
1959 var numericVals = [
1960 "maxstatements",
1961 "maxparams",
1962 "maxdepth",
1963 "maxcomplexity",
1964 "maxerr",
1965 "maxlen",
1966 "indent"
1967 ];
1968
1969 if (numericVals.indexOf(t.value) > -1 && (o === "/*jshint" || o === "/*jslint")) {
1970 b = +v.value;
1971
1972 if (typeof b !== "number" || !isFinite(b) || b <= 0 || Math.floor(b) !== b) {
1973 error("Expected a small integer and instead saw '{a}'.", v, v.value);
1974 }
1975
1976 if (t.value === "indent")
1977 obj.white = true;
1978
1979 obj[t.value] = b;
1980 } else if (t.value === "validthis") {
1981 if (funct["(global)"]) {
1982 error("Option 'validthis' can't be used in a global scope.");
1983 } else {
1984 if (v.value === "true" || v.value === "false")
1985 obj[t.value] = v.value === "true";
1986 else
1987 error("Bad option value.", v);
1988 }
1989 } else if (t.value === "quotmark" && (o === "/*jshint")) {
1990 switch (v.value) {
1991 case "true":
1992 obj.quotmark = true;
1993 break;
1994 case "false":
1995 obj.quotmark = false;
1996 break;
1997 case "double":
1998 case "single":
1999 obj.quotmark = v.value;
2000 break;
2001 default:
2002 error("Bad option value.", v);
2003 }
2004 } else if (v.value === "true" || v.value === "false") {
2005 if (o === "/*jslint") {
2006 tn = renamedOptions[t.value] || t.value;
2007 obj[tn] = v.value === "true";
2008 if (invertedOptions[tn] !== undefined) {
2009 obj[tn] = !obj[tn];
2010 }
2011 } else {
2012 obj[t.value] = v.value === "true";
2013 }
2014
2015 if (t.value === "newcap")
2016 obj["(explicitNewcap)"] = true;
2017 } else {
2018 error("Bad option value.", v);
2019 }
2020 t = lex.token();
2021 } else {
2022 if (o === "/*jshint" || o === "/*jslint") {
2023 error("Missing option value.", t);
2024 }
2025
2026 obj[t.value] = false;
2027
2028 if (o === "/*global" && minus === true) {
2029 JSHINT.blacklist[t.value] = t.value;
2030 updatePredefined();
2031 }
2032
2033 t = v;
2034 }
2035 }
2036
2037 if (o === "/*members") {
2038 option.quotmark = quotmarkValue;
2039 }
2040
2041 combine(predefined, predef);
2042
2043 for (var key in predef) {
2044 if (is_own(predef, key)) {
2045 declared[key] = nt;
2046 }
2047 }
2048
2049 if (filter) {
2050 assume();
2051 }
2052 }
2053
2054
2055 // We need a peek function. If it has an argument, it peeks that much farther
2056 // ahead. It is used to distinguish
2057 // for ( var i in ...
2058 // from
2059 // for ( var i = ...
2060
2061 function peek(p) {
2062 var i = p || 0, j = 0, t;
2063
2064 while (j <= i) {
2065 t = lookahead[j];
2066 if (!t) {
2067 t = lookahead[j] = lex.token();
2068 }
2069 j += 1;
2070 }
2071 return t;
2072 }
2073
2074
2075
2076 // Produce the next token. It looks for programming errors.
2077
2078 function advance(id, t) {
2079 switch (token.id) {
2080 case "(number)":
2081 if (nexttoken.id === ".") {
2082 warning("A dot following a number can be confused with a decimal point.", token);
2083 }
2084 break;
2085 case "-":
2086 if (nexttoken.id === "-" || nexttoken.id === "--") {
2087 warning("Confusing minusses.");
2088 }
2089 break;
2090 case "+":
2091 if (nexttoken.id === "+" || nexttoken.id === "++") {
2092 warning("Confusing plusses.");
2093 }
2094 break;
2095 }
2096
2097 if (token.type === "(string)" || token.identifier) {
2098 anonname = token.value;
2099 }
2100
2101 if (id && nexttoken.id !== id) {
2102 if (t) {
2103 if (nexttoken.id === "(end)") {
2104 warning("Unmatched '{a}'.", t, t.id);
2105 } else {
2106 warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
2107 nexttoken, id, t.id, t.line, nexttoken.value);
2108 }
2109 } else if (nexttoken.type !== "(identifier)" ||
2110 nexttoken.value !== id) {
2111 warning("Expected '{a}' and instead saw '{b}'.",
2112 nexttoken, id, nexttoken.value);
2113 }
2114 }
2115
2116 prevtoken = token;
2117 token = nexttoken;
2118 for (;;) {
2119 nexttoken = lookahead.shift() || lex.token();
2120 if (nexttoken.id === "(end)" || nexttoken.id === "(error)") {
2121 return;
2122 }
2123 if (nexttoken.type === "special") {
2124 doOption();
2125 } else {
2126 if (nexttoken.id !== "(endline)") {
2127 break;
2128 }
2129 }
2130 }
2131 }
2132
2133
2134 // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it
2135 // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
2136 // like .nud except that it is only used on the first token of a statement.
2137 // Having .fud makes it much easier to define statement-oriented languages like
2138 // JavaScript. I retained Pratt's nomenclature.
2139
2140 // .nud Null denotation
2141 // .fud First null denotation
2142 // .led Left denotation
2143 // lbp Left binding power
2144 // rbp Right binding power
2145
2146 // They are elements of the parsing method called Top Down Operator Precedence.
2147
2148 function expression(rbp, initial) {
2149 var left, isArray = false, isObject = false;
2150
2151 if (nexttoken.id === "(end)")
2152 error("Unexpected early end of program.", token);
2153
2154 advance();
2155 if (initial) {
2156 anonname = "anonymous";
2157 funct["(verb)"] = token.value;
2158 }
2159 if (initial === true && token.fud) {
2160 left = token.fud();
2161 } else {
2162 if (token.nud) {
2163 left = token.nud();
2164 } else {
2165 if (nexttoken.type === "(number)" && token.id === ".") {
2166 warning("A leading decimal point can be confused with a dot: '.{a}'.",
2167 token, nexttoken.value);
2168 advance();
2169 return token;
2170 } else {
2171 error("Expected an identifier and instead saw '{a}'.",
2172 token, token.id);
2173 }
2174 }
2175 while (rbp < nexttoken.lbp) {
2176 isArray = token.value === "Array";
2177 isObject = token.value === "Object";
2178
2179 // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object()
2180 // Line breaks in IfStatement heads exist to satisfy the checkJSHint
2181 // "Line too long." error.
2182 if (left && (left.value || (left.first && left.first.value))) {
2183 // If the left.value is not "new", or the left.first.value is a "."
2184 // then safely assume that this is not "new Array()" and possibly
2185 // not "new Object()"...
2186 if (left.value !== "new" ||
2187 (left.first && left.first.value && left.first.value === ".")) {
2188 isArray = false;
2189 // ...In the case of Object, if the left.value and token.value
2190 // are not equal, then safely assume that this not "new Object()"
2191 if (left.value !== token.value) {
2192 isObject = false;
2193 }
2194 }
2195 }
2196
2197 advance();
2198 if (isArray && token.id === "(" && nexttoken.id === ")")
2199 warning("Use the array literal notation [].", token);
2200 if (isObject && token.id === "(" && nexttoken.id === ")")
2201 warning("Use the object literal notation {}.", token);
2202 if (token.led) {
2203 left = token.led(left);
2204 } else {
2205 error("Expected an operator and instead saw '{a}'.",
2206 token, token.id);
2207 }
2208 }
2209 }
2210 return left;
2211 }
2212
2213
2214 // Functions for conformance of style.
2215
2216 function adjacent(left, right) {
2217 left = left || token;
2218 right = right || nexttoken;
2219 if (option.white) {
2220 if (left.character !== right.from && left.line === right.line) {
2221 left.from += (left.character - left.from);
2222 warning("Unexpected space after '{a}'.", left, left.value);
2223 }
2224 }
2225 }
2226
2227 function nobreak(left, right) {
2228 left = left || token;
2229 right = right || nexttoken;
2230 if (option.white && (left.character !== right.from || left.line !== right.line)) {
2231 warning("Unexpected space before '{a}'.", right, right.value);
2232 }
2233 }
2234
2235 function nospace(left, right) {
2236 left = left || token;
2237 right = right || nexttoken;
2238 if (option.white && !left.comment) {
2239 if (left.line === right.line) {
2240 adjacent(left, right);
2241 }
2242 }
2243 }
2244
2245 function nonadjacent(left, right) {
2246 if (option.white) {
2247 left = left || token;
2248 right = right || nexttoken;
2249 if (left.value === ";" && right.value === ";") {
2250 return;
2251 }
2252 if (left.line === right.line && left.character === right.from) {
2253 left.from += (left.character - left.from);
2254 warning("Missing space after '{a}'.",
2255 left, left.value);
2256 }
2257 }
2258 }
2259
2260 function nobreaknonadjacent(left, right) {
2261 left = left || token;
2262 right = right || nexttoken;
2263 if (!option.laxbreak && left.line !== right.line) {
2264 warning("Bad line breaking before '{a}'.", right, right.id);
2265 } else if (option.white) {
2266 left = left || token;
2267 right = right || nexttoken;
2268 if (left.character === right.from) {
2269 left.from += (left.character - left.from);
2270 warning("Missing space after '{a}'.",
2271 left, left.value);
2272 }
2273 }
2274 }
2275
2276 function indentation(bias) {
2277 var i;
2278 if (option.white && nexttoken.id !== "(end)") {
2279 i = indent + (bias || 0);
2280 if (nexttoken.from !== i) {
2281 warning(
2282 "Expected '{a}' to have an indentation at {b} instead at {c}.",
2283 nexttoken, nexttoken.value, i, nexttoken.from);
2284 }
2285 }
2286 }
2287
2288 function nolinebreak(t) {
2289 t = t || token;
2290 if (t.line !== nexttoken.line) {
2291 warning("Line breaking error '{a}'.", t, t.value);
2292 }
2293 }
2294
2295
2296 function comma() {
2297 if (token.line !== nexttoken.line) {
2298 if (!option.laxcomma) {
2299 if (comma.first) {
2300 warning("Comma warnings can be turned off with 'laxcomma'");
2301 comma.first = false;
2302 }
2303 warning("Bad line breaking before '{a}'.", token, nexttoken.id);
2304 }
2305 } else if (!token.comment && token.character !== nexttoken.from && option.white) {
2306 token.from += (token.character - token.from);
2307 warning("Unexpected space after '{a}'.", token, token.value);
2308 }
2309 advance(",");
2310 nonadjacent(token, nexttoken);
2311 }
2312
2313
2314 // Functional constructors for making the symbols that will be inherited by
2315 // tokens.
2316
2317 function symbol(s, p) {
2318 var x = syntax[s];
2319 if (!x || typeof x !== "object") {
2320 syntax[s] = x = {
2321 id: s,
2322 lbp: p,
2323 value: s
2324 };
2325 }
2326 return x;
2327 }
2328
2329
2330 function delim(s) {
2331 return symbol(s, 0);
2332 }
2333
2334
2335 function stmt(s, f) {
2336 var x = delim(s);
2337 x.identifier = x.reserved = true;
2338 x.fud = f;
2339 return x;
2340 }
2341
2342
2343 function blockstmt(s, f) {
2344 var x = stmt(s, f);
2345 x.block = true;
2346 return x;
2347 }
2348
2349
2350 function reserveName(x) {
2351 var c = x.id.charAt(0);
2352 if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) {
2353 x.identifier = x.reserved = true;
2354 }
2355 return x;
2356 }
2357
2358
2359 function prefix(s, f) {
2360 var x = symbol(s, 150);
2361 reserveName(x);
2362 x.nud = (typeof f === "function") ? f : function () {
2363 this.right = expression(150);
2364 this.arity = "unary";
2365 if (this.id === "++" || this.id === "--") {
2366 if (option.plusplus) {
2367 warning("Unexpected use of '{a}'.", this, this.id);
2368 } else if ((!this.right.identifier || this.right.reserved) &&
2369 this.right.id !== "." && this.right.id !== "[") {
2370 warning("Bad operand.", this);
2371 }
2372 }
2373 return this;
2374 };
2375 return x;
2376 }
2377
2378
2379 function type(s, f) {
2380 var x = delim(s);
2381 x.type = s;
2382 x.nud = f;
2383 return x;
2384 }
2385
2386
2387 function reserve(s, f) {
2388 var x = type(s, f);
2389 x.identifier = x.reserved = true;
2390 return x;
2391 }
2392
2393
2394 function reservevar(s, v) {
2395 return reserve(s, function () {
2396 if (typeof v === "function") {
2397 v(this);
2398 }
2399 return this;
2400 });
2401 }
2402
2403
2404 function infix(s, f, p, w) {
2405 var x = symbol(s, p);
2406 reserveName(x);
2407 x.led = function (left) {
2408 if (!w) {
2409 nobreaknonadjacent(prevtoken, token);
2410 nonadjacent(token, nexttoken);
2411 }
2412 if (s === "in" && left.id === "!") {
2413 warning("Confusing use of '{a}'.", left, "!");
2414 }
2415 if (typeof f === "function") {
2416 return f(left, this);
2417 } else {
2418 this.left = left;
2419 this.right = expression(p);
2420 return this;
2421 }
2422 };
2423 return x;
2424 }
2425
2426
2427 function relation(s, f) {
2428 var x = symbol(s, 100);
2429 x.led = function (left) {
2430 nobreaknonadjacent(prevtoken, token);
2431 nonadjacent(token, nexttoken);
2432 var right = expression(100);
2433
2434 if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) {
2435 warning("Use the isNaN function to compare with NaN.", this);
2436 } else if (f) {
2437 f.apply(this, [left, right]);
2438 }
2439 if (left.id === "!") {
2440 warning("Confusing use of '{a}'.", left, "!");
2441 }
2442 if (right.id === "!") {
2443 warning("Confusing use of '{a}'.", right, "!");
2444 }
2445 this.left = left;
2446 this.right = right;
2447 return this;
2448 };
2449 return x;
2450 }
2451
2452
2453 function isPoorRelation(node) {
2454 return node &&
2455 ((node.type === "(number)" && +node.value === 0) ||
2456 (node.type === "(string)" && node.value === "") ||
2457 (node.type === "null" && !option.eqnull) ||
2458 node.type === "true" ||
2459 node.type === "false" ||
2460 node.type === "undefined");
2461 }
2462
2463
2464 function assignop(s) {
2465 symbol(s, 20).exps = true;
2466
2467 return infix(s, function (left, that) {
2468 that.left = left;
2469
2470 if (predefined[left.value] === false &&
2471 scope[left.value]["(global)"] === true) {
2472 warning("Read only.", left);
2473 } else if (left["function"]) {
2474 warning("'{a}' is a function.", left, left.value);
2475 }
2476
2477 if (left) {
2478 if (option.esnext && funct[left.value] === "const") {
2479 warning("Attempting to override '{a}' which is a constant", left, left.value);
2480 }
2481
2482 if (left.id === "." || left.id === "[") {
2483 if (!left.left || left.left.value === "arguments") {
2484 warning("Bad assignment.", that);
2485 }
2486 that.right = expression(19);
2487 return that;
2488 } else if (left.identifier && !left.reserved) {
2489 if (funct[left.value] === "exception") {
2490 warning("Do not assign to the exception parameter.", left);
2491 }
2492 that.right = expression(19);
2493 return that;
2494 }
2495
2496 if (left === syntax["function"]) {
2497 warning(
2498 "Expected an identifier in an assignment and instead saw a function invocation.",
2499 token);
2500 }
2501 }
2502
2503 error("Bad assignment.", that);
2504 }, 20);
2505 }
2506
2507
2508 function bitwise(s, f, p) {
2509 var x = symbol(s, p);
2510 reserveName(x);
2511 x.led = (typeof f === "function") ? f : function (left) {
2512 if (option.bitwise) {
2513 warning("Unexpected use of '{a}'.", this, this.id);
2514 }
2515 this.left = left;
2516 this.right = expression(p);
2517 return this;
2518 };
2519 return x;
2520 }
2521
2522
2523 function bitwiseassignop(s) {
2524 symbol(s, 20).exps = true;
2525 return infix(s, function (left, that) {
2526 if (option.bitwise) {
2527 warning("Unexpected use of '{a}'.", that, that.id);
2528 }
2529 nonadjacent(prevtoken, token);
2530 nonadjacent(token, nexttoken);
2531 if (left) {
2532 if (left.id === "." || left.id === "[" ||
2533 (left.identifier && !left.reserved)) {
2534 expression(19);
2535 return that;
2536 }
2537 if (left === syntax["function"]) {
2538 warning(
2539 "Expected an identifier in an assignment, and instead saw a function invocation.",
2540 token);
2541 }
2542 return that;
2543 }
2544 error("Bad assignment.", that);
2545 }, 20);
2546 }
2547
2548
2549 function suffix(s) {
2550 var x = symbol(s, 150);
2551 x.led = function (left) {
2552 if (option.plusplus) {
2553 warning("Unexpected use of '{a}'.", this, this.id);
2554 } else if ((!left.identifier || left.reserved) &&
2555 left.id !== "." && left.id !== "[") {
2556 warning("Bad operand.", this);
2557 }
2558 this.left = left;
2559 return this;
2560 };
2561 return x;
2562 }
2563
2564
2565 // fnparam means that this identifier is being defined as a function
2566 // argument (see identifier())
2567 function optionalidentifier(fnparam) {
2568 if (nexttoken.identifier) {
2569 advance();
2570 if (token.reserved && !option.es5) {
2571 // `undefined` as a function param is a common pattern to protect
2572 // against the case when somebody does `undefined = true` and
2573 // help with minification. More info: https://gist.github.com/315916
2574 if (!fnparam || token.value !== "undefined") {
2575 warning("Expected an identifier and instead saw '{a}' (a reserved word).",
2576 token, token.id);
2577 }
2578 }
2579 return token.value;
2580 }
2581 }
2582
2583 // fnparam means that this identifier is being defined as a function
2584 // argument
2585 function identifier(fnparam) {
2586 var i = optionalidentifier(fnparam);
2587 if (i) {
2588 return i;
2589 }
2590 if (token.id === "function" && nexttoken.id === "(") {
2591 warning("Missing name in function declaration.");
2592 } else {
2593 error("Expected an identifier and instead saw '{a}'.",
2594 nexttoken, nexttoken.value);
2595 }
2596 }
2597
2598
2599 function reachable(s) {
2600 var i = 0, t;
2601 if (nexttoken.id !== ";" || noreach) {
2602 return;
2603 }
2604 for (;;) {
2605 t = peek(i);
2606 if (t.reach) {
2607 return;
2608 }
2609 if (t.id !== "(endline)") {
2610 if (t.id === "function") {
2611 if (!option.latedef) {
2612 break;
2613 }
2614 warning(
2615 "Inner functions should be listed at the top of the outer function.", t);
2616 break;
2617 }
2618 warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
2619 break;
2620 }
2621 i += 1;
2622 }
2623 }
2624
2625
2626 function statement(noindent) {
2627 var i = indent, r, s = scope, t = nexttoken;
2628
2629 if (t.id === ";") {
2630 advance(";");
2631 return;
2632 }
2633
2634 // Is this a labelled statement?
2635
2636 if (t.identifier && !t.reserved && peek().id === ":") {
2637 advance();
2638 advance(":");
2639 scope = Object.create(s);
2640 addlabel(t.value, "label");
2641
2642 if (!nexttoken.labelled && nexttoken.value !== "{") {
2643 warning("Label '{a}' on {b} statement.", nexttoken, t.value, nexttoken.value);
2644 }
2645
2646 if (jx.test(t.value + ":")) {
2647 warning("Label '{a}' looks like a javascript url.", t, t.value);
2648 }
2649
2650 nexttoken.label = t.value;
2651 t = nexttoken;
2652 }
2653
2654 // Is it a lonely block?
2655
2656 if (t.id === "{") {
2657 block(true, true);
2658 return;
2659 }
2660
2661 // Parse the statement.
2662
2663 if (!noindent) {
2664 indentation();
2665 }
2666 r = expression(0, true);
2667
2668 // Look for the final semicolon.
2669
2670 if (!t.block) {
2671 if (!option.expr && (!r || !r.exps)) {
2672 warning("Expected an assignment or function call and instead saw an expression.",
2673 token);
2674 } else if (option.nonew && r.id === "(" && r.left.id === "new") {
2675 warning("Do not use 'new' for side effects.", t);
2676 }
2677
2678 if (nexttoken.id === ",") {
2679 return comma();
2680 }
2681
2682 if (nexttoken.id !== ";") {
2683 if (!option.asi) {
2684 // If this is the last statement in a block that ends on
2685 // the same line *and* option lastsemic is on, ignore the warning.
2686 // Otherwise, complain about missing semicolon.
2687 if (!option.lastsemic || nexttoken.id !== "}" ||
2688 nexttoken.line !== token.line) {
2689 warningAt("Missing semicolon.", token.line, token.character);
2690 }
2691 }
2692 } else {
2693 adjacent(token, nexttoken);
2694 advance(";");
2695 nonadjacent(token, nexttoken);
2696 }
2697 }
2698
2699 // Restore the indentation.
2700
2701 indent = i;
2702 scope = s;
2703 return r;
2704 }
2705
2706
2707 function statements(startLine) {
2708 var a = [], p;
2709
2710 while (!nexttoken.reach && nexttoken.id !== "(end)") {
2711 if (nexttoken.id === ";") {
2712 p = peek();
2713 if (!p || p.id !== "(") {
2714 warning("Unnecessary semicolon.");
2715 }
2716 advance(";");
2717 } else {
2718 a.push(statement(startLine === nexttoken.line));
2719 }
2720 }
2721 return a;
2722 }
2723
2724
2725 /*
2726 * read all directives
2727 * recognizes a simple form of asi, but always
2728 * warns, if it is used
2729 */
2730 function directives() {
2731 var i, p, pn;
2732
2733 for (;;) {
2734 if (nexttoken.id === "(string)") {
2735 p = peek(0);
2736 if (p.id === "(endline)") {
2737 i = 1;
2738 do {
2739 pn = peek(i);
2740 i = i + 1;
2741 } while (pn.id === "(endline)");
2742
2743 if (pn.id !== ";") {
2744 if (pn.id !== "(string)" && pn.id !== "(number)" &&
2745 pn.id !== "(regexp)" && pn.identifier !== true &&
2746 pn.id !== "}") {
2747 break;
2748 }
2749 warning("Missing semicolon.", nexttoken);
2750 } else {
2751 p = pn;
2752 }
2753 } else if (p.id === "}") {
2754 // directive with no other statements, warn about missing semicolon
2755 warning("Missing semicolon.", p);
2756 } else if (p.id !== ";") {
2757 break;
2758 }
2759
2760 indentation();
2761 advance();
2762 if (directive[token.value]) {
2763 warning("Unnecessary directive \"{a}\".", token, token.value);
2764 }
2765
2766 if (token.value === "use strict") {
2767 if (!option["(explicitNewcap)"])
2768 option.newcap = true;
2769 option.undef = true;
2770 }
2771
2772 // there's no directive negation, so always set to true
2773 directive[token.value] = true;
2774
2775 if (p.id === ";") {
2776 advance(";");
2777 }
2778 continue;
2779 }
2780 break;
2781 }
2782 }
2783
2784
2785 /*
2786 * Parses a single block. A block is a sequence of statements wrapped in
2787 * braces.
2788 *
2789 * ordinary - true for everything but function bodies and try blocks.
2790 * stmt - true if block can be a single statement (e.g. in if/for/while).
2791 * isfunc - true if block is a function body
2792 */
2793 function block(ordinary, stmt, isfunc) {
2794 var a,
2795 b = inblock,
2796 old_indent = indent,
2797 m,
2798 s = scope,
2799 t,
2800 line,
2801 d;
2802
2803 inblock = ordinary;
2804
2805 if (!ordinary || !option.funcscope)
2806 scope = Object.create(scope);
2807
2808 nonadjacent(token, nexttoken);
2809 t = nexttoken;
2810
2811 var metrics = funct["(metrics)"];
2812 metrics.nestedBlockDepth += 1;
2813 metrics.verifyMaxNestedBlockDepthPerFunction();
2814
2815 if (nexttoken.id === "{") {
2816 advance("{");
2817 line = token.line;
2818 if (nexttoken.id !== "}") {
2819 indent += option.indent;
2820 while (!ordinary && nexttoken.from > indent) {
2821 indent += option.indent;
2822 }
2823
2824 if (isfunc) {
2825 m = {};
2826 for (d in directive) {
2827 if (is_own(directive, d)) {
2828 m[d] = directive[d];
2829 }
2830 }
2831 directives();
2832
2833 if (option.strict && funct["(context)"]["(global)"]) {
2834 if (!m["use strict"] && !directive["use strict"]) {
2835 warning("Missing \"use strict\" statement.");
2836 }
2837 }
2838 }
2839
2840 a = statements(line);
2841
2842 metrics.statementCount += a.length;
2843
2844 if (isfunc) {
2845 directive = m;
2846 }
2847
2848 indent -= option.indent;
2849 if (line !== nexttoken.line) {
2850 indentation();
2851 }
2852 } else if (line !== nexttoken.line) {
2853 indentation();
2854 }
2855 advance("}", t);
2856 indent = old_indent;
2857 } else if (!ordinary) {
2858 error("Expected '{a}' and instead saw '{b}'.",
2859 nexttoken, "{", nexttoken.value);
2860 } else {
2861 if (!stmt || option.curly)
2862 warning("Expected '{a}' and instead saw '{b}'.",
2863 nexttoken, "{", nexttoken.value);
2864
2865 noreach = true;
2866 indent += option.indent;
2867 // test indentation only if statement is in new line
2868 a = [statement(nexttoken.line === token.line)];
2869 indent -= option.indent;
2870 noreach = false;
2871 }
2872 funct["(verb)"] = null;
2873 if (!ordinary || !option.funcscope) scope = s;
2874 inblock = b;
2875 if (ordinary && option.noempty && (!a || a.length === 0)) {
2876 warning("Empty block.");
2877 }
2878 metrics.nestedBlockDepth -= 1;
2879 return a;
2880 }
2881
2882
2883 function countMember(m) {
2884 if (membersOnly && typeof membersOnly[m] !== "boolean") {
2885 warning("Unexpected /*member '{a}'.", token, m);
2886 }
2887 if (typeof member[m] === "number") {
2888 member[m] += 1;
2889 } else {
2890 member[m] = 1;
2891 }
2892 }
2893
2894
2895 function note_implied(token) {
2896 var name = token.value, line = token.line, a = implied[name];
2897 if (typeof a === "function") {
2898 a = false;
2899 }
2900
2901 if (!a) {
2902 a = [line];
2903 implied[name] = a;
2904 } else if (a[a.length - 1] !== line) {
2905 a.push(line);
2906 }
2907 }
2908
2909
2910 // Build the syntax table by declaring the syntactic elements of the language.
2911
2912 type("(number)", function () {
2913 return this;
2914 });
2915
2916 type("(string)", function () {
2917 return this;
2918 });
2919
2920 syntax["(identifier)"] = {
2921 type: "(identifier)",
2922 lbp: 0,
2923 identifier: true,
2924 nud: function () {
2925 var v = this.value,
2926 s = scope[v],
2927 f;
2928
2929 if (typeof s === "function") {
2930 // Protection against accidental inheritance.
2931 s = undefined;
2932 } else if (typeof s === "boolean") {
2933 f = funct;
2934 funct = functions[0];
2935 addlabel(v, "var");
2936 s = funct;
2937 funct = f;
2938 }
2939
2940 // The name is in scope and defined in the current function.
2941 if (funct === s) {
2942 // Change 'unused' to 'var', and reject labels.
2943 switch (funct[v]) {
2944 case "unused":
2945 funct[v] = "var";
2946 break;
2947 case "unction":
2948 funct[v] = "function";
2949 this["function"] = true;
2950 break;
2951 case "function":
2952 this["function"] = true;
2953 break;
2954 case "label":
2955 warning("'{a}' is a statement label.", token, v);
2956 break;
2957 }
2958 } else if (funct["(global)"]) {
2959 // The name is not defined in the function. If we are in the global
2960 // scope, then we have an undefined variable.
2961 //
2962 // Operators typeof and delete do not raise runtime errors even if
2963 // the base object of a reference is null so no need to display warning
2964 // if we're inside of typeof or delete.
2965
2966 if (option.undef && typeof predefined[v] !== "boolean") {
2967 // Attempting to subscript a null reference will throw an
2968 // error, even within the typeof and delete operators
2969 if (!(anonname === "typeof" || anonname === "delete") ||
2970 (nexttoken && (nexttoken.value === "." || nexttoken.value === "["))) {
2971
2972 isundef(funct, "'{a}' is not defined.", token, v);
2973 }
2974 }
2975
2976 note_implied(token);
2977 } else {
2978 // If the name is already defined in the current
2979 // function, but not as outer, then there is a scope error.
2980
2981 switch (funct[v]) {
2982 case "closure":
2983 case "function":
2984 case "var":
2985 case "unused":
2986 warning("'{a}' used out of scope.", token, v);
2987 break;
2988 case "label":
2989 warning("'{a}' is a statement label.", token, v);
2990 break;
2991 case "outer":
2992 case "global":
2993 break;
2994 default:
2995 // If the name is defined in an outer function, make an outer entry,
2996 // and if it was unused, make it var.
2997 if (s === true) {
2998 funct[v] = true;
2999 } else if (s === null) {
3000 warning("'{a}' is not allowed.", token, v);
3001 note_implied(token);
3002 } else if (typeof s !== "object") {
3003 // Operators typeof and delete do not raise runtime errors even
3004 // if the base object of a reference is null so no need to
3005 // display warning if we're inside of typeof or delete.
3006 if (option.undef) {
3007 // Attempting to subscript a null reference will throw an
3008 // error, even within the typeof and delete operators
3009 if (!(anonname === "typeof" || anonname === "delete") ||
3010 (nexttoken &&
3011 (nexttoken.value === "." || nexttoken.value === "["))) {
3012
3013 isundef(funct, "'{a}' is not defined.", token, v);
3014 }
3015 }
3016 funct[v] = true;
3017 note_implied(token);
3018 } else {
3019 switch (s[v]) {
3020 case "function":
3021 case "unction":
3022 this["function"] = true;
3023 s[v] = "closure";
3024 funct[v] = s["(global)"] ? "global" : "outer";
3025 break;
3026 case "var":
3027 case "unused":
3028 s[v] = "closure";
3029 funct[v] = s["(global)"] ? "global" : "outer";
3030 break;
3031 case "closure":
3032 funct[v] = s["(global)"] ? "global" : "outer";
3033 break;
3034 case "label":
3035 warning("'{a}' is a statement label.", token, v);
3036 }
3037 }
3038 }
3039 }
3040 return this;
3041 },
3042 led: function () {
3043 error("Expected an operator and instead saw '{a}'.",
3044 nexttoken, nexttoken.value);
3045 }
3046 };
3047
3048 type("(regexp)", function () {
3049 return this;
3050 });
3051
3052
3053 // ECMAScript parser
3054
3055 delim("(endline)");
3056 delim("(begin)");
3057 delim("(end)").reach = true;
3058 delim("</").reach = true;
3059 delim("<!");
3060 delim("<!--");
3061 delim("-->");
3062 delim("(error)").reach = true;
3063 delim("}").reach = true;
3064 delim(")");
3065 delim("]");
3066 delim("\"").reach = true;
3067 delim("'").reach = true;
3068 delim(";");
3069 delim(":").reach = true;
3070 delim(",");
3071 delim("#");
3072 delim("@");
3073 reserve("else");
3074 reserve("case").reach = true;
3075 reserve("catch");
3076 reserve("default").reach = true;
3077 reserve("finally");
3078 reservevar("arguments", function (x) {
3079 if (directive["use strict"] && funct["(global)"]) {
3080 warning("Strict violation.", x);
3081 }
3082 });
3083 reservevar("eval");
3084 reservevar("false");
3085 reservevar("Infinity");
3086 reservevar("null");
3087 reservevar("this", function (x) {
3088 if (directive["use strict"] && !option.validthis && ((funct["(statement)"] &&
3089 funct["(name)"].charAt(0) > "Z") || funct["(global)"])) {
3090 warning("Possible strict violation.", x);
3091 }
3092 });
3093 reservevar("true");
3094 reservevar("undefined");
3095 assignop("=", "assign", 20);
3096 assignop("+=", "assignadd", 20);
3097 assignop("-=", "assignsub", 20);
3098 assignop("*=", "assignmult", 20);
3099 assignop("/=", "assigndiv", 20).nud = function () {
3100 error("A regular expression literal can be confused with '/='.");
3101 };
3102 assignop("%=", "assignmod", 20);
3103 bitwiseassignop("&=", "assignbitand", 20);
3104 bitwiseassignop("|=", "assignbitor", 20);
3105 bitwiseassignop("^=", "assignbitxor", 20);
3106 bitwiseassignop("<<=", "assignshiftleft", 20);
3107 bitwiseassignop(">>=", "assignshiftright", 20);
3108 bitwiseassignop(">>>=", "assignshiftrightunsigned", 20);
3109 infix("?", function (left, that) {
3110 that.left = left;
3111 that.right = expression(10);
3112 advance(":");
3113 that["else"] = expression(10);
3114 return that;
3115 }, 30);
3116
3117 infix("||", "or", 40);
3118 infix("&&", "and", 50);
3119 bitwise("|", "bitor", 70);
3120 bitwise("^", "bitxor", 80);
3121 bitwise("&", "bitand", 90);
3122 relation("==", function (left, right) {
3123 var eqnull = option.eqnull && (left.value === "null" || right.value === "null");
3124
3125 if (!eqnull && option.eqeqeq)
3126 warning("Expected '{a}' and instead saw '{b}'.", this, "===", "==");
3127 else if (isPoorRelation(left))
3128 warning("Use '{a}' to compare with '{b}'.", this, "===", left.value);
3129 else if (isPoorRelation(right))
3130 warning("Use '{a}' to compare with '{b}'.", this, "===", right.value);
3131
3132 return this;
3133 });
3134 relation("===");
3135 relation("!=", function (left, right) {
3136 var eqnull = option.eqnull &&
3137 (left.value === "null" || right.value === "null");
3138
3139 if (!eqnull && option.eqeqeq) {
3140 warning("Expected '{a}' and instead saw '{b}'.",
3141 this, "!==", "!=");
3142 } else if (isPoorRelation(left)) {
3143 warning("Use '{a}' to compare with '{b}'.",
3144 this, "!==", left.value);
3145 } else if (isPoorRelation(right)) {
3146 warning("Use '{a}' to compare with '{b}'.",
3147 this, "!==", right.value);
3148 }
3149 return this;
3150 });
3151 relation("!==");
3152 relation("<");
3153 relation(">");
3154 relation("<=");
3155 relation(">=");
3156 bitwise("<<", "shiftleft", 120);
3157 bitwise(">>", "shiftright", 120);
3158 bitwise(">>>", "shiftrightunsigned", 120);
3159 infix("in", "in", 120);
3160 infix("instanceof", "instanceof", 120);
3161 infix("+", function (left, that) {
3162 var right = expression(130);
3163 if (left && right && left.id === "(string)" && right.id === "(string)") {
3164 left.value += right.value;
3165 left.character = right.character;
3166 if (!option.scripturl && jx.test(left.value)) {
3167 warning("JavaScript URL.", left);
3168 }
3169 return left;
3170 }
3171 that.left = left;
3172 that.right = right;
3173 return that;
3174 }, 130);
3175 prefix("+", "num");
3176 prefix("+++", function () {
3177 warning("Confusing pluses.");
3178 this.right = expression(150);
3179 this.arity = "unary";
3180 return this;
3181 });
3182 infix("+++", function (left) {
3183 warning("Confusing pluses.");
3184 this.left = left;
3185 this.right = expression(130);
3186 return this;
3187 }, 130);
3188 infix("-", "sub", 130);
3189 prefix("-", "neg");
3190 prefix("---", function () {
3191 warning("Confusing minuses.");
3192 this.right = expression(150);
3193 this.arity = "unary";
3194 return this;
3195 });
3196 infix("---", function (left) {
3197 warning("Confusing minuses.");
3198 this.left = left;
3199 this.right = expression(130);
3200 return this;
3201 }, 130);
3202 infix("*", "mult", 140);
3203 infix("/", "div", 140);
3204 infix("%", "mod", 140);
3205
3206 suffix("++", "postinc");
3207 prefix("++", "preinc");
3208 syntax["++"].exps = true;
3209
3210 suffix("--", "postdec");
3211 prefix("--", "predec");
3212 syntax["--"].exps = true;
3213 prefix("delete", function () {
3214 var p = expression(0);
3215 if (!p || (p.id !== "." && p.id !== "[")) {
3216 warning("Variables should not be deleted.");
3217 }
3218 this.first = p;
3219 return this;
3220 }).exps = true;
3221
3222 prefix("~", function () {
3223 if (option.bitwise) {
3224 warning("Unexpected '{a}'.", this, "~");
3225 }
3226 expression(150);
3227 return this;
3228 });
3229
3230 prefix("!", function () {
3231 this.right = expression(150);
3232 this.arity = "unary";
3233 if (bang[this.right.id] === true) {
3234 warning("Confusing use of '{a}'.", this, "!");
3235 }
3236 return this;
3237 });
3238 prefix("typeof", "typeof");
3239 prefix("new", function () {
3240 var c = expression(155), i;
3241 if (c && c.id !== "function") {
3242 if (c.identifier) {
3243 c["new"] = true;
3244 switch (c.value) {
3245 case "Number":
3246 case "String":
3247 case "Boolean":
3248 case "Math":
3249 case "JSON":
3250 warning("Do not use {a} as a constructor.", prevtoken, c.value);
3251 break;
3252 case "Function":
3253 if (!option.evil) {
3254 warning("The Function constructor is eval.");
3255 }
3256 break;
3257 case "Date":
3258 case "RegExp":
3259 break;
3260 default:
3261 if (c.id !== "function") {
3262 i = c.value.substr(0, 1);
3263 if (option.newcap && (i < "A" || i > "Z") && !is_own(global, c.value)) {
3264 warning("A constructor name should start with an uppercase letter.",
3265 token);
3266 }
3267 }
3268 }
3269 } else {
3270 if (c.id !== "." && c.id !== "[" && c.id !== "(") {
3271 warning("Bad constructor.", token);
3272 }
3273 }
3274 } else {
3275 if (!option.supernew)
3276 warning("Weird construction. Delete 'new'.", this);
3277 }
3278 adjacent(token, nexttoken);
3279 if (nexttoken.id !== "(" && !option.supernew) {
3280 warning("Missing '()' invoking a constructor.",
3281 token, token.value);
3282 }
3283 this.first = c;
3284 return this;
3285 });
3286 syntax["new"].exps = true;
3287
3288 prefix("void").exps = true;
3289
3290 infix(".", function (left, that) {
3291 adjacent(prevtoken, token);
3292 nobreak();
3293 var m = identifier();
3294 if (typeof m === "string") {
3295 countMember(m);
3296 }
3297 that.left = left;
3298 that.right = m;
3299 if (left && left.value === "arguments" && (m === "callee" || m === "caller")) {
3300 if (option.noarg)
3301 warning("Avoid arguments.{a}.", left, m);
3302 else if (directive["use strict"])
3303 error("Strict violation.");
3304 } else if (!option.evil && left && left.value === "document" &&
3305 (m === "write" || m === "writeln")) {
3306 warning("document.write can be a form of eval.", left);
3307 }
3308 if (!option.evil && (m === "eval" || m === "execScript")) {
3309 warning("eval is evil.");
3310 }
3311 return that;
3312 }, 160, true);
3313
3314 infix("(", function (left, that) {
3315 if (prevtoken.id !== "}" && prevtoken.id !== ")") {
3316 nobreak(prevtoken, token);
3317 }
3318 nospace();
3319 if (option.immed && !left.immed && left.id === "function") {
3320 warning("Wrap an immediate function invocation in parentheses " +
3321 "to assist the reader in understanding that the expression " +
3322 "is the result of a function, and not the function itself.");
3323 }
3324 var n = 0,
3325 p = [];
3326 if (left) {
3327 if (left.type === "(identifier)") {
3328 if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
3329 if ("Number String Boolean Date Object".indexOf(left.value) === -1) {
3330 if (left.value === "Math") {
3331 warning("Math is not a function.", left);
3332 } else if (option.newcap) {
3333 warning("Missing 'new' prefix when invoking a constructor.", left);
3334 }
3335 }
3336 }
3337 }
3338 }
3339 if (nexttoken.id !== ")") {
3340 for (;;) {
3341 p[p.length] = expression(10);
3342 n += 1;
3343 if (nexttoken.id !== ",") {
3344 break;
3345 }
3346 comma();
3347 }
3348 }
3349 advance(")");
3350 nospace(prevtoken, token);
3351 if (typeof left === "object") {
3352 if (left.value === "parseInt" && n === 1) {
3353 warning("Missing radix parameter.", token);
3354 }
3355 if (!option.evil) {
3356 if (left.value === "eval" || left.value === "Function" ||
3357 left.value === "execScript") {
3358 warning("eval is evil.", left);
3359
3360 if (p[0] && [0].id === "(string)") {
3361 addInternalSrc(left, p[0].value);
3362 }
3363 } else if (p[0] && p[0].id === "(string)" &&
3364 (left.value === "setTimeout" ||
3365 left.value === "setInterval")) {
3366 warning(
3367 "Implied eval is evil. Pass a function instead of a string.", left);
3368 addInternalSrc(left, p[0].value);
3369
3370 // window.setTimeout/setInterval
3371 } else if (p[0] && p[0].id === "(string)" &&
3372 left.value === "." &&
3373 left.left.value === "window" &&
3374 (left.right === "setTimeout" ||
3375 left.right === "setInterval")) {
3376 warning(
3377 "Implied eval is evil. Pass a function instead of a string.", left);
3378 addInternalSrc(left, p[0].value);
3379 }
3380 }
3381 if (!left.identifier && left.id !== "." && left.id !== "[" &&
3382 left.id !== "(" && left.id !== "&&" && left.id !== "||" &&
3383 left.id !== "?") {
3384 warning("Bad invocation.", left);
3385 }
3386 }
3387 that.left = left;
3388 return that;
3389 }, 155, true).exps = true;
3390
3391 prefix("(", function () {
3392 nospace();
3393 if (nexttoken.id === "function") {
3394 nexttoken.immed = true;
3395 }
3396 var v = expression(0);
3397 advance(")", this);
3398 nospace(prevtoken, token);
3399 if (option.immed && v.id === "function") {
3400 if (nexttoken.id !== "(" &&
3401 (nexttoken.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) {
3402 warning(
3403 "Do not wrap function literals in parens unless they are to be immediately invoked.",
3404 this);
3405 }
3406 }
3407
3408 return v;
3409 });
3410
3411 infix("[", function (left, that) {
3412 nobreak(prevtoken, token);
3413 nospace();
3414 var e = expression(0), s;
3415 if (e && e.type === "(string)") {
3416 if (!option.evil && (e.value === "eval" || e.value === "execScript")) {
3417 warning("eval is evil.", that);
3418 }
3419 countMember(e.value);
3420 if (!option.sub && ix.test(e.value)) {
3421 s = syntax[e.value];
3422 if (!s || !s.reserved) {
3423 warning("['{a}'] is better written in dot notation.",
3424 prevtoken, e.value);
3425 }
3426 }
3427 }
3428 advance("]", that);
3429 nospace(prevtoken, token);
3430 that.left = left;
3431 that.right = e;
3432 return that;
3433 }, 160, true);
3434
3435 prefix("[", function () {
3436 var b = token.line !== nexttoken.line;
3437 this.first = [];
3438 if (b) {
3439 indent += option.indent;
3440 if (nexttoken.from === indent + option.indent) {
3441 indent += option.indent;
3442 }
3443 }
3444 while (nexttoken.id !== "(end)") {
3445 while (nexttoken.id === ",") {
3446 if (!option.es5)
3447 warning("Extra comma.");
3448 advance(",");
3449 }
3450 if (nexttoken.id === "]") {
3451 break;
3452 }
3453 if (b && token.line !== nexttoken.line) {
3454 indentation();
3455 }
3456 this.first.push(expression(10));
3457 if (nexttoken.id === ",") {
3458 comma();
3459 if (nexttoken.id === "]" && !option.es5) {
3460 warning("Extra comma.", token);
3461 break;
3462 }
3463 } else {
3464 break;
3465 }
3466 }
3467 if (b) {
3468 indent -= option.indent;
3469 indentation();
3470 }
3471 advance("]", this);
3472 return this;
3473 }, 160);
3474
3475
3476 function property_name() {
3477 var id = optionalidentifier(true);
3478 if (!id) {
3479 if (nexttoken.id === "(string)") {
3480 id = nexttoken.value;
3481 advance();
3482 } else if (nexttoken.id === "(number)") {
3483 id = nexttoken.value.toString();
3484 advance();
3485 }
3486 }
3487 return id;
3488 }
3489
3490
3491 function functionparams() {
3492 var next = nexttoken;
3493 var params = [];
3494 var ident;
3495
3496 advance("(");
3497 nospace();
3498
3499 if (nexttoken.id === ")") {
3500 advance(")");
3501 return;
3502 }
3503
3504 for (;;) {
3505 ident = identifier(true);
3506 params.push(ident);
3507 addlabel(ident, "unused", token);
3508 if (nexttoken.id === ",") {
3509 comma();
3510 } else {
3511 advance(")", next);
3512 nospace(prevtoken, token);
3513 return params;
3514 }
3515 }
3516 }
3517
3518
3519 function doFunction(name, statement) {
3520 var f;
3521 var oldOption = option;
3522 var oldScope = scope;
3523
3524 option = Object.create(option);
3525 scope = Object.create(scope);
3526
3527 funct = {
3528 "(name)" : name || "\"" + anonname + "\"",
3529 "(line)" : nexttoken.line,
3530 "(character)": nexttoken.character,
3531 "(context)" : funct,
3532 "(breakage)" : 0,
3533 "(loopage)" : 0,
3534 "(metrics)" : createMetrics(nexttoken),
3535 "(scope)" : scope,
3536 "(statement)": statement,
3537 "(tokens)" : {}
3538 };
3539
3540 f = funct;
3541 token.funct = funct;
3542
3543 functions.push(funct);
3544
3545 if (name) {
3546 addlabel(name, "function");
3547 }
3548
3549 funct["(params)"] = functionparams();
3550 funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]);
3551
3552 block(false, false, true);
3553
3554 funct["(metrics)"].verifyMaxStatementsPerFunction();
3555 funct["(metrics)"].verifyMaxComplexityPerFunction();
3556
3557 scope = oldScope;
3558 option = oldOption;
3559 funct["(last)"] = token.line;
3560 funct["(lastcharacter)"] = token.character;
3561 funct = funct["(context)"];
3562
3563 return f;
3564 }
3565
3566 function createMetrics(functionStartToken) {
3567 return {
3568 statementCount: 0,
3569 nestedBlockDepth: -1,
3570 ComplexityCount: 1,
3571 verifyMaxStatementsPerFunction: function () {
3572 if (option.maxstatements &&
3573 this.statementCount > option.maxstatements) {
3574 var message = "Too many statements per function (" + this.statementCount + ").";
3575 warning(message, functionStartToken);
3576 }
3577 },
3578
3579 verifyMaxParametersPerFunction: function (params) {
3580 params = params || [];
3581
3582 if (option.maxparams && params.length > option.maxparams) {
3583 var message = "Too many parameters per function (" + params.length + ").";
3584 warning(message, functionStartToken);
3585 }
3586 },
3587
3588 verifyMaxNestedBlockDepthPerFunction: function () {
3589 if (option.maxdepth &&
3590 this.nestedBlockDepth > 0 &&
3591 this.nestedBlockDepth === option.maxdepth + 1) {
3592 var message = "Blocks are nested too deeply (" + this.nestedBlockDepth + ").";
3593 warning(message);
3594 }
3595 },
3596
3597 verifyMaxComplexityPerFunction: function () {
3598 var max = option.maxcomplexity;
3599 var cc = this.ComplexityCount;
3600 if (max && cc > max) {
3601 var message = "Cyclomatic complexity is too high per function (" + cc + ").";
3602 warning(message, functionStartToken);
3603 }
3604 }
3605 };
3606 }
3607
3608 function increaseComplexityCount() {
3609 funct["(metrics)"].ComplexityCount += 1;
3610 }
3611
3612
3613 (function (x) {
3614 x.nud = function () {
3615 var b, f, i, p, t;
3616 var props = {}; // All properties, including accessors
3617
3618 function saveProperty(name, token) {
3619 if (props[name] && is_own(props, name))
3620 warning("Duplicate member '{a}'.", nexttoken, i);
3621 else
3622 props[name] = {};
3623
3624 props[name].basic = true;
3625 props[name].basicToken = token;
3626 }
3627
3628 function saveSetter(name, token) {
3629 if (props[name] && is_own(props, name)) {
3630 if (props[name].basic || props[name].setter)
3631 warning("Duplicate member '{a}'.", nexttoken, i);
3632 } else {
3633 props[name] = {};
3634 }
3635
3636 props[name].setter = true;
3637 props[name].setterToken = token;
3638 }
3639
3640 function saveGetter(name) {
3641 if (props[name] && is_own(props, name)) {
3642 if (props[name].basic || props[name].getter)
3643 warning("Duplicate member '{a}'.", nexttoken, i);
3644 } else {
3645 props[name] = {};
3646 }
3647
3648 props[name].getter = true;
3649 props[name].getterToken = token;
3650 }
3651
3652 b = token.line !== nexttoken.line;
3653 if (b) {
3654 indent += option.indent;
3655 if (nexttoken.from === indent + option.indent) {
3656 indent += option.indent;
3657 }
3658 }
3659 for (;;) {
3660 if (nexttoken.id === "}") {
3661 break;
3662 }
3663 if (b) {
3664 indentation();
3665 }
3666 if (nexttoken.value === "get" && peek().id !== ":") {
3667 advance("get");
3668 if (!option.es5) {
3669 error("get/set are ES5 features.");
3670 }
3671 i = property_name();
3672 if (!i) {
3673 error("Missing property name.");
3674 }
3675 saveGetter(i);
3676 t = nexttoken;
3677 adjacent(token, nexttoken);
3678 f = doFunction();
3679 p = f["(params)"];
3680 if (p) {
3681 warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
3682 }
3683 adjacent(token, nexttoken);
3684 } else if (nexttoken.value === "set" && peek().id !== ":") {
3685 advance("set");
3686 if (!option.es5) {
3687 error("get/set are ES5 features.");
3688 }
3689 i = property_name();
3690 if (!i) {
3691 error("Missing property name.");
3692 }
3693 saveSetter(i, nexttoken);
3694 t = nexttoken;
3695 adjacent(token, nexttoken);
3696 f = doFunction();
3697 p = f["(params)"];
3698 if (!p || p.length !== 1) {
3699 warning("Expected a single parameter in set {a} function.", t, i);
3700 }
3701 } else {
3702 i = property_name();
3703 saveProperty(i, nexttoken);
3704 if (typeof i !== "string") {
3705 break;
3706 }
3707 advance(":");
3708 nonadjacent(token, nexttoken);
3709 expression(10);
3710 }
3711
3712 countMember(i);
3713 if (nexttoken.id === ",") {
3714 comma();
3715 if (nexttoken.id === ",") {
3716 warning("Extra comma.", token);
3717 } else if (nexttoken.id === "}" && !option.es5) {
3718 warning("Extra comma.", token);
3719 }
3720 } else {
3721 break;
3722 }
3723 }
3724 if (b) {
3725 indent -= option.indent;
3726 indentation();
3727 }
3728 advance("}", this);
3729
3730 // Check for lonely setters if in the ES5 mode.
3731 if (option.es5) {
3732 for (var name in props) {
3733 if (is_own(props, name) && props[name].setter && !props[name].getter) {
3734 warning("Setter is defined without getter.", props[name].setterToken);
3735 }
3736 }
3737 }
3738 return this;
3739 };
3740 x.fud = function () {
3741 error("Expected to see a statement and instead saw a block.", token);
3742 };
3743 }(delim("{")));
3744
3745 // This Function is called when esnext option is set to true
3746 // it adds the `const` statement to JSHINT
3747
3748 useESNextSyntax = function () {
3749 var conststatement = stmt("const", function (prefix) {
3750 var id, name, value;
3751
3752 this.first = [];
3753 for (;;) {
3754 nonadjacent(token, nexttoken);
3755 id = identifier();
3756 if (funct[id] === "const") {
3757 warning("const '" + id + "' has already been declared");
3758 }
3759 if (funct["(global)"] && predefined[id] === false) {
3760 warning("Redefinition of '{a}'.", token, id);
3761 }
3762 addlabel(id, "const");
3763 if (prefix) {
3764 break;
3765 }
3766 name = token;
3767 this.first.push(token);
3768
3769 if (nexttoken.id !== "=") {
3770 warning("const " +
3771 "'{a}' is initialized to 'undefined'.", token, id);
3772 }
3773
3774 if (nexttoken.id === "=") {
3775 nonadjacent(token, nexttoken);
3776 advance("=");
3777 nonadjacent(token, nexttoken);
3778 if (nexttoken.id === "undefined") {
3779 warning("It is not necessary to initialize " +
3780 "'{a}' to 'undefined'.", token, id);
3781 }
3782 if (peek(0).id === "=" && nexttoken.identifier) {
3783 error("Constant {a} was not declared correctly.",
3784 nexttoken, nexttoken.value);
3785 }
3786 value = expression(0);
3787 name.first = value;
3788 }
3789
3790 if (nexttoken.id !== ",") {
3791 break;
3792 }
3793 comma();
3794 }
3795 return this;
3796 });
3797 conststatement.exps = true;
3798 };
3799
3800 var varstatement = stmt("var", function (prefix) {
3801 // JavaScript does not have block scope. It only has function scope. So,
3802 // declaring a variable in a block can have unexpected consequences.
3803 var id, name, value;
3804
3805 if (funct["(onevar)"] && option.onevar) {
3806 warning("Too many var statements.");
3807 } else if (!funct["(global)"]) {
3808 funct["(onevar)"] = true;
3809 }
3810
3811 this.first = [];
3812
3813 for (;;) {
3814 nonadjacent(token, nexttoken);
3815 id = identifier();
3816
3817 if (option.esnext && funct[id] === "const") {
3818 warning("const '" + id + "' has already been declared");
3819 }
3820
3821 if (funct["(global)"] && predefined[id] === false) {
3822 warning("Redefinition of '{a}'.", token, id);
3823 }
3824
3825 addlabel(id, "unused", token);
3826
3827 if (prefix) {
3828 break;
3829 }
3830
3831 name = token;
3832 this.first.push(token);
3833
3834 if (nexttoken.id === "=") {
3835 nonadjacent(token, nexttoken);
3836 advance("=");
3837 nonadjacent(token, nexttoken);
3838 if (nexttoken.id === "undefined") {
3839 warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
3840 }
3841 if (peek(0).id === "=" && nexttoken.identifier) {
3842 error("Variable {a} was not declared correctly.",
3843 nexttoken, nexttoken.value);
3844 }
3845 value = expression(0);
3846 name.first = value;
3847 }
3848 if (nexttoken.id !== ",") {
3849 break;
3850 }
3851 comma();
3852 }
3853 return this;
3854 });
3855 varstatement.exps = true;
3856
3857 blockstmt("function", function () {
3858 if (inblock) {
3859 warning("Function declarations should not be placed in blocks. " +
3860 "Use a function expression or move the statement to the top of " +
3861 "the outer function.", token);
3862
3863 }
3864 var i = identifier();
3865 if (option.esnext && funct[i] === "const") {
3866 warning("const '" + i + "' has already been declared");
3867 }
3868 adjacent(token, nexttoken);
3869 addlabel(i, "unction", token);
3870
3871 doFunction(i, { statement: true });
3872 if (nexttoken.id === "(" && nexttoken.line === token.line) {
3873 error(
3874 "Function declarations are not invocable. Wrap the whole function invocation in parens.");
3875 }
3876 return this;
3877 });
3878
3879 prefix("function", function () {
3880 var i = optionalidentifier();
3881 if (i) {
3882 adjacent(token, nexttoken);
3883 } else {
3884 nonadjacent(token, nexttoken);
3885 }
3886 doFunction(i);
3887 if (!option.loopfunc && funct["(loopage)"]) {
3888 warning("Don't make functions within a loop.");
3889 }
3890 return this;
3891 });
3892
3893 blockstmt("if", function () {
3894 var t = nexttoken;
3895 increaseComplexityCount();
3896 advance("(");
3897 nonadjacent(this, t);
3898 nospace();
3899 expression(20);
3900 if (nexttoken.id === "=") {
3901 if (!option.boss)
3902 warning("Expected a conditional expression and instead saw an assignment.");
3903 advance("=");
3904 expression(20);
3905 }
3906 advance(")", t);
3907 nospace(prevtoken, token);
3908 block(true, true);
3909 if (nexttoken.id === "else") {
3910 nonadjacent(token, nexttoken);
3911 advance("else");
3912 if (nexttoken.id === "if" || nexttoken.id === "switch") {
3913 statement(true);
3914 } else {
3915 block(true, true);
3916 }
3917 }
3918 return this;
3919 });
3920
3921 blockstmt("try", function () {
3922 var b;
3923
3924 function doCatch() {
3925 var oldScope = scope;
3926 var e;
3927
3928 advance("catch");
3929 nonadjacent(token, nexttoken);
3930 advance("(");
3931
3932 scope = Object.create(oldScope);
3933
3934 e = nexttoken.value;
3935 if (nexttoken.type !== "(identifier)") {
3936 e = null;
3937 warning("Expected an identifier and instead saw '{a}'.", nexttoken, e);
3938 }
3939
3940 advance();
3941 advance(")");
3942
3943 funct = {
3944 "(name)" : "(catch)",
3945 "(line)" : nexttoken.line,
3946 "(character)": nexttoken.character,
3947 "(context)" : funct,
3948 "(breakage)" : funct["(breakage)"],
3949 "(loopage)" : funct["(loopage)"],
3950 "(scope)" : scope,
3951 "(statement)": false,
3952 "(metrics)" : createMetrics(nexttoken),
3953 "(catch)" : true,
3954 "(tokens)" : {}
3955 };
3956
3957 if (e) {
3958 addlabel(e, "exception");
3959 }
3960
3961 token.funct = funct;
3962 functions.push(funct);
3963
3964 block(false);
3965
3966 scope = oldScope;
3967
3968 funct["(last)"] = token.line;
3969 funct["(lastcharacter)"] = token.character;
3970 funct = funct["(context)"];
3971 }
3972
3973 block(false);
3974
3975 if (nexttoken.id === "catch") {
3976 increaseComplexityCount();
3977 doCatch();
3978 b = true;
3979 }
3980
3981 if (nexttoken.id === "finally") {
3982 advance("finally");
3983 block(false);
3984 return;
3985 } else if (!b) {
3986 error("Expected '{a}' and instead saw '{b}'.",
3987 nexttoken, "catch", nexttoken.value);
3988 }
3989
3990 return this;
3991 });
3992
3993 blockstmt("while", function () {
3994 var t = nexttoken;
3995 funct["(breakage)"] += 1;
3996 funct["(loopage)"] += 1;
3997 increaseComplexityCount();
3998 advance("(");
3999 nonadjacent(this, t);
4000 nospace();
4001 expression(20);
4002 if (nexttoken.id === "=") {
4003 if (!option.boss)
4004 warning("Expected a conditional expression and instead saw an assignment.");
4005 advance("=");
4006 expression(20);
4007 }
4008 advance(")", t);
4009 nospace(prevtoken, token);
4010 block(true, true);
4011 funct["(breakage)"] -= 1;
4012 funct["(loopage)"] -= 1;
4013 return this;
4014 }).labelled = true;
4015
4016 blockstmt("with", function () {
4017 var t = nexttoken;
4018 if (directive["use strict"]) {
4019 error("'with' is not allowed in strict mode.", token);
4020 } else if (!option.withstmt) {
4021 warning("Don't use 'with'.", token);
4022 }
4023
4024 advance("(");
4025 nonadjacent(this, t);
4026 nospace();
4027 expression(0);
4028 advance(")", t);
4029 nospace(prevtoken, token);
4030 block(true, true);
4031
4032 return this;
4033 });
4034
4035 blockstmt("switch", function () {
4036 var t = nexttoken,
4037 g = false;
4038 funct["(breakage)"] += 1;
4039 advance("(");
4040 nonadjacent(this, t);
4041 nospace();
4042 this.condition = expression(20);
4043 advance(")", t);
4044 nospace(prevtoken, token);
4045 nonadjacent(token, nexttoken);
4046 t = nexttoken;
4047 advance("{");
4048 nonadjacent(token, nexttoken);
4049 indent += option.indent;
4050 this.cases = [];
4051 for (;;) {
4052 switch (nexttoken.id) {
4053 case "case":
4054 switch (funct["(verb)"]) {
4055 case "break":
4056 case "case":
4057 case "continue":
4058 case "return":
4059 case "switch":
4060 case "throw":
4061 break;
4062 default:
4063 // You can tell JSHint that you don't use break intentionally by
4064 // adding a comment /* falls through */ on a line just before
4065 // the next `case`.
4066 if (!ft.test(lines[nexttoken.line - 2])) {
4067 warning(
4068 "Expected a 'break' statement before 'case'.",
4069 token);
4070 }
4071 }
4072 indentation(-option.indent);
4073 advance("case");
4074 this.cases.push(expression(20));
4075 increaseComplexityCount();
4076 g = true;
4077 advance(":");
4078 funct["(verb)"] = "case";
4079 break;
4080 case "default":
4081 switch (funct["(verb)"]) {
4082 case "break":
4083 case "continue":
4084 case "return":
4085 case "throw":
4086 break;
4087 default:
4088 if (!ft.test(lines[nexttoken.line - 2])) {
4089 warning(
4090 "Expected a 'break' statement before 'default'.",
4091 token);
4092 }
4093 }
4094 indentation(-option.indent);
4095 advance("default");
4096 g = true;
4097 advance(":");
4098 break;
4099 case "}":
4100 indent -= option.indent;
4101 indentation();
4102 advance("}", t);
4103 if (this.cases.length === 1 || this.condition.id === "true" ||
4104 this.condition.id === "false") {
4105 if (!option.onecase)
4106 warning("This 'switch' should be an 'if'.", this);
4107 }
4108 funct["(breakage)"] -= 1;
4109 funct["(verb)"] = undefined;
4110 return;
4111 case "(end)":
4112 error("Missing '{a}'.", nexttoken, "}");
4113 return;
4114 default:
4115 if (g) {
4116 switch (token.id) {
4117 case ",":
4118 error("Each value should have its own case label.");
4119 return;
4120 case ":":
4121 g = false;
4122 statements();
4123 break;
4124 default:
4125 error("Missing ':' on a case clause.", token);
4126 return;
4127 }
4128 } else {
4129 if (token.id === ":") {
4130 advance(":");
4131 error("Unexpected '{a}'.", token, ":");
4132 statements();
4133 } else {
4134 error("Expected '{a}' and instead saw '{b}'.",
4135 nexttoken, "case", nexttoken.value);
4136 return;
4137 }
4138 }
4139 }
4140 }
4141 }).labelled = true;
4142
4143 stmt("debugger", function () {
4144 if (!option.debug) {
4145 warning("All 'debugger' statements should be removed.");
4146 }
4147 return this;
4148 }).exps = true;
4149
4150 (function () {
4151 var x = stmt("do", function () {
4152 funct["(breakage)"] += 1;
4153 funct["(loopage)"] += 1;
4154 increaseComplexityCount();
4155
4156 this.first = block(true);
4157 advance("while");
4158 var t = nexttoken;
4159 nonadjacent(token, t);
4160 advance("(");
4161 nospace();
4162 expression(20);
4163 if (nexttoken.id === "=") {
4164 if (!option.boss)
4165 warning("Expected a conditional expression and instead saw an assignment.");
4166 advance("=");
4167 expression(20);
4168 }
4169 advance(")", t);
4170 nospace(prevtoken, token);
4171 funct["(breakage)"] -= 1;
4172 funct["(loopage)"] -= 1;
4173 return this;
4174 });
4175 x.labelled = true;
4176 x.exps = true;
4177 }());
4178
4179 blockstmt("for", function () {
4180 var s, t = nexttoken;
4181 funct["(breakage)"] += 1;
4182 funct["(loopage)"] += 1;
4183 increaseComplexityCount();
4184 advance("(");
4185 nonadjacent(this, t);
4186 nospace();
4187 if (peek(nexttoken.id === "var" ? 1 : 0).id === "in") {
4188 if (nexttoken.id === "var") {
4189 advance("var");
4190 varstatement.fud.call(varstatement, true);
4191 } else {
4192 switch (funct[nexttoken.value]) {
4193 case "unused":
4194 funct[nexttoken.value] = "var";
4195 break;
4196 case "var":
4197 break;
4198 default:
4199 warning("Bad for in variable '{a}'.",
4200 nexttoken, nexttoken.value);
4201 }
4202 advance();
4203 }
4204 advance("in");
4205 expression(20);
4206 advance(")", t);
4207 s = block(true, true);
4208 if (option.forin && s && (s.length > 1 || typeof s[0] !== "object" ||
4209 s[0].value !== "if")) {
4210 warning("The body of a for in should be wrapped in an if statement to filter " +
4211 "unwanted properties from the prototype.", this);
4212 }
4213 funct["(breakage)"] -= 1;
4214 funct["(loopage)"] -= 1;
4215 return this;
4216 } else {
4217 if (nexttoken.id !== ";") {
4218 if (nexttoken.id === "var") {
4219 advance("var");
4220 varstatement.fud.call(varstatement);
4221 } else {
4222 for (;;) {
4223 expression(0, "for");
4224 if (nexttoken.id !== ",") {
4225 break;
4226 }
4227 comma();
4228 }
4229 }
4230 }
4231 nolinebreak(token);
4232 advance(";");
4233 if (nexttoken.id !== ";") {
4234 expression(20);
4235 if (nexttoken.id === "=") {
4236 if (!option.boss)
4237 warning("Expected a conditional expression and instead saw an assignment.");
4238 advance("=");
4239 expression(20);
4240 }
4241 }
4242 nolinebreak(token);
4243 advance(";");
4244 if (nexttoken.id === ";") {
4245 error("Expected '{a}' and instead saw '{b}'.",
4246 nexttoken, ")", ";");
4247 }
4248 if (nexttoken.id !== ")") {
4249 for (;;) {
4250 expression(0, "for");
4251 if (nexttoken.id !== ",") {
4252 break;
4253 }
4254 comma();
4255 }
4256 }
4257 advance(")", t);
4258 nospace(prevtoken, token);
4259 block(true, true);
4260 funct["(breakage)"] -= 1;
4261 funct["(loopage)"] -= 1;
4262 return this;
4263 }
4264 }).labelled = true;
4265
4266
4267 stmt("break", function () {
4268 var v = nexttoken.value;
4269
4270 if (funct["(breakage)"] === 0)
4271 warning("Unexpected '{a}'.", nexttoken, this.value);
4272
4273 if (!option.asi)
4274 nolinebreak(this);
4275
4276 if (nexttoken.id !== ";") {
4277 if (token.line === nexttoken.line) {
4278 if (funct[v] !== "label") {
4279 warning("'{a}' is not a statement label.", nexttoken, v);
4280 } else if (scope[v] !== funct) {
4281 warning("'{a}' is out of scope.", nexttoken, v);
4282 }
4283 this.first = nexttoken;
4284 advance();
4285 }
4286 }
4287 reachable("break");
4288 return this;
4289 }).exps = true;
4290
4291
4292 stmt("continue", function () {
4293 var v = nexttoken.value;
4294
4295 if (funct["(breakage)"] === 0)
4296 warning("Unexpected '{a}'.", nexttoken, this.value);
4297
4298 if (!option.asi)
4299 nolinebreak(this);
4300
4301 if (nexttoken.id !== ";") {
4302 if (token.line === nexttoken.line) {
4303 if (funct[v] !== "label") {
4304 warning("'{a}' is not a statement label.", nexttoken, v);
4305 } else if (scope[v] !== funct) {
4306 warning("'{a}' is out of scope.", nexttoken, v);
4307 }
4308 this.first = nexttoken;
4309 advance();
4310 }
4311 } else if (!funct["(loopage)"]) {
4312 warning("Unexpected '{a}'.", nexttoken, this.value);
4313 }
4314 reachable("continue");
4315 return this;
4316 }).exps = true;
4317
4318
4319 stmt("return", function () {
4320 if (this.line === nexttoken.line) {
4321 if (nexttoken.id === "(regexp)")
4322 warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
4323
4324 if (nexttoken.id !== ";" && !nexttoken.reach) {
4325 nonadjacent(token, nexttoken);
4326 if (peek().value === "=" && !option.boss) {
4327 warningAt("Did you mean to return a conditional instead of an assignment?",
4328 token.line, token.character + 1);
4329 }
4330 this.first = expression(0);
4331 }
4332 } else if (!option.asi) {
4333 nolinebreak(this); // always warn (Line breaking error)
4334 }
4335 reachable("return");
4336 return this;
4337 }).exps = true;
4338
4339
4340 stmt("throw", function () {
4341 nolinebreak(this);
4342 nonadjacent(token, nexttoken);
4343 this.first = expression(20);
4344 reachable("throw");
4345 return this;
4346 }).exps = true;
4347
4348 // Superfluous reserved words
4349
4350 reserve("class");
4351 reserve("const");
4352 reserve("enum");
4353 reserve("export");
4354 reserve("extends");
4355 reserve("import");
4356 reserve("super");
4357
4358 reserve("let");
4359 reserve("yield");
4360 reserve("implements");
4361 reserve("interface");
4362 reserve("package");
4363 reserve("private");
4364 reserve("protected");
4365 reserve("public");
4366 reserve("static");
4367
4368
4369 // Parse JSON
4370
4371 function jsonValue() {
4372
4373 function jsonObject() {
4374 var o = {}, t = nexttoken;
4375 advance("{");
4376 if (nexttoken.id !== "}") {
4377 for (;;) {
4378 if (nexttoken.id === "(end)") {
4379 error("Missing '}' to match '{' from line {a}.",
4380 nexttoken, t.line);
4381 } else if (nexttoken.id === "}") {
4382 warning("Unexpected comma.", token);
4383 break;
4384 } else if (nexttoken.id === ",") {
4385 error("Unexpected comma.", nexttoken);
4386 } else if (nexttoken.id !== "(string)") {
4387 warning("Expected a string and instead saw {a}.",
4388 nexttoken, nexttoken.value);
4389 }
4390 if (o[nexttoken.value] === true) {
4391 warning("Duplicate key '{a}'.",
4392 nexttoken, nexttoken.value);
4393 } else if ((nexttoken.value === "__proto__" &&
4394 !option.proto) || (nexttoken.value === "__iterator__" &&
4395 !option.iterator)) {
4396 warning("The '{a}' key may produce unexpected results.",
4397 nexttoken, nexttoken.value);
4398 } else {
4399 o[nexttoken.value] = true;
4400 }
4401 advance();
4402 advance(":");
4403 jsonValue();
4404 if (nexttoken.id !== ",") {
4405 break;
4406 }
4407 advance(",");
4408 }
4409 }
4410 advance("}");
4411 }
4412
4413 function jsonArray() {
4414 var t = nexttoken;
4415 advance("[");
4416 if (nexttoken.id !== "]") {
4417 for (;;) {
4418 if (nexttoken.id === "(end)") {
4419 error("Missing ']' to match '[' from line {a}.",
4420 nexttoken, t.line);
4421 } else if (nexttoken.id === "]") {
4422 warning("Unexpected comma.", token);
4423 break;
4424 } else if (nexttoken.id === ",") {
4425 error("Unexpected comma.", nexttoken);
4426 }
4427 jsonValue();
4428 if (nexttoken.id !== ",") {
4429 break;
4430 }
4431 advance(",");
4432 }
4433 }
4434 advance("]");
4435 }
4436
4437 switch (nexttoken.id) {
4438 case "{":
4439 jsonObject();
4440 break;
4441 case "[":
4442 jsonArray();
4443 break;
4444 case "true":
4445 case "false":
4446 case "null":
4447 case "(number)":
4448 case "(string)":
4449 advance();
4450 break;
4451 case "-":
4452 advance("-");
4453 if (token.character !== nexttoken.from) {
4454 warning("Unexpected space after '-'.", token);
4455 }
4456 adjacent(token, nexttoken);
4457 advance("(number)");
4458 break;
4459 default:
4460 error("Expected a JSON value.", nexttoken);
4461 }
4462 }
4463
4464
4465 // The actual JSHINT function itself.
4466 var itself = function (s, o, g) {
4467 var a, i, k, x;
4468 var optionKeys;
4469 var newOptionObj = {};
4470
4471 if (o && o.scope) {
4472 JSHINT.scope = o.scope;
4473 } else {
4474 JSHINT.errors = [];
4475 JSHINT.undefs = [];
4476 JSHINT.internals = [];
4477 JSHINT.blacklist = {};
4478 JSHINT.scope = "(main)";
4479 }
4480
4481 predefined = Object.create(standard);
4482 declared = Object.create(null);
4483 combine(predefined, g || {});
4484
4485 if (o) {
4486 a = o.predef;
4487 if (a) {
4488 if (!Array.isArray(a) && typeof a === "object") {
4489 a = Object.keys(a);
4490 }
4491 a.forEach(function (item) {
4492 var slice;
4493 if (item[0] === "-") {
4494 slice = item.slice(1);
4495 JSHINT.blacklist[slice] = slice;
4496 } else {
4497 predefined[item] = true;
4498 }
4499 });
4500 }
4501
4502 optionKeys = Object.keys(o);
4503 for (x = 0; x < optionKeys.length; x++) {
4504 newOptionObj[optionKeys[x]] = o[optionKeys[x]];
4505
4506 if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false)
4507 newOptionObj["(explicitNewcap)"] = true;
4508
4509 if (optionKeys[x] === "indent")
4510 newOptionObj.white = true;
4511 }
4512 }
4513
4514 option = newOptionObj;
4515
4516 option.indent = option.indent || 4;
4517 option.maxerr = option.maxerr || 50;
4518
4519 tab = "";
4520 for (i = 0; i < option.indent; i += 1) {
4521 tab += " ";
4522 }
4523 indent = 1;
4524 global = Object.create(predefined);
4525 scope = global;
4526 funct = {
4527 "(global)": true,
4528 "(name)": "(global)",
4529 "(scope)": scope,
4530 "(breakage)": 0,
4531 "(loopage)": 0,
4532 "(tokens)": {},
4533 "(metrics)": createMetrics(nexttoken)
4534 };
4535 functions = [funct];
4536 urls = [];
4537 stack = null;
4538 member = {};
4539 membersOnly = null;
4540 implied = {};
4541 inblock = false;
4542 lookahead = [];
4543 jsonmode = false;
4544 warnings = 0;
4545 lines = [];
4546 unuseds = [];
4547
4548 if (!isString(s) && !Array.isArray(s)) {
4549 errorAt("Input is neither a string nor an array of strings.", 0);
4550 return false;
4551 }
4552
4553 if (isString(s) && /^\s*$/g.test(s)) {
4554 errorAt("Input is an empty string.", 0);
4555 return false;
4556 }
4557
4558 if (s.length === 0) {
4559 errorAt("Input is an empty array.", 0);
4560 return false;
4561 }
4562
4563 lex.init(s);
4564
4565 prereg = true;
4566 directive = {};
4567
4568 prevtoken = token = nexttoken = syntax["(begin)"];
4569
4570 // Check options
4571 for (var name in o) {
4572 if (is_own(o, name)) {
4573 checkOption(name, token);
4574 }
4575 }
4576
4577 assume();
4578
4579 // combine the passed globals after we've assumed all our options
4580 combine(predefined, g || {});
4581
4582 //reset values
4583 comma.first = true;
4584 quotmark = undefined;
4585
4586 try {
4587 advance();
4588 switch (nexttoken.id) {
4589 case "{":
4590 case "[":
4591 option.laxbreak = true;
4592 jsonmode = true;
4593 jsonValue();
4594 break;
4595 default:
4596 directives();
4597 if (directive["use strict"] && !option.globalstrict) {
4598 warning("Use the function form of \"use strict\".", prevtoken);
4599 }
4600
4601 statements();
4602 }
4603 advance((nexttoken && nexttoken.value !== ".") ? "(end)" : undefined);
4604
4605 var markDefined = function (name, context) {
4606 do {
4607 if (typeof context[name] === "string") {
4608 // JSHINT marks unused variables as 'unused' and
4609 // unused function declaration as 'unction'. This
4610 // code changes such instances back 'var' and
4611 // 'closure' so that the code in JSHINT.data()
4612 // doesn't think they're unused.
4613
4614 if (context[name] === "unused")
4615 context[name] = "var";
4616 else if (context[name] === "unction")
4617 context[name] = "closure";
4618
4619 return true;
4620 }
4621
4622 context = context["(context)"];
4623 } while (context);
4624
4625 return false;
4626 };
4627
4628 var clearImplied = function (name, line) {
4629 if (!implied[name])
4630 return;
4631
4632 var newImplied = [];
4633 for (var i = 0; i < implied[name].length; i += 1) {
4634 if (implied[name][i] !== line)
4635 newImplied.push(implied[name][i]);
4636 }
4637
4638 if (newImplied.length === 0)
4639 delete implied[name];
4640 else
4641 implied[name] = newImplied;
4642 };
4643
4644 var warnUnused = function (name, token) {
4645 var line = token.line;
4646 var chr = token.character;
4647
4648 if (option.unused)
4649 warningAt("'{a}' is defined but never used.", line, chr, name);
4650
4651 unuseds.push({
4652 name: name,
4653 line: line,
4654 character: chr
4655 });
4656 };
4657
4658 var checkUnused = function (func, key) {
4659 var type = func[key];
4660 var token = func["(tokens)"][key];
4661
4662 if (key.charAt(0) === "(")
4663 return;
4664
4665 if (type !== "unused" && type !== "unction")
4666 return;
4667
4668 // Params are checked separately from other variables.
4669 if (func["(params)"] && func["(params)"].indexOf(key) !== -1)
4670 return;
4671
4672 warnUnused(key, token);
4673 };
4674
4675 // Check queued 'x is not defined' instances to see if they're still undefined.
4676 for (i = 0; i < JSHINT.undefs.length; i += 1) {
4677 k = JSHINT.undefs[i].slice(0);
4678
4679 if (markDefined(k[2].value, k[0])) {
4680 clearImplied(k[2].value, k[2].line);
4681 } else {
4682 warning.apply(warning, k.slice(1));
4683 }
4684 }
4685
4686 functions.forEach(function (func) {
4687 for (var key in func) {
4688 if (is_own(func, key)) {
4689 checkUnused(func, key);
4690 }
4691 }
4692
4693 if (!func["(params)"])
4694 return;
4695
4696 var params = func["(params)"].slice();
4697 var param = params.pop();
4698 var type;
4699
4700 while (param) {
4701 type = func[param];
4702
4703 // 'undefined' is a special case for (function (window, undefined) { ... })();
4704 // patterns.
4705
4706 if (param === "undefined")
4707 return;
4708
4709 if (type !== "unused" && type !== "unction")
4710 return;
4711
4712 warnUnused(param, func["(tokens)"][param]);
4713 param = params.pop();
4714 }
4715 });
4716
4717 for (var key in declared) {
4718 if (is_own(declared, key) && !is_own(global, key)) {
4719 warnUnused(key, declared[key]);
4720 }
4721 }
4722 } catch (e) {
4723 if (e) {
4724 var nt = nexttoken || {};
4725 JSHINT.errors.push({
4726 raw : e.raw,
4727 reason : e.message,
4728 line : e.line || nt.line,
4729 character : e.character || nt.from
4730 }, null);
4731 }
4732 }
4733
4734 // Loop over the listed "internals", and check them as well.
4735
4736 if (JSHINT.scope === "(main)") {
4737 o = o || {};
4738
4739 for (i = 0; i < JSHINT.internals.length; i += 1) {
4740 k = JSHINT.internals[i];
4741 o.scope = k.elem;
4742 itself(k.value, o, g);
4743 }
4744 }
4745
4746 return JSHINT.errors.length === 0;
4747 };
4748
4749 // Data summary.
4750 itself.data = function () {
4751 var data = {
4752 functions: [],
4753 options: option
4754 };
4755 var implieds = [];
4756 var members = [];
4757 var fu, f, i, j, n, globals;
4758
4759 if (itself.errors.length) {
4760 data.errors = itself.errors;
4761 }
4762
4763 if (jsonmode) {
4764 data.json = true;
4765 }
4766
4767 for (n in implied) {
4768 if (is_own(implied, n)) {
4769 implieds.push({
4770 name: n,
4771 line: implied[n]
4772 });
4773 }
4774 }
4775
4776 if (implieds.length > 0) {
4777 data.implieds = implieds;
4778 }
4779
4780 if (urls.length > 0) {
4781 data.urls = urls;
4782 }
4783
4784 globals = Object.keys(scope);
4785 if (globals.length > 0) {
4786 data.globals = globals;
4787 }
4788
4789 for (i = 1; i < functions.length; i += 1) {
4790 f = functions[i];
4791 fu = {};
4792
4793 for (j = 0; j < functionicity.length; j += 1) {
4794 fu[functionicity[j]] = [];
4795 }
4796
4797 for (j = 0; j < functionicity.length; j += 1) {
4798 if (fu[functionicity[j]].length === 0) {
4799 delete fu[functionicity[j]];
4800 }
4801 }
4802
4803 fu.name = f["(name)"];
4804 fu.param = f["(params)"];
4805 fu.line = f["(line)"];
4806 fu.character = f["(character)"];
4807 fu.last = f["(last)"];
4808 fu.lastcharacter = f["(lastcharacter)"];
4809 data.functions.push(fu);
4810 }
4811
4812 if (unuseds.length > 0) {
4813 data.unused = unuseds;
4814 }
4815
4816 members = [];
4817 for (n in member) {
4818 if (typeof member[n] === "number") {
4819 data.member = member;
4820 break;
4821 }
4822 }
4823
4824 return data;
4825 };
4826
4827 itself.jshint = itself;
4828
4829 return itself;
4830 }());
4831
4832 // Make JSHINT a Node module, if possible.
4833 if (typeof exports === "object" && exports) {
4834 exports.JSHINT = JSHINT;
4835 }

  ViewVC Help
Powered by ViewVC 1.1.20