eslint 4.7.2 → 4.11.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.
- package/CHANGELOG.md +123 -0
- package/README.md +34 -19
- package/conf/default-cli-options.js +7 -4
- package/conf/eslint-recommended.js +2 -0
- package/lib/ast-utils.js +83 -42
- package/lib/cli-engine.js +53 -17
- package/lib/cli.js +17 -9
- package/lib/code-path-analysis/code-path-analyzer.js +8 -4
- package/lib/code-path-analysis/code-path-segment.js +43 -41
- package/lib/code-path-analysis/code-path-state.js +7 -2
- package/lib/config/autoconfig.js +14 -12
- package/lib/config/config-file.js +8 -51
- package/lib/config/config-initializer.js +10 -6
- package/lib/config/config-ops.js +21 -21
- package/lib/config/config-rule.js +24 -24
- package/lib/config/config-validator.js +38 -36
- package/lib/config/plugins.js +8 -35
- package/lib/config.js +12 -8
- package/lib/formatters/html-template-message.html +1 -1
- package/lib/formatters/html-template-page.html +3 -1
- package/lib/formatters/html.js +2 -1
- package/lib/formatters/junit.js +21 -15
- package/lib/formatters/tap.js +5 -3
- package/lib/ignored-paths.js +5 -3
- package/lib/linter.js +42 -42
- package/lib/logging.js +2 -2
- package/lib/options.js +12 -0
- package/lib/rules/.eslintrc.yml +2 -2
- package/lib/rules/array-bracket-newline.js +39 -25
- package/lib/rules/array-bracket-spacing.js +28 -28
- package/lib/rules/array-callback-return.js +13 -9
- package/lib/rules/array-element-newline.js +8 -8
- package/lib/rules/arrow-body-style.js +12 -6
- package/lib/rules/arrow-parens.js +4 -2
- package/lib/rules/block-spacing.js +1 -1
- package/lib/rules/brace-style.js +14 -14
- package/lib/rules/callback-return.js +2 -1
- package/lib/rules/capitalized-comments.js +2 -1
- package/lib/rules/comma-style.js +3 -1
- package/lib/rules/computed-property-spacing.js +22 -22
- package/lib/rules/consistent-return.js +4 -4
- package/lib/rules/consistent-this.js +4 -2
- package/lib/rules/curly.js +13 -9
- package/lib/rules/dot-notation.js +56 -35
- package/lib/rules/func-call-spacing.js +4 -2
- package/lib/rules/generator-star-spacing.js +3 -3
- package/lib/rules/getter-return.js +2 -1
- package/lib/rules/indent-legacy.js +25 -14
- package/lib/rules/indent.js +101 -91
- package/lib/rules/key-spacing.js +5 -3
- package/lib/rules/lines-around-comment.js +33 -4
- package/lib/rules/lines-around-directive.js +16 -12
- package/lib/rules/lines-between-class-members.js +91 -0
- package/lib/rules/max-len.js +2 -3
- package/lib/rules/max-statements-per-line.js +5 -3
- package/lib/rules/multiline-comment-style.js +294 -0
- package/lib/rules/new-cap.js +2 -1
- package/lib/rules/newline-after-var.js +8 -6
- package/lib/rules/newline-before-return.js +13 -9
- package/lib/rules/no-alert.js +7 -15
- package/lib/rules/no-await-in-loop.js +17 -9
- package/lib/rules/no-bitwise.js +5 -3
- package/lib/rules/no-catch-shadow.js +4 -2
- package/lib/rules/no-console.js +2 -1
- package/lib/rules/no-constant-condition.js +2 -2
- package/lib/rules/no-control-regex.js +2 -1
- package/lib/rules/no-else-return.js +60 -19
- package/lib/rules/no-empty-character-class.js +11 -11
- package/lib/rules/no-extra-parens.js +22 -11
- package/lib/rules/no-extra-semi.js +5 -3
- package/lib/rules/no-global-assign.js +4 -2
- package/lib/rules/no-implicit-coercion.js +6 -6
- package/lib/rules/no-implied-eval.js +2 -1
- package/lib/rules/no-label-var.js +4 -2
- package/lib/rules/no-lone-blocks.js +3 -3
- package/lib/rules/no-lonely-if.js +2 -1
- package/lib/rules/no-loop-func.js +10 -7
- package/lib/rules/no-mixed-requires.js +8 -4
- package/lib/rules/no-native-reassign.js +4 -2
- package/lib/rules/no-param-reassign.js +4 -2
- package/lib/rules/no-regex-spaces.js +1 -1
- package/lib/rules/no-restricted-imports.js +86 -17
- package/lib/rules/no-restricted-modules.js +84 -15
- package/lib/rules/no-restricted-properties.js +10 -10
- package/lib/rules/no-return-await.js +6 -6
- package/lib/rules/no-self-assign.js +4 -2
- package/lib/rules/no-sequences.js +6 -4
- package/lib/rules/no-trailing-spaces.js +14 -8
- package/lib/rules/no-unneeded-ternary.js +3 -1
- package/lib/rules/no-unreachable.js +4 -2
- package/lib/rules/no-unused-labels.js +2 -1
- package/lib/rules/no-use-before-define.js +13 -11
- package/lib/rules/no-useless-call.js +1 -25
- package/lib/rules/no-useless-computed-key.js +2 -1
- package/lib/rules/no-useless-escape.js +31 -23
- package/lib/rules/no-useless-return.js +14 -8
- package/lib/rules/no-var.js +11 -0
- package/lib/rules/no-whitespace-before-property.js +4 -2
- package/lib/rules/object-curly-newline.js +9 -2
- package/lib/rules/object-curly-spacing.js +20 -20
- package/lib/rules/object-shorthand.js +47 -35
- package/lib/rules/operator-assignment.js +9 -9
- package/lib/rules/operator-linebreak.js +15 -11
- package/lib/rules/padding-line-between-statements.js +6 -4
- package/lib/rules/prefer-arrow-callback.js +12 -10
- package/lib/rules/prefer-const.js +18 -10
- package/lib/rules/prefer-destructuring.js +4 -2
- package/lib/rules/prefer-numeric-literals.js +4 -2
- package/lib/rules/prefer-promise-reject-errors.js +16 -16
- package/lib/rules/prefer-rest-params.js +4 -2
- package/lib/rules/prefer-spread.js +1 -25
- package/lib/rules/prefer-template.js +33 -29
- package/lib/rules/quote-props.js +8 -8
- package/lib/rules/require-jsdoc.js +11 -18
- package/lib/rules/semi-style.js +44 -19
- package/lib/rules/semi.js +5 -3
- package/lib/rules/sort-imports.js +11 -6
- package/lib/rules/space-unary-ops.js +67 -69
- package/lib/rules/strict.js +8 -8
- package/lib/rules/valid-jsdoc.js +39 -33
- package/lib/rules/valid-typeof.js +4 -4
- package/lib/rules/wrap-iife.js +4 -4
- package/lib/rules/yoda.js +9 -7
- package/lib/testers/rule-tester.js +63 -40
- package/lib/token-store/backward-token-cursor.js +5 -3
- package/lib/token-store/forward-token-cursor.js +5 -3
- package/lib/token-store/utils.js +8 -4
- package/lib/util/apply-disable-directives.js +56 -27
- package/lib/util/glob.js +1 -1
- package/lib/util/naming.js +112 -0
- package/lib/util/node-event-generator.js +13 -27
- package/lib/util/safe-emitter.js +54 -0
- package/lib/util/source-code-fixer.js +4 -2
- package/lib/util/source-code.js +70 -65
- package/messages/no-config-found.txt +1 -1
- package/package.json +8 -8
- package/lib/internal-rules/.eslintrc.yml +0 -3
- package/lib/internal-rules/internal-consistent-docs-description.js +0 -130
- package/lib/internal-rules/internal-no-invalid-meta.js +0 -188
package/lib/util/source-code.js
CHANGED
@@ -25,7 +25,6 @@ const TokenStore = require("../token-store"),
|
|
25
25
|
* @private
|
26
26
|
*/
|
27
27
|
function validate(ast) {
|
28
|
-
|
29
28
|
if (!ast.tokens) {
|
30
29
|
throw new Error("AST is missing the tokens array.");
|
31
30
|
}
|
@@ -44,34 +43,9 @@ function validate(ast) {
|
|
44
43
|
}
|
45
44
|
|
46
45
|
/**
|
47
|
-
*
|
48
|
-
* @param {ASTNode
|
49
|
-
* @
|
50
|
-
* @returns {ASTNode} The node if found, null if not.
|
51
|
-
* @private
|
52
|
-
*/
|
53
|
-
function findJSDocComment(comments, line) {
|
54
|
-
|
55
|
-
if (comments) {
|
56
|
-
for (let i = comments.length - 1; i >= 0; i--) {
|
57
|
-
if (comments[i].type === "Block" && comments[i].value.charAt(0) === "*") {
|
58
|
-
|
59
|
-
if (line - comments[i].loc.end.line <= 1) {
|
60
|
-
return comments[i];
|
61
|
-
}
|
62
|
-
break;
|
63
|
-
|
64
|
-
}
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
return null;
|
69
|
-
}
|
70
|
-
|
71
|
-
/**
|
72
|
-
* Check to see if its a ES6 export declaration
|
73
|
-
* @param {ASTNode} astNode - any node
|
74
|
-
* @returns {boolean} whether the given node represents a export declaration
|
46
|
+
* Check to see if its a ES6 export declaration.
|
47
|
+
* @param {ASTNode} astNode An AST node.
|
48
|
+
* @returns {boolean} whether the given node represents an export declaration.
|
75
49
|
* @private
|
76
50
|
*/
|
77
51
|
function looksLikeExport(astNode) {
|
@@ -80,10 +54,11 @@ function looksLikeExport(astNode) {
|
|
80
54
|
}
|
81
55
|
|
82
56
|
/**
|
83
|
-
* Merges two sorted lists into a larger sorted list in O(n) time
|
84
|
-
* @param {Token[]} tokens The list of tokens
|
85
|
-
* @param {Token[]} comments The list of comments
|
86
|
-
* @returns {Token[]} A sorted list of tokens and comments
|
57
|
+
* Merges two sorted lists into a larger sorted list in O(n) time.
|
58
|
+
* @param {Token[]} tokens The list of tokens.
|
59
|
+
* @param {Token[]} comments The list of comments.
|
60
|
+
* @returns {Token[]} A sorted list of tokens and comments.
|
61
|
+
* @private
|
87
62
|
*/
|
88
63
|
function sortedMerge(tokens, comments) {
|
89
64
|
const result = [];
|
@@ -182,9 +157,9 @@ class SourceCode extends TokenStore {
|
|
182
157
|
}
|
183
158
|
|
184
159
|
/**
|
185
|
-
* Split the source code into multiple lines based on the line delimiters
|
186
|
-
* @param {string} text Source code as a string
|
187
|
-
* @returns {string[]} Array of source code lines
|
160
|
+
* Split the source code into multiple lines based on the line delimiters.
|
161
|
+
* @param {string} text Source code as a string.
|
162
|
+
* @returns {string[]} Array of source code lines.
|
188
163
|
* @public
|
189
164
|
*/
|
190
165
|
static splitLines(text) {
|
@@ -197,6 +172,7 @@ class SourceCode extends TokenStore {
|
|
197
172
|
* @param {int=} beforeCount The number of characters before the node to retrieve.
|
198
173
|
* @param {int=} afterCount The number of characters after the node to retrieve.
|
199
174
|
* @returns {string} The text representing the AST node.
|
175
|
+
* @public
|
200
176
|
*/
|
201
177
|
getText(node, beforeCount, afterCount) {
|
202
178
|
if (node) {
|
@@ -209,6 +185,7 @@ class SourceCode extends TokenStore {
|
|
209
185
|
/**
|
210
186
|
* Gets the entire source text split into an array of lines.
|
211
187
|
* @returns {Array} The source text as an array of lines.
|
188
|
+
* @public
|
212
189
|
*/
|
213
190
|
getLines() {
|
214
191
|
return this.lines;
|
@@ -217,6 +194,7 @@ class SourceCode extends TokenStore {
|
|
217
194
|
/**
|
218
195
|
* Retrieves an array containing all comments in the source code.
|
219
196
|
* @returns {ASTNode[]} An array of comment nodes.
|
197
|
+
* @public
|
220
198
|
*/
|
221
199
|
getAllComments() {
|
222
200
|
return this.ast.comments;
|
@@ -225,7 +203,8 @@ class SourceCode extends TokenStore {
|
|
225
203
|
/**
|
226
204
|
* Gets all comments for the given node.
|
227
205
|
* @param {ASTNode} node The AST node to get the comments for.
|
228
|
-
* @returns {Object}
|
206
|
+
* @returns {Object} An object containing a leading and trailing array
|
207
|
+
* of comments indexed by their position.
|
229
208
|
* @public
|
230
209
|
*/
|
231
210
|
getComments(node) {
|
@@ -248,7 +227,8 @@ class SourceCode extends TokenStore {
|
|
248
227
|
}
|
249
228
|
} else {
|
250
229
|
|
251
|
-
/*
|
230
|
+
/*
|
231
|
+
* Return comments as trailing comments of nodes that only contain
|
252
232
|
* comments (to mimic the comment attachment behavior present in Espree).
|
253
233
|
*/
|
254
234
|
if ((node.type === "BlockStatement" || node.type === "ClassBody") && node.body.length === 0 ||
|
@@ -297,47 +277,68 @@ class SourceCode extends TokenStore {
|
|
297
277
|
/**
|
298
278
|
* Retrieves the JSDoc comment for a given node.
|
299
279
|
* @param {ASTNode} node The AST node to get the comment for.
|
300
|
-
* @returns {
|
301
|
-
* given node or null if not found.
|
280
|
+
* @returns {Token|null} The Block comment token containing the JSDoc comment
|
281
|
+
* for the given node or null if not found.
|
302
282
|
* @public
|
303
283
|
*/
|
304
284
|
getJSDocComment(node) {
|
285
|
+
|
286
|
+
/**
|
287
|
+
* Checks for the presence of a JSDoc comment for the given node and returns it.
|
288
|
+
* @param {ASTNode} astNode The AST node to get the comment for.
|
289
|
+
* @returns {Token|null} The Block comment token containing the JSDoc comment
|
290
|
+
* for the given node or null if not found.
|
291
|
+
* @private
|
292
|
+
*/
|
293
|
+
const findJSDocComment = astNode => {
|
294
|
+
const tokenBefore = this.getTokenBefore(astNode, { includeComments: true });
|
295
|
+
|
296
|
+
if (
|
297
|
+
tokenBefore &&
|
298
|
+
astUtils.isCommentToken(tokenBefore) &&
|
299
|
+
tokenBefore.type === "Block" &&
|
300
|
+
tokenBefore.value.charAt(0) === "*" &&
|
301
|
+
astNode.loc.start.line - tokenBefore.loc.end.line <= 1
|
302
|
+
) {
|
303
|
+
return tokenBefore;
|
304
|
+
}
|
305
|
+
|
306
|
+
return null;
|
307
|
+
};
|
305
308
|
let parent = node.parent;
|
306
|
-
const leadingComments = this.getCommentsBefore(node);
|
307
309
|
|
308
310
|
switch (node.type) {
|
309
311
|
case "ClassDeclaration":
|
310
312
|
case "FunctionDeclaration":
|
311
|
-
|
312
|
-
return findJSDocComment(this.getCommentsBefore(parent), parent.loc.start.line);
|
313
|
-
}
|
314
|
-
return findJSDocComment(leadingComments, node.loc.start.line);
|
313
|
+
return findJSDocComment(looksLikeExport(parent) ? parent : node);
|
315
314
|
|
316
315
|
case "ClassExpression":
|
317
|
-
return findJSDocComment(
|
316
|
+
return findJSDocComment(parent.parent);
|
318
317
|
|
319
318
|
case "ArrowFunctionExpression":
|
320
319
|
case "FunctionExpression":
|
321
320
|
if (parent.type !== "CallExpression" && parent.type !== "NewExpression") {
|
322
|
-
|
323
|
-
|
324
|
-
|
321
|
+
while (
|
322
|
+
!this.getCommentsBefore(parent).length &&
|
323
|
+
!/Function/.test(parent.type) &&
|
324
|
+
parent.type !== "MethodDefinition" &&
|
325
|
+
parent.type !== "Property"
|
326
|
+
) {
|
325
327
|
parent = parent.parent;
|
326
328
|
|
327
329
|
if (!parent) {
|
328
330
|
break;
|
329
331
|
}
|
330
|
-
|
331
|
-
parentLeadingComments = this.getCommentsBefore(parent);
|
332
332
|
}
|
333
333
|
|
334
|
-
|
335
|
-
|
336
|
-
|
334
|
+
if (parent && parent.type !== "FunctionDeclaration" && parent.type !== "Program") {
|
335
|
+
return findJSDocComment(parent);
|
336
|
+
}
|
337
337
|
}
|
338
338
|
|
339
|
-
|
339
|
+
return findJSDocComment(node);
|
340
340
|
|
341
|
+
// falls through
|
341
342
|
default:
|
342
343
|
return null;
|
343
344
|
}
|
@@ -347,6 +348,7 @@ class SourceCode extends TokenStore {
|
|
347
348
|
* Gets the deepest node containing a range index.
|
348
349
|
* @param {int} index Range index of the desired node.
|
349
350
|
* @returns {ASTNode} The node if found or null if not found.
|
351
|
+
* @public
|
350
352
|
*/
|
351
353
|
getNodeByRangeIndex(index) {
|
352
354
|
let result = null,
|
@@ -380,6 +382,7 @@ class SourceCode extends TokenStore {
|
|
380
382
|
* @param {Token} second The token to check before.
|
381
383
|
* @returns {boolean} True if there is only space between tokens, false
|
382
384
|
* if there is anything other than whitespace between tokens.
|
385
|
+
* @public
|
383
386
|
*/
|
384
387
|
isSpaceBetweenTokens(first, second) {
|
385
388
|
const text = this.text.slice(first.range[1], second.range[0]);
|
@@ -388,10 +391,11 @@ class SourceCode extends TokenStore {
|
|
388
391
|
}
|
389
392
|
|
390
393
|
/**
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
394
|
+
* Converts a source text index into a (line, column) pair.
|
395
|
+
* @param {number} index The index of a character in a file
|
396
|
+
* @returns {Object} A {line, column} location object with a 0-indexed column
|
397
|
+
* @public
|
398
|
+
*/
|
395
399
|
getLocFromIndex(index) {
|
396
400
|
if (typeof index !== "number") {
|
397
401
|
throw new TypeError("Expected `index` to be a number.");
|
@@ -422,12 +426,13 @@ class SourceCode extends TokenStore {
|
|
422
426
|
}
|
423
427
|
|
424
428
|
/**
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
429
|
+
* Converts a (line, column) pair into a range index.
|
430
|
+
* @param {Object} loc A line/column location
|
431
|
+
* @param {number} loc.line The line number of the location (1-indexed)
|
432
|
+
* @param {number} loc.column The column number of the location (0-indexed)
|
433
|
+
* @returns {number} The range index of the location in the file.
|
434
|
+
* @public
|
435
|
+
*/
|
431
436
|
getIndexFromLoc(loc) {
|
432
437
|
if (typeof loc !== "object" || typeof loc.line !== "number" || typeof loc.column !== "number") {
|
433
438
|
throw new TypeError("Expected `loc` to be an object with numeric `line` and `column` properties.");
|
@@ -2,6 +2,6 @@ ESLint couldn't find a configuration file. To set up a configuration file for th
|
|
2
2
|
|
3
3
|
eslint --init
|
4
4
|
|
5
|
-
ESLint looked for configuration files in <%= directory %> and its ancestors.
|
5
|
+
ESLint looked for configuration files in <%= directory %> and its ancestors. If it found none, it then looked in your home directory.
|
6
6
|
|
7
7
|
If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://gitter.im/eslint/eslint
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "4.
|
3
|
+
"version": "4.11.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -20,8 +20,7 @@
|
|
20
20
|
"browserify": "node Makefile.js browserify",
|
21
21
|
"perf": "node Makefile.js perf",
|
22
22
|
"profile": "beefy tests/bench/bench.js --open -- -t brfs -t ./tests/bench/xform-rules.js -r espree",
|
23
|
-
"coveralls": "cat ./coverage/lcov.info | coveralls"
|
24
|
-
"check-commit": "node Makefile.js checkGitCommit"
|
23
|
+
"coveralls": "cat ./coverage/lcov.info | coveralls"
|
25
24
|
},
|
26
25
|
"files": [
|
27
26
|
"LICENSE",
|
@@ -32,10 +31,10 @@
|
|
32
31
|
"messages"
|
33
32
|
],
|
34
33
|
"repository": "eslint/eslint",
|
35
|
-
"homepage": "
|
34
|
+
"homepage": "https://eslint.org",
|
36
35
|
"bugs": "https://github.com/eslint/eslint/issues/",
|
37
36
|
"dependencies": {
|
38
|
-
"ajv": "^5.
|
37
|
+
"ajv": "^5.3.0",
|
39
38
|
"babel-code-frame": "^6.22.0",
|
40
39
|
"chalk": "^2.1.0",
|
41
40
|
"concat-stream": "^1.6.0",
|
@@ -43,7 +42,7 @@
|
|
43
42
|
"debug": "^3.0.1",
|
44
43
|
"doctrine": "^2.0.0",
|
45
44
|
"eslint-scope": "^3.7.1",
|
46
|
-
"espree": "^3.5.
|
45
|
+
"espree": "^3.5.2",
|
47
46
|
"esquery": "^1.0.0",
|
48
47
|
"estraverse": "^4.2.0",
|
49
48
|
"esutils": "^2.0.2",
|
@@ -56,7 +55,7 @@
|
|
56
55
|
"inquirer": "^3.0.6",
|
57
56
|
"is-resolvable": "^1.0.0",
|
58
57
|
"js-yaml": "^3.9.1",
|
59
|
-
"json-stable-stringify": "^1.0.1",
|
58
|
+
"json-stable-stringify-without-jsonify": "^1.0.1",
|
60
59
|
"levn": "^0.3.0",
|
61
60
|
"lodash": "^4.17.4",
|
62
61
|
"minimatch": "^3.0.2",
|
@@ -87,7 +86,9 @@
|
|
87
86
|
"ejs": "^2.5.6",
|
88
87
|
"eslint-plugin-eslint-plugin": "^1.2.0",
|
89
88
|
"eslint-plugin-node": "^5.1.0",
|
89
|
+
"eslint-plugin-rulesdir": "^0.1.0",
|
90
90
|
"eslint-release": "^0.10.1",
|
91
|
+
"eslint-rule-composer": "^0.1.0",
|
91
92
|
"eslump": "1.6.0",
|
92
93
|
"esprima": "^4.0.0",
|
93
94
|
"esprima-fb": "^15001.1001.0-dev-harmony-fb",
|
@@ -107,7 +108,6 @@
|
|
107
108
|
"phantomjs-prebuilt": "^2.1.14",
|
108
109
|
"proxyquire": "^1.8.0",
|
109
110
|
"shelljs": "^0.7.7",
|
110
|
-
"shelljs-nodecli": "~0.1.1",
|
111
111
|
"sinon": "^3.2.1",
|
112
112
|
"temp": "^0.8.3",
|
113
113
|
"through": "^2.3.8"
|
@@ -1,130 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Internal rule to enforce meta.docs.description conventions.
|
3
|
-
* @author Vitor Balocco
|
4
|
-
*/
|
5
|
-
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
const ALLOWED_FIRST_WORDS = [
|
9
|
-
"enforce",
|
10
|
-
"require",
|
11
|
-
"disallow"
|
12
|
-
];
|
13
|
-
|
14
|
-
//------------------------------------------------------------------------------
|
15
|
-
// Helpers
|
16
|
-
//------------------------------------------------------------------------------
|
17
|
-
|
18
|
-
/**
|
19
|
-
* Gets the property of the Object node passed in that has the name specified.
|
20
|
-
*
|
21
|
-
* @param {string} property Name of the property to return.
|
22
|
-
* @param {ASTNode} node The ObjectExpression node.
|
23
|
-
* @returns {ASTNode} The Property node or null if not found.
|
24
|
-
*/
|
25
|
-
function getPropertyFromObject(property, node) {
|
26
|
-
const properties = node.properties;
|
27
|
-
|
28
|
-
for (let i = 0; i < properties.length; i++) {
|
29
|
-
if (properties[i].key.name === property) {
|
30
|
-
return properties[i];
|
31
|
-
}
|
32
|
-
}
|
33
|
-
|
34
|
-
return null;
|
35
|
-
}
|
36
|
-
|
37
|
-
/**
|
38
|
-
* Verifies that the meta.docs.description property follows our internal conventions.
|
39
|
-
*
|
40
|
-
* @param {RuleContext} context The ESLint rule context.
|
41
|
-
* @param {ASTNode} exportsNode ObjectExpression node that the rule exports.
|
42
|
-
* @returns {void}
|
43
|
-
*/
|
44
|
-
function checkMetaDocsDescription(context, exportsNode) {
|
45
|
-
if (exportsNode.type !== "ObjectExpression") {
|
46
|
-
|
47
|
-
// if the exported node is not the correct format, "internal-no-invalid-meta" will already report this.
|
48
|
-
return;
|
49
|
-
}
|
50
|
-
|
51
|
-
const metaProperty = getPropertyFromObject("meta", exportsNode);
|
52
|
-
const metaDocs = metaProperty && getPropertyFromObject("docs", metaProperty.value);
|
53
|
-
const metaDocsDescription = metaDocs && getPropertyFromObject("description", metaDocs.value);
|
54
|
-
|
55
|
-
if (!metaDocsDescription) {
|
56
|
-
|
57
|
-
// if there is no `meta.docs.description` property, "internal-no-invalid-meta" will already report this.
|
58
|
-
return;
|
59
|
-
}
|
60
|
-
|
61
|
-
const description = metaDocsDescription.value.value;
|
62
|
-
|
63
|
-
if (typeof description !== "string") {
|
64
|
-
context.report({
|
65
|
-
node: metaDocsDescription.value,
|
66
|
-
message: "`meta.docs.description` should be a string."
|
67
|
-
});
|
68
|
-
return;
|
69
|
-
}
|
70
|
-
|
71
|
-
if (description === "") {
|
72
|
-
context.report({
|
73
|
-
node: metaDocsDescription.value,
|
74
|
-
message: "`meta.docs.description` should not be empty."
|
75
|
-
});
|
76
|
-
return;
|
77
|
-
}
|
78
|
-
|
79
|
-
if (description.indexOf(" ") === 0) {
|
80
|
-
context.report({
|
81
|
-
node: metaDocsDescription.value,
|
82
|
-
message: "`meta.docs.description` should not start with whitespace."
|
83
|
-
});
|
84
|
-
return;
|
85
|
-
}
|
86
|
-
|
87
|
-
const firstWord = description.split(" ")[0];
|
88
|
-
|
89
|
-
if (ALLOWED_FIRST_WORDS.indexOf(firstWord) === -1) {
|
90
|
-
context.report({
|
91
|
-
node: metaDocsDescription.value,
|
92
|
-
message: "`meta.docs.description` should start with one of the following words: {{ allowedWords }}. Started with \"{{ firstWord }}\" instead.",
|
93
|
-
data: {
|
94
|
-
allowedWords: ALLOWED_FIRST_WORDS.join(", "),
|
95
|
-
firstWord
|
96
|
-
}
|
97
|
-
});
|
98
|
-
}
|
99
|
-
}
|
100
|
-
|
101
|
-
//------------------------------------------------------------------------------
|
102
|
-
// Rule Definition
|
103
|
-
//------------------------------------------------------------------------------
|
104
|
-
|
105
|
-
module.exports = {
|
106
|
-
meta: {
|
107
|
-
docs: {
|
108
|
-
description: "enforce correct conventions of `meta.docs.description` property in core rules",
|
109
|
-
category: "Internal",
|
110
|
-
recommended: false
|
111
|
-
},
|
112
|
-
|
113
|
-
schema: []
|
114
|
-
},
|
115
|
-
|
116
|
-
create(context) {
|
117
|
-
return {
|
118
|
-
AssignmentExpression(node) {
|
119
|
-
if (node.left &&
|
120
|
-
node.right &&
|
121
|
-
node.left.type === "MemberExpression" &&
|
122
|
-
node.left.object.name === "module" &&
|
123
|
-
node.left.property.name === "exports") {
|
124
|
-
|
125
|
-
checkMetaDocsDescription(context, node.right);
|
126
|
-
}
|
127
|
-
}
|
128
|
-
};
|
129
|
-
}
|
130
|
-
};
|
@@ -1,188 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Internal rule to prevent missing or invalid meta property in core rules.
|
3
|
-
* @author Vitor Balocco
|
4
|
-
*/
|
5
|
-
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
//------------------------------------------------------------------------------
|
9
|
-
// Helpers
|
10
|
-
//------------------------------------------------------------------------------
|
11
|
-
|
12
|
-
/**
|
13
|
-
* Gets the property of the Object node passed in that has the name specified.
|
14
|
-
*
|
15
|
-
* @param {string} property Name of the property to return.
|
16
|
-
* @param {ASTNode} node The ObjectExpression node.
|
17
|
-
* @returns {ASTNode} The Property node or null if not found.
|
18
|
-
*/
|
19
|
-
function getPropertyFromObject(property, node) {
|
20
|
-
const properties = node.properties;
|
21
|
-
|
22
|
-
for (let i = 0; i < properties.length; i++) {
|
23
|
-
if (properties[i].key.name === property) {
|
24
|
-
return properties[i];
|
25
|
-
}
|
26
|
-
}
|
27
|
-
|
28
|
-
return null;
|
29
|
-
}
|
30
|
-
|
31
|
-
/**
|
32
|
-
* Extracts the `meta` property from the ObjectExpression that all rules export.
|
33
|
-
*
|
34
|
-
* @param {ASTNode} exportsNode ObjectExpression node that the rule exports.
|
35
|
-
* @returns {ASTNode} The `meta` Property node or null if not found.
|
36
|
-
*/
|
37
|
-
function getMetaPropertyFromExportsNode(exportsNode) {
|
38
|
-
return getPropertyFromObject("meta", exportsNode);
|
39
|
-
}
|
40
|
-
|
41
|
-
/**
|
42
|
-
* Whether this `meta` ObjectExpression has a `docs` property defined or not.
|
43
|
-
*
|
44
|
-
* @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
|
45
|
-
* @returns {boolean} `true` if a `docs` property exists.
|
46
|
-
*/
|
47
|
-
function hasMetaDocs(metaPropertyNode) {
|
48
|
-
return Boolean(getPropertyFromObject("docs", metaPropertyNode.value));
|
49
|
-
}
|
50
|
-
|
51
|
-
/**
|
52
|
-
* Whether this `meta` ObjectExpression has a `docs.description` property defined or not.
|
53
|
-
*
|
54
|
-
* @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
|
55
|
-
* @returns {boolean} `true` if a `docs.description` property exists.
|
56
|
-
*/
|
57
|
-
function hasMetaDocsDescription(metaPropertyNode) {
|
58
|
-
const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
|
59
|
-
|
60
|
-
return metaDocs && getPropertyFromObject("description", metaDocs.value);
|
61
|
-
}
|
62
|
-
|
63
|
-
/**
|
64
|
-
* Whether this `meta` ObjectExpression has a `docs.category` property defined or not.
|
65
|
-
*
|
66
|
-
* @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
|
67
|
-
* @returns {boolean} `true` if a `docs.category` property exists.
|
68
|
-
*/
|
69
|
-
function hasMetaDocsCategory(metaPropertyNode) {
|
70
|
-
const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
|
71
|
-
|
72
|
-
return metaDocs && getPropertyFromObject("category", metaDocs.value);
|
73
|
-
}
|
74
|
-
|
75
|
-
/**
|
76
|
-
* Whether this `meta` ObjectExpression has a `docs.recommended` property defined or not.
|
77
|
-
*
|
78
|
-
* @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
|
79
|
-
* @returns {boolean} `true` if a `docs.recommended` property exists.
|
80
|
-
*/
|
81
|
-
function hasMetaDocsRecommended(metaPropertyNode) {
|
82
|
-
const metaDocs = getPropertyFromObject("docs", metaPropertyNode.value);
|
83
|
-
|
84
|
-
return metaDocs && getPropertyFromObject("recommended", metaDocs.value);
|
85
|
-
}
|
86
|
-
|
87
|
-
/**
|
88
|
-
* Whether this `meta` ObjectExpression has a `schema` property defined or not.
|
89
|
-
*
|
90
|
-
* @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
|
91
|
-
* @returns {boolean} `true` if a `schema` property exists.
|
92
|
-
*/
|
93
|
-
function hasMetaSchema(metaPropertyNode) {
|
94
|
-
return getPropertyFromObject("schema", metaPropertyNode.value);
|
95
|
-
}
|
96
|
-
|
97
|
-
/**
|
98
|
-
* Checks the validity of the meta definition of this rule and reports any errors found.
|
99
|
-
*
|
100
|
-
* @param {RuleContext} context The ESLint rule context.
|
101
|
-
* @param {ASTNode} exportsNode ObjectExpression node that the rule exports.
|
102
|
-
* @param {boolean} ruleIsFixable whether the rule is fixable or not.
|
103
|
-
* @returns {void}
|
104
|
-
*/
|
105
|
-
function checkMetaValidity(context, exportsNode) {
|
106
|
-
const metaProperty = getMetaPropertyFromExportsNode(exportsNode);
|
107
|
-
|
108
|
-
if (!metaProperty) {
|
109
|
-
context.report(exportsNode, "Rule is missing a meta property.");
|
110
|
-
return;
|
111
|
-
}
|
112
|
-
|
113
|
-
if (!hasMetaDocs(metaProperty)) {
|
114
|
-
context.report(metaProperty, "Rule is missing a meta.docs property.");
|
115
|
-
return;
|
116
|
-
}
|
117
|
-
|
118
|
-
if (!hasMetaDocsDescription(metaProperty)) {
|
119
|
-
context.report(metaProperty, "Rule is missing a meta.docs.description property.");
|
120
|
-
return;
|
121
|
-
}
|
122
|
-
|
123
|
-
if (!hasMetaDocsCategory(metaProperty)) {
|
124
|
-
context.report(metaProperty, "Rule is missing a meta.docs.category property.");
|
125
|
-
return;
|
126
|
-
}
|
127
|
-
|
128
|
-
if (!hasMetaDocsRecommended(metaProperty)) {
|
129
|
-
context.report(metaProperty, "Rule is missing a meta.docs.recommended property.");
|
130
|
-
return;
|
131
|
-
}
|
132
|
-
|
133
|
-
if (!hasMetaSchema(metaProperty)) {
|
134
|
-
context.report(metaProperty, "Rule is missing a meta.schema property.");
|
135
|
-
}
|
136
|
-
}
|
137
|
-
|
138
|
-
/**
|
139
|
-
* Whether this node is the correct format for a rule definition or not.
|
140
|
-
*
|
141
|
-
* @param {ASTNode} node node that the rule exports.
|
142
|
-
* @returns {boolean} `true` if the exported node is the correct format for a rule definition
|
143
|
-
*/
|
144
|
-
function isCorrectExportsFormat(node) {
|
145
|
-
return node.type === "ObjectExpression";
|
146
|
-
}
|
147
|
-
|
148
|
-
//------------------------------------------------------------------------------
|
149
|
-
// Rule Definition
|
150
|
-
//------------------------------------------------------------------------------
|
151
|
-
|
152
|
-
module.exports = {
|
153
|
-
meta: {
|
154
|
-
docs: {
|
155
|
-
description: "enforce correct use of `meta` property in core rules",
|
156
|
-
category: "Internal",
|
157
|
-
recommended: false
|
158
|
-
},
|
159
|
-
|
160
|
-
schema: []
|
161
|
-
},
|
162
|
-
|
163
|
-
create(context) {
|
164
|
-
let exportsNode;
|
165
|
-
|
166
|
-
return {
|
167
|
-
AssignmentExpression(node) {
|
168
|
-
if (node.left &&
|
169
|
-
node.right &&
|
170
|
-
node.left.type === "MemberExpression" &&
|
171
|
-
node.left.object.name === "module" &&
|
172
|
-
node.left.property.name === "exports") {
|
173
|
-
|
174
|
-
exportsNode = node.right;
|
175
|
-
}
|
176
|
-
},
|
177
|
-
|
178
|
-
"Program:exit"() {
|
179
|
-
if (!isCorrectExportsFormat(exportsNode)) {
|
180
|
-
context.report({ node: exportsNode, message: "Rule does not export an Object. Make sure the rule follows the new rule format." });
|
181
|
-
return;
|
182
|
-
}
|
183
|
-
|
184
|
-
checkMetaValidity(context, exportsNode);
|
185
|
-
}
|
186
|
-
};
|
187
|
-
}
|
188
|
-
};
|