eslint 9.39.1 → 10.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 +3 -3
- package/bin/eslint.js +1 -2
- package/lib/api.js +4 -15
- package/lib/cli.js +14 -56
- package/lib/config/config-loader.js +6 -154
- package/lib/eslint/eslint-helpers.js +5 -8
- package/lib/eslint/eslint.js +1 -1
- package/lib/eslint/index.js +0 -2
- package/lib/languages/js/source-code/source-code.js +39 -87
- package/lib/languages/js/source-code/token-store/utils.js +29 -8
- package/lib/linter/apply-disable-directives.js +0 -1
- package/lib/linter/file-context.js +0 -56
- package/lib/linter/file-report.js +0 -4
- package/lib/linter/linter.js +45 -1086
- package/lib/linter/rule-fixer.js +30 -0
- package/lib/options.js +62 -182
- package/lib/rule-tester/rule-tester.js +255 -194
- package/lib/rules/dot-notation.js +2 -2
- package/lib/rules/func-names.js +2 -0
- package/lib/rules/no-eval.js +1 -1
- package/lib/rules/no-invalid-regexp.js +1 -0
- package/lib/rules/no-shadow-restricted-names.js +1 -1
- package/lib/rules/no-unassigned-vars.js +1 -1
- package/lib/rules/no-useless-assignment.js +1 -1
- package/lib/rules/preserve-caught-error.js +1 -1
- package/lib/rules/radix.js +25 -48
- package/lib/services/parser-service.js +0 -1
- package/lib/services/processor-service.js +0 -1
- package/lib/services/warning-service.js +0 -11
- package/lib/shared/flags.js +0 -19
- package/lib/shared/translate-cli-options.js +106 -164
- package/lib/types/index.d.ts +7 -60
- package/lib/types/rules.d.ts +11 -2
- package/lib/types/use-at-your-own-risk.d.ts +1 -54
- package/lib/unsupported-api.js +3 -6
- package/package.json +14 -19
- package/conf/default-cli-options.js +0 -32
- package/lib/cli-engine/cli-engine.js +0 -1109
- package/lib/cli-engine/file-enumerator.js +0 -541
- package/lib/cli-engine/index.js +0 -7
- package/lib/cli-engine/load-rules.js +0 -46
- package/lib/eslint/legacy-eslint.js +0 -786
package/lib/linter/linter.js
CHANGED
|
@@ -13,21 +13,11 @@
|
|
|
13
13
|
const path = require("node:path"),
|
|
14
14
|
eslintScope = require("eslint-scope"),
|
|
15
15
|
evk = require("eslint-visitor-keys"),
|
|
16
|
-
espree = require("espree"),
|
|
17
|
-
merge = require("lodash.merge"),
|
|
18
16
|
pkg = require("../../package.json"),
|
|
19
|
-
{
|
|
20
|
-
Legacy: {
|
|
21
|
-
ConfigOps,
|
|
22
|
-
ConfigValidator,
|
|
23
|
-
environments: BuiltInEnvironments,
|
|
24
|
-
},
|
|
25
|
-
} = require("@eslint/eslintrc/universal"),
|
|
26
17
|
Traverser = require("../shared/traverser"),
|
|
27
18
|
{ SourceCode } = require("../languages/js/source-code"),
|
|
28
19
|
applyDisableDirectives = require("./apply-disable-directives"),
|
|
29
20
|
{ ConfigCommentParser } = require("@eslint/plugin-kit"),
|
|
30
|
-
Rules = require("./rules"),
|
|
31
21
|
SourceCodeFixer = require("./source-code-fixer"),
|
|
32
22
|
{ SourceCodeVisitor } = require("./source-code-visitor"),
|
|
33
23
|
timing = require("./timing");
|
|
@@ -39,7 +29,6 @@ const {
|
|
|
39
29
|
normalizeSeverityToNumber,
|
|
40
30
|
} = require("../shared/severity");
|
|
41
31
|
const { deepMergeArrays } = require("../shared/deep-merge-arrays");
|
|
42
|
-
const jslang = require("../languages/js");
|
|
43
32
|
const {
|
|
44
33
|
activeFlags,
|
|
45
34
|
inactiveFlags,
|
|
@@ -47,11 +36,8 @@ const {
|
|
|
47
36
|
} = require("../shared/flags");
|
|
48
37
|
const debug = require("debug")("eslint:linter");
|
|
49
38
|
const MAX_AUTOFIX_PASSES = 10;
|
|
50
|
-
const DEFAULT_PARSER_NAME = "espree";
|
|
51
39
|
const DEFAULT_ECMA_VERSION = 5;
|
|
52
40
|
const commentParser = new ConfigCommentParser();
|
|
53
|
-
const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
|
54
|
-
const { LATEST_ECMA_VERSION } = require("../../conf/ecma-version");
|
|
55
41
|
const { VFile } = require("./vfile");
|
|
56
42
|
const { ParserService } = require("../services/parser-service");
|
|
57
43
|
const { FileContext } = require("./file-context");
|
|
@@ -66,7 +52,7 @@ const { FileReport, updateLocationInformation } = require("./file-report");
|
|
|
66
52
|
// Typedefs
|
|
67
53
|
//------------------------------------------------------------------------------
|
|
68
54
|
|
|
69
|
-
/** @import { Language, LanguageOptions, RuleConfig, RuleDefinition
|
|
55
|
+
/** @import { Language, LanguageOptions, RuleConfig, RuleDefinition } from "@eslint/core" */
|
|
70
56
|
|
|
71
57
|
/** @typedef {import("../types").Linter.Config} Config */
|
|
72
58
|
/** @typedef {import("../types").ESLint.ConfigData} ConfigData */
|
|
@@ -104,9 +90,7 @@ const { FileReport, updateLocationInformation } = require("./file-report");
|
|
|
104
90
|
* @property {ConfigArray|null} lastConfigArray The `ConfigArray` instance that the last `verify()` call used.
|
|
105
91
|
* @property {SourceCode|null} lastSourceCode The `SourceCode` instance that the last `verify()` call used.
|
|
106
92
|
* @property {SuppressedLintMessage[]} lastSuppressedMessages The `SuppressedLintMessage[]` instance that the last `verify()` call produced.
|
|
107
|
-
* @property {Map<string, Parser>} parserMap The loaded parsers.
|
|
108
93
|
* @property {{ passes: TimePass[]; }} times The times spent on applying a rule to a file (see `stats` option).
|
|
109
|
-
* @property {Rules} ruleMap The loaded rules.
|
|
110
94
|
* @property {WarningService} warningService The warning service.
|
|
111
95
|
*/
|
|
112
96
|
|
|
@@ -154,100 +138,6 @@ const { FileReport, updateLocationInformation } = require("./file-report");
|
|
|
154
138
|
// Helpers
|
|
155
139
|
//------------------------------------------------------------------------------
|
|
156
140
|
|
|
157
|
-
/**
|
|
158
|
-
* Determines if a given object is Espree.
|
|
159
|
-
* @param {Object} parser The parser to check.
|
|
160
|
-
* @returns {boolean} True if the parser is Espree or false if not.
|
|
161
|
-
*/
|
|
162
|
-
function isEspree(parser) {
|
|
163
|
-
return !!(parser === espree || parser[parserSymbol] === espree);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Ensures that variables representing built-in properties of the Global Object,
|
|
168
|
-
* and any globals declared by special block comments, are present in the global
|
|
169
|
-
* scope.
|
|
170
|
-
* @param {Scope} globalScope The global scope.
|
|
171
|
-
* @param {Object} configGlobals The globals declared in configuration
|
|
172
|
-
* @param {{exportedVariables: Object, enabledGlobals: Object}} commentDirectives Directives from comment configuration
|
|
173
|
-
* @returns {void}
|
|
174
|
-
*/
|
|
175
|
-
function addDeclaredGlobals(
|
|
176
|
-
globalScope,
|
|
177
|
-
configGlobals,
|
|
178
|
-
{ exportedVariables, enabledGlobals },
|
|
179
|
-
) {
|
|
180
|
-
// Define configured global variables.
|
|
181
|
-
for (const id of new Set([
|
|
182
|
-
...Object.keys(configGlobals),
|
|
183
|
-
...Object.keys(enabledGlobals),
|
|
184
|
-
])) {
|
|
185
|
-
/*
|
|
186
|
-
* `ConfigOps.normalizeConfigGlobal` will throw an error if a configured global value is invalid. However, these errors would
|
|
187
|
-
* typically be caught when validating a config anyway (validity for inline global comments is checked separately).
|
|
188
|
-
*/
|
|
189
|
-
const configValue =
|
|
190
|
-
configGlobals[id] === void 0
|
|
191
|
-
? void 0
|
|
192
|
-
: ConfigOps.normalizeConfigGlobal(configGlobals[id]);
|
|
193
|
-
const commentValue = enabledGlobals[id] && enabledGlobals[id].value;
|
|
194
|
-
const value = commentValue || configValue;
|
|
195
|
-
const sourceComments =
|
|
196
|
-
enabledGlobals[id] && enabledGlobals[id].comments;
|
|
197
|
-
|
|
198
|
-
if (value === "off") {
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
let variable = globalScope.set.get(id);
|
|
203
|
-
|
|
204
|
-
if (!variable) {
|
|
205
|
-
variable = new eslintScope.Variable(id, globalScope);
|
|
206
|
-
|
|
207
|
-
globalScope.variables.push(variable);
|
|
208
|
-
globalScope.set.set(id, variable);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
variable.eslintImplicitGlobalSetting = configValue;
|
|
212
|
-
variable.eslintExplicitGlobal = sourceComments !== void 0;
|
|
213
|
-
variable.eslintExplicitGlobalComments = sourceComments;
|
|
214
|
-
variable.writeable = value === "writable";
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// mark all exported variables as such
|
|
218
|
-
Object.keys(exportedVariables).forEach(name => {
|
|
219
|
-
const variable = globalScope.set.get(name);
|
|
220
|
-
|
|
221
|
-
if (variable) {
|
|
222
|
-
variable.eslintUsed = true;
|
|
223
|
-
variable.eslintExported = true;
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
/*
|
|
228
|
-
* "through" contains all references which definitions cannot be found.
|
|
229
|
-
* Since we augment the global scope using configuration, we need to update
|
|
230
|
-
* references and remove the ones that were added by configuration.
|
|
231
|
-
*/
|
|
232
|
-
globalScope.through = globalScope.through.filter(reference => {
|
|
233
|
-
const name = reference.identifier.name;
|
|
234
|
-
const variable = globalScope.set.get(name);
|
|
235
|
-
|
|
236
|
-
if (variable) {
|
|
237
|
-
/*
|
|
238
|
-
* Links the variable and the reference.
|
|
239
|
-
* And this reference is removed from `Scope#through`.
|
|
240
|
-
*/
|
|
241
|
-
reference.resolved = variable;
|
|
242
|
-
variable.references.push(reference);
|
|
243
|
-
|
|
244
|
-
return false;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return true;
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
|
|
251
141
|
/**
|
|
252
142
|
* Wraps the value in an Array if it isn't already one.
|
|
253
143
|
* @template T
|
|
@@ -395,257 +285,6 @@ function createDisableDirectives(
|
|
|
395
285
|
return directives;
|
|
396
286
|
}
|
|
397
287
|
|
|
398
|
-
/**
|
|
399
|
-
* Parses comments in file to extract file-specific config of rules, globals
|
|
400
|
-
* and environments and merges them with global config; also code blocks
|
|
401
|
-
* where reporting is disabled or enabled and merges them with reporting config.
|
|
402
|
-
* @param {SourceCode} sourceCode The SourceCode object to get comments from.
|
|
403
|
-
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
|
404
|
-
* @param {string|null} warnInlineConfig If a string then it should warn directive comments as disabled. The string value is the config name what the setting came from.
|
|
405
|
-
* @param {ConfigData} config Provided config.
|
|
406
|
-
* @param {FileReport} report The report to add problems to.
|
|
407
|
-
* @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, disableDirectives: DisableDirective[]}}
|
|
408
|
-
* A collection of the directive comments that were found, along with any problems that occurred when parsing
|
|
409
|
-
*/
|
|
410
|
-
function getDirectiveComments(
|
|
411
|
-
sourceCode,
|
|
412
|
-
ruleMapper,
|
|
413
|
-
warnInlineConfig,
|
|
414
|
-
config,
|
|
415
|
-
report,
|
|
416
|
-
) {
|
|
417
|
-
const configuredRules = {};
|
|
418
|
-
const enabledGlobals = Object.create(null);
|
|
419
|
-
const exportedVariables = {};
|
|
420
|
-
const disableDirectives = [];
|
|
421
|
-
const validator = new ConfigValidator({
|
|
422
|
-
builtInRules: Rules,
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
sourceCode
|
|
426
|
-
.getInlineConfigNodes()
|
|
427
|
-
.filter(token => token.type !== "Shebang")
|
|
428
|
-
.forEach(comment => {
|
|
429
|
-
const directive = commentParser.parseDirective(comment.value);
|
|
430
|
-
|
|
431
|
-
if (!directive) {
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
const {
|
|
436
|
-
label,
|
|
437
|
-
value,
|
|
438
|
-
justification: justificationPart,
|
|
439
|
-
} = directive;
|
|
440
|
-
|
|
441
|
-
const lineCommentSupported =
|
|
442
|
-
/^eslint-disable-(?:next-)?line$/u.test(label);
|
|
443
|
-
|
|
444
|
-
if (comment.type === "Line" && !lineCommentSupported) {
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
const loc = sourceCode.getLoc(comment);
|
|
449
|
-
|
|
450
|
-
if (warnInlineConfig) {
|
|
451
|
-
const kind =
|
|
452
|
-
comment.type === "Block" ? `/*${label}*/` : `//${label}`;
|
|
453
|
-
|
|
454
|
-
report.addWarning({
|
|
455
|
-
ruleId: null,
|
|
456
|
-
message: `'${kind}' has no effect because you have 'noInlineConfig' setting in ${warnInlineConfig}.`,
|
|
457
|
-
loc,
|
|
458
|
-
});
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
if (
|
|
463
|
-
label === "eslint-disable-line" &&
|
|
464
|
-
loc.start.line !== loc.end.line
|
|
465
|
-
) {
|
|
466
|
-
const message = `${label} comment should not span multiple lines.`;
|
|
467
|
-
|
|
468
|
-
report.addError({
|
|
469
|
-
message,
|
|
470
|
-
loc,
|
|
471
|
-
});
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
switch (label) {
|
|
476
|
-
case "eslint-disable":
|
|
477
|
-
case "eslint-enable":
|
|
478
|
-
case "eslint-disable-next-line":
|
|
479
|
-
case "eslint-disable-line": {
|
|
480
|
-
const directiveType = label.slice("eslint-".length);
|
|
481
|
-
const directives = createDisableDirectives(
|
|
482
|
-
{
|
|
483
|
-
type: directiveType,
|
|
484
|
-
value,
|
|
485
|
-
justification: justificationPart,
|
|
486
|
-
node: comment,
|
|
487
|
-
},
|
|
488
|
-
ruleMapper,
|
|
489
|
-
jslang,
|
|
490
|
-
sourceCode,
|
|
491
|
-
report,
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
disableDirectives.push(...directives);
|
|
495
|
-
break;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
case "exported":
|
|
499
|
-
Object.assign(
|
|
500
|
-
exportedVariables,
|
|
501
|
-
commentParser.parseListConfig(value),
|
|
502
|
-
);
|
|
503
|
-
break;
|
|
504
|
-
|
|
505
|
-
case "globals":
|
|
506
|
-
case "global":
|
|
507
|
-
for (const [id, idSetting] of Object.entries(
|
|
508
|
-
commentParser.parseStringConfig(value),
|
|
509
|
-
)) {
|
|
510
|
-
let normalizedValue;
|
|
511
|
-
|
|
512
|
-
try {
|
|
513
|
-
normalizedValue =
|
|
514
|
-
ConfigOps.normalizeConfigGlobal(idSetting);
|
|
515
|
-
} catch (err) {
|
|
516
|
-
report.addError({
|
|
517
|
-
loc,
|
|
518
|
-
message: err.message,
|
|
519
|
-
});
|
|
520
|
-
continue;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
if (enabledGlobals[id]) {
|
|
524
|
-
enabledGlobals[id].comments.push(comment);
|
|
525
|
-
enabledGlobals[id].value = normalizedValue;
|
|
526
|
-
} else {
|
|
527
|
-
enabledGlobals[id] = {
|
|
528
|
-
comments: [comment],
|
|
529
|
-
value: normalizedValue,
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
break;
|
|
534
|
-
|
|
535
|
-
case "eslint": {
|
|
536
|
-
const parseResult =
|
|
537
|
-
commentParser.parseJSONLikeConfig(value);
|
|
538
|
-
|
|
539
|
-
if (parseResult.ok) {
|
|
540
|
-
Object.keys(parseResult.config).forEach(name => {
|
|
541
|
-
const rule = ruleMapper(name);
|
|
542
|
-
const ruleValue = parseResult.config[name];
|
|
543
|
-
|
|
544
|
-
if (!rule) {
|
|
545
|
-
report.addError({ ruleId: name, loc });
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
if (Object.hasOwn(configuredRules, name)) {
|
|
550
|
-
report.addError({
|
|
551
|
-
message: `Rule "${name}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`,
|
|
552
|
-
loc,
|
|
553
|
-
});
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
let ruleOptions = asArray(ruleValue);
|
|
558
|
-
|
|
559
|
-
/*
|
|
560
|
-
* If the rule was already configured, inline rule configuration that
|
|
561
|
-
* only has severity should retain options from the config and just override the severity.
|
|
562
|
-
*
|
|
563
|
-
* Example:
|
|
564
|
-
*
|
|
565
|
-
* {
|
|
566
|
-
* rules: {
|
|
567
|
-
* curly: ["error", "multi"]
|
|
568
|
-
* }
|
|
569
|
-
* }
|
|
570
|
-
*
|
|
571
|
-
* /* eslint curly: ["warn"] * /
|
|
572
|
-
*
|
|
573
|
-
* Results in:
|
|
574
|
-
*
|
|
575
|
-
* curly: ["warn", "multi"]
|
|
576
|
-
*/
|
|
577
|
-
if (
|
|
578
|
-
/*
|
|
579
|
-
* If inline config for the rule has only severity
|
|
580
|
-
*/
|
|
581
|
-
ruleOptions.length === 1 &&
|
|
582
|
-
/*
|
|
583
|
-
* And the rule was already configured
|
|
584
|
-
*/
|
|
585
|
-
config.rules &&
|
|
586
|
-
Object.hasOwn(config.rules, name)
|
|
587
|
-
) {
|
|
588
|
-
/*
|
|
589
|
-
* Then use severity from the inline config and options from the provided config
|
|
590
|
-
*/
|
|
591
|
-
ruleOptions = [
|
|
592
|
-
ruleOptions[0], // severity from the inline config
|
|
593
|
-
...asArray(config.rules[name]).slice(1), // options from the provided config
|
|
594
|
-
];
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
try {
|
|
598
|
-
validator.validateRuleOptions(
|
|
599
|
-
rule,
|
|
600
|
-
name,
|
|
601
|
-
ruleOptions,
|
|
602
|
-
);
|
|
603
|
-
} catch (err) {
|
|
604
|
-
/*
|
|
605
|
-
* If the rule has invalid `meta.schema`, throw the error because
|
|
606
|
-
* this is not an invalid inline configuration but an invalid rule.
|
|
607
|
-
*/
|
|
608
|
-
if (
|
|
609
|
-
err.code ===
|
|
610
|
-
"ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
|
|
611
|
-
) {
|
|
612
|
-
throw err;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
report.addError({
|
|
616
|
-
ruleId: name,
|
|
617
|
-
message: err.message,
|
|
618
|
-
loc,
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
// do not apply the config, if found invalid options.
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
configuredRules[name] = ruleOptions;
|
|
626
|
-
});
|
|
627
|
-
} else {
|
|
628
|
-
report.addFatal({
|
|
629
|
-
loc,
|
|
630
|
-
message: parseResult.error.message,
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
break;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
// no default
|
|
638
|
-
}
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
return {
|
|
642
|
-
configuredRules,
|
|
643
|
-
enabledGlobals,
|
|
644
|
-
exportedVariables,
|
|
645
|
-
disableDirectives,
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
|
|
649
288
|
/**
|
|
650
289
|
* Parses comments in file to extract disable directives.
|
|
651
290
|
* @param {SourceCode} sourceCode The SourceCode object to get comments from.
|
|
@@ -687,83 +326,6 @@ function getDirectiveCommentsForFlatConfig(
|
|
|
687
326
|
return disableDirectives;
|
|
688
327
|
}
|
|
689
328
|
|
|
690
|
-
/**
|
|
691
|
-
* Normalize ECMAScript version from the initial config
|
|
692
|
-
* @param {Parser} parser The parser which uses this options.
|
|
693
|
-
* @param {number} ecmaVersion ECMAScript version from the initial config
|
|
694
|
-
* @returns {number} normalized ECMAScript version
|
|
695
|
-
*/
|
|
696
|
-
function normalizeEcmaVersion(parser, ecmaVersion) {
|
|
697
|
-
if (isEspree(parser)) {
|
|
698
|
-
if (ecmaVersion === "latest") {
|
|
699
|
-
return espree.latestEcmaVersion;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
/*
|
|
704
|
-
* Calculate ECMAScript edition number from official year version starting with
|
|
705
|
-
* ES2015, which corresponds with ES6 (or a difference of 2009).
|
|
706
|
-
*/
|
|
707
|
-
return ecmaVersion >= 2015 ? ecmaVersion - 2009 : ecmaVersion;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
* Normalize ECMAScript version from the initial config into languageOptions (year)
|
|
712
|
-
* format.
|
|
713
|
-
* @param {any} [ecmaVersion] ECMAScript version from the initial config
|
|
714
|
-
* @returns {number} normalized ECMAScript version
|
|
715
|
-
*/
|
|
716
|
-
function normalizeEcmaVersionForLanguageOptions(ecmaVersion) {
|
|
717
|
-
switch (ecmaVersion) {
|
|
718
|
-
case 3:
|
|
719
|
-
return 3;
|
|
720
|
-
|
|
721
|
-
// void 0 = no ecmaVersion specified so use the default
|
|
722
|
-
case 5:
|
|
723
|
-
case void 0:
|
|
724
|
-
return 5;
|
|
725
|
-
|
|
726
|
-
default:
|
|
727
|
-
if (typeof ecmaVersion === "number") {
|
|
728
|
-
return ecmaVersion >= 2015 ? ecmaVersion : ecmaVersion + 2009;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/*
|
|
733
|
-
* We default to the latest supported ecmaVersion for everything else.
|
|
734
|
-
* Remember, this is for languageOptions.ecmaVersion, which sets the version
|
|
735
|
-
* that is used for a number of processes inside of ESLint. It's normally
|
|
736
|
-
* safe to assume people want the latest unless otherwise specified.
|
|
737
|
-
*/
|
|
738
|
-
return LATEST_ECMA_VERSION;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
const eslintEnvPattern = /\/\*\s*eslint-env\s.+?(?:\*\/|$)/gsu;
|
|
742
|
-
|
|
743
|
-
/**
|
|
744
|
-
* Checks whether or not there is a comment which has "eslint-env *" in a given text.
|
|
745
|
-
* @param {string} text A source code text to check.
|
|
746
|
-
* @returns {Object|null} A result of parseListConfig() with "eslint-env *" comment.
|
|
747
|
-
*/
|
|
748
|
-
function findEslintEnv(text) {
|
|
749
|
-
let match, retv;
|
|
750
|
-
|
|
751
|
-
eslintEnvPattern.lastIndex = 0;
|
|
752
|
-
|
|
753
|
-
while ((match = eslintEnvPattern.exec(text)) !== null) {
|
|
754
|
-
if (match[0].endsWith("*/")) {
|
|
755
|
-
retv = Object.assign(
|
|
756
|
-
retv || {},
|
|
757
|
-
commentParser.parseListConfig(
|
|
758
|
-
commentParser.parseDirective(match[0].slice(2, -2)).value,
|
|
759
|
-
),
|
|
760
|
-
);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
return retv;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
329
|
/**
|
|
768
330
|
* Convert "/path/to/<text>" to "<text>".
|
|
769
331
|
* `CLIEngine#executeOnText()` method gives "/path/to/<text>" if the filename
|
|
@@ -792,8 +354,6 @@ function normalizeFilename(filename) {
|
|
|
792
354
|
*/
|
|
793
355
|
function normalizeVerifyOptions(providedOptions, config) {
|
|
794
356
|
const linterOptions = config.linterOptions || config;
|
|
795
|
-
|
|
796
|
-
// .noInlineConfig for eslintrc, .linterOptions.noInlineConfig for flat
|
|
797
357
|
const disableInlineConfig = linterOptions.noInlineConfig === true;
|
|
798
358
|
const ignoreInlineConfig = providedOptions.allowInlineConfig === false;
|
|
799
359
|
const configNameOfNoInlineConfig = config.configNameOfNoInlineConfig
|
|
@@ -850,86 +410,6 @@ function normalizeVerifyOptions(providedOptions, config) {
|
|
|
850
410
|
};
|
|
851
411
|
}
|
|
852
412
|
|
|
853
|
-
/**
|
|
854
|
-
* Combines the provided parserOptions with the options from environments
|
|
855
|
-
* @param {Parser} parser The parser which uses this options.
|
|
856
|
-
* @param {ParserOptions} providedOptions The provided 'parserOptions' key in a config
|
|
857
|
-
* @param {Environment[]} enabledEnvironments The environments enabled in configuration and with inline comments
|
|
858
|
-
* @returns {ParserOptions} Resulting parser options after merge
|
|
859
|
-
*/
|
|
860
|
-
function resolveParserOptions(parser, providedOptions, enabledEnvironments) {
|
|
861
|
-
const parserOptionsFromEnv = enabledEnvironments
|
|
862
|
-
.filter(env => env.parserOptions)
|
|
863
|
-
.reduce(
|
|
864
|
-
(parserOptions, env) => merge(parserOptions, env.parserOptions),
|
|
865
|
-
{},
|
|
866
|
-
);
|
|
867
|
-
const mergedParserOptions = merge(
|
|
868
|
-
parserOptionsFromEnv,
|
|
869
|
-
providedOptions || {},
|
|
870
|
-
);
|
|
871
|
-
const isModule = mergedParserOptions.sourceType === "module";
|
|
872
|
-
|
|
873
|
-
if (isModule) {
|
|
874
|
-
/*
|
|
875
|
-
* can't have global return inside of modules
|
|
876
|
-
* TODO: espree validate parserOptions.globalReturn when sourceType is setting to module.(@aladdin-add)
|
|
877
|
-
*/
|
|
878
|
-
mergedParserOptions.ecmaFeatures = Object.assign(
|
|
879
|
-
{},
|
|
880
|
-
mergedParserOptions.ecmaFeatures,
|
|
881
|
-
{ globalReturn: false },
|
|
882
|
-
);
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
mergedParserOptions.ecmaVersion = normalizeEcmaVersion(
|
|
886
|
-
parser,
|
|
887
|
-
mergedParserOptions.ecmaVersion,
|
|
888
|
-
);
|
|
889
|
-
|
|
890
|
-
return mergedParserOptions;
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
/**
|
|
894
|
-
* Converts parserOptions to languageOptions for backwards compatibility with eslintrc.
|
|
895
|
-
* @param {ConfigData} config Config object.
|
|
896
|
-
* @param {Object} config.globals Global variable definitions.
|
|
897
|
-
* @param {Parser} config.parser The parser to use.
|
|
898
|
-
* @param {ParserOptions} config.parserOptions The parserOptions to use.
|
|
899
|
-
* @returns {JSLanguageOptions} The languageOptions equivalent.
|
|
900
|
-
*/
|
|
901
|
-
function createLanguageOptions({
|
|
902
|
-
globals: configuredGlobals,
|
|
903
|
-
parser,
|
|
904
|
-
parserOptions,
|
|
905
|
-
}) {
|
|
906
|
-
const { ecmaVersion, sourceType } = parserOptions;
|
|
907
|
-
|
|
908
|
-
return {
|
|
909
|
-
globals: configuredGlobals,
|
|
910
|
-
ecmaVersion: normalizeEcmaVersionForLanguageOptions(ecmaVersion),
|
|
911
|
-
sourceType,
|
|
912
|
-
parser,
|
|
913
|
-
parserOptions,
|
|
914
|
-
};
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
/**
|
|
918
|
-
* Combines the provided globals object with the globals from environments
|
|
919
|
-
* @param {Record<string, GlobalConf>} providedGlobals The 'globals' key in a config
|
|
920
|
-
* @param {Environment[]} enabledEnvironments The environments enabled in configuration and with inline comments
|
|
921
|
-
* @returns {Record<string, GlobalConf>} The resolved globals object
|
|
922
|
-
*/
|
|
923
|
-
function resolveGlobals(providedGlobals, enabledEnvironments) {
|
|
924
|
-
return Object.assign(
|
|
925
|
-
Object.create(null),
|
|
926
|
-
...enabledEnvironments
|
|
927
|
-
.filter(env => env.globals)
|
|
928
|
-
.map(env => env.globals),
|
|
929
|
-
providedGlobals,
|
|
930
|
-
);
|
|
931
|
-
}
|
|
932
|
-
|
|
933
413
|
/**
|
|
934
414
|
* Store time measurements in map
|
|
935
415
|
* @param {number} time Time measurement
|
|
@@ -1028,7 +508,6 @@ function createRuleListeners(rule, ruleContext) {
|
|
|
1028
508
|
* @param {SourceCode} sourceCode A SourceCode object for the given text
|
|
1029
509
|
* @param {Object} configuredRules The rules configuration
|
|
1030
510
|
* @param {function(string): RuleDefinition} ruleMapper A mapper function from rule names to rules
|
|
1031
|
-
* @param {string | undefined} parserName The name of the parser in the config
|
|
1032
511
|
* @param {Language} language The language object used for parsing.
|
|
1033
512
|
* @param {LanguageOptions} languageOptions The options for parsing the code.
|
|
1034
513
|
* @param {Object} settings The settings that were enabled in the config
|
|
@@ -1047,7 +526,6 @@ function runRules(
|
|
|
1047
526
|
sourceCode,
|
|
1048
527
|
configuredRules,
|
|
1049
528
|
ruleMapper,
|
|
1050
|
-
parserName,
|
|
1051
529
|
language,
|
|
1052
530
|
languageOptions,
|
|
1053
531
|
settings,
|
|
@@ -1072,10 +550,6 @@ function runRules(
|
|
|
1072
550
|
filename,
|
|
1073
551
|
physicalFilename: physicalFilename || filename,
|
|
1074
552
|
sourceCode,
|
|
1075
|
-
parserOptions: {
|
|
1076
|
-
...languageOptions.parserOptions,
|
|
1077
|
-
},
|
|
1078
|
-
parserPath: parserName,
|
|
1079
553
|
languageOptions,
|
|
1080
554
|
settings,
|
|
1081
555
|
});
|
|
@@ -1232,35 +706,6 @@ function ensureText(textOrSourceCode) {
|
|
|
1232
706
|
return String(textOrSourceCode);
|
|
1233
707
|
}
|
|
1234
708
|
|
|
1235
|
-
/**
|
|
1236
|
-
* Get an environment.
|
|
1237
|
-
* @param {LinterInternalSlots} slots The internal slots of Linter.
|
|
1238
|
-
* @param {string} envId The environment ID to get.
|
|
1239
|
-
* @returns {Environment|null} The environment.
|
|
1240
|
-
*/
|
|
1241
|
-
function getEnv(slots, envId) {
|
|
1242
|
-
return (
|
|
1243
|
-
(slots.lastConfigArray &&
|
|
1244
|
-
slots.lastConfigArray.pluginEnvironments.get(envId)) ||
|
|
1245
|
-
BuiltInEnvironments.get(envId) ||
|
|
1246
|
-
null
|
|
1247
|
-
);
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
/**
|
|
1251
|
-
* Get a rule.
|
|
1252
|
-
* @param {LinterInternalSlots} slots The internal slots of Linter.
|
|
1253
|
-
* @param {string} ruleId The rule ID to get.
|
|
1254
|
-
* @returns {Rule|null} The rule.
|
|
1255
|
-
*/
|
|
1256
|
-
function getRule(slots, ruleId) {
|
|
1257
|
-
return (
|
|
1258
|
-
(slots.lastConfigArray &&
|
|
1259
|
-
slots.lastConfigArray.pluginRules.get(ruleId)) ||
|
|
1260
|
-
slots.ruleMap.get(ruleId)
|
|
1261
|
-
);
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
709
|
/**
|
|
1265
710
|
* Normalize the value of the cwd
|
|
1266
711
|
* @param {string | undefined} cwd raw value of the cwd, path to a directory that should be considered as the current working directory, can be undefined.
|
|
@@ -1285,22 +730,6 @@ function normalizeCwd(cwd) {
|
|
|
1285
730
|
*/
|
|
1286
731
|
const internalSlotsMap = new WeakMap();
|
|
1287
732
|
|
|
1288
|
-
/**
|
|
1289
|
-
* Throws an error when the given linter is in flat config mode.
|
|
1290
|
-
* @param {Linter} linter The linter to check.
|
|
1291
|
-
* @returns {void}
|
|
1292
|
-
* @throws {Error} If the linter is in flat config mode.
|
|
1293
|
-
*/
|
|
1294
|
-
function assertEslintrcConfig(linter) {
|
|
1295
|
-
const { configType } = internalSlotsMap.get(linter);
|
|
1296
|
-
|
|
1297
|
-
if (configType === "flat") {
|
|
1298
|
-
throw new Error(
|
|
1299
|
-
"This method cannot be used with flat config. Add your entries directly into the config array.",
|
|
1300
|
-
);
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
733
|
//------------------------------------------------------------------------------
|
|
1305
734
|
// Public Interface
|
|
1306
735
|
//------------------------------------------------------------------------------
|
|
@@ -1315,7 +744,7 @@ class Linter {
|
|
|
1315
744
|
* @param {Object} [config] the config object
|
|
1316
745
|
* @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
|
|
1317
746
|
* @param {Array<string>} [config.flags] the feature flags to enable.
|
|
1318
|
-
* @param {"flat"
|
|
747
|
+
* @param {"flat"} [config.configType="flat"] the type of config used. Retrained for backwards compatibility, will be removed in future.
|
|
1319
748
|
* @param {WarningService} [config.warningService] The warning service to use.
|
|
1320
749
|
*/
|
|
1321
750
|
constructor({
|
|
@@ -1326,6 +755,12 @@ class Linter {
|
|
|
1326
755
|
} = {}) {
|
|
1327
756
|
const processedFlags = [];
|
|
1328
757
|
|
|
758
|
+
if (configType !== "flat") {
|
|
759
|
+
throw new TypeError(
|
|
760
|
+
`The 'configType' option value must be 'flat'. The value '${configType}' is not supported.`,
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
|
|
1329
764
|
flags.forEach(flag => {
|
|
1330
765
|
if (inactiveFlags.has(flag)) {
|
|
1331
766
|
const inactiveFlagData = inactiveFlags.get(flag);
|
|
@@ -1360,9 +795,6 @@ class Linter {
|
|
|
1360
795
|
lastConfigArray: null,
|
|
1361
796
|
lastSourceCode: null,
|
|
1362
797
|
lastSuppressedMessages: [],
|
|
1363
|
-
configType, // TODO: Remove after flat config conversion
|
|
1364
|
-
parserMap: new Map([["espree", espree]]),
|
|
1365
|
-
ruleMap: new Rules(),
|
|
1366
798
|
warningService,
|
|
1367
799
|
});
|
|
1368
800
|
|
|
@@ -1388,334 +820,51 @@ class Linter {
|
|
|
1388
820
|
}
|
|
1389
821
|
|
|
1390
822
|
/**
|
|
1391
|
-
*
|
|
1392
|
-
* @param {
|
|
1393
|
-
* @param {ConfigData}
|
|
1394
|
-
* @param {VerifyOptions} [
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
823
|
+
* Verifies the text against the rules specified by the second argument.
|
|
824
|
+
* @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
|
|
825
|
+
* @param {ConfigData|ConfigArray} config An ESLintConfig instance to configure everything.
|
|
826
|
+
* @param {(string|(VerifyOptions&ProcessorOptions))} [filenameOrOptions] The optional filename of the file being checked.
|
|
827
|
+
* If this is not set, the filename will default to '<input>' in the rule context. If
|
|
828
|
+
* an object, then it has "filename", "allowInlineConfig", and some properties.
|
|
829
|
+
* @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
|
|
1397
830
|
*/
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
const config = providedConfig || {};
|
|
1401
|
-
const options = normalizeVerifyOptions(providedOptions, config);
|
|
1402
|
-
|
|
1403
|
-
// Resolve parser.
|
|
1404
|
-
let parserName = DEFAULT_PARSER_NAME;
|
|
1405
|
-
let parser = espree;
|
|
1406
|
-
|
|
1407
|
-
if (typeof config.parser === "object" && config.parser !== null) {
|
|
1408
|
-
parserName = config.parser.filePath;
|
|
1409
|
-
parser = config.parser.definition;
|
|
1410
|
-
} else if (typeof config.parser === "string") {
|
|
1411
|
-
if (!slots.parserMap.has(config.parser)) {
|
|
1412
|
-
return [
|
|
1413
|
-
{
|
|
1414
|
-
ruleId: null,
|
|
1415
|
-
fatal: true,
|
|
1416
|
-
severity: 2,
|
|
1417
|
-
message: `Configured parser '${config.parser}' was not found.`,
|
|
1418
|
-
line: 0,
|
|
1419
|
-
column: 0,
|
|
1420
|
-
nodeType: null,
|
|
1421
|
-
},
|
|
1422
|
-
];
|
|
1423
|
-
}
|
|
1424
|
-
parserName = config.parser;
|
|
1425
|
-
parser = slots.parserMap.get(config.parser);
|
|
1426
|
-
}
|
|
831
|
+
verify(textOrSourceCode, config, filenameOrOptions) {
|
|
832
|
+
debug("Verify");
|
|
1427
833
|
|
|
1428
|
-
|
|
1429
|
-
const envInFile =
|
|
1430
|
-
options.allowInlineConfig && !options.warnInlineConfig
|
|
1431
|
-
? findEslintEnv(file.body)
|
|
1432
|
-
: {};
|
|
1433
|
-
const resolvedEnvConfig = Object.assign(
|
|
1434
|
-
{ builtin: true },
|
|
1435
|
-
config.env,
|
|
1436
|
-
envInFile,
|
|
1437
|
-
);
|
|
1438
|
-
const enabledEnvs = Object.keys(resolvedEnvConfig)
|
|
1439
|
-
.filter(envName => resolvedEnvConfig[envName])
|
|
1440
|
-
.map(envName => getEnv(slots, envName))
|
|
1441
|
-
.filter(env => env);
|
|
1442
|
-
|
|
1443
|
-
const parserOptions = resolveParserOptions(
|
|
1444
|
-
parser,
|
|
1445
|
-
config.parserOptions || {},
|
|
1446
|
-
enabledEnvs,
|
|
1447
|
-
);
|
|
1448
|
-
const configuredGlobals = resolveGlobals(
|
|
1449
|
-
config.globals || {},
|
|
1450
|
-
enabledEnvs,
|
|
1451
|
-
);
|
|
1452
|
-
const settings = config.settings || {};
|
|
1453
|
-
const languageOptions = createLanguageOptions({
|
|
1454
|
-
globals: config.globals,
|
|
1455
|
-
parser,
|
|
1456
|
-
parserOptions,
|
|
1457
|
-
});
|
|
834
|
+
const { cwd } = internalSlotsMap.get(this);
|
|
1458
835
|
|
|
1459
|
-
|
|
1460
|
-
|
|
836
|
+
const options =
|
|
837
|
+
typeof filenameOrOptions === "string"
|
|
838
|
+
? { filename: filenameOrOptions }
|
|
839
|
+
: filenameOrOptions || {};
|
|
1461
840
|
|
|
1462
|
-
|
|
1463
|
-
t = startTime();
|
|
1464
|
-
}
|
|
841
|
+
const configToUse = config ?? {};
|
|
1465
842
|
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
843
|
+
/*
|
|
844
|
+
* Because of how Webpack packages up the files, we can't
|
|
845
|
+
* compare directly to `FlatConfigArray` using `instanceof`
|
|
846
|
+
* because it's not the same `FlatConfigArray` as in the tests.
|
|
847
|
+
* So, we work around it by assuming an array is, in fact, a
|
|
848
|
+
* `FlatConfigArray` if it has a `getConfig()` method.
|
|
849
|
+
*/
|
|
850
|
+
let configArray = configToUse;
|
|
851
|
+
|
|
852
|
+
if (
|
|
853
|
+
!Array.isArray(configToUse) ||
|
|
854
|
+
typeof configToUse.getConfig !== "function"
|
|
855
|
+
) {
|
|
856
|
+
configArray = new FlatConfigArray(configToUse, {
|
|
857
|
+
basePath: cwd,
|
|
1470
858
|
});
|
|
859
|
+
configArray.normalizeSync();
|
|
860
|
+
}
|
|
1471
861
|
|
|
1472
|
-
if (options.stats) {
|
|
1473
|
-
const time = endTime(t);
|
|
1474
|
-
const timeOpts = { type: "parse" };
|
|
1475
|
-
|
|
1476
|
-
storeTime(time, timeOpts, slots);
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
if (!parseResult.ok) {
|
|
1480
|
-
return parseResult.errors;
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
slots.lastSourceCode = parseResult.sourceCode;
|
|
1484
|
-
} else {
|
|
1485
|
-
/*
|
|
1486
|
-
* If the given source code object as the first argument does not have scopeManager, analyze the scope.
|
|
1487
|
-
* This is for backward compatibility (SourceCode is frozen so it cannot rebind).
|
|
1488
|
-
*/
|
|
1489
|
-
if (!slots.lastSourceCode.scopeManager) {
|
|
1490
|
-
slots.lastSourceCode = new SourceCode({
|
|
1491
|
-
text: slots.lastSourceCode.text,
|
|
1492
|
-
ast: slots.lastSourceCode.ast,
|
|
1493
|
-
hasBOM: slots.lastSourceCode.hasBOM,
|
|
1494
|
-
parserServices: slots.lastSourceCode.parserServices,
|
|
1495
|
-
visitorKeys: slots.lastSourceCode.visitorKeys,
|
|
1496
|
-
scopeManager: analyzeScope(
|
|
1497
|
-
slots.lastSourceCode.ast,
|
|
1498
|
-
languageOptions,
|
|
1499
|
-
),
|
|
1500
|
-
});
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
const sourceCode = slots.lastSourceCode;
|
|
1505
|
-
const report = new FileReport({
|
|
1506
|
-
ruleMapper: ruleId => getRule(slots, ruleId),
|
|
1507
|
-
language: jslang,
|
|
1508
|
-
sourceCode,
|
|
1509
|
-
disableFixes: options.disableFixes,
|
|
1510
|
-
});
|
|
1511
|
-
|
|
1512
|
-
const commentDirectives = options.allowInlineConfig
|
|
1513
|
-
? getDirectiveComments(
|
|
1514
|
-
sourceCode,
|
|
1515
|
-
ruleId => getRule(slots, ruleId),
|
|
1516
|
-
options.warnInlineConfig,
|
|
1517
|
-
config,
|
|
1518
|
-
report,
|
|
1519
|
-
)
|
|
1520
|
-
: {
|
|
1521
|
-
configuredRules: {},
|
|
1522
|
-
enabledGlobals: {},
|
|
1523
|
-
exportedVariables: {},
|
|
1524
|
-
disableDirectives: [],
|
|
1525
|
-
};
|
|
1526
|
-
|
|
1527
|
-
addDeclaredGlobals(
|
|
1528
|
-
sourceCode.scopeManager.scopes[0],
|
|
1529
|
-
configuredGlobals,
|
|
1530
|
-
{
|
|
1531
|
-
exportedVariables: commentDirectives.exportedVariables,
|
|
1532
|
-
enabledGlobals: commentDirectives.enabledGlobals,
|
|
1533
|
-
},
|
|
1534
|
-
);
|
|
1535
|
-
|
|
1536
|
-
const configuredRules = Object.assign(
|
|
1537
|
-
{},
|
|
1538
|
-
config.rules,
|
|
1539
|
-
commentDirectives.configuredRules,
|
|
1540
|
-
);
|
|
1541
|
-
|
|
1542
|
-
try {
|
|
1543
|
-
runRules(
|
|
1544
|
-
sourceCode,
|
|
1545
|
-
configuredRules,
|
|
1546
|
-
ruleId => getRule(slots, ruleId),
|
|
1547
|
-
parserName,
|
|
1548
|
-
jslang,
|
|
1549
|
-
languageOptions,
|
|
1550
|
-
settings,
|
|
1551
|
-
options.filename,
|
|
1552
|
-
true,
|
|
1553
|
-
slots.cwd,
|
|
1554
|
-
providedOptions.physicalFilename,
|
|
1555
|
-
null,
|
|
1556
|
-
options.stats,
|
|
1557
|
-
slots,
|
|
1558
|
-
report,
|
|
1559
|
-
);
|
|
1560
|
-
} catch (err) {
|
|
1561
|
-
err.message += `\nOccurred while linting ${options.filename}`;
|
|
1562
|
-
debug("An error occurred while traversing");
|
|
1563
|
-
debug("Filename:", options.filename);
|
|
1564
|
-
if (err.currentNode) {
|
|
1565
|
-
const { line } = sourceCode.getLoc(err.currentNode).start;
|
|
1566
|
-
|
|
1567
|
-
debug("Line:", line);
|
|
1568
|
-
err.message += `:${line}`;
|
|
1569
|
-
}
|
|
1570
|
-
debug("Parser Options:", parserOptions);
|
|
1571
|
-
debug("Parser Path:", parserName);
|
|
1572
|
-
debug("Settings:", settings);
|
|
1573
|
-
|
|
1574
|
-
if (err.ruleId) {
|
|
1575
|
-
err.message += `\nRule: "${err.ruleId}"`;
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
throw err;
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
return applyDisableDirectives({
|
|
1582
|
-
language: jslang,
|
|
1583
|
-
sourceCode,
|
|
1584
|
-
directives: commentDirectives.disableDirectives,
|
|
1585
|
-
disableFixes: options.disableFixes,
|
|
1586
|
-
problems: report.messages.sort(
|
|
1587
|
-
(problemA, problemB) =>
|
|
1588
|
-
problemA.line - problemB.line ||
|
|
1589
|
-
problemA.column - problemB.column,
|
|
1590
|
-
),
|
|
1591
|
-
reportUnusedDisableDirectives:
|
|
1592
|
-
options.reportUnusedDisableDirectives,
|
|
1593
|
-
});
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
/**
|
|
1597
|
-
* Same as linter.verify, except without support for processors.
|
|
1598
|
-
* @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
|
|
1599
|
-
* @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
|
|
1600
|
-
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
|
1601
|
-
* @throws {Error} If during rule execution.
|
|
1602
|
-
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
|
1603
|
-
*/
|
|
1604
|
-
_verifyWithoutProcessors(
|
|
1605
|
-
textOrSourceCode,
|
|
1606
|
-
providedConfig,
|
|
1607
|
-
providedOptions,
|
|
1608
|
-
) {
|
|
1609
|
-
const slots = internalSlotsMap.get(this);
|
|
1610
|
-
const filename = normalizeFilename(
|
|
1611
|
-
providedOptions.filename || "<input>",
|
|
1612
|
-
);
|
|
1613
|
-
let text;
|
|
1614
|
-
|
|
1615
|
-
// evaluate arguments
|
|
1616
|
-
if (typeof textOrSourceCode === "string") {
|
|
1617
|
-
slots.lastSourceCode = null;
|
|
1618
|
-
text = textOrSourceCode;
|
|
1619
|
-
} else {
|
|
1620
|
-
slots.lastSourceCode = textOrSourceCode;
|
|
1621
|
-
text = textOrSourceCode.text;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
const file = new VFile(filename, text, {
|
|
1625
|
-
physicalPath: providedOptions.physicalFilename,
|
|
1626
|
-
});
|
|
1627
|
-
|
|
1628
|
-
return this.#eslintrcVerifyWithoutProcessors(
|
|
1629
|
-
file,
|
|
1630
|
-
providedConfig,
|
|
1631
|
-
providedOptions,
|
|
1632
|
-
);
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
/**
|
|
1636
|
-
* Verifies the text against the rules specified by the second argument.
|
|
1637
|
-
* @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
|
|
1638
|
-
* @param {ConfigData|ConfigArray} config An ESLintConfig instance to configure everything.
|
|
1639
|
-
* @param {(string|(VerifyOptions&ProcessorOptions))} [filenameOrOptions] The optional filename of the file being checked.
|
|
1640
|
-
* If this is not set, the filename will default to '<input>' in the rule context. If
|
|
1641
|
-
* an object, then it has "filename", "allowInlineConfig", and some properties.
|
|
1642
|
-
* @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
|
|
1643
|
-
*/
|
|
1644
|
-
verify(textOrSourceCode, config, filenameOrOptions) {
|
|
1645
|
-
debug("Verify");
|
|
1646
|
-
|
|
1647
|
-
const { configType, cwd } = internalSlotsMap.get(this);
|
|
1648
|
-
|
|
1649
|
-
const options =
|
|
1650
|
-
typeof filenameOrOptions === "string"
|
|
1651
|
-
? { filename: filenameOrOptions }
|
|
1652
|
-
: filenameOrOptions || {};
|
|
1653
|
-
|
|
1654
|
-
const configToUse = config ?? {};
|
|
1655
|
-
|
|
1656
|
-
if (configType !== "eslintrc") {
|
|
1657
|
-
/*
|
|
1658
|
-
* Because of how Webpack packages up the files, we can't
|
|
1659
|
-
* compare directly to `FlatConfigArray` using `instanceof`
|
|
1660
|
-
* because it's not the same `FlatConfigArray` as in the tests.
|
|
1661
|
-
* So, we work around it by assuming an array is, in fact, a
|
|
1662
|
-
* `FlatConfigArray` if it has a `getConfig()` method.
|
|
1663
|
-
*/
|
|
1664
|
-
let configArray = configToUse;
|
|
1665
|
-
|
|
1666
|
-
if (
|
|
1667
|
-
!Array.isArray(configToUse) ||
|
|
1668
|
-
typeof configToUse.getConfig !== "function"
|
|
1669
|
-
) {
|
|
1670
|
-
configArray = new FlatConfigArray(configToUse, {
|
|
1671
|
-
basePath: cwd,
|
|
1672
|
-
});
|
|
1673
|
-
configArray.normalizeSync();
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
return this._distinguishSuppressedMessages(
|
|
1677
|
-
this._verifyWithFlatConfigArray(
|
|
1678
|
-
textOrSourceCode,
|
|
1679
|
-
configArray,
|
|
1680
|
-
options,
|
|
1681
|
-
true,
|
|
1682
|
-
),
|
|
1683
|
-
);
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
if (typeof configToUse.extractConfig === "function") {
|
|
1687
|
-
return this._distinguishSuppressedMessages(
|
|
1688
|
-
this._verifyWithConfigArray(
|
|
1689
|
-
textOrSourceCode,
|
|
1690
|
-
configToUse,
|
|
1691
|
-
options,
|
|
1692
|
-
),
|
|
1693
|
-
);
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
/*
|
|
1697
|
-
* If we get to here, it means `config` is just an object rather
|
|
1698
|
-
* than a config array so we can go right into linting.
|
|
1699
|
-
*/
|
|
1700
|
-
|
|
1701
|
-
/*
|
|
1702
|
-
* `Linter` doesn't support `overrides` property in configuration.
|
|
1703
|
-
* So we cannot apply multiple processors.
|
|
1704
|
-
*/
|
|
1705
|
-
if (options.preprocess || options.postprocess) {
|
|
1706
|
-
return this._distinguishSuppressedMessages(
|
|
1707
|
-
this._verifyWithProcessor(
|
|
1708
|
-
textOrSourceCode,
|
|
1709
|
-
configToUse,
|
|
1710
|
-
options,
|
|
1711
|
-
),
|
|
1712
|
-
);
|
|
1713
|
-
}
|
|
1714
862
|
return this._distinguishSuppressedMessages(
|
|
1715
|
-
this.
|
|
863
|
+
this._verifyWithFlatConfigArray(
|
|
1716
864
|
textOrSourceCode,
|
|
1717
|
-
|
|
865
|
+
configArray,
|
|
1718
866
|
options,
|
|
867
|
+
true,
|
|
1719
868
|
),
|
|
1720
869
|
);
|
|
1721
870
|
}
|
|
@@ -2102,7 +1251,6 @@ class Linter {
|
|
|
2102
1251
|
sourceCode,
|
|
2103
1252
|
configuredRules,
|
|
2104
1253
|
ruleId => config.getRuleDefinition(ruleId),
|
|
2105
|
-
void 0,
|
|
2106
1254
|
config.language,
|
|
2107
1255
|
languageOptions,
|
|
2108
1256
|
settings,
|
|
@@ -2126,8 +1274,6 @@ class Linter {
|
|
|
2126
1274
|
err.message += `:${line}`;
|
|
2127
1275
|
}
|
|
2128
1276
|
debug("Parser Options:", languageOptions.parserOptions);
|
|
2129
|
-
|
|
2130
|
-
// debug("Parser Path:", parserName);
|
|
2131
1277
|
debug("Settings:", settings);
|
|
2132
1278
|
|
|
2133
1279
|
if (err.ruleId) {
|
|
@@ -2193,48 +1339,13 @@ class Linter {
|
|
|
2193
1339
|
);
|
|
2194
1340
|
}
|
|
2195
1341
|
|
|
2196
|
-
/**
|
|
2197
|
-
* Verify a given code with `ConfigArray`.
|
|
2198
|
-
* @param {string|SourceCode} textOrSourceCode The source code.
|
|
2199
|
-
* @param {ConfigArray} configArray The config array.
|
|
2200
|
-
* @param {VerifyOptions&ProcessorOptions} options The options.
|
|
2201
|
-
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
|
2202
|
-
*/
|
|
2203
|
-
_verifyWithConfigArray(textOrSourceCode, configArray, options) {
|
|
2204
|
-
debug("With ConfigArray: %s", options.filename);
|
|
2205
|
-
|
|
2206
|
-
// Store the config array in order to get plugin envs and rules later.
|
|
2207
|
-
internalSlotsMap.get(this).lastConfigArray = configArray;
|
|
2208
|
-
|
|
2209
|
-
// Extract the final config for this file.
|
|
2210
|
-
const config = configArray.extractConfig(options.filename);
|
|
2211
|
-
const processor =
|
|
2212
|
-
config.processor &&
|
|
2213
|
-
configArray.pluginProcessors.get(config.processor);
|
|
2214
|
-
|
|
2215
|
-
// Verify.
|
|
2216
|
-
if (processor) {
|
|
2217
|
-
debug("Apply the processor: %o", config.processor);
|
|
2218
|
-
const { preprocess, postprocess, supportsAutofix } = processor;
|
|
2219
|
-
const disableFixes = options.disableFixes || !supportsAutofix;
|
|
2220
|
-
|
|
2221
|
-
return this._verifyWithProcessor(
|
|
2222
|
-
textOrSourceCode,
|
|
2223
|
-
config,
|
|
2224
|
-
{ ...options, disableFixes, postprocess, preprocess },
|
|
2225
|
-
configArray,
|
|
2226
|
-
);
|
|
2227
|
-
}
|
|
2228
|
-
return this._verifyWithoutProcessors(textOrSourceCode, config, options);
|
|
2229
|
-
}
|
|
2230
|
-
|
|
2231
1342
|
/**
|
|
2232
1343
|
* Verify a given code with a flat config.
|
|
2233
1344
|
* @param {string|SourceCode} textOrSourceCode The source code.
|
|
2234
1345
|
* @param {FlatConfigArray} configArray The config array.
|
|
2235
1346
|
* @param {VerifyOptions&ProcessorOptions} options The options.
|
|
2236
|
-
* @param {boolean}
|
|
2237
|
-
*
|
|
1347
|
+
* @param {boolean} firstCall Indicates if this is the first call in `verify()`
|
|
1348
|
+
* to determine processor behavior.
|
|
2238
1349
|
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
|
2239
1350
|
*/
|
|
2240
1351
|
_verifyWithFlatConfigArray(
|
|
@@ -2260,7 +1371,6 @@ class Linter {
|
|
|
2260
1371
|
message: `No matching configuration found for ${filename}.`,
|
|
2261
1372
|
line: 0,
|
|
2262
1373
|
column: 0,
|
|
2263
|
-
nodeType: null,
|
|
2264
1374
|
},
|
|
2265
1375
|
];
|
|
2266
1376
|
}
|
|
@@ -2296,104 +1406,6 @@ class Linter {
|
|
|
2296
1406
|
);
|
|
2297
1407
|
}
|
|
2298
1408
|
|
|
2299
|
-
/**
|
|
2300
|
-
* Verify with a processor.
|
|
2301
|
-
* @param {string|SourceCode} textOrSourceCode The source code.
|
|
2302
|
-
* @param {ConfigData|ExtractedConfig} config The config array.
|
|
2303
|
-
* @param {VerifyOptions&ProcessorOptions} options The options.
|
|
2304
|
-
* @param {ConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
|
|
2305
|
-
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
|
2306
|
-
*/
|
|
2307
|
-
_verifyWithProcessor(
|
|
2308
|
-
textOrSourceCode,
|
|
2309
|
-
config,
|
|
2310
|
-
options,
|
|
2311
|
-
configForRecursive,
|
|
2312
|
-
) {
|
|
2313
|
-
const slots = internalSlotsMap.get(this);
|
|
2314
|
-
const filename = options.filename || "<input>";
|
|
2315
|
-
const filenameToExpose = normalizeFilename(filename);
|
|
2316
|
-
const physicalFilename = options.physicalFilename || filenameToExpose;
|
|
2317
|
-
const text = ensureText(textOrSourceCode);
|
|
2318
|
-
const file = new VFile(filenameToExpose, text, {
|
|
2319
|
-
physicalPath: physicalFilename,
|
|
2320
|
-
});
|
|
2321
|
-
|
|
2322
|
-
const preprocess = options.preprocess || (rawText => [rawText]);
|
|
2323
|
-
const postprocess =
|
|
2324
|
-
options.postprocess || (messagesList => messagesList.flat());
|
|
2325
|
-
|
|
2326
|
-
const processorService = new ProcessorService();
|
|
2327
|
-
const preprocessResult = processorService.preprocessSync(file, {
|
|
2328
|
-
processor: {
|
|
2329
|
-
preprocess,
|
|
2330
|
-
postprocess,
|
|
2331
|
-
},
|
|
2332
|
-
});
|
|
2333
|
-
|
|
2334
|
-
if (!preprocessResult.ok) {
|
|
2335
|
-
return preprocessResult.errors;
|
|
2336
|
-
}
|
|
2337
|
-
|
|
2338
|
-
const filterCodeBlock =
|
|
2339
|
-
options.filterCodeBlock ||
|
|
2340
|
-
(blockFilePath => blockFilePath.endsWith(".js"));
|
|
2341
|
-
const originalExtname = path.extname(filename);
|
|
2342
|
-
|
|
2343
|
-
const { files } = preprocessResult;
|
|
2344
|
-
|
|
2345
|
-
const messageLists = files.map(block => {
|
|
2346
|
-
debug("A code block was found: %o", block.path ?? "(unnamed)");
|
|
2347
|
-
|
|
2348
|
-
// Keep the legacy behavior.
|
|
2349
|
-
if (typeof block === "string") {
|
|
2350
|
-
return this._verifyWithoutProcessors(block, config, options);
|
|
2351
|
-
}
|
|
2352
|
-
|
|
2353
|
-
// Skip this block if filtered.
|
|
2354
|
-
if (!filterCodeBlock(block.path, block.body)) {
|
|
2355
|
-
debug("This code block was skipped.");
|
|
2356
|
-
return [];
|
|
2357
|
-
}
|
|
2358
|
-
|
|
2359
|
-
// Resolve configuration again if the file content or extension was changed.
|
|
2360
|
-
if (
|
|
2361
|
-
configForRecursive &&
|
|
2362
|
-
(text !== block.rawBody ||
|
|
2363
|
-
path.extname(block.path) !== originalExtname)
|
|
2364
|
-
) {
|
|
2365
|
-
debug(
|
|
2366
|
-
"Resolving configuration again because the file content or extension was changed.",
|
|
2367
|
-
);
|
|
2368
|
-
return this._verifyWithConfigArray(
|
|
2369
|
-
block.rawBody,
|
|
2370
|
-
configForRecursive,
|
|
2371
|
-
{
|
|
2372
|
-
...options,
|
|
2373
|
-
filename: block.path,
|
|
2374
|
-
physicalFilename: block.physicalPath,
|
|
2375
|
-
},
|
|
2376
|
-
);
|
|
2377
|
-
}
|
|
2378
|
-
|
|
2379
|
-
slots.lastSourceCode = null;
|
|
2380
|
-
|
|
2381
|
-
// Does lint.
|
|
2382
|
-
return this.#eslintrcVerifyWithoutProcessors(block, config, {
|
|
2383
|
-
...options,
|
|
2384
|
-
filename: block.path,
|
|
2385
|
-
physicalFilename: block.physicalPath,
|
|
2386
|
-
});
|
|
2387
|
-
});
|
|
2388
|
-
|
|
2389
|
-
return processorService.postprocessSync(file, messageLists, {
|
|
2390
|
-
processor: {
|
|
2391
|
-
preprocess,
|
|
2392
|
-
postprocess,
|
|
2393
|
-
},
|
|
2394
|
-
});
|
|
2395
|
-
}
|
|
2396
|
-
|
|
2397
1409
|
/**
|
|
2398
1410
|
* Given a list of reported problems, distinguish problems between normal messages and suppressed messages.
|
|
2399
1411
|
* The normal messages will be returned and the suppressed messages will be stored as lastSuppressedMessages.
|
|
@@ -2450,59 +1462,6 @@ class Linter {
|
|
|
2450
1462
|
return internalSlotsMap.get(this).lastSuppressedMessages;
|
|
2451
1463
|
}
|
|
2452
1464
|
|
|
2453
|
-
/**
|
|
2454
|
-
* Defines a new linting rule.
|
|
2455
|
-
* @param {string} ruleId A unique rule identifier
|
|
2456
|
-
* @param {Rule} rule A rule object
|
|
2457
|
-
* @returns {void}
|
|
2458
|
-
*/
|
|
2459
|
-
defineRule(ruleId, rule) {
|
|
2460
|
-
assertEslintrcConfig(this);
|
|
2461
|
-
internalSlotsMap.get(this).ruleMap.define(ruleId, rule);
|
|
2462
|
-
}
|
|
2463
|
-
|
|
2464
|
-
/**
|
|
2465
|
-
* Defines many new linting rules.
|
|
2466
|
-
* @param {Record<string, Rule>} rulesToDefine map from unique rule identifier to rule
|
|
2467
|
-
* @returns {void}
|
|
2468
|
-
*/
|
|
2469
|
-
defineRules(rulesToDefine) {
|
|
2470
|
-
assertEslintrcConfig(this);
|
|
2471
|
-
Object.getOwnPropertyNames(rulesToDefine).forEach(ruleId => {
|
|
2472
|
-
this.defineRule(ruleId, rulesToDefine[ruleId]);
|
|
2473
|
-
});
|
|
2474
|
-
}
|
|
2475
|
-
|
|
2476
|
-
/**
|
|
2477
|
-
* Gets an object with all loaded rules.
|
|
2478
|
-
* @returns {Map<string, Rule>} All loaded rules
|
|
2479
|
-
*/
|
|
2480
|
-
getRules() {
|
|
2481
|
-
assertEslintrcConfig(this);
|
|
2482
|
-
const { lastConfigArray, ruleMap } = internalSlotsMap.get(this);
|
|
2483
|
-
|
|
2484
|
-
return new Map(
|
|
2485
|
-
(function* () {
|
|
2486
|
-
yield* ruleMap;
|
|
2487
|
-
|
|
2488
|
-
if (lastConfigArray) {
|
|
2489
|
-
yield* lastConfigArray.pluginRules;
|
|
2490
|
-
}
|
|
2491
|
-
})(),
|
|
2492
|
-
);
|
|
2493
|
-
}
|
|
2494
|
-
|
|
2495
|
-
/**
|
|
2496
|
-
* Define a new parser module
|
|
2497
|
-
* @param {string} parserId Name of the parser
|
|
2498
|
-
* @param {Parser} parserModule The parser object
|
|
2499
|
-
* @returns {void}
|
|
2500
|
-
*/
|
|
2501
|
-
defineParser(parserId, parserModule) {
|
|
2502
|
-
assertEslintrcConfig(this);
|
|
2503
|
-
internalSlotsMap.get(this).parserMap.set(parserId, parserModule);
|
|
2504
|
-
}
|
|
2505
|
-
|
|
2506
1465
|
/**
|
|
2507
1466
|
* Performs multiple autofix passes over the text until as many fixes as possible
|
|
2508
1467
|
* have been applied.
|