jslint_on_rails 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,8 @@
1
+ Version 1.0.5 (08.01.2011)
2
+
3
+ * options passed on the command line to JSLint are joined with "&" to fix the "predef" option
4
+ * load YAJL module explicitly (in some environments it may not be loaded automatically)
5
+
1
6
  Version 1.0.4 (05.12.2010)
2
7
 
3
8
  * bundler should be able to load the gem without :require
@@ -31,7 +31,7 @@ In Rails 2 and in other frameworks JSLint on Rails can't be loaded automatically
31
31
  bit more work. The procedure in this case is:
32
32
 
33
33
  * install the gem in your application using whatever technique is recommended for your framework (e.g. using bundler,
34
- or just plain old `gem install jslint_on_rails`)
34
+ or by installing the gem manually with `gem install jslint_on_rails` and loading it with `require 'jslint'`)
35
35
  * in your Rakefile, add a line to load the JSLint tasks:
36
36
 
37
37
  require 'jslint/tasks'
@@ -34,7 +34,7 @@ module JSLint
34
34
  def run
35
35
  check_java
36
36
  Utils.xputs "Running JSLint:\n\n"
37
- arguments = "#{JSLINT_FILE} #{option_string} #{@file_list.join(' ')}"
37
+ arguments = "#{JSLINT_FILE} #{option_string.inspect} #{@file_list.join(' ')}"
38
38
  success = call_java_with_status(RHINO_JAR_FILE, RHINO_JAR_CLASS, arguments)
39
39
  raise LintCheckFailure, "JSLint test failed." unless success
40
40
  end
@@ -51,7 +51,7 @@ module JSLint
51
51
  end
52
52
 
53
53
  def option_string
54
- @config.map { |k, v| "#{k}=#{v.inspect}" }.join(',')
54
+ @config.map { |k, v| "#{k}=#{v.inspect}" }.join('&')
55
55
  end
56
56
 
57
57
  def check_java
@@ -1,8 +1,9 @@
1
1
  require 'fileutils'
2
+ require 'yaml'
2
3
 
3
4
  module JSLint
4
5
 
5
- VERSION = "1.0.4"
6
+ VERSION = "1.0.5"
6
7
  DEFAULT_CONFIG_FILE = File.expand_path(File.dirname(__FILE__) + "/config/jslint.yml")
7
8
 
8
9
  class << self
@@ -1,5 +1,5 @@
1
1
  // jslint.js
2
- // 2010-11-27
2
+ // 2010-12-21
3
3
 
4
4
  /*
5
5
  Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
@@ -36,8 +36,11 @@ SOFTWARE.
36
36
  JavaScript text, or HTML text, or a JSON text, or a CSS text.
37
37
 
38
38
  The second parameter is an optional object of options which control the
39
- operation of JSLINT. Most of the options are booleans: They are all are
40
- optional and have a default value of false.
39
+ operation of JSLINT. Most of the options are booleans: They are all
40
+ optional and have a default value of false. One of the options, predef,
41
+ can be an array of names, which will be used to declare global variables,
42
+ or an object whose keys are used as global names, with a boolean value
43
+ that determines if they are assignable.
41
44
 
42
45
  If it checks out, JSLINT returns true. Otherwise, it returns false.
43
46
 
@@ -186,31 +189,31 @@ SOFTWARE.
186
189
  darksalmon, darkseagreen, darkslateblue, darkslategray, darkturquoise,
187
190
  darkviolet, data, datalist, dd, debug, decodeURI, decodeURIComponent,
188
191
  deeppink, deepskyblue, defaultStatus, defineClass, del, deserialize,
189
- details, devel, dfn, dialog, dimension, dimgray, dir, direction,
190
- display, div, dl, document, dodgerblue, dt, edition, else, em, embed,
191
- embossed, empty, "empty-cells", encodeURI, encodeURIComponent,
192
- entityify, eqeqeq, errors, es5, escape, eval, event, evidence, evil, ex,
193
- exception, exec, exps, fieldset, figure, filesystem, firebrick, first,
194
- float, floor, floralwhite, focus, focusWidget, font, "font-family",
195
- "font-size", "font-size-adjust", "font-stretch", "font-style",
196
- "font-variant", "font-weight", footer, forestgreen, forin, form,
197
- fragment, frame, frames, frameset, from, fromCharCode, fuchsia, fud,
198
- funct, function, functions, g, gainsboro, gc, getComputedStyle,
199
- ghostwhite, global, globals, gold, goldenrod, gray, graytext, green,
200
- greenyellow, h1, h2, h3, h4, h5, h6, handheld, hasOwnProperty, head,
201
- header, height, help, hgroup, highlight, highlighttext, history,
202
- honeydew, hotpink, hr, "hta:application", html, i, iTunes, id,
203
- identifier, iframe, img, immed, implieds, in, inactiveborder,
204
- inactivecaption, inactivecaptiontext, include, indent, indexOf,
205
- indianred, indigo, infobackground, infotext, init, input, ins, isAlpha,
206
- isApplicationRunning, isDigit, isFinite, isNaN, ivory, join, jslint,
207
- json, kbd, keygen, khaki, konfabulatorVersion, label, labelled, lang,
208
- last, lavender, lavenderblush, lawngreen, laxbreak, lbp, led, left,
209
- legend, lemonchiffon, length, "letter-spacing", li, lib, lightblue,
210
- lightcoral, lightcyan, lightgoldenrodyellow, lightgreen, lightpink,
211
- lightsalmon, lightseagreen, lightskyblue, lightslategray,
212
- lightsteelblue, lightyellow, lime, limegreen, line, "line-height",
213
- linen, link, "list-style", "list-style-image", "list-style-position",
192
+ details, devel, dfn, dialog, dimgray, dir, direction, display, div, dl,
193
+ document, dodgerblue, dt, edition, else, em, embed, embossed, empty,
194
+ "empty-cells", encodeURI, encodeURIComponent, entityify, eqeqeq, errors,
195
+ es5, escape, eval, event, evidence, evil, ex, exception, exec, exps,
196
+ fieldset, figure, filesystem, firebrick, first, float, floor,
197
+ floralwhite, focus, focusWidget, font, "font-family", "font-size",
198
+ "font-size-adjust", "font-stretch", "font-style", "font-variant",
199
+ "font-weight", footer, forestgreen, forin, form, fragment, frame,
200
+ frames, frameset, from, fromCharCode, fuchsia, fud, funct, function,
201
+ functions, g, gainsboro, gc, getComputedStyle, ghostwhite, global,
202
+ globals, gold, goldenrod, gray, graytext, green, greenyellow, h1, h2,
203
+ h3, h4, h5, h6, handheld, hasOwnProperty, head, header, height, help,
204
+ hgroup, highlight, highlighttext, history, honeydew, hotpink, hr,
205
+ "hta:application", html, i, iTunes, id, identifier, iframe, img, immed,
206
+ implieds, in, inactiveborder, inactivecaption, inactivecaptiontext,
207
+ include, indent, indexOf, indianred, indigo, infobackground, infotext,
208
+ init, input, ins, isAlpha, isApplicationRunning, isArray, isDigit,
209
+ isFinite, isNaN, ivory, join, jslint, json, kbd, keygen, keys, khaki,
210
+ konfabulatorVersion, label, labelled, lang, last, lavender,
211
+ lavenderblush, lawngreen, laxbreak, lbp, led, left, legend,
212
+ lemonchiffon, length, "letter-spacing", li, lib, lightblue, lightcoral,
213
+ lightcyan, lightgoldenrodyellow, lightgreen, lightpink, lightsalmon,
214
+ lightseagreen, lightskyblue, lightslategray, lightsteelblue,
215
+ lightyellow, lime, limegreen, line, "line-height", linen, link,
216
+ "list-style", "list-style-image", "list-style-position",
214
217
  "list-style-type", load, loadClass, location, log, m, magenta, map,
215
218
  margin, "margin-bottom", "margin-left", "margin-right", "margin-top",
216
219
  mark, "marker-offset", maroon, match, "max-height", "max-width", maxerr,
@@ -256,12 +259,12 @@ SOFTWARE.
256
259
  */
257
260
 
258
261
  // We build the application inside a function so that we produce only a single
259
- // global variable. The function will be invoked, its return value is the JSLINT
260
- // application itself.
261
-
262
- "use strict";
262
+ // global variable. That function will be invoked immediately, and its return
263
+ // value is the JSLINT function itself.
263
264
 
264
265
  var JSLINT = (function () {
266
+ "use strict";
267
+
265
268
  var adsafe_id, // The widget's ADsafe id.
266
269
  adsafe_may, // The widget may load approved scripts.
267
270
  adsafe_went, // ADSAFE.go has been called.
@@ -286,7 +289,7 @@ var JSLINT = (function () {
286
289
  '%': true
287
290
  },
288
291
 
289
- // These are members that should not be permitted in the safe subset.
292
+ // These are property names that should not be permitted in the safe subset.
290
293
 
291
294
  banned = { // the member names that ADsafe prohibits.
292
295
  'arguments' : true,
@@ -929,7 +932,7 @@ var JSLINT = (function () {
929
932
  xmode,
930
933
  xquote,
931
934
 
932
- // Regular expressions. Some of these are ridiculously long.
935
+ // Regular expressions. Some of these are stupidly long.
933
936
 
934
937
  // unsafe comment or string
935
938
  ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i,
@@ -967,7 +970,24 @@ var JSLINT = (function () {
967
970
  styleproperty: ssx
968
971
  };
969
972
 
970
- function F() {}
973
+
974
+ function F() {} // Used by Object.create
975
+
976
+ function is_own(object, name) {
977
+
978
+ // The object.hasOwnProperty method fails when the property under consideration
979
+ // is named 'hasOwnProperty'. So we have to use this more convoluted form.
980
+
981
+ return Object.prototype.hasOwnProperty.call(object, name);
982
+ }
983
+
984
+ // Provide critical ES5 functions to ES3.
985
+
986
+ if (typeof Array.isArray !== 'function') {
987
+ Array.isArray = function (o) {
988
+ return Object.prototype.toString.apply(o) === '[object Array]';
989
+ };
990
+ }
971
991
 
972
992
  if (typeof Object.create !== 'function') {
973
993
  Object.create = function (o) {
@@ -976,47 +996,53 @@ var JSLINT = (function () {
976
996
  };
977
997
  }
978
998
 
979
-
980
- function is_own(object, name) {
981
- return Object.prototype.hasOwnProperty.call(object, name);
982
- }
983
-
984
-
985
- function combine(t, o) {
986
- var n;
987
- for (n in o) {
988
- if (is_own(o, n)) {
989
- t[n] = o[n];
999
+ if (typeof Object.keys !== 'function') {
1000
+ Object.keys = function (o) {
1001
+ var a = [], k;
1002
+ for (k in o) {
1003
+ if (is_own(o, k)) {
1004
+ a.push(k);
1005
+ }
990
1006
  }
991
- }
1007
+ return a;
1008
+ };
992
1009
  }
993
1010
 
994
- String.prototype.entityify = function () {
995
- return this
996
- .replace(/&/g, '&amp;')
997
- .replace(/</g, '&lt;')
998
- .replace(/>/g, '&gt;');
999
- };
1000
-
1001
- String.prototype.isAlpha = function () {
1002
- return (this >= 'a' && this <= 'z\uffff') ||
1003
- (this >= 'A' && this <= 'Z\uffff');
1004
- };
1011
+ // Non standard methods
1005
1012
 
1013
+ if (typeof String.prototype.entityify !== 'function') {
1014
+ String.prototype.entityify = function () {
1015
+ return this
1016
+ .replace(/&/g, '&amp;')
1017
+ .replace(/</g, '&lt;')
1018
+ .replace(/>/g, '&gt;');
1019
+ };
1020
+ }
1006
1021
 
1007
- String.prototype.isDigit = function () {
1008
- return (this >= '0' && this <= '9');
1009
- };
1022
+ if (typeof String.prototype.isAlpha !== 'function') {
1023
+ String.prototype.isAlpha = function () {
1024
+ return (this >= 'a' && this <= 'z\uffff') ||
1025
+ (this >= 'A' && this <= 'Z\uffff');
1026
+ };
1027
+ }
1010
1028
 
1029
+ if (typeof String.prototype.isDigit !== 'function') {
1030
+ String.prototype.isDigit = function () {
1031
+ return (this >= '0' && this <= '9');
1032
+ };
1033
+ }
1011
1034
 
1012
- String.prototype.supplant = function (o) {
1013
- return this.replace(/\{([^{}]*)\}/g, function (a, b) {
1014
- var r = o[b];
1015
- return typeof r === 'string' || typeof r === 'number' ? r : a;
1016
- });
1017
- };
1035
+ if (typeof String.prototype.supplant !== 'function') {
1036
+ String.prototype.supplant = function (o) {
1037
+ return this.replace(/\{([^{}]*)\}/g, function (a, b) {
1038
+ var r = o[b];
1039
+ return typeof r === 'string' || typeof r === 'number' ? r : a;
1040
+ });
1041
+ };
1042
+ }
1018
1043
 
1019
- String.prototype.name = function () {
1044
+ if (typeof String.prototype.name !== 'function') {
1045
+ String.prototype.name = function () {
1020
1046
 
1021
1047
  // If the string looks like an identifier, then we can return it as is.
1022
1048
  // If the string contains no control characters, no quote characters, and no
@@ -1024,22 +1050,32 @@ var JSLINT = (function () {
1024
1050
  // Otherwise we must also replace the offending characters with safe
1025
1051
  // sequences.
1026
1052
 
1027
- if (ix.test(this)) {
1028
- return this;
1029
- }
1030
- if (nx.test(this)) {
1031
- return '"' + this.replace(nxg, function (a) {
1032
- var c = escapes[a];
1033
- if (c) {
1034
- return c;
1035
- }
1036
- return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
1037
- }) + '"';
1038
- }
1039
- return '"' + this + '"';
1040
- };
1053
+ if (ix.test(this)) {
1054
+ return this;
1055
+ }
1056
+ if (nx.test(this)) {
1057
+ return '"' + this.replace(nxg, function (a) {
1058
+ var c = escapes[a];
1059
+ if (c) {
1060
+ return c;
1061
+ }
1062
+ return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
1063
+ }) + '"';
1064
+ }
1065
+ return '"' + this + '"';
1066
+ };
1067
+ }
1041
1068
 
1042
1069
 
1070
+ function combine(t, o) {
1071
+ var n;
1072
+ for (n in o) {
1073
+ if (is_own(o, n)) {
1074
+ t[n] = o[n];
1075
+ }
1076
+ }
1077
+ }
1078
+
1043
1079
  function assume() {
1044
1080
  if (!option.safe) {
1045
1081
  if (option.rhino) {
@@ -1125,7 +1161,7 @@ var JSLINT = (function () {
1125
1161
 
1126
1162
 
1127
1163
 
1128
- // lexical analysis
1164
+ // lexical analysis and token construction
1129
1165
 
1130
1166
  var lex = (function lex() {
1131
1167
  var character, from, line, s;
@@ -1338,10 +1374,14 @@ var JSLINT = (function () {
1338
1374
  character + j);
1339
1375
  break;
1340
1376
  case '\\':
1341
- case '\'':
1342
1377
  case '"':
1343
1378
  case '/':
1344
1379
  break;
1380
+ case '\'':
1381
+ if (jsonmode) {
1382
+ warningAt("Avoid \\'.", line, character);
1383
+ }
1384
+ break;
1345
1385
  case 'b':
1346
1386
  c = '\b';
1347
1387
  break;
@@ -1361,6 +1401,9 @@ var JSLINT = (function () {
1361
1401
  esc(4);
1362
1402
  break;
1363
1403
  case 'v':
1404
+ if (jsonmode) {
1405
+ warningAt("Avoid \\v.", line, character);
1406
+ }
1364
1407
  c = '\v';
1365
1408
  break;
1366
1409
  case 'x':
@@ -1398,21 +1441,6 @@ var JSLINT = (function () {
1398
1441
  }
1399
1442
  }
1400
1443
  }
1401
- // t = match(rx[xmode] || tx);
1402
- // if (!t) {
1403
- // if (xmode === 'html') {
1404
- // return it('(error)', s.charAt(0));
1405
- // } else {
1406
- // t = '';
1407
- // c = '';
1408
- // while (s && s < '!') {
1409
- // s = s.substr(1);
1410
- // }
1411
- // if (s) {
1412
- // errorAt("Unexpected '{a}'.",
1413
- // line, character, s.substr(0, 1));
1414
- // }
1415
- // }
1416
1444
  t = match(rx[xmode] || tx);
1417
1445
  if (!t) {
1418
1446
  t = '';
@@ -1463,8 +1491,7 @@ var JSLINT = (function () {
1463
1491
  }
1464
1492
  if (t.substr(t.length - 1) === '.') {
1465
1493
  warningAt(
1466
- "A trailing decimal point can be confused with a dot '{a}'.",
1467
- line, character, t);
1494
+ "A trailing decimal point can be confused with a dot '{a}'.", line, character, t);
1468
1495
  }
1469
1496
  return it('(number)', t);
1470
1497
  }
@@ -1937,6 +1964,7 @@ klass: do {
1937
1964
  obj = predefined;
1938
1965
  break;
1939
1966
  default:
1967
+ error("What?");
1940
1968
  }
1941
1969
  t = lex.token();
1942
1970
  loop: for (;;) {
@@ -2087,10 +2115,10 @@ loop: for (;;) {
2087
2115
 
2088
2116
 
2089
2117
  // This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
2090
- // is looking for ad hoc lint patterns. We add to Pratt's model .fud, which is
2091
- // like nud except that it is only used on the first token of a statement.
2092
- // Having .fud makes it much easier to define JavaScript. I retained Pratt's
2093
- // nomenclature.
2118
+ // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
2119
+ // like .nud except that it is only used on the first token of a statement.
2120
+ // Having .fud makes it much easier to define statement-oriented languages like
2121
+ // JavaScript. I retained Pratt's nomenclature.
2094
2122
 
2095
2123
  // .nud Null denotation
2096
2124
  // .fud First null denotation
@@ -2098,9 +2126,9 @@ loop: for (;;) {
2098
2126
  // lbp Left binding power
2099
2127
  // rbp Right binding power
2100
2128
 
2101
- // They are key to the parsing method called Top Down Operator Precedence.
2129
+ // They are elements of the parsing method called Top Down Operator Precedence.
2102
2130
 
2103
- function parse(rbp, initial) {
2131
+ function expression(rbp, initial) {
2104
2132
  var left;
2105
2133
  if (nexttoken.id === '(end)') {
2106
2134
  error("Unexpected early end of program.", token);
@@ -2175,7 +2203,6 @@ loop: for (;;) {
2175
2203
  }
2176
2204
  }
2177
2205
 
2178
-
2179
2206
  function nonadjacent(left, right) {
2180
2207
  if (option.white) {
2181
2208
  left = left || token;
@@ -2202,6 +2229,16 @@ loop: for (;;) {
2202
2229
  }
2203
2230
  }
2204
2231
 
2232
+ function step_in() {
2233
+ var old_indent = indent;
2234
+ if (prevtoken.line !== token.line) {
2235
+ indent = token.from;
2236
+ }
2237
+ return function step_out() {
2238
+ return (indent = old_indent);
2239
+ };
2240
+ }
2241
+
2205
2242
  function indentation(bias) {
2206
2243
  var i;
2207
2244
  if (option.white && nexttoken.id !== '(end)') {
@@ -2284,7 +2321,7 @@ loop: for (;;) {
2284
2321
  var x = symbol(s, 150);
2285
2322
  reserveName(x);
2286
2323
  x.nud = (typeof f === 'function') ? f : function () {
2287
- this.right = parse(150);
2324
+ this.right = expression(150);
2288
2325
  this.arity = 'unary';
2289
2326
  if (this.id === '++' || this.id === '--') {
2290
2327
  if (option.plusplus) {
@@ -2337,7 +2374,7 @@ loop: for (;;) {
2337
2374
  return f(left, this);
2338
2375
  } else {
2339
2376
  this.left = left;
2340
- this.right = parse(p);
2377
+ this.right = expression(p);
2341
2378
  return this;
2342
2379
  }
2343
2380
  };
@@ -2350,7 +2387,7 @@ loop: for (;;) {
2350
2387
  x.led = function (left) {
2351
2388
  nobreaknonadjacent(prevtoken, token);
2352
2389
  nonadjacent(token, nexttoken);
2353
- var right = parse(100);
2390
+ var right = expression(100);
2354
2391
  if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) {
2355
2392
  warning("Use the isNaN function to compare with NaN.", this);
2356
2393
  } else if (f) {
@@ -2406,13 +2443,13 @@ loop: for (;;) {
2406
2443
  if (!left.left || left.left.value === 'arguments') {
2407
2444
  warning('Bad assignment.', that);
2408
2445
  }
2409
- that.right = parse(19);
2446
+ that.right = expression(19);
2410
2447
  return that;
2411
2448
  } else if (left.identifier && !left.reserved) {
2412
2449
  if (funct[left.value] === 'exception') {
2413
2450
  warning("Do not assign to the exception parameter.", left);
2414
2451
  }
2415
- that.right = parse(19);
2452
+ that.right = expression(19);
2416
2453
  return that;
2417
2454
  }
2418
2455
  if (left === syntax['function']) {
@@ -2434,7 +2471,7 @@ loop: for (;;) {
2434
2471
  warning("Unexpected use of '{a}'.", this, this.id);
2435
2472
  }
2436
2473
  this.left = left;
2437
- this.right = parse(p);
2474
+ this.right = expression(p);
2438
2475
  return this;
2439
2476
  };
2440
2477
  return x;
@@ -2452,7 +2489,7 @@ loop: for (;;) {
2452
2489
  if (left) {
2453
2490
  if (left.id === '.' || left.id === '[' ||
2454
2491
  (left.identifier && !left.reserved)) {
2455
- parse(19);
2492
+ expression(19);
2456
2493
  return that;
2457
2494
  }
2458
2495
  if (left === syntax['function']) {
@@ -2570,7 +2607,7 @@ loop: for (;;) {
2570
2607
  if (!noindent) {
2571
2608
  indentation();
2572
2609
  }
2573
- r = parse(0, true);
2610
+ r = expression(0, true);
2574
2611
 
2575
2612
  // Look for the final semicolon.
2576
2613
 
@@ -2604,6 +2641,9 @@ loop: for (;;) {
2604
2641
 
2605
2642
  function use_strict() {
2606
2643
  if (nexttoken.value === 'use strict') {
2644
+ if (strict_mode) {
2645
+ warning("Unnecessary \"use strict\".");
2646
+ }
2607
2647
  advance();
2608
2648
  advance(';');
2609
2649
  strict_mode = true;
@@ -2618,12 +2658,12 @@ loop: for (;;) {
2618
2658
 
2619
2659
  function statements(begin) {
2620
2660
  var a = [], f, p;
2621
- if (begin && !use_strict() && option.strict) {
2622
- warning('Missing "use strict" statement.', nexttoken);
2623
- }
2624
2661
  if (option.adsafe) {
2625
2662
  switch (begin) {
2626
2663
  case 'script':
2664
+
2665
+ // JSLint is also the static analizer for ADsafe. See www.ADsafe.org.
2666
+
2627
2667
  if (!adsafe_may) {
2628
2668
  if (nexttoken.value !== 'ADSAFE' ||
2629
2669
  peek(0).id !== '.' ||
@@ -2660,7 +2700,7 @@ loop: for (;;) {
2660
2700
  advance('(');
2661
2701
  advance('(string)');
2662
2702
  comma();
2663
- f = parse(0);
2703
+ f = expression(0);
2664
2704
  if (f.id !== 'function') {
2665
2705
  error('The second argument to lib must be a function.', f);
2666
2706
  }
@@ -2691,7 +2731,7 @@ loop: for (;;) {
2691
2731
 
2692
2732
 
2693
2733
  function block(f) {
2694
- var a, b = inblock, old_indent = indent, s = scope, t;
2734
+ var a, b = inblock, old_indent = indent, m = strict_mode, s = scope, t;
2695
2735
  inblock = f;
2696
2736
  scope = Object.create(scope);
2697
2737
  nonadjacent(token, nexttoken);
@@ -2703,10 +2743,12 @@ loop: for (;;) {
2703
2743
  while (!f && nexttoken.from > indent) {
2704
2744
  indent += option.indent;
2705
2745
  }
2706
- if (!f) {
2707
- use_strict();
2746
+ if (!f && !use_strict() && !m && option.strict &&
2747
+ funct['(context)']['(global)']) {
2748
+ warning("Missing \"use strict\" statement.");
2708
2749
  }
2709
2750
  a = statements();
2751
+ strict_mode = m;
2710
2752
  indent -= option.indent;
2711
2753
  indentation();
2712
2754
  }
@@ -2757,7 +2799,6 @@ loop: for (;;) {
2757
2799
 
2758
2800
  // CSS parsing.
2759
2801
 
2760
-
2761
2802
  function cssName() {
2762
2803
  if (nexttoken.identifier) {
2763
2804
  advance();
@@ -3779,6 +3820,7 @@ loop: for (;;) {
3779
3820
  if (adsafe_went) {
3780
3821
  error("ADsafe script violation.", token);
3781
3822
  }
3823
+ use_strict();
3782
3824
  statements('script');
3783
3825
  }
3784
3826
  xmode = 'html';
@@ -3924,6 +3966,7 @@ loop: for (;;) {
3924
3966
  wmode = option.white;
3925
3967
  option.white = false;
3926
3968
  advance(q);
3969
+ use_strict();
3927
3970
  statements('on');
3928
3971
  option.white = wmode;
3929
3972
  if (nexttoken.id !== q) {
@@ -4245,9 +4288,9 @@ loop: for (;;) {
4245
4288
  bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20);
4246
4289
  infix('?', function (left, that) {
4247
4290
  that.left = left;
4248
- that.right = parse(10);
4291
+ that.right = expression(10);
4249
4292
  advance(':');
4250
- that['else'] = parse(10);
4293
+ that['else'] = expression(10);
4251
4294
  if (option.statinexp) {
4252
4295
  that.exps = that.right.exps && that['else'].exps;
4253
4296
  }
@@ -4256,7 +4299,7 @@ loop: for (;;) {
4256
4299
 
4257
4300
  infix('||', function(left, that) {
4258
4301
  that.left = left;
4259
- that.right = parse(40);
4302
+ that.right = expression(40);
4260
4303
  if (option.statinexp) {
4261
4304
  that.exps = that.right.exps;
4262
4305
  }
@@ -4265,7 +4308,7 @@ loop: for (;;) {
4265
4308
 
4266
4309
  infix('&&', function(left, that) {
4267
4310
  that.left = left;
4268
- that.right = parse(50);
4311
+ that.right = expression(50);
4269
4312
  if (option.statinexp) {
4270
4313
  that.exps = that.right.exps;
4271
4314
  }
@@ -4313,7 +4356,7 @@ loop: for (;;) {
4313
4356
  infix('in', 'in', 120);
4314
4357
  infix('instanceof', 'instanceof', 120);
4315
4358
  infix('+', function (left, that) {
4316
- var right = parse(130);
4359
+ var right = expression(130);
4317
4360
  if (left && right && left.id === '(string)' && right.id === '(string)') {
4318
4361
  left.value += right.value;
4319
4362
  left.character = right.character;
@@ -4329,28 +4372,28 @@ loop: for (;;) {
4329
4372
  prefix('+', 'num');
4330
4373
  prefix('+++', function () {
4331
4374
  warning("Confusing pluses.");
4332
- this.right = parse(150);
4375
+ this.right = expression(150);
4333
4376
  this.arity = 'unary';
4334
4377
  return this;
4335
4378
  });
4336
4379
  infix('+++', function (left) {
4337
4380
  warning("Confusing pluses.");
4338
4381
  this.left = left;
4339
- this.right = parse(130);
4382
+ this.right = expression(130);
4340
4383
  return this;
4341
4384
  }, 130);
4342
4385
  infix('-', 'sub', 130);
4343
4386
  prefix('-', 'neg');
4344
4387
  prefix('---', function () {
4345
4388
  warning("Confusing minuses.");
4346
- this.right = parse(150);
4389
+ this.right = expression(150);
4347
4390
  this.arity = 'unary';
4348
4391
  return this;
4349
4392
  });
4350
4393
  infix('---', function (left) {
4351
4394
  warning("Confusing minuses.");
4352
4395
  this.left = left;
4353
- this.right = parse(130);
4396
+ this.right = expression(130);
4354
4397
  return this;
4355
4398
  }, 130);
4356
4399
  infix('*', 'mult', 140);
@@ -4365,7 +4408,7 @@ loop: for (;;) {
4365
4408
  prefix('--', 'predec');
4366
4409
  syntax['--'].exps = true;
4367
4410
  prefix('delete', function () {
4368
- var p = parse(0);
4411
+ var p = expression(0);
4369
4412
  if (!p || (p.id !== '.' && p.id !== '[')) {
4370
4413
  warning("Variables should not be deleted.");
4371
4414
  }
@@ -4378,11 +4421,11 @@ loop: for (;;) {
4378
4421
  if (option.bitwise) {
4379
4422
  warning("Unexpected '{a}'.", this, '~');
4380
4423
  }
4381
- parse(150);
4424
+ expression(150);
4382
4425
  return this;
4383
4426
  });
4384
4427
  prefix('!', function () {
4385
- this.right = parse(150);
4428
+ this.right = expression(150);
4386
4429
  this.arity = 'unary';
4387
4430
  if (bang[this.right.id] === true) {
4388
4431
  warning("Confusing use of '{a}'.", this, '!');
@@ -4391,7 +4434,7 @@ loop: for (;;) {
4391
4434
  });
4392
4435
  prefix('typeof', 'typeof');
4393
4436
  prefix('new', function () {
4394
- var c = parse(155), i;
4437
+ var c = expression(155), i;
4395
4438
  if (c && c.id !== 'function') {
4396
4439
  if (c.identifier) {
4397
4440
  c['new'] = true;
@@ -4406,21 +4449,6 @@ loop: for (;;) {
4406
4449
  advance('(');
4407
4450
  if (nexttoken.id === ')') {
4408
4451
  warning("Use the array literal notation [].", token);
4409
- } else {
4410
- i = parse(0);
4411
- c.dimension = i;
4412
- if ((i.id === '(number)' && /[.+\-Ee]/.test(i.value)) ||
4413
- (i.id === '-' && !i.right) ||
4414
- i.id === '(string)' || i.id === '[' ||
4415
- i.id === '{' || i.id === 'true' ||
4416
- i.id === 'false' ||
4417
- i.id === 'null' || i.id === 'undefined' ||
4418
- i.id === 'Infinity') {
4419
- warning("Use the array literal notation [].", token);
4420
- }
4421
- if (nexttoken.id !== ')') {
4422
- error("Use the array literal notation [].", token);
4423
- }
4424
4452
  }
4425
4453
  advance(')');
4426
4454
  }
@@ -4570,7 +4598,7 @@ loop: for (;;) {
4570
4598
  }
4571
4599
  if (nexttoken.id !== ')') {
4572
4600
  for (;;) {
4573
- p[p.length] = parse(10);
4601
+ p[p.length] = expression(10);
4574
4602
  n += 1;
4575
4603
  if (nexttoken.id !== ',') {
4576
4604
  break;
@@ -4610,7 +4638,7 @@ loop: for (;;) {
4610
4638
  if (nexttoken.id === 'function') {
4611
4639
  nexttoken.immed = true;
4612
4640
  }
4613
- var v = parse(0);
4641
+ var v = expression(0);
4614
4642
  advance(')', this);
4615
4643
  nospace(prevtoken, token);
4616
4644
  if (option.immed && v.id === 'function') {
@@ -4629,7 +4657,7 @@ loop: for (;;) {
4629
4657
  infix('[', function (left, that) {
4630
4658
  nobreak(prevtoken, token);
4631
4659
  nospace();
4632
- var e = parse(0), s;
4660
+ var e = expression(0), s;
4633
4661
  if (e && e.type === '(string)') {
4634
4662
  if (option.safe && banned[e.value] === true) {
4635
4663
  warning("ADsafe restricted word '{a}'.", that, e.value);
@@ -4661,7 +4689,7 @@ loop: for (;;) {
4661
4689
  }, 160, true);
4662
4690
 
4663
4691
  prefix('[', function () {
4664
- var b = token.line !== nexttoken.line;
4692
+ var step_out = step_in(), b = token.line !== nexttoken.line;
4665
4693
  this.first = [];
4666
4694
  if (b) {
4667
4695
  indent += option.indent;
@@ -4680,7 +4708,7 @@ loop: for (;;) {
4680
4708
  if (b && token.line !== nexttoken.line) {
4681
4709
  indentation();
4682
4710
  }
4683
- this.first.push(parse(10));
4711
+ this.first.push(expression(10));
4684
4712
  if (nexttoken.id === ',') {
4685
4713
  comma();
4686
4714
  if (nexttoken.id === ']' && !option.es5) {
@@ -4696,6 +4724,7 @@ loop: for (;;) {
4696
4724
  indentation();
4697
4725
  }
4698
4726
  advance(']', this);
4727
+ step_out();
4699
4728
  return this;
4700
4729
  }, 160);
4701
4730
 
@@ -4775,7 +4804,7 @@ loop: for (;;) {
4775
4804
 
4776
4805
  (function (x) {
4777
4806
  x.nud = function () {
4778
- var b, f, i, j, p, seen = {}, t;
4807
+ var step_out = step_in(), b, f, i, j, p, seen = {}, t;
4779
4808
  b = token.line !== nexttoken.line;
4780
4809
  if (b) {
4781
4810
  indent += option.indent;
@@ -4831,7 +4860,7 @@ loop: for (;;) {
4831
4860
  }
4832
4861
  advance(':');
4833
4862
  nonadjacent(token, nexttoken);
4834
- parse(10);
4863
+ expression(10);
4835
4864
  }
4836
4865
  if (seen[i] === true) {
4837
4866
  warning("Duplicate member '{a}'.", nexttoken, i);
@@ -4854,6 +4883,7 @@ loop: for (;;) {
4854
4883
  indentation();
4855
4884
  }
4856
4885
  advance('}', this);
4886
+ step_out();
4857
4887
  return this;
4858
4888
  };
4859
4889
  x.fud = function () {
@@ -4867,14 +4897,14 @@ loop: for (;;) {
4867
4897
  // JavaScript does not have block scope. It only has function scope. So,
4868
4898
  // declaring a variable in a block can have unexpected consequences.
4869
4899
 
4870
- var id, name, value;
4900
+ var id, name, value, v = token;
4871
4901
 
4872
4902
  if (funct['(onevar)'] && option.onevar) {
4873
4903
  warning("Too many var statements.");
4874
4904
  } else if (!funct['(global)']) {
4875
4905
  funct['(onevar)'] = true;
4876
4906
  }
4877
- this.first = [];
4907
+ v.first = [];
4878
4908
  for (;;) {
4879
4909
  nonadjacent(token, nexttoken);
4880
4910
  id = identifier();
@@ -4886,7 +4916,7 @@ loop: for (;;) {
4886
4916
  break;
4887
4917
  }
4888
4918
  name = token;
4889
- this.first.push(token);
4919
+ v.first.push(token);
4890
4920
  if (nexttoken.id === '=') {
4891
4921
  nonadjacent(token, nexttoken);
4892
4922
  advance('=');
@@ -4898,7 +4928,7 @@ loop: for (;;) {
4898
4928
  error("Variable {a} was not declared correctly.",
4899
4929
  nexttoken, nexttoken.value);
4900
4930
  }
4901
- value = parse(0);
4931
+ value = expression(0);
4902
4932
  name.first = value;
4903
4933
  }
4904
4934
  if (nexttoken.id !== ',') {
@@ -4906,7 +4936,7 @@ loop: for (;;) {
4906
4936
  }
4907
4937
  comma();
4908
4938
  }
4909
- return this;
4939
+ return v;
4910
4940
  };
4911
4941
 
4912
4942
 
@@ -4916,7 +4946,7 @@ loop: for (;;) {
4916
4946
  blockstmt('function', function () {
4917
4947
  if (inblock) {
4918
4948
  warning(
4919
- "Function statements cannot be placed in blocks. Use a function expression or move the statement to the top of the outer function.", token);
4949
+ "Function statements should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.", token);
4920
4950
 
4921
4951
  }
4922
4952
  var i = identifier();
@@ -4931,7 +4961,7 @@ loop: for (;;) {
4931
4961
  });
4932
4962
 
4933
4963
  prefix('function', function () {
4934
- var i = optionalidentifier();
4964
+ var step_out = step_in(), i = optionalidentifier();
4935
4965
  if (i) {
4936
4966
  adjacent(token, nexttoken);
4937
4967
  } else {
@@ -4941,6 +4971,7 @@ loop: for (;;) {
4941
4971
  if (funct['(loopage)']) {
4942
4972
  warning("Don't make functions within a loop.");
4943
4973
  }
4974
+ step_out();
4944
4975
  return this;
4945
4976
  });
4946
4977
 
@@ -4949,11 +4980,11 @@ loop: for (;;) {
4949
4980
  advance('(');
4950
4981
  nonadjacent(this, t);
4951
4982
  nospace();
4952
- parse(20);
4983
+ expression(20);
4953
4984
  if (nexttoken.id === '=') {
4954
4985
  warning("Expected a conditional expression and instead saw an assignment.");
4955
4986
  advance('=');
4956
- parse(20);
4987
+ expression(20);
4957
4988
  }
4958
4989
  advance(')', t);
4959
4990
  nospace(prevtoken, token);
@@ -5013,11 +5044,11 @@ loop: for (;;) {
5013
5044
  advance('(');
5014
5045
  nonadjacent(this, t);
5015
5046
  nospace();
5016
- parse(20);
5047
+ expression(20);
5017
5048
  if (nexttoken.id === '=') {
5018
5049
  warning("Expected a conditional expression and instead saw an assignment.");
5019
5050
  advance('=');
5020
- parse(20);
5051
+ expression(20);
5021
5052
  }
5022
5053
  advance(')', t);
5023
5054
  nospace(prevtoken, token);
@@ -5036,7 +5067,7 @@ loop: for (;;) {
5036
5067
  advance('(');
5037
5068
  nonadjacent(this, t);
5038
5069
  nospace();
5039
- this.condition = parse(20);
5070
+ this.condition = expression(20);
5040
5071
  advance(')', t);
5041
5072
  nospace(prevtoken, token);
5042
5073
  nonadjacent(token, nexttoken);
@@ -5063,7 +5094,7 @@ loop: for (;;) {
5063
5094
  }
5064
5095
  indentation(-option.indent);
5065
5096
  advance('case');
5066
- this.cases.push(parse(20));
5097
+ this.cases.push(expression(20));
5067
5098
  g = true;
5068
5099
  advance(':');
5069
5100
  funct['(verb)'] = 'case';
@@ -5136,11 +5167,11 @@ loop: for (;;) {
5136
5167
  nonadjacent(token, t);
5137
5168
  advance('(');
5138
5169
  nospace();
5139
- parse(20);
5170
+ expression(20);
5140
5171
  if (nexttoken.id === '=') {
5141
5172
  warning("Expected a conditional expression and instead saw an assignment.");
5142
5173
  advance('=');
5143
- parse(20);
5174
+ expression(20);
5144
5175
  }
5145
5176
  advance(')', t);
5146
5177
  nospace(prevtoken, token);
@@ -5177,7 +5208,7 @@ loop: for (;;) {
5177
5208
  advance();
5178
5209
  }
5179
5210
  advance('in');
5180
- parse(20);
5211
+ expression(20);
5181
5212
  advance(')', t);
5182
5213
  s = block(true);
5183
5214
  if (!f && (s.length > 1 || typeof s[0] !== 'object' ||
@@ -5194,7 +5225,7 @@ loop: for (;;) {
5194
5225
  varstatement();
5195
5226
  } else {
5196
5227
  for (;;) {
5197
- parse(0, 'for');
5228
+ expression(0, 'for');
5198
5229
  if (nexttoken.id !== ',') {
5199
5230
  break;
5200
5231
  }
@@ -5205,11 +5236,11 @@ loop: for (;;) {
5205
5236
  nolinebreak(token);
5206
5237
  advance(';');
5207
5238
  if (nexttoken.id !== ';') {
5208
- parse(20);
5239
+ expression(20);
5209
5240
  if (nexttoken.id === '=') {
5210
5241
  warning("Expected a conditional expression and instead saw an assignment.");
5211
5242
  advance('=');
5212
- parse(20);
5243
+ expression(20);
5213
5244
  }
5214
5245
  }
5215
5246
  nolinebreak(token);
@@ -5220,7 +5251,7 @@ loop: for (;;) {
5220
5251
  }
5221
5252
  if (nexttoken.id !== ')') {
5222
5253
  for (;;) {
5223
- parse(0, 'for');
5254
+ expression(0, 'for');
5224
5255
  if (nexttoken.id !== ',') {
5225
5256
  break;
5226
5257
  }
@@ -5290,7 +5321,7 @@ loop: for (;;) {
5290
5321
  }
5291
5322
  if (nexttoken.id !== ';' && !nexttoken.reach) {
5292
5323
  nonadjacent(token, nexttoken);
5293
- this.first = parse(20);
5324
+ this.first = expression(20);
5294
5325
  }
5295
5326
  reachable('return');
5296
5327
  return this;
@@ -5300,7 +5331,7 @@ loop: for (;;) {
5300
5331
  stmt('throw', function () {
5301
5332
  nolinebreak(this);
5302
5333
  nonadjacent(token, nexttoken);
5303
- this.first = parse(20);
5334
+ this.first = expression(20);
5304
5335
  reachable('throw');
5305
5336
  return this;
5306
5337
  }).exps = true;
@@ -5425,14 +5456,21 @@ loop: for (;;) {
5425
5456
  // The actual JSLINT function itself.
5426
5457
 
5427
5458
  var itself = function (s, o) {
5428
- var a, i;
5459
+ var a, i, k;
5429
5460
  JSLINT.errors = [];
5430
5461
  predefined = Object.create(standard);
5431
5462
  if (o) {
5432
5463
  a = o.predef;
5433
- if (a instanceof Array) {
5434
- for (i = 0; i < a.length; i += 1) {
5435
- predefined[a[i]] = true;
5464
+ if (a) {
5465
+ if (Array.isArray(a)) {
5466
+ for (i = 0; i < a.length; i += 1) {
5467
+ predefined[a[i]] = true;
5468
+ }
5469
+ } else if (typeof a === 'object') {
5470
+ k = Object.keys(a);
5471
+ for (i = 0; i < k.length; i += 1) {
5472
+ predefined[k[i]] = !!a[k];
5473
+ }
5436
5474
  }
5437
5475
  }
5438
5476
  if (o.adsafe) {
@@ -5454,7 +5492,6 @@ loop: for (;;) {
5454
5492
  o.eqeqeq =
5455
5493
  o.nomen =
5456
5494
  o.safe =
5457
- o.strict =
5458
5495
  o.undef = true;
5459
5496
 
5460
5497
  predefined.Date =
@@ -5558,6 +5595,10 @@ loop: for (;;) {
5558
5595
  error("Expected '{a}' and instead saw '{b}'.",
5559
5596
  nexttoken, '<div>', nexttoken.value);
5560
5597
  }
5598
+ if (nexttoken.value === 'use strict') {
5599
+ warning("Use the function form of \"use strict\".");
5600
+ use_strict();
5601
+ }
5561
5602
  statements('lib');
5562
5603
  }
5563
5604
  }
@@ -5574,20 +5615,6 @@ loop: for (;;) {
5574
5615
  return JSLINT.errors.length === 0;
5575
5616
  };
5576
5617
 
5577
- function is_array(o) {
5578
- return Object.prototype.toString.apply(o) === '[object Array]';
5579
- }
5580
-
5581
- function to_array(o) {
5582
- var a = [], k;
5583
- for (k in o) {
5584
- if (is_own(o, k)) {
5585
- a.push(k);
5586
- }
5587
- }
5588
- return a;
5589
- }
5590
-
5591
5618
 
5592
5619
  // Data summary.
5593
5620
 
@@ -5619,7 +5646,7 @@ loop: for (;;) {
5619
5646
  data.urls = urls;
5620
5647
  }
5621
5648
 
5622
- globals = to_array(scope);
5649
+ globals = Object.keys(scope);
5623
5650
  if (globals.length > 0) {
5624
5651
  data.globals = globals;
5625
5652
  }
@@ -5636,7 +5663,7 @@ loop: for (;;) {
5636
5663
  if (v === 'unction') {
5637
5664
  v = 'unused';
5638
5665
  }
5639
- if (is_array(fu[v])) {
5666
+ if (Array.isArray(fu[v])) {
5640
5667
  fu[v].push(n);
5641
5668
  if (v === 'unused') {
5642
5669
  unused.push({
@@ -5696,7 +5723,6 @@ loop: for (;;) {
5696
5723
  }
5697
5724
  }
5698
5725
 
5699
-
5700
5726
  if (data.errors || data.implieds || data.unused) {
5701
5727
  err = true;
5702
5728
  o.push('<div id=errors><i>Error:</i>');
@@ -5774,7 +5800,7 @@ loop: for (;;) {
5774
5800
  }
5775
5801
 
5776
5802
  if (data.member) {
5777
- a = to_array(data.member);
5803
+ a = Object.keys(data.member);
5778
5804
  if (a.length) {
5779
5805
  a = a.sort();
5780
5806
  m = '<br><pre id=members>/*members ';
@@ -5805,7 +5831,7 @@ loop: for (;;) {
5805
5831
  };
5806
5832
  itself.jslint = itself;
5807
5833
 
5808
- itself.edition = '2010-11-27';
5834
+ itself.edition = '2010-12-21';
5809
5835
 
5810
5836
  return itself;
5811
5837
 
@@ -5828,7 +5854,7 @@ loop: for (;;) {
5828
5854
  }
5829
5855
 
5830
5856
  // parse options from a comma-separated string into a hash
5831
- var optionFields = args[0].split(",");
5857
+ var optionFields = args[0].split("&");
5832
5858
  var options = {};
5833
5859
  for (var i = 0; i < optionFields.length; i++) {
5834
5860
  var equalsSignIndex = optionFields[i].lastIndexOf("=");
@@ -5838,6 +5864,9 @@ loop: for (;;) {
5838
5864
  options[key] = eval(value);
5839
5865
  }
5840
5866
  }
5867
+ if (options.predef) {
5868
+ options.predef = options.predef.split(",");
5869
+ }
5841
5870
 
5842
5871
  var totalErrors = 0;
5843
5872
 
@@ -70,7 +70,7 @@ describe JSLint::Lint do
70
70
  end.should_not raise_error(JSLint::NoJavaException)
71
71
  end
72
72
 
73
- it "should pass comma-separated option string to JSLint" do
73
+ it "should pass an ampersand-separated option string to JSLint" do
74
74
  lint = JSLint::Lint.new
75
75
  lint.instance_variable_set("@config", { 'debug' => true, 'semicolons' => false, 'linelength' => 120 })
76
76
  setup_java(lint)
@@ -81,9 +81,9 @@ describe JSLint::Lint do
81
81
  with(an_instance_of(String), an_instance_of(String), an_instance_of(String)).
82
82
  and_return { |a, b, c| param_string = c; true }
83
83
  lint.run
84
- param_string.should =~ /semicolons=false/
85
- param_string.should =~ /linelength=120/
86
- param_string.should =~ /debug=true/
84
+
85
+ option_string = param_string.split(/\s+/).detect { |p| p =~ /linelength/ }
86
+ eval(option_string).split('&').sort.should == ['debug=true', 'linelength=120', 'semicolons=false']
87
87
  end
88
88
 
89
89
  it "should pass space-separated list of files to JSLint" do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jslint_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 29
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 4
10
- version: 1.0.4
9
+ - 5
10
+ version: 1.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jakub Suder
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-05 00:00:00 +01:00
18
+ date: 2011-01-08 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies: []
21
21