eslint 3.16.1 → 3.19.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 +103 -0
- package/README.md +1 -0
- package/conf/eslint-recommended.js +2 -0
- package/lib/ast-utils.js +3 -67
- package/lib/code-path-analysis/code-path-analyzer.js +2 -7
- package/lib/code-path-analysis/debug-helpers.js +17 -16
- package/lib/config/config-file.js +68 -38
- package/lib/config/config-rule.js +14 -10
- package/lib/config/plugins.js +19 -8
- package/lib/eslint.js +11 -10
- package/lib/formatters/codeframe.js +4 -9
- package/lib/formatters/stylish.js +5 -4
- package/lib/ignored-paths.js +6 -0
- package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
- package/lib/rules/array-callback-return.js +15 -5
- package/lib/rules/arrow-body-style.js +2 -2
- package/lib/rules/arrow-parens.js +9 -3
- package/lib/rules/capitalized-comments.js +2 -1
- package/lib/rules/comma-dangle.js +3 -2
- package/lib/rules/comma-spacing.js +4 -14
- package/lib/rules/comma-style.js +8 -14
- package/lib/rules/complexity.js +14 -8
- package/lib/rules/consistent-return.js +17 -10
- package/lib/rules/curly.js +2 -2
- package/lib/rules/dot-notation.js +12 -6
- package/lib/rules/func-name-matching.js +18 -7
- package/lib/rules/func-names.js +20 -5
- package/lib/rules/keyword-spacing.js +19 -4
- package/lib/rules/line-comment-position.js +15 -5
- package/lib/rules/lines-around-comment.js +19 -0
- package/lib/rules/lines-around-directive.js +1 -1
- package/lib/rules/max-params.js +17 -4
- package/lib/rules/max-statements.js +11 -10
- package/lib/rules/new-parens.js +7 -21
- package/lib/rules/no-compare-neg-zero.js +53 -0
- package/lib/rules/no-cond-assign.js +4 -17
- package/lib/rules/no-else-return.js +19 -4
- package/lib/rules/no-empty-function.js +9 -16
- package/lib/rules/no-extra-parens.js +110 -121
- package/lib/rules/no-extra-semi.js +16 -3
- package/lib/rules/no-global-assign.js +1 -1
- package/lib/rules/no-implicit-coercion.js +21 -8
- package/lib/rules/no-invalid-regexp.js +2 -1
- package/lib/rules/no-multiple-empty-lines.js +2 -4
- package/lib/rules/no-native-reassign.js +1 -1
- package/lib/rules/no-negated-in-lhs.js +1 -1
- package/lib/rules/no-new-func.js +6 -8
- package/lib/rules/no-new.js +2 -6
- package/lib/rules/no-param-reassign.js +37 -7
- package/lib/rules/no-process-exit.js +2 -10
- package/lib/rules/no-restricted-properties.js +2 -0
- package/lib/rules/no-restricted-syntax.js +32 -21
- package/lib/rules/no-return-await.js +1 -1
- package/lib/rules/no-sequences.js +2 -2
- package/lib/rules/no-sync.js +8 -13
- package/lib/rules/no-unsafe-negation.js +1 -1
- package/lib/rules/no-unused-expressions.js +10 -1
- package/lib/rules/no-unused-vars.js +12 -12
- package/lib/rules/no-use-before-define.js +1 -1
- package/lib/rules/no-useless-computed-key.js +12 -1
- package/lib/rules/no-useless-escape.js +8 -2
- package/lib/rules/no-useless-return.js +13 -2
- package/lib/rules/nonblock-statement-body-position.js +114 -0
- package/lib/rules/object-curly-spacing.js +2 -2
- package/lib/rules/object-shorthand.js +10 -3
- package/lib/rules/operator-assignment.js +20 -3
- package/lib/rules/padded-blocks.js +37 -31
- package/lib/rules/prefer-const.js +1 -1
- package/lib/rules/prefer-destructuring.js +1 -1
- package/lib/rules/quotes.js +1 -0
- package/lib/rules/semi-spacing.js +2 -15
- package/lib/rules/semi.js +17 -13
- package/lib/rules/sort-vars.js +3 -5
- package/lib/rules/space-before-function-paren.js +53 -77
- package/lib/rules/space-in-parens.js +4 -8
- package/lib/rules/space-unary-ops.js +19 -1
- package/lib/rules/strict.js +8 -2
- package/lib/rules/yoda.js +2 -2
- package/lib/testers/rule-tester.js +44 -13
- package/lib/util/fix-tracker.js +121 -0
- package/lib/util/glob-util.js +1 -1
- package/lib/util/node-event-generator.js +274 -4
- package/lib/util/source-code-fixer.js +3 -9
- package/lib/util/source-code.js +99 -2
- package/lib/util/traverser.js +16 -25
- package/package.json +34 -34
@@ -26,17 +26,9 @@ module.exports = {
|
|
26
26
|
//--------------------------------------------------------------------------
|
27
27
|
|
28
28
|
return {
|
29
|
-
|
30
|
-
|
31
|
-
const callee = node.callee;
|
32
|
-
|
33
|
-
if (callee.type === "MemberExpression" && callee.object.name === "process" &&
|
34
|
-
callee.property.name === "exit"
|
35
|
-
) {
|
36
|
-
context.report({ node, message: "Don't use process.exit(); throw an error instead." });
|
37
|
-
}
|
29
|
+
"CallExpression > MemberExpression.callee[object.name = 'process'][property.name = 'exit']"(node) {
|
30
|
+
context.report({ node: node.parent, message: "Don't use process.exit(); throw an error instead." });
|
38
31
|
}
|
39
|
-
|
40
32
|
};
|
41
33
|
|
42
34
|
}
|
@@ -109,6 +109,7 @@ module.exports = {
|
|
109
109
|
if (matchedObjectProperty) {
|
110
110
|
const message = matchedObjectProperty.message ? ` ${matchedObjectProperty.message}` : "";
|
111
111
|
|
112
|
+
// eslint-disable-next-line eslint-plugin/report-message-format
|
112
113
|
context.report({ node, message: "'{{objectName}}.{{propertyName}}' is restricted from being used.{{message}}", data: {
|
113
114
|
objectName,
|
114
115
|
propertyName,
|
@@ -117,6 +118,7 @@ module.exports = {
|
|
117
118
|
} else if (globalMatchedProperty) {
|
118
119
|
const message = globalMatchedProperty.message ? ` ${globalMatchedProperty.message}` : "";
|
119
120
|
|
121
|
+
// eslint-disable-next-line eslint-plugin/report-message-format
|
120
122
|
context.report({ node, message: "'{{propertyName}}' is restricted from being used.{{message}}", data: {
|
121
123
|
propertyName,
|
122
124
|
message
|
@@ -8,8 +8,6 @@
|
|
8
8
|
// Rule Definition
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
|
-
const nodeTypes = require("espree").Syntax;
|
12
|
-
|
13
11
|
module.exports = {
|
14
12
|
meta: {
|
15
13
|
docs: {
|
@@ -20,31 +18,44 @@ module.exports = {
|
|
20
18
|
|
21
19
|
schema: {
|
22
20
|
type: "array",
|
23
|
-
items: [
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
items: [{
|
22
|
+
oneOf: [
|
23
|
+
{
|
24
|
+
type: "string"
|
25
|
+
},
|
26
|
+
{
|
27
|
+
type: "object",
|
28
|
+
properties: {
|
29
|
+
selector: { type: "string" },
|
30
|
+
message: { type: "string" }
|
31
|
+
},
|
32
|
+
required: ["selector"],
|
33
|
+
additionalProperties: false
|
34
|
+
}
|
35
|
+
]
|
36
|
+
}],
|
28
37
|
uniqueItems: true,
|
29
38
|
minItems: 0
|
30
39
|
}
|
31
40
|
},
|
32
41
|
|
33
42
|
create(context) {
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
return context.options.reduce((result, selectorOrObject) => {
|
44
|
+
const isStringFormat = (typeof selectorOrObject === "string");
|
45
|
+
const hasCustomMessage = !isStringFormat && Boolean(selectorOrObject.message);
|
46
|
+
|
47
|
+
const selector = isStringFormat ? selectorOrObject : selectorOrObject.selector;
|
48
|
+
const message = hasCustomMessage ? selectorOrObject.message : "Using '{{selector}}' is not allowed.";
|
49
|
+
|
50
|
+
return Object.assign(result, {
|
51
|
+
[selector](node) {
|
52
|
+
context.report({
|
53
|
+
node,
|
54
|
+
message,
|
55
|
+
data: hasCustomMessage ? {} : { selector }
|
56
|
+
});
|
57
|
+
}
|
58
|
+
});
|
48
59
|
}, {});
|
49
60
|
|
50
61
|
}
|
@@ -76,8 +76,8 @@ module.exports = {
|
|
76
76
|
nextToken = sourceCode.getTokenAfter(node, 1);
|
77
77
|
|
78
78
|
return isParenthesised(node) && previousToken && nextToken &&
|
79
|
-
|
80
|
-
nextToken
|
79
|
+
astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
|
80
|
+
astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
|
81
81
|
}
|
82
82
|
|
83
83
|
return {
|
package/lib/rules/no-sync.js
CHANGED
@@ -26,19 +26,14 @@ module.exports = {
|
|
26
26
|
|
27
27
|
return {
|
28
28
|
|
29
|
-
MemberExpression(node) {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
data: {
|
38
|
-
propertyName
|
39
|
-
}
|
40
|
-
});
|
41
|
-
}
|
29
|
+
"MemberExpression[property.name=/.*Sync$/]"(node) {
|
30
|
+
context.report({
|
31
|
+
node,
|
32
|
+
message: "Unexpected sync method: '{{propertyName}}'.",
|
33
|
+
data: {
|
34
|
+
propertyName: node.property.name
|
35
|
+
}
|
36
|
+
});
|
42
37
|
}
|
43
38
|
};
|
44
39
|
|
@@ -25,6 +25,9 @@ module.exports = {
|
|
25
25
|
},
|
26
26
|
allowTernary: {
|
27
27
|
type: "boolean"
|
28
|
+
},
|
29
|
+
allowTaggedTemplates: {
|
30
|
+
type: "boolean"
|
28
31
|
}
|
29
32
|
},
|
30
33
|
additionalProperties: false
|
@@ -35,7 +38,8 @@ module.exports = {
|
|
35
38
|
create(context) {
|
36
39
|
const config = context.options[0] || {},
|
37
40
|
allowShortCircuit = config.allowShortCircuit || false,
|
38
|
-
allowTernary = config.allowTernary || false
|
41
|
+
allowTernary = config.allowTernary || false,
|
42
|
+
allowTaggedTemplates = config.allowTaggedTemplates || false;
|
39
43
|
|
40
44
|
/**
|
41
45
|
* @param {ASTNode} node - any node
|
@@ -95,12 +99,17 @@ module.exports = {
|
|
95
99
|
return isValidExpression(node.consequent) && isValidExpression(node.alternate);
|
96
100
|
}
|
97
101
|
}
|
102
|
+
|
98
103
|
if (allowShortCircuit) {
|
99
104
|
if (node.type === "LogicalExpression") {
|
100
105
|
return isValidExpression(node.right);
|
101
106
|
}
|
102
107
|
}
|
103
108
|
|
109
|
+
if (allowTaggedTemplates && node.type === "TaggedTemplateExpression") {
|
110
|
+
return true;
|
111
|
+
}
|
112
|
+
|
104
113
|
return /^(?:Assignment|Call|New|Update|Yield|Await)Expression$/.test(node.type) ||
|
105
114
|
(node.type === "UnaryExpression" && ["delete", "void"].indexOf(node.operator) >= 0);
|
106
115
|
}
|
@@ -66,6 +66,7 @@ module.exports = {
|
|
66
66
|
|
67
67
|
const DEFINED_MESSAGE = "'{{name}}' is defined but never used.";
|
68
68
|
const ASSIGNED_MESSAGE = "'{{name}}' is assigned a value but never used.";
|
69
|
+
const REST_PROPERTY_TYPE = /^(?:Experimental)?RestProperty$/;
|
69
70
|
|
70
71
|
const config = {
|
71
72
|
vars: "all",
|
@@ -139,17 +140,16 @@ module.exports = {
|
|
139
140
|
*/
|
140
141
|
function hasRestSpreadSibling(variable) {
|
141
142
|
if (config.ignoreRestSiblings) {
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
));
|
143
|
+
return variable.defs.some(def => {
|
144
|
+
const propertyNode = def.name.parent;
|
145
|
+
const patternNode = propertyNode.parent;
|
146
|
+
|
147
|
+
return (
|
148
|
+
propertyNode.type === "Property" &&
|
149
|
+
patternNode.type === "ObjectPattern" &&
|
150
|
+
REST_PROPERTY_TYPE.test(patternNode.properties[patternNode.properties.length - 1].type)
|
151
|
+
);
|
152
|
+
});
|
153
153
|
}
|
154
154
|
|
155
155
|
return false;
|
@@ -568,7 +568,7 @@ module.exports = {
|
|
568
568
|
function getLocation(variable) {
|
569
569
|
const comment = variable.eslintExplicitGlobalComment;
|
570
570
|
|
571
|
-
return
|
571
|
+
return sourceCode.getLocFromIndex(comment.range[0] + 2 + getColumnInComment(variable, comment));
|
572
572
|
}
|
573
573
|
|
574
574
|
//--------------------------------------------------------------------------
|
@@ -166,7 +166,7 @@ module.exports = {
|
|
166
166
|
const options = parseOptions(context.options[0]);
|
167
167
|
|
168
168
|
/**
|
169
|
-
* Determines whether a given use-before-define case should be
|
169
|
+
* Determines whether a given use-before-define case should be reported according to the options.
|
170
170
|
* @param {escope.Variable} variable The variable that gets used before being defined
|
171
171
|
* @param {escope.Reference} reference The reference to the variable
|
172
172
|
* @returns {boolean} `true` if the usage should be reported
|
@@ -9,6 +9,7 @@
|
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
11
|
const astUtils = require("../ast-utils");
|
12
|
+
const esUtils = require("esutils");
|
12
13
|
|
13
14
|
//------------------------------------------------------------------------------
|
14
15
|
// Rule Definition
|
@@ -55,7 +56,17 @@ module.exports = {
|
|
55
56
|
// If there are comments between the brackets and the property name, don't do a fix.
|
56
57
|
return null;
|
57
58
|
}
|
58
|
-
|
59
|
+
|
60
|
+
const tokenBeforeLeftBracket = sourceCode.getTokenBefore(leftSquareBracket);
|
61
|
+
|
62
|
+
// Insert a space before the key to avoid changing identifiers, e.g. ({ get[2]() {} }) to ({ get2() {} })
|
63
|
+
const needsSpaceBeforeKey = tokenBeforeLeftBracket.range[1] === leftSquareBracket.range[0] &&
|
64
|
+
esUtils.code.isIdentifierPartES6(tokenBeforeLeftBracket.value.slice(-1).charCodeAt(0)) &&
|
65
|
+
esUtils.code.isIdentifierPartES6(key.raw.charCodeAt(0));
|
66
|
+
|
67
|
+
const replacementKey = (needsSpaceBeforeKey ? " " : "") + key.raw;
|
68
|
+
|
69
|
+
return fixer.replaceTextRange([leftSquareBracket.range[0], rightSquareBracket.range[1]], replacementKey);
|
59
70
|
}
|
60
71
|
});
|
61
72
|
}
|
@@ -94,7 +94,7 @@ module.exports = {
|
|
94
94
|
function report(node, startOffset, character) {
|
95
95
|
context.report({
|
96
96
|
node,
|
97
|
-
loc:
|
97
|
+
loc: sourceCode.getLocFromIndex(sourceCode.getIndexFromLoc(node.loc.start) + startOffset),
|
98
98
|
message: "Unnecessary escape character: \\{{character}}.",
|
99
99
|
data: { character }
|
100
100
|
});
|
@@ -147,7 +147,13 @@ module.exports = {
|
|
147
147
|
function check(node) {
|
148
148
|
const isTemplateElement = node.type === "TemplateElement";
|
149
149
|
|
150
|
-
if (
|
150
|
+
if (
|
151
|
+
isTemplateElement &&
|
152
|
+
node.parent &&
|
153
|
+
node.parent.parent &&
|
154
|
+
node.parent.parent.type === "TaggedTemplateExpression" &&
|
155
|
+
node.parent === node.parent.parent.quasi
|
156
|
+
) {
|
151
157
|
|
152
158
|
// Don't report tagged template literals, because the backslash character is accessible to the tag function.
|
153
159
|
return;
|
@@ -8,7 +8,8 @@
|
|
8
8
|
// Requirements
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
|
-
const astUtils = require("../ast-utils")
|
11
|
+
const astUtils = require("../ast-utils"),
|
12
|
+
FixTracker = require("../util/fix-tracker");
|
12
13
|
|
13
14
|
//------------------------------------------------------------------------------
|
14
15
|
// Helpers
|
@@ -219,7 +220,17 @@ module.exports = {
|
|
219
220
|
loc: node.loc,
|
220
221
|
message: "Unnecessary return statement.",
|
221
222
|
fix(fixer) {
|
222
|
-
|
223
|
+
if (isRemovable(node)) {
|
224
|
+
|
225
|
+
// Extend the replacement range to include the
|
226
|
+
// entire function to avoid conflicting with
|
227
|
+
// no-else-return.
|
228
|
+
// https://github.com/eslint/eslint/issues/8026
|
229
|
+
return new FixTracker(fixer, context.getSourceCode())
|
230
|
+
.retainEnclosingFunction(node)
|
231
|
+
.remove(node);
|
232
|
+
}
|
233
|
+
return null;
|
223
234
|
}
|
224
235
|
});
|
225
236
|
}
|
@@ -0,0 +1,114 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview enforce the location of single-line statements
|
3
|
+
* @author Teddy Katz
|
4
|
+
*/
|
5
|
+
"use strict";
|
6
|
+
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Rule Definition
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
const POSITION_SCHEMA = { enum: ["beside", "below", "any"] };
|
12
|
+
|
13
|
+
module.exports = {
|
14
|
+
meta: {
|
15
|
+
docs: {
|
16
|
+
description: "enforce the location of single-line statements",
|
17
|
+
category: "Stylistic Issues",
|
18
|
+
recommended: false
|
19
|
+
},
|
20
|
+
fixable: "whitespace",
|
21
|
+
schema: [
|
22
|
+
POSITION_SCHEMA,
|
23
|
+
{
|
24
|
+
properties: {
|
25
|
+
overrides: {
|
26
|
+
properties: {
|
27
|
+
if: POSITION_SCHEMA,
|
28
|
+
else: POSITION_SCHEMA,
|
29
|
+
while: POSITION_SCHEMA,
|
30
|
+
do: POSITION_SCHEMA,
|
31
|
+
for: POSITION_SCHEMA
|
32
|
+
},
|
33
|
+
additionalProperties: false
|
34
|
+
}
|
35
|
+
},
|
36
|
+
additionalProperties: false
|
37
|
+
}
|
38
|
+
]
|
39
|
+
},
|
40
|
+
|
41
|
+
create(context) {
|
42
|
+
const sourceCode = context.getSourceCode();
|
43
|
+
|
44
|
+
//----------------------------------------------------------------------
|
45
|
+
// Helpers
|
46
|
+
//----------------------------------------------------------------------
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Gets the applicable preference for a particular keyword
|
50
|
+
* @param {string} keywordName The name of a keyword, e.g. 'if'
|
51
|
+
* @returns {string} The applicable option for the keyword, e.g. 'beside'
|
52
|
+
*/
|
53
|
+
function getOption(keywordName) {
|
54
|
+
return context.options[1] && context.options[1].overrides && context.options[1].overrides[keywordName] ||
|
55
|
+
context.options[0] ||
|
56
|
+
"beside";
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Validates the location of a single-line statement
|
61
|
+
* @param {ASTNode} node The single-line statement
|
62
|
+
* @param {string} keywordName The applicable keyword name for the single-line statement
|
63
|
+
* @returns {void}
|
64
|
+
*/
|
65
|
+
function validateStatement(node, keywordName) {
|
66
|
+
const option = getOption(keywordName);
|
67
|
+
|
68
|
+
if (node.type === "BlockStatement" || option === "any") {
|
69
|
+
return;
|
70
|
+
}
|
71
|
+
|
72
|
+
const tokenBefore = sourceCode.getTokenBefore(node);
|
73
|
+
|
74
|
+
if (tokenBefore.loc.end.line === node.loc.start.line && option === "below") {
|
75
|
+
context.report({
|
76
|
+
node,
|
77
|
+
message: "Expected a linebreak before this statement.",
|
78
|
+
fix: fixer => fixer.insertTextBefore(node, "\n")
|
79
|
+
});
|
80
|
+
} else if (tokenBefore.loc.end.line !== node.loc.start.line && option === "beside") {
|
81
|
+
context.report({
|
82
|
+
node,
|
83
|
+
message: "Expected no linebreak before this statement.",
|
84
|
+
fix(fixer) {
|
85
|
+
if (sourceCode.getText().slice(tokenBefore.range[1], node.range[0]).trim()) {
|
86
|
+
return null;
|
87
|
+
}
|
88
|
+
return fixer.replaceTextRange([tokenBefore.range[1], node.range[0]], " ");
|
89
|
+
}
|
90
|
+
});
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
//----------------------------------------------------------------------
|
95
|
+
// Public
|
96
|
+
//----------------------------------------------------------------------
|
97
|
+
|
98
|
+
return {
|
99
|
+
IfStatement(node) {
|
100
|
+
validateStatement(node.consequent, "if");
|
101
|
+
|
102
|
+
// Check the `else` node, but don't check 'else if' statements.
|
103
|
+
if (node.alternate && node.alternate.type !== "IfStatement") {
|
104
|
+
validateStatement(node.alternate, "else");
|
105
|
+
}
|
106
|
+
},
|
107
|
+
WhileStatement: node => validateStatement(node.body, "while"),
|
108
|
+
DoWhileStatement: node => validateStatement(node.body, "do"),
|
109
|
+
ForStatement: node => validateStatement(node.body, "for"),
|
110
|
+
ForInStatement: node => validateStatement(node.body, "for"),
|
111
|
+
ForOfStatement: node => validateStatement(node.body, "for")
|
112
|
+
};
|
113
|
+
}
|
114
|
+
};
|
@@ -171,8 +171,8 @@ module.exports = {
|
|
171
171
|
|
172
172
|
if (astUtils.isTokenOnSameLine(penultimate, last)) {
|
173
173
|
const shouldCheckPenultimate = (
|
174
|
-
options.arraysInObjectsException && penultimate
|
175
|
-
options.objectsInObjectsException && penultimate
|
174
|
+
options.arraysInObjectsException && astUtils.isClosingBracketToken(penultimate) ||
|
175
|
+
options.objectsInObjectsException && astUtils.isClosingBraceToken(penultimate)
|
176
176
|
);
|
177
177
|
const penultimateType = shouldCheckPenultimate && sourceCode.getNodeByRangeIndex(penultimate.start).type;
|
178
178
|
|
@@ -230,7 +230,10 @@ module.exports = {
|
|
230
230
|
const functionToken = sourceCode.getTokens(node.value).find(token => token.type === "Keyword" && token.value === "function");
|
231
231
|
const tokenBeforeParams = node.value.generator ? sourceCode.getTokenAfter(functionToken) : functionToken;
|
232
232
|
|
233
|
-
return fixer.replaceTextRange(
|
233
|
+
return fixer.replaceTextRange(
|
234
|
+
[firstKeyToken.range[0], node.range[1]],
|
235
|
+
keyPrefix + keyText + sourceCode.text.slice(tokenBeforeParams.range[1], node.value.range[1])
|
236
|
+
);
|
234
237
|
}
|
235
238
|
const arrowToken = sourceCode.getTokens(node.value).find(token => token.value === "=>");
|
236
239
|
const tokenBeforeArrow = sourceCode.getTokenBefore(arrowToken);
|
@@ -238,7 +241,10 @@ module.exports = {
|
|
238
241
|
const oldParamText = sourceCode.text.slice(sourceCode.getFirstToken(node.value, node.value.async ? 1 : 0).range[0], tokenBeforeArrow.range[1]);
|
239
242
|
const newParamText = hasParensAroundParameters ? oldParamText : `(${oldParamText})`;
|
240
243
|
|
241
|
-
return fixer.replaceTextRange(
|
244
|
+
return fixer.replaceTextRange(
|
245
|
+
[firstKeyToken.range[0], node.range[1]],
|
246
|
+
keyPrefix + keyText + newParamText + sourceCode.text.slice(arrowToken.range[1], node.value.range[1])
|
247
|
+
);
|
242
248
|
|
243
249
|
}
|
244
250
|
|
@@ -368,11 +374,12 @@ module.exports = {
|
|
368
374
|
// Checks for property/method shorthand.
|
369
375
|
if (isConciseProperty) {
|
370
376
|
if (node.method && (APPLY_NEVER || AVOID_QUOTES && isStringLiteral(node.key))) {
|
377
|
+
const message = APPLY_NEVER ? "Expected longform method syntax." : "Expected longform method syntax for string literal keys.";
|
371
378
|
|
372
379
|
// { x() {} } should be written as { x: function() {} }
|
373
380
|
context.report({
|
374
381
|
node,
|
375
|
-
message
|
382
|
+
message,
|
376
383
|
fix: fixer => makeFunctionLongform(fixer, node)
|
377
384
|
});
|
378
385
|
} else if (APPLY_NEVER) {
|
@@ -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
|
// Helpers
|
9
15
|
//------------------------------------------------------------------------------
|
@@ -135,7 +141,7 @@ module.exports = {
|
|
135
141
|
const equalsToken = getOperatorToken(node);
|
136
142
|
const operatorToken = getOperatorToken(expr);
|
137
143
|
const leftText = sourceCode.getText().slice(node.range[0], equalsToken.range[0]);
|
138
|
-
const rightText = sourceCode.getText().slice(operatorToken.range[1], node.range[1]);
|
144
|
+
const rightText = sourceCode.getText().slice(operatorToken.range[1], node.right.range[1]);
|
139
145
|
|
140
146
|
return fixer.replaceText(node, `${leftText}${expr.operator}=${rightText}`);
|
141
147
|
}
|
@@ -171,9 +177,20 @@ module.exports = {
|
|
171
177
|
if (canBeFixed(node.left)) {
|
172
178
|
const operatorToken = getOperatorToken(node);
|
173
179
|
const leftText = sourceCode.getText().slice(node.range[0], operatorToken.range[0]);
|
174
|
-
const
|
180
|
+
const newOperator = node.operator.slice(0, -1);
|
181
|
+
let rightText;
|
182
|
+
|
183
|
+
// If this change would modify precedence (e.g. `foo *= bar + 1` => `foo = foo * (bar + 1)`), parenthesize the right side.
|
184
|
+
if (
|
185
|
+
astUtils.getPrecedence(node.right) <= astUtils.getPrecedence({ type: "BinaryExpression", operator: newOperator }) &&
|
186
|
+
!astUtils.isParenthesised(sourceCode, node.right)
|
187
|
+
) {
|
188
|
+
rightText = `${sourceCode.text.slice(operatorToken.range[1], node.right.range[0])}(${sourceCode.getText(node.right)})`;
|
189
|
+
} else {
|
190
|
+
rightText = sourceCode.text.slice(operatorToken.range[1], node.range[1]);
|
191
|
+
}
|
175
192
|
|
176
|
-
return fixer.replaceText(node, `${leftText}= ${leftText}${
|
193
|
+
return fixer.replaceText(node, `${leftText}= ${leftText}${newOperator}${rightText}`);
|
177
194
|
}
|
178
195
|
return null;
|
179
196
|
}
|