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
@@ -82,6 +82,12 @@ module.exports = {
|
|
82
82
|
allowBlockEnd: {
|
83
83
|
type: "boolean"
|
84
84
|
},
|
85
|
+
allowClassStart: {
|
86
|
+
type: "boolean"
|
87
|
+
},
|
88
|
+
allowClassEnd: {
|
89
|
+
type: "boolean"
|
90
|
+
},
|
85
91
|
allowObjectStart: {
|
86
92
|
type: "boolean"
|
87
93
|
},
|
@@ -224,6 +230,24 @@ module.exports = {
|
|
224
230
|
return isCommentAtParentEnd(token, "ClassBody") || isCommentAtParentEnd(token, "BlockStatement") || isCommentAtParentEnd(token, "SwitchCase") || isCommentAtParentEnd(token, "SwitchStatement");
|
225
231
|
}
|
226
232
|
|
233
|
+
/**
|
234
|
+
* Returns whether or not comments are at the class start or not.
|
235
|
+
* @param {token} token The Comment token.
|
236
|
+
* @returns {boolean} True if the comment is at class start.
|
237
|
+
*/
|
238
|
+
function isCommentAtClassStart(token) {
|
239
|
+
return isCommentAtParentStart(token, "ClassBody");
|
240
|
+
}
|
241
|
+
|
242
|
+
/**
|
243
|
+
* Returns whether or not comments are at the class end or not.
|
244
|
+
* @param {token} token The Comment token.
|
245
|
+
* @returns {boolean} True if the comment is at class end.
|
246
|
+
*/
|
247
|
+
function isCommentAtClassEnd(token) {
|
248
|
+
return isCommentAtParentEnd(token, "ClassBody");
|
249
|
+
}
|
250
|
+
|
227
251
|
/**
|
228
252
|
* Returns whether or not comments are at the object start or not.
|
229
253
|
* @param {token} token The Comment token.
|
@@ -284,15 +308,20 @@ module.exports = {
|
|
284
308
|
nextLineNum = token.loc.end.line + 1,
|
285
309
|
commentIsNotAlone = codeAroundComment(token);
|
286
310
|
|
287
|
-
const blockStartAllowed = options.allowBlockStart &&
|
288
|
-
|
311
|
+
const blockStartAllowed = options.allowBlockStart &&
|
312
|
+
isCommentAtBlockStart(token) &&
|
313
|
+
!(options.allowClassStart === false &&
|
314
|
+
isCommentAtClassStart(token)),
|
315
|
+
blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(token) && !(options.allowClassEnd === false && isCommentAtClassEnd(token)),
|
316
|
+
classStartAllowed = options.allowClassStart && isCommentAtClassStart(token),
|
317
|
+
classEndAllowed = options.allowClassEnd && isCommentAtClassEnd(token),
|
289
318
|
objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(token),
|
290
319
|
objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(token),
|
291
320
|
arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(token),
|
292
321
|
arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(token);
|
293
322
|
|
294
|
-
const exceptionStartAllowed = blockStartAllowed || objectStartAllowed || arrayStartAllowed;
|
295
|
-
const exceptionEndAllowed = blockEndAllowed || objectEndAllowed || arrayEndAllowed;
|
323
|
+
const exceptionStartAllowed = blockStartAllowed || classStartAllowed || objectStartAllowed || arrayStartAllowed;
|
324
|
+
const exceptionEndAllowed = blockEndAllowed || classEndAllowed || objectEndAllowed || arrayEndAllowed;
|
296
325
|
|
297
326
|
// ignore top of the file and bottom of the file
|
298
327
|
if (prevLineNum < 1) {
|
@@ -67,12 +67,12 @@ module.exports = {
|
|
67
67
|
}
|
68
68
|
|
69
69
|
/**
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
* Gets the last token of a node that is on the same line as the rest of the node.
|
71
|
+
* This will usually be the last token of the node, but it will be the second-to-last token if the node has a trailing
|
72
|
+
* semicolon on a different line.
|
73
|
+
* @param {ASTNode} node A directive node
|
74
|
+
* @returns {Token} The last token of the node on the line
|
75
|
+
*/
|
76
76
|
function getLastTokenOnLine(node) {
|
77
77
|
const lastToken = sourceCode.getLastToken(node);
|
78
78
|
const secondToLastToken = sourceCode.getTokenBefore(lastToken);
|
@@ -136,9 +136,11 @@ module.exports = {
|
|
136
136
|
const firstDirective = directives[0];
|
137
137
|
const leadingComments = sourceCode.getCommentsBefore(firstDirective);
|
138
138
|
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
/*
|
140
|
+
* Only check before the first directive if it is preceded by a comment or if it is at the top of
|
141
|
+
* the file and expectLineBefore is set to "never". This is to not force a newline at the top of
|
142
|
+
* the file if there are no comments as well as for compatibility with padded-blocks.
|
143
|
+
*/
|
142
144
|
if (leadingComments.length) {
|
143
145
|
if (expectLineBefore === "always" && !hasNewlineBefore(firstDirective)) {
|
144
146
|
reportError(firstDirective, "before", true);
|
@@ -159,9 +161,11 @@ module.exports = {
|
|
159
161
|
const lastDirective = directives[directives.length - 1];
|
160
162
|
const statements = node.type === "Program" ? node.body : node.body.body;
|
161
163
|
|
162
|
-
|
163
|
-
|
164
|
-
|
164
|
+
/*
|
165
|
+
* Do not check after the last directive if the body only
|
166
|
+
* contains a directive prologue and isn't followed by a comment to ensure
|
167
|
+
* this rule behaves well with padded-blocks.
|
168
|
+
*/
|
165
169
|
if (lastDirective === statements[statements.length - 1] && !lastDirective.trailingComments) {
|
166
170
|
return;
|
167
171
|
}
|
@@ -0,0 +1,91 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Rule to check empty newline between class members
|
3
|
+
* @author 薛定谔的猫<hh_2013@foxmail.com>
|
4
|
+
*/
|
5
|
+
"use strict";
|
6
|
+
|
7
|
+
const astUtils = require("../ast-utils");
|
8
|
+
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
// Rule Definition
|
11
|
+
//------------------------------------------------------------------------------
|
12
|
+
|
13
|
+
module.exports = {
|
14
|
+
meta: {
|
15
|
+
docs: {
|
16
|
+
description: "require or disallow an empty line between class members",
|
17
|
+
category: "Stylistic Issues",
|
18
|
+
recommended: false
|
19
|
+
},
|
20
|
+
|
21
|
+
fixable: "whitespace",
|
22
|
+
|
23
|
+
schema: [
|
24
|
+
{
|
25
|
+
enum: ["always", "never"]
|
26
|
+
},
|
27
|
+
{
|
28
|
+
type: "object",
|
29
|
+
properties: {
|
30
|
+
exceptAfterSingleLine: {
|
31
|
+
type: "boolean"
|
32
|
+
}
|
33
|
+
},
|
34
|
+
additionalProperties: false
|
35
|
+
}
|
36
|
+
]
|
37
|
+
},
|
38
|
+
|
39
|
+
create(context) {
|
40
|
+
|
41
|
+
const options = [];
|
42
|
+
|
43
|
+
options[0] = context.options[0] || "always";
|
44
|
+
options[1] = context.options[1] || { exceptAfterSingleLine: false };
|
45
|
+
|
46
|
+
const ALWAYS_MESSAGE = "Expected blank line between class members.";
|
47
|
+
const NEVER_MESSAGE = "Unexpected blank line between class members.";
|
48
|
+
|
49
|
+
const sourceCode = context.getSourceCode();
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Checks if there is padding between two tokens
|
53
|
+
* @param {Token} first The first token
|
54
|
+
* @param {Token} second The second token
|
55
|
+
* @returns {boolean} True if there is at least a line between the tokens
|
56
|
+
*/
|
57
|
+
function isPaddingBetweenTokens(first, second) {
|
58
|
+
return second.loc.start.line - first.loc.end.line >= 2;
|
59
|
+
}
|
60
|
+
|
61
|
+
return {
|
62
|
+
ClassBody(node) {
|
63
|
+
const body = node.body;
|
64
|
+
|
65
|
+
for (let i = 0; i < body.length - 1; i++) {
|
66
|
+
const curFirst = sourceCode.getFirstToken(body[i]);
|
67
|
+
const curLast = sourceCode.getLastToken(body[i]);
|
68
|
+
const comments = sourceCode.getCommentsBefore(body[i + 1]);
|
69
|
+
const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]);
|
70
|
+
const isPadded = isPaddingBetweenTokens(curLast, nextFirst);
|
71
|
+
const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast);
|
72
|
+
const skip = !isMulti && options[1].exceptAfterSingleLine;
|
73
|
+
|
74
|
+
|
75
|
+
if ((options[0] === "always" && !skip && !isPadded) ||
|
76
|
+
(options[0] === "never" && isPadded)) {
|
77
|
+
context.report({
|
78
|
+
node: body[i + 1],
|
79
|
+
message: isPadded ? NEVER_MESSAGE : ALWAYS_MESSAGE,
|
80
|
+
fix(fixer) {
|
81
|
+
return isPadded
|
82
|
+
? fixer.replaceTextRange([curLast.range[1], nextFirst.range[0]], "\n")
|
83
|
+
: fixer.insertTextAfter(curLast, "\n");
|
84
|
+
}
|
85
|
+
});
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
};
|
90
|
+
}
|
91
|
+
};
|
package/lib/rules/max-len.js
CHANGED
@@ -181,11 +181,10 @@ module.exports = {
|
|
181
181
|
* Gets the line after the comment and any remaining trailing whitespace is
|
182
182
|
* stripped.
|
183
183
|
* @param {string} line The source line with a trailing comment
|
184
|
-
* @param {number} lineNumber The one-indexed line number this is on
|
185
184
|
* @param {ASTNode} comment The comment to remove
|
186
185
|
* @returns {string} Line without comment and trailing whitepace
|
187
186
|
*/
|
188
|
-
function stripTrailingComment(line,
|
187
|
+
function stripTrailingComment(line, comment) {
|
189
188
|
|
190
189
|
// loc.column is zero-indexed
|
191
190
|
return line.slice(0, comment.loc.start.column).replace(/\s+$/, "");
|
@@ -306,7 +305,7 @@ module.exports = {
|
|
306
305
|
if (isFullLineComment(line, lineNumber, comment)) {
|
307
306
|
lineIsComment = true;
|
308
307
|
} else if (ignoreTrailingComments && isTrailingComment(line, lineNumber, comment)) {
|
309
|
-
line = stripTrailingComment(line,
|
308
|
+
line = stripTrailingComment(line, comment);
|
310
309
|
}
|
311
310
|
}
|
312
311
|
if (ignorePattern && ignorePattern.test(line) ||
|
@@ -93,9 +93,11 @@ module.exports = {
|
|
93
93
|
function enterStatement(node) {
|
94
94
|
const line = node.loc.start.line;
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
96
|
+
/*
|
97
|
+
* Skip to allow non-block statements if this is direct child of control statements.
|
98
|
+
* `if (a) foo();` is counted as 1.
|
99
|
+
* But `if (a) foo(); else foo();` should be counted as 2.
|
100
|
+
*/
|
99
101
|
if (SINGLE_CHILD_ALLOWED.test(node.parent.type) &&
|
100
102
|
node.parent.alternate !== node
|
101
103
|
) {
|
@@ -0,0 +1,294 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview enforce a particular style for multiline comments
|
3
|
+
* @author Teddy Katz
|
4
|
+
*/
|
5
|
+
"use strict";
|
6
|
+
|
7
|
+
const astUtils = require("../ast-utils");
|
8
|
+
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
// Rule Definition
|
11
|
+
//------------------------------------------------------------------------------
|
12
|
+
|
13
|
+
module.exports = {
|
14
|
+
meta: {
|
15
|
+
docs: {
|
16
|
+
description: "enforce a particular style for multiline comments",
|
17
|
+
category: "Stylistic Issues",
|
18
|
+
recommended: false
|
19
|
+
},
|
20
|
+
fixable: "whitespace",
|
21
|
+
schema: [{ enum: ["starred-block", "separate-lines", "bare-block"] }]
|
22
|
+
},
|
23
|
+
|
24
|
+
create(context) {
|
25
|
+
const sourceCode = context.getSourceCode();
|
26
|
+
const option = context.options[0] || "starred-block";
|
27
|
+
|
28
|
+
const EXPECTED_BLOCK_ERROR = "Expected a block comment instead of consecutive line comments.";
|
29
|
+
const START_NEWLINE_ERROR = "Expected a linebreak after '/*'.";
|
30
|
+
const END_NEWLINE_ERROR = "Expected a linebreak before '*/'.";
|
31
|
+
const MISSING_STAR_ERROR = "Expected a '*' at the start of this line.";
|
32
|
+
const ALIGNMENT_ERROR = "Expected this line to be aligned with the start of the comment.";
|
33
|
+
const EXPECTED_LINES_ERROR = "Expected multiple line comments instead of a block comment.";
|
34
|
+
|
35
|
+
//----------------------------------------------------------------------
|
36
|
+
// Helpers
|
37
|
+
//----------------------------------------------------------------------
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Gets a list of comment lines in a group
|
41
|
+
* @param {Token[]} commentGroup A group of comments, containing either multiple line comments or a single block comment
|
42
|
+
* @returns {string[]} A list of comment lines
|
43
|
+
*/
|
44
|
+
function getCommentLines(commentGroup) {
|
45
|
+
if (commentGroup[0].type === "Line") {
|
46
|
+
return commentGroup.map(comment => comment.value);
|
47
|
+
}
|
48
|
+
return commentGroup[0].value
|
49
|
+
.split(astUtils.LINEBREAK_MATCHER)
|
50
|
+
.map(line => line.replace(/^\s*\*?/, ""));
|
51
|
+
}
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Converts a comment into starred-block form
|
55
|
+
* @param {Token} firstComment The first comment of the group being converted
|
56
|
+
* @param {string[]} commentLinesList A list of lines to appear in the new starred-block comment
|
57
|
+
* @returns {string} A representation of the comment value in starred-block form, excluding start and end markers
|
58
|
+
*/
|
59
|
+
function convertToStarredBlock(firstComment, commentLinesList) {
|
60
|
+
const initialOffset = sourceCode.text.slice(firstComment.range[0] - firstComment.loc.start.column, firstComment.range[0]);
|
61
|
+
const starredLines = commentLinesList.map(line => `${initialOffset} *${line}`);
|
62
|
+
|
63
|
+
return `\n${starredLines.join("\n")}\n${initialOffset} `;
|
64
|
+
}
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Converts a comment into separate-line form
|
68
|
+
* @param {Token} firstComment The first comment of the group being converted
|
69
|
+
* @param {string[]} commentLinesList A list of lines to appear in the new starred-block comment
|
70
|
+
* @returns {string} A representation of the comment value in separate-line form
|
71
|
+
*/
|
72
|
+
function convertToSeparateLines(firstComment, commentLinesList) {
|
73
|
+
const initialOffset = sourceCode.text.slice(firstComment.range[0] - firstComment.loc.start.column, firstComment.range[0]);
|
74
|
+
const separateLines = commentLinesList.map(line => `// ${line.trim()}`);
|
75
|
+
|
76
|
+
return separateLines.join(`\n${initialOffset}`);
|
77
|
+
}
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Converts a comment into bare-block form
|
81
|
+
* @param {Token} firstComment The first comment of the group being converted
|
82
|
+
* @param {string[]} commentLinesList A list of lines to appear in the new starred-block comment
|
83
|
+
* @returns {string} A representation of the comment value in bare-block form
|
84
|
+
*/
|
85
|
+
function convertToBlock(firstComment, commentLinesList) {
|
86
|
+
const initialOffset = sourceCode.text.slice(firstComment.range[0] - firstComment.loc.start.column, firstComment.range[0]);
|
87
|
+
const blockLines = commentLinesList.map(line => line.trim());
|
88
|
+
|
89
|
+
return `/* ${blockLines.join(`\n${initialOffset} `)} */`;
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Check a comment is JSDoc form
|
94
|
+
* @param {Token[]} commentGroup A group of comments, containing either multiple line comments or a single block comment
|
95
|
+
* @returns {boolean} if commentGroup is JSDoc form, return true
|
96
|
+
*/
|
97
|
+
function isJSDoc(commentGroup) {
|
98
|
+
const lines = commentGroup[0].value.split(astUtils.LINEBREAK_MATCHER);
|
99
|
+
|
100
|
+
return commentGroup[0].type === "Block" &&
|
101
|
+
/^\*\s*$/.test(lines[0]) &&
|
102
|
+
lines.slice(1, -1).every(line => /^\s* /.test(line)) &&
|
103
|
+
/^\s*$/.test(lines[lines.length - 1]);
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Each method checks a group of comments to see if it's valid according to the given option.
|
108
|
+
* @param {Token[]} commentGroup A list of comments that appear together. This will either contain a single
|
109
|
+
* block comment or multiple line comments.
|
110
|
+
* @returns {void}
|
111
|
+
*/
|
112
|
+
const commentGroupCheckers = {
|
113
|
+
"starred-block"(commentGroup) {
|
114
|
+
const commentLines = getCommentLines(commentGroup);
|
115
|
+
|
116
|
+
if (commentLines.some(value => value.includes("*/"))) {
|
117
|
+
return;
|
118
|
+
}
|
119
|
+
|
120
|
+
if (commentGroup.length > 1) {
|
121
|
+
context.report({
|
122
|
+
loc: {
|
123
|
+
start: commentGroup[0].loc.start,
|
124
|
+
end: commentGroup[commentGroup.length - 1].loc.end
|
125
|
+
},
|
126
|
+
message: EXPECTED_BLOCK_ERROR,
|
127
|
+
fix(fixer) {
|
128
|
+
const range = [commentGroup[0].range[0], commentGroup[commentGroup.length - 1].range[1]];
|
129
|
+
const starredBlock = `/*${convertToStarredBlock(commentGroup[0], commentLines)}*/`;
|
130
|
+
|
131
|
+
return commentLines.some(value => value.startsWith("/"))
|
132
|
+
? null
|
133
|
+
: fixer.replaceTextRange(range, starredBlock);
|
134
|
+
}
|
135
|
+
});
|
136
|
+
} else {
|
137
|
+
const block = commentGroup[0];
|
138
|
+
const lines = block.value.split(astUtils.LINEBREAK_MATCHER);
|
139
|
+
const expectedLinePrefix = `${sourceCode.text.slice(block.range[0] - block.loc.start.column, block.range[0])} *`;
|
140
|
+
|
141
|
+
if (!/^\*?\s*$/.test(lines[0])) {
|
142
|
+
const start = block.value.startsWith("*") ? block.range[0] + 1 : block.range[0];
|
143
|
+
|
144
|
+
context.report({
|
145
|
+
loc: {
|
146
|
+
start: block.loc.start,
|
147
|
+
end: { line: block.loc.start.line, column: block.loc.start.column + 2 }
|
148
|
+
},
|
149
|
+
message: START_NEWLINE_ERROR,
|
150
|
+
fix: fixer => fixer.insertTextAfterRange([start, start + 2], `\n${expectedLinePrefix}`)
|
151
|
+
});
|
152
|
+
}
|
153
|
+
|
154
|
+
if (!/^\s*$/.test(lines[lines.length - 1])) {
|
155
|
+
context.report({
|
156
|
+
loc: {
|
157
|
+
start: { line: block.loc.end.line, column: block.loc.end.column - 2 },
|
158
|
+
end: block.loc.end
|
159
|
+
},
|
160
|
+
message: END_NEWLINE_ERROR,
|
161
|
+
fix: fixer => fixer.replaceTextRange([block.range[1] - 2, block.range[1]], `\n${expectedLinePrefix}/`)
|
162
|
+
});
|
163
|
+
}
|
164
|
+
|
165
|
+
for (let lineNumber = block.loc.start.line + 1; lineNumber <= block.loc.end.line; lineNumber++) {
|
166
|
+
const lineText = sourceCode.lines[lineNumber - 1];
|
167
|
+
|
168
|
+
if (!lineText.startsWith(expectedLinePrefix)) {
|
169
|
+
context.report({
|
170
|
+
loc: {
|
171
|
+
start: { line: lineNumber, column: 0 },
|
172
|
+
end: { line: lineNumber, column: sourceCode.lines[lineNumber - 1].length }
|
173
|
+
},
|
174
|
+
message: /^\s*\*/.test(lineText)
|
175
|
+
? ALIGNMENT_ERROR
|
176
|
+
: MISSING_STAR_ERROR,
|
177
|
+
fix(fixer) {
|
178
|
+
const lineStartIndex = sourceCode.getIndexFromLoc({ line: lineNumber, column: 0 });
|
179
|
+
const linePrefixLength = lineText.match(/^\s*\*? ?/)[0].length;
|
180
|
+
const commentStartIndex = lineStartIndex + linePrefixLength;
|
181
|
+
|
182
|
+
const replacementText = lineNumber === block.loc.end.line || lineText.length === linePrefixLength
|
183
|
+
? expectedLinePrefix
|
184
|
+
: `${expectedLinePrefix} `;
|
185
|
+
|
186
|
+
return fixer.replaceTextRange([lineStartIndex, commentStartIndex], replacementText);
|
187
|
+
}
|
188
|
+
});
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
},
|
193
|
+
"separate-lines"(commentGroup) {
|
194
|
+
if (!isJSDoc(commentGroup) && commentGroup[0].type === "Block") {
|
195
|
+
const commentLines = getCommentLines(commentGroup);
|
196
|
+
const block = commentGroup[0];
|
197
|
+
const tokenAfter = sourceCode.getTokenAfter(block, { includeComments: true });
|
198
|
+
|
199
|
+
if (tokenAfter && block.loc.end.line === tokenAfter.loc.start.line) {
|
200
|
+
return;
|
201
|
+
}
|
202
|
+
|
203
|
+
context.report({
|
204
|
+
loc: {
|
205
|
+
start: block.loc.start,
|
206
|
+
end: { line: block.loc.start.line, column: block.loc.start.column + 2 }
|
207
|
+
},
|
208
|
+
message: EXPECTED_LINES_ERROR,
|
209
|
+
fix(fixer) {
|
210
|
+
return fixer.replaceText(block, convertToSeparateLines(block, commentLines.filter(line => line)));
|
211
|
+
}
|
212
|
+
});
|
213
|
+
}
|
214
|
+
},
|
215
|
+
"bare-block"(commentGroup) {
|
216
|
+
if (!isJSDoc(commentGroup)) {
|
217
|
+
const commentLines = getCommentLines(commentGroup);
|
218
|
+
|
219
|
+
// disallows consecutive line comments in favor of using a block comment.
|
220
|
+
if (commentGroup[0].type === "Line" && commentLines.length > 1 &&
|
221
|
+
!commentLines.some(value => value.includes("*/"))) {
|
222
|
+
context.report({
|
223
|
+
loc: {
|
224
|
+
start: commentGroup[0].loc.start,
|
225
|
+
end: commentGroup[commentGroup.length - 1].loc.end
|
226
|
+
},
|
227
|
+
message: EXPECTED_BLOCK_ERROR,
|
228
|
+
fix(fixer) {
|
229
|
+
const range = [commentGroup[0].range[0], commentGroup[commentGroup.length - 1].range[1]];
|
230
|
+
const block = convertToBlock(commentGroup[0], commentLines.filter(line => line));
|
231
|
+
|
232
|
+
return fixer.replaceTextRange(range, block);
|
233
|
+
}
|
234
|
+
});
|
235
|
+
}
|
236
|
+
|
237
|
+
// prohibits block comments from having a * at the beginning of each line.
|
238
|
+
if (commentGroup[0].type === "Block") {
|
239
|
+
const block = commentGroup[0];
|
240
|
+
const lines = block.value.split(astUtils.LINEBREAK_MATCHER).filter(line => line.trim());
|
241
|
+
|
242
|
+
if (lines.length > 0 && lines.every(line => /^\s*\*/.test(line))) {
|
243
|
+
context.report({
|
244
|
+
loc: {
|
245
|
+
start: block.loc.start,
|
246
|
+
end: { line: block.loc.start.line, column: block.loc.start.column + 2 }
|
247
|
+
},
|
248
|
+
message: EXPECTED_BLOCK_ERROR,
|
249
|
+
fix(fixer) {
|
250
|
+
return fixer.replaceText(block, convertToBlock(block, commentLines.filter(line => line)));
|
251
|
+
}
|
252
|
+
});
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
257
|
+
};
|
258
|
+
|
259
|
+
//----------------------------------------------------------------------
|
260
|
+
// Public
|
261
|
+
//----------------------------------------------------------------------
|
262
|
+
|
263
|
+
return {
|
264
|
+
Program() {
|
265
|
+
return sourceCode.getAllComments()
|
266
|
+
.filter(comment => comment.type !== "Shebang")
|
267
|
+
.filter(comment => !astUtils.COMMENTS_IGNORE_PATTERN.test(comment.value))
|
268
|
+
.filter(comment => {
|
269
|
+
const tokenBefore = sourceCode.getTokenBefore(comment, { includeComments: true });
|
270
|
+
|
271
|
+
return !tokenBefore || tokenBefore.loc.end.line < comment.loc.start.line;
|
272
|
+
})
|
273
|
+
.reduce((commentGroups, comment, index, commentList) => {
|
274
|
+
const tokenBefore = sourceCode.getTokenBefore(comment, { includeComments: true });
|
275
|
+
|
276
|
+
if (
|
277
|
+
comment.type === "Line" &&
|
278
|
+
index && commentList[index - 1].type === "Line" &&
|
279
|
+
tokenBefore && tokenBefore.loc.end.line === comment.loc.start.line - 1 &&
|
280
|
+
tokenBefore === commentList[index - 1]
|
281
|
+
) {
|
282
|
+
commentGroups[commentGroups.length - 1].push(comment);
|
283
|
+
} else {
|
284
|
+
commentGroups.push([comment]);
|
285
|
+
}
|
286
|
+
|
287
|
+
return commentGroups;
|
288
|
+
}, [])
|
289
|
+
.filter(commentGroup => !(commentGroup.length === 1 && commentGroup[0].loc.start.line === commentGroup[0].loc.end.line))
|
290
|
+
.forEach(commentGroupCheckers[option]);
|
291
|
+
}
|
292
|
+
};
|
293
|
+
}
|
294
|
+
};
|
package/lib/rules/new-cap.js
CHANGED
@@ -132,10 +132,10 @@ module.exports = {
|
|
132
132
|
}
|
133
133
|
|
134
134
|
/**
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
135
|
+
* Gets the last line of a group of consecutive comments
|
136
|
+
* @param {number} commentStartLine The starting line of the group
|
137
|
+
* @returns {number} The number of the last comment line of the group
|
138
|
+
*/
|
139
139
|
function getLastCommentLineOfBlock(commentStartLine) {
|
140
140
|
const currentCommentEnd = commentEndLine[commentStartLine];
|
141
141
|
|
@@ -190,8 +190,10 @@ module.exports = {
|
|
190
190
|
return;
|
191
191
|
}
|
192
192
|
|
193
|
-
|
194
|
-
|
193
|
+
/*
|
194
|
+
* Some coding styles use multiple `var` statements, so do nothing if
|
195
|
+
* the next token is a `var` statement.
|
196
|
+
*/
|
195
197
|
if (nextToken.type === "Keyword" && isVar(nextToken.value)) {
|
196
198
|
return;
|
197
199
|
}
|
@@ -59,9 +59,11 @@ module.exports = {
|
|
59
59
|
|
60
60
|
if (parentType === "IfStatement") {
|
61
61
|
return isPrecededByTokens(node, ["else", ")"]);
|
62
|
-
}
|
62
|
+
}
|
63
|
+
if (parentType === "DoWhileStatement") {
|
63
64
|
return isPrecededByTokens(node, ["do"]);
|
64
|
-
}
|
65
|
+
}
|
66
|
+
if (parentType === "SwitchCase") {
|
65
67
|
return isPrecededByTokens(node, [":"]);
|
66
68
|
}
|
67
69
|
return isPrecededByTokens(node, [")"]);
|
@@ -164,13 +166,15 @@ module.exports = {
|
|
164
166
|
return true;
|
165
167
|
}
|
166
168
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
169
|
+
/*
|
170
|
+
* if the last leading comment ends in the same line as the previous token and
|
171
|
+
* does not share a line with the `return` node, we can consider it safe to fix.
|
172
|
+
* Example:
|
173
|
+
* function a() {
|
174
|
+
* var b; //comment
|
175
|
+
* return;
|
176
|
+
* }
|
177
|
+
*/
|
174
178
|
if (lastLeadingComment.loc.end.line === tokenBefore.loc.end.line &&
|
175
179
|
lastLeadingComment.loc.end.line !== node.loc.start.line) {
|
176
180
|
return true;
|