eslint 3.15.0 → 3.16.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 +32 -0
- package/conf/{eslint.json → eslint-recommended.js} +85 -71
- package/lib/ast-utils.js +185 -19
- package/lib/code-path-analysis/code-path-state.js +2 -2
- package/lib/config/autoconfig.js +3 -3
- package/lib/config/config-file.js +14 -7
- package/lib/config/config-initializer.js +1 -1
- package/lib/config.js +3 -2
- package/lib/eslint.js +4 -4
- package/lib/rules/arrow-body-style.js +7 -4
- package/lib/rules/arrow-spacing.js +7 -6
- package/lib/rules/block-spacing.js +2 -2
- package/lib/rules/brace-style.js +2 -6
- package/lib/rules/capitalized-comments.js +6 -6
- package/lib/rules/comma-spacing.js +3 -3
- package/lib/rules/consistent-return.js +1 -1
- package/lib/rules/constructor-super.js +3 -3
- package/lib/rules/curly.js +11 -7
- package/lib/rules/default-case.js +3 -3
- package/lib/rules/eqeqeq.js +15 -6
- package/lib/rules/func-call-spacing.js +10 -13
- package/lib/rules/generator-star-spacing.js +18 -19
- package/lib/rules/id-blacklist.js +2 -2
- package/lib/rules/id-length.js +3 -3
- package/lib/rules/id-match.js +2 -2
- package/lib/rules/indent.js +7 -6
- package/lib/rules/key-spacing.js +12 -16
- package/lib/rules/keyword-spacing.js +2 -13
- package/lib/rules/line-comment-position.js +1 -1
- package/lib/rules/linebreak-style.js +7 -1
- package/lib/rules/lines-around-comment.js +4 -4
- package/lib/rules/lines-around-directive.js +3 -3
- package/lib/rules/max-lines.js +2 -2
- package/lib/rules/max-statements-per-line.js +7 -6
- package/lib/rules/newline-after-var.js +7 -2
- package/lib/rules/newline-per-chained-call.js +3 -1
- package/lib/rules/no-cond-assign.js +3 -3
- package/lib/rules/no-extend-native.js +3 -3
- package/lib/rules/no-extra-bind.js +3 -4
- package/lib/rules/no-extra-boolean-cast.js +8 -0
- package/lib/rules/no-extra-parens.js +1 -2
- package/lib/rules/no-inner-declarations.js +4 -4
- package/lib/rules/no-irregular-whitespace.js +7 -1
- package/lib/rules/no-lone-blocks.js +10 -10
- package/lib/rules/no-mixed-operators.js +1 -7
- package/lib/rules/no-multi-spaces.js +4 -1
- package/lib/rules/no-multi-str.js +7 -3
- package/lib/rules/no-return-assign.js +7 -14
- package/lib/rules/no-sequences.js +7 -6
- package/lib/rules/no-trailing-spaces.js +8 -2
- package/lib/rules/no-undefined.js +45 -6
- package/lib/rules/no-unexpected-multiline.js +9 -8
- package/lib/rules/no-unneeded-ternary.js +5 -1
- package/lib/rules/no-unused-labels.js +17 -2
- package/lib/rules/no-unused-vars.js +2 -16
- package/lib/rules/no-useless-computed-key.js +8 -3
- package/lib/rules/no-useless-concat.js +10 -7
- package/lib/rules/no-useless-escape.js +1 -1
- package/lib/rules/no-useless-return.js +1 -7
- package/lib/rules/no-var.js +1 -3
- package/lib/rules/no-whitespace-before-property.js +5 -16
- package/lib/rules/object-curly-newline.js +2 -2
- package/lib/rules/object-curly-spacing.js +7 -25
- package/lib/rules/object-property-newline.js +3 -3
- package/lib/rules/object-shorthand.js +2 -2
- package/lib/rules/operator-assignment.js +1 -1
- package/lib/rules/operator-linebreak.js +8 -10
- package/lib/rules/padded-blocks.js +4 -4
- package/lib/rules/prefer-spread.js +1 -1
- package/lib/rules/prefer-template.js +1 -1
- package/lib/rules/quotes.js +10 -6
- package/lib/rules/semi-spacing.js +4 -0
- package/lib/rules/space-before-function-paren.js +8 -5
- package/lib/rules/spaced-comment.js +2 -2
- package/lib/rules/strict.js +2 -2
- package/lib/rules/unicode-bom.js +1 -1
- package/lib/rules/wrap-iife.js +5 -5
- package/lib/rules/yoda.js +2 -7
- package/lib/testers/rule-tester.js +13 -6
- package/lib/token-store/backward-token-comment-cursor.js +57 -0
- package/lib/token-store/backward-token-cursor.js +56 -0
- package/lib/token-store/cursor.js +76 -0
- package/lib/token-store/cursors.js +92 -0
- package/lib/token-store/decorative-cursor.js +39 -0
- package/lib/token-store/filter-cursor.js +43 -0
- package/lib/token-store/forward-token-comment-cursor.js +57 -0
- package/lib/token-store/forward-token-cursor.js +61 -0
- package/lib/token-store/index.js +604 -0
- package/lib/token-store/limit-cursor.js +40 -0
- package/lib/token-store/padded-token-cursor.js +38 -0
- package/lib/token-store/skip-cursor.js +42 -0
- package/lib/token-store/utils.js +100 -0
- package/lib/util/source-code-fixer.js +35 -39
- package/lib/util/source-code.js +31 -15
- package/messages/extend-config-missing.txt +3 -0
- package/package.json +2 -2
- package/lib/token-store.js +0 -203
@@ -128,8 +128,8 @@ module.exports = {
|
|
128
128
|
const options = normalizedOptions[node.type];
|
129
129
|
const openBrace = sourceCode.getFirstToken(node);
|
130
130
|
const closeBrace = sourceCode.getLastToken(node);
|
131
|
-
let first = sourceCode.
|
132
|
-
let last = sourceCode.
|
131
|
+
let first = sourceCode.getTokenAfter(openBrace, { includeComments: true });
|
132
|
+
let last = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
|
133
133
|
const needsLinebreaks = (
|
134
134
|
node.properties.length >= options.minProperties ||
|
135
135
|
(
|
@@ -206,14 +206,8 @@ module.exports = {
|
|
206
206
|
*/
|
207
207
|
function getClosingBraceOfObject(node) {
|
208
208
|
const lastProperty = node.properties[node.properties.length - 1];
|
209
|
-
let token = sourceCode.getTokenAfter(lastProperty);
|
210
209
|
|
211
|
-
|
212
|
-
while (token.type !== "Punctuator" || token.value !== "}") {
|
213
|
-
token = sourceCode.getTokenAfter(token);
|
214
|
-
}
|
215
|
-
|
216
|
-
return token;
|
210
|
+
return sourceCode.getTokenAfter(lastProperty, astUtils.isClosingBraceToken);
|
217
211
|
}
|
218
212
|
|
219
213
|
/**
|
@@ -254,15 +248,9 @@ module.exports = {
|
|
254
248
|
firstSpecifier = node.specifiers[1];
|
255
249
|
}
|
256
250
|
|
257
|
-
const first = sourceCode.getTokenBefore(firstSpecifier)
|
258
|
-
|
259
|
-
|
260
|
-
// to support a trailing comma.
|
261
|
-
if (last.value === ",") {
|
262
|
-
last = sourceCode.getTokenAfter(last);
|
263
|
-
}
|
264
|
-
|
265
|
-
const second = sourceCode.getTokenAfter(first),
|
251
|
+
const first = sourceCode.getTokenBefore(firstSpecifier),
|
252
|
+
last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
|
253
|
+
second = sourceCode.getTokenAfter(first),
|
266
254
|
penultimate = sourceCode.getTokenBefore(last);
|
267
255
|
|
268
256
|
validateBraceSpacing(node, first, second, penultimate, last);
|
@@ -280,15 +268,9 @@ module.exports = {
|
|
280
268
|
|
281
269
|
const firstSpecifier = node.specifiers[0],
|
282
270
|
lastSpecifier = node.specifiers[node.specifiers.length - 1],
|
283
|
-
first = sourceCode.getTokenBefore(firstSpecifier)
|
284
|
-
|
285
|
-
|
286
|
-
// to support a trailing comma.
|
287
|
-
if (last.value === ",") {
|
288
|
-
last = sourceCode.getTokenAfter(last);
|
289
|
-
}
|
290
|
-
|
291
|
-
const second = sourceCode.getTokenAfter(first),
|
271
|
+
first = sourceCode.getTokenBefore(firstSpecifier),
|
272
|
+
last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
|
273
|
+
second = sourceCode.getTokenAfter(first),
|
292
274
|
penultimate = sourceCode.getTokenBefore(last);
|
293
275
|
|
294
276
|
validateBraceSpacing(node, first, second, penultimate, last);
|
@@ -34,9 +34,9 @@ module.exports = {
|
|
34
34
|
|
35
35
|
create(context) {
|
36
36
|
const allowSameLine = context.options[0] && Boolean(context.options[0].allowMultiplePropertiesPerLine);
|
37
|
-
const errorMessage = allowSameLine
|
38
|
-
"Object properties must go on a new line if they aren't all on the same line."
|
39
|
-
"Object properties must go on a new line.";
|
37
|
+
const errorMessage = allowSameLine
|
38
|
+
? "Object properties must go on a new line if they aren't all on the same line."
|
39
|
+
: "Object properties must go on a new line.";
|
40
40
|
|
41
41
|
const sourceCode = context.getSourceCode();
|
42
42
|
|
@@ -215,8 +215,8 @@ module.exports = {
|
|
215
215
|
* @returns {Object} A fix for this node
|
216
216
|
*/
|
217
217
|
function makeFunctionShorthand(fixer, node) {
|
218
|
-
const firstKeyToken = node.computed ? sourceCode.
|
219
|
-
const lastKeyToken = node.computed ? sourceCode.
|
218
|
+
const firstKeyToken = node.computed ? sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken) : sourceCode.getFirstToken(node.key);
|
219
|
+
const lastKeyToken = node.computed ? sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken) : sourceCode.getLastToken(node.key);
|
220
220
|
const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
|
221
221
|
let keyPrefix = "";
|
222
222
|
|
@@ -108,7 +108,7 @@ module.exports = {
|
|
108
108
|
* @returns {Token} The operator token in the node
|
109
109
|
*/
|
110
110
|
function getOperatorToken(node) {
|
111
|
-
return sourceCode.
|
111
|
+
return sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
|
112
112
|
}
|
113
113
|
|
114
114
|
/**
|
@@ -5,14 +5,16 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
8
12
|
const astUtils = require("../ast-utils");
|
9
13
|
|
10
14
|
//------------------------------------------------------------------------------
|
11
15
|
// Rule Definition
|
12
16
|
//------------------------------------------------------------------------------
|
13
17
|
|
14
|
-
const LINEBREAK_REGEX = /\r\n|\r|\n|\u2028|\u2029/g;
|
15
|
-
|
16
18
|
module.exports = {
|
17
19
|
meta: {
|
18
20
|
docs: {
|
@@ -85,7 +87,7 @@ module.exports = {
|
|
85
87
|
if (hasLinebreakBefore !== hasLinebreakAfter && desiredStyle !== "none") {
|
86
88
|
|
87
89
|
// If there is a comment before and after the operator, don't do a fix.
|
88
|
-
if (sourceCode.
|
90
|
+
if (sourceCode.getTokenBefore(operatorToken, { includeComments: true }) !== tokenBefore && sourceCode.getTokenAfter(operatorToken, { includeComments: true }) !== tokenAfter) {
|
89
91
|
return null;
|
90
92
|
}
|
91
93
|
|
@@ -100,6 +102,7 @@ module.exports = {
|
|
100
102
|
newTextBefore = textAfter;
|
101
103
|
newTextAfter = textBefore;
|
102
104
|
} else {
|
105
|
+
const LINEBREAK_REGEX = astUtils.createGlobalLinebreakMatcher();
|
103
106
|
|
104
107
|
// Otherwise, if no linebreak is desired and no comments interfere, replace the linebreaks with empty strings.
|
105
108
|
newTextBefore = desiredStyle === "before" || textBefore.trim() ? textBefore : textBefore.replace(LINEBREAK_REGEX, "");
|
@@ -129,19 +132,14 @@ module.exports = {
|
|
129
132
|
* @returns {void}
|
130
133
|
*/
|
131
134
|
function validateNode(node, leftSide) {
|
132
|
-
let leftToken = sourceCode.getLastToken(leftSide);
|
133
|
-
let operatorToken = sourceCode.getTokenAfter(leftToken);
|
134
135
|
|
135
136
|
// When the left part of a binary expression is a single expression wrapped in
|
136
137
|
// parentheses (ex: `(a) + b`), leftToken will be the last token of the expression
|
137
138
|
// and operatorToken will be the closing parenthesis.
|
138
139
|
// The leftToken should be the last closing parenthesis, and the operatorToken
|
139
140
|
// should be the token right after that.
|
140
|
-
|
141
|
-
|
142
|
-
operatorToken = sourceCode.getTokenAfter(operatorToken);
|
143
|
-
}
|
144
|
-
|
141
|
+
const operatorToken = sourceCode.getTokenAfter(leftSide, astUtils.isNotClosingParenToken);
|
142
|
+
const leftToken = sourceCode.getTokenBefore(operatorToken);
|
145
143
|
const rightToken = sourceCode.getTokenAfter(operatorToken);
|
146
144
|
const operator = operatorToken.value;
|
147
145
|
const operatorStyleOverride = styleOverrides[operator];
|
@@ -101,7 +101,7 @@ module.exports = {
|
|
101
101
|
let first = token;
|
102
102
|
|
103
103
|
do {
|
104
|
-
first = sourceCode.
|
104
|
+
first = sourceCode.getTokenAfter(first, { includeComments: true });
|
105
105
|
} while (isComment(first) && first.loc.start.line === tokenStartLine);
|
106
106
|
|
107
107
|
const firstLine = first.loc.start.line;
|
@@ -120,7 +120,7 @@ module.exports = {
|
|
120
120
|
let last = token;
|
121
121
|
|
122
122
|
do {
|
123
|
-
last = sourceCode.
|
123
|
+
last = sourceCode.getTokenBefore(last, { includeComments: true });
|
124
124
|
} while (isComment(last) && last.loc.end.line === blockEnd);
|
125
125
|
|
126
126
|
const lastLine = last.loc.end.line;
|
@@ -182,7 +182,7 @@ module.exports = {
|
|
182
182
|
}
|
183
183
|
} else {
|
184
184
|
if (blockHasTopPadding) {
|
185
|
-
const nextToken = sourceCode.
|
185
|
+
const nextToken = sourceCode.getTokenAfter(openBrace, { includeComments: true });
|
186
186
|
|
187
187
|
context.report({
|
188
188
|
node,
|
@@ -195,7 +195,7 @@ module.exports = {
|
|
195
195
|
}
|
196
196
|
|
197
197
|
if (blockHasBottomPadding) {
|
198
|
-
const previousToken = sourceCode.
|
198
|
+
const previousToken = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
|
199
199
|
|
200
200
|
context.report({
|
201
201
|
node,
|
@@ -108,7 +108,7 @@ module.exports = {
|
|
108
108
|
return null;
|
109
109
|
}
|
110
110
|
|
111
|
-
const propertyDot = sourceCode.
|
111
|
+
const propertyDot = sourceCode.getFirstTokenBetween(applied, node.callee.property, token => token.value === ".");
|
112
112
|
|
113
113
|
return fixer.replaceTextRange([propertyDot.range[0], node.range[1]], `(...${sourceCode.getText(node.arguments[1])})`);
|
114
114
|
}
|
@@ -157,7 +157,7 @@ module.exports = {
|
|
157
157
|
}
|
158
158
|
|
159
159
|
if (isConcatenation(currentNode) && hasStringLiteral(currentNode) && hasNonStringLiteral(currentNode)) {
|
160
|
-
const plusSign = sourceCode.
|
160
|
+
const plusSign = sourceCode.getFirstTokenBetween(currentNode.left, currentNode.right, token => token.value === "+");
|
161
161
|
const textBeforePlus = getTextBetween(currentNode.left, plusSign);
|
162
162
|
const textAfterPlus = getTextBetween(plusSign, currentNode.right);
|
163
163
|
const leftEndsWithCurly = endsWithTemplateCurly(currentNode.left);
|
package/lib/rules/quotes.js
CHANGED
@@ -33,6 +33,9 @@ const QUOTE_SETTINGS = {
|
|
33
33
|
}
|
34
34
|
};
|
35
35
|
|
36
|
+
// An unescaped newline is a newline preceded by an even number of backslashes.
|
37
|
+
const UNESCAPED_LINEBREAK_PATTERN = new RegExp(String.raw`(^|[^\\])(\\\\)*[${Array.from(astUtils.LINEBREAKS).join("")}]`);
|
38
|
+
|
36
39
|
/**
|
37
40
|
* Switches quoting of javascript string between ' " and `
|
38
41
|
* escaping and unescaping as necessary.
|
@@ -254,15 +257,16 @@ module.exports = {
|
|
254
257
|
TemplateLiteral(node) {
|
255
258
|
|
256
259
|
// If backticks are expected or it's a tagged template, then this shouldn't throw an errors
|
257
|
-
if (
|
260
|
+
if (
|
261
|
+
allowTemplateLiterals ||
|
262
|
+
quoteOption === "backtick" ||
|
263
|
+
node.parent.type === "TaggedTemplateExpression" && node === node.parent.quasi
|
264
|
+
) {
|
258
265
|
return;
|
259
266
|
}
|
260
267
|
|
261
|
-
|
262
|
-
|
263
|
-
* An unescaped newline is a newline preceded by an even number of backslashes.
|
264
|
-
*/
|
265
|
-
const shouldWarn = node.quasis.length === 1 && !/(^|[^\\])(\\\\)*[\r\n\u2028\u2029]/.test(node.quasis[0].value.raw);
|
268
|
+
// A warning should be produced if the template literal only has one TemplateElement, and has no unescaped newlines.
|
269
|
+
const shouldWarn = node.quasis.length === 1 && !UNESCAPED_LINEBREAK_PATTERN.test(node.quasis[0].value.raw);
|
266
270
|
|
267
271
|
if (shouldWarn) {
|
268
272
|
context.report({
|
@@ -206,6 +206,10 @@ module.exports = {
|
|
206
206
|
DebuggerStatement: checkNode,
|
207
207
|
ReturnStatement: checkNode,
|
208
208
|
ThrowStatement: checkNode,
|
209
|
+
ImportDeclaration: checkNode,
|
210
|
+
ExportNamedDeclaration: checkNode,
|
211
|
+
ExportAllDeclaration: checkNode,
|
212
|
+
ExportDefaultDeclaration: checkNode,
|
209
213
|
ForStatement(node) {
|
210
214
|
if (node.init) {
|
211
215
|
checkSemicolonSpacing(sourceCode.getTokenAfter(node.init), node);
|
@@ -4,6 +4,12 @@
|
|
4
4
|
*/
|
5
5
|
"use strict";
|
6
6
|
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Requirements
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
const astUtils = require("../ast-utils");
|
12
|
+
|
7
13
|
//------------------------------------------------------------------------------
|
8
14
|
// Rule Definition
|
9
15
|
//------------------------------------------------------------------------------
|
@@ -104,7 +110,7 @@ module.exports = {
|
|
104
110
|
const isAnonymousGenerator = node.generator && !isNamed;
|
105
111
|
const isNormalArrow = isArrow && !node.async;
|
106
112
|
const isArrowWithoutParens = isArrow && sourceCode.getFirstToken(node, 1).value !== "(";
|
107
|
-
let forbidSpacing, requireSpacing
|
113
|
+
let forbidSpacing, requireSpacing;
|
108
114
|
|
109
115
|
// isAnonymousGenerator → `generator-star-spacing` should warn it. E.g. `function* () {}`
|
110
116
|
// isNormalArrow → ignore always.
|
@@ -124,10 +130,7 @@ module.exports = {
|
|
124
130
|
requireSpacing = requireAnonymousFunctionSpacing;
|
125
131
|
}
|
126
132
|
|
127
|
-
rightToken = sourceCode.getFirstToken(node);
|
128
|
-
while (rightToken.value !== "(") {
|
129
|
-
rightToken = sourceCode.getTokenAfter(rightToken);
|
130
|
-
}
|
133
|
+
const rightToken = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
|
131
134
|
const leftToken = sourceCode.getTokenBefore(rightToken);
|
132
135
|
const location = leftToken.loc.end;
|
133
136
|
|
@@ -5,6 +5,7 @@
|
|
5
5
|
"use strict";
|
6
6
|
|
7
7
|
const lodash = require("lodash");
|
8
|
+
const astUtils = require("../ast-utils");
|
8
9
|
|
9
10
|
//------------------------------------------------------------------------------
|
10
11
|
// Helpers
|
@@ -88,8 +89,7 @@ function createExceptionsPattern(exceptions) {
|
|
88
89
|
pattern += exceptions.map(escapeAndRepeat).join("|");
|
89
90
|
pattern += ")";
|
90
91
|
}
|
91
|
-
|
92
|
-
pattern += "(?:$|[\n\r]))";
|
92
|
+
pattern += `(?:$|[${Array.from(astUtils.LINEBREAKS).join("")}]))`;
|
93
93
|
}
|
94
94
|
|
95
95
|
return pattern;
|
package/lib/rules/strict.js
CHANGED
@@ -212,8 +212,8 @@ module.exports = {
|
|
212
212
|
*/
|
213
213
|
function enterFunction(node) {
|
214
214
|
const isBlock = node.body.type === "BlockStatement",
|
215
|
-
useStrictDirectives = isBlock
|
216
|
-
getUseStrictDirectives(node.body.body) : [];
|
215
|
+
useStrictDirectives = isBlock
|
216
|
+
? getUseStrictDirectives(node.body.body) : [];
|
217
217
|
|
218
218
|
if (mode === "function") {
|
219
219
|
enterFunctionInFunctionMode(node, useStrictDirectives);
|
package/lib/rules/unicode-bom.js
CHANGED
@@ -45,7 +45,7 @@ module.exports = {
|
|
45
45
|
loc: location,
|
46
46
|
message: "Expected Unicode BOM (Byte Order Mark).",
|
47
47
|
fix(fixer) {
|
48
|
-
return fixer.
|
48
|
+
return fixer.insertTextBeforeRange([0, 1], "\uFEFF");
|
49
49
|
}
|
50
50
|
});
|
51
51
|
} else if (sourceCode.hasBOM && (requireBOM === "never")) {
|
package/lib/rules/wrap-iife.js
CHANGED
@@ -5,6 +5,10 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
8
12
|
const astUtils = require("../ast-utils");
|
9
13
|
|
10
14
|
//------------------------------------------------------------------------------
|
@@ -51,11 +55,7 @@ module.exports = {
|
|
51
55
|
* @private
|
52
56
|
*/
|
53
57
|
function wrapped(node) {
|
54
|
-
|
55
|
-
nextToken = sourceCode.getTokenAfter(node);
|
56
|
-
|
57
|
-
return previousToken && previousToken.value === "(" &&
|
58
|
-
nextToken && nextToken.value === ")";
|
58
|
+
return astUtils.isParenthesised(sourceCode, node);
|
59
59
|
}
|
60
60
|
|
61
61
|
/**
|
package/lib/rules/yoda.js
CHANGED
@@ -235,12 +235,7 @@ module.exports = {
|
|
235
235
|
* paren token.
|
236
236
|
*/
|
237
237
|
function isParenWrapped() {
|
238
|
-
|
239
|
-
|
240
|
-
return ((tokenBefore = sourceCode.getTokenBefore(node)) &&
|
241
|
-
tokenBefore.value === "(" &&
|
242
|
-
(tokenAfter = sourceCode.getTokenAfter(node)) &&
|
243
|
-
tokenAfter.value === ")");
|
238
|
+
return astUtils.isParenthesised(sourceCode, node);
|
244
239
|
}
|
245
240
|
|
246
241
|
return (node.type === "LogicalExpression" &&
|
@@ -269,7 +264,7 @@ module.exports = {
|
|
269
264
|
* @returns {string} A string representation of the node with the sides and operator flipped
|
270
265
|
*/
|
271
266
|
function getFlippedString(node) {
|
272
|
-
const operatorToken = sourceCode.
|
267
|
+
const operatorToken = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
|
273
268
|
const textBeforeOperator = sourceCode.getText().slice(sourceCode.getTokenBefore(operatorToken).range[1], operatorToken.range[0]);
|
274
269
|
const textAfterOperator = sourceCode.getText().slice(operatorToken.range[1], sourceCode.getTokenAfter(operatorToken).range[0]);
|
275
270
|
const leftText = sourceCode.getText().slice(sourceCode.getFirstToken(node).range[0], sourceCode.getTokenBefore(operatorToken).range[1]);
|
@@ -147,6 +147,12 @@ function RuleTester(testerConfig) {
|
|
147
147
|
lodash.cloneDeep(defaultConfig),
|
148
148
|
testerConfig
|
149
149
|
);
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Rule definitions to define before tests.
|
153
|
+
* @type {Object}
|
154
|
+
*/
|
155
|
+
this.rules = {};
|
150
156
|
}
|
151
157
|
|
152
158
|
/**
|
@@ -239,7 +245,7 @@ RuleTester.prototype = {
|
|
239
245
|
* @returns {void}
|
240
246
|
*/
|
241
247
|
defineRule(name, rule) {
|
242
|
-
|
248
|
+
this.rules[name] = rule;
|
243
249
|
},
|
244
250
|
|
245
251
|
/**
|
@@ -488,13 +494,12 @@ RuleTester.prototype = {
|
|
488
494
|
assert.fail(messages[i], null, "Error should be a string or object.");
|
489
495
|
}
|
490
496
|
}
|
497
|
+
}
|
491
498
|
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
assert.equal(fixResult.output, item.output, "Output is incorrect.");
|
496
|
-
}
|
499
|
+
if (item.hasOwnProperty("output")) {
|
500
|
+
const fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
|
497
501
|
|
502
|
+
assert.equal(fixResult.output, item.output, "Output is incorrect.");
|
498
503
|
}
|
499
504
|
|
500
505
|
assertASTDidntChange(result.beforeAST, result.afterAST);
|
@@ -508,6 +513,7 @@ RuleTester.prototype = {
|
|
508
513
|
RuleTester.describe("valid", () => {
|
509
514
|
test.valid.forEach(valid => {
|
510
515
|
RuleTester.it(valid.code || valid, () => {
|
516
|
+
eslint.defineRules(this.rules);
|
511
517
|
testValidTemplate(ruleName, valid);
|
512
518
|
});
|
513
519
|
});
|
@@ -516,6 +522,7 @@ RuleTester.prototype = {
|
|
516
522
|
RuleTester.describe("invalid", () => {
|
517
523
|
test.invalid.forEach(invalid => {
|
518
524
|
RuleTester.it(invalid.code, () => {
|
525
|
+
eslint.defineRules(this.rules);
|
519
526
|
testInvalidTemplate(ruleName, invalid);
|
520
527
|
});
|
521
528
|
});
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Define the cursor which iterates tokens and comments in reverse.
|
3
|
+
* @author Toru Nagashima
|
4
|
+
*/
|
5
|
+
"use strict";
|
6
|
+
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Requirements
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
const Cursor = require("./cursor");
|
12
|
+
const utils = require("./utils");
|
13
|
+
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Exports
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
/**
|
19
|
+
* The cursor which iterates tokens and comments in reverse.
|
20
|
+
*/
|
21
|
+
module.exports = class BackwardTokenCommentCursor extends Cursor {
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Initializes this cursor.
|
25
|
+
* @param {Token[]} tokens - The array of tokens.
|
26
|
+
* @param {Comment[]} comments - The array of comments.
|
27
|
+
* @param {Object} indexMap - The map from locations to indices in `tokens`.
|
28
|
+
* @param {number} startLoc - The start location of the iteration range.
|
29
|
+
* @param {number} endLoc - The end location of the iteration range.
|
30
|
+
*/
|
31
|
+
constructor(tokens, comments, indexMap, startLoc, endLoc) {
|
32
|
+
super();
|
33
|
+
this.tokens = tokens;
|
34
|
+
this.comments = comments;
|
35
|
+
this.tokenIndex = utils.getLastIndex(tokens, indexMap, endLoc);
|
36
|
+
this.commentIndex = utils.search(comments, endLoc) - 1;
|
37
|
+
this.border = startLoc;
|
38
|
+
}
|
39
|
+
|
40
|
+
/** @inheritdoc */
|
41
|
+
moveNext() {
|
42
|
+
const token = (this.tokenIndex >= 0) ? this.tokens[this.tokenIndex] : null;
|
43
|
+
const comment = (this.commentIndex >= 0) ? this.comments[this.commentIndex] : null;
|
44
|
+
|
45
|
+
if (token && (!comment || token.range[1] > comment.range[1])) {
|
46
|
+
this.current = token;
|
47
|
+
this.tokenIndex -= 1;
|
48
|
+
} else if (comment) {
|
49
|
+
this.current = comment;
|
50
|
+
this.commentIndex -= 1;
|
51
|
+
} else {
|
52
|
+
this.current = null;
|
53
|
+
}
|
54
|
+
|
55
|
+
return Boolean(this.current) && (this.border === -1 || this.current.range[0] >= this.border);
|
56
|
+
}
|
57
|
+
};
|
@@ -0,0 +1,56 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Define the cursor which iterates tokens only in reverse.
|
3
|
+
* @author Toru Nagashima
|
4
|
+
*/
|
5
|
+
"use strict";
|
6
|
+
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Requirements
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
const Cursor = require("./cursor");
|
12
|
+
const utils = require("./utils");
|
13
|
+
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Exports
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
/**
|
19
|
+
* The cursor which iterates tokens only in reverse.
|
20
|
+
*/
|
21
|
+
module.exports = class BackwardTokenCursor extends Cursor {
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Initializes this cursor.
|
25
|
+
* @param {Token[]} tokens - The array of tokens.
|
26
|
+
* @param {Comment[]} comments - The array of comments.
|
27
|
+
* @param {Object} indexMap - The map from locations to indices in `tokens`.
|
28
|
+
* @param {number} startLoc - The start location of the iteration range.
|
29
|
+
* @param {number} endLoc - The end location of the iteration range.
|
30
|
+
*/
|
31
|
+
constructor(tokens, comments, indexMap, startLoc, endLoc) {
|
32
|
+
super();
|
33
|
+
this.tokens = tokens;
|
34
|
+
this.index = utils.getLastIndex(tokens, indexMap, endLoc);
|
35
|
+
this.indexEnd = utils.getFirstIndex(tokens, indexMap, startLoc);
|
36
|
+
}
|
37
|
+
|
38
|
+
/** @inheritdoc */
|
39
|
+
moveNext() {
|
40
|
+
if (this.index >= this.indexEnd) {
|
41
|
+
this.current = this.tokens[this.index];
|
42
|
+
this.index -= 1;
|
43
|
+
return true;
|
44
|
+
}
|
45
|
+
return false;
|
46
|
+
}
|
47
|
+
|
48
|
+
//
|
49
|
+
// Shorthand for performance.
|
50
|
+
//
|
51
|
+
|
52
|
+
/** @inheritdoc */
|
53
|
+
getOneToken() {
|
54
|
+
return (this.index >= this.indexEnd) ? this.tokens[this.index] : null;
|
55
|
+
}
|
56
|
+
};
|
@@ -0,0 +1,76 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Define the abstract class about cursors which iterate tokens.
|
3
|
+
* @author Toru Nagashima
|
4
|
+
*/
|
5
|
+
"use strict";
|
6
|
+
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Exports
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
/**
|
12
|
+
* The abstract class about cursors which iterate tokens.
|
13
|
+
*
|
14
|
+
* This class has 2 abstract methods.
|
15
|
+
*
|
16
|
+
* - `current: Token | Comment | null` ... The current token.
|
17
|
+
* - `moveNext(): boolean` ... Moves this cursor to the next token. If the next token didn't exist, it returns `false`.
|
18
|
+
*
|
19
|
+
* This is similar to ES2015 Iterators.
|
20
|
+
* However, Iterators were slow (at 2017-01), so I created this class as similar to C# IEnumerable.
|
21
|
+
*
|
22
|
+
* There are the following known sub classes.
|
23
|
+
*
|
24
|
+
* - ForwardTokenCursor .......... The cursor which iterates tokens only.
|
25
|
+
* - BackwardTokenCursor ......... The cursor which iterates tokens only in reverse.
|
26
|
+
* - ForwardTokenCommentCursor ... The cursor which iterates tokens and comments.
|
27
|
+
* - BackwardTokenCommentCursor .. The cursor which iterates tokens and comments in reverse.
|
28
|
+
* - DecorativeCursor
|
29
|
+
* - FilterCursor ............ The cursor which ignores the specified tokens.
|
30
|
+
* - SkipCursor .............. The cursor which ignores the first few tokens.
|
31
|
+
* - LimitCursor ............. The cursor which limits the count of tokens.
|
32
|
+
*
|
33
|
+
*/
|
34
|
+
module.exports = class Cursor {
|
35
|
+
|
36
|
+
/**
|
37
|
+
* Initializes this cursor.
|
38
|
+
*/
|
39
|
+
constructor() {
|
40
|
+
this.current = null;
|
41
|
+
}
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Gets the first token.
|
45
|
+
* This consumes this cursor.
|
46
|
+
* @returns {Token|Comment} The first token or null.
|
47
|
+
*/
|
48
|
+
getOneToken() {
|
49
|
+
return this.moveNext() ? this.current : null;
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Gets the first tokens.
|
54
|
+
* This consumes this cursor.
|
55
|
+
* @returns {(Token|Comment)[]} All tokens.
|
56
|
+
*/
|
57
|
+
getAllTokens() {
|
58
|
+
const tokens = [];
|
59
|
+
|
60
|
+
while (this.moveNext()) {
|
61
|
+
tokens.push(this.current);
|
62
|
+
}
|
63
|
+
|
64
|
+
return tokens;
|
65
|
+
}
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Moves this cursor to the next token.
|
69
|
+
* @returns {boolean} `true` if the next token exists.
|
70
|
+
* @abstract
|
71
|
+
*/
|
72
|
+
/* istanbul ignore next */
|
73
|
+
moveNext() { // eslint-disable-line class-methods-use-this
|
74
|
+
throw new Error("Not implemented.");
|
75
|
+
}
|
76
|
+
};
|