jslint_on_rails 1.0.4 → 1.0.5

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.
@@ -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