eslint 8.55.0 → 9.0.0-alpha.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 +15 -15
- package/conf/rule-type-list.json +3 -1
- package/lib/api.js +1 -1
- package/lib/cli-engine/cli-engine.js +15 -4
- package/lib/cli-engine/formatters/formatters-meta.json +1 -29
- package/lib/cli.js +52 -10
- package/lib/config/default-config.js +3 -0
- package/lib/config/flat-config-array.js +0 -20
- package/lib/config/flat-config-helpers.js +41 -20
- package/lib/config/flat-config-schema.js +57 -26
- package/lib/config/rule-validator.js +27 -4
- package/lib/eslint/eslint-helpers.js +35 -22
- package/lib/eslint/eslint.js +856 -373
- package/lib/eslint/index.js +2 -2
- package/lib/eslint/legacy-eslint.js +722 -0
- package/lib/linter/apply-disable-directives.js +33 -5
- package/lib/linter/config-comment-parser.js +36 -2
- package/lib/linter/linter.js +100 -120
- package/lib/linter/rules.js +6 -15
- package/lib/options.js +17 -1
- package/lib/rule-tester/rule-tester.js +240 -272
- package/lib/rules/index.js +0 -2
- package/lib/rules/no-constant-binary-expression.js +1 -1
- package/lib/rules/no-constructor-return.js +1 -1
- package/lib/rules/no-empty-static-block.js +1 -1
- package/lib/rules/no-extra-semi.js +1 -1
- package/lib/rules/no-implicit-coercion.js +17 -1
- package/lib/rules/no-inner-declarations.js +1 -1
- package/lib/rules/no-invalid-regexp.js +1 -1
- package/lib/rules/no-invalid-this.js +1 -1
- package/lib/rules/no-mixed-spaces-and-tabs.js +1 -1
- package/lib/rules/no-new-native-nonconstructor.js +1 -1
- package/lib/rules/no-new-symbol.js +8 -1
- package/lib/rules/no-promise-executor-return.js +9 -6
- package/lib/rules/no-restricted-properties.js +15 -28
- package/lib/rules/no-sequences.js +1 -0
- package/lib/rules/no-unused-private-class-members.js +1 -1
- package/lib/shared/config-validator.js +44 -11
- package/lib/shared/severity.js +49 -0
- package/lib/shared/types.js +1 -1
- package/lib/source-code/source-code.js +3 -102
- package/lib/unsupported-api.js +3 -5
- package/package.json +12 -14
- package/lib/cli-engine/formatters/checkstyle.js +0 -60
- package/lib/cli-engine/formatters/compact.js +0 -60
- package/lib/cli-engine/formatters/jslint-xml.js +0 -41
- package/lib/cli-engine/formatters/junit.js +0 -82
- package/lib/cli-engine/formatters/tap.js +0 -95
- package/lib/cli-engine/formatters/unix.js +0 -58
- package/lib/cli-engine/formatters/visualstudio.js +0 -63
- package/lib/eslint/flat-eslint.js +0 -1149
- package/lib/rule-tester/flat-rule-tester.js +0 -1122
- package/lib/rules/require-jsdoc.js +0 -122
- package/lib/rules/valid-jsdoc.js +0 -516
@@ -16,6 +16,11 @@
|
|
16
16
|
//------------------------------------------------------------------------------
|
17
17
|
|
18
18
|
const escapeRegExp = require("escape-string-regexp");
|
19
|
+
const {
|
20
|
+
Legacy: {
|
21
|
+
ConfigOps
|
22
|
+
}
|
23
|
+
} = require("@eslint/eslintrc/universal");
|
19
24
|
|
20
25
|
/**
|
21
26
|
* Compares the locations of two objects in a source file
|
@@ -345,11 +350,11 @@ function applyDirectives(options) {
|
|
345
350
|
}
|
346
351
|
|
347
352
|
const unusedDisableDirectivesToReport = options.directives
|
348
|
-
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive));
|
353
|
+
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive) && !options.rulesToIgnore.has(directive.ruleId));
|
349
354
|
|
350
355
|
|
351
356
|
const unusedEnableDirectivesToReport = new Set(
|
352
|
-
options.directives.filter(directive => directive.unprocessedDirective.type === "enable")
|
357
|
+
options.directives.filter(directive => directive.unprocessedDirective.type === "enable" && !options.rulesToIgnore.has(directive.ruleId))
|
353
358
|
);
|
354
359
|
|
355
360
|
/*
|
@@ -410,11 +415,13 @@ function applyDirectives(options) {
|
|
410
415
|
* @param {{ruleId: (string|null), line: number, column: number}[]} options.problems
|
411
416
|
* A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
|
412
417
|
* @param {"off" | "warn" | "error"} options.reportUnusedDisableDirectives If `"warn"` or `"error"`, adds additional problems for unused directives
|
418
|
+
* @param {Object} options.configuredRules The rules configuration.
|
419
|
+
* @param {Function} options.ruleFilter A predicate function to filter which rules should be executed.
|
413
420
|
* @param {boolean} options.disableFixes If true, it doesn't make `fix` properties.
|
414
421
|
* @returns {{ruleId: (string|null), line: number, column: number, suppressions?: {kind: string, justification: string}}[]}
|
415
422
|
* An object with a list of reported problems, the suppressed of which contain the suppression information.
|
416
423
|
*/
|
417
|
-
module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirectives = "off" }) => {
|
424
|
+
module.exports = ({ directives, disableFixes, problems, configuredRules, ruleFilter, reportUnusedDisableDirectives = "off" }) => {
|
418
425
|
const blockDirectives = directives
|
419
426
|
.filter(directive => directive.type === "disable" || directive.type === "enable")
|
420
427
|
.map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
|
@@ -443,17 +450,38 @@ module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirec
|
|
443
450
|
}
|
444
451
|
}).sort(compareLocations);
|
445
452
|
|
453
|
+
// This determines a list of rules that are not being run by the given ruleFilter, if present.
|
454
|
+
const rulesToIgnore = configuredRules && ruleFilter
|
455
|
+
? new Set(Object.keys(configuredRules).filter(ruleId => {
|
456
|
+
const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
|
457
|
+
|
458
|
+
// Ignore for disabled rules.
|
459
|
+
if (severity === 0) {
|
460
|
+
return false;
|
461
|
+
}
|
462
|
+
|
463
|
+
return !ruleFilter({ severity, ruleId });
|
464
|
+
}))
|
465
|
+
: new Set();
|
466
|
+
|
467
|
+
// If no ruleId is supplied that means this directive is applied to all rules, so we can't determine if it's unused if any rules are filtered out.
|
468
|
+
if (rulesToIgnore.size > 0) {
|
469
|
+
rulesToIgnore.add(null);
|
470
|
+
}
|
471
|
+
|
446
472
|
const blockDirectivesResult = applyDirectives({
|
447
473
|
problems,
|
448
474
|
directives: blockDirectives,
|
449
475
|
disableFixes,
|
450
|
-
reportUnusedDisableDirectives
|
476
|
+
reportUnusedDisableDirectives,
|
477
|
+
rulesToIgnore
|
451
478
|
});
|
452
479
|
const lineDirectivesResult = applyDirectives({
|
453
480
|
problems: blockDirectivesResult.problems,
|
454
481
|
directives: lineDirectives,
|
455
482
|
disableFixes,
|
456
|
-
reportUnusedDisableDirectives
|
483
|
+
reportUnusedDisableDirectives,
|
484
|
+
rulesToIgnore
|
457
485
|
});
|
458
486
|
|
459
487
|
return reportUnusedDisableDirectives !== "off"
|
@@ -15,7 +15,10 @@ const levn = require("levn"),
|
|
15
15
|
Legacy: {
|
16
16
|
ConfigOps
|
17
17
|
}
|
18
|
-
} = require("@eslint/eslintrc/universal")
|
18
|
+
} = require("@eslint/eslintrc/universal"),
|
19
|
+
{
|
20
|
+
directivesPattern
|
21
|
+
} = require("../shared/directives");
|
19
22
|
|
20
23
|
const debug = require("debug")("eslint:config-comment-parser");
|
21
24
|
|
@@ -37,7 +40,7 @@ module.exports = class ConfigCommentParser {
|
|
37
40
|
|
38
41
|
/**
|
39
42
|
* Parses a list of "name:string_value" or/and "name" options divided by comma or
|
40
|
-
* whitespace. Used for "global"
|
43
|
+
* whitespace. Used for "global" comments.
|
41
44
|
* @param {string} string The string to parse.
|
42
45
|
* @param {Comment} comment The comment node which has the string.
|
43
46
|
* @returns {Object} Result map object of names and string values, or null values if no value was provided
|
@@ -148,4 +151,35 @@ module.exports = class ConfigCommentParser {
|
|
148
151
|
return items;
|
149
152
|
}
|
150
153
|
|
154
|
+
/**
|
155
|
+
* Extract the directive and the justification from a given directive comment and trim them.
|
156
|
+
* @param {string} value The comment text to extract.
|
157
|
+
* @returns {{directivePart: string, justificationPart: string}} The extracted directive and justification.
|
158
|
+
*/
|
159
|
+
extractDirectiveComment(value) {
|
160
|
+
const match = /\s-{2,}\s/u.exec(value);
|
161
|
+
|
162
|
+
if (!match) {
|
163
|
+
return { directivePart: value.trim(), justificationPart: "" };
|
164
|
+
}
|
165
|
+
|
166
|
+
const directive = value.slice(0, match.index).trim();
|
167
|
+
const justification = value.slice(match.index + match[0].length).trim();
|
168
|
+
|
169
|
+
return { directivePart: directive, justificationPart: justification };
|
170
|
+
}
|
171
|
+
|
172
|
+
/**
|
173
|
+
* Parses a directive comment into directive text and value.
|
174
|
+
* @param {Comment} comment The comment node with the directive to be parsed.
|
175
|
+
* @returns {{directiveText: string, directiveValue: string}} The directive text and value.
|
176
|
+
*/
|
177
|
+
parseDirective(comment) {
|
178
|
+
const { directivePart } = this.extractDirectiveComment(comment.value);
|
179
|
+
const match = directivesPattern.exec(directivePart);
|
180
|
+
const directiveText = match[1];
|
181
|
+
const directiveValue = directivePart.slice(match.index + directiveText.length);
|
182
|
+
|
183
|
+
return { directiveText, directiveValue };
|
184
|
+
}
|
151
185
|
};
|
package/lib/linter/linter.js
CHANGED
@@ -44,6 +44,7 @@ const { getRuleFromConfig } = require("../config/flat-config-helpers");
|
|
44
44
|
const { FlatConfigArray } = require("../config/flat-config-array");
|
45
45
|
const { RuleValidator } = require("../config/rule-validator");
|
46
46
|
const { assertIsRuleOptions, assertIsRuleSeverity } = require("../config/flat-config-schema");
|
47
|
+
const { normalizeSeverityToString } = require("../shared/severity");
|
47
48
|
const debug = require("debug")("eslint:linter");
|
48
49
|
const MAX_AUTOFIX_PASSES = 10;
|
49
50
|
const DEFAULT_PARSER_NAME = "espree";
|
@@ -104,6 +105,7 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|
104
105
|
* @property {string} [filename] the filename of the source code.
|
105
106
|
* @property {boolean | "off" | "warn" | "error"} [reportUnusedDisableDirectives] Adds reported errors for
|
106
107
|
* unused `eslint-disable` directives.
|
108
|
+
* @property {Function} [ruleFilter] A predicate function that determines whether a given rule should run.
|
107
109
|
*/
|
108
110
|
|
109
111
|
/**
|
@@ -316,24 +318,6 @@ function createDisableDirectives(options) {
|
|
316
318
|
return result;
|
317
319
|
}
|
318
320
|
|
319
|
-
/**
|
320
|
-
* Extract the directive and the justification from a given directive comment and trim them.
|
321
|
-
* @param {string} value The comment text to extract.
|
322
|
-
* @returns {{directivePart: string, justificationPart: string}} The extracted directive and justification.
|
323
|
-
*/
|
324
|
-
function extractDirectiveComment(value) {
|
325
|
-
const match = /\s-{2,}\s/u.exec(value);
|
326
|
-
|
327
|
-
if (!match) {
|
328
|
-
return { directivePart: value.trim(), justificationPart: "" };
|
329
|
-
}
|
330
|
-
|
331
|
-
const directive = value.slice(0, match.index).trim();
|
332
|
-
const justification = value.slice(match.index + match[0].length).trim();
|
333
|
-
|
334
|
-
return { directivePart: directive, justificationPart: justification };
|
335
|
-
}
|
336
|
-
|
337
321
|
/**
|
338
322
|
* Parses comments in file to extract file-specific config of rules, globals
|
339
323
|
* and environments and merges them with global config; also code blocks
|
@@ -355,7 +339,7 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig) {
|
|
355
339
|
});
|
356
340
|
|
357
341
|
sourceCode.getInlineConfigNodes().filter(token => token.type !== "Shebang").forEach(comment => {
|
358
|
-
const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
|
342
|
+
const { directivePart, justificationPart } = commentParser.extractDirectiveComment(comment.value);
|
359
343
|
|
360
344
|
const match = directivesPattern.exec(directivePart);
|
361
345
|
|
@@ -409,7 +393,7 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig) {
|
|
409
393
|
}
|
410
394
|
|
411
395
|
case "exported":
|
412
|
-
Object.assign(exportedVariables, commentParser.
|
396
|
+
Object.assign(exportedVariables, commentParser.parseListConfig(directiveValue, comment));
|
413
397
|
break;
|
414
398
|
|
415
399
|
case "globals":
|
@@ -456,6 +440,15 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig) {
|
|
456
440
|
try {
|
457
441
|
validator.validateRuleOptions(rule, name, ruleValue);
|
458
442
|
} catch (err) {
|
443
|
+
|
444
|
+
/*
|
445
|
+
* If the rule has invalid `meta.schema`, throw the error because
|
446
|
+
* this is not an invalid inline configuration but an invalid rule.
|
447
|
+
*/
|
448
|
+
if (err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA") {
|
449
|
+
throw err;
|
450
|
+
}
|
451
|
+
|
459
452
|
problems.push(createLintingProblem({
|
460
453
|
ruleId: name,
|
461
454
|
message: err.message,
|
@@ -500,7 +493,7 @@ function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper) {
|
|
500
493
|
const disableDirectives = [];
|
501
494
|
|
502
495
|
sourceCode.getInlineConfigNodes().filter(token => token.type !== "Shebang").forEach(comment => {
|
503
|
-
const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
|
496
|
+
const { directivePart, justificationPart } = commentParser.extractDirectiveComment(comment.value);
|
504
497
|
|
505
498
|
const match = directivesPattern.exec(directivePart);
|
506
499
|
|
@@ -620,7 +613,7 @@ function findEslintEnv(text) {
|
|
620
613
|
if (match[0].endsWith("*/")) {
|
621
614
|
retv = Object.assign(
|
622
615
|
retv || {},
|
623
|
-
commentParser.parseListConfig(extractDirectiveComment(match[1]).directivePart)
|
616
|
+
commentParser.parseListConfig(commentParser.extractDirectiveComment(match[1]).directivePart)
|
624
617
|
);
|
625
618
|
}
|
626
619
|
}
|
@@ -671,9 +664,17 @@ function normalizeVerifyOptions(providedOptions, config) {
|
|
671
664
|
reportUnusedDisableDirectives = reportUnusedDisableDirectives ? "error" : "off";
|
672
665
|
}
|
673
666
|
if (typeof reportUnusedDisableDirectives !== "string") {
|
674
|
-
reportUnusedDisableDirectives
|
675
|
-
linterOptions.reportUnusedDisableDirectives
|
676
|
-
|
667
|
+
if (typeof linterOptions.reportUnusedDisableDirectives === "boolean") {
|
668
|
+
reportUnusedDisableDirectives = linterOptions.reportUnusedDisableDirectives ? "warn" : "off";
|
669
|
+
} else {
|
670
|
+
reportUnusedDisableDirectives = linterOptions.reportUnusedDisableDirectives === void 0 ? "off" : normalizeSeverityToString(linterOptions.reportUnusedDisableDirectives);
|
671
|
+
}
|
672
|
+
}
|
673
|
+
|
674
|
+
let ruleFilter = providedOptions.ruleFilter;
|
675
|
+
|
676
|
+
if (typeof ruleFilter !== "function") {
|
677
|
+
ruleFilter = () => true;
|
677
678
|
}
|
678
679
|
|
679
680
|
return {
|
@@ -683,7 +684,8 @@ function normalizeVerifyOptions(providedOptions, config) {
|
|
683
684
|
? `your config${configNameOfNoInlineConfig}`
|
684
685
|
: null,
|
685
686
|
reportUnusedDisableDirectives,
|
686
|
-
disableFixes: Boolean(providedOptions.disableFixes)
|
687
|
+
disableFixes: Boolean(providedOptions.disableFixes),
|
688
|
+
ruleFilter
|
687
689
|
};
|
688
690
|
}
|
689
691
|
|
@@ -900,12 +902,18 @@ function parse(text, languageOptions, filePath) {
|
|
900
902
|
|
901
903
|
/**
|
902
904
|
* Runs a rule, and gets its listeners
|
903
|
-
* @param {Rule} rule A
|
905
|
+
* @param {Rule} rule A rule object
|
904
906
|
* @param {Context} ruleContext The context that should be passed to the rule
|
907
|
+
* @throws {TypeError} If `rule` is not an object with a `create` method
|
905
908
|
* @throws {any} Any error during the rule's `create`
|
906
909
|
* @returns {Object} A map of selector listeners provided by the rule
|
907
910
|
*/
|
908
911
|
function createRuleListeners(rule, ruleContext) {
|
912
|
+
|
913
|
+
if (!rule || typeof rule !== "object" || typeof rule.create !== "function") {
|
914
|
+
throw new TypeError(`Error while loading rule '${ruleContext.id}': Rule must be an object with a \`create\` method`);
|
915
|
+
}
|
916
|
+
|
909
917
|
try {
|
910
918
|
return rule.create(ruleContext);
|
911
919
|
} catch (ex) {
|
@@ -914,43 +922,6 @@ function createRuleListeners(rule, ruleContext) {
|
|
914
922
|
}
|
915
923
|
}
|
916
924
|
|
917
|
-
// methods that exist on SourceCode object
|
918
|
-
const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
|
919
|
-
getSource: "getText",
|
920
|
-
getSourceLines: "getLines",
|
921
|
-
getAllComments: "getAllComments",
|
922
|
-
getNodeByRangeIndex: "getNodeByRangeIndex",
|
923
|
-
getComments: "getComments",
|
924
|
-
getCommentsBefore: "getCommentsBefore",
|
925
|
-
getCommentsAfter: "getCommentsAfter",
|
926
|
-
getCommentsInside: "getCommentsInside",
|
927
|
-
getJSDocComment: "getJSDocComment",
|
928
|
-
getFirstToken: "getFirstToken",
|
929
|
-
getFirstTokens: "getFirstTokens",
|
930
|
-
getLastToken: "getLastToken",
|
931
|
-
getLastTokens: "getLastTokens",
|
932
|
-
getTokenAfter: "getTokenAfter",
|
933
|
-
getTokenBefore: "getTokenBefore",
|
934
|
-
getTokenByRangeStart: "getTokenByRangeStart",
|
935
|
-
getTokens: "getTokens",
|
936
|
-
getTokensAfter: "getTokensAfter",
|
937
|
-
getTokensBefore: "getTokensBefore",
|
938
|
-
getTokensBetween: "getTokensBetween"
|
939
|
-
};
|
940
|
-
|
941
|
-
|
942
|
-
const BASE_TRAVERSAL_CONTEXT = Object.freeze(
|
943
|
-
Object.keys(DEPRECATED_SOURCECODE_PASSTHROUGHS).reduce(
|
944
|
-
(contextInfo, methodName) =>
|
945
|
-
Object.assign(contextInfo, {
|
946
|
-
[methodName](...args) {
|
947
|
-
return this.sourceCode[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]](...args);
|
948
|
-
}
|
949
|
-
}),
|
950
|
-
{}
|
951
|
-
)
|
952
|
-
);
|
953
|
-
|
954
925
|
/**
|
955
926
|
* Runs the given rules on the given SourceCode object
|
956
927
|
* @param {SourceCode} sourceCode A SourceCode object for the given text
|
@@ -963,9 +934,10 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
|
|
963
934
|
* @param {boolean} disableFixes If true, it doesn't make `fix` properties.
|
964
935
|
* @param {string | undefined} cwd cwd of the cli
|
965
936
|
* @param {string} physicalFilename The full path of the file on disk without any code block information
|
937
|
+
* @param {Function} ruleFilter A predicate function to filter which rules should be executed.
|
966
938
|
* @returns {LintMessage[]} An array of reported problems
|
967
939
|
*/
|
968
|
-
function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageOptions, settings, filename, disableFixes, cwd, physicalFilename) {
|
940
|
+
function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageOptions, settings, filename, disableFixes, cwd, physicalFilename, ruleFilter) {
|
969
941
|
const emitter = createEmitter();
|
970
942
|
const nodeQueue = [];
|
971
943
|
let currentNode = sourceCode.ast;
|
@@ -987,30 +959,22 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
|
|
987
959
|
* properties once for each rule.
|
988
960
|
*/
|
989
961
|
const sharedTraversalContext = Object.freeze(
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
...languageOptions.parserOptions
|
1007
|
-
},
|
1008
|
-
parserPath: parserName,
|
1009
|
-
languageOptions,
|
1010
|
-
parserServices: sourceCode.parserServices,
|
1011
|
-
settings
|
1012
|
-
}
|
1013
|
-
)
|
962
|
+
{
|
963
|
+
getCwd: () => cwd,
|
964
|
+
cwd,
|
965
|
+
getFilename: () => filename,
|
966
|
+
filename,
|
967
|
+
getPhysicalFilename: () => physicalFilename || filename,
|
968
|
+
physicalFilename: physicalFilename || filename,
|
969
|
+
getSourceCode: () => sourceCode,
|
970
|
+
sourceCode,
|
971
|
+
parserOptions: {
|
972
|
+
...languageOptions.parserOptions
|
973
|
+
},
|
974
|
+
parserPath: parserName,
|
975
|
+
languageOptions,
|
976
|
+
settings
|
977
|
+
}
|
1014
978
|
);
|
1015
979
|
|
1016
980
|
const lintingProblems = [];
|
@@ -1023,6 +987,10 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
|
|
1023
987
|
return;
|
1024
988
|
}
|
1025
989
|
|
990
|
+
if (ruleFilter && !ruleFilter({ ruleId, severity })) {
|
991
|
+
return;
|
992
|
+
}
|
993
|
+
|
1026
994
|
const rule = ruleMapper(ruleId);
|
1027
995
|
|
1028
996
|
if (!rule) {
|
@@ -1232,9 +1200,9 @@ class Linter {
|
|
1232
1200
|
* Initialize the Linter.
|
1233
1201
|
* @param {Object} [config] the config object
|
1234
1202
|
* @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
|
1235
|
-
* @param {"flat"|"eslintrc"} [config.configType="
|
1203
|
+
* @param {"flat"|"eslintrc"} [config.configType="flat"] the type of config used.
|
1236
1204
|
*/
|
1237
|
-
constructor({ cwd, configType } = {}) {
|
1205
|
+
constructor({ cwd, configType = "flat" } = {}) {
|
1238
1206
|
internalSlotsMap.set(this, {
|
1239
1207
|
cwd: normalizeCwd(cwd),
|
1240
1208
|
lastConfigArray: null,
|
@@ -1377,7 +1345,8 @@ class Linter {
|
|
1377
1345
|
options.filename,
|
1378
1346
|
options.disableFixes,
|
1379
1347
|
slots.cwd,
|
1380
|
-
providedOptions.physicalFilename
|
1348
|
+
providedOptions.physicalFilename,
|
1349
|
+
null
|
1381
1350
|
);
|
1382
1351
|
} catch (err) {
|
1383
1352
|
err.message += `\nOccurred while linting ${options.filename}`;
|
@@ -1428,29 +1397,29 @@ class Linter {
|
|
1428
1397
|
? { filename: filenameOrOptions }
|
1429
1398
|
: filenameOrOptions || {};
|
1430
1399
|
|
1431
|
-
|
1432
|
-
if (configType === "flat") {
|
1433
|
-
|
1434
|
-
/*
|
1435
|
-
* Because of how Webpack packages up the files, we can't
|
1436
|
-
* compare directly to `FlatConfigArray` using `instanceof`
|
1437
|
-
* because it's not the same `FlatConfigArray` as in the tests.
|
1438
|
-
* So, we work around it by assuming an array is, in fact, a
|
1439
|
-
* `FlatConfigArray` if it has a `getConfig()` method.
|
1440
|
-
*/
|
1441
|
-
let configArray = config;
|
1442
|
-
|
1443
|
-
if (!Array.isArray(config) || typeof config.getConfig !== "function") {
|
1444
|
-
configArray = new FlatConfigArray(config, { basePath: cwd });
|
1445
|
-
configArray.normalizeSync();
|
1446
|
-
}
|
1400
|
+
const configToUse = config ?? {};
|
1447
1401
|
|
1448
|
-
|
1449
|
-
}
|
1402
|
+
if (configType !== "eslintrc") {
|
1450
1403
|
|
1451
|
-
|
1452
|
-
|
1404
|
+
/*
|
1405
|
+
* Because of how Webpack packages up the files, we can't
|
1406
|
+
* compare directly to `FlatConfigArray` using `instanceof`
|
1407
|
+
* because it's not the same `FlatConfigArray` as in the tests.
|
1408
|
+
* So, we work around it by assuming an array is, in fact, a
|
1409
|
+
* `FlatConfigArray` if it has a `getConfig()` method.
|
1410
|
+
*/
|
1411
|
+
let configArray = configToUse;
|
1412
|
+
|
1413
|
+
if (!Array.isArray(configToUse) || typeof configToUse.getConfig !== "function") {
|
1414
|
+
configArray = new FlatConfigArray(configToUse, { basePath: cwd });
|
1415
|
+
configArray.normalizeSync();
|
1453
1416
|
}
|
1417
|
+
|
1418
|
+
return this._distinguishSuppressedMessages(this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true));
|
1419
|
+
}
|
1420
|
+
|
1421
|
+
if (typeof configToUse.extractConfig === "function") {
|
1422
|
+
return this._distinguishSuppressedMessages(this._verifyWithConfigArray(textOrSourceCode, configToUse, options));
|
1454
1423
|
}
|
1455
1424
|
|
1456
1425
|
/*
|
@@ -1463,9 +1432,9 @@ class Linter {
|
|
1463
1432
|
* So we cannot apply multiple processors.
|
1464
1433
|
*/
|
1465
1434
|
if (options.preprocess || options.postprocess) {
|
1466
|
-
return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode,
|
1435
|
+
return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode, configToUse, options));
|
1467
1436
|
}
|
1468
|
-
return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode,
|
1437
|
+
return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode, configToUse, options));
|
1469
1438
|
}
|
1470
1439
|
|
1471
1440
|
/**
|
@@ -1708,6 +1677,14 @@ class Linter {
|
|
1708
1677
|
mergedInlineConfig.rules[ruleId] = ruleValue;
|
1709
1678
|
} catch (err) {
|
1710
1679
|
|
1680
|
+
/*
|
1681
|
+
* If the rule has invalid `meta.schema`, throw the error because
|
1682
|
+
* this is not an invalid inline configuration but an invalid rule.
|
1683
|
+
*/
|
1684
|
+
if (err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA") {
|
1685
|
+
throw err;
|
1686
|
+
}
|
1687
|
+
|
1711
1688
|
let baseMessage = err.message.slice(
|
1712
1689
|
err.message.startsWith("Key \"rules\":")
|
1713
1690
|
? err.message.indexOf(":", 12) + 1
|
@@ -1752,7 +1729,8 @@ class Linter {
|
|
1752
1729
|
options.filename,
|
1753
1730
|
options.disableFixes,
|
1754
1731
|
slots.cwd,
|
1755
|
-
providedOptions.physicalFilename
|
1732
|
+
providedOptions.physicalFilename,
|
1733
|
+
options.ruleFilter
|
1756
1734
|
);
|
1757
1735
|
} catch (err) {
|
1758
1736
|
err.message += `\nOccurred while linting ${options.filename}`;
|
@@ -1783,7 +1761,9 @@ class Linter {
|
|
1783
1761
|
.concat(commentDirectives.problems)
|
1784
1762
|
.concat(inlineConfigProblems)
|
1785
1763
|
.sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column),
|
1786
|
-
reportUnusedDisableDirectives: options.reportUnusedDisableDirectives
|
1764
|
+
reportUnusedDisableDirectives: options.reportUnusedDisableDirectives,
|
1765
|
+
ruleFilter: options.ruleFilter,
|
1766
|
+
configuredRules
|
1787
1767
|
});
|
1788
1768
|
}
|
1789
1769
|
|
@@ -2001,17 +1981,17 @@ class Linter {
|
|
2001
1981
|
/**
|
2002
1982
|
* Defines a new linting rule.
|
2003
1983
|
* @param {string} ruleId A unique rule identifier
|
2004
|
-
* @param {
|
1984
|
+
* @param {Rule} rule A rule object
|
2005
1985
|
* @returns {void}
|
2006
1986
|
*/
|
2007
|
-
defineRule(ruleId,
|
1987
|
+
defineRule(ruleId, rule) {
|
2008
1988
|
assertEslintrcConfig(this);
|
2009
|
-
internalSlotsMap.get(this).ruleMap.define(ruleId,
|
1989
|
+
internalSlotsMap.get(this).ruleMap.define(ruleId, rule);
|
2010
1990
|
}
|
2011
1991
|
|
2012
1992
|
/**
|
2013
1993
|
* Defines many new linting rules.
|
2014
|
-
* @param {Record<string,
|
1994
|
+
* @param {Record<string, Rule>} rulesToDefine map from unique rule identifier to rule
|
2015
1995
|
* @returns {void}
|
2016
1996
|
*/
|
2017
1997
|
defineRules(rulesToDefine) {
|
package/lib/linter/rules.js
CHANGED
@@ -13,18 +13,10 @@
|
|
13
13
|
const builtInRules = require("../rules");
|
14
14
|
|
15
15
|
//------------------------------------------------------------------------------
|
16
|
-
//
|
16
|
+
// Typedefs
|
17
17
|
//------------------------------------------------------------------------------
|
18
18
|
|
19
|
-
/**
|
20
|
-
* Normalizes a rule module to the new-style API
|
21
|
-
* @param {(Function|{create: Function})} rule A rule object, which can either be a function
|
22
|
-
* ("old-style") or an object with a `create` method ("new-style")
|
23
|
-
* @returns {{create: Function}} A new-style rule.
|
24
|
-
*/
|
25
|
-
function normalizeRule(rule) {
|
26
|
-
return typeof rule === "function" ? Object.assign({ create: rule }, rule) : rule;
|
27
|
-
}
|
19
|
+
/** @typedef {import("../shared/types").Rule} Rule */
|
28
20
|
|
29
21
|
//------------------------------------------------------------------------------
|
30
22
|
// Public Interface
|
@@ -41,18 +33,17 @@ class Rules {
|
|
41
33
|
/**
|
42
34
|
* Registers a rule module for rule id in storage.
|
43
35
|
* @param {string} ruleId Rule id (file name).
|
44
|
-
* @param {
|
36
|
+
* @param {Rule} rule Rule object.
|
45
37
|
* @returns {void}
|
46
38
|
*/
|
47
|
-
define(ruleId,
|
48
|
-
this._rules[ruleId] =
|
39
|
+
define(ruleId, rule) {
|
40
|
+
this._rules[ruleId] = rule;
|
49
41
|
}
|
50
42
|
|
51
43
|
/**
|
52
44
|
* Access rule handler by id (file name).
|
53
45
|
* @param {string} ruleId Rule id (file name).
|
54
|
-
* @returns {
|
55
|
-
* A rule. This is normalized to always have the new-style shape with a `create` method.
|
46
|
+
* @returns {Rule} Rule object.
|
56
47
|
*/
|
57
48
|
get(ruleId) {
|
58
49
|
if (typeof this._rules[ruleId] === "string") {
|
package/lib/options.js
CHANGED
@@ -48,6 +48,7 @@ const optionator = require("optionator");
|
|
48
48
|
* @property {string[]} [plugin] Specify plugins
|
49
49
|
* @property {string} [printConfig] Print the configuration for the given file
|
50
50
|
* @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable and eslint-enable directives
|
51
|
+
* @property {string | undefined} reportUnusedDisableDirectivesSeverity A severity string indicating if and how unused disable and enable directives should be tracked and reported.
|
51
52
|
* @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default
|
52
53
|
* @property {Object} [rule] Specify rules
|
53
54
|
* @property {string[]} [rulesdir] Load additional rules from this directory. Deprecated: Use rules from plugins
|
@@ -56,6 +57,8 @@ const optionator = require("optionator");
|
|
56
57
|
* @property {boolean} quiet Report errors only
|
57
58
|
* @property {boolean} [version] Output the version number
|
58
59
|
* @property {boolean} warnIgnored Show warnings when the file list includes ignored files
|
60
|
+
* @property {boolean} [passOnNoPatterns=false] When set to true, missing patterns cause
|
61
|
+
* the linting operation to short circuit and not report any failures.
|
59
62
|
* @property {string[]} _ Positional filenames or patterns
|
60
63
|
*/
|
61
64
|
|
@@ -167,7 +170,7 @@ module.exports = function(usingFlatConfig) {
|
|
167
170
|
alias: "c",
|
168
171
|
type: "path::String",
|
169
172
|
description: usingFlatConfig
|
170
|
-
? "Use this configuration instead of eslint.config.js"
|
173
|
+
? "Use this configuration instead of eslint.config.js, eslint.config.mjs, or eslint.config.cjs"
|
171
174
|
: "Use this configuration, overriding .eslintrc.* config options if present"
|
172
175
|
},
|
173
176
|
envFlag,
|
@@ -306,6 +309,13 @@ module.exports = function(usingFlatConfig) {
|
|
306
309
|
default: void 0,
|
307
310
|
description: "Adds reported errors for unused eslint-disable and eslint-enable directives"
|
308
311
|
},
|
312
|
+
{
|
313
|
+
option: "report-unused-disable-directives-severity",
|
314
|
+
type: "String",
|
315
|
+
default: void 0,
|
316
|
+
description: "Chooses severity level for reporting unused eslint-disable and eslint-enable directives",
|
317
|
+
enum: ["off", "warn", "error", "0", "1", "2"]
|
318
|
+
},
|
309
319
|
{
|
310
320
|
heading: "Caching"
|
311
321
|
},
|
@@ -362,6 +372,12 @@ module.exports = function(usingFlatConfig) {
|
|
362
372
|
description: "Exit with exit code 2 in case of fatal error"
|
363
373
|
},
|
364
374
|
warnIgnoredFlag,
|
375
|
+
{
|
376
|
+
option: "pass-on-no-patterns",
|
377
|
+
type: "Boolean",
|
378
|
+
default: false,
|
379
|
+
description: "Exit with exit code 0 in case no file patterns are passed"
|
380
|
+
},
|
365
381
|
{
|
366
382
|
option: "debug",
|
367
383
|
type: "Boolean",
|