eslint 9.4.0 → 9.5.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 +2 -2
- package/lib/api.js +1 -1
- package/lib/config/default-config.js +5 -0
- package/lib/config/flat-config-array.js +71 -8
- package/lib/config/flat-config-schema.js +46 -62
- package/lib/eslint/eslint-helpers.js +27 -17
- package/lib/eslint/eslint.js +14 -10
- package/lib/languages/js/index.js +247 -0
- package/lib/{source-code → languages/js/source-code}/source-code.js +38 -18
- package/lib/languages/js/validate-language-options.js +181 -0
- package/lib/linter/apply-disable-directives.js +8 -3
- package/lib/linter/linter.js +122 -121
- package/lib/linter/report-translator.js +14 -7
- package/lib/linter/vfile.js +104 -0
- package/lib/rule-tester/rule-tester.js +5 -2
- package/lib/rules/no-sparse-arrays.js +26 -3
- package/messages/all-matched-files-ignored.js +21 -0
- package/package.json +11 -11
- /package/lib/{source-code → languages/js/source-code}/index.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/backward-token-comment-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/backward-token-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/cursors.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/decorative-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/filter-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/forward-token-comment-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/forward-token-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/index.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/limit-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/padded-token-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/skip-cursor.js +0 -0
- /package/lib/{source-code → languages/js/source-code}/token-store/utils.js +0 -0
package/lib/linter/linter.js
CHANGED
@@ -17,7 +17,6 @@ const
|
|
17
17
|
espree = require("espree"),
|
18
18
|
merge = require("lodash.merge"),
|
19
19
|
pkg = require("../../package.json"),
|
20
|
-
astUtils = require("../shared/ast-utils"),
|
21
20
|
{
|
22
21
|
directivesPattern
|
23
22
|
} = require("../shared/directives"),
|
@@ -29,7 +28,7 @@ const
|
|
29
28
|
}
|
30
29
|
} = require("@eslint/eslintrc/universal"),
|
31
30
|
Traverser = require("../shared/traverser"),
|
32
|
-
{ SourceCode } = require("../source-code"),
|
31
|
+
{ SourceCode } = require("../languages/js/source-code"),
|
33
32
|
applyDisableDirectives = require("./apply-disable-directives"),
|
34
33
|
ConfigCommentParser = require("./config-comment-parser"),
|
35
34
|
NodeEventGenerator = require("./node-event-generator"),
|
@@ -45,6 +44,7 @@ const { startTime, endTime } = require("../shared/stats");
|
|
45
44
|
const { RuleValidator } = require("../config/rule-validator");
|
46
45
|
const { assertIsRuleSeverity } = require("../config/flat-config-schema");
|
47
46
|
const { normalizeSeverityToString } = require("../shared/severity");
|
47
|
+
const jslang = require("../languages/js");
|
48
48
|
const debug = require("debug")("eslint:linter");
|
49
49
|
const MAX_AUTOFIX_PASSES = 10;
|
50
50
|
const DEFAULT_PARSER_NAME = "espree";
|
@@ -53,6 +53,7 @@ const commentParser = new ConfigCommentParser();
|
|
53
53
|
const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, column: 1 } };
|
54
54
|
const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
55
55
|
const { LATEST_ECMA_VERSION } = require("../../conf/ecma-version");
|
56
|
+
const { VFile } = require("./vfile");
|
56
57
|
const STEP_KIND_VISIT = 1;
|
57
58
|
const STEP_KIND_CALL = 2;
|
58
59
|
|
@@ -239,6 +240,35 @@ function createMissingRuleMessage(ruleId) {
|
|
239
240
|
: `Definition for rule '${ruleId}' was not found.`;
|
240
241
|
}
|
241
242
|
|
243
|
+
/**
|
244
|
+
* Updates a given location based on the language offsets. This allows us to
|
245
|
+
* change 0-based locations to 1-based locations. We always want ESLint
|
246
|
+
* reporting lines and columns starting from 1.
|
247
|
+
* @param {Object} location The location to update.
|
248
|
+
* @param {number} location.line The starting line number.
|
249
|
+
* @param {number} location.column The starting column number.
|
250
|
+
* @param {number} [location.endLine] The ending line number.
|
251
|
+
* @param {number} [location.endColumn] The ending column number.
|
252
|
+
* @param {Language} language The language to use to adjust the location information.
|
253
|
+
* @returns {Object} The updated location.
|
254
|
+
*/
|
255
|
+
function updateLocationInformation({ line, column, endLine, endColumn }, language) {
|
256
|
+
|
257
|
+
const columnOffset = language.columnStart === 1 ? 0 : 1;
|
258
|
+
const lineOffset = language.lineStart === 1 ? 0 : 1;
|
259
|
+
|
260
|
+
// calculate separately to account for undefined
|
261
|
+
const finalEndLine = endLine === void 0 ? endLine : endLine + lineOffset;
|
262
|
+
const finalEndColumn = endColumn === void 0 ? endColumn : endColumn + columnOffset;
|
263
|
+
|
264
|
+
return {
|
265
|
+
line: line + lineOffset,
|
266
|
+
column: column + columnOffset,
|
267
|
+
endLine: finalEndLine,
|
268
|
+
endColumn: finalEndColumn
|
269
|
+
};
|
270
|
+
}
|
271
|
+
|
242
272
|
/**
|
243
273
|
* creates a linting problem
|
244
274
|
* @param {Object} options to create linting error
|
@@ -246,6 +276,7 @@ function createMissingRuleMessage(ruleId) {
|
|
246
276
|
* @param {Object} [options.loc] the loc to report
|
247
277
|
* @param {string} [options.message] the error message to report
|
248
278
|
* @param {string} [options.severity] the error message to report
|
279
|
+
* @param {Language} [options.language] the language to use to adjust the location information
|
249
280
|
* @returns {LintMessage} created problem, returns a missing-rule problem if only provided ruleId.
|
250
281
|
* @private
|
251
282
|
*/
|
@@ -254,16 +285,24 @@ function createLintingProblem(options) {
|
|
254
285
|
ruleId = null,
|
255
286
|
loc = DEFAULT_ERROR_LOC,
|
256
287
|
message = createMissingRuleMessage(options.ruleId),
|
257
|
-
severity = 2
|
288
|
+
severity = 2,
|
289
|
+
|
290
|
+
// fallback for eslintrc mode
|
291
|
+
language = {
|
292
|
+
columnStart: 0,
|
293
|
+
lineStart: 1
|
294
|
+
}
|
258
295
|
} = options;
|
259
296
|
|
260
297
|
return {
|
261
298
|
ruleId,
|
262
299
|
message,
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
300
|
+
...updateLocationInformation({
|
301
|
+
line: loc.start.line,
|
302
|
+
column: loc.start.column,
|
303
|
+
endLine: loc.end.line,
|
304
|
+
endColumn: loc.end.column
|
305
|
+
}, language),
|
267
306
|
severity,
|
268
307
|
nodeType: null
|
269
308
|
};
|
@@ -541,10 +580,11 @@ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig, config)
|
|
541
580
|
* Parses comments in file to extract disable directives.
|
542
581
|
* @param {SourceCode} sourceCode The SourceCode object to get comments from.
|
543
582
|
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
583
|
+
* @param {Language} language The language to use to adjust the location information
|
544
584
|
* @returns {{problems: LintMessage[], disableDirectives: DisableDirective[]}}
|
545
585
|
* A collection of the directive comments that were found, along with any problems that occurred when parsing
|
546
586
|
*/
|
547
|
-
function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper) {
|
587
|
+
function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper, language) {
|
548
588
|
const disableDirectives = [];
|
549
589
|
const problems = [];
|
550
590
|
|
@@ -553,7 +593,10 @@ function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper) {
|
|
553
593
|
problems: directivesProblems
|
554
594
|
} = sourceCode.getDisableDirectives();
|
555
595
|
|
556
|
-
problems.push(...directivesProblems.map(createLintingProblem
|
596
|
+
problems.push(...directivesProblems.map(directiveProblem => createLintingProblem({
|
597
|
+
...directiveProblem,
|
598
|
+
language
|
599
|
+
})));
|
557
600
|
|
558
601
|
directivesSources.forEach(directive => {
|
559
602
|
const { directives, directiveProblems } = createDisableDirectives(directive, ruleMapper);
|
@@ -781,24 +824,6 @@ function resolveGlobals(providedGlobals, enabledEnvironments) {
|
|
781
824
|
);
|
782
825
|
}
|
783
826
|
|
784
|
-
/**
|
785
|
-
* Strips Unicode BOM from a given text.
|
786
|
-
* @param {string} text A text to strip.
|
787
|
-
* @returns {string} The stripped text.
|
788
|
-
*/
|
789
|
-
function stripUnicodeBOM(text) {
|
790
|
-
|
791
|
-
/*
|
792
|
-
* Check Unicode BOM.
|
793
|
-
* In JavaScript, string data is stored as UTF-16, so BOM is 0xFEFF.
|
794
|
-
* http://www.ecma-international.org/ecma-262/6.0/#sec-unicode-format-control-characters
|
795
|
-
*/
|
796
|
-
if (text.charCodeAt(0) === 0xFEFF) {
|
797
|
-
return text.slice(1);
|
798
|
-
}
|
799
|
-
return text;
|
800
|
-
}
|
801
|
-
|
802
827
|
/**
|
803
828
|
* Store time measurements in map
|
804
829
|
* @param {number} time Time measurement
|
@@ -866,93 +891,40 @@ function analyzeScope(ast, languageOptions, visitorKeys) {
|
|
866
891
|
}
|
867
892
|
|
868
893
|
/**
|
869
|
-
* Parses
|
894
|
+
* Parses file into an AST. Moved out here because the try-catch prevents
|
870
895
|
* optimization of functions, so it's best to keep the try-catch as isolated
|
871
896
|
* as possible
|
872
|
-
* @param {
|
897
|
+
* @param {VFile} file The file to parse.
|
898
|
+
* @param {Language} language The language to use.
|
873
899
|
* @param {LanguageOptions} languageOptions Options to pass to the parser
|
874
|
-
* @param {string} filePath The path to the file being parsed.
|
875
900
|
* @returns {{success: false, error: LintMessage}|{success: true, sourceCode: SourceCode}}
|
876
901
|
* An object containing the AST and parser services if parsing was successful, or the error if parsing failed
|
877
902
|
* @private
|
878
903
|
*/
|
879
|
-
function parse(
|
880
|
-
const textToParse = stripUnicodeBOM(text).replace(astUtils.shebangPattern, (match, captured) => `//${captured}`);
|
881
|
-
const { ecmaVersion, sourceType, parser } = languageOptions;
|
882
|
-
const parserOptions = Object.assign(
|
883
|
-
{ ecmaVersion, sourceType },
|
884
|
-
languageOptions.parserOptions,
|
885
|
-
{
|
886
|
-
loc: true,
|
887
|
-
range: true,
|
888
|
-
raw: true,
|
889
|
-
tokens: true,
|
890
|
-
comment: true,
|
891
|
-
eslintVisitorKeys: true,
|
892
|
-
eslintScopeManager: true,
|
893
|
-
filePath
|
894
|
-
}
|
895
|
-
);
|
896
|
-
|
897
|
-
/*
|
898
|
-
* Check for parsing errors first. If there's a parsing error, nothing
|
899
|
-
* else can happen. However, a parsing error does not throw an error
|
900
|
-
* from this method - it's just considered a fatal error message, a
|
901
|
-
* problem that ESLint identified just like any other.
|
902
|
-
*/
|
903
|
-
try {
|
904
|
-
debug("Parsing:", filePath);
|
905
|
-
const parseResult = (typeof parser.parseForESLint === "function")
|
906
|
-
? parser.parseForESLint(textToParse, parserOptions)
|
907
|
-
: { ast: parser.parse(textToParse, parserOptions) };
|
904
|
+
function parse(file, language, languageOptions) {
|
908
905
|
|
909
|
-
|
910
|
-
const ast = parseResult.ast;
|
911
|
-
const parserServices = parseResult.services || {};
|
912
|
-
const visitorKeys = parseResult.visitorKeys || evk.KEYS;
|
913
|
-
|
914
|
-
debug("Scope analysis:", filePath);
|
915
|
-
const scopeManager = parseResult.scopeManager || analyzeScope(ast, languageOptions, visitorKeys);
|
916
|
-
|
917
|
-
debug("Scope analysis successful:", filePath);
|
906
|
+
const result = language.parse(file, { languageOptions });
|
918
907
|
|
908
|
+
if (result.ok) {
|
919
909
|
return {
|
920
910
|
success: true,
|
921
|
-
|
922
|
-
/*
|
923
|
-
* Save all values that `parseForESLint()` returned.
|
924
|
-
* If a `SourceCode` object is given as the first parameter instead of source code text,
|
925
|
-
* linter skips the parsing process and reuses the source code object.
|
926
|
-
* In that case, linter needs all the values that `parseForESLint()` returned.
|
927
|
-
*/
|
928
|
-
sourceCode: new SourceCode({
|
929
|
-
text,
|
930
|
-
ast,
|
931
|
-
parserServices,
|
932
|
-
scopeManager,
|
933
|
-
visitorKeys
|
934
|
-
})
|
935
|
-
};
|
936
|
-
} catch (ex) {
|
937
|
-
|
938
|
-
// If the message includes a leading line number, strip it:
|
939
|
-
const message = `Parsing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
|
940
|
-
|
941
|
-
debug("%s\n%s", message, ex.stack);
|
942
|
-
|
943
|
-
return {
|
944
|
-
success: false,
|
945
|
-
error: {
|
946
|
-
ruleId: null,
|
947
|
-
fatal: true,
|
948
|
-
severity: 2,
|
949
|
-
message,
|
950
|
-
line: ex.lineNumber,
|
951
|
-
column: ex.column,
|
952
|
-
nodeType: null
|
953
|
-
}
|
911
|
+
sourceCode: language.createSourceCode(file, result, { languageOptions })
|
954
912
|
};
|
955
913
|
}
|
914
|
+
|
915
|
+
// if we made it to here there was an error
|
916
|
+
return {
|
917
|
+
success: false,
|
918
|
+
errors: result.errors.map(error => ({
|
919
|
+
ruleId: null,
|
920
|
+
nodeType: null,
|
921
|
+
fatal: true,
|
922
|
+
severity: 2,
|
923
|
+
message: error.message,
|
924
|
+
line: error.line,
|
925
|
+
column: error.column
|
926
|
+
}))
|
927
|
+
};
|
956
928
|
}
|
957
929
|
|
958
930
|
/**
|
@@ -983,6 +955,7 @@ function createRuleListeners(rule, ruleContext) {
|
|
983
955
|
* @param {Object} configuredRules The rules configuration
|
984
956
|
* @param {function(string): Rule} ruleMapper A mapper function from rule names to rules
|
985
957
|
* @param {string | undefined} parserName The name of the parser in the config
|
958
|
+
* @param {Language} language The language object used for parsing.
|
986
959
|
* @param {LanguageOptions} languageOptions The options for parsing the code.
|
987
960
|
* @param {Object} settings The settings that were enabled in the config
|
988
961
|
* @param {string} filename The reported filename of the code
|
@@ -995,8 +968,11 @@ function createRuleListeners(rule, ruleContext) {
|
|
995
968
|
* @returns {LintMessage[]} An array of reported problems
|
996
969
|
* @throws {Error} If traversal into a node fails.
|
997
970
|
*/
|
998
|
-
function runRules(
|
999
|
-
|
971
|
+
function runRules(
|
972
|
+
sourceCode, configuredRules, ruleMapper, parserName, language, languageOptions,
|
973
|
+
settings, filename, disableFixes, cwd, physicalFilename, ruleFilter,
|
974
|
+
stats, slots
|
975
|
+
) {
|
1000
976
|
const emitter = createEmitter();
|
1001
977
|
|
1002
978
|
// must happen first to assign all node.parent properties
|
@@ -1043,7 +1019,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
|
|
1043
1019
|
const rule = ruleMapper(ruleId);
|
1044
1020
|
|
1045
1021
|
if (!rule) {
|
1046
|
-
lintingProblems.push(createLintingProblem({ ruleId }));
|
1022
|
+
lintingProblems.push(createLintingProblem({ ruleId, language }));
|
1047
1023
|
return;
|
1048
1024
|
}
|
1049
1025
|
|
@@ -1073,7 +1049,8 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
|
|
1073
1049
|
severity,
|
1074
1050
|
sourceCode,
|
1075
1051
|
messageIds,
|
1076
|
-
disableFixes
|
1052
|
+
disableFixes,
|
1053
|
+
language
|
1077
1054
|
});
|
1078
1055
|
}
|
1079
1056
|
const problem = reportTranslator(...args);
|
@@ -1144,7 +1121,12 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageO
|
|
1144
1121
|
});
|
1145
1122
|
});
|
1146
1123
|
|
1147
|
-
const eventGenerator = new NodeEventGenerator(emitter, {
|
1124
|
+
const eventGenerator = new NodeEventGenerator(emitter, {
|
1125
|
+
visitorKeys: sourceCode.visitorKeys,
|
1126
|
+
fallback: Traverser.getKeys,
|
1127
|
+
matchClass: language.matchesSelectorClass,
|
1128
|
+
nodeTypeKey: language.nodeTypeKey
|
1129
|
+
});
|
1148
1130
|
|
1149
1131
|
for (const step of eventQueue) {
|
1150
1132
|
switch (step.kind) {
|
@@ -1360,6 +1342,9 @@ class Linter {
|
|
1360
1342
|
parser,
|
1361
1343
|
parserOptions
|
1362
1344
|
});
|
1345
|
+
const file = new VFile(options.filename, text, {
|
1346
|
+
physicalPath: providedOptions.physicalFilename
|
1347
|
+
});
|
1363
1348
|
|
1364
1349
|
if (!slots.lastSourceCode) {
|
1365
1350
|
let t;
|
@@ -1369,9 +1354,9 @@ class Linter {
|
|
1369
1354
|
}
|
1370
1355
|
|
1371
1356
|
const parseResult = parse(
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1357
|
+
file,
|
1358
|
+
jslang,
|
1359
|
+
languageOptions
|
1375
1360
|
);
|
1376
1361
|
|
1377
1362
|
if (options.stats) {
|
@@ -1382,7 +1367,7 @@ class Linter {
|
|
1382
1367
|
}
|
1383
1368
|
|
1384
1369
|
if (!parseResult.success) {
|
1385
|
-
return
|
1370
|
+
return parseResult.errors;
|
1386
1371
|
}
|
1387
1372
|
|
1388
1373
|
slots.lastSourceCode = parseResult.sourceCode;
|
@@ -1396,6 +1381,7 @@ class Linter {
|
|
1396
1381
|
slots.lastSourceCode = new SourceCode({
|
1397
1382
|
text: slots.lastSourceCode.text,
|
1398
1383
|
ast: slots.lastSourceCode.ast,
|
1384
|
+
hasBOM: slots.lastSourceCode.hasBOM,
|
1399
1385
|
parserServices: slots.lastSourceCode.parserServices,
|
1400
1386
|
visitorKeys: slots.lastSourceCode.visitorKeys,
|
1401
1387
|
scopeManager: analyzeScope(slots.lastSourceCode.ast, languageOptions)
|
@@ -1408,7 +1394,6 @@ class Linter {
|
|
1408
1394
|
? getDirectiveComments(sourceCode, ruleId => getRule(slots, ruleId), options.warnInlineConfig, config)
|
1409
1395
|
: { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] };
|
1410
1396
|
|
1411
|
-
// augment global scope with declared global variables
|
1412
1397
|
addDeclaredGlobals(
|
1413
1398
|
sourceCode.scopeManager.scopes[0],
|
1414
1399
|
configuredGlobals,
|
@@ -1425,6 +1410,7 @@ class Linter {
|
|
1425
1410
|
configuredRules,
|
1426
1411
|
ruleId => getRule(slots, ruleId),
|
1427
1412
|
parserName,
|
1413
|
+
jslang,
|
1428
1414
|
languageOptions,
|
1429
1415
|
settings,
|
1430
1416
|
options.filename,
|
@@ -1457,6 +1443,7 @@ class Linter {
|
|
1457
1443
|
}
|
1458
1444
|
|
1459
1445
|
return applyDisableDirectives({
|
1446
|
+
language: jslang,
|
1460
1447
|
directives: commentDirectives.disableDirectives,
|
1461
1448
|
disableFixes: options.disableFixes,
|
1462
1449
|
problems: lintingProblems
|
@@ -1659,6 +1646,9 @@ class Linter {
|
|
1659
1646
|
}
|
1660
1647
|
|
1661
1648
|
const settings = config.settings || {};
|
1649
|
+
const file = new VFile(options.filename, text, {
|
1650
|
+
physicalPath: providedOptions.physicalFilename
|
1651
|
+
});
|
1662
1652
|
|
1663
1653
|
if (!slots.lastSourceCode) {
|
1664
1654
|
let t;
|
@@ -1668,9 +1658,9 @@ class Linter {
|
|
1668
1658
|
}
|
1669
1659
|
|
1670
1660
|
const parseResult = parse(
|
1671
|
-
|
1672
|
-
|
1673
|
-
|
1661
|
+
file,
|
1662
|
+
config.language,
|
1663
|
+
languageOptions
|
1674
1664
|
);
|
1675
1665
|
|
1676
1666
|
if (options.stats) {
|
@@ -1680,7 +1670,7 @@ class Linter {
|
|
1680
1670
|
}
|
1681
1671
|
|
1682
1672
|
if (!parseResult.success) {
|
1683
|
-
return
|
1673
|
+
return parseResult.errors;
|
1684
1674
|
}
|
1685
1675
|
|
1686
1676
|
slots.lastSourceCode = parseResult.sourceCode;
|
@@ -1694,6 +1684,7 @@ class Linter {
|
|
1694
1684
|
slots.lastSourceCode = new SourceCode({
|
1695
1685
|
text: slots.lastSourceCode.text,
|
1696
1686
|
ast: slots.lastSourceCode.ast,
|
1687
|
+
hasBOM: slots.lastSourceCode.hasBOM,
|
1697
1688
|
parserServices: slots.lastSourceCode.parserServices,
|
1698
1689
|
visitorKeys: slots.lastSourceCode.visitorKeys,
|
1699
1690
|
scopeManager: analyzeScope(slots.lastSourceCode.ast, languageOptions)
|
@@ -1730,7 +1721,8 @@ class Linter {
|
|
1730
1721
|
ruleId: null,
|
1731
1722
|
message: `'${sourceCode.text.slice(node.range[0], node.range[1])}' has no effect because you have 'noInlineConfig' setting in ${options.warnInlineConfig}.`,
|
1732
1723
|
loc: node.loc,
|
1733
|
-
severity: 1
|
1724
|
+
severity: 1,
|
1725
|
+
language: config.language
|
1734
1726
|
}));
|
1735
1727
|
|
1736
1728
|
});
|
@@ -1739,7 +1731,7 @@ class Linter {
|
|
1739
1731
|
|
1740
1732
|
inlineConfigProblems.push(
|
1741
1733
|
...inlineConfigResult.problems
|
1742
|
-
.map(createLintingProblem)
|
1734
|
+
.map(problem => createLintingProblem({ ...problem, language: config.language }))
|
1743
1735
|
.map(problem => {
|
1744
1736
|
problem.fatal = true;
|
1745
1737
|
return problem;
|
@@ -1756,14 +1748,19 @@ class Linter {
|
|
1756
1748
|
const ruleValue = inlineConfig.rules[ruleId];
|
1757
1749
|
|
1758
1750
|
if (!rule) {
|
1759
|
-
inlineConfigProblems.push(createLintingProblem({
|
1751
|
+
inlineConfigProblems.push(createLintingProblem({
|
1752
|
+
ruleId,
|
1753
|
+
loc: node.loc,
|
1754
|
+
language: config.language
|
1755
|
+
}));
|
1760
1756
|
return;
|
1761
1757
|
}
|
1762
1758
|
|
1763
1759
|
if (Object.hasOwn(mergedInlineConfig.rules, ruleId)) {
|
1764
1760
|
inlineConfigProblems.push(createLintingProblem({
|
1765
1761
|
message: `Rule "${ruleId}" is already configured by another configuration comment in the preceding code. This configuration is ignored.`,
|
1766
|
-
loc: node.loc
|
1762
|
+
loc: node.loc,
|
1763
|
+
language: config.language
|
1767
1764
|
}));
|
1768
1765
|
return;
|
1769
1766
|
}
|
@@ -1855,7 +1852,8 @@ class Linter {
|
|
1855
1852
|
inlineConfigProblems.push(createLintingProblem({
|
1856
1853
|
ruleId,
|
1857
1854
|
message: `Inline configuration for rule "${ruleId}" is invalid:\n\t${baseMessage}\n`,
|
1858
|
-
loc: node.loc
|
1855
|
+
loc: node.loc,
|
1856
|
+
language: config.language
|
1859
1857
|
}));
|
1860
1858
|
}
|
1861
1859
|
});
|
@@ -1866,7 +1864,8 @@ class Linter {
|
|
1866
1864
|
const commentDirectives = options.allowInlineConfig && !options.warnInlineConfig
|
1867
1865
|
? getDirectiveCommentsForFlatConfig(
|
1868
1866
|
sourceCode,
|
1869
|
-
ruleId => getRuleFromConfig(ruleId, config)
|
1867
|
+
ruleId => getRuleFromConfig(ruleId, config),
|
1868
|
+
config.language
|
1870
1869
|
)
|
1871
1870
|
: { problems: [], disableDirectives: [] };
|
1872
1871
|
|
@@ -1882,6 +1881,7 @@ class Linter {
|
|
1882
1881
|
configuredRules,
|
1883
1882
|
ruleId => getRuleFromConfig(ruleId, config),
|
1884
1883
|
void 0,
|
1884
|
+
config.language,
|
1885
1885
|
languageOptions,
|
1886
1886
|
settings,
|
1887
1887
|
options.filename,
|
@@ -1915,6 +1915,7 @@ class Linter {
|
|
1915
1915
|
}
|
1916
1916
|
|
1917
1917
|
return applyDisableDirectives({
|
1918
|
+
language: config.language,
|
1918
1919
|
directives: commentDirectives.disableDirectives,
|
1919
1920
|
disableFixes: options.disableFixes,
|
1920
1921
|
problems: lintingProblems
|
@@ -240,15 +240,22 @@ function mapSuggestions(descriptor, sourceCode, messages) {
|
|
240
240
|
* @param {{start: SourceLocation, end: (SourceLocation|null)}} options.loc Start and end location
|
241
241
|
* @param {{text: string, range: (number[]|null)}} options.fix The fix object
|
242
242
|
* @param {Array<{text: string, range: (number[]|null)}>} options.suggestions The array of suggestions objects
|
243
|
+
* @param {Language} [options.language] The language to use to adjust line and column offsets.
|
243
244
|
* @returns {LintMessage} Information about the report
|
244
245
|
*/
|
245
246
|
function createProblem(options) {
|
247
|
+
const { language } = options;
|
248
|
+
|
249
|
+
// calculate offsets based on the language in use
|
250
|
+
const columnOffset = language.columnStart === 1 ? 0 : 1;
|
251
|
+
const lineOffset = language.lineStart === 1 ? 0 : 1;
|
252
|
+
|
246
253
|
const problem = {
|
247
254
|
ruleId: options.ruleId,
|
248
255
|
severity: options.severity,
|
249
256
|
message: options.message,
|
250
|
-
line: options.loc.start.line,
|
251
|
-
column: options.loc.start.column +
|
257
|
+
line: options.loc.start.line + lineOffset,
|
258
|
+
column: options.loc.start.column + columnOffset,
|
252
259
|
nodeType: options.node && options.node.type || null
|
253
260
|
};
|
254
261
|
|
@@ -261,8 +268,8 @@ function createProblem(options) {
|
|
261
268
|
}
|
262
269
|
|
263
270
|
if (options.loc.end) {
|
264
|
-
problem.endLine = options.loc.end.line;
|
265
|
-
problem.endColumn = options.loc.end.column +
|
271
|
+
problem.endLine = options.loc.end.line + lineOffset;
|
272
|
+
problem.endColumn = options.loc.end.column + columnOffset;
|
266
273
|
}
|
267
274
|
|
268
275
|
if (options.fix) {
|
@@ -313,8 +320,7 @@ function validateSuggestions(suggest, messages) {
|
|
313
320
|
/**
|
314
321
|
* Returns a function that converts the arguments of a `context.report` call from a rule into a reported
|
315
322
|
* problem for the Node.js API.
|
316
|
-
* @param {{ruleId: string, severity: number, sourceCode: SourceCode, messageIds: Object, disableFixes: boolean}} metadata Metadata for the reported problem
|
317
|
-
* @param {SourceCode} sourceCode The `SourceCode` instance for the text being linted
|
323
|
+
* @param {{ruleId: string, severity: number, sourceCode: SourceCode, messageIds: Object, disableFixes: boolean, language:Language}} metadata Metadata for the reported problem
|
318
324
|
* @returns {function(...args): LintMessage} Function that returns information about the report
|
319
325
|
*/
|
320
326
|
|
@@ -363,7 +369,8 @@ module.exports = function createReportTranslator(metadata) {
|
|
363
369
|
messageId: descriptor.messageId,
|
364
370
|
loc: normalizeReportLoc(descriptor),
|
365
371
|
fix: metadata.disableFixes ? null : normalizeFixes(descriptor, metadata.sourceCode),
|
366
|
-
suggestions: metadata.disableFixes ? [] : mapSuggestions(descriptor, metadata.sourceCode, messages)
|
372
|
+
suggestions: metadata.disableFixes ? [] : mapSuggestions(descriptor, metadata.sourceCode, messages),
|
373
|
+
language: metadata.language
|
367
374
|
});
|
368
375
|
};
|
369
376
|
};
|
@@ -0,0 +1,104 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Virtual file
|
3
|
+
* @author Nicholas C. Zakas
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Helpers
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Determines if a given value has a byte order mark (BOM).
|
14
|
+
* @param {string|Uint8Array} value The value to check.
|
15
|
+
* @returns {boolean} `true` if the value has a BOM, `false` otherwise.
|
16
|
+
*/
|
17
|
+
function hasUnicodeBOM(value) {
|
18
|
+
return typeof value === "string"
|
19
|
+
? value.charCodeAt(0) === 0xFEFF
|
20
|
+
: value[0] === 0xEF && value[1] === 0xBB && value[2] === 0xBF;
|
21
|
+
}
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Strips Unicode BOM from the given value.
|
25
|
+
* @param {string|Uint8Array} value The value to remove the BOM from.
|
26
|
+
* @returns {string|Uint8Array} The stripped value.
|
27
|
+
*/
|
28
|
+
function stripUnicodeBOM(value) {
|
29
|
+
|
30
|
+
if (!hasUnicodeBOM(value)) {
|
31
|
+
return value;
|
32
|
+
}
|
33
|
+
|
34
|
+
if (typeof value === "string") {
|
35
|
+
|
36
|
+
/*
|
37
|
+
* Check Unicode BOM.
|
38
|
+
* In JavaScript, string data is stored as UTF-16, so BOM is 0xFEFF.
|
39
|
+
* http://www.ecma-international.org/ecma-262/6.0/#sec-unicode-format-control-characters
|
40
|
+
*/
|
41
|
+
return value.slice(1);
|
42
|
+
}
|
43
|
+
|
44
|
+
/*
|
45
|
+
* In a Uint8Array, the BOM is represented by three bytes: 0xEF, 0xBB, and 0xBF,
|
46
|
+
* so we can just remove the first three bytes.
|
47
|
+
*/
|
48
|
+
return value.slice(3);
|
49
|
+
}
|
50
|
+
|
51
|
+
//------------------------------------------------------------------------------
|
52
|
+
// Exports
|
53
|
+
//------------------------------------------------------------------------------
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Represents a virtual file inside of ESLint.
|
57
|
+
*/
|
58
|
+
class VFile {
|
59
|
+
|
60
|
+
/**
|
61
|
+
* The file path including any processor-created virtual path.
|
62
|
+
* @type {string}
|
63
|
+
* @readonly
|
64
|
+
*/
|
65
|
+
path;
|
66
|
+
|
67
|
+
/**
|
68
|
+
* The file path on disk.
|
69
|
+
* @type {string}
|
70
|
+
* @readonly
|
71
|
+
*/
|
72
|
+
physicalPath;
|
73
|
+
|
74
|
+
/**
|
75
|
+
* The file contents.
|
76
|
+
* @type {string|Uint8Array}
|
77
|
+
* @readonly
|
78
|
+
*/
|
79
|
+
body;
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Indicates whether the file has a byte order mark (BOM).
|
83
|
+
* @type {boolean}
|
84
|
+
* @readonly
|
85
|
+
*/
|
86
|
+
bom;
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Creates a new instance.
|
90
|
+
* @param {string} path The file path.
|
91
|
+
* @param {string|Uint8Array} body The file contents.
|
92
|
+
* @param {Object} [options] Additional options.
|
93
|
+
* @param {string} [options.physicalPath] The file path on disk.
|
94
|
+
*/
|
95
|
+
constructor(path, body, { physicalPath } = {}) {
|
96
|
+
this.path = path;
|
97
|
+
this.physicalPath = physicalPath ?? path;
|
98
|
+
this.bom = hasUnicodeBOM(body);
|
99
|
+
this.body = stripUnicodeBOM(body);
|
100
|
+
}
|
101
|
+
|
102
|
+
}
|
103
|
+
|
104
|
+
module.exports = { VFile };
|
@@ -27,10 +27,11 @@ const { defaultConfig } = require("../config/default-config");
|
|
27
27
|
const ajv = require("../shared/ajv")({ strictDefaults: true });
|
28
28
|
|
29
29
|
const parserSymbol = Symbol.for("eslint.RuleTester.parser");
|
30
|
-
const { SourceCode } = require("../source-code");
|
31
30
|
const { ConfigArraySymbol } = require("@eslint/config-array");
|
32
31
|
const { isSerializable } = require("../shared/serialization");
|
33
32
|
|
33
|
+
const { SourceCode } = require("../languages/js/source-code");
|
34
|
+
|
34
35
|
//------------------------------------------------------------------------------
|
35
36
|
// Typedefs
|
36
37
|
//------------------------------------------------------------------------------
|
@@ -591,7 +592,8 @@ class RuleTester {
|
|
591
592
|
* here, just use the default one to keep that performance
|
592
593
|
* enhancement.
|
593
594
|
*/
|
594
|
-
rules: defaultConfig[0].plugins["@"].rules
|
595
|
+
rules: defaultConfig[0].plugins["@"].rules,
|
596
|
+
languages: defaultConfig[0].plugins["@"].languages
|
595
597
|
},
|
596
598
|
"rule-to-test": {
|
597
599
|
rules: {
|
@@ -611,6 +613,7 @@ class RuleTester {
|
|
611
613
|
}
|
612
614
|
}
|
613
615
|
},
|
616
|
+
language: defaultConfig[0].language,
|
614
617
|
languageOptions: {
|
615
618
|
...defaultConfig[0].languageOptions
|
616
619
|
}
|