eslint 0.5.0 → 0.6.2

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.
Files changed (48) hide show
  1. package/README.md +2 -8
  2. package/conf/environments.json +29 -12
  3. package/conf/eslint.json +7 -0
  4. package/lib/cli.js +21 -12
  5. package/lib/config.js +36 -13
  6. package/lib/eslint.js +218 -63
  7. package/lib/formatters/checkstyle.js +4 -6
  8. package/lib/formatters/compact.js +2 -5
  9. package/lib/formatters/junit.js +2 -5
  10. package/lib/formatters/stylish.js +2 -1
  11. package/lib/formatters/tap.js +3 -6
  12. package/lib/load-rules.js +3 -1
  13. package/lib/options.js +56 -47
  14. package/lib/rules/block-scoped-var.js +38 -4
  15. package/lib/rules/brace-style.js +6 -2
  16. package/lib/rules/default-case.js +64 -0
  17. package/lib/rules/eqeqeq.js +4 -0
  18. package/lib/rules/new-cap.js +1 -1
  19. package/lib/rules/no-comma-dangle.js +1 -1
  20. package/lib/rules/no-constant-condition.js +2 -1
  21. package/lib/rules/no-delete-var.js +1 -1
  22. package/lib/rules/no-else-return.js +1 -1
  23. package/lib/rules/no-extend-native.js +6 -2
  24. package/lib/rules/no-extra-parens.js +68 -33
  25. package/lib/rules/no-extra-strict.js +1 -1
  26. package/lib/rules/no-fallthrough.js +8 -0
  27. package/lib/rules/no-inner-declarations.js +70 -0
  28. package/lib/rules/no-invalid-regexp.js +2 -2
  29. package/lib/rules/no-lonely-if.js +28 -0
  30. package/lib/rules/no-mixed-requires.js +1 -1
  31. package/lib/rules/no-new-require.js +23 -0
  32. package/lib/rules/no-redeclare.js +4 -1
  33. package/lib/rules/no-restricted-modules.js +72 -0
  34. package/lib/rules/no-sequences.js +92 -0
  35. package/lib/rules/no-shadow-restricted-names.js +4 -2
  36. package/lib/rules/no-shadow.js +1 -1
  37. package/lib/rules/no-spaced-func.js +5 -3
  38. package/lib/rules/no-sparse-arrays.js +1 -3
  39. package/lib/rules/no-unused-vars.js +10 -4
  40. package/lib/rules/no-use-before-define.js +11 -2
  41. package/lib/rules/semi.js +11 -3
  42. package/lib/rules/sort-vars.js +1 -1
  43. package/lib/rules/space-after-keywords.js +64 -0
  44. package/lib/rules/space-infix-ops.js +11 -9
  45. package/lib/rules/space-return-throw-case.js +11 -3
  46. package/lib/rules/space-unary-word-ops.js +3 -2
  47. package/lib/rules/valid-jsdoc.js +18 -3
  48. package/package.json +8 -5
@@ -46,7 +46,16 @@ module.exports = function(context) {
46
46
  * @returns {Boolean} true when the identifier is in property position.
47
47
  */
48
48
  function isProperty(id, parent) {
49
- return id === parent.property && parent.type === "MemberExpression" && !parent.computed;
49
+ switch (parent.type) {
50
+ case "MemberExpression":
51
+ return id === parent.property && !parent.computed;
52
+
53
+ case "Property":
54
+ return id === parent.key;
55
+
56
+ default:
57
+ return false;
58
+ }
50
59
  }
51
60
 
52
61
  /**
@@ -84,6 +93,13 @@ module.exports = function(context) {
84
93
  return id.name;
85
94
  }));
86
95
  declare(node.id ? [node.id.name] : []);
96
+ declare(["arguments"]);
97
+ }
98
+
99
+ function variableDeclarationHandler(node) {
100
+ declare(node.declarations.map(function(decl) {
101
+ return decl.id.name;
102
+ }));
87
103
  }
88
104
 
89
105
  return {
@@ -98,9 +114,7 @@ module.exports = function(context) {
98
114
  pushScope();
99
115
  statements.forEach(function(stmt) {
100
116
  if (stmt.type === "VariableDeclaration") {
101
- declare(stmt.declarations.map(function(decl) {
102
- return decl.id.name;
103
- }));
117
+ variableDeclarationHandler(stmt);
104
118
  } else if (stmt.type === "FunctionDeclaration") {
105
119
  declare([stmt.id.name]);
106
120
  }
@@ -113,9 +127,29 @@ module.exports = function(context) {
113
127
  pushScope();
114
128
  declare([node.param.name]);
115
129
  },
130
+ "CatchClause:exit": popScope,
116
131
 
117
132
  "FunctionDeclaration": functionHandler,
133
+ "FunctionDeclaration:exit": popScope,
134
+
118
135
  "FunctionExpression": functionHandler,
136
+ "FunctionExpression:exit": popScope,
137
+
138
+ "ForStatement": function(node) {
139
+ pushScope();
140
+ if (node.init && node.init.type === "VariableDeclaration") {
141
+ variableDeclarationHandler(node.init);
142
+ }
143
+ },
144
+ "ForStatement:exit": popScope,
145
+
146
+ "ForInStatement": function(node) {
147
+ pushScope();
148
+ if (node.left.type === "VariableDeclaration") {
149
+ variableDeclarationHandler(node.left);
150
+ }
151
+ },
152
+ "ForInStatement:exit": popScope,
119
153
 
120
154
  "Identifier": function(node) {
121
155
  var ancestor = context.getAncestors().pop();
@@ -13,6 +13,7 @@ module.exports = function(context) {
13
13
  var style = context.options[0] || "1tbs";
14
14
 
15
15
  var OPEN_MESSAGE = "Opening curly brace does not appear on the same line as controlling statement.",
16
+ BODY_MESSAGE = "Statement inside of curly braces should be on next line.",
16
17
  CLOSE_MESSAGE = "Closing curly brace does not appear on the same line as the subsequent block.",
17
18
  CLOSE_MESSAGE_STROUSTRUP = "Closing curly brace appears on the same line as the subsequent block.";
18
19
 
@@ -33,11 +34,14 @@ module.exports = function(context) {
33
34
  [].forEach.call(blockProperties, function(blockProp) {
34
35
  var block = node[blockProp], previousToken, curlyToken;
35
36
  block = node[blockProp];
36
- if(block && block.type === "BlockStatement") {
37
+ if (block && block.type === "BlockStatement") {
37
38
  previousToken = context.getTokenBefore(block);
38
39
  curlyToken = context.getFirstToken(block);
40
+
39
41
  if (previousToken.loc.start.line !== curlyToken.loc.start.line) {
40
42
  context.report(node, OPEN_MESSAGE);
43
+ } else if (block.body.length && curlyToken.loc.start.line === block.body[0].loc.start.line) {
44
+ context.report(block.body[0], BODY_MESSAGE);
41
45
  }
42
46
  }
43
47
  });
@@ -123,7 +127,7 @@ module.exports = function(context) {
123
127
  */
124
128
  function checkSwitchStatement(node) {
125
129
  var tokens;
126
- if(node.cases && node.cases.length) {
130
+ if (node.cases && node.cases.length) {
127
131
  tokens = context.getTokensBefore(node.cases[0], 2);
128
132
  if (tokens[0].loc.start.line !== tokens[1].loc.start.line) {
129
133
  context.report(node, OPEN_MESSAGE);
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview require default case in switch statements
3
+ * @author Aliaksei Shytkin
4
+ */
5
+ "use strict";
6
+
7
+ var COMMENT_VALUE = "no default";
8
+
9
+ //------------------------------------------------------------------------------
10
+ // Rule Definition
11
+ //------------------------------------------------------------------------------
12
+
13
+ module.exports = function(context) {
14
+
15
+ //--------------------------------------------------------------------------
16
+ // Helpers
17
+ //--------------------------------------------------------------------------
18
+
19
+ /**
20
+ * Shortcut to get last element of array
21
+ * @param {*[]} collection Array
22
+ * @returns {*} Last element
23
+ */
24
+ function last(collection) {
25
+ return collection[collection.length - 1];
26
+ }
27
+
28
+ //--------------------------------------------------------------------------
29
+ // Public
30
+ //--------------------------------------------------------------------------
31
+
32
+ return {
33
+
34
+ "SwitchStatement": function(node) {
35
+
36
+ if (!node.cases.length) {
37
+ // skip check of empty switch because there is no easy way
38
+ // to extract comments inside it now
39
+ return;
40
+ }
41
+
42
+ var hasDefault = node.cases.some(function(v) {
43
+ return v.test === null;
44
+ });
45
+
46
+ if (!hasDefault) {
47
+
48
+ var comment;
49
+ var comments;
50
+
51
+ var lastCase = last(node.cases);
52
+ comments = context.getComments(lastCase).trailing;
53
+
54
+ if (comments.length) {
55
+ comment = last(comments);
56
+ }
57
+
58
+ if (!comment || comment.value.trim() !== COMMENT_VALUE) {
59
+ context.report(node, "Expected a default case.");
60
+ }
61
+ }
62
+ }
63
+ };
64
+ };
@@ -36,6 +36,10 @@ module.exports = function(context) {
36
36
  return;
37
37
  }
38
38
 
39
+ if (context.options[0] === "allow-null" && isNullCheck(node)) {
40
+ return;
41
+ }
42
+
39
43
  if (operator === "==") {
40
44
  context.report(node, "Expected '===' and instead saw '=='.");
41
45
  } else if (operator === "!=") {
@@ -22,7 +22,7 @@ module.exports = function(context) {
22
22
  constructorName = node.callee.name;
23
23
  }
24
24
 
25
- if (constructorName && constructorName.charAt(0) === constructorName.charAt(0).toLowerCase()) {
25
+ if (constructorName && constructorName.charAt(0) !== constructorName.charAt(0).toUpperCase()) {
26
26
  context.report(node, "A constructor name should start with an uppercase letter.");
27
27
  }
28
28
  }
@@ -22,7 +22,7 @@ module.exports = function(context) {
22
22
  lastItem = items[items.length - 1];
23
23
  // The last token in an object/array literal will always be a closing
24
24
  // curly, so we check the second to last token for a comma.
25
- if(secondToLastToken.value === "," && items.length && lastItem) {
25
+ if (secondToLastToken.value === "," && items.length && lastItem) {
26
26
  context.report(lastItem, secondToLastToken.loc.start, "Trailing comma.");
27
27
  }
28
28
  }
@@ -23,7 +23,7 @@ module.exports = function(context) {
23
23
  * @private
24
24
  */
25
25
  function isConstant(node) {
26
- switch(node.type) {
26
+ switch (node.type) {
27
27
  case "Literal":
28
28
  case "FunctionExpression":
29
29
  case "ObjectExpression":
@@ -38,6 +38,7 @@ module.exports = function(context) {
38
38
  return isConstant(node.right);
39
39
  case "SequenceExpression":
40
40
  return isConstant(node.expressions[node.expressions.length - 1]);
41
+ // no default
41
42
  }
42
43
  return false;
43
44
  }
@@ -15,7 +15,7 @@ module.exports = function(context) {
15
15
 
16
16
  "UnaryExpression": function(node) {
17
17
  if (node.operator === "delete" && node.argument.type === "Identifier") {
18
- context.report(node, "Variables should not be deleted​.");
18
+ context.report(node, "Variables should not be deleted.");
19
19
  }
20
20
  }
21
21
  };
@@ -17,7 +17,7 @@ module.exports = function(context) {
17
17
 
18
18
  function checkForReturnStatement(node, alternate) {
19
19
  if (node.type === "ReturnStatement") {
20
- context.report(alternate, "Unexpected 'else' after 'return'​.");
20
+ context.report(alternate, "Unexpected 'else' after 'return'.");
21
21
  }
22
22
  }
23
23
 
@@ -27,13 +27,17 @@ module.exports = function(context) {
27
27
  "AssignmentExpression": function(node) {
28
28
  var lhs = node.left, affectsProto;
29
29
 
30
- if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") { return; }
30
+ if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") {
31
+ return;
32
+ }
31
33
 
32
34
  affectsProto = lhs.object.computed ?
33
35
  lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype" :
34
36
  lhs.object.property.name === "prototype";
35
37
 
36
- if (!affectsProto) { return; }
38
+ if (!affectsProto) {
39
+ return;
40
+ }
37
41
 
38
42
  BUILTINS.forEach(function(builtin) {
39
43
  if (lhs.object.object.name === builtin) {
@@ -30,7 +30,7 @@ module.exports = function(context) {
30
30
 
31
31
  function precedence(node) {
32
32
 
33
- switch(node.type) {
33
+ switch (node.type) {
34
34
  case "SequenceExpression":
35
35
  return 0;
36
36
 
@@ -41,16 +41,17 @@ module.exports = function(context) {
41
41
  return 3;
42
42
 
43
43
  case "LogicalExpression":
44
- switch(node.operator) {
44
+ switch (node.operator) {
45
45
  case "||":
46
46
  return 4;
47
47
  case "&&":
48
48
  return 5;
49
+ // no default
49
50
  }
50
51
 
51
52
  /* falls through */
52
53
  case "BinaryExpression":
53
- switch(node.operator) {
54
+ switch (node.operator) {
54
55
  case "|":
55
56
  return 6;
56
57
  case "^":
@@ -80,6 +81,7 @@ module.exports = function(context) {
80
81
  case "/":
81
82
  case "%":
82
83
  return 13;
84
+ // no default
83
85
  }
84
86
  /* falls through */
85
87
  case "UnaryExpression":
@@ -87,9 +89,14 @@ module.exports = function(context) {
87
89
  case "UpdateExpression":
88
90
  return 15;
89
91
  case "CallExpression":
92
+ // IIFE is allowed to have parens in any position (#655)
93
+ if (node.callee.type === "FunctionExpression") {
94
+ return -1;
95
+ }
90
96
  return 16;
91
97
  case "NewExpression":
92
98
  return 17;
99
+ // no default
93
100
  }
94
101
  return 18;
95
102
  }
@@ -99,22 +106,22 @@ module.exports = function(context) {
99
106
  }
100
107
 
101
108
  function dryUnaryUpdate(node) {
102
- if(isParenthesised(node.argument) && precedence(node.argument) >= precedence(node)) {
109
+ if (isParenthesised(node.argument) && precedence(node.argument) >= precedence(node)) {
103
110
  report(node.argument);
104
111
  }
105
112
  }
106
113
 
107
114
  function dryCallNew(node) {
108
- if(isParenthesised(node.callee) && precedence(node.callee) >= precedence(node)) {
115
+ if (isParenthesised(node.callee) && precedence(node.callee) >= precedence(node)) {
109
116
  report(node.callee);
110
117
  }
111
- if(node.arguments.length === 1) {
112
- if(isParenthesisedTwice(node.arguments[0]) && precedence(node.arguments[0]) >= precedence({type: "AssignmentExpression"})) {
118
+ if (node.arguments.length === 1) {
119
+ if (isParenthesisedTwice(node.arguments[0]) && precedence(node.arguments[0]) >= precedence({type: "AssignmentExpression"})) {
113
120
  report(node.arguments[0]);
114
121
  }
115
122
  } else {
116
123
  [].forEach.call(node.arguments, function(arg){
117
- if(isParenthesised(arg) && precedence(arg) >= precedence({type: "AssignmentExpression"})) {
124
+ if (isParenthesised(arg) && precedence(arg) >= precedence({type: "AssignmentExpression"})) {
118
125
  report(arg);
119
126
  }
120
127
  });
@@ -123,10 +130,10 @@ module.exports = function(context) {
123
130
 
124
131
  function dryBinaryLogical(node) {
125
132
  var prec = precedence(node);
126
- if(isParenthesised(node.left) && precedence(node.left) >= prec) {
133
+ if (isParenthesised(node.left) && precedence(node.left) >= prec) {
127
134
  report(node.left);
128
135
  }
129
- if(isParenthesised(node.right) && precedence(node.right) > prec) {
136
+ if (isParenthesised(node.right) && precedence(node.right) > prec) {
130
137
  report(node.right);
131
138
  }
132
139
  }
@@ -134,55 +141,69 @@ module.exports = function(context) {
134
141
  return {
135
142
  "ArrayExpression": function(node) {
136
143
  [].forEach.call(node.elements, function(e) {
137
- if(e && isParenthesised(e) && precedence(e) >= precedence({type: "AssignmentExpression"})) {
144
+ if (e && isParenthesised(e) && precedence(e) >= precedence({type: "AssignmentExpression"})) {
138
145
  report(e);
139
146
  }
140
147
  });
141
148
  },
142
149
  "AssignmentExpression": function(node) {
143
- if(isParenthesised(node.right) && precedence(node.right) >= precedence(node)) {
150
+ if (isParenthesised(node.right) && precedence(node.right) >= precedence(node)) {
144
151
  report(node.right);
145
152
  }
146
153
  },
147
154
  "BinaryExpression": dryBinaryLogical,
148
155
  "CallExpression": dryCallNew,
149
156
  "ConditionalExpression": function(node) {
150
- if(isParenthesised(node.test) && precedence(node.test) >= precedence({type: "LogicalExpression", operator: "||"})) {
157
+ if (isParenthesised(node.test) && precedence(node.test) >= precedence({type: "LogicalExpression", operator: "||"})) {
151
158
  report(node.test);
152
159
  }
153
- if(isParenthesised(node.consequent) && precedence(node.consequent) >= precedence({type: "AssignmentExpression"})) {
160
+ if (isParenthesised(node.consequent) && precedence(node.consequent) >= precedence({type: "AssignmentExpression"})) {
154
161
  report(node.consequent);
155
162
  }
156
- if(isParenthesised(node.alternate) && precedence(node.alternate) >= precedence({type: "AssignmentExpression"})) {
163
+ if (isParenthesised(node.alternate) && precedence(node.alternate) >= precedence({type: "AssignmentExpression"})) {
157
164
  report(node.alternate);
158
165
  }
159
166
  },
160
167
  "DoWhileStatement": function(node) {
161
- if(isParenthesisedTwice(node.test)) { report(node.test); }
168
+ if (isParenthesisedTwice(node.test)) {
169
+ report(node.test);
170
+ }
162
171
  },
163
172
  "ExpressionStatement": function(node) {
164
173
  var firstToken;
165
- if(isParenthesised(node.expression)) {
174
+ if (isParenthesised(node.expression)) {
166
175
  firstToken = context.getFirstToken(node.expression);
167
- if(firstToken.value !== "function" && firstToken.value !== "{") {
176
+ if (firstToken.value !== "function" && firstToken.value !== "{") {
168
177
  report(node.expression);
169
178
  }
170
179
  }
171
180
  },
172
181
  "ForInStatement": function(node) {
173
- if(isParenthesised(node.right)) { report(node.right); }
182
+ if (isParenthesised(node.right)) {
183
+ report(node.right);
184
+ }
174
185
  },
175
186
  "ForStatement": function(node) {
176
- if(node.init && isParenthesised(node.init)) { report(node.init); }
177
- if(node.test && isParenthesised(node.test)) { report(node.test); }
178
- if(node.update && isParenthesised(node.update)) { report(node.update); }
187
+ if (node.init && isParenthesised(node.init)) {
188
+ report(node.init);
189
+ }
190
+
191
+ if (node.test && isParenthesised(node.test)) {
192
+ report(node.test);
193
+ }
194
+
195
+ if (node.update && isParenthesised(node.update)) {
196
+ report(node.update);
197
+ }
179
198
  },
180
199
  "IfStatement": function(node) {
181
- if(isParenthesisedTwice(node.test)) { report(node.test); }
200
+ if (isParenthesisedTwice(node.test)) {
201
+ report(node.test);
202
+ }
182
203
  },
183
204
  "LogicalExpression": dryBinaryLogical,
184
205
  "MemberExpression": function(node) {
185
- if(
206
+ if (
186
207
  isParenthesised(node.object) &&
187
208
  precedence(node.object) >= precedence(node) &&
188
209
  (
@@ -201,40 +222,54 @@ module.exports = function(context) {
201
222
  "ObjectExpression": function(node) {
202
223
  [].forEach.call(node.properties, function(e) {
203
224
  var v = e.value;
204
- if(v && isParenthesised(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) {
225
+ if (v && isParenthesised(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) {
205
226
  report(v);
206
227
  }
207
228
  });
208
229
  },
209
230
  "ReturnStatement": function(node) {
210
- if(node.argument && isParenthesised(node.argument)) { report(node.argument); }
231
+ if (node.argument && isParenthesised(node.argument)) {
232
+ report(node.argument);
233
+ }
211
234
  },
212
235
  "SequenceExpression": function(node) {
213
236
  [].forEach.call(node.expressions, function(e) {
214
- if(isParenthesised(e)) { report(e); }
237
+ if (isParenthesised(e) && precedence(e) >= precedence(node)) {
238
+ report(e);
239
+ }
215
240
  });
216
241
  },
217
242
  "SwitchCase": function(node) {
218
- if(node.test && isParenthesised(node.test)) { report(node.test); }
243
+ if (node.test && isParenthesised(node.test)) {
244
+ report(node.test);
245
+ }
219
246
  },
220
247
  "SwitchStatement": function(node) {
221
- if(isParenthesisedTwice(node.discriminant)) { report(node.discriminant); }
248
+ if (isParenthesisedTwice(node.discriminant)) {
249
+ report(node.discriminant);
250
+ }
222
251
  },
223
252
  "ThrowStatement": function(node) {
224
- if(isParenthesised(node.argument)) { report(node.argument); }
253
+ if (isParenthesised(node.argument)) {
254
+ report(node.argument);
255
+ }
225
256
  },
226
257
  "UnaryExpression": dryUnaryUpdate,
227
258
  "UpdateExpression": dryUnaryUpdate,
228
259
  "VariableDeclarator": function(node) {
229
- if(node.init && isParenthesised(node.init) && precedence(node.init) >= precedence({type: "AssignmentExpression"})) {
260
+ if (node.init && isParenthesised(node.init) && precedence(node.init) >= precedence({type: "AssignmentExpression"})) {
230
261
  report(node.init);
231
262
  }
232
263
  },
233
264
  "WhileStatement": function(node) {
234
- if(isParenthesisedTwice(node.test)) { report(node.test); }
265
+ if (isParenthesisedTwice(node.test)) {
266
+ report(node.test);
267
+ }
235
268
  },
236
269
  "WithStatement": function(node) {
237
- if(isParenthesisedTwice(node.object)) { report(node.object); }
270
+ if (isParenthesisedTwice(node.object)) {
271
+ report(node.object);
272
+ }
238
273
  }
239
274
  };
240
275
 
@@ -37,7 +37,7 @@ module.exports = function(context) {
37
37
  var useStrictDirectives, scope;
38
38
  useStrictDirectives = directives(node).filter(isStrict);
39
39
 
40
- switch(useStrictDirectives.length) {
40
+ switch (useStrictDirectives.length) {
41
41
  case 0:
42
42
  break;
43
43
 
@@ -25,6 +25,14 @@ module.exports = function(context) {
25
25
  comments,
26
26
  comment;
27
27
 
28
+ /*
29
+ * Some developers wrap case bodies in blocks, so if there is just one
30
+ * node and it's a block statement, check inside.
31
+ */
32
+ if (consequent.length === 1 && consequent[0].type === "BlockStatement") {
33
+ consequent = consequent[0];
34
+ }
35
+
28
36
  // checking on previous case
29
37
  if (!switchData.lastCaseClosed) {
30
38
 
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview Rule to enforce declarations in program or function body root.
3
+ * @author Brandon Mills
4
+ */
5
+
6
+ //------------------------------------------------------------------------------
7
+ // Rule Definition
8
+ //------------------------------------------------------------------------------
9
+
10
+ module.exports = function(context) {
11
+
12
+ "use strict";
13
+
14
+ /**
15
+ * Find the nearest Program or Function ancestor node.
16
+ * @returns {Object} Ancestor's type and distance from node.
17
+ */
18
+ function nearestBody() {
19
+ var ancestors = context.getAncestors(),
20
+ ancestor = ancestors.pop(),
21
+ generation = 1;
22
+
23
+ while (ancestor && ["Program", "FunctionDeclaration",
24
+ "FunctionExpression"].indexOf(ancestor.type) < 0) {
25
+ generation += 1;
26
+ ancestor = ancestors.pop();
27
+ }
28
+
29
+ return {
30
+ // Type of containing ancestor
31
+ type: ancestor.type,
32
+ // Separation between ancestor and node
33
+ distance: generation
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Ensure that a given node is at a program or function body's root.
39
+ * @param {ASTNode} node Declaration node to check.
40
+ * @returns {void}
41
+ */
42
+ function check(node) {
43
+ var body = nearestBody(node),
44
+ valid = ((body.type === "Program" && body.distance === 1) ||
45
+ body.distance === 2);
46
+
47
+ if (!valid) {
48
+ context.report(node, "Move {{type}} declaration to {{body}} root.",
49
+ {
50
+ type: (node.type === "FunctionDeclaration" ?
51
+ "function" : "variable"),
52
+ body: (body.type === "Program" ?
53
+ "program" : "function body")
54
+ }
55
+ );
56
+ }
57
+ }
58
+
59
+ return {
60
+
61
+ "FunctionDeclaration": check,
62
+ "VariableDeclaration": function(node) {
63
+ if (context.options[0] === "both") {
64
+ check(node);
65
+ }
66
+ }
67
+
68
+ };
69
+
70
+ };
@@ -15,9 +15,9 @@ module.exports = function(context) {
15
15
  }
16
16
 
17
17
  function check(node) {
18
- if(node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(node.arguments[0])) {
18
+ if (node.callee.type === "Identifier" && node.callee.name === "RegExp" && isString(node.arguments[0])) {
19
19
  try {
20
- if(isString(node.arguments[1])) {
20
+ if (isString(node.arguments[1])) {
21
21
  void new RegExp(node.arguments[0].value, node.arguments[1].value);
22
22
  } else {
23
23
  void new RegExp(node.arguments[0].value);
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @fileoverview Rule to disallow if as the only statmenet in an else block
3
+ * @author Brandon Mills
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Rule Definition
9
+ //------------------------------------------------------------------------------
10
+
11
+ module.exports = function(context) {
12
+
13
+ return {
14
+ "IfStatement": function(node) {
15
+ var ancestors = context.getAncestors(),
16
+ parent = ancestors.pop(),
17
+ grandparent = ancestors.pop();
18
+
19
+ if (parent && parent.type === "BlockStatement" &&
20
+ parent.body.length === 1 && grandparent &&
21
+ grandparent.type === "IfStatement" &&
22
+ parent === grandparent.alternate) {
23
+ context.report(node, "Unexpected if as the only statement in an else block.");
24
+ }
25
+ }
26
+ };
27
+
28
+ };
@@ -127,7 +127,7 @@ module.exports = function(context) {
127
127
  var found = {};
128
128
 
129
129
  declarations.forEach(function (declaration) {
130
- if(getDeclarationType(declaration.init) === DECL_REQUIRE) {
130
+ if (getDeclarationType(declaration.init) === DECL_REQUIRE) {
131
131
  found[inferModuleType(declaration.init)] = true;
132
132
  }
133
133
  });