jshintrb 0.1.6 → 0.2.0

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