eslint 1.7.3 → 1.8.0

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.
@@ -33,6 +33,16 @@ module.exports = function(context) {
33
33
  // Using a stack to store if a function returns or not (handling nested functions)
34
34
  var fns = [];
35
35
 
36
+ /**
37
+ * Check if node type is a Class
38
+ * @param {ASTNode} node node to check.
39
+ * @returns {boolean} True is its a class
40
+ * @private
41
+ */
42
+ function isTypeClass(node) {
43
+ return node.type === "ClassExpression" || node.type === "ClassDeclaration";
44
+ }
45
+
36
46
  /**
37
47
  * When parsing a new function, store it in our function stack.
38
48
  * @param {ASTNode} node A function node to check.
@@ -41,7 +51,8 @@ module.exports = function(context) {
41
51
  */
42
52
  function startFunction(node) {
43
53
  fns.push({
44
- returnPresent: (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement")
54
+ returnPresent: (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") ||
55
+ isTypeClass(node)
45
56
  });
46
57
  }
47
58
 
@@ -165,7 +176,7 @@ module.exports = function(context) {
165
176
  });
166
177
 
167
178
  // check for functions missing @returns
168
- if (!isOverride && !hasReturns && !hasConstructor && node.parent.kind !== "get") {
179
+ if (!isOverride && !hasReturns && !hasConstructor && node.parent.kind !== "get" && !isTypeClass(node)) {
169
180
  if (requireReturn || functionData.returnPresent) {
170
181
  context.report(jsdocNode, "Missing JSDoc @" + (prefer.returns || "returns") + " for function.");
171
182
  }
@@ -174,23 +185,25 @@ module.exports = function(context) {
174
185
  // check the parameters
175
186
  var jsdocParams = Object.keys(params);
176
187
 
177
- node.params.forEach(function(param, i) {
178
- var name = param.name;
179
-
180
- // TODO(nzakas): Figure out logical things to do with destructured, default, rest params
181
- if (param.type === "Identifier") {
182
- if (jsdocParams[i] && (name !== jsdocParams[i])) {
183
- context.report(jsdocNode, "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.", {
184
- name: name,
185
- jsdocName: jsdocParams[i]
186
- });
187
- } else if (!params[name] && !isOverride) {
188
- context.report(jsdocNode, "Missing JSDoc for parameter '{{name}}'.", {
189
- name: name
190
- });
188
+ if (node.params) {
189
+ node.params.forEach(function(param, i) {
190
+ var name = param.name;
191
+
192
+ // TODO(nzakas): Figure out logical things to do with destructured, default, rest params
193
+ if (param.type === "Identifier") {
194
+ if (jsdocParams[i] && (name !== jsdocParams[i])) {
195
+ context.report(jsdocNode, "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.", {
196
+ name: name,
197
+ jsdocName: jsdocParams[i]
198
+ });
199
+ } else if (!params[name] && !isOverride) {
200
+ context.report(jsdocNode, "Missing JSDoc for parameter '{{name}}'.", {
201
+ name: name
202
+ });
203
+ }
191
204
  }
192
- }
193
- });
205
+ });
206
+ }
194
207
 
195
208
  if (options.matchDescription) {
196
209
  var regex = new RegExp(options.matchDescription);
@@ -212,9 +225,13 @@ module.exports = function(context) {
212
225
  "ArrowFunctionExpression": startFunction,
213
226
  "FunctionExpression": startFunction,
214
227
  "FunctionDeclaration": startFunction,
228
+ "ClassExpression": startFunction,
229
+ "ClassDeclaration": startFunction,
215
230
  "ArrowFunctionExpression:exit": checkJSDoc,
216
231
  "FunctionExpression:exit": checkJSDoc,
217
232
  "FunctionDeclaration:exit": checkJSDoc,
233
+ "ClassExpression:exit": checkJSDoc,
234
+ "ClassDeclaration:exit": checkJSDoc,
218
235
  "ReturnStatement": addReturn
219
236
  };
220
237
 
@@ -78,6 +78,34 @@ var RuleTesterParameters = [
78
78
 
79
79
  var validateSchema = validate(metaSchema, { verbose: true });
80
80
 
81
+ var hasOwnProperty = Function.call.bind(Object.hasOwnProperty);
82
+
83
+ /**
84
+ * Clones a given value deeply.
85
+ * Note: This ignores `parent` property.
86
+ *
87
+ * @param {any} x - A value to clone.
88
+ * @returns {any} A cloned value.
89
+ */
90
+ function cloneDeeplyExcludesParent(x) {
91
+ if (typeof x === "object" && x !== null) {
92
+ if (Array.isArray(x)) {
93
+ return x.map(cloneDeeplyExcludesParent);
94
+ }
95
+
96
+ var retv = {};
97
+ for (var key in x) {
98
+ if (key !== "parent" && hasOwnProperty(x, key)) {
99
+ retv[key] = cloneDeeplyExcludesParent(x[key]);
100
+ }
101
+ }
102
+
103
+ return retv;
104
+ }
105
+
106
+ return x;
107
+ }
108
+
81
109
  //------------------------------------------------------------------------------
82
110
  // Public Interface
83
111
  //------------------------------------------------------------------------------
@@ -178,7 +206,7 @@ RuleTester.prototype = {
178
206
  */
179
207
  function runRuleForItem(ruleName, item) {
180
208
  var config = clone(testerConfig),
181
- code, filename, schema;
209
+ code, filename, schema, beforeAST, afterAST;
182
210
 
183
211
  if (typeof item === "string") {
184
212
  code = item;
@@ -223,7 +251,21 @@ RuleTester.prototype = {
223
251
 
224
252
  validator.validate(config, "rule-tester");
225
253
 
226
- return eslint.verify(code, config, filename);
254
+ // To cache AST.
255
+ eslint.reset();
256
+ eslint.on("Program", function(node) {
257
+ beforeAST = cloneDeeplyExcludesParent(node);
258
+
259
+ eslint.on("Program:exit", function(node) {
260
+ afterAST = cloneDeeplyExcludesParent(node);
261
+ });
262
+ });
263
+
264
+ return {
265
+ messages: eslint.verify(code, config, filename, true),
266
+ beforeAST: beforeAST,
267
+ afterAST: afterAST
268
+ };
227
269
  }
228
270
 
229
271
  /**
@@ -235,10 +277,17 @@ RuleTester.prototype = {
235
277
  * @private
236
278
  */
237
279
  function testValidTemplate(ruleName, item) {
238
- var messages = runRuleForItem(ruleName, item);
280
+ var result = runRuleForItem(ruleName, item);
281
+ var messages = result.messages;
239
282
 
240
283
  assert.equal(messages.length, 0, util.format("Should have no errors but had %d: %s",
241
284
  messages.length, util.inspect(messages)));
285
+
286
+ assert.deepEqual(
287
+ result.beforeAST,
288
+ result.afterAST,
289
+ "Rule should not modify AST."
290
+ );
242
291
  }
243
292
 
244
293
  /**
@@ -250,7 +299,8 @@ RuleTester.prototype = {
250
299
  * @private
251
300
  */
252
301
  function testInvalidTemplate(ruleName, item) {
253
- var messages = runRuleForItem(ruleName, item);
302
+ var result = runRuleForItem(ruleName, item);
303
+ var messages = result.messages;
254
304
 
255
305
  if (typeof item.errors === "number") {
256
306
  assert.equal(messages.length, item.errors, util.format("Should have %d errors but had %d: %s",
@@ -261,11 +311,10 @@ RuleTester.prototype = {
261
311
  item.errors.length, messages.length, util.inspect(messages)));
262
312
 
263
313
  if (item.hasOwnProperty("output")) {
264
- var result = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
265
- assert.equal(result.output, item.output, "Output is incorrect.");
314
+ var fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
315
+ assert.equal(fixResult.output, item.output, "Output is incorrect.");
266
316
  }
267
317
 
268
-
269
318
  for (var i = 0, l = item.errors.length; i < l; i++) {
270
319
  assert.ok(!("fatal" in messages[i]), "A fatal parsing error occurred: " + messages[i].message);
271
320
  assert.equal(messages[i].ruleId, ruleName, "Error rule name should be the same as the name of the rule being tested");
@@ -299,6 +348,12 @@ RuleTester.prototype = {
299
348
  }
300
349
  }
301
350
  }
351
+
352
+ assert.deepEqual(
353
+ result.beforeAST,
354
+ result.afterAST,
355
+ "Rule should not modify AST."
356
+ );
302
357
  }
303
358
 
304
359
  // this creates a mocha test suite and pipes all supplied info
@@ -211,6 +211,12 @@ SourceCode.prototype = {
211
211
  }
212
212
  break;
213
213
 
214
+ case "ClassDeclaration":
215
+ return findJSDocComment(node.leadingComments, line);
216
+
217
+ case "ClassExpression":
218
+ return findJSDocComment(parent.parent.leadingComments, line);
219
+
214
220
  case "ArrowFunctionExpression":
215
221
  case "FunctionExpression":
216
222
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "1.7.3",
3
+ "version": "1.8.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {