jshint4r 0.1.0

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