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
@@ -54,46 +54,67 @@ module.exports = {
|
|
54
54
|
allowPattern = new RegExp(options.allowPattern);
|
55
55
|
}
|
56
56
|
|
57
|
+
/**
|
58
|
+
* Check if the property is valid dot notation
|
59
|
+
* @param {ASTNode} node The dot notation node
|
60
|
+
* @param {string} value Value which is to be checked
|
61
|
+
* @returns {void}
|
62
|
+
*/
|
63
|
+
function checkComputedProperty(node, value) {
|
64
|
+
if (
|
65
|
+
validIdentifier.test(value) &&
|
66
|
+
(allowKeywords || keywords.indexOf(String(value)) === -1) &&
|
67
|
+
!(allowPattern && allowPattern.test(value))
|
68
|
+
) {
|
69
|
+
const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``;
|
70
|
+
|
71
|
+
context.report({
|
72
|
+
node: node.property,
|
73
|
+
message: "[{{propertyValue}}] is better written in dot notation.",
|
74
|
+
data: {
|
75
|
+
propertyValue: formattedValue
|
76
|
+
},
|
77
|
+
fix(fixer) {
|
78
|
+
const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);
|
79
|
+
const rightBracket = sourceCode.getLastToken(node);
|
80
|
+
|
81
|
+
if (sourceCode.getFirstTokenBetween(leftBracket, rightBracket, { includeComments: true, filter: astUtils.isCommentToken })) {
|
82
|
+
|
83
|
+
// Don't perform any fixes if there are comments inside the brackets.
|
84
|
+
return null;
|
85
|
+
}
|
86
|
+
|
87
|
+
const tokenAfterProperty = sourceCode.getTokenAfter(rightBracket);
|
88
|
+
const needsSpaceAfterProperty = tokenAfterProperty &&
|
89
|
+
rightBracket.range[1] === tokenAfterProperty.range[0] &&
|
90
|
+
!astUtils.canTokensBeAdjacent(String(value), tokenAfterProperty);
|
91
|
+
|
92
|
+
const textBeforeDot = astUtils.isDecimalInteger(node.object) ? " " : "";
|
93
|
+
const textAfterProperty = needsSpaceAfterProperty ? " " : "";
|
94
|
+
|
95
|
+
return fixer.replaceTextRange(
|
96
|
+
[leftBracket.range[0], rightBracket.range[1]],
|
97
|
+
`${textBeforeDot}.${value}${textAfterProperty}`
|
98
|
+
);
|
99
|
+
}
|
100
|
+
});
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
57
104
|
return {
|
58
105
|
MemberExpression(node) {
|
59
106
|
if (
|
60
107
|
node.computed &&
|
61
|
-
node.property.type === "Literal"
|
62
|
-
validIdentifier.test(node.property.value) &&
|
63
|
-
(allowKeywords || keywords.indexOf(String(node.property.value)) === -1)
|
108
|
+
node.property.type === "Literal"
|
64
109
|
) {
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);
|
74
|
-
const rightBracket = sourceCode.getLastToken(node);
|
75
|
-
|
76
|
-
if (sourceCode.getFirstTokenBetween(leftBracket, rightBracket, { includeComments: true, filter: astUtils.isCommentToken })) {
|
77
|
-
|
78
|
-
// Don't perform any fixes if there are comments inside the brackets.
|
79
|
-
return null;
|
80
|
-
}
|
81
|
-
|
82
|
-
const tokenAfterProperty = sourceCode.getTokenAfter(rightBracket);
|
83
|
-
const needsSpaceAfterProperty = tokenAfterProperty &&
|
84
|
-
rightBracket.range[1] === tokenAfterProperty.range[0] &&
|
85
|
-
!astUtils.canTokensBeAdjacent(String(node.property.value), tokenAfterProperty);
|
86
|
-
|
87
|
-
const textBeforeDot = astUtils.isDecimalInteger(node.object) ? " " : "";
|
88
|
-
const textAfterProperty = needsSpaceAfterProperty ? " " : "";
|
89
|
-
|
90
|
-
return fixer.replaceTextRange(
|
91
|
-
[leftBracket.range[0], rightBracket.range[1]],
|
92
|
-
`${textBeforeDot}.${node.property.value}${textAfterProperty}`
|
93
|
-
);
|
94
|
-
}
|
95
|
-
});
|
96
|
-
}
|
110
|
+
checkComputedProperty(node, node.property.value);
|
111
|
+
}
|
112
|
+
if (
|
113
|
+
node.computed &&
|
114
|
+
node.property.type === "TemplateLiteral" &&
|
115
|
+
node.property.expressions.length === 0
|
116
|
+
) {
|
117
|
+
checkComputedProperty(node, node.property.quasis[0].value.cooked);
|
97
118
|
}
|
98
119
|
if (
|
99
120
|
!allowKeywords &&
|
@@ -118,8 +118,10 @@ module.exports = {
|
|
118
118
|
message: "Unexpected space between function name and paren.",
|
119
119
|
fix(fixer) {
|
120
120
|
|
121
|
-
|
122
|
-
|
121
|
+
/*
|
122
|
+
* Only autofix if there is no newline
|
123
|
+
* https://github.com/eslint/eslint/issues/7787
|
124
|
+
*/
|
123
125
|
if (!hasNewline) {
|
124
126
|
return fixer.removeRange([prevToken.range[1], parenToken.range[0]]);
|
125
127
|
}
|
@@ -68,7 +68,7 @@ module.exports = {
|
|
68
68
|
|
69
69
|
/**
|
70
70
|
* Returns resolved option definitions based on an option and defaults
|
71
|
-
*
|
71
|
+
*
|
72
72
|
* @param {any} option - The option object or string value
|
73
73
|
* @param {Object} defaults - The defaults to use if options are not present
|
74
74
|
* @returns {Object} the resolved object definition
|
@@ -121,7 +121,7 @@ module.exports = {
|
|
121
121
|
|
122
122
|
/**
|
123
123
|
* Checks the spacing between two tokens before or after the star token.
|
124
|
-
*
|
124
|
+
*
|
125
125
|
* @param {string} kind Either "named", "anonymous", or "method"
|
126
126
|
* @param {string} side Either "before" or "after".
|
127
127
|
* @param {Token} leftToken `function` keyword token if side is "before", or
|
@@ -161,7 +161,7 @@ module.exports = {
|
|
161
161
|
|
162
162
|
/**
|
163
163
|
* Enforces the spacing around the star if node is a generator function.
|
164
|
-
*
|
164
|
+
*
|
165
165
|
* @param {ASTNode} node A function expression or declaration node.
|
166
166
|
* @returns {void}
|
167
167
|
*/
|
@@ -102,7 +102,8 @@ module.exports = {
|
|
102
102
|
}
|
103
103
|
}
|
104
104
|
|
105
|
-
/**
|
105
|
+
/**
|
106
|
+
* Checks whether a node means a getter function.
|
106
107
|
* @param {ASTNode} node - a node to check.
|
107
108
|
* @returns {boolean} if node means a getter, return true; else return false.
|
108
109
|
*/
|
@@ -274,8 +274,10 @@ module.exports = {
|
|
274
274
|
foundStatement = `${actualSpaces} ${foundSpacesWord} and ${actualTabs} ${foundTabsWord}`; // e.g. "1 space and 2 tabs"
|
275
275
|
} else if (actualSpaces > 0) {
|
276
276
|
|
277
|
-
|
278
|
-
|
277
|
+
/*
|
278
|
+
* Abbreviate the message if the expected indentation is also spaces.
|
279
|
+
* e.g. 'Expected 4 spaces but found 2' rather than 'Expected 4 spaces but found 2 spaces'
|
280
|
+
*/
|
279
281
|
foundStatement = indentType === "space" ? actualSpaces : `${actualSpaces} ${foundSpacesWord}`;
|
280
282
|
} else if (actualTabs > 0) {
|
281
283
|
foundStatement = indentType === "tab" ? actualTabs : `${actualTabs} ${foundTabsWord}`;
|
@@ -323,8 +325,8 @@ module.exports = {
|
|
323
325
|
* @param {ASTNode|Token} node Node to examine
|
324
326
|
* @param {boolean} [byLastLine=false] get indent of node's last line
|
325
327
|
* @returns {Object} The node's indent. Contains keys `space` and `tab`, representing the indent of each character. Also
|
326
|
-
contains keys `goodChar` and `badChar`, where `goodChar` is the amount of the user's desired indentation character, and
|
327
|
-
`badChar` is the amount of the other indentation character.
|
328
|
+
* contains keys `goodChar` and `badChar`, where `goodChar` is the amount of the user's desired indentation character, and
|
329
|
+
* `badChar` is the amount of the other indentation character.
|
328
330
|
*/
|
329
331
|
function getNodeIndent(node, byLastLine) {
|
330
332
|
const token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node);
|
@@ -445,8 +447,10 @@ module.exports = {
|
|
445
447
|
*/
|
446
448
|
function checkLastReturnStatementLineIndent(node, firstLineIndent) {
|
447
449
|
|
448
|
-
|
449
|
-
|
450
|
+
/*
|
451
|
+
* in case if return statement ends with ');' we have traverse back to ')'
|
452
|
+
* otherwise we'll measure indent for ';' and replace ')'
|
453
|
+
*/
|
450
454
|
const lastToken = sourceCode.getLastToken(node, astUtils.isClosingParenToken);
|
451
455
|
const textBeforeClosingParenthesis = sourceCode.getText(lastToken, lastToken.loc.start.column).slice(0, -1);
|
452
456
|
|
@@ -645,8 +649,10 @@ module.exports = {
|
|
645
649
|
}
|
646
650
|
}
|
647
651
|
|
648
|
-
|
649
|
-
|
652
|
+
/*
|
653
|
+
* function body indent should be indent + indent size, unless this
|
654
|
+
* is a FunctionDeclaration, FunctionExpression, or outer IIFE and the corresponding options are enabled.
|
655
|
+
*/
|
650
656
|
let functionOffset = indentSize;
|
651
657
|
|
652
658
|
if (options.outerIIFEBody !== null && isOuterIIFE(calleeNode)) {
|
@@ -733,7 +739,9 @@ module.exports = {
|
|
733
739
|
} else if (parent.type === "ObjectExpression" || parent.type === "ArrayExpression") {
|
734
740
|
const parentElements = node.parent.type === "ObjectExpression" ? node.parent.properties : node.parent.elements;
|
735
741
|
|
736
|
-
if (parentElements[0] &&
|
742
|
+
if (parentElements[0] &&
|
743
|
+
parentElements[0].loc.start.line === parent.loc.start.line &&
|
744
|
+
parentElements[0].loc.end.line !== parent.loc.start.line) {
|
737
745
|
|
738
746
|
/*
|
739
747
|
* If the first element of the array spans multiple lines, don't increase the expected indentation of the rest.
|
@@ -797,7 +805,8 @@ module.exports = {
|
|
797
805
|
}
|
798
806
|
}
|
799
807
|
|
800
|
-
checkLastNodeLineIndent(node, nodeIndent +
|
808
|
+
checkLastNodeLineIndent(node, nodeIndent +
|
809
|
+
(isNodeInVarOnTop(node, parentVarNode) ? options.VariableDeclarator[parentVarNode.parent.kind] * indentSize : 0));
|
801
810
|
}
|
802
811
|
|
803
812
|
/**
|
@@ -1024,10 +1033,12 @@ module.exports = {
|
|
1024
1033
|
return;
|
1025
1034
|
}
|
1026
1035
|
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1036
|
+
/*
|
1037
|
+
* The typical layout of variable declarations and assignments
|
1038
|
+
* alter the expectation of correct indentation. Skip them.
|
1039
|
+
* TODO: Add appropriate configuration options for variable
|
1040
|
+
* declarations and assignments.
|
1041
|
+
*/
|
1031
1042
|
if (getParentNodeByType(node, "VariableDeclarator", ["FunctionExpression", "ArrowFunctionExpression"])) {
|
1032
1043
|
return;
|
1033
1044
|
}
|
package/lib/rules/indent.js
CHANGED
@@ -200,19 +200,19 @@ class TokenInfo {
|
|
200
200
|
}
|
201
201
|
|
202
202
|
/**
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
203
|
+
* Gets the first token on a given token's line
|
204
|
+
* @param {Token|ASTNode} token a node or token
|
205
|
+
* @returns {Token} The first token on the given line
|
206
|
+
*/
|
207
207
|
getFirstTokenOfLine(token) {
|
208
208
|
return this.firstTokensByLineNumber.get(token.loc.start.line);
|
209
209
|
}
|
210
210
|
|
211
211
|
/**
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
212
|
+
* Determines whether a token is the first token in its line
|
213
|
+
* @param {Token} token The token
|
214
|
+
* @returns {boolean} `true` if the token is the first on its line
|
215
|
+
*/
|
216
216
|
isFirstTokenOfLine(token) {
|
217
217
|
return this.getFirstTokenOfLine(token) === token;
|
218
218
|
}
|
@@ -235,10 +235,12 @@ class OffsetStorage {
|
|
235
235
|
/**
|
236
236
|
* @param {TokenInfo} tokenInfo a TokenInfo instance
|
237
237
|
* @param {number} indentSize The desired size of each indentation level
|
238
|
+
* @param {string} indentType The indentation character
|
238
239
|
*/
|
239
|
-
constructor(tokenInfo, indentSize) {
|
240
|
+
constructor(tokenInfo, indentSize, indentType) {
|
240
241
|
this._tokenInfo = tokenInfo;
|
241
242
|
this._indentSize = indentSize;
|
243
|
+
this._indentType = indentType;
|
242
244
|
|
243
245
|
this._tree = new BinarySearchTree();
|
244
246
|
this._tree.insert(0, { offset: 0, from: null, force: false });
|
@@ -334,31 +336,31 @@ class OffsetStorage {
|
|
334
336
|
}
|
335
337
|
|
336
338
|
/**
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
339
|
+
* Sets the desired offset of all tokens in a range
|
340
|
+
* It's common for node listeners in this file to need to apply the same offset to a large, contiguous range of tokens.
|
341
|
+
* Moreover, the offset of any given token is usually updated multiple times (roughly once for each node that contains
|
342
|
+
* it). This means that the offset of each token is updated O(AST depth) times.
|
343
|
+
* It would not be performant to store and update the offsets for each token independently, because the rule would end
|
344
|
+
* up having a time complexity of O(number of tokens * AST depth), which is quite slow for large files.
|
345
|
+
*
|
346
|
+
* Instead, the offset tree is represented as a collection of contiguous offset ranges in a file. For example, the following
|
347
|
+
* list could represent the state of the offset tree at a given point:
|
348
|
+
*
|
349
|
+
* * Tokens starting in the interval [0, 15) are aligned with the beginning of the file
|
350
|
+
* * Tokens starting in the interval [15, 30) are offset by 1 indent level from the `bar` token
|
351
|
+
* * Tokens starting in the interval [30, 43) are offset by 1 indent level from the `foo` token
|
352
|
+
* * Tokens starting in the interval [43, 820) are offset by 2 indent levels from the `bar` token
|
353
|
+
* * Tokens starting in the interval [820, ∞) are offset by 1 indent level from the `baz` token
|
354
|
+
*
|
355
|
+
* The `setDesiredOffsets` methods inserts ranges like the ones above. The third line above would be inserted by using:
|
356
|
+
* `setDesiredOffsets([30, 43], fooToken, 1);`
|
357
|
+
*
|
358
|
+
* @param {[number, number]} range A [start, end] pair. All tokens with range[0] <= token.start < range[1] will have the offset applied.
|
359
|
+
* @param {Token} fromToken The token that this is offset from
|
360
|
+
* @param {number} offset The desired indent level
|
361
|
+
* @param {boolean} force `true` if this offset should not use the normal collapsing behavior. This should almost always be false.
|
362
|
+
* @returns {void}
|
363
|
+
*/
|
362
364
|
setDesiredOffsets(range, fromToken, offset, force) {
|
363
365
|
|
364
366
|
/*
|
@@ -406,18 +408,23 @@ class OffsetStorage {
|
|
406
408
|
}
|
407
409
|
|
408
410
|
/**
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
411
|
+
* Gets the desired indent of a token
|
412
|
+
* @param {Token} token The token
|
413
|
+
* @returns {string} The desired indent of the token
|
414
|
+
*/
|
413
415
|
getDesiredIndent(token) {
|
414
416
|
if (!this._desiredIndentCache.has(token)) {
|
415
417
|
|
416
418
|
if (this._ignoredTokens.has(token)) {
|
417
419
|
|
418
|
-
|
419
|
-
|
420
|
-
|
420
|
+
/*
|
421
|
+
* If the token is ignored, use the actual indent of the token as the desired indent.
|
422
|
+
* This ensures that no errors are reported for this token.
|
423
|
+
*/
|
424
|
+
this._desiredIndentCache.set(
|
425
|
+
token,
|
426
|
+
this._tokenInfo.getTokenIndent(token)
|
427
|
+
);
|
421
428
|
} else if (this._lockedFirstTokens.has(token)) {
|
422
429
|
const firstToken = this._lockedFirstTokens.get(token);
|
423
430
|
|
@@ -428,7 +435,7 @@ class OffsetStorage {
|
|
428
435
|
this.getDesiredIndent(this._tokenInfo.getFirstTokenOfLine(firstToken)) +
|
429
436
|
|
430
437
|
// (space between the start of the first element's line and the first element)
|
431
|
-
(firstToken.loc.start.column - this._tokenInfo.getFirstTokenOfLine(firstToken).loc.start.column)
|
438
|
+
this._indentType.repeat(firstToken.loc.start.column - this._tokenInfo.getFirstTokenOfLine(firstToken).loc.start.column)
|
432
439
|
);
|
433
440
|
} else {
|
434
441
|
const offsetInfo = this._getOffsetDescriptor(token);
|
@@ -436,19 +443,22 @@ class OffsetStorage {
|
|
436
443
|
offsetInfo.from &&
|
437
444
|
offsetInfo.from.loc.start.line === token.loc.start.line &&
|
438
445
|
!offsetInfo.force
|
439
|
-
) ? 0 : offsetInfo.offset;
|
446
|
+
) ? 0 : offsetInfo.offset * this._indentSize;
|
440
447
|
|
441
|
-
this._desiredIndentCache.set(
|
448
|
+
this._desiredIndentCache.set(
|
449
|
+
token,
|
450
|
+
(offsetInfo.from ? this.getDesiredIndent(offsetInfo.from) : "") + this._indentType.repeat(offset)
|
451
|
+
);
|
442
452
|
}
|
443
453
|
}
|
444
454
|
return this._desiredIndentCache.get(token);
|
445
455
|
}
|
446
456
|
|
447
457
|
/**
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
458
|
+
* Ignores a token, preventing it from being reported.
|
459
|
+
* @param {Token} token The token
|
460
|
+
* @returns {void}
|
461
|
+
*/
|
452
462
|
ignoreToken(token) {
|
453
463
|
if (this._tokenInfo.isFirstTokenOfLine(token)) {
|
454
464
|
this._ignoredTokens.add(token);
|
@@ -655,7 +665,7 @@ module.exports = {
|
|
655
665
|
|
656
666
|
const sourceCode = context.getSourceCode();
|
657
667
|
const tokenInfo = new TokenInfo(sourceCode);
|
658
|
-
const offsets = new OffsetStorage(tokenInfo, indentSize);
|
668
|
+
const offsets = new OffsetStorage(tokenInfo, indentSize, indentType === "space" ? " " : "\t");
|
659
669
|
const parameterParens = new WeakSet();
|
660
670
|
|
661
671
|
/**
|
@@ -673,8 +683,10 @@ module.exports = {
|
|
673
683
|
|
674
684
|
if (actualSpaces > 0) {
|
675
685
|
|
676
|
-
|
677
|
-
|
686
|
+
/*
|
687
|
+
* Abbreviate the message if the expected indentation is also spaces.
|
688
|
+
* e.g. 'Expected 4 spaces but found 2' rather than 'Expected 4 spaces but found 2 spaces'
|
689
|
+
*/
|
678
690
|
foundStatement = indentType === "space" ? actualSpaces : `${actualSpaces} ${foundSpacesWord}`;
|
679
691
|
} else if (actualTabs > 0) {
|
680
692
|
foundStatement = indentType === "tab" ? actualTabs : `${actualTabs} ${foundTabsWord}`;
|
@@ -688,27 +700,24 @@ module.exports = {
|
|
688
700
|
/**
|
689
701
|
* Reports a given indent violation
|
690
702
|
* @param {Token} token Token violating the indent rule
|
691
|
-
* @param {
|
692
|
-
* @param {int} gottenSpaces Actual number of indentation spaces for the token
|
693
|
-
* @param {int} gottenTabs Actual number of indentation tabs for the token
|
703
|
+
* @param {string} neededIndent Expected indentation string
|
694
704
|
* @returns {void}
|
695
705
|
*/
|
696
|
-
function report(token,
|
706
|
+
function report(token, neededIndent) {
|
697
707
|
const actualIndent = Array.from(tokenInfo.getTokenIndent(token));
|
698
708
|
const numSpaces = actualIndent.filter(char => char === " ").length;
|
699
709
|
const numTabs = actualIndent.filter(char => char === "\t").length;
|
700
|
-
const neededChars = neededIndentLevel * indentSize;
|
701
710
|
|
702
711
|
context.report({
|
703
712
|
node: token,
|
704
|
-
message: createErrorMessage(
|
713
|
+
message: createErrorMessage(neededIndent.length, numSpaces, numTabs),
|
705
714
|
loc: {
|
706
715
|
start: { line: token.loc.start.line, column: 0 },
|
707
716
|
end: { line: token.loc.start.line, column: token.loc.start.column }
|
708
717
|
},
|
709
718
|
fix(fixer) {
|
710
719
|
const range = [token.range[0] - token.loc.start.column, token.range[0]];
|
711
|
-
const newText =
|
720
|
+
const newText = neededIndent;
|
712
721
|
|
713
722
|
return fixer.replaceTextRange(range, newText);
|
714
723
|
}
|
@@ -718,14 +727,13 @@ module.exports = {
|
|
718
727
|
/**
|
719
728
|
* Checks if a token's indentation is correct
|
720
729
|
* @param {Token} token Token to examine
|
721
|
-
* @param {
|
730
|
+
* @param {string} desiredIndent Desired indentation of the string
|
722
731
|
* @returns {boolean} `true` if the token's indentation is correct
|
723
732
|
*/
|
724
|
-
function validateTokenIndent(token,
|
733
|
+
function validateTokenIndent(token, desiredIndent) {
|
725
734
|
const indentation = tokenInfo.getTokenIndent(token);
|
726
|
-
const expectedChar = indentType === "space" ? " " : "\t";
|
727
735
|
|
728
|
-
return indentation ===
|
736
|
+
return indentation === desiredIndent ||
|
729
737
|
|
730
738
|
// To avoid conflicts with no-mixed-spaces-and-tabs, don't report mixed spaces and tabs.
|
731
739
|
indentation.includes(" ") && indentation.includes("\t");
|
@@ -766,20 +774,20 @@ module.exports = {
|
|
766
774
|
}
|
767
775
|
|
768
776
|
/**
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
777
|
+
* Check indentation for lists of elements (arrays, objects, function params)
|
778
|
+
* @param {ASTNode[]} elements List of elements that should be offset
|
779
|
+
* @param {Token} startToken The start token of the list that element should be aligned against, e.g. '['
|
780
|
+
* @param {Token} endToken The end token of the list, e.g. ']'
|
781
|
+
* @param {number|string} offset The amount that the elements should be offset
|
782
|
+
* @returns {void}
|
783
|
+
*/
|
776
784
|
function addElementListIndent(elements, startToken, endToken, offset) {
|
777
785
|
|
778
786
|
/**
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
787
|
+
* Gets the first token of a given element, including surrounding parentheses.
|
788
|
+
* @param {ASTNode} element A node in the `elements` list
|
789
|
+
* @returns {Token} The first token of this element
|
790
|
+
*/
|
783
791
|
function getFirstToken(element) {
|
784
792
|
let token = sourceCode.getTokenBefore(element);
|
785
793
|
|
@@ -868,10 +876,10 @@ module.exports = {
|
|
868
876
|
}
|
869
877
|
|
870
878
|
/**
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
879
|
+
* Checks the indentation for nodes that are like function calls (`CallExpression` and `NewExpression`)
|
880
|
+
* @param {ASTNode} node A CallExpression or NewExpression node
|
881
|
+
* @returns {void}
|
882
|
+
*/
|
875
883
|
function addFunctionCallIndent(node) {
|
876
884
|
let openingParen;
|
877
885
|
|
@@ -890,10 +898,10 @@ module.exports = {
|
|
890
898
|
}
|
891
899
|
|
892
900
|
/**
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
901
|
+
* Checks the indentation of parenthesized values, given a list of tokens in a program
|
902
|
+
* @param {Token[]} tokens A list of tokens
|
903
|
+
* @returns {void}
|
904
|
+
*/
|
897
905
|
function addParensIndent(tokens) {
|
898
906
|
const parenStack = [];
|
899
907
|
const parenPairs = [];
|
@@ -928,11 +936,11 @@ module.exports = {
|
|
928
936
|
}
|
929
937
|
|
930
938
|
/**
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
939
|
+
* Ignore all tokens within an unknown node whose offset do not depend
|
940
|
+
* on another token's offset within the unknown node
|
941
|
+
* @param {ASTNode} node Unknown Node
|
942
|
+
* @returns {void}
|
943
|
+
*/
|
936
944
|
function ignoreNode(node) {
|
937
945
|
const unknownNodeTokens = new Set(sourceCode.getTokens(node, { includeComments: true }));
|
938
946
|
|
@@ -1019,10 +1027,10 @@ module.exports = {
|
|
1019
1027
|
const operator = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
|
1020
1028
|
|
1021
1029
|
/*
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1030
|
+
* For backwards compatibility, don't check BinaryExpression indents, e.g.
|
1031
|
+
* var foo = bar &&
|
1032
|
+
* baz;
|
1033
|
+
*/
|
1026
1034
|
|
1027
1035
|
const tokenAfterOperator = sourceCode.getTokenAfter(operator);
|
1028
1036
|
|
@@ -1241,7 +1249,9 @@ module.exports = {
|
|
1241
1249
|
NewExpression(node) {
|
1242
1250
|
|
1243
1251
|
// Only indent the arguments if the NewExpression has parens (e.g. `new Foo(bar)` or `new Foo()`, but not `new Foo`
|
1244
|
-
if (node.arguments.length > 0 ||
|
1252
|
+
if (node.arguments.length > 0 ||
|
1253
|
+
astUtils.isClosingParenToken(sourceCode.getLastToken(node)) &&
|
1254
|
+
astUtils.isOpeningParenToken(sourceCode.getLastToken(node, 1))) {
|
1245
1255
|
addFunctionCallIndent(node);
|
1246
1256
|
}
|
1247
1257
|
},
|
package/lib/rules/key-spacing.js
CHANGED
@@ -329,9 +329,11 @@ module.exports = {
|
|
329
329
|
return true;
|
330
330
|
}
|
331
331
|
|
332
|
-
|
333
|
-
|
334
|
-
|
332
|
+
/*
|
333
|
+
* Check that the first comment is adjacent to the end of the group, the
|
334
|
+
* last comment is adjacent to the candidate property, and that successive
|
335
|
+
* comments are adjacent to each other.
|
336
|
+
*/
|
335
337
|
const leadingComments = sourceCode.getCommentsBefore(candidate);
|
336
338
|
|
337
339
|
if (
|