eslint 9.0.0-alpha.0 → 9.0.0-alpha.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/README.md +5 -0
- package/conf/ecma-version.js +16 -0
- package/lib/cli-engine/cli-engine.js +1 -1
- package/lib/cli-engine/lint-result-cache.js +2 -2
- package/lib/cli.js +14 -16
- package/lib/linter/apply-disable-directives.js +2 -2
- package/lib/linter/code-path-analysis/code-path.js +5 -19
- package/lib/linter/code-path-analysis/fork-context.js +1 -1
- package/lib/linter/config-comment-parser.js +7 -10
- package/lib/linter/linter.js +105 -4
- package/lib/linter/report-translator.js +2 -2
- package/lib/linter/source-code-fixer.js +1 -1
- package/lib/rule-tester/rule-tester.js +1 -26
- package/lib/rules/array-bracket-newline.js +1 -1
- package/lib/rules/array-bracket-spacing.js +1 -1
- package/lib/rules/block-scoped-var.js +1 -1
- package/lib/rules/callback-return.js +2 -2
- package/lib/rules/comma-dangle.js +1 -1
- package/lib/rules/comma-style.js +2 -2
- package/lib/rules/complexity.js +1 -1
- package/lib/rules/constructor-super.js +1 -1
- package/lib/rules/default-case.js +1 -1
- package/lib/rules/eol-last.js +2 -2
- package/lib/rules/function-paren-newline.js +2 -2
- package/lib/rules/indent-legacy.js +5 -5
- package/lib/rules/indent.js +5 -5
- package/lib/rules/index.js +1 -0
- package/lib/rules/key-spacing.js +2 -2
- package/lib/rules/line-comment-position.js +1 -1
- package/lib/rules/lines-around-directive.js +2 -2
- package/lib/rules/max-depth.js +1 -1
- package/lib/rules/max-len.js +3 -3
- package/lib/rules/max-lines.js +3 -3
- package/lib/rules/max-nested-callbacks.js +1 -1
- package/lib/rules/max-params.js +1 -1
- package/lib/rules/max-statements.js +1 -1
- package/lib/rules/multiline-comment-style.js +7 -7
- package/lib/rules/new-cap.js +1 -1
- package/lib/rules/newline-after-var.js +1 -1
- package/lib/rules/newline-before-return.js +1 -1
- package/lib/rules/no-constant-binary-expression.js +5 -5
- package/lib/rules/no-constructor-return.js +1 -1
- package/lib/rules/no-dupe-class-members.js +2 -2
- package/lib/rules/no-else-return.js +1 -1
- package/lib/rules/no-empty-function.js +2 -2
- package/lib/rules/no-fallthrough.js +1 -1
- package/lib/rules/no-inner-declarations.js +22 -1
- package/lib/rules/no-invalid-this.js +1 -1
- package/lib/rules/no-lone-blocks.js +2 -2
- package/lib/rules/no-loss-of-precision.js +1 -1
- package/lib/rules/no-misleading-character-class.js +174 -65
- package/lib/rules/no-multiple-empty-lines.js +1 -1
- package/lib/rules/no-restricted-globals.js +1 -1
- package/lib/rules/no-restricted-imports.js +2 -2
- package/lib/rules/no-restricted-modules.js +2 -2
- package/lib/rules/no-return-await.js +1 -1
- package/lib/rules/no-trailing-spaces.js +2 -3
- package/lib/rules/no-unneeded-ternary.js +1 -1
- package/lib/rules/no-unsafe-optional-chaining.js +1 -1
- package/lib/rules/no-unused-vars.js +6 -8
- package/lib/rules/no-useless-assignment.js +566 -0
- package/lib/rules/no-useless-backreference.js +1 -1
- package/lib/rules/object-curly-spacing.js +3 -3
- package/lib/rules/object-property-newline.js +1 -1
- package/lib/rules/one-var.js +5 -5
- package/lib/rules/padded-blocks.js +7 -7
- package/lib/rules/prefer-arrow-callback.js +3 -3
- package/lib/rules/prefer-reflect.js +1 -1
- package/lib/rules/prefer-regex-literals.js +1 -1
- package/lib/rules/prefer-template.js +1 -1
- package/lib/rules/radix.js +2 -2
- package/lib/rules/semi-style.js +1 -1
- package/lib/rules/sort-imports.js +1 -1
- package/lib/rules/sort-keys.js +1 -1
- package/lib/rules/sort-vars.js +1 -1
- package/lib/rules/space-unary-ops.js +1 -1
- package/lib/rules/strict.js +1 -1
- package/lib/rules/utils/ast-utils.js +7 -7
- package/lib/rules/yield-star-spacing.js +1 -1
- package/lib/source-code/source-code.js +4 -4
- package/lib/source-code/token-store/index.js +2 -2
- package/package.json +4 -4
- package/conf/config-schema.js +0 -93
- package/lib/shared/config-validator.js +0 -380
- package/lib/shared/relative-module-resolver.js +0 -50
@@ -62,7 +62,6 @@ function *iterateCharacterSequence(nodes) {
|
|
62
62
|
}
|
63
63
|
}
|
64
64
|
|
65
|
-
|
66
65
|
/**
|
67
66
|
* Checks whether the given character node is a Unicode code point escape or not.
|
68
67
|
* @param {Character} char the character node to check.
|
@@ -73,80 +72,126 @@ function isUnicodeCodePointEscape(char) {
|
|
73
72
|
}
|
74
73
|
|
75
74
|
/**
|
76
|
-
* Each function returns
|
77
|
-
* @type {Record<string, (chars: Character[]) =>
|
75
|
+
* Each function returns matched characters if it detects that kind of problem.
|
76
|
+
* @type {Record<string, (chars: Character[]) => IterableIterator<Character[]>>}
|
78
77
|
*/
|
79
|
-
const
|
80
|
-
surrogatePairWithoutUFlag(chars) {
|
81
|
-
|
82
|
-
if (
|
83
|
-
|
78
|
+
const findCharacterSequences = {
|
79
|
+
*surrogatePairWithoutUFlag(chars) {
|
80
|
+
for (const [index, char] of chars.entries()) {
|
81
|
+
if (index === 0) {
|
82
|
+
continue;
|
83
|
+
}
|
84
|
+
const previous = chars[index - 1];
|
85
|
+
|
86
|
+
if (
|
87
|
+
isSurrogatePair(previous.value, char.value) &&
|
88
|
+
!isUnicodeCodePointEscape(previous) &&
|
89
|
+
!isUnicodeCodePointEscape(char)
|
90
|
+
) {
|
91
|
+
yield [previous, char];
|
84
92
|
}
|
85
|
-
|
86
|
-
|
87
|
-
return (
|
88
|
-
isSurrogatePair(c1.value, c.value) &&
|
89
|
-
!isUnicodeCodePointEscape(c1) &&
|
90
|
-
!isUnicodeCodePointEscape(c)
|
91
|
-
);
|
92
|
-
});
|
93
|
+
}
|
93
94
|
},
|
94
95
|
|
95
|
-
surrogatePair(chars) {
|
96
|
-
|
97
|
-
if (
|
98
|
-
|
96
|
+
*surrogatePair(chars) {
|
97
|
+
for (const [index, char] of chars.entries()) {
|
98
|
+
if (index === 0) {
|
99
|
+
continue;
|
99
100
|
}
|
100
|
-
const
|
101
|
+
const previous = chars[index - 1];
|
101
102
|
|
102
|
-
|
103
|
-
isSurrogatePair(
|
103
|
+
if (
|
104
|
+
isSurrogatePair(previous.value, char.value) &&
|
104
105
|
(
|
105
|
-
isUnicodeCodePointEscape(
|
106
|
-
isUnicodeCodePointEscape(
|
106
|
+
isUnicodeCodePointEscape(previous) ||
|
107
|
+
isUnicodeCodePointEscape(char)
|
107
108
|
)
|
108
|
-
)
|
109
|
-
|
109
|
+
) {
|
110
|
+
yield [previous, char];
|
111
|
+
}
|
112
|
+
}
|
110
113
|
},
|
111
114
|
|
112
|
-
combiningClass(chars) {
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
115
|
+
*combiningClass(chars) {
|
116
|
+
for (const [index, char] of chars.entries()) {
|
117
|
+
if (index === 0) {
|
118
|
+
continue;
|
119
|
+
}
|
120
|
+
const previous = chars[index - 1];
|
121
|
+
|
122
|
+
if (
|
123
|
+
isCombiningCharacter(char.value) &&
|
124
|
+
!isCombiningCharacter(previous.value)
|
125
|
+
) {
|
126
|
+
yield [previous, char];
|
127
|
+
}
|
128
|
+
}
|
118
129
|
},
|
119
130
|
|
120
|
-
emojiModifier(chars) {
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
131
|
+
*emojiModifier(chars) {
|
132
|
+
for (const [index, char] of chars.entries()) {
|
133
|
+
if (index === 0) {
|
134
|
+
continue;
|
135
|
+
}
|
136
|
+
const previous = chars[index - 1];
|
137
|
+
|
138
|
+
if (
|
139
|
+
isEmojiModifier(char.value) &&
|
140
|
+
!isEmojiModifier(previous.value)
|
141
|
+
) {
|
142
|
+
yield [previous, char];
|
143
|
+
}
|
144
|
+
}
|
126
145
|
},
|
127
146
|
|
128
|
-
regionalIndicatorSymbol(chars) {
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
147
|
+
*regionalIndicatorSymbol(chars) {
|
148
|
+
for (const [index, char] of chars.entries()) {
|
149
|
+
if (index === 0) {
|
150
|
+
continue;
|
151
|
+
}
|
152
|
+
const previous = chars[index - 1];
|
153
|
+
|
154
|
+
if (
|
155
|
+
isRegionalIndicatorSymbol(char.value) &&
|
156
|
+
isRegionalIndicatorSymbol(previous.value)
|
157
|
+
) {
|
158
|
+
yield [previous, char];
|
159
|
+
}
|
160
|
+
}
|
134
161
|
},
|
135
162
|
|
136
|
-
zwj(chars) {
|
137
|
-
|
163
|
+
*zwj(chars) {
|
164
|
+
let sequence = null;
|
138
165
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
166
|
+
for (const [index, char] of chars.entries()) {
|
167
|
+
if (index === 0 || index === chars.length - 1) {
|
168
|
+
continue;
|
169
|
+
}
|
170
|
+
if (
|
171
|
+
char.value === 0x200d &&
|
172
|
+
chars[index - 1].value !== 0x200d &&
|
173
|
+
chars[index + 1].value !== 0x200d
|
174
|
+
) {
|
175
|
+
if (sequence) {
|
176
|
+
if (sequence.at(-1) === chars[index - 1]) {
|
177
|
+
sequence.push(char, chars[index + 1]); // append to the sequence
|
178
|
+
} else {
|
179
|
+
yield sequence;
|
180
|
+
sequence = chars.slice(index - 1, index + 2);
|
181
|
+
}
|
182
|
+
} else {
|
183
|
+
sequence = chars.slice(index - 1, index + 2);
|
184
|
+
}
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
if (sequence) {
|
189
|
+
yield sequence;
|
190
|
+
}
|
146
191
|
}
|
147
192
|
};
|
148
193
|
|
149
|
-
const kinds = Object.keys(
|
194
|
+
const kinds = Object.keys(findCharacterSequences);
|
150
195
|
|
151
196
|
//------------------------------------------------------------------------------
|
152
197
|
// Rule Definition
|
@@ -181,6 +226,62 @@ module.exports = {
|
|
181
226
|
const sourceCode = context.sourceCode;
|
182
227
|
const parser = new RegExpParser();
|
183
228
|
|
229
|
+
/**
|
230
|
+
* Generates a granular loc for context.report, if directly calculable.
|
231
|
+
* @param {Character[]} chars Individual characters being reported on.
|
232
|
+
* @param {Node} node Parent string node to report within.
|
233
|
+
* @returns {Object | null} Granular loc for context.report, if directly calculable.
|
234
|
+
* @see https://github.com/eslint/eslint/pull/17515
|
235
|
+
*/
|
236
|
+
function generateReportLocation(chars, node) {
|
237
|
+
|
238
|
+
// Limit to to literals and expression-less templates with raw values === their value.
|
239
|
+
switch (node.type) {
|
240
|
+
case "TemplateLiteral":
|
241
|
+
if (node.expressions.length || sourceCode.getText(node).slice(1, -1) !== node.quasis[0].value.cooked) {
|
242
|
+
return null;
|
243
|
+
}
|
244
|
+
break;
|
245
|
+
|
246
|
+
case "Literal":
|
247
|
+
if (typeof node.value === "string" && node.value !== node.raw.slice(1, -1)) {
|
248
|
+
return null;
|
249
|
+
}
|
250
|
+
break;
|
251
|
+
|
252
|
+
default:
|
253
|
+
return null;
|
254
|
+
}
|
255
|
+
|
256
|
+
return {
|
257
|
+
start: sourceCode.getLocFromIndex(node.range[0] + 1 + chars[0].start),
|
258
|
+
end: sourceCode.getLocFromIndex(node.range[0] + 1 + chars.at(-1).end)
|
259
|
+
};
|
260
|
+
}
|
261
|
+
|
262
|
+
/**
|
263
|
+
* Finds the report loc(s) for a range of matches.
|
264
|
+
* @param {Character[][]} matches Characters that should trigger a report.
|
265
|
+
* @param {Node} node The node to report.
|
266
|
+
* @returns {Object | null} Node loc(s) for context.report.
|
267
|
+
*/
|
268
|
+
function getNodeReportLocations(matches, node) {
|
269
|
+
const locs = [];
|
270
|
+
|
271
|
+
for (const chars of matches) {
|
272
|
+
const loc = generateReportLocation(chars, node);
|
273
|
+
|
274
|
+
// If a report can't match to a range, don't report any others
|
275
|
+
if (!loc) {
|
276
|
+
return [node.loc];
|
277
|
+
}
|
278
|
+
|
279
|
+
locs.push(loc);
|
280
|
+
}
|
281
|
+
|
282
|
+
return locs;
|
283
|
+
}
|
284
|
+
|
184
285
|
/**
|
185
286
|
* Verify a given regular expression.
|
186
287
|
* @param {Node} node The node to report.
|
@@ -208,21 +309,24 @@ module.exports = {
|
|
208
309
|
return;
|
209
310
|
}
|
210
311
|
|
211
|
-
const
|
312
|
+
const foundKindMatches = new Map();
|
212
313
|
|
213
314
|
visitRegExpAST(patternNode, {
|
214
315
|
onCharacterClassEnter(ccNode) {
|
215
316
|
for (const chars of iterateCharacterSequence(ccNode.elements)) {
|
216
317
|
for (const kind of kinds) {
|
217
|
-
if (
|
218
|
-
|
318
|
+
if (foundKindMatches.has(kind)) {
|
319
|
+
foundKindMatches.get(kind).push(...findCharacterSequences[kind](chars));
|
320
|
+
} else {
|
321
|
+
foundKindMatches.set(kind, [...findCharacterSequences[kind](chars)]);
|
219
322
|
}
|
323
|
+
|
220
324
|
}
|
221
325
|
}
|
222
326
|
}
|
223
327
|
});
|
224
328
|
|
225
|
-
for (const kind of
|
329
|
+
for (const [kind, matches] of foundKindMatches) {
|
226
330
|
let suggest;
|
227
331
|
|
228
332
|
if (kind === "surrogatePairWithoutUFlag") {
|
@@ -232,11 +336,16 @@ module.exports = {
|
|
232
336
|
}];
|
233
337
|
}
|
234
338
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
339
|
+
const locs = getNodeReportLocations(matches, node);
|
340
|
+
|
341
|
+
for (const loc of locs) {
|
342
|
+
context.report({
|
343
|
+
node,
|
344
|
+
loc,
|
345
|
+
messageId: kind,
|
346
|
+
suggest
|
347
|
+
});
|
348
|
+
}
|
240
349
|
}
|
241
350
|
}
|
242
351
|
|
@@ -267,7 +376,7 @@ module.exports = {
|
|
267
376
|
const flags = getStringIfConstant(flagsNode, scope);
|
268
377
|
|
269
378
|
if (typeof pattern === "string") {
|
270
|
-
verify(
|
379
|
+
verify(patternNode, pattern, flags || "", fixer => {
|
271
380
|
|
272
381
|
if (!isValidWithUnicodeFlag(context.languageOptions.ecmaVersion, pattern)) {
|
273
382
|
return null;
|
@@ -70,7 +70,7 @@ module.exports = {
|
|
70
70
|
const sourceCode = context.sourceCode;
|
71
71
|
|
72
72
|
// Swallow the final newline, as some editors add it automatically and we don't want it to cause an issue
|
73
|
-
const allLines = sourceCode.lines
|
73
|
+
const allLines = sourceCode.lines.at(-1) === "" ? sourceCode.lines.slice(0, -1) : sourceCode.lines;
|
74
74
|
const templateLiteralLines = new Set();
|
75
75
|
|
76
76
|
//--------------------------------------------------------------------------
|
@@ -158,7 +158,7 @@ module.exports = {
|
|
158
158
|
const options = Array.isArray(context.options) ? context.options : [];
|
159
159
|
const isPathAndPatternsObject =
|
160
160
|
typeof options[0] === "object" &&
|
161
|
-
(Object.
|
161
|
+
(Object.hasOwn(options[0], "paths") || Object.hasOwn(options[0], "patterns"));
|
162
162
|
|
163
163
|
const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
|
164
164
|
const restrictedPathMessages = restrictedPaths.reduce((memo, importSource) => {
|
@@ -203,7 +203,7 @@ module.exports = {
|
|
203
203
|
* @private
|
204
204
|
*/
|
205
205
|
function checkRestrictedPathAndReport(importSource, importNames, node) {
|
206
|
-
if (!Object.
|
206
|
+
if (!Object.hasOwn(restrictedPathMessages, importSource)) {
|
207
207
|
return;
|
208
208
|
}
|
209
209
|
|
@@ -90,7 +90,7 @@ module.exports = {
|
|
90
90
|
const options = Array.isArray(context.options) ? context.options : [];
|
91
91
|
const isPathAndPatternsObject =
|
92
92
|
typeof options[0] === "object" &&
|
93
|
-
(Object.
|
93
|
+
(Object.hasOwn(options[0], "paths") || Object.hasOwn(options[0], "patterns"));
|
94
94
|
|
95
95
|
const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
|
96
96
|
const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
|
@@ -178,7 +178,7 @@ module.exports = {
|
|
178
178
|
* @private
|
179
179
|
*/
|
180
180
|
function isRestrictedPath(name) {
|
181
|
-
return Object.
|
181
|
+
return Object.hasOwn(restrictedPathMessages, name);
|
182
182
|
}
|
183
183
|
|
184
184
|
return {
|
@@ -118,7 +118,7 @@ module.exports = {
|
|
118
118
|
if (node.parent.type === "LogicalExpression" && node === node.parent.right) {
|
119
119
|
return isInTailCallPosition(node.parent);
|
120
120
|
}
|
121
|
-
if (node.parent.type === "SequenceExpression" && node === node.parent.expressions
|
121
|
+
if (node.parent.type === "SequenceExpression" && node === node.parent.expressions.at(-1)) {
|
122
122
|
return isInTailCallPosition(node.parent);
|
123
123
|
}
|
124
124
|
return false;
|
@@ -129,8 +129,7 @@ module.exports = {
|
|
129
129
|
comments = sourceCode.getAllComments(),
|
130
130
|
commentLineNumbers = getCommentLineNumbers(comments);
|
131
131
|
|
132
|
-
let totalLength = 0
|
133
|
-
fixRange = [];
|
132
|
+
let totalLength = 0;
|
134
133
|
|
135
134
|
for (let i = 0, ii = lines.length; i < ii; i++) {
|
136
135
|
const lineNumber = i + 1;
|
@@ -177,7 +176,7 @@ module.exports = {
|
|
177
176
|
continue;
|
178
177
|
}
|
179
178
|
|
180
|
-
fixRange = [rangeStart, rangeEnd];
|
179
|
+
const fixRange = [rangeStart, rangeEnd];
|
181
180
|
|
182
181
|
if (!ignoreComments || !commentLineNumbers.has(lineNumber)) {
|
183
182
|
report(node, location, fixRange);
|
@@ -76,7 +76,7 @@ module.exports = {
|
|
76
76
|
* @returns {string} A string representing an inverted expression
|
77
77
|
*/
|
78
78
|
function invertExpression(node) {
|
79
|
-
if (node.type === "BinaryExpression" && Object.
|
79
|
+
if (node.type === "BinaryExpression" && Object.hasOwn(OPERATOR_INVERSES, node.operator)) {
|
80
80
|
const operatorToken = sourceCode.getFirstTokenBetween(
|
81
81
|
node.left,
|
82
82
|
node.right,
|
@@ -141,7 +141,7 @@ module.exports = {
|
|
141
141
|
} else if (defType === "Parameter" && config.argsIgnorePattern) {
|
142
142
|
type = "args";
|
143
143
|
pattern = config.argsIgnorePattern.toString();
|
144
|
-
} else if (defType !== "Parameter" && config.varsIgnorePattern) {
|
144
|
+
} else if (defType !== "Parameter" && defType !== "CatchClause" && config.varsIgnorePattern) {
|
145
145
|
type = "vars";
|
146
146
|
pattern = config.varsIgnorePattern.toString();
|
147
147
|
}
|
@@ -218,7 +218,7 @@ module.exports = {
|
|
218
218
|
function hasRestSibling(node) {
|
219
219
|
return node.type === "Property" &&
|
220
220
|
node.parent.type === "ObjectPattern" &&
|
221
|
-
REST_PROPERTY_TYPE.test(node.parent.properties
|
221
|
+
REST_PROPERTY_TYPE.test(node.parent.properties.at(-1).type);
|
222
222
|
}
|
223
223
|
|
224
224
|
/**
|
@@ -323,7 +323,7 @@ module.exports = {
|
|
323
323
|
}
|
324
324
|
|
325
325
|
if (parent.type === "SequenceExpression") {
|
326
|
-
const isLastExpression = parent.expressions
|
326
|
+
const isLastExpression = parent.expressions.at(-1) === node;
|
327
327
|
|
328
328
|
if (!isLastExpression) {
|
329
329
|
return true;
|
@@ -392,7 +392,7 @@ module.exports = {
|
|
392
392
|
while (parent && isInside(parent, rhsNode)) {
|
393
393
|
switch (parent.type) {
|
394
394
|
case "SequenceExpression":
|
395
|
-
if (parent.expressions
|
395
|
+
if (parent.expressions.at(-1) !== node) {
|
396
396
|
return false;
|
397
397
|
}
|
398
398
|
break;
|
@@ -623,9 +623,7 @@ module.exports = {
|
|
623
623
|
if (config.caughtErrorsIgnorePattern && config.caughtErrorsIgnorePattern.test(def.name.name)) {
|
624
624
|
continue;
|
625
625
|
}
|
626
|
-
}
|
627
|
-
|
628
|
-
if (type === "Parameter") {
|
626
|
+
} else if (type === "Parameter") {
|
629
627
|
|
630
628
|
// skip any setter argument
|
631
629
|
if ((def.node.parent.type === "Property" || def.node.parent.type === "MethodDefinition") && def.node.parent.kind === "set") {
|
@@ -688,7 +686,7 @@ module.exports = {
|
|
688
686
|
let referenceToReport;
|
689
687
|
|
690
688
|
if (writeReferences.length > 0) {
|
691
|
-
referenceToReport = writeReferences
|
689
|
+
referenceToReport = writeReferences.at(-1);
|
692
690
|
}
|
693
691
|
|
694
692
|
context.report({
|