pre-commit 0.1.17 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,11 +24,7 @@ class PreCommit
24
24
 
25
25
  def run_check(file)
26
26
  context = ExecJS.compile(File.read(linter_src))
27
- if !(context.call('JSHINT', File.read(file), config))
28
- context.exec('return JSHINT.errors;')
29
- else
30
- []
31
- end
27
+ context.call('JSHINT', File.read(file), config)
32
28
  end
33
29
 
34
30
  def linter_src
@@ -1,4 +1,4 @@
1
- /*
1
+ /*!
2
2
  * JSHint, by JSHint Community.
3
3
  *
4
4
  * Licensed under the same slightly modified MIT license that JSLint is.
@@ -128,7 +128,7 @@
128
128
  member: {
129
129
  STRING: NUMBER
130
130
  },
131
- unuseds: [
131
+ unused: [
132
132
  {
133
133
  name: STRING,
134
134
  line: NUMBER
@@ -151,65 +151,79 @@
151
151
  */
152
152
 
153
153
  /*jshint
154
- evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true
154
+ evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
155
+ undef: true, maxlen: 100, indent:4
155
156
  */
156
157
 
157
- /*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%",
158
- "(begin)", "(breakage)", "(context)", "(error)", "(global)",
159
- "(identifier)", "(last)", "(line)", "(loopage)", "(name)", "(onevar)",
160
- "(params)", "(scope)", "(statement)", "(verb)", "*", "+", "++", "-",
161
- "--", "\/", "<", "<=", "==", "===", ">", ">=", $, $$, $A, $F, $H, $R, $break,
162
- $continue, $w, Abstract, Ajax, __filename, __dirname, ActiveXObject, Array,
163
- ArrayBuffer, ArrayBufferView, Autocompleter, Assets, Boolean, Builder,
164
- Buffer, Browser, COM, CScript, Canvas, CustomAnimation, Class, Control,
165
- Chain, Color, Cookie, Core, DataView, Date, Debug, Draggable, Draggables,
166
- Droppables, Document, DomReady, DOMReady, Drag, E, Enumerator, Enumerable,
167
- Element, Elements, Error, Effect, EvalError, Event, Events, FadeAnimation,
168
- Field, Flash, Float32Array, Float64Array, Form, FormField, Frame, Function,
169
- Fx, Group, Hash, HotKey, HTMLElement, HtmlTable, Iframe, IframeShim, Image,
170
- Int16Array, Int32Array, Int8Array, Insertion, InputValidator, JSON, Keyboard,
171
- Locale, LN10, LN2, LOG10E, LOG2E, MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem,
172
- MoveAnimation, MooTools, Native, NEGATIVE_INFINITY, Number, Object,
173
- ObjectRange, Option, Options, OverText, PI, POSITIVE_INFINITY,
174
- PeriodicalExecuter, Point, Position, Prototype, RangeError, Rectangle,
175
- ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation, SQRT1_2,
176
- SQRT2, ScrollBar, Scriptaculous, Scroller, Slick, Slider, Selector, String,
177
- Style, SyntaxError, Sortable, Sortables, SortableObserver, Sound, Spinner,
178
- System, Swiff, Text, TextArea, Template, Timer, Tips, Type, TypeError,
179
- Toggle, Try, URI, URIError, URL, VBArray, WScript, Web, Window, XMLDOM,
180
- XMLHttpRequest, XPathEvaluator, XPathException, XPathExpression,
181
- XPathNamespace, XPathNSResolver, XPathResult, "\\", a, addEventListener,
182
- address, alert, apply, applicationCache, arguments, arity, asi, b, bitwise,
183
- block, blur, boolOptions, boss, browser, c, call, callee, caller, cases,
184
- charAt, charCodeAt, character, clearInterval, clearTimeout, close, closed,
185
- closure, comment, condition, confirm, console, constructor, content, couch,
186
- create, css, curly, d, data, datalist, dd, debug, decodeURI,
187
- decodeURIComponent, defaultStatus, defineClass, deserialize, devel,
188
- document, edition, else, emit, encodeURI, encodeURIComponent, entityify,
189
- eqeqeq, eqnull, errors, es5, escape, eval, event, evidence, evil, ex,
190
- exception, exec, exps, expr, exports, FileReader, first, floor, focus,
191
- forin, fragment, frames, from, fromCharCode, fud, funct, function, functions,
192
- g, gc, getComputedStyle, getRow, GLOBAL, global, globals, globalstrict,
193
- hasOwnProperty, help, history, i, id, identifier, immed, implieds,
194
- include, indent, indexOf, init, ins, instanceOf, isAlpha,
195
- isApplicationRunning, isArray, isDigit, isFinite, isNaN, join, jshint,
196
- JSHINT, json, jquery, jQuery, keys, label, labelled, last, laxbreak,
197
- latedef, lbp, led, left, length, line, load, loadClass, localStorage,
198
- location, log, loopfunc, m, match, maxerr, maxlen, member,message, meta,
199
- module, moveBy, moveTo, mootools, name, navigator, new, newcap, noarg,
200
- node, noempty, nomen, nonew, nud, onbeforeunload, onblur, onerror, onevar,
201
- onfocus, onload, onresize, onunload, open, openDatabase, openURL, opener,
202
- opera, outer, param, parent, parseFloat, parseInt, passfail, plusplus,
203
- predef, print, process, prompt, prototype, prototypejs, push, quit, range,
204
- raw, reach, reason, regexp, readFile, readUrl, removeEventListener, replace,
205
- report, require, reserved, resizeBy, resizeTo, resolvePath, resumeUpdates,
206
- respond, rhino, right, runCommand, scroll, screen, scrollBy, scrollTo,
207
- scrollbar, search, seal, send, serialize, setInterval, setTimeout, shift,
208
- slice, sort,spawn, split, stack, status, start, strict, sub, substr, supernew,
209
- shadow, supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32,
210
- token, top, type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef,
211
- unused, urls, value, valueOf, var, version, WebSocket, white, window, Worker
212
- */
158
+ /*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
159
+ "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)",
160
+ "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)",
161
+ "(statement)", "(verb)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
162
+ "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
163
+ __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio,
164
+ Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas,
165
+ CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date,
166
+ Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, Drag,
167
+ E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
168
+ Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
169
+ FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey,
170
+ HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement,
171
+ HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement,
172
+ HTMLDivElement, HTMLDListElement, HTMLFieldSetElement,
173
+ HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement,
174
+ HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement,
175
+ HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement,
176
+ HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement,
177
+ HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement,
178
+ HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement,
179
+ HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement,
180
+ HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement,
181
+ HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement,
182
+ HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement,
183
+ HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement,
184
+ Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array,
185
+ Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
186
+ MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MoveAnimation, MooTools, Native,
187
+ NEGATIVE_INFINITY, Number, Object, ObjectRange, Option, Options, OverText, PI,
188
+ POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype, RangeError,
189
+ Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation,
190
+ SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
191
+ ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
192
+ Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables,
193
+ SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
194
+ Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL,
195
+ VBArray, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XPathEvaluator,
196
+ XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult, "\\", a,
197
+ addEventListener, address, alert, apply, applicationCache, arguments, arity,
198
+ asi, b, basic, basicToken, bitwise, block, blur, boolOptions, boss, browser, c, call, callee,
199
+ caller, cases, charAt, charCodeAt, character, clearInterval, clearTimeout,
200
+ close, closed, closure, comment, condition, confirm, console, constructor,
201
+ content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI,
202
+ decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
203
+ dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent,
204
+ entityify, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,
205
+ ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,
206
+ forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,
207
+ g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict,
208
+ hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,
209
+ indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray,
210
+ isDigit, isFinite, isNaN, iterator, java, join, jshint,
211
+ JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak, laxcomma,
212
+ latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
213
+ log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy,
214
+ moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen,
215
+ nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus,
216
+ onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param,
217
+ parent, parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt,
218
+ proto, prototype, prototypejs, provides, push, quit, range, raw, reach, reason, regexp,
219
+ readFile, readUrl, regexdash, removeEventListener, replace, report, require,
220
+ reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
221
+ runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal,
222
+ send, serialize, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice,
223
+ smarttabs, sort, spawn, split, stack, status, start, strict, sub, substr, supernew, shadow,
224
+ supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing,
225
+ type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis,
226
+ value, valueOf, var, version, WebSocket, white, window, Worker, wsh*/
213
227
 
214
228
  /*global exports: false */
215
229
 
@@ -240,123 +254,208 @@ var JSHINT = (function () {
240
254
  '%' : true
241
255
  },
242
256
 
243
- // These are the JSHint boolean options.
244
-
257
+ // These are the JSHint boolean options.
245
258
  boolOptions = {
246
259
  asi : true, // if automatic semicolon insertion should be tolerated
247
260
  bitwise : true, // if bitwise operators should not be allowed
248
261
  boss : true, // if advanced usage of assignments should be allowed
249
262
  browser : true, // if the standard browser globals should be predefined
250
263
  couch : true, // if CouchDB globals should be predefined
251
- curly : true, // if curly braces around blocks should be required (even in if/for/while)
264
+ curly : true, // if curly braces around all blocks should be required
252
265
  debug : true, // if debugger statements should be allowed
253
- devel : true, // if logging globals should be predefined (console, alert, etc.)
266
+ devel : true, // if logging globals should be predefined (console,
267
+ // alert, etc.)
268
+ dojo : true, // if Dojo Toolkit globals should be predefined
254
269
  eqeqeq : true, // if === should be required
255
270
  eqnull : true, // if == null comparisons should be tolerated
256
271
  es5 : true, // if ES5 syntax should be allowed
272
+ esnext : true, // if es.next specific syntax should be allowed
257
273
  evil : true, // if eval should be allowed
258
274
  expr : true, // if ExpressionStatement should be allowed as Programs
259
275
  forin : true, // if for in statements must filter
260
- globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict')
276
+ funcscope : true, // if only function scope should be used for scope tests
277
+ globalstrict: true, // if global "use strict"; should be allowed (also
278
+ // enables 'strict')
261
279
  immed : true, // if immediate invocations must be wrapped in parens
280
+ iterator : true, // if the `__iterator__` property should be allowed
262
281
  jquery : true, // if jQuery globals should be predefined
282
+ lastsemic : true, // if semicolons may be ommitted for the trailing
283
+ // statements inside of a one-line blocks.
263
284
  latedef : true, // if the use before definition should not be tolerated
264
285
  laxbreak : true, // if line breaks should not be checked
265
- loopfunc : true, // if functions should be allowed to be defined within loops
286
+ laxcomma : true, // if line breaks should not be checked around commas
287
+ loopfunc : true, // if functions should be allowed to be defined within
288
+ // loops
266
289
  mootools : true, // if MooTools globals should be predefined
290
+ multistr : true, // allow multiline strings
267
291
  newcap : true, // if constructor names must be capitalized
268
- noarg : true, // if arguments.caller and arguments.callee should be disallowed
269
- node : true, // if the Node.js environment globals should be predefined
292
+ noarg : true, // if arguments.caller and arguments.callee should be
293
+ // disallowed
294
+ node : true, // if the Node.js environment globals should be
295
+ // predefined
270
296
  noempty : true, // if empty blocks should be disallowed
271
297
  nonew : true, // if using `new` for side-effects should be disallowed
298
+ nonstandard : true, // if non-standard (but widely adopted) globals should
299
+ // be predefined
272
300
  nomen : true, // if names should be checked
273
- onevar : true, // if only one var statement per function should be allowed
301
+ onevar : true, // if only one var statement per function should be
302
+ // allowed
303
+ onecase : true, // if one case switch statements should be allowed
274
304
  passfail : true, // if the scan should stop on first error
275
305
  plusplus : true, // if increment/decrement should not be allowed
276
- prototypejs : true, // if Prototype and Scriptaculous globals shoudl be predefined
306
+ proto : true, // if the `__proto__` property should be allowed
307
+ prototypejs : true, // if Prototype and Scriptaculous globals should be
308
+ // predefined
309
+ regexdash : true, // if unescaped first/last dash (-) inside brackets
310
+ // should be tolerated
277
311
  regexp : true, // if the . should not be allowed in regexp literals
278
312
  rhino : true, // if the Rhino environment globals should be predefined
279
313
  undef : true, // if variables should be declared before used
314
+ scripturl : true, // if script-targeted URLs should be tolerated
280
315
  shadow : true, // if variable shadowing should be tolerated
316
+ smarttabs : true, // if smarttabs should be tolerated
317
+ // (http://www.emacswiki.org/emacs/SmartTabs)
281
318
  strict : true, // require the "use strict"; pragma
282
319
  sub : true, // if all forms of subscript notation are tolerated
283
- supernew : true, // if `new function () { ... };` and `new Object;` should be tolerated
284
- white : true // if strict whitespace rules apply
320
+ supernew : true, // if `new function () { ... };` and `new Object;`
321
+ // should be tolerated
322
+ trailing : true, // if trailing whitespace rules apply
323
+ validthis : true, // if 'this' inside a non-constructor function is valid.
324
+ // This is a function scoped option only.
325
+ white : true, // if strict whitespace rules apply
326
+ wsh : true // if the Windows Scripting Host environment globals
327
+ // should be predefined
285
328
  },
286
329
 
287
- // browser contains a set of global names which are commonly provided by a
288
- // web browser environment.
289
-
330
+ // browser contains a set of global names which are commonly provided by a
331
+ // web browser environment.
290
332
  browser = {
291
- ArrayBuffer : false,
292
- ArrayBufferView : false,
293
- addEventListener: false,
294
- applicationCache: false,
295
- blur : false,
296
- clearInterval : false,
297
- clearTimeout : false,
298
- close : false,
299
- closed : false,
300
- DataView : false,
301
- defaultStatus : false,
302
- document : false,
303
- event : false,
304
- FileReader : false,
305
- Float32Array : false,
306
- Float64Array : false,
307
- focus : false,
308
- frames : false,
309
- getComputedStyle: false,
310
- HTMLElement : false,
311
- history : false,
312
- Int16Array : false,
313
- Int32Array : false,
314
- Int8Array : false,
315
- Image : false,
316
- length : false,
317
- localStorage : false,
318
- location : false,
319
- moveBy : false,
320
- moveTo : false,
321
- name : false,
322
- navigator : false,
323
- onbeforeunload : true,
324
- onblur : true,
325
- onerror : true,
326
- onfocus : true,
327
- onload : true,
328
- onresize : true,
329
- onunload : true,
330
- open : false,
331
- openDatabase : false,
332
- opener : false,
333
- Option : false,
334
- parent : false,
335
- print : false,
336
- removeEventListener: false,
337
- resizeBy : false,
338
- resizeTo : false,
339
- screen : false,
340
- scroll : false,
341
- scrollBy : false,
342
- scrollTo : false,
343
- setInterval : false,
344
- setTimeout : false,
345
- status : false,
346
- top : false,
347
- Uint16Array : false,
348
- Uint32Array : false,
349
- Uint8Array : false,
350
- WebSocket : false,
351
- window : false,
352
- Worker : false,
353
- XMLHttpRequest : false,
354
- XPathEvaluator : false,
355
- XPathException : false,
356
- XPathExpression : false,
357
- XPathNamespace : false,
358
- XPathNSResolver : false,
359
- XPathResult : false
333
+ ArrayBuffer : false,
334
+ ArrayBufferView : false,
335
+ Audio : false,
336
+ addEventListener : false,
337
+ applicationCache : false,
338
+ blur : false,
339
+ clearInterval : false,
340
+ clearTimeout : false,
341
+ close : false,
342
+ closed : false,
343
+ DataView : false,
344
+ defaultStatus : false,
345
+ document : false,
346
+ event : false,
347
+ FileReader : false,
348
+ Float32Array : false,
349
+ Float64Array : false,
350
+ FormData : false,
351
+ focus : false,
352
+ frames : false,
353
+ getComputedStyle : false,
354
+ HTMLElement : false,
355
+ HTMLAnchorElement : false,
356
+ HTMLBaseElement : false,
357
+ HTMLBlockquoteElement : false,
358
+ HTMLBodyElement : false,
359
+ HTMLBRElement : false,
360
+ HTMLButtonElement : false,
361
+ HTMLCanvasElement : false,
362
+ HTMLDirectoryElement : false,
363
+ HTMLDivElement : false,
364
+ HTMLDListElement : false,
365
+ HTMLFieldSetElement : false,
366
+ HTMLFontElement : false,
367
+ HTMLFormElement : false,
368
+ HTMLFrameElement : false,
369
+ HTMLFrameSetElement : false,
370
+ HTMLHeadElement : false,
371
+ HTMLHeadingElement : false,
372
+ HTMLHRElement : false,
373
+ HTMLHtmlElement : false,
374
+ HTMLIFrameElement : false,
375
+ HTMLImageElement : false,
376
+ HTMLInputElement : false,
377
+ HTMLIsIndexElement : false,
378
+ HTMLLabelElement : false,
379
+ HTMLLayerElement : false,
380
+ HTMLLegendElement : false,
381
+ HTMLLIElement : false,
382
+ HTMLLinkElement : false,
383
+ HTMLMapElement : false,
384
+ HTMLMenuElement : false,
385
+ HTMLMetaElement : false,
386
+ HTMLModElement : false,
387
+ HTMLObjectElement : false,
388
+ HTMLOListElement : false,
389
+ HTMLOptGroupElement : false,
390
+ HTMLOptionElement : false,
391
+ HTMLParagraphElement : false,
392
+ HTMLParamElement : false,
393
+ HTMLPreElement : false,
394
+ HTMLQuoteElement : false,
395
+ HTMLScriptElement : false,
396
+ HTMLSelectElement : false,
397
+ HTMLStyleElement : false,
398
+ HTMLTableCaptionElement : false,
399
+ HTMLTableCellElement : false,
400
+ HTMLTableColElement : false,
401
+ HTMLTableElement : false,
402
+ HTMLTableRowElement : false,
403
+ HTMLTableSectionElement : false,
404
+ HTMLTextAreaElement : false,
405
+ HTMLTitleElement : false,
406
+ HTMLUListElement : false,
407
+ HTMLVideoElement : false,
408
+ history : false,
409
+ Int16Array : false,
410
+ Int32Array : false,
411
+ Int8Array : false,
412
+ Image : false,
413
+ length : false,
414
+ localStorage : false,
415
+ location : false,
416
+ moveBy : false,
417
+ moveTo : false,
418
+ name : false,
419
+ navigator : false,
420
+ onbeforeunload : true,
421
+ onblur : true,
422
+ onerror : true,
423
+ onfocus : true,
424
+ onload : true,
425
+ onresize : true,
426
+ onunload : true,
427
+ open : false,
428
+ openDatabase : false,
429
+ opener : false,
430
+ Option : false,
431
+ parent : false,
432
+ print : false,
433
+ removeEventListener : false,
434
+ resizeBy : false,
435
+ resizeTo : false,
436
+ screen : false,
437
+ scroll : false,
438
+ scrollBy : false,
439
+ scrollTo : false,
440
+ sessionStorage : false,
441
+ setInterval : false,
442
+ setTimeout : false,
443
+ SharedWorker : false,
444
+ status : false,
445
+ top : false,
446
+ Uint16Array : false,
447
+ Uint32Array : false,
448
+ Uint8Array : false,
449
+ WebSocket : false,
450
+ window : false,
451
+ Worker : false,
452
+ XMLHttpRequest : false,
453
+ XPathEvaluator : false,
454
+ XPathException : false,
455
+ XPathExpression : false,
456
+ XPathNamespace : false,
457
+ XPathNSResolver : false,
458
+ XPathResult : false
360
459
  },
361
460
 
362
461
  couch = {
@@ -369,16 +468,25 @@ var JSHINT = (function () {
369
468
  sum : false,
370
469
  log : false,
371
470
  exports : false,
372
- module : false
471
+ module : false,
472
+ provides : false
373
473
  },
374
474
 
375
475
  devel = {
376
- alert : false,
377
- confirm : false,
378
- console : false,
379
- Debug : false,
380
- opera : false,
381
- prompt : false
476
+ alert : false,
477
+ confirm : false,
478
+ console : false,
479
+ Debug : false,
480
+ opera : false,
481
+ prompt : false
482
+ },
483
+
484
+ dojo = {
485
+ dojo : false,
486
+ dijit : false,
487
+ dojox : false,
488
+ define : false,
489
+ "require" : false
382
490
  },
383
491
 
384
492
  escapes = {
@@ -467,15 +575,20 @@ var JSHINT = (function () {
467
575
  nexttoken,
468
576
 
469
577
  node = {
470
- __filename : false,
471
- __dirname : false,
472
- exports : false,
473
- Buffer : false,
474
- GLOBAL : false,
475
- global : false,
476
- module : false,
477
- process : false,
478
- require : false
578
+ __filename : false,
579
+ __dirname : false,
580
+ Buffer : false,
581
+ console : false,
582
+ exports : false,
583
+ GLOBAL : false,
584
+ global : false,
585
+ module : false,
586
+ process : false,
587
+ require : false,
588
+ setTimeout : false,
589
+ clearTimeout : false,
590
+ setInterval : false,
591
+ clearInterval : false
479
592
  },
480
593
 
481
594
  noreach,
@@ -526,32 +639,32 @@ var JSHINT = (function () {
526
639
  },
527
640
 
528
641
  rhino = {
529
- defineClass : false,
530
- deserialize : false,
531
- gc : false,
532
- help : false,
533
- load : false,
534
- loadClass : false,
535
- print : false,
536
- quit : false,
537
- readFile : false,
538
- readUrl : false,
539
- runCommand : false,
540
- seal : false,
541
- serialize : false,
542
- spawn : false,
543
- sync : false,
544
- toint32 : false,
545
- version : false
642
+ defineClass : false,
643
+ deserialize : false,
644
+ gc : false,
645
+ help : false,
646
+ importPackage: false,
647
+ "java" : false,
648
+ load : false,
649
+ loadClass : false,
650
+ print : false,
651
+ quit : false,
652
+ readFile : false,
653
+ readUrl : false,
654
+ runCommand : false,
655
+ seal : false,
656
+ serialize : false,
657
+ spawn : false,
658
+ sync : false,
659
+ toint32 : false,
660
+ version : false
546
661
  },
547
662
 
548
663
  scope, // The current scope
549
- src,
550
664
  stack,
551
665
 
552
- // standard contains the global names that are provided by the
553
- // ECMAScript standard.
554
-
666
+ // standard contains the global names that are provided by the
667
+ // ECMAScript standard.
555
668
  standard = {
556
669
  Array : false,
557
670
  Boolean : false,
@@ -582,6 +695,12 @@ var JSHINT = (function () {
582
695
  URIError : false
583
696
  },
584
697
 
698
+ // widely adopted global names that are not part of ECMAScript standard
699
+ nonstandard = {
700
+ escape : false,
701
+ unescape : false
702
+ },
703
+
585
704
  standard_member = {
586
705
  E : true,
587
706
  LN2 : true,
@@ -597,32 +716,58 @@ var JSHINT = (function () {
597
716
  SQRT2 : true
598
717
  },
599
718
 
600
- strict_mode,
719
+ directive,
601
720
  syntax = {},
602
721
  tab,
603
722
  token,
604
723
  urls,
724
+ useESNextSyntax,
605
725
  warnings,
606
726
 
607
- // Regular expressions. Some of these are stupidly long.
608
-
609
- // unsafe comment or string
610
- ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i,
611
- // unsafe characters that are silently deleted by one or more browsers
612
- cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
613
- // token
614
- tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,
615
- // characters in strings that need escapement
616
- nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
617
- nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
618
- // star slash
619
- lx = /\*\/|\/\*/,
620
- // identifier
621
- ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
622
- // javascript url
623
- jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,
624
- // catches /* falls through */ comments
727
+ wsh = {
728
+ ActiveXObject : true,
729
+ Enumerator : true,
730
+ GetObject : true,
731
+ ScriptEngine : true,
732
+ ScriptEngineBuildVersion : true,
733
+ ScriptEngineMajorVersion : true,
734
+ ScriptEngineMinorVersion : true,
735
+ VBArray : true,
736
+ WSH : true,
737
+ WScript : true,
738
+ XDomainRequest : true
739
+ };
740
+
741
+ // Regular expressions. Some of these are stupidly long.
742
+ var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
743
+ (function () {
744
+ /*jshint maxlen:300 */
745
+
746
+ // unsafe comment or string
747
+ ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
748
+
749
+ // unsafe characters that are silently deleted by one or more browsers
750
+ cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
751
+
752
+ // token
753
+ tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/;
754
+
755
+ // characters in strings that need escapement
756
+ nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
757
+ nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
758
+
759
+ // star slash
760
+ lx = /\*\/|\/\*/;
761
+
762
+ // identifier
763
+ ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
764
+
765
+ // javascript url
766
+ jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;
767
+
768
+ // catches /* falls through */ comments
625
769
  ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
770
+ }());
626
771
 
627
772
  function F() {} // Used by Object.create
628
773
 
@@ -730,47 +875,77 @@ var JSHINT = (function () {
730
875
  }
731
876
 
732
877
  function assume() {
733
- if (option.couch)
878
+ if (option.couch) {
734
879
  combine(predefined, couch);
880
+ }
735
881
 
736
- if (option.rhino)
882
+ if (option.rhino) {
737
883
  combine(predefined, rhino);
884
+ }
738
885
 
739
- if (option.prototypejs)
886
+ if (option.prototypejs) {
740
887
  combine(predefined, prototypejs);
888
+ }
741
889
 
742
- if (option.node)
890
+ if (option.node) {
743
891
  combine(predefined, node);
892
+ }
744
893
 
745
- if (option.devel)
894
+ if (option.devel) {
746
895
  combine(predefined, devel);
896
+ }
747
897
 
748
- if (option.browser)
898
+ if (option.dojo) {
899
+ combine(predefined, dojo);
900
+ }
901
+
902
+ if (option.browser) {
749
903
  combine(predefined, browser);
904
+ }
750
905
 
751
- if (option.jquery)
906
+ if (option.nonstandard) {
907
+ combine(predefined, nonstandard);
908
+ }
909
+
910
+ if (option.jquery) {
752
911
  combine(predefined, jquery);
912
+ }
753
913
 
754
- if (option.mootools)
914
+ if (option.mootools) {
755
915
  combine(predefined, mootools);
916
+ }
756
917
 
757
- if (option.globalstrict)
918
+ if (option.wsh) {
919
+ combine(predefined, wsh);
920
+ }
921
+
922
+ if (option.esnext) {
923
+ useESNextSyntax();
924
+ }
925
+
926
+ if (option.globalstrict && option.strict !== false) {
758
927
  option.strict = true;
928
+ }
759
929
  }
760
930
 
761
931
 
762
- // Produce an error warning.
932
+ // Produce an error warning.
933
+ function quit(message, line, chr) {
934
+ var percentage = Math.floor((line / lines.length) * 100);
763
935
 
764
- function quit(m, l, ch) {
765
936
  throw {
766
937
  name: 'JSHintError',
767
- line: l,
768
- character: ch,
769
- message: m + " (" + Math.floor((l / lines.length) * 100) +
770
- "% scanned)."
938
+ line: line,
939
+ character: chr,
940
+ message: message + " (" + percentage + "% scanned).",
941
+ raw: message
771
942
  };
772
943
  }
773
944
 
945
+ function isundef(scope, m, t, a) {
946
+ return JSHINT.undefs.push([scope, m, t, a]);
947
+ }
948
+
774
949
  function warning(m, t, a, b, c, d) {
775
950
  var ch, l, w;
776
951
  t = t || nexttoken;
@@ -811,7 +986,6 @@ var JSHINT = (function () {
811
986
 
812
987
  function error(m, t, a, b, c, d) {
813
988
  var w = warning(m, t, a, b, c, d);
814
- quit("Stopping, unable to continue.", w.line, w.character);
815
989
  }
816
990
 
817
991
  function errorAt(m, l, ch, a, b, c, d) {
@@ -840,7 +1014,13 @@ var JSHINT = (function () {
840
1014
  character = 1;
841
1015
  s = lines[line];
842
1016
  line += 1;
843
- at = s.search(/ \t/);
1017
+
1018
+ // If smarttabs option is used check for spaces followed by tabs only.
1019
+ // Otherwise check for any occurence of mixed tabs and spaces.
1020
+ if (option.smarttabs)
1021
+ at = s.search(/ \t/);
1022
+ else
1023
+ at = s.search(/ \t|\t /);
844
1024
 
845
1025
  if (at >= 0)
846
1026
  warningAt("Mixed spaces and tabs.", line, at + 1);
@@ -855,10 +1035,10 @@ var JSHINT = (function () {
855
1035
  warningAt("Line too long.", line, s.length);
856
1036
 
857
1037
  // Check for trailing whitespaces
858
- tw = s.search(/\s+$/);
859
- if (option.white && ~tw)
1038
+ tw = /\s+$/.test(s);
1039
+ if (option.trailing && tw && !/^\s+$/.test(s)) {
860
1040
  warningAt("Trailing whitespace.", line, tw);
861
-
1041
+ }
862
1042
  return true;
863
1043
  }
864
1044
 
@@ -876,20 +1056,24 @@ var JSHINT = (function () {
876
1056
  }
877
1057
  t = Object.create(t);
878
1058
  if (type === '(string)' || type === '(range)') {
879
- if (jx.test(value)) {
1059
+ if (!option.scripturl && jx.test(value)) {
880
1060
  warningAt("Script URL.", line, from);
881
1061
  }
882
1062
  }
883
1063
  if (type === '(identifier)') {
884
1064
  t.identifier = true;
885
- if (value === '__iterator__' || value === '__proto__') {
886
- errorAt("Reserved name '{a}'.",
1065
+ if (value === '__proto__' && !option.proto) {
1066
+ warningAt("The '{a}' property is deprecated.",
1067
+ line, from, value);
1068
+ } else if (value === '__iterator__' && !option.iterator) {
1069
+ warningAt("'{a}' is only available in JavaScript 1.7.",
887
1070
  line, from, value);
888
- } else if (option.nomen &&
889
- (value.charAt(0) === '_' ||
1071
+ } else if (option.nomen && (value.charAt(0) === '_' ||
890
1072
  value.charAt(value.length - 1) === '_')) {
891
- warningAt("Unexpected {a} in '{b}'.", line, from,
892
- "dangling '_'", value);
1073
+ if (!option.node || token.id === '.' ||
1074
+ (value !== '__dirname' && value !== '__filename')) {
1075
+ warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", value);
1076
+ }
893
1077
  }
894
1078
  }
895
1079
  t.value = value;
@@ -900,13 +1084,13 @@ var JSHINT = (function () {
900
1084
  if (i !== '(endline)') {
901
1085
  prereg = i &&
902
1086
  (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) ||
903
- i === 'return');
1087
+ i === 'return' ||
1088
+ i === 'case');
904
1089
  }
905
1090
  return t;
906
1091
  }
907
1092
 
908
- // Public lex methods
909
-
1093
+ // Public lex methods
910
1094
  return {
911
1095
  init: function (source) {
912
1096
  if (typeof source === 'string') {
@@ -920,7 +1104,7 @@ var JSHINT = (function () {
920
1104
 
921
1105
  // If the first line is a shebang (#!), make it a blank and move on.
922
1106
  // Shebangs are used by Node scripts.
923
- if (lines[0] && lines[0].substr(0, 2) == '#!')
1107
+ if (lines[0] && lines[0].substr(0, 2) === '#!')
924
1108
  lines[0] = '';
925
1109
 
926
1110
  line = 0;
@@ -955,10 +1139,10 @@ var JSHINT = (function () {
955
1139
 
956
1140
  },
957
1141
 
958
- // token -- this is called by advance to get the next token.
959
1142
 
1143
+ // token -- this is called by advance to get the next token
960
1144
  token: function () {
961
- var b, c, captures, d, depth, high, i, l, low, q, t;
1145
+ var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange;
962
1146
 
963
1147
  function match(x) {
964
1148
  var r = x.exec(s), r1;
@@ -974,7 +1158,7 @@ var JSHINT = (function () {
974
1158
  }
975
1159
 
976
1160
  function string(x) {
977
- var c, j, r = '';
1161
+ var c, j, r = '', allowNewLine = false;
978
1162
 
979
1163
  if (jsonmode && x !== '"') {
980
1164
  warningAt("Strings must use doublequote.",
@@ -992,11 +1176,20 @@ var JSHINT = (function () {
992
1176
  c = String.fromCharCode(i);
993
1177
  }
994
1178
  j = 0;
995
- for (;;) {
1179
+ unclosedString: for (;;) {
996
1180
  while (j >= s.length) {
997
1181
  j = 0;
1182
+
1183
+ var cl = line, cf = from;
998
1184
  if (!nextLine()) {
999
- errorAt("Unclosed string.", line, from);
1185
+ errorAt("Unclosed string.", cl, cf);
1186
+ break unclosedString;
1187
+ }
1188
+
1189
+ if (allowNewLine) {
1190
+ allowNewLine = false;
1191
+ } else {
1192
+ warningAt("Unclosed string.", cl, cf);
1000
1193
  }
1001
1194
  }
1002
1195
  c = s.charAt(j);
@@ -1055,6 +1248,22 @@ var JSHINT = (function () {
1055
1248
  }
1056
1249
  esc(2);
1057
1250
  break;
1251
+ case '':
1252
+ // last character is escape character
1253
+ // always allow new line if escaped, but show
1254
+ // warning if option is not set
1255
+ allowNewLine = true;
1256
+ if (option.multistr) {
1257
+ if (jsonmode) {
1258
+ warningAt("Avoid EOL escapement.", line, character);
1259
+ }
1260
+ c = '';
1261
+ character -= 1;
1262
+ break;
1263
+ }
1264
+ warningAt("Bad escapement of EOL. Use option multistr if needed.",
1265
+ line, character);
1266
+ break;
1058
1267
  default:
1059
1268
  warningAt("Bad escapement.", line, character);
1060
1269
  }
@@ -1078,6 +1287,7 @@ var JSHINT = (function () {
1078
1287
  }
1079
1288
  if (s) {
1080
1289
  errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
1290
+ s = '';
1081
1291
  }
1082
1292
  } else {
1083
1293
 
@@ -1127,9 +1337,6 @@ var JSHINT = (function () {
1127
1337
  // // comment
1128
1338
 
1129
1339
  case '//':
1130
- if (src) {
1131
- warningAt("Unexpected comment.", line, character);
1132
- }
1133
1340
  s = '';
1134
1341
  token.comment = true;
1135
1342
  break;
@@ -1137,9 +1344,6 @@ var JSHINT = (function () {
1137
1344
  // /* comment
1138
1345
 
1139
1346
  case '/*':
1140
- if (src) {
1141
- warningAt("Unexpected comment.", line, character);
1142
- }
1143
1347
  for (;;) {
1144
1348
  i = s.search(lx);
1145
1349
  if (i >= 0) {
@@ -1178,8 +1382,8 @@ var JSHINT = (function () {
1178
1382
  // /
1179
1383
  case '/':
1180
1384
  if (token.id === '/=') {
1181
- errorAt(
1182
- "A regular expression literal can be confused with '/='.", line, from);
1385
+ errorAt("A regular expression literal can be confused with '/='.",
1386
+ line, from);
1183
1387
  }
1184
1388
  if (prereg) {
1185
1389
  depth = 0;
@@ -1191,13 +1395,12 @@ var JSHINT = (function () {
1191
1395
  l += 1;
1192
1396
  switch (c) {
1193
1397
  case '':
1194
- errorAt("Unclosed regular expression.",
1195
- line, from);
1196
- return;
1398
+ errorAt("Unclosed regular expression.", line, from);
1399
+ return quit('Stopping.', line, from);
1197
1400
  case '/':
1198
1401
  if (depth > 0) {
1199
- warningAt("Unescaped '{a}'.",
1200
- line, from + l, '/');
1402
+ warningAt("{a} unterminated regular expression " +
1403
+ "group(s).", line, from + l, depth);
1201
1404
  }
1202
1405
  c = s.substr(0, l - 1);
1203
1406
  q = {
@@ -1281,12 +1484,12 @@ var JSHINT = (function () {
1281
1484
  line, from + l, '^');
1282
1485
  }
1283
1486
  }
1284
- q = false;
1285
1487
  if (c === ']') {
1286
1488
  warningAt("Empty class.", line,
1287
1489
  from + l - 1);
1288
- q = true;
1289
1490
  }
1491
+ isLiteral = false;
1492
+ isInRange = false;
1290
1493
  klass: do {
1291
1494
  c = s.charAt(l);
1292
1495
  l += 1;
@@ -1295,19 +1498,31 @@ klass: do {
1295
1498
  case '^':
1296
1499
  warningAt("Unescaped '{a}'.",
1297
1500
  line, from + l, c);
1298
- q = true;
1501
+ if (isInRange) {
1502
+ isInRange = false;
1503
+ } else {
1504
+ isLiteral = true;
1505
+ }
1299
1506
  break;
1300
1507
  case '-':
1301
- if (q) {
1302
- q = false;
1508
+ if (isLiteral && !isInRange) {
1509
+ isLiteral = false;
1510
+ isInRange = true;
1511
+ } else if (isInRange) {
1512
+ isInRange = false;
1513
+ } else if (s.charAt(l) === ']') {
1514
+ isInRange = true;
1303
1515
  } else {
1304
- warningAt("Unescaped '{a}'.",
1305
- line, from + l, '-');
1306
- q = true;
1516
+ if (option.regexdash !== (l === 2 || (l === 3 &&
1517
+ s.charAt(1) === '^'))) {
1518
+ warningAt("Unescaped '{a}'.",
1519
+ line, from + l - 1, '-');
1520
+ }
1521
+ isLiteral = true;
1307
1522
  }
1308
1523
  break;
1309
1524
  case ']':
1310
- if (!q) {
1525
+ if (isInRange && !option.regexdash) {
1311
1526
  warningAt("Unescaped '{a}'.",
1312
1527
  line, from + l - 1, '-');
1313
1528
  }
@@ -1322,18 +1537,44 @@ klass: do {
1322
1537
  "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
1323
1538
  }
1324
1539
  l += 1;
1325
- q = true;
1540
+
1541
+ // \w, \s and \d are never part of a character range
1542
+ if (/[wsd]/i.test(c)) {
1543
+ if (isInRange) {
1544
+ warningAt("Unescaped '{a}'.",
1545
+ line, from + l, '-');
1546
+ isInRange = false;
1547
+ }
1548
+ isLiteral = false;
1549
+ } else if (isInRange) {
1550
+ isInRange = false;
1551
+ } else {
1552
+ isLiteral = true;
1553
+ }
1326
1554
  break;
1327
1555
  case '/':
1328
1556
  warningAt("Unescaped '{a}'.",
1329
1557
  line, from + l - 1, '/');
1330
- q = true;
1558
+
1559
+ if (isInRange) {
1560
+ isInRange = false;
1561
+ } else {
1562
+ isLiteral = true;
1563
+ }
1331
1564
  break;
1332
1565
  case '<':
1333
- q = true;
1566
+ if (isInRange) {
1567
+ isInRange = false;
1568
+ } else {
1569
+ isLiteral = true;
1570
+ }
1334
1571
  break;
1335
1572
  default:
1336
- q = true;
1573
+ if (isInRange) {
1574
+ isInRange = false;
1575
+ } else {
1576
+ isLiteral = true;
1577
+ }
1337
1578
  }
1338
1579
  } while (c);
1339
1580
  break;
@@ -1441,13 +1682,12 @@ klass: do {
1441
1682
  }
1442
1683
 
1443
1684
  // Define t in the current function in the current scope.
1444
-
1445
1685
  if (is_own(funct, t) && !funct['(global)']) {
1446
1686
  if (funct[t] === true) {
1447
1687
  if (option.latedef)
1448
1688
  warning("'{a}' was used before it was defined.", nexttoken, t);
1449
1689
  } else {
1450
- if (!option.shadow)
1690
+ if (!option.shadow && type !== "exception")
1451
1691
  warning("'{a}' is already defined.", nexttoken, t);
1452
1692
  }
1453
1693
  }
@@ -1538,6 +1778,15 @@ loop: for (;;) {
1538
1778
  v, v.value);
1539
1779
  }
1540
1780
  obj.maxlen = b;
1781
+ } else if (t.value === 'validthis') {
1782
+ if (funct['(global)']) {
1783
+ error("Option 'validthis' can't be used in a global scope.");
1784
+ } else {
1785
+ if (v.value === 'true' || v.value === 'false')
1786
+ obj[t.value] = v.value === 'true';
1787
+ else
1788
+ error("Bad option value.", v);
1789
+ }
1541
1790
  } else if (v.value === 'true') {
1542
1791
  obj[t.value] = true;
1543
1792
  } else if (v.value === 'false') {
@@ -1601,6 +1850,7 @@ loop: for (;;) {
1601
1850
  }
1602
1851
  break;
1603
1852
  }
1853
+
1604
1854
  if (token.type === '(string)' || token.identifier) {
1605
1855
  anonname = token.value;
1606
1856
  }
@@ -1619,6 +1869,7 @@ loop: for (;;) {
1619
1869
  nexttoken, id, nexttoken.value);
1620
1870
  }
1621
1871
  }
1872
+
1622
1873
  prevtoken = token;
1623
1874
  token = nexttoken;
1624
1875
  for (;;) {
@@ -1679,9 +1930,9 @@ loop: for (;;) {
1679
1930
  }
1680
1931
  }
1681
1932
  while (rbp < nexttoken.lbp) {
1682
- isArray = token.value == 'Array';
1933
+ isArray = token.value === 'Array';
1683
1934
  advance();
1684
- if (isArray && token.id == '(' && nexttoken.id == ')')
1935
+ if (isArray && token.id === '(' && nexttoken.id === ')')
1685
1936
  warning("Use the array literal notation [].", token);
1686
1937
  if (token.led) {
1687
1938
  left = token.led(left);
@@ -1702,7 +1953,8 @@ loop: for (;;) {
1702
1953
  right = right || nexttoken;
1703
1954
  if (option.white) {
1704
1955
  if (left.character !== right.from && left.line === right.line) {
1705
- warning("Unexpected space after '{a}'.", right, left.value);
1956
+ left.from += (left.character - left.from);
1957
+ warning("Unexpected space after '{a}'.", left, left.value);
1706
1958
  }
1707
1959
  }
1708
1960
  }
@@ -1730,8 +1982,9 @@ loop: for (;;) {
1730
1982
  left = left || token;
1731
1983
  right = right || nexttoken;
1732
1984
  if (left.line === right.line && left.character === right.from) {
1985
+ left.from += (left.character - left.from);
1733
1986
  warning("Missing space after '{a}'.",
1734
- nexttoken, left.value);
1987
+ left, left.value);
1735
1988
  }
1736
1989
  }
1737
1990
  }
@@ -1745,8 +1998,9 @@ loop: for (;;) {
1745
1998
  left = left || token;
1746
1999
  right = right || nexttoken;
1747
2000
  if (left.character === right.from) {
2001
+ left.from += (left.character - left.from);
1748
2002
  warning("Missing space after '{a}'.",
1749
- nexttoken, left.value);
2003
+ left, left.value);
1750
2004
  }
1751
2005
  }
1752
2006
  }
@@ -1773,16 +2027,23 @@ loop: for (;;) {
1773
2027
 
1774
2028
  function comma() {
1775
2029
  if (token.line !== nexttoken.line) {
1776
- if (!option.laxbreak) {
2030
+ if (!option.laxcomma) {
2031
+ if (comma.first) {
2032
+ warning("Comma warnings can be turned off with 'laxcomma'");
2033
+ comma.first = false;
2034
+ }
1777
2035
  warning("Bad line breaking before '{a}'.", token, nexttoken.id);
1778
2036
  }
1779
- } else if (token.character !== nexttoken.from && option.white) {
1780
- warning("Unexpected space after '{a}'.", nexttoken, token.value);
2037
+ } else if (!token.comment && token.character !== nexttoken.from && option.white) {
2038
+ token.from += (token.character - token.from);
2039
+ warning("Unexpected space after '{a}'.", token, token.value);
1781
2040
  }
1782
2041
  advance(',');
1783
2042
  nonadjacent(token, nexttoken);
1784
2043
  }
1785
2044
 
2045
+ comma.first = true;
2046
+
1786
2047
 
1787
2048
  // Functional constructors for making the symbols that will be inherited by
1788
2049
  // tokens.
@@ -1882,6 +2143,9 @@ loop: for (;;) {
1882
2143
  nobreaknonadjacent(prevtoken, token);
1883
2144
  nonadjacent(token, nexttoken);
1884
2145
  }
2146
+ if (s === "in" && left.id === "!") {
2147
+ warning("Confusing use of '{a}'.", left, '!');
2148
+ }
1885
2149
  if (typeof f === 'function') {
1886
2150
  return f(left, this);
1887
2151
  } else {
@@ -1909,7 +2173,7 @@ loop: for (;;) {
1909
2173
  warning("Confusing use of '{a}'.", left, '!');
1910
2174
  }
1911
2175
  if (right.id === '!') {
1912
- warning("Confusing use of '{a}'.", left, '!');
2176
+ warning("Confusing use of '{a}'.", right, '!');
1913
2177
  }
1914
2178
  this.left = left;
1915
2179
  this.right = right;
@@ -1942,6 +2206,9 @@ loop: for (;;) {
1942
2206
  warning("'{a}' is a function.", left, left.value);
1943
2207
  }
1944
2208
  if (left) {
2209
+ if (option.esnext && funct[left.value] === 'const') {
2210
+ warning("Attempting to override '{a}' which is a constant", left, left.value);
2211
+ }
1945
2212
  if (left.id === '.' || left.id === '[') {
1946
2213
  if (!left.left || left.left.value === 'arguments') {
1947
2214
  warning('Bad assignment.', that);
@@ -2032,7 +2299,7 @@ loop: for (;;) {
2032
2299
  // `undefined` as a function param is a common pattern to protect
2033
2300
  // against the case when somebody does `undefined = true` and
2034
2301
  // help with minification. More info: https://gist.github.com/315916
2035
- if (!fnparam || token.value != 'undefined') {
2302
+ if (!fnparam || token.value !== 'undefined') {
2036
2303
  warning("Expected an identifier and instead saw '{a}' (a reserved word).",
2037
2304
  token, token.id);
2038
2305
  }
@@ -2069,6 +2336,9 @@ loop: for (;;) {
2069
2336
  }
2070
2337
  if (t.id !== '(endline)') {
2071
2338
  if (t.id === 'function') {
2339
+ if (!option.latedef) {
2340
+ break;
2341
+ }
2072
2342
  warning(
2073
2343
  "Inner functions should be listed at the top of the outer function.", t);
2074
2344
  break;
@@ -2084,11 +2354,8 @@ loop: for (;;) {
2084
2354
  function statement(noindent) {
2085
2355
  var i = indent, r, s = scope, t = nexttoken;
2086
2356
 
2087
- // We don't like the empty statement.
2088
-
2089
- if (t.id === ';') {
2090
- warning("Unnecessary semicolon.", t);
2091
- advance(';');
2357
+ if (t.id === ";") {
2358
+ advance(";");
2092
2359
  return;
2093
2360
  }
2094
2361
 
@@ -2118,17 +2385,24 @@ loop: for (;;) {
2118
2385
  }
2119
2386
  r = expression(0, true);
2120
2387
 
2121
- // Look for the final semicolon.
2122
-
2388
+ // Look for the final semicolon.
2123
2389
  if (!t.block) {
2124
2390
  if (!option.expr && (!r || !r.exps)) {
2125
- warning("Expected an assignment or function call and instead saw an expression.", token);
2391
+ warning("Expected an assignment or function call and instead saw an expression.",
2392
+ token);
2126
2393
  } else if (option.nonew && r.id === '(' && r.left.id === 'new') {
2127
2394
  warning("Do not use 'new' for side effects.");
2128
2395
  }
2396
+
2129
2397
  if (nexttoken.id !== ';') {
2130
2398
  if (!option.asi) {
2131
- warningAt("Missing semicolon.", token.line, token.from + token.value.length);
2399
+ // If this is the last statement in a block that ends on
2400
+ // the same line *and* option lastsemic is on, ignore the warning.
2401
+ // Otherwise, complain about missing semicolon.
2402
+ if (!option.lastsemic || nexttoken.id !== '}' ||
2403
+ nexttoken.line !== token.line) {
2404
+ warningAt("Missing semicolon.", token.line, token.character);
2405
+ }
2132
2406
  }
2133
2407
  } else {
2134
2408
  adjacent(token, nexttoken);
@@ -2145,72 +2419,142 @@ loop: for (;;) {
2145
2419
  }
2146
2420
 
2147
2421
 
2148
- function use_strict() {
2149
- if (nexttoken.value === 'use strict') {
2150
- if (strict_mode) {
2151
- warning("Unnecessary \"use strict\".");
2152
- }
2153
- advance();
2154
- advance(';');
2155
- strict_mode = true;
2156
- option.newcap = true;
2157
- option.undef = true;
2158
- return true;
2159
- } else {
2160
- return false;
2161
- }
2162
- }
2163
-
2164
-
2165
- function statements(begin) {
2422
+ function statements(startLine) {
2166
2423
  var a = [], f, p;
2167
2424
 
2168
2425
  while (!nexttoken.reach && nexttoken.id !== '(end)') {
2169
2426
  if (nexttoken.id === ';') {
2170
- warning("Unnecessary semicolon.");
2427
+ p = peek();
2428
+ if (!p || p.id !== "(") {
2429
+ warning("Unnecessary semicolon.");
2430
+ }
2171
2431
  advance(';');
2172
2432
  } else {
2173
- a.push(statement());
2433
+ a.push(statement(startLine === nexttoken.line));
2174
2434
  }
2175
2435
  }
2176
2436
  return a;
2177
2437
  }
2178
2438
 
2179
2439
 
2440
+ /*
2441
+ * read all directives
2442
+ * recognizes a simple form of asi, but always
2443
+ * warns, if it is used
2444
+ */
2445
+ function directives() {
2446
+ var i, p, pn;
2447
+
2448
+ for (;;) {
2449
+ if (nexttoken.id === "(string)") {
2450
+ p = peek(0);
2451
+ if (p.id === "(endline)") {
2452
+ i = 1;
2453
+ do {
2454
+ pn = peek(i);
2455
+ i = i + 1;
2456
+ } while (pn.id === "(endline)");
2457
+
2458
+ if (pn.id !== ";") {
2459
+ if (pn.id !== "(string)" && pn.id !== "(number)" &&
2460
+ pn.id !== "(regexp)" && pn.identifier !== true &&
2461
+ pn.id !== "}") {
2462
+ break;
2463
+ }
2464
+ warning("Missing semicolon.", nexttoken);
2465
+ } else {
2466
+ p = pn;
2467
+ }
2468
+ } else if (p.id === "}") {
2469
+ // directive with no other statements, warn about missing semicolon
2470
+ warning("Missing semicolon.", p);
2471
+ } else if (p.id !== ";") {
2472
+ break;
2473
+ }
2474
+
2475
+ indentation();
2476
+ advance();
2477
+ if (directive[token.value]) {
2478
+ warning("Unnecessary directive \"{a}\".", token, token.value);
2479
+ }
2480
+
2481
+ if (token.value === "use strict") {
2482
+ option.newcap = true;
2483
+ option.undef = true;
2484
+ }
2485
+
2486
+ // there's no directive negation, so always set to true
2487
+ directive[token.value] = true;
2488
+
2489
+ if (p.id === ";") {
2490
+ advance(";");
2491
+ }
2492
+ continue;
2493
+ }
2494
+ break;
2495
+ }
2496
+ }
2497
+
2498
+
2180
2499
  /*
2181
2500
  * Parses a single block. A block is a sequence of statements wrapped in
2182
2501
  * braces.
2183
2502
  *
2184
2503
  * ordinary - true for everything but function bodies and try blocks.
2185
2504
  * stmt - true if block can be a single statement (e.g. in if/for/while).
2505
+ * isfunc - true if block is a function body
2186
2506
  */
2187
- function block(ordinary, stmt) {
2507
+ function block(ordinary, stmt, isfunc) {
2188
2508
  var a,
2189
2509
  b = inblock,
2190
2510
  old_indent = indent,
2191
- m = strict_mode,
2511
+ m,
2192
2512
  s = scope,
2193
- t;
2513
+ t,
2514
+ line,
2515
+ d;
2194
2516
 
2195
2517
  inblock = ordinary;
2196
- scope = Object.create(scope);
2518
+ if (!ordinary || !option.funcscope) scope = Object.create(scope);
2197
2519
  nonadjacent(token, nexttoken);
2198
2520
  t = nexttoken;
2199
2521
 
2200
2522
  if (nexttoken.id === '{') {
2201
2523
  advance('{');
2202
- if (nexttoken.id !== '}' || token.line !== nexttoken.line) {
2524
+ line = token.line;
2525
+ if (nexttoken.id !== '}') {
2203
2526
  indent += option.indent;
2204
2527
  while (!ordinary && nexttoken.from > indent) {
2205
2528
  indent += option.indent;
2206
2529
  }
2207
- if (!ordinary && !use_strict() && !m && option.strict &&
2208
- funct['(context)']['(global)']) {
2209
- warning("Missing \"use strict\" statement.");
2530
+
2531
+ if (isfunc) {
2532
+ m = {};
2533
+ for (d in directive) {
2534
+ if (is_own(directive, d)) {
2535
+ m[d] = directive[d];
2536
+ }
2537
+ }
2538
+ directives();
2539
+
2540
+ if (option.strict && funct['(context)']['(global)']) {
2541
+ if (!m["use strict"] && !directive["use strict"]) {
2542
+ warning("Missing \"use strict\" statement.");
2543
+ }
2544
+ }
2545
+ }
2546
+
2547
+ a = statements(line);
2548
+
2549
+ if (isfunc) {
2550
+ directive = m;
2210
2551
  }
2211
- a = statements();
2212
- strict_mode = m;
2552
+
2213
2553
  indent -= option.indent;
2554
+ if (line !== nexttoken.line) {
2555
+ indentation();
2556
+ }
2557
+ } else if (line !== nexttoken.line) {
2214
2558
  indentation();
2215
2559
  }
2216
2560
  advance('}', t);
@@ -2224,11 +2568,14 @@ loop: for (;;) {
2224
2568
  nexttoken, '{', nexttoken.value);
2225
2569
 
2226
2570
  noreach = true;
2227
- a = [statement()];
2571
+ indent += option.indent;
2572
+ // test indentation only if statement is in new line
2573
+ a = [statement(nexttoken.line === token.line)];
2574
+ indent -= option.indent;
2228
2575
  noreach = false;
2229
2576
  }
2230
2577
  funct['(verb)'] = null;
2231
- scope = s;
2578
+ if (!ordinary || !option.funcscope) scope = s;
2232
2579
  inblock = b;
2233
2580
  if (ordinary && option.noempty && (!a || a.length === 0)) {
2234
2581
  warning("Empty block.");
@@ -2254,6 +2601,7 @@ loop: for (;;) {
2254
2601
  if (typeof a === 'function') {
2255
2602
  a = false;
2256
2603
  }
2604
+
2257
2605
  if (!a) {
2258
2606
  a = [line];
2259
2607
  implied[name] = a;
@@ -2262,11 +2610,13 @@ loop: for (;;) {
2262
2610
  }
2263
2611
  }
2264
2612
 
2265
- // Build the syntax table by declaring the syntactic elements of the language.
2613
+
2614
+ // Build the syntax table by declaring the syntactic elements of the language.
2266
2615
 
2267
2616
  type('(number)', function () {
2268
2617
  return this;
2269
2618
  });
2619
+
2270
2620
  type('(string)', function () {
2271
2621
  return this;
2272
2622
  });
@@ -2279,10 +2629,9 @@ loop: for (;;) {
2279
2629
  var v = this.value,
2280
2630
  s = scope[v],
2281
2631
  f;
2282
- if (typeof s === 'function') {
2283
-
2284
- // Protection against accidental inheritance.
2285
2632
 
2633
+ if (typeof s === 'function') {
2634
+ // Protection against accidental inheritance.
2286
2635
  s = undefined;
2287
2636
  } else if (typeof s === 'boolean') {
2288
2637
  f = funct;
@@ -2292,12 +2641,9 @@ loop: for (;;) {
2292
2641
  funct = f;
2293
2642
  }
2294
2643
 
2295
- // The name is in scope and defined in the current function.
2296
-
2644
+ // The name is in scope and defined in the current function.
2297
2645
  if (funct === s) {
2298
-
2299
- // Change 'unused' to 'var', and reject labels.
2300
-
2646
+ // Change 'unused' to 'var', and reject labels.
2301
2647
  switch (funct[v]) {
2302
2648
  case 'unused':
2303
2649
  funct[v] = 'var';
@@ -2313,25 +2659,28 @@ loop: for (;;) {
2313
2659
  warning("'{a}' is a statement label.", token, v);
2314
2660
  break;
2315
2661
  }
2316
-
2317
- // The name is not defined in the function. If we are in the global scope,
2318
- // then we have an undefined variable.
2319
- //
2320
- // Operators typeof and delete do not raise runtime errors even if the base
2321
- // object of a reference is null so no need to display warning if we're
2322
- // inside of typeof or delete.
2323
-
2324
2662
  } else if (funct['(global)']) {
2325
- if (anonname != 'typeof' && anonname != 'delete' &&
2326
- option.undef && typeof predefined[v] !== 'boolean') {
2327
- warning("'{a}' is not defined.", token, v);
2663
+ // The name is not defined in the function. If we are in the global
2664
+ // scope, then we have an undefined variable.
2665
+ //
2666
+ // Operators typeof and delete do not raise runtime errors even if
2667
+ // the base object of a reference is null so no need to display warning
2668
+ // if we're inside of typeof or delete.
2669
+
2670
+ if (option.undef && typeof predefined[v] !== 'boolean') {
2671
+ // Attempting to subscript a null reference will throw an
2672
+ // error, even within the typeof and delete operators
2673
+ if (!(anonname === 'typeof' || anonname === 'delete') ||
2674
+ (nexttoken && (nexttoken.value === '.' || nexttoken.value === '['))) {
2675
+
2676
+ isundef(funct, "'{a}' is not defined.", token, v);
2677
+ }
2328
2678
  }
2329
2679
  note_implied(token);
2330
-
2331
- // If the name is already defined in the current
2332
- // function, but not as outer, then there is a scope error.
2333
-
2334
2680
  } else {
2681
+ // If the name is already defined in the current
2682
+ // function, but not as outer, then there is a scope error.
2683
+
2335
2684
  switch (funct[v]) {
2336
2685
  case 'closure':
2337
2686
  case 'function':
@@ -2346,25 +2695,28 @@ loop: for (;;) {
2346
2695
  case 'global':
2347
2696
  break;
2348
2697
  default:
2349
-
2350
- // If the name is defined in an outer function, make an outer entry, and if
2351
- // it was unused, make it var.
2352
-
2698
+ // If the name is defined in an outer function, make an outer entry,
2699
+ // and if it was unused, make it var.
2353
2700
  if (s === true) {
2354
2701
  funct[v] = true;
2355
2702
  } else if (s === null) {
2356
2703
  warning("'{a}' is not allowed.", token, v);
2357
2704
  note_implied(token);
2358
2705
  } else if (typeof s !== 'object') {
2359
-
2360
- // Operators typeof and delete do not raise runtime errors even if the base object of
2361
- // a reference is null so no need to display warning if we're inside of typeof or delete.
2362
-
2363
- if (anonname != 'typeof' && anonname != 'delete' && option.undef) {
2364
- warning("'{a}' is not defined.", token, v);
2365
- } else {
2366
- funct[v] = true;
2706
+ // Operators typeof and delete do not raise runtime errors even
2707
+ // if the base object of a reference is null so no need to
2708
+ // display warning if we're inside of typeof or delete.
2709
+ if (option.undef) {
2710
+ // Attempting to subscript a null reference will throw an
2711
+ // error, even within the typeof and delete operators
2712
+ if (!(anonname === 'typeof' || anonname === 'delete') ||
2713
+ (nexttoken &&
2714
+ (nexttoken.value === '.' || nexttoken.value === '['))) {
2715
+
2716
+ isundef(funct, "'{a}' is not defined.", token, v);
2717
+ }
2367
2718
  }
2719
+ funct[v] = true;
2368
2720
  note_implied(token);
2369
2721
  } else {
2370
2722
  switch (s[v]) {
@@ -2428,7 +2780,7 @@ loop: for (;;) {
2428
2780
  reserve('default').reach = true;
2429
2781
  reserve('finally');
2430
2782
  reservevar('arguments', function (x) {
2431
- if (strict_mode && funct['(global)']) {
2783
+ if (directive['use strict'] && funct['(global)']) {
2432
2784
  warning("Strict violation.", x);
2433
2785
  }
2434
2786
  });
@@ -2438,9 +2790,9 @@ loop: for (;;) {
2438
2790
  reservevar('NaN');
2439
2791
  reservevar('null');
2440
2792
  reservevar('this', function (x) {
2441
- if (strict_mode && ((funct['(statement)'] &&
2793
+ if (directive['use strict'] && !option.validthis && ((funct['(statement)'] &&
2442
2794
  funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) {
2443
- warning("Strict violation.", x);
2795
+ warning("Possible strict violation.", x);
2444
2796
  }
2445
2797
  });
2446
2798
  reservevar('true');
@@ -2473,24 +2825,23 @@ loop: for (;;) {
2473
2825
  bitwise('^', 'bitxor', 80);
2474
2826
  bitwise('&', 'bitand', 90);
2475
2827
  relation('==', function (left, right) {
2476
- var eqnull = option.eqnull &&
2477
- (left.value == 'null' || right.value == 'null');
2828
+ var eqnull = option.eqnull && (left.value === 'null' || right.value === 'null');
2829
+
2830
+ if (!eqnull && option.eqeqeq)
2831
+ warning("Expected '{a}' and instead saw '{b}'.", this, '===', '==');
2832
+ else if (isPoorRelation(left))
2833
+ warning("Use '{a}' to compare with '{b}'.", this, '===', left.value);
2834
+ else if (isPoorRelation(right))
2835
+ warning("Use '{a}' to compare with '{b}'.", this, '===', right.value);
2478
2836
 
2479
- if (!eqnull && option.eqeqeq) {
2480
- warning("Expected '{a}' and instead saw '{b}'.",
2481
- this, '===', '==');
2482
- } else if (isPoorRelation(left)) {
2483
- warning("Use '{a}' to compare with '{b}'.",
2484
- this, '===', left.value);
2485
- } else if (isPoorRelation(right)) {
2486
- warning("Use '{a}' to compare with '{b}'.",
2487
- this, '===', right.value);
2488
- }
2489
2837
  return this;
2490
2838
  });
2491
2839
  relation('===');
2492
2840
  relation('!=', function (left, right) {
2493
- if (option.eqeqeq) {
2841
+ var eqnull = option.eqnull &&
2842
+ (left.value === 'null' || right.value === 'null');
2843
+
2844
+ if (!eqnull && option.eqeqeq) {
2494
2845
  warning("Expected '{a}' and instead saw '{b}'.",
2495
2846
  this, '!==', '!=');
2496
2847
  } else if (isPoorRelation(left)) {
@@ -2517,7 +2868,7 @@ loop: for (;;) {
2517
2868
  if (left && right && left.id === '(string)' && right.id === '(string)') {
2518
2869
  left.value += right.value;
2519
2870
  left.character = right.character;
2520
- if (jx.test(left.value)) {
2871
+ if (!option.scripturl && jx.test(left.value)) {
2521
2872
  warning("JavaScript URL.", left);
2522
2873
  }
2523
2874
  return left;
@@ -2618,7 +2969,8 @@ loop: for (;;) {
2618
2969
  if (c.id !== 'function') {
2619
2970
  i = c.value.substr(0, 1);
2620
2971
  if (option.newcap && (i < 'A' || i > 'Z')) {
2621
- warning("A constructor name should start with an uppercase letter.", token);
2972
+ warning("A constructor name should start with an uppercase letter.",
2973
+ token);
2622
2974
  }
2623
2975
  }
2624
2976
  }
@@ -2651,9 +3003,11 @@ loop: for (;;) {
2651
3003
  }
2652
3004
  that.left = left;
2653
3005
  that.right = m;
2654
- if (option.noarg && left && left.value === 'arguments' &&
2655
- (m === 'callee' || m === 'caller')) {
2656
- warning("Avoid arguments.{a}.", left, m);
3006
+ if (left && left.value === 'arguments' && (m === 'callee' || m === 'caller')) {
3007
+ if (option.noarg)
3008
+ warning("Avoid arguments.{a}.", left, m);
3009
+ else if (directive['use strict'])
3010
+ error('Strict violation.');
2657
3011
  } else if (!option.evil && left && left.value === 'document' &&
2658
3012
  (m === 'write' || m === 'writeln')) {
2659
3013
  warning("document.write can be a form of eval.", left);
@@ -2738,7 +3092,8 @@ loop: for (;;) {
2738
3092
  advance(')', this);
2739
3093
  nospace(prevtoken, token);
2740
3094
  if (option.immed && v.id === 'function') {
2741
- if (nexttoken.id === '(') {
3095
+ if (nexttoken.id === '(' ||
3096
+ (nexttoken.id === '.' && (peek().value === 'call' || peek().value === 'apply'))) {
2742
3097
  warning(
2743
3098
  "Move the invocation into the parens that contain the function.", nexttoken);
2744
3099
  } else {
@@ -2835,7 +3190,6 @@ loop: for (;;) {
2835
3190
  nospace();
2836
3191
  if (nexttoken.id === ')') {
2837
3192
  advance(')');
2838
- nospace(prevtoken, token);
2839
3193
  return;
2840
3194
  }
2841
3195
  for (;;) {
@@ -2878,7 +3232,7 @@ loop: for (;;) {
2878
3232
  }
2879
3233
  funct['(params)'] = functionparams();
2880
3234
 
2881
- block(false);
3235
+ block(false, false, true);
2882
3236
  scope = oldScope;
2883
3237
  option = oldOption;
2884
3238
  funct['(last)'] = token.line;
@@ -2889,7 +3243,42 @@ loop: for (;;) {
2889
3243
 
2890
3244
  (function (x) {
2891
3245
  x.nud = function () {
2892
- var b, f, i, j, p, seen = {}, t;
3246
+ var b, f, i, j, p, t;
3247
+ var props = {}; // All properties, including accessors
3248
+
3249
+ function saveProperty(name, token) {
3250
+ if (props[name] && is_own(props, name))
3251
+ warning("Duplicate member '{a}'.", nexttoken, i);
3252
+ else
3253
+ props[name] = {};
3254
+
3255
+ props[name].basic = true;
3256
+ props[name].basicToken = token;
3257
+ }
3258
+
3259
+ function saveSetter(name, token) {
3260
+ if (props[name] && is_own(props, name)) {
3261
+ if (props[name].basic || props[name].setter)
3262
+ warning("Duplicate member '{a}'.", nexttoken, i);
3263
+ } else {
3264
+ props[name] = {};
3265
+ }
3266
+
3267
+ props[name].setter = true;
3268
+ props[name].setterToken = token;
3269
+ }
3270
+
3271
+ function saveGetter(name) {
3272
+ if (props[name] && is_own(props, name)) {
3273
+ if (props[name].basic || props[name].getter)
3274
+ warning("Duplicate member '{a}'.", nexttoken, i);
3275
+ } else {
3276
+ props[name] = {};
3277
+ }
3278
+
3279
+ props[name].getter = true;
3280
+ props[name].getterToken = token;
3281
+ }
2893
3282
 
2894
3283
  b = token.line !== nexttoken.line;
2895
3284
  if (b) {
@@ -2914,33 +3303,35 @@ loop: for (;;) {
2914
3303
  if (!i) {
2915
3304
  error("Missing property name.");
2916
3305
  }
3306
+ saveGetter(i);
2917
3307
  t = nexttoken;
2918
3308
  adjacent(token, nexttoken);
2919
3309
  f = doFunction();
2920
- if (!option.loopfunc && funct['(loopage)']) {
2921
- warning("Don't make functions within a loop.", t);
2922
- }
2923
3310
  p = f['(params)'];
2924
3311
  if (p) {
2925
3312
  warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
2926
3313
  }
2927
3314
  adjacent(token, nexttoken);
2928
- advance(',');
2929
- indentation();
3315
+ } else if (nexttoken.value === 'set' && peek().id !== ':') {
2930
3316
  advance('set');
2931
- j = property_name();
2932
- if (i !== j) {
2933
- error("Expected {a} and instead saw {b}.", token, i, j);
3317
+ if (!option.es5) {
3318
+ error("get/set are ES5 features.");
2934
3319
  }
3320
+ i = property_name();
3321
+ if (!i) {
3322
+ error("Missing property name.");
3323
+ }
3324
+ saveSetter(i, nexttoken);
2935
3325
  t = nexttoken;
2936
3326
  adjacent(token, nexttoken);
2937
3327
  f = doFunction();
2938
3328
  p = f['(params)'];
2939
- if (!p || p.length !== 1 || p[0] !== 'value') {
2940
- warning("Expected (value) in set {a} function.", t, i);
3329
+ if (!p || p.length !== 1) {
3330
+ warning("Expected a single parameter in set {a} function.", t, i);
2941
3331
  }
2942
3332
  } else {
2943
3333
  i = property_name();
3334
+ saveProperty(i, nexttoken);
2944
3335
  if (typeof i !== 'string') {
2945
3336
  break;
2946
3337
  }
@@ -2948,10 +3339,7 @@ loop: for (;;) {
2948
3339
  nonadjacent(token, nexttoken);
2949
3340
  expression(10);
2950
3341
  }
2951
- if (seen[i] === true) {
2952
- warning("Duplicate member '{a}'.", nexttoken, i);
2953
- }
2954
- seen[i] = true;
3342
+
2955
3343
  countMember(i);
2956
3344
  if (nexttoken.id === ',') {
2957
3345
  comma();
@@ -2969,6 +3357,15 @@ loop: for (;;) {
2969
3357
  indentation();
2970
3358
  }
2971
3359
  advance('}', this);
3360
+
3361
+ // Check for lonely setters if in the ES5 mode.
3362
+ if (option.es5) {
3363
+ for (var name in props) {
3364
+ if (is_own(props, name) && props[name].setter && !props[name].getter) {
3365
+ warning("Setter is defined without getter.", props[name].setterToken);
3366
+ }
3367
+ }
3368
+ }
2972
3369
  return this;
2973
3370
  };
2974
3371
  x.fud = function () {
@@ -2976,6 +3373,61 @@ loop: for (;;) {
2976
3373
  };
2977
3374
  }(delim('{')));
2978
3375
 
3376
+ // This Function is called when esnext option is set to true
3377
+ // it adds the `const` statement to JSHINT
3378
+
3379
+ useESNextSyntax = function () {
3380
+ var conststatement = stmt('const', function (prefix) {
3381
+ var id, name, value;
3382
+
3383
+ this.first = [];
3384
+ for (;;) {
3385
+ nonadjacent(token, nexttoken);
3386
+ id = identifier();
3387
+ if (funct[id] === "const") {
3388
+ warning("const '" + id + "' has already been declared");
3389
+ }
3390
+ if (funct['(global)'] && predefined[id] === false) {
3391
+ warning("Redefinition of '{a}'.", token, id);
3392
+ }
3393
+ addlabel(id, 'const');
3394
+ if (prefix) {
3395
+ break;
3396
+ }
3397
+ name = token;
3398
+ this.first.push(token);
3399
+
3400
+ if (nexttoken.id !== "=") {
3401
+ warning("const " +
3402
+ "'{a}' is initialized to 'undefined'.", token, id);
3403
+ }
3404
+
3405
+ if (nexttoken.id === '=') {
3406
+ nonadjacent(token, nexttoken);
3407
+ advance('=');
3408
+ nonadjacent(token, nexttoken);
3409
+ if (nexttoken.id === 'undefined') {
3410
+ warning("It is not necessary to initialize " +
3411
+ "'{a}' to 'undefined'.", token, id);
3412
+ }
3413
+ if (peek(0).id === '=' && nexttoken.identifier) {
3414
+ error("Constant {a} was not declared correctly.",
3415
+ nexttoken, nexttoken.value);
3416
+ }
3417
+ value = expression(0);
3418
+ name.first = value;
3419
+ }
3420
+
3421
+ if (nexttoken.id !== ',') {
3422
+ break;
3423
+ }
3424
+ comma();
3425
+ }
3426
+ return this;
3427
+ });
3428
+ conststatement.exps = true;
3429
+ };
3430
+
2979
3431
  var varstatement = stmt('var', function (prefix) {
2980
3432
  // JavaScript does not have block scope. It only has function scope. So,
2981
3433
  // declaring a variable in a block can have unexpected consequences.
@@ -2990,6 +3442,9 @@ loop: for (;;) {
2990
3442
  for (;;) {
2991
3443
  nonadjacent(token, nexttoken);
2992
3444
  id = identifier();
3445
+ if (option.esnext && funct[id] === "const") {
3446
+ warning("const '" + id + "' has already been declared");
3447
+ }
2993
3448
  if (funct['(global)'] && predefined[id] === false) {
2994
3449
  warning("Redefinition of '{a}'.", token, id);
2995
3450
  }
@@ -3024,11 +3479,15 @@ loop: for (;;) {
3024
3479
 
3025
3480
  blockstmt('function', function () {
3026
3481
  if (inblock) {
3027
- warning(
3028
- "Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.", token);
3482
+ warning("Function declarations should not be placed in blocks. " +
3483
+ "Use a function expression or move the statement to the top of " +
3484
+ "the outer function.", token);
3029
3485
 
3030
3486
  }
3031
3487
  var i = identifier();
3488
+ if (option.esnext && funct[i] === "const") {
3489
+ warning("const '" + i + "' has already been declared");
3490
+ }
3032
3491
  adjacent(token, nexttoken);
3033
3492
  addlabel(i, 'unction');
3034
3493
  doFunction(i, true);
@@ -3207,7 +3666,8 @@ loop: for (;;) {
3207
3666
  advance('}', t);
3208
3667
  if (this.cases.length === 1 || this.condition.id === 'true' ||
3209
3668
  this.condition.id === 'false') {
3210
- warning("This 'switch' should be an 'if'.", this);
3669
+ if (!option.onecase)
3670
+ warning("This 'switch' should be an 'if'.", this);
3211
3671
  }
3212
3672
  funct['(breakage)'] -= 1;
3213
3673
  funct['(verb)'] = undefined;
@@ -3222,14 +3682,23 @@ loop: for (;;) {
3222
3682
  error("Each value should have its own case label.");
3223
3683
  return;
3224
3684
  case ':':
3685
+ g = false;
3225
3686
  statements();
3226
3687
  break;
3227
3688
  default:
3228
3689
  error("Missing ':' on a case clause.", token);
3690
+ return;
3229
3691
  }
3230
3692
  } else {
3231
- error("Expected '{a}' and instead saw '{b}'.",
3232
- nexttoken, 'case', nexttoken.value);
3693
+ if (token.id === ':') {
3694
+ advance(':');
3695
+ error("Unexpected '{a}'.", token, ':');
3696
+ statements();
3697
+ } else {
3698
+ error("Expected '{a}' and instead saw '{b}'.",
3699
+ nexttoken, 'case', nexttoken.value);
3700
+ return;
3701
+ }
3233
3702
  }
3234
3703
  }
3235
3704
  }
@@ -3297,9 +3766,10 @@ loop: for (;;) {
3297
3766
  expression(20);
3298
3767
  advance(')', t);
3299
3768
  s = block(true, true);
3300
- if (option.forin && (s.length > 1 || typeof s[0] !== 'object' ||
3769
+ if (option.forin && s && (s.length > 1 || typeof s[0] !== 'object' ||
3301
3770
  s[0].value !== 'if')) {
3302
- warning("The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.", this);
3771
+ warning("The body of a for in should be wrapped in an if statement to filter " +
3772
+ "unwanted properties from the prototype.", this);
3303
3773
  }
3304
3774
  funct['(breakage)'] -= 1;
3305
3775
  funct['(loopage)'] -= 1;
@@ -3357,10 +3827,13 @@ loop: for (;;) {
3357
3827
 
3358
3828
  stmt('break', function () {
3359
3829
  var v = nexttoken.value;
3360
- if (funct['(breakage)'] === 0) {
3830
+
3831
+ if (funct['(breakage)'] === 0)
3361
3832
  warning("Unexpected '{a}'.", nexttoken, this.value);
3362
- }
3363
- nolinebreak(this);
3833
+
3834
+ if (!option.asi)
3835
+ nolinebreak(this);
3836
+
3364
3837
  if (nexttoken.id !== ';') {
3365
3838
  if (token.line === nexttoken.line) {
3366
3839
  if (funct[v] !== 'label') {
@@ -3379,10 +3852,13 @@ loop: for (;;) {
3379
3852
 
3380
3853
  stmt('continue', function () {
3381
3854
  var v = nexttoken.value;
3382
- if (funct['(breakage)'] === 0) {
3855
+
3856
+ if (funct['(breakage)'] === 0)
3383
3857
  warning("Unexpected '{a}'.", nexttoken, this.value);
3384
- }
3385
- nolinebreak(this);
3858
+
3859
+ if (!option.asi)
3860
+ nolinebreak(this);
3861
+
3386
3862
  if (nexttoken.id !== ';') {
3387
3863
  if (token.line === nexttoken.line) {
3388
3864
  if (funct[v] !== 'label') {
@@ -3402,13 +3878,20 @@ loop: for (;;) {
3402
3878
 
3403
3879
 
3404
3880
  stmt('return', function () {
3405
- nolinebreak(this);
3406
- if (nexttoken.id === '(regexp)') {
3407
- warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
3408
- }
3409
- if (nexttoken.id !== ';' && !nexttoken.reach) {
3410
- nonadjacent(token, nexttoken);
3411
- this.first = expression(20);
3881
+ if (this.line === nexttoken.line) {
3882
+ if (nexttoken.id === '(regexp)')
3883
+ warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");
3884
+
3885
+ if (nexttoken.id !== ';' && !nexttoken.reach) {
3886
+ nonadjacent(token, nexttoken);
3887
+ if (peek().value === "=" && !option.boss) {
3888
+ warningAt("Did you mean to return a conditional instead of an assignment?",
3889
+ token.line, token.character + 1);
3890
+ }
3891
+ this.first = expression(0);
3892
+ }
3893
+ } else if (!option.asi) {
3894
+ nolinebreak(this); // always warn (Line breaking error)
3412
3895
  }
3413
3896
  reachable('return');
3414
3897
  return this;
@@ -3468,9 +3951,11 @@ loop: for (;;) {
3468
3951
  if (o[nexttoken.value] === true) {
3469
3952
  warning("Duplicate key '{a}'.",
3470
3953
  nexttoken, nexttoken.value);
3471
- } else if (nexttoken.value === '__proto__') {
3472
- warning("Stupid key '{a}'.",
3473
- nexttoken, nexttoken.value);
3954
+ } else if ((nexttoken.value === '__proto__' &&
3955
+ !option.proto) || (nexttoken.value === '__iterator__' &&
3956
+ !option.iterator)) {
3957
+ warning("The '{a}' key may produce unexpected results.",
3958
+ nexttoken, nexttoken.value);
3474
3959
  } else {
3475
3960
  o[nexttoken.value] = true;
3476
3961
  }
@@ -3543,6 +4028,7 @@ loop: for (;;) {
3543
4028
  var itself = function (s, o, g) {
3544
4029
  var a, i, k;
3545
4030
  JSHINT.errors = [];
4031
+ JSHINT.undefs = [];
3546
4032
  predefined = Object.create(standard);
3547
4033
  combine(predefined, g || {});
3548
4034
  if (o) {
@@ -3555,7 +4041,7 @@ loop: for (;;) {
3555
4041
  } else if (typeof a === 'object') {
3556
4042
  k = Object.keys(a);
3557
4043
  for (i = 0; i < k.length; i += 1) {
3558
- predefined[k[i]] = !!a[k];
4044
+ predefined[k[i]] = !!a[k[i]];
3559
4045
  }
3560
4046
  }
3561
4047
  }
@@ -3582,7 +4068,6 @@ loop: for (;;) {
3582
4068
  };
3583
4069
  functions = [funct];
3584
4070
  urls = [];
3585
- src = false;
3586
4071
  stack = null;
3587
4072
  member = {};
3588
4073
  membersOnly = null;
@@ -3593,11 +4078,14 @@ loop: for (;;) {
3593
4078
  warnings = 0;
3594
4079
  lex.init(s);
3595
4080
  prereg = true;
3596
- strict_mode = false;
4081
+ directive = {};
3597
4082
 
3598
4083
  prevtoken = token = nexttoken = syntax['(begin)'];
3599
4084
  assume();
3600
4085
 
4086
+ // combine the passed globals after we've assumed all our options
4087
+ combine(predefined, g || {});
4088
+
3601
4089
  try {
3602
4090
  advance();
3603
4091
  switch (nexttoken.id) {
@@ -3608,32 +4096,83 @@ loop: for (;;) {
3608
4096
  jsonValue();
3609
4097
  break;
3610
4098
  default:
3611
- if (nexttoken.value === 'use strict') {
3612
- if (!option.globalstrict)
3613
- warning("Use the function form of \"use strict\".");
3614
- use_strict();
4099
+ directives();
4100
+ if (directive["use strict"] && !option.globalstrict) {
4101
+ warning("Use the function form of \"use strict\".", prevtoken);
3615
4102
  }
3616
- statements('lib');
4103
+
4104
+ statements();
3617
4105
  }
3618
4106
  advance('(end)');
4107
+
4108
+ var markDefined = function (name, context) {
4109
+ do {
4110
+ if (typeof context[name] === 'string') {
4111
+ // JSHINT marks unused variables as 'unused' and
4112
+ // unused function declaration as 'unction'. This
4113
+ // code changes such instances back 'var' and
4114
+ // 'closure' so that the code in JSHINT.data()
4115
+ // doesn't think they're unused.
4116
+
4117
+ if (context[name] === 'unused')
4118
+ context[name] = 'var';
4119
+ else if (context[name] === 'unction')
4120
+ context[name] = 'closure';
4121
+
4122
+ return true;
4123
+ }
4124
+
4125
+ context = context['(context)'];
4126
+ } while (context);
4127
+
4128
+ return false;
4129
+ };
4130
+
4131
+ var clearImplied = function (name, line) {
4132
+ if (!implied[name])
4133
+ return;
4134
+
4135
+ var newImplied = [];
4136
+ for (var i = 0; i < implied[name].length; i += 1) {
4137
+ if (implied[name][i] !== line)
4138
+ newImplied.push(implied[name][i]);
4139
+ }
4140
+
4141
+ if (newImplied.length === 0)
4142
+ delete implied[name];
4143
+ else
4144
+ implied[name] = newImplied;
4145
+ };
4146
+
4147
+ // Check queued 'x is not defined' instances to see if they're still undefined.
4148
+ for (i = 0; i < JSHINT.undefs.length; i += 1) {
4149
+ k = JSHINT.undefs[i].slice(0);
4150
+
4151
+ if (markDefined(k[2].value, k[0])) {
4152
+ clearImplied(k[2].value, k[2].line);
4153
+ } else {
4154
+ warning.apply(warning, k.slice(1));
4155
+ }
4156
+ }
3619
4157
  } catch (e) {
3620
4158
  if (e) {
4159
+ var nt = nexttoken || {};
3621
4160
  JSHINT.errors.push({
4161
+ raw : e.raw,
3622
4162
  reason : e.message,
3623
- line : e.line || nexttoken.line,
3624
- character : e.character || nexttoken.from
4163
+ line : e.line || nt.line,
4164
+ character : e.character || nt.from
3625
4165
  }, null);
3626
4166
  }
3627
4167
  }
3628
- return JSHINT.errors.length === 0;
3629
- };
3630
4168
 
4169
+ return JSHINT.errors;
4170
+ };
3631
4171
 
3632
- // Data summary.
3633
-
4172
+ // Data summary.
3634
4173
  itself.data = function () {
3635
4174
 
3636
- var data = {functions: []}, fu, globals, implieds = [], f, i, j,
4175
+ var data = { functions: [], options: option }, fu, globals, implieds = [], f, i, j,
3637
4176
  members = [], n, unused = [], v;
3638
4177
  if (itself.errors.length) {
3639
4178
  data.errors = itself.errors;
@@ -3663,7 +4202,6 @@ loop: for (;;) {
3663
4202
  if (globals.length > 0) {
3664
4203
  data.globals = globals;
3665
4204
  }
3666
-
3667
4205
  for (i = 1; i < functions.length; i += 1) {
3668
4206
  f = functions[i];
3669
4207
  fu = {};
@@ -3841,14 +4379,12 @@ loop: for (;;) {
3841
4379
  }
3842
4380
  return o.join('');
3843
4381
  };
3844
- itself.jshint = itself;
3845
4382
 
3846
- itself.edition = '2011-04-16';
4383
+ itself.jshint = itself;
3847
4384
 
3848
4385
  return itself;
3849
-
3850
4386
  }());
3851
4387
 
3852
4388
  // Make JSHINT a Node module, if possible.
3853
- if (typeof exports == 'object' && exports)
3854
- exports.JSHINT = JSHINT;
4389
+ if (typeof exports === 'object' && exports)
4390
+ exports.JSHINT = JSHINT;