eslint 9.25.1 → 9.27.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/README.md +44 -39
- package/bin/eslint.js +15 -0
- package/conf/rule-type-list.json +2 -1
- package/lib/cli-engine/cli-engine.js +8 -8
- package/lib/cli.js +6 -5
- package/lib/config/config-loader.js +10 -18
- package/lib/config/config.js +328 -5
- package/lib/eslint/eslint-helpers.js +3 -1
- package/lib/eslint/eslint.js +31 -17
- package/lib/eslint/legacy-eslint.js +7 -7
- package/lib/languages/js/index.js +4 -3
- package/lib/languages/js/source-code/source-code.js +10 -6
- package/lib/linter/apply-disable-directives.js +1 -1
- package/lib/linter/esquery.js +329 -0
- package/lib/linter/file-context.js +11 -0
- package/lib/linter/linter.js +81 -89
- package/lib/linter/node-event-generator.js +94 -251
- package/lib/linter/report-translator.js +2 -1
- package/lib/options.js +11 -0
- package/lib/rule-tester/rule-tester.js +17 -9
- package/lib/rules/eqeqeq.js +31 -8
- package/lib/rules/index.js +2 -1
- package/lib/rules/max-params.js +32 -7
- package/lib/rules/no-array-constructor.js +51 -1
- package/lib/rules/no-shadow-restricted-names.js +25 -2
- package/lib/rules/no-unassigned-vars.js +72 -0
- package/lib/rules/no-unused-expressions.js +7 -1
- package/lib/rules/no-useless-escape.js +24 -2
- package/lib/rules/prefer-named-capture-group.js +7 -1
- package/lib/rules/utils/lazy-loading-rule-map.js +2 -2
- package/lib/services/processor-service.js +1 -2
- package/lib/services/suppressions-service.js +5 -3
- package/lib/shared/flags.js +1 -0
- package/lib/shared/serialization.js +29 -6
- package/lib/types/index.d.ts +126 -6
- package/lib/types/rules.d.ts +33 -2
- package/package.json +7 -6
- package/lib/config/flat-config-helpers.js +0 -128
- package/lib/config/rule-validator.js +0 -199
- package/lib/shared/types.js +0 -246
@@ -0,0 +1,329 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview ESQuery wrapper for ESLint.
|
3
|
+
* @author Nicholas C. Zakas
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Requirements
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
const esquery = require("esquery");
|
13
|
+
|
14
|
+
//-----------------------------------------------------------------------------
|
15
|
+
// Typedefs
|
16
|
+
//-----------------------------------------------------------------------------
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @typedef {import("esquery").Selector} ESQuerySelector
|
20
|
+
* @typedef {import("esquery").ESQueryOptions} ESQueryOptions
|
21
|
+
*/
|
22
|
+
|
23
|
+
//------------------------------------------------------------------------------
|
24
|
+
// Classes
|
25
|
+
//------------------------------------------------------------------------------
|
26
|
+
|
27
|
+
/**
|
28
|
+
* The result of parsing and analyzing an ESQuery selector.
|
29
|
+
*/
|
30
|
+
class ESQueryParsedSelector {
|
31
|
+
/**
|
32
|
+
* The raw selector string that was parsed
|
33
|
+
* @type {string}
|
34
|
+
*/
|
35
|
+
source;
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Whether this selector is an exit selector
|
39
|
+
* @type {boolean}
|
40
|
+
*/
|
41
|
+
isExit;
|
42
|
+
|
43
|
+
/**
|
44
|
+
* An object (from esquery) describing the matching behavior of the selector
|
45
|
+
* @type {ESQuerySelector}
|
46
|
+
*/
|
47
|
+
root;
|
48
|
+
|
49
|
+
/**
|
50
|
+
* The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
51
|
+
* @type {string[]|null}
|
52
|
+
*/
|
53
|
+
nodeTypes;
|
54
|
+
|
55
|
+
/**
|
56
|
+
* The number of class, pseudo-class, and attribute queries in this selector
|
57
|
+
* @type {number}
|
58
|
+
*/
|
59
|
+
attributeCount;
|
60
|
+
|
61
|
+
/**
|
62
|
+
* The number of identifier queries in this selector
|
63
|
+
* @type {number}
|
64
|
+
*/
|
65
|
+
identifierCount;
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Creates a new parsed selector.
|
69
|
+
* @param {string} source The raw selector string that was parsed
|
70
|
+
* @param {boolean} isExit Whether this selector is an exit selector
|
71
|
+
* @param {ESQuerySelector} root An object (from esquery) describing the matching behavior of the selector
|
72
|
+
* @param {string[]|null} nodeTypes The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
73
|
+
* @param {number} attributeCount The number of class, pseudo-class, and attribute queries in this selector
|
74
|
+
* @param {number} identifierCount The number of identifier queries in this selector
|
75
|
+
*/
|
76
|
+
constructor(
|
77
|
+
source,
|
78
|
+
isExit,
|
79
|
+
root,
|
80
|
+
nodeTypes,
|
81
|
+
attributeCount,
|
82
|
+
identifierCount,
|
83
|
+
) {
|
84
|
+
this.source = source;
|
85
|
+
this.isExit = isExit;
|
86
|
+
this.root = root;
|
87
|
+
this.nodeTypes = nodeTypes;
|
88
|
+
this.attributeCount = attributeCount;
|
89
|
+
this.identifierCount = identifierCount;
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Compares this selector's specifity to another selector for sorting purposes.
|
94
|
+
* @param {ESQueryParsedSelector} otherSelector The selector to compare against
|
95
|
+
* @returns {number}
|
96
|
+
* a value less than 0 if this selector is less specific than otherSelector
|
97
|
+
* a value greater than 0 if this selector is more specific than otherSelector
|
98
|
+
* a value less than 0 if this selector and otherSelector have the same specificity, and this selector <= otherSelector alphabetically
|
99
|
+
* a value greater than 0 if this selector and otherSelector have the same specificity, and this selector > otherSelector alphabetically
|
100
|
+
*/
|
101
|
+
compare(otherSelector) {
|
102
|
+
return (
|
103
|
+
this.attributeCount - otherSelector.attributeCount ||
|
104
|
+
this.identifierCount - otherSelector.identifierCount ||
|
105
|
+
(this.source <= otherSelector.source ? -1 : 1)
|
106
|
+
);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
//------------------------------------------------------------------------------
|
111
|
+
// Helpers
|
112
|
+
//------------------------------------------------------------------------------
|
113
|
+
|
114
|
+
const selectorCache = new Map();
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Computes the union of one or more arrays
|
118
|
+
* @param {...any[]} arrays One or more arrays to union
|
119
|
+
* @returns {any[]} The union of the input arrays
|
120
|
+
*/
|
121
|
+
function union(...arrays) {
|
122
|
+
return [...new Set(arrays.flat())];
|
123
|
+
}
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Computes the intersection of one or more arrays
|
127
|
+
* @param {...any[]} arrays One or more arrays to intersect
|
128
|
+
* @returns {any[]} The intersection of the input arrays
|
129
|
+
*/
|
130
|
+
function intersection(...arrays) {
|
131
|
+
if (arrays.length === 0) {
|
132
|
+
return [];
|
133
|
+
}
|
134
|
+
|
135
|
+
let result = [...new Set(arrays[0])];
|
136
|
+
|
137
|
+
for (const array of arrays.slice(1)) {
|
138
|
+
result = result.filter(x => array.includes(x));
|
139
|
+
}
|
140
|
+
return result;
|
141
|
+
}
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Analyzes a parsed selector and returns combined data about it
|
145
|
+
* @param {ESQuerySelector} parsedSelector An object (from esquery) describing the matching behavior of the selector
|
146
|
+
* @returns {{nodeTypes:string[]|null, attributeCount:number, identifierCount:number}} Object containing selector data.
|
147
|
+
*/
|
148
|
+
function analyzeParsedSelector(parsedSelector) {
|
149
|
+
let attributeCount = 0;
|
150
|
+
let identifierCount = 0;
|
151
|
+
|
152
|
+
/**
|
153
|
+
* Analyzes a selector and returns the node types that could possibly trigger it.
|
154
|
+
* @param {ESQuerySelector} selector The selector to analyze.
|
155
|
+
* @returns {string[]|null} The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
156
|
+
*/
|
157
|
+
function analyzeSelector(selector) {
|
158
|
+
switch (selector.type) {
|
159
|
+
case "identifier":
|
160
|
+
identifierCount++;
|
161
|
+
return [selector.value];
|
162
|
+
|
163
|
+
case "not":
|
164
|
+
selector.selectors.map(analyzeSelector);
|
165
|
+
return null;
|
166
|
+
|
167
|
+
case "matches": {
|
168
|
+
const typesForComponents =
|
169
|
+
selector.selectors.map(analyzeSelector);
|
170
|
+
|
171
|
+
if (typesForComponents.every(Boolean)) {
|
172
|
+
return union(...typesForComponents);
|
173
|
+
}
|
174
|
+
return null;
|
175
|
+
}
|
176
|
+
|
177
|
+
case "compound": {
|
178
|
+
const typesForComponents = selector.selectors
|
179
|
+
.map(analyzeSelector)
|
180
|
+
.filter(typesForComponent => typesForComponent);
|
181
|
+
|
182
|
+
// If all of the components could match any type, then the compound could also match any type.
|
183
|
+
if (!typesForComponents.length) {
|
184
|
+
return null;
|
185
|
+
}
|
186
|
+
|
187
|
+
/*
|
188
|
+
* If at least one of the components could only match a particular type, the compound could only match
|
189
|
+
* the intersection of those types.
|
190
|
+
*/
|
191
|
+
return intersection(...typesForComponents);
|
192
|
+
}
|
193
|
+
|
194
|
+
case "attribute":
|
195
|
+
case "field":
|
196
|
+
case "nth-child":
|
197
|
+
case "nth-last-child":
|
198
|
+
attributeCount++;
|
199
|
+
return null;
|
200
|
+
|
201
|
+
case "child":
|
202
|
+
case "descendant":
|
203
|
+
case "sibling":
|
204
|
+
case "adjacent":
|
205
|
+
analyzeSelector(selector.left);
|
206
|
+
return analyzeSelector(selector.right);
|
207
|
+
|
208
|
+
case "class":
|
209
|
+
// TODO: abstract into JSLanguage somehow
|
210
|
+
if (selector.name === "function") {
|
211
|
+
return [
|
212
|
+
"FunctionDeclaration",
|
213
|
+
"FunctionExpression",
|
214
|
+
"ArrowFunctionExpression",
|
215
|
+
];
|
216
|
+
}
|
217
|
+
return null;
|
218
|
+
|
219
|
+
default:
|
220
|
+
return null;
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
const nodeTypes = analyzeSelector(parsedSelector);
|
225
|
+
|
226
|
+
return {
|
227
|
+
nodeTypes,
|
228
|
+
attributeCount,
|
229
|
+
identifierCount,
|
230
|
+
};
|
231
|
+
}
|
232
|
+
|
233
|
+
/**
|
234
|
+
* Tries to parse a simple selector string, such as a single identifier or wildcard.
|
235
|
+
* This saves time by avoiding the overhead of esquery parsing for simple cases.
|
236
|
+
* @param {string} selector The selector string to parse.
|
237
|
+
* @returns {Object|null} An object describing the selector if it is simple, or `null` if it is not.
|
238
|
+
*/
|
239
|
+
function trySimpleParseSelector(selector) {
|
240
|
+
if (selector === "*") {
|
241
|
+
return {
|
242
|
+
type: "wildcard",
|
243
|
+
value: "*",
|
244
|
+
};
|
245
|
+
}
|
246
|
+
|
247
|
+
if (/^[a-z]+$/iu.test(selector)) {
|
248
|
+
return {
|
249
|
+
type: "identifier",
|
250
|
+
value: selector,
|
251
|
+
};
|
252
|
+
}
|
253
|
+
|
254
|
+
return null;
|
255
|
+
}
|
256
|
+
|
257
|
+
/**
|
258
|
+
* Parses a raw selector string, and throws a useful error if parsing fails.
|
259
|
+
* @param {string} selector The selector string to parse.
|
260
|
+
* @returns {Object} An object (from esquery) describing the matching behavior of this selector
|
261
|
+
* @throws {Error} An error if the selector is invalid
|
262
|
+
*/
|
263
|
+
function tryParseSelector(selector) {
|
264
|
+
try {
|
265
|
+
return esquery.parse(selector);
|
266
|
+
} catch (err) {
|
267
|
+
if (
|
268
|
+
err.location &&
|
269
|
+
err.location.start &&
|
270
|
+
typeof err.location.start.offset === "number"
|
271
|
+
) {
|
272
|
+
throw new SyntaxError(
|
273
|
+
`Syntax error in selector "${selector}" at position ${err.location.start.offset}: ${err.message}`,
|
274
|
+
);
|
275
|
+
}
|
276
|
+
throw err;
|
277
|
+
}
|
278
|
+
}
|
279
|
+
|
280
|
+
/**
|
281
|
+
* Parses a raw selector string, and returns the parsed selector along with specificity and type information.
|
282
|
+
* @param {string} source A raw AST selector
|
283
|
+
* @returns {ESQueryParsedSelector} A selector descriptor
|
284
|
+
*/
|
285
|
+
function parse(source) {
|
286
|
+
if (selectorCache.has(source)) {
|
287
|
+
return selectorCache.get(source);
|
288
|
+
}
|
289
|
+
|
290
|
+
const cleanSource = source.replace(/:exit$/u, "");
|
291
|
+
const parsedSelector =
|
292
|
+
trySimpleParseSelector(cleanSource) ?? tryParseSelector(cleanSource);
|
293
|
+
const { nodeTypes, attributeCount, identifierCount } =
|
294
|
+
analyzeParsedSelector(parsedSelector);
|
295
|
+
|
296
|
+
const result = new ESQueryParsedSelector(
|
297
|
+
source,
|
298
|
+
source.endsWith(":exit"),
|
299
|
+
parsedSelector,
|
300
|
+
nodeTypes,
|
301
|
+
attributeCount,
|
302
|
+
identifierCount,
|
303
|
+
);
|
304
|
+
|
305
|
+
selectorCache.set(source, result);
|
306
|
+
return result;
|
307
|
+
}
|
308
|
+
|
309
|
+
/**
|
310
|
+
* Checks if a node matches a given selector.
|
311
|
+
* @param {Object} node The node to check against the selector.
|
312
|
+
* @param {ESQuerySelector} root The root of the selector to match against.
|
313
|
+
* @param {Object[]} ancestry The ancestry of the node being checked, which is an array of nodes from the current node to the root.
|
314
|
+
* @param {ESQueryOptions} options The options to use for matching.
|
315
|
+
* @returns {boolean} `true` if the node matches the selector, `false` otherwise.
|
316
|
+
*/
|
317
|
+
function matches(node, root, ancestry, options) {
|
318
|
+
return esquery.matches(node, root, ancestry, options);
|
319
|
+
}
|
320
|
+
|
321
|
+
//-----------------------------------------------------------------------------
|
322
|
+
// Exports
|
323
|
+
//-----------------------------------------------------------------------------
|
324
|
+
|
325
|
+
module.exports = {
|
326
|
+
parse,
|
327
|
+
matches,
|
328
|
+
ESQueryParsedSelector,
|
329
|
+
};
|
@@ -128,6 +128,17 @@ class FileContext {
|
|
128
128
|
getSourceCode() {
|
129
129
|
return this.sourceCode;
|
130
130
|
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* Creates a new object with the current object as the prototype and
|
134
|
+
* the specified properties as its own properties.
|
135
|
+
* @param {Object} extension The properties to add to the new object.
|
136
|
+
* @returns {FileContext} A new object with the current object as the prototype
|
137
|
+
* and the specified properties as its own properties.
|
138
|
+
*/
|
139
|
+
extend(extension) {
|
140
|
+
return Object.freeze(Object.assign(Object.create(this), extension));
|
141
|
+
}
|
131
142
|
}
|
132
143
|
|
133
144
|
exports.FileContext = FileContext;
|
package/lib/linter/linter.js
CHANGED
@@ -34,10 +34,8 @@ const path = require("node:path"),
|
|
34
34
|
SourceCodeFixer = require("./source-code-fixer"),
|
35
35
|
timing = require("./timing"),
|
36
36
|
ruleReplacements = require("../../conf/replacements.json");
|
37
|
-
const { getRuleFromConfig } = require("../config/flat-config-helpers");
|
38
37
|
const { FlatConfigArray } = require("../config/flat-config-array");
|
39
38
|
const { startTime, endTime } = require("../shared/stats");
|
40
|
-
const { RuleValidator } = require("../config/rule-validator");
|
41
39
|
const { assertIsRuleSeverity } = require("../config/flat-config-schema");
|
42
40
|
const {
|
43
41
|
normalizeSeverityToString,
|
@@ -66,6 +64,7 @@ const { ParserService } = require("../services/parser-service");
|
|
66
64
|
const { FileContext } = require("./file-context");
|
67
65
|
const { ProcessorService } = require("../services/processor-service");
|
68
66
|
const { containsDifferentProperty } = require("../shared/option-utils");
|
67
|
+
const { Config } = require("../config/config");
|
69
68
|
const STEP_KIND_VISIT = 1;
|
70
69
|
const STEP_KIND_CALL = 2;
|
71
70
|
|
@@ -73,20 +72,21 @@ const STEP_KIND_CALL = 2;
|
|
73
72
|
// Typedefs
|
74
73
|
//------------------------------------------------------------------------------
|
75
74
|
|
76
|
-
/** @
|
77
|
-
|
78
|
-
/** @typedef {import("../
|
79
|
-
/** @typedef {import("../
|
80
|
-
/** @typedef {import("../
|
81
|
-
/** @typedef {import("../
|
82
|
-
/** @typedef {import("../
|
83
|
-
/** @typedef {import("../
|
75
|
+
/** @import { Language, LanguageOptions, RuleConfig, RuleDefinition, RuleSeverity } from "@eslint/core" */
|
76
|
+
|
77
|
+
/** @typedef {import("../types").Linter.Config} Config */
|
78
|
+
/** @typedef {import("../types").ESLint.ConfigData} ConfigData */
|
79
|
+
/** @typedef {import("../types").ESLint.Environment} Environment */
|
80
|
+
/** @typedef {import("../types").Linter.GlobalConf} GlobalConf */
|
81
|
+
/** @typedef {import("../types").Linter.LanguageOptions} JSLanguageOptions */
|
82
|
+
/** @typedef {import("../types").Linter.LintMessage} LintMessage */
|
83
|
+
/** @typedef {import("../types").Linter.Parser} Parser */
|
84
|
+
/** @typedef {import("../types").Linter.ParserOptions} ParserOptions */
|
85
|
+
/** @typedef {import("../types").Linter.Processor} Processor */
|
84
86
|
/** @typedef {import("../types").Rule.RuleModule} Rule */
|
85
|
-
/** @typedef {import("../shared/types").Times} Times */
|
86
|
-
/** @typedef {import("@eslint/core").Language} Language */
|
87
|
-
/** @typedef {import("@eslint/core").RuleSeverity} RuleSeverity */
|
88
|
-
/** @typedef {import("@eslint/core").RuleConfig} RuleConfig */
|
89
87
|
/** @typedef {import("../types").Linter.StringSeverity} StringSeverity */
|
88
|
+
/** @typedef {import("../types").Linter.SuppressedLintMessage} SuppressedLintMessage */
|
89
|
+
/** @typedef {import("../types").Linter.TimePass} TimePass */
|
90
90
|
|
91
91
|
/* eslint-disable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/4#issuecomment-778805577 */
|
92
92
|
/**
|
@@ -111,7 +111,7 @@ const STEP_KIND_CALL = 2;
|
|
111
111
|
* @property {SourceCode|null} lastSourceCode The `SourceCode` instance that the last `verify()` call used.
|
112
112
|
* @property {SuppressedLintMessage[]} lastSuppressedMessages The `SuppressedLintMessage[]` instance that the last `verify()` call produced.
|
113
113
|
* @property {Map<string, Parser>} parserMap The loaded parsers.
|
114
|
-
* @property {
|
114
|
+
* @property {{ passes: TimePass[]; }} times The times spent on applying a rule to a file (see `stats` option).
|
115
115
|
* @property {Rules} ruleMap The loaded rules.
|
116
116
|
*/
|
117
117
|
|
@@ -351,7 +351,7 @@ function asArray(value) {
|
|
351
351
|
|
352
352
|
/**
|
353
353
|
* Pushes a problem to inlineConfigProblems if ruleOptions are redundant.
|
354
|
-
* @param {
|
354
|
+
* @param {Config} config Provided config.
|
355
355
|
* @param {Object} loc A line/column location
|
356
356
|
* @param {Array} problems Problems that may be added to.
|
357
357
|
* @param {string} ruleId The rule ID.
|
@@ -902,7 +902,7 @@ function normalizeFilename(filename) {
|
|
902
902
|
* Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
|
903
903
|
* consistent shape.
|
904
904
|
* @param {VerifyOptions} providedOptions Options
|
905
|
-
* @param {ConfigData} config Config.
|
905
|
+
* @param {Config|ConfigData} config Config.
|
906
906
|
* @returns {Required<VerifyOptions> & InternalOptions} Normalized options
|
907
907
|
*/
|
908
908
|
function normalizeVerifyOptions(providedOptions, config) {
|
@@ -1011,7 +1011,7 @@ function resolveParserOptions(parser, providedOptions, enabledEnvironments) {
|
|
1011
1011
|
* @param {Object} config.globals Global variable definitions.
|
1012
1012
|
* @param {Parser} config.parser The parser to use.
|
1013
1013
|
* @param {ParserOptions} config.parserOptions The parserOptions to use.
|
1014
|
-
* @returns {
|
1014
|
+
* @returns {JSLanguageOptions} The languageOptions equivalent.
|
1015
1015
|
*/
|
1016
1016
|
function createLanguageOptions({
|
1017
1017
|
globals: configuredGlobals,
|
@@ -1091,7 +1091,7 @@ function getRuleOptions(ruleConfig, defaultOptions) {
|
|
1091
1091
|
/**
|
1092
1092
|
* Analyze scope of the given AST.
|
1093
1093
|
* @param {ASTNode} ast The `Program` node to analyze.
|
1094
|
-
* @param {
|
1094
|
+
* @param {JSLanguageOptions} languageOptions The language options.
|
1095
1095
|
* @param {Record<string, string[]>} visitorKeys The visitor keys.
|
1096
1096
|
* @returns {ScopeManager} The analysis result.
|
1097
1097
|
*/
|
@@ -1113,7 +1113,7 @@ function analyzeScope(ast, languageOptions, visitorKeys) {
|
|
1113
1113
|
|
1114
1114
|
/**
|
1115
1115
|
* Runs a rule, and gets its listeners
|
1116
|
-
* @param {
|
1116
|
+
* @param {RuleDefinition} rule A rule object
|
1117
1117
|
* @param {Context} ruleContext The context that should be passed to the rule
|
1118
1118
|
* @throws {TypeError} If `rule` is not an object with a `create` method
|
1119
1119
|
* @throws {any} Any error during the rule's `create`
|
@@ -1142,7 +1142,7 @@ function createRuleListeners(rule, ruleContext) {
|
|
1142
1142
|
* Runs the given rules on the given SourceCode object
|
1143
1143
|
* @param {SourceCode} sourceCode A SourceCode object for the given text
|
1144
1144
|
* @param {Object} configuredRules The rules configuration
|
1145
|
-
* @param {function(string):
|
1145
|
+
* @param {function(string): RuleDefinition} ruleMapper A mapper function from rule names to rules
|
1146
1146
|
* @param {string | undefined} parserName The name of the parser in the config
|
1147
1147
|
* @param {Language} language The language object used for parsing.
|
1148
1148
|
* @param {LanguageOptions} languageOptions The options for parsing the code.
|
@@ -1185,7 +1185,7 @@ function runRules(
|
|
1185
1185
|
* All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
|
1186
1186
|
* properties once for each rule.
|
1187
1187
|
*/
|
1188
|
-
const
|
1188
|
+
const fileContext = new FileContext({
|
1189
1189
|
cwd,
|
1190
1190
|
filename,
|
1191
1191
|
physicalFilename: physicalFilename || filename,
|
@@ -1201,7 +1201,7 @@ function runRules(
|
|
1201
1201
|
const lintingProblems = [];
|
1202
1202
|
|
1203
1203
|
Object.keys(configuredRules).forEach(ruleId => {
|
1204
|
-
const severity =
|
1204
|
+
const severity = Config.getRuleNumericSeverity(configuredRules[ruleId]);
|
1205
1205
|
|
1206
1206
|
// not load disabled rules
|
1207
1207
|
if (severity === 0) {
|
@@ -1221,63 +1221,61 @@ function runRules(
|
|
1221
1221
|
|
1222
1222
|
const messageIds = rule.meta && rule.meta.messages;
|
1223
1223
|
let reportTranslator = null;
|
1224
|
-
const ruleContext =
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
const problem = reportTranslator(...args);
|
1224
|
+
const ruleContext = fileContext.extend({
|
1225
|
+
id: ruleId,
|
1226
|
+
options: getRuleOptions(
|
1227
|
+
configuredRules[ruleId],
|
1228
|
+
applyDefaultOptions ? rule.meta?.defaultOptions : void 0,
|
1229
|
+
),
|
1230
|
+
report(...args) {
|
1231
|
+
/*
|
1232
|
+
* Create a report translator lazily.
|
1233
|
+
* In a vast majority of cases, any given rule reports zero errors on a given
|
1234
|
+
* piece of code. Creating a translator lazily avoids the performance cost of
|
1235
|
+
* creating a new translator function for each rule that usually doesn't get
|
1236
|
+
* called.
|
1237
|
+
*
|
1238
|
+
* Using lazy report translators improves end-to-end performance by about 3%
|
1239
|
+
* with Node 8.4.0.
|
1240
|
+
*/
|
1241
|
+
if (reportTranslator === null) {
|
1242
|
+
reportTranslator = createReportTranslator({
|
1243
|
+
ruleId,
|
1244
|
+
severity,
|
1245
|
+
sourceCode,
|
1246
|
+
messageIds,
|
1247
|
+
disableFixes,
|
1248
|
+
language,
|
1249
|
+
});
|
1250
|
+
}
|
1251
|
+
const problem = reportTranslator(...args);
|
1253
1252
|
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1253
|
+
if (problem.fix && !(rule.meta && rule.meta.fixable)) {
|
1254
|
+
throw new Error(
|
1255
|
+
'Fixable rules must set the `meta.fixable` property to "code" or "whitespace".',
|
1256
|
+
);
|
1257
|
+
}
|
1258
|
+
if (
|
1259
|
+
problem.suggestions &&
|
1260
|
+
!(rule.meta && rule.meta.hasSuggestions === true)
|
1261
|
+
) {
|
1259
1262
|
if (
|
1260
|
-
|
1261
|
-
|
1263
|
+
rule.meta &&
|
1264
|
+
rule.meta.docs &&
|
1265
|
+
typeof rule.meta.docs.suggestion !== "undefined"
|
1262
1266
|
) {
|
1263
|
-
|
1264
|
-
rule.meta &&
|
1265
|
-
rule.meta.docs &&
|
1266
|
-
typeof rule.meta.docs.suggestion !== "undefined"
|
1267
|
-
) {
|
1268
|
-
// Encourage migration from the former property name.
|
1269
|
-
throw new Error(
|
1270
|
-
"Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.",
|
1271
|
-
);
|
1272
|
-
}
|
1267
|
+
// Encourage migration from the former property name.
|
1273
1268
|
throw new Error(
|
1274
|
-
"Rules with suggestions must set the `meta.hasSuggestions` property to `true`.",
|
1269
|
+
"Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.",
|
1275
1270
|
);
|
1276
1271
|
}
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1272
|
+
throw new Error(
|
1273
|
+
"Rules with suggestions must set the `meta.hasSuggestions` property to `true`.",
|
1274
|
+
);
|
1275
|
+
}
|
1276
|
+
lintingProblems.push(problem);
|
1277
|
+
},
|
1278
|
+
});
|
1281
1279
|
|
1282
1280
|
const ruleListenersReturn =
|
1283
1281
|
timing.enabled || stats
|
@@ -1886,7 +1884,7 @@ class Linter {
|
|
1886
1884
|
/**
|
1887
1885
|
* Verify with a processor.
|
1888
1886
|
* @param {string|SourceCode} textOrSourceCode The source code.
|
1889
|
-
* @param {
|
1887
|
+
* @param {Config} config The config array.
|
1890
1888
|
* @param {VerifyOptions&ProcessorOptions} options The options.
|
1891
1889
|
* @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
|
1892
1890
|
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
@@ -1987,7 +1985,7 @@ class Linter {
|
|
1987
1985
|
/**
|
1988
1986
|
* Verify using flat config and without any processors.
|
1989
1987
|
* @param {VFile} file The file to lint.
|
1990
|
-
* @param {
|
1988
|
+
* @param {Config} providedConfig An ESLintConfig instance to configure everything.
|
1991
1989
|
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
1992
1990
|
* @throws {Error} If during rule execution.
|
1993
1991
|
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
@@ -2101,15 +2099,12 @@ class Linter {
|
|
2101
2099
|
}),
|
2102
2100
|
);
|
2103
2101
|
|
2104
|
-
// next we need to verify information about the specified rules
|
2105
|
-
const ruleValidator = new RuleValidator();
|
2106
|
-
|
2107
2102
|
for (const {
|
2108
2103
|
config: inlineConfig,
|
2109
2104
|
loc,
|
2110
2105
|
} of inlineConfigResult.configs) {
|
2111
2106
|
Object.keys(inlineConfig.rules).forEach(ruleId => {
|
2112
|
-
const rule =
|
2107
|
+
const rule = config.getRuleDefinition(ruleId);
|
2113
2108
|
const ruleValue = inlineConfig.rules[ruleId];
|
2114
2109
|
|
2115
2110
|
if (!rule) {
|
@@ -2219,11 +2214,8 @@ class Linter {
|
|
2219
2214
|
}
|
2220
2215
|
|
2221
2216
|
if (shouldValidateOptions) {
|
2222
|
-
|
2223
|
-
|
2224
|
-
rules: {
|
2225
|
-
[ruleId]: ruleOptions,
|
2226
|
-
},
|
2217
|
+
config.validateRulesConfig({
|
2218
|
+
[ruleId]: ruleOptions,
|
2227
2219
|
});
|
2228
2220
|
}
|
2229
2221
|
|
@@ -2271,7 +2263,7 @@ class Linter {
|
|
2271
2263
|
options.allowInlineConfig && !options.warnInlineConfig
|
2272
2264
|
? getDirectiveCommentsForFlatConfig(
|
2273
2265
|
sourceCode,
|
2274
|
-
ruleId =>
|
2266
|
+
ruleId => config.getRuleDefinition(ruleId),
|
2275
2267
|
config.language,
|
2276
2268
|
)
|
2277
2269
|
: { problems: [], disableDirectives: [] };
|
@@ -2290,7 +2282,7 @@ class Linter {
|
|
2290
2282
|
lintingProblems = runRules(
|
2291
2283
|
sourceCode,
|
2292
2284
|
configuredRules,
|
2293
|
-
ruleId =>
|
2285
|
+
ruleId => config.getRuleDefinition(ruleId),
|
2294
2286
|
void 0,
|
2295
2287
|
config.language,
|
2296
2288
|
languageOptions,
|
@@ -2349,7 +2341,7 @@ class Linter {
|
|
2349
2341
|
/**
|
2350
2342
|
* Same as linter.verify, except without support for processors.
|
2351
2343
|
* @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
|
2352
|
-
* @param {
|
2344
|
+
* @param {Config} providedConfig An ESLintConfig instance to configure everything.
|
2353
2345
|
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
2354
2346
|
* @throws {Error} If during rule execution.
|
2355
2347
|
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
@@ -2620,7 +2612,7 @@ class Linter {
|
|
2620
2612
|
|
2621
2613
|
/**
|
2622
2614
|
* Gets the times spent on (parsing, fixing, linting) a file.
|
2623
|
-
* @returns {
|
2615
|
+
* @returns {{ passes: TimePass[]; }} The times.
|
2624
2616
|
*/
|
2625
2617
|
getTimes() {
|
2626
2618
|
return internalSlotsMap.get(this).times ?? { passes: [] };
|