jshintrb 0.0.1

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