eslint 6.2.2 → 6.5.1
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 +91 -0
- package/README.md +9 -8
- package/bin/eslint.js +38 -12
- package/conf/config-schema.js +1 -0
- package/conf/default-cli-options.js +1 -1
- package/lib/cli-engine/cli-engine.js +2 -4
- package/lib/cli-engine/config-array/config-array.js +6 -0
- package/lib/cli-engine/config-array/extracted-config.js +6 -0
- package/lib/cli-engine/config-array/override-tester.js +2 -2
- package/lib/cli-engine/config-array-factory.js +2 -0
- package/lib/cli-engine/formatters/stylish.js +2 -1
- package/lib/cli-engine/ignored-paths.js +3 -3
- package/lib/cli-engine/lint-result-cache.js +0 -1
- package/lib/cli.js +13 -12
- package/lib/init/config-initializer.js +29 -0
- package/lib/init/config-rule.js +2 -2
- package/lib/init/npm-utils.js +9 -9
- package/lib/linter/apply-disable-directives.js +17 -9
- package/lib/linter/code-path-analysis/debug-helpers.js +1 -1
- package/lib/linter/linter.js +23 -4
- package/lib/options.js +7 -1
- package/lib/rule-tester/rule-tester.js +1 -2
- package/lib/rules/accessor-pairs.js +51 -11
- package/lib/rules/capitalized-comments.js +2 -2
- package/lib/rules/computed-property-spacing.js +18 -1
- package/lib/rules/default-param-last.js +61 -0
- package/lib/rules/eqeqeq.js +7 -19
- package/lib/rules/func-name-matching.js +1 -0
- package/lib/rules/function-paren-newline.js +2 -2
- package/lib/rules/indent-legacy.js +1 -1
- package/lib/rules/indent.js +44 -6
- package/lib/rules/index.js +3 -0
- package/lib/rules/new-parens.js +5 -1
- package/lib/rules/no-extra-bind.js +7 -1
- package/lib/rules/no-extra-boolean-cast.js +12 -2
- package/lib/rules/no-extra-label.js +9 -1
- package/lib/rules/no-extra-parens.js +23 -3
- package/lib/rules/no-import-assign.js +238 -0
- package/lib/rules/no-lone-blocks.js +6 -1
- package/lib/rules/no-obj-calls.js +29 -9
- package/lib/rules/no-octal-escape.js +14 -8
- package/lib/rules/no-regex-spaces.js +106 -45
- package/lib/rules/no-self-assign.js +17 -6
- package/lib/rules/no-sequences.js +2 -2
- package/lib/rules/no-undef-init.js +7 -1
- package/lib/rules/no-unsafe-negation.js +2 -10
- package/lib/rules/no-useless-rename.js +25 -13
- package/lib/rules/no-useless-return.js +3 -2
- package/lib/rules/object-curly-spacing.js +1 -1
- package/lib/rules/object-shorthand.js +35 -9
- package/lib/rules/prefer-named-capture-group.js +3 -15
- package/lib/rules/prefer-numeric-literals.js +4 -0
- package/lib/rules/prefer-regex-literals.js +125 -0
- package/lib/rules/quotes.js +6 -0
- package/lib/rules/space-before-function-paren.js +12 -1
- package/lib/rules/space-in-parens.js +77 -71
- package/lib/rules/use-isnan.js +67 -6
- package/lib/rules/yoda.js +11 -2
- package/lib/shared/logging.js +2 -0
- package/lib/shared/runtime-info.js +163 -0
- package/lib/shared/types.js +2 -0
- package/lib/source-code/source-code.js +3 -4
- package/package.json +3 -1
@@ -93,7 +93,7 @@ function applyDirectives(options) {
|
|
93
93
|
: "Unused eslint-disable directive (no problems were reported).",
|
94
94
|
line: directive.unprocessedDirective.line,
|
95
95
|
column: directive.unprocessedDirective.column,
|
96
|
-
severity: 2,
|
96
|
+
severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
|
97
97
|
nodeType: null
|
98
98
|
}));
|
99
99
|
|
@@ -114,17 +114,17 @@ function applyDirectives(options) {
|
|
114
114
|
* comment for two different rules is represented as two directives).
|
115
115
|
* @param {{ruleId: (string|null), line: number, column: number}[]} options.problems
|
116
116
|
* A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
|
117
|
-
* @param {
|
117
|
+
* @param {"off" | "warn" | "error"} options.reportUnusedDisableDirectives If `"warn"` or `"error"`, adds additional problems for unused directives
|
118
118
|
* @returns {{ruleId: (string|null), line: number, column: number}[]}
|
119
119
|
* A list of reported problems that were not disabled by the directive comments.
|
120
120
|
*/
|
121
|
-
module.exports =
|
122
|
-
const blockDirectives =
|
121
|
+
module.exports = ({ directives, problems, reportUnusedDisableDirectives = "off" }) => {
|
122
|
+
const blockDirectives = directives
|
123
123
|
.filter(directive => directive.type === "disable" || directive.type === "enable")
|
124
124
|
.map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
|
125
125
|
.sort(compareLocations);
|
126
126
|
|
127
|
-
const lineDirectives = lodash.flatMap(
|
127
|
+
const lineDirectives = lodash.flatMap(directives, directive => {
|
128
128
|
switch (directive.type) {
|
129
129
|
case "disable":
|
130
130
|
case "enable":
|
@@ -147,10 +147,18 @@ module.exports = options => {
|
|
147
147
|
}
|
148
148
|
}).sort(compareLocations);
|
149
149
|
|
150
|
-
const blockDirectivesResult = applyDirectives({
|
151
|
-
|
152
|
-
|
153
|
-
|
150
|
+
const blockDirectivesResult = applyDirectives({
|
151
|
+
problems,
|
152
|
+
directives: blockDirectives,
|
153
|
+
reportUnusedDisableDirectives
|
154
|
+
});
|
155
|
+
const lineDirectivesResult = applyDirectives({
|
156
|
+
problems: blockDirectivesResult.problems,
|
157
|
+
directives: lineDirectives,
|
158
|
+
reportUnusedDisableDirectives
|
159
|
+
});
|
160
|
+
|
161
|
+
return reportUnusedDisableDirectives !== "off"
|
154
162
|
? lineDirectivesResult.problems
|
155
163
|
.concat(blockDirectivesResult.unusedDisableDirectives)
|
156
164
|
.concat(lineDirectivesResult.unusedDisableDirectives)
|
@@ -21,7 +21,7 @@ const debug = require("debug")("eslint:code-path");
|
|
21
21
|
* @returns {string} Id of the segment.
|
22
22
|
*/
|
23
23
|
/* istanbul ignore next */
|
24
|
-
function getId(segment) { // eslint-disable-line require-jsdoc
|
24
|
+
function getId(segment) { // eslint-disable-line jsdoc/require-jsdoc
|
25
25
|
return segment.id + (segment.reachable ? "" : "!");
|
26
26
|
}
|
27
27
|
|
package/lib/linter/linter.js
CHANGED
@@ -54,6 +54,11 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
|
|
54
54
|
/** @typedef {import("../shared/types").Processor} Processor */
|
55
55
|
/** @typedef {import("../shared/types").Rule} Rule */
|
56
56
|
|
57
|
+
/**
|
58
|
+
* @template T
|
59
|
+
* @typedef {{ [P in keyof T]-?: T[P] }} Required
|
60
|
+
*/
|
61
|
+
|
57
62
|
/**
|
58
63
|
* @typedef {Object} DisableDirective
|
59
64
|
* @property {("disable"|"enable"|"disable-line"|"disable-next-line")} type
|
@@ -79,7 +84,7 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
|
|
79
84
|
* @property {boolean} [disableFixes] if `true` then the linter doesn't make `fix`
|
80
85
|
* properties into the lint result.
|
81
86
|
* @property {string} [filename] the filename of the source code.
|
82
|
-
* @property {boolean} [reportUnusedDisableDirectives] Adds reported errors for
|
87
|
+
* @property {boolean | "off" | "warn" | "error"} [reportUnusedDisableDirectives] Adds reported errors for
|
83
88
|
* unused `eslint-disable` directives.
|
84
89
|
*/
|
85
90
|
|
@@ -103,6 +108,12 @@ const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, colum
|
|
103
108
|
* whether fixes should be applied.
|
104
109
|
*/
|
105
110
|
|
111
|
+
/**
|
112
|
+
* @typedef {Object} InternalOptions
|
113
|
+
* @property {string | null} warnInlineConfig The config name what `noInlineConfig` setting came from. If `noInlineConfig` setting didn't exist, this is null. If this is a config name, then the linter warns directive comments.
|
114
|
+
* @property {"off" | "warn" | "error"} reportUnusedDisableDirectives (boolean values were normalized)
|
115
|
+
*/
|
116
|
+
|
106
117
|
//------------------------------------------------------------------------------
|
107
118
|
// Helpers
|
108
119
|
//------------------------------------------------------------------------------
|
@@ -461,13 +472,12 @@ function normalizeFilename(filename) {
|
|
461
472
|
return index === -1 ? filename : parts.slice(index).join(path.sep);
|
462
473
|
}
|
463
474
|
|
464
|
-
// eslint-disable-next-line valid-jsdoc
|
465
475
|
/**
|
466
476
|
* Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
|
467
477
|
* consistent shape.
|
468
478
|
* @param {VerifyOptions} providedOptions Options
|
469
479
|
* @param {ConfigData} config Config.
|
470
|
-
* @returns {Required<VerifyOptions> &
|
480
|
+
* @returns {Required<VerifyOptions> & InternalOptions} Normalized options
|
471
481
|
*/
|
472
482
|
function normalizeVerifyOptions(providedOptions, config) {
|
473
483
|
const disableInlineConfig = config.noInlineConfig === true;
|
@@ -476,13 +486,22 @@ function normalizeVerifyOptions(providedOptions, config) {
|
|
476
486
|
? ` (${config.configNameOfNoInlineConfig})`
|
477
487
|
: "";
|
478
488
|
|
489
|
+
let reportUnusedDisableDirectives = providedOptions.reportUnusedDisableDirectives;
|
490
|
+
|
491
|
+
if (typeof reportUnusedDisableDirectives === "boolean") {
|
492
|
+
reportUnusedDisableDirectives = reportUnusedDisableDirectives ? "error" : "off";
|
493
|
+
}
|
494
|
+
if (typeof reportUnusedDisableDirectives !== "string") {
|
495
|
+
reportUnusedDisableDirectives = config.reportUnusedDisableDirectives ? "warn" : "off";
|
496
|
+
}
|
497
|
+
|
479
498
|
return {
|
480
499
|
filename: normalizeFilename(providedOptions.filename || "<input>"),
|
481
500
|
allowInlineConfig: !ignoreInlineConfig,
|
482
501
|
warnInlineConfig: disableInlineConfig && !ignoreInlineConfig
|
483
502
|
? `your config${configNameOfNoInlineConfig}`
|
484
503
|
: null,
|
485
|
-
reportUnusedDisableDirectives
|
504
|
+
reportUnusedDisableDirectives,
|
486
505
|
disableFixes: Boolean(providedOptions.disableFixes)
|
487
506
|
};
|
488
507
|
}
|
package/lib/options.js
CHANGED
@@ -192,7 +192,7 @@ module.exports = optionator({
|
|
192
192
|
{
|
193
193
|
option: "report-unused-disable-directives",
|
194
194
|
type: "Boolean",
|
195
|
-
default:
|
195
|
+
default: void 0,
|
196
196
|
description: "Adds reported errors for unused eslint-disable directives"
|
197
197
|
},
|
198
198
|
{
|
@@ -224,6 +224,12 @@ module.exports = optionator({
|
|
224
224
|
default: "false",
|
225
225
|
description: "Run config initialization wizard"
|
226
226
|
},
|
227
|
+
{
|
228
|
+
option: "env-info",
|
229
|
+
type: "Boolean",
|
230
|
+
default: "false",
|
231
|
+
description: "Output execution environment information"
|
232
|
+
},
|
227
233
|
{
|
228
234
|
option: "debug",
|
229
235
|
type: "Boolean",
|
@@ -130,7 +130,7 @@ function freezeDeeply(x) {
|
|
130
130
|
*/
|
131
131
|
function sanitize(text) {
|
132
132
|
return text.replace(
|
133
|
-
/[\u0000-\
|
133
|
+
/[\u0000-\u0009|\u000b-\u001a]/gu, // eslint-disable-line no-control-regex
|
134
134
|
c => `\\u${c.codePointAt(0).toString(16).padStart(4, "0")}`
|
135
135
|
);
|
136
136
|
}
|
@@ -177,7 +177,6 @@ class RuleTester {
|
|
177
177
|
/**
|
178
178
|
* Creates a new instance of RuleTester.
|
179
179
|
* @param {Object} [testerConfig] Optional, extra configuration for the tester
|
180
|
-
* @constructor
|
181
180
|
*/
|
182
181
|
constructor(testerConfig) {
|
183
182
|
|
@@ -152,7 +152,7 @@ module.exports = {
|
|
152
152
|
type: "suggestion",
|
153
153
|
|
154
154
|
docs: {
|
155
|
-
description: "enforce getter and setter pairs in objects",
|
155
|
+
description: "enforce getter and setter pairs in objects and classes",
|
156
156
|
category: "Best Practices",
|
157
157
|
recommended: false,
|
158
158
|
url: "https://eslint.org/docs/rules/accessor-pairs"
|
@@ -168,6 +168,10 @@ module.exports = {
|
|
168
168
|
setWithoutGet: {
|
169
169
|
type: "boolean",
|
170
170
|
default: true
|
171
|
+
},
|
172
|
+
enforceForClassMembers: {
|
173
|
+
type: "boolean",
|
174
|
+
default: false
|
171
175
|
}
|
172
176
|
},
|
173
177
|
additionalProperties: false
|
@@ -177,13 +181,16 @@ module.exports = {
|
|
177
181
|
missingGetterInPropertyDescriptor: "Getter is not present in property descriptor.",
|
178
182
|
missingSetterInPropertyDescriptor: "Setter is not present in property descriptor.",
|
179
183
|
missingGetterInObjectLiteral: "Getter is not present for {{ name }}.",
|
180
|
-
missingSetterInObjectLiteral: "Setter is not present for {{ name }}."
|
184
|
+
missingSetterInObjectLiteral: "Setter is not present for {{ name }}.",
|
185
|
+
missingGetterInClass: "Getter is not present for class {{ name }}.",
|
186
|
+
missingSetterInClass: "Setter is not present for class {{ name }}."
|
181
187
|
}
|
182
188
|
},
|
183
189
|
create(context) {
|
184
190
|
const config = context.options[0] || {};
|
185
191
|
const checkGetWithoutSet = config.getWithoutSet === true;
|
186
192
|
const checkSetWithoutGet = config.setWithoutGet !== false;
|
193
|
+
const enforceForClassMembers = config.enforceForClassMembers === true;
|
187
194
|
const sourceCode = context.getSourceCode();
|
188
195
|
|
189
196
|
/**
|
@@ -201,6 +208,13 @@ module.exports = {
|
|
201
208
|
loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
|
202
209
|
data: { name: astUtils.getFunctionNameWithKind(node.value) }
|
203
210
|
});
|
211
|
+
} else if (node.type === "MethodDefinition") {
|
212
|
+
context.report({
|
213
|
+
node,
|
214
|
+
messageId: `${messageKind}InClass`,
|
215
|
+
loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
|
216
|
+
data: { name: astUtils.getFunctionNameWithKind(node.value) }
|
217
|
+
});
|
204
218
|
} else {
|
205
219
|
context.report({
|
206
220
|
node,
|
@@ -313,15 +327,41 @@ module.exports = {
|
|
313
327
|
}
|
314
328
|
}
|
315
329
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
330
|
+
/**
|
331
|
+
* Checks the given object expression as an object literal and as a possible property descriptor.
|
332
|
+
* @param {ASTNode} node `ObjectExpression` node to check.
|
333
|
+
* @returns {void}
|
334
|
+
* @private
|
335
|
+
*/
|
336
|
+
function checkObjectExpression(node) {
|
337
|
+
checkObjectLiteral(node);
|
338
|
+
if (isPropertyDescriptor(node)) {
|
339
|
+
checkPropertyDescriptor(node);
|
324
340
|
}
|
325
|
-
}
|
341
|
+
}
|
342
|
+
|
343
|
+
/**
|
344
|
+
* Checks the given class body.
|
345
|
+
* @param {ASTNode} node `ClassBody` node to check.
|
346
|
+
* @returns {void}
|
347
|
+
* @private
|
348
|
+
*/
|
349
|
+
function checkClassBody(node) {
|
350
|
+
const methodDefinitions = node.body.filter(m => m.type === "MethodDefinition");
|
351
|
+
|
352
|
+
checkList(methodDefinitions.filter(m => m.static));
|
353
|
+
checkList(methodDefinitions.filter(m => !m.static));
|
354
|
+
}
|
355
|
+
|
356
|
+
const listeners = {};
|
357
|
+
|
358
|
+
if (checkSetWithoutGet || checkGetWithoutSet) {
|
359
|
+
listeners.ObjectExpression = checkObjectExpression;
|
360
|
+
if (enforceForClassMembers) {
|
361
|
+
listeners.ClassBody = checkClassBody;
|
362
|
+
}
|
363
|
+
}
|
364
|
+
|
365
|
+
return listeners;
|
326
366
|
}
|
327
367
|
};
|
@@ -59,7 +59,7 @@ const DEFAULTS = {
|
|
59
59
|
* @param {string} which Either "line" or "block".
|
60
60
|
* @returns {Object} The normalized options.
|
61
61
|
*/
|
62
|
-
function getNormalizedOptions(rawOptions
|
62
|
+
function getNormalizedOptions(rawOptions, which) {
|
63
63
|
return Object.assign({}, DEFAULTS, rawOptions[which] || rawOptions);
|
64
64
|
}
|
65
65
|
|
@@ -70,7 +70,7 @@ function getNormalizedOptions(rawOptions = {}, which) {
|
|
70
70
|
* @returns {Object} An object with "Line" and "Block" keys and corresponding
|
71
71
|
* normalized options objects.
|
72
72
|
*/
|
73
|
-
function getAllNormalizedOptions(rawOptions) {
|
73
|
+
function getAllNormalizedOptions(rawOptions = {}) {
|
74
74
|
return {
|
75
75
|
Line: getNormalizedOptions(rawOptions, "line"),
|
76
76
|
Block: getNormalizedOptions(rawOptions, "block")
|
@@ -26,6 +26,16 @@ module.exports = {
|
|
26
26
|
schema: [
|
27
27
|
{
|
28
28
|
enum: ["always", "never"]
|
29
|
+
},
|
30
|
+
{
|
31
|
+
type: "object",
|
32
|
+
properties: {
|
33
|
+
enforceForClassMembers: {
|
34
|
+
type: "boolean",
|
35
|
+
default: false
|
36
|
+
}
|
37
|
+
},
|
38
|
+
additionalProperties: false
|
29
39
|
}
|
30
40
|
],
|
31
41
|
|
@@ -41,6 +51,7 @@ module.exports = {
|
|
41
51
|
create(context) {
|
42
52
|
const sourceCode = context.getSourceCode();
|
43
53
|
const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
|
54
|
+
const enforceForClassMembers = context.options[1] && context.options[1].enforceForClassMembers;
|
44
55
|
|
45
56
|
//--------------------------------------------------------------------------
|
46
57
|
// Helpers
|
@@ -178,10 +189,16 @@ module.exports = {
|
|
178
189
|
// Public
|
179
190
|
//--------------------------------------------------------------------------
|
180
191
|
|
181
|
-
|
192
|
+
const listeners = {
|
182
193
|
Property: checkSpacing("key"),
|
183
194
|
MemberExpression: checkSpacing("property")
|
184
195
|
};
|
185
196
|
|
197
|
+
if (enforceForClassMembers) {
|
198
|
+
listeners.MethodDefinition = checkSpacing("key");
|
199
|
+
}
|
200
|
+
|
201
|
+
return listeners;
|
202
|
+
|
186
203
|
}
|
187
204
|
};
|
@@ -0,0 +1,61 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview enforce default parameters to be last
|
3
|
+
* @author Chiawen Chen
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
module.exports = {
|
9
|
+
meta: {
|
10
|
+
type: "suggestion",
|
11
|
+
|
12
|
+
docs: {
|
13
|
+
description: "enforce default parameters to be last",
|
14
|
+
category: "Best Practices",
|
15
|
+
recommended: false,
|
16
|
+
url: "https://eslint.org/docs/rules/default-param-last"
|
17
|
+
},
|
18
|
+
|
19
|
+
schema: [],
|
20
|
+
|
21
|
+
messages: {
|
22
|
+
shouldBeLast: "Default parameters should be last."
|
23
|
+
}
|
24
|
+
},
|
25
|
+
|
26
|
+
create(context) {
|
27
|
+
|
28
|
+
/**
|
29
|
+
* @param {ASTNode} node function node
|
30
|
+
* @returns {void}
|
31
|
+
*/
|
32
|
+
function handleFunction(node) {
|
33
|
+
let hasSeenPlainParam = false;
|
34
|
+
|
35
|
+
for (let i = node.params.length - 1; i >= 0; i -= 1) {
|
36
|
+
const param = node.params[i];
|
37
|
+
|
38
|
+
if (
|
39
|
+
param.type !== "AssignmentPattern" &&
|
40
|
+
param.type !== "RestElement"
|
41
|
+
) {
|
42
|
+
hasSeenPlainParam = true;
|
43
|
+
continue;
|
44
|
+
}
|
45
|
+
|
46
|
+
if (hasSeenPlainParam && param.type === "AssignmentPattern") {
|
47
|
+
context.report({
|
48
|
+
node: param,
|
49
|
+
messageId: "shouldBeLast"
|
50
|
+
});
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
return {
|
56
|
+
FunctionDeclaration: handleFunction,
|
57
|
+
FunctionExpression: handleFunction,
|
58
|
+
ArrowFunctionExpression: handleFunction
|
59
|
+
};
|
60
|
+
}
|
61
|
+
};
|
package/lib/rules/eqeqeq.js
CHANGED
@@ -116,18 +116,6 @@ module.exports = {
|
|
116
116
|
return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left);
|
117
117
|
}
|
118
118
|
|
119
|
-
/**
|
120
|
-
* Gets the location (line and column) of the binary expression's operator
|
121
|
-
* @param {ASTNode} node The binary expression node to check
|
122
|
-
* @returns {Object} { line, column } location of operator
|
123
|
-
* @private
|
124
|
-
*/
|
125
|
-
function getOperatorLocation(node) {
|
126
|
-
const opToken = sourceCode.getTokenAfter(node.left);
|
127
|
-
|
128
|
-
return { line: opToken.loc.start.line, column: opToken.loc.start.column };
|
129
|
-
}
|
130
|
-
|
131
119
|
/**
|
132
120
|
* Reports a message for this rule.
|
133
121
|
* @param {ASTNode} node The binary expression node that was checked
|
@@ -136,21 +124,21 @@ module.exports = {
|
|
136
124
|
* @private
|
137
125
|
*/
|
138
126
|
function report(node, expectedOperator) {
|
127
|
+
const operatorToken = sourceCode.getFirstTokenBetween(
|
128
|
+
node.left,
|
129
|
+
node.right,
|
130
|
+
token => token.value === node.operator
|
131
|
+
);
|
132
|
+
|
139
133
|
context.report({
|
140
134
|
node,
|
141
|
-
loc:
|
135
|
+
loc: operatorToken.loc,
|
142
136
|
messageId: "unexpected",
|
143
137
|
data: { expectedOperator, actualOperator: node.operator },
|
144
138
|
fix(fixer) {
|
145
139
|
|
146
140
|
// If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
|
147
141
|
if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
|
148
|
-
const operatorToken = sourceCode.getFirstTokenBetween(
|
149
|
-
node.left,
|
150
|
-
node.right,
|
151
|
-
token => token.value === node.operator
|
152
|
-
);
|
153
|
-
|
154
142
|
return fixer.replaceText(operatorToken, expectedOperator);
|
155
143
|
}
|
156
144
|
return null;
|
@@ -51,8 +51,8 @@ module.exports = {
|
|
51
51
|
expectedBefore: "Expected newline before ')'.",
|
52
52
|
expectedAfter: "Expected newline after '('.",
|
53
53
|
expectedBetween: "Expected newline between arguments/params.",
|
54
|
-
unexpectedBefore: "Unexpected newline before '
|
55
|
-
unexpectedAfter: "Unexpected newline after '
|
54
|
+
unexpectedBefore: "Unexpected newline before ')'.",
|
55
|
+
unexpectedAfter: "Unexpected newline after '('."
|
56
56
|
}
|
57
57
|
},
|
58
58
|
|
@@ -303,7 +303,7 @@ module.exports = {
|
|
303
303
|
* @param {int} needed Expected indentation character count
|
304
304
|
* @param {int} gottenSpaces Indentation space count in the actual node/code
|
305
305
|
* @param {int} gottenTabs Indentation tab count in the actual node/code
|
306
|
-
* @param {Object
|
306
|
+
* @param {Object} [loc] Error line and column location
|
307
307
|
* @param {boolean} isLastNodeCheck Is the error for last node check
|
308
308
|
* @returns {void}
|
309
309
|
*/
|
package/lib/rules/indent.js
CHANGED
@@ -81,6 +81,9 @@ const KNOWN_NODES = new Set([
|
|
81
81
|
"WhileStatement",
|
82
82
|
"WithStatement",
|
83
83
|
"YieldExpression",
|
84
|
+
"JSXFragment",
|
85
|
+
"JSXOpeningFragment",
|
86
|
+
"JSXClosingFragment",
|
84
87
|
"JSXIdentifier",
|
85
88
|
"JSXNamespacedName",
|
86
89
|
"JSXMemberExpression",
|
@@ -1453,6 +1456,31 @@ module.exports = {
|
|
1453
1456
|
offsets.setDesiredOffsets(node.name.range, firstToken, 1);
|
1454
1457
|
},
|
1455
1458
|
|
1459
|
+
JSXFragment(node) {
|
1460
|
+
const firstOpeningToken = sourceCode.getFirstToken(node.openingFragment);
|
1461
|
+
const firstClosingToken = sourceCode.getFirstToken(node.closingFragment);
|
1462
|
+
|
1463
|
+
addElementListIndent(node.children, firstOpeningToken, firstClosingToken, 1);
|
1464
|
+
},
|
1465
|
+
|
1466
|
+
JSXOpeningFragment(node) {
|
1467
|
+
const firstToken = sourceCode.getFirstToken(node);
|
1468
|
+
const closingToken = sourceCode.getLastToken(node);
|
1469
|
+
|
1470
|
+
offsets.setDesiredOffsets(node.range, firstToken, 1);
|
1471
|
+
offsets.matchOffsetOf(firstToken, closingToken);
|
1472
|
+
},
|
1473
|
+
|
1474
|
+
JSXClosingFragment(node) {
|
1475
|
+
const firstToken = sourceCode.getFirstToken(node);
|
1476
|
+
const slashToken = sourceCode.getLastToken(node, { skip: 1 });
|
1477
|
+
const closingToken = sourceCode.getLastToken(node);
|
1478
|
+
const tokenToMatch = astUtils.isTokenOnSameLine(slashToken, closingToken) ? slashToken : closingToken;
|
1479
|
+
|
1480
|
+
offsets.setDesiredOffsets(node.range, firstToken, 1);
|
1481
|
+
offsets.matchOffsetOf(firstToken, tokenToMatch);
|
1482
|
+
},
|
1483
|
+
|
1456
1484
|
JSXExpressionContainer(node) {
|
1457
1485
|
const openingCurly = sourceCode.getFirstToken(node);
|
1458
1486
|
const closingCurly = sourceCode.getLastToken(node);
|
@@ -1588,18 +1616,23 @@ module.exports = {
|
|
1588
1616
|
return;
|
1589
1617
|
}
|
1590
1618
|
|
1591
|
-
// If the token matches the expected expected indentation, don't report it.
|
1592
|
-
if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) {
|
1593
|
-
return;
|
1594
|
-
}
|
1595
|
-
|
1596
1619
|
if (astUtils.isCommentToken(firstTokenOfLine)) {
|
1597
1620
|
const tokenBefore = precedingTokens.get(firstTokenOfLine);
|
1598
1621
|
const tokenAfter = tokenBefore ? sourceCode.getTokenAfter(tokenBefore) : sourceCode.ast.tokens[0];
|
1599
|
-
|
1600
1622
|
const mayAlignWithBefore = tokenBefore && !hasBlankLinesBetween(tokenBefore, firstTokenOfLine);
|
1601
1623
|
const mayAlignWithAfter = tokenAfter && !hasBlankLinesBetween(firstTokenOfLine, tokenAfter);
|
1602
1624
|
|
1625
|
+
/*
|
1626
|
+
* If a comment precedes a line that begins with a semicolon token, align to that token, i.e.
|
1627
|
+
*
|
1628
|
+
* let foo
|
1629
|
+
* // comment
|
1630
|
+
* ;(async () => {})()
|
1631
|
+
*/
|
1632
|
+
if (tokenAfter && astUtils.isSemicolonToken(tokenAfter) && !astUtils.isTokenOnSameLine(firstTokenOfLine, tokenAfter)) {
|
1633
|
+
offsets.setDesiredOffset(firstTokenOfLine, tokenAfter, 0);
|
1634
|
+
}
|
1635
|
+
|
1603
1636
|
// If a comment matches the expected indentation of the token immediately before or after, don't report it.
|
1604
1637
|
if (
|
1605
1638
|
mayAlignWithBefore && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenBefore)) ||
|
@@ -1609,6 +1642,11 @@ module.exports = {
|
|
1609
1642
|
}
|
1610
1643
|
}
|
1611
1644
|
|
1645
|
+
// If the token matches the expected indentation, don't report it.
|
1646
|
+
if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) {
|
1647
|
+
return;
|
1648
|
+
}
|
1649
|
+
|
1612
1650
|
// Otherwise, report the token/comment.
|
1613
1651
|
report(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine));
|
1614
1652
|
});
|
package/lib/rules/index.js
CHANGED
@@ -37,6 +37,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
37
37
|
"constructor-super": () => require("./constructor-super"),
|
38
38
|
curly: () => require("./curly"),
|
39
39
|
"default-case": () => require("./default-case"),
|
40
|
+
"default-param-last": () => require("./default-param-last"),
|
40
41
|
"dot-location": () => require("./dot-location"),
|
41
42
|
"dot-notation": () => require("./dot-notation"),
|
42
43
|
"eol-last": () => require("./eol-last"),
|
@@ -131,6 +132,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
131
132
|
"no-implicit-coercion": () => require("./no-implicit-coercion"),
|
132
133
|
"no-implicit-globals": () => require("./no-implicit-globals"),
|
133
134
|
"no-implied-eval": () => require("./no-implied-eval"),
|
135
|
+
"no-import-assign": () => require("./no-import-assign"),
|
134
136
|
"no-inline-comments": () => require("./no-inline-comments"),
|
135
137
|
"no-inner-declarations": () => require("./no-inner-declarations"),
|
136
138
|
"no-invalid-regexp": () => require("./no-invalid-regexp"),
|
@@ -241,6 +243,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
|
|
241
243
|
"prefer-object-spread": () => require("./prefer-object-spread"),
|
242
244
|
"prefer-promise-reject-errors": () => require("./prefer-promise-reject-errors"),
|
243
245
|
"prefer-reflect": () => require("./prefer-reflect"),
|
246
|
+
"prefer-regex-literals": () => require("./prefer-regex-literals"),
|
244
247
|
"prefer-rest-params": () => require("./prefer-rest-params"),
|
245
248
|
"prefer-spread": () => require("./prefer-spread"),
|
246
249
|
"prefer-template": () => require("./prefer-template"),
|
package/lib/rules/new-parens.js
CHANGED
@@ -65,7 +65,11 @@ module.exports = {
|
|
65
65
|
|
66
66
|
const lastToken = sourceCode.getLastToken(node);
|
67
67
|
const hasLastParen = lastToken && astUtils.isClosingParenToken(lastToken);
|
68
|
-
|
68
|
+
|
69
|
+
// `hasParens` is true only if the new expression ends with its own parens, e.g., new new foo() does not end with its own parens
|
70
|
+
const hasParens = hasLastParen &&
|
71
|
+
astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken)) &&
|
72
|
+
node.callee.range[1] < node.range[1];
|
69
73
|
|
70
74
|
if (always) {
|
71
75
|
if (!hasParens) {
|
@@ -40,6 +40,7 @@ module.exports = {
|
|
40
40
|
},
|
41
41
|
|
42
42
|
create(context) {
|
43
|
+
const sourceCode = context.getSourceCode();
|
43
44
|
let scopeInfo = null;
|
44
45
|
|
45
46
|
/**
|
@@ -71,8 +72,13 @@ module.exports = {
|
|
71
72
|
return null;
|
72
73
|
}
|
73
74
|
|
74
|
-
const firstTokenToRemove =
|
75
|
+
const firstTokenToRemove = sourceCode
|
75
76
|
.getFirstTokenBetween(node.parent.object, node.parent.property, astUtils.isNotClosingParenToken);
|
77
|
+
const lastTokenToRemove = sourceCode.getLastToken(node.parent.parent);
|
78
|
+
|
79
|
+
if (sourceCode.commentsExistBetween(firstTokenToRemove, lastTokenToRemove)) {
|
80
|
+
return null;
|
81
|
+
}
|
76
82
|
|
77
83
|
return fixer.removeRange([firstTokenToRemove.range[0], node.parent.parent.range[1]]);
|
78
84
|
}
|
@@ -96,13 +96,23 @@ module.exports = {
|
|
96
96
|
grandparent.callee.name === "Boolean")
|
97
97
|
) {
|
98
98
|
context.report({
|
99
|
-
node,
|
99
|
+
node: parent,
|
100
100
|
messageId: "unexpectedNegation",
|
101
101
|
fix: fixer => {
|
102
102
|
if (hasCommentsInside(parent)) {
|
103
103
|
return null;
|
104
104
|
}
|
105
|
-
|
105
|
+
|
106
|
+
let prefix = "";
|
107
|
+
const tokenBefore = sourceCode.getTokenBefore(parent);
|
108
|
+
const firstReplacementToken = sourceCode.getFirstToken(node.argument);
|
109
|
+
|
110
|
+
if (tokenBefore && tokenBefore.range[1] === parent.range[0] &&
|
111
|
+
!astUtils.canTokensBeAdjacent(tokenBefore, firstReplacementToken)) {
|
112
|
+
prefix = " ";
|
113
|
+
}
|
114
|
+
|
115
|
+
return fixer.replaceText(parent, prefix + sourceCode.getText(node.argument));
|
106
116
|
}
|
107
117
|
});
|
108
118
|
}
|