eslint 10.0.0-alpha.1 → 10.0.0-beta.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 +1 -1
- package/lib/api.js +2 -2
- package/lib/cli-engine/formatters/stylish.js +65 -34
- package/lib/cli.js +18 -8
- package/lib/eslint/eslint.js +4 -2
- package/lib/languages/js/index.js +1 -0
- package/lib/linter/linter.js +1 -0
- package/lib/rule-tester/rule-tester.js +107 -43
- package/lib/rules/no-restricted-imports.js +56 -14
- package/lib/rules/no-useless-assignment.js +8 -5
- package/lib/rules/utils/ast-utils.js +39 -36
- package/lib/types/index.d.ts +59 -15
- package/lib/types/use-at-your-own-risk.d.ts +1 -1
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -343,7 +343,7 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
|
|
|
343
343
|
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="128"></a></p><h3>Gold Sponsors</h3>
|
|
344
344
|
<p><a href="https://qlty.sh/"><img src="https://images.opencollective.com/qltysh/33d157d/logo.png" alt="Qlty Software" height="96"></a> <a href="https://shopify.engineering/"><img src="https://avatars.githubusercontent.com/u/8085" alt="Shopify" height="96"></a></p><h3>Silver Sponsors</h3>
|
|
345
345
|
<p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/2d6c3b6/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
|
|
346
|
-
<p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://www.n-ix.com/"><img src="https://images.opencollective.com/n-ix-ltd/575a7a5/logo.png" alt="N-iX Ltd" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://
|
|
346
|
+
<p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://www.crawljobs.com/"><img src="https://images.opencollective.com/crawljobs-poland/fa43a17/logo.png" alt="CrawlJobs" height="32"></a> <a href="https://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://www.n-ix.com/"><img src="https://images.opencollective.com/n-ix-ltd/575a7a5/logo.png" alt="N-iX Ltd" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
|
|
347
347
|
<h3>Technology Sponsors</h3>
|
|
348
348
|
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.
|
|
349
349
|
<p><a href="https://netlify.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/netlify-icon.svg" alt="Netlify" height="32"></a> <a href="https://algolia.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/algolia-icon.svg" alt="Algolia" height="32"></a> <a href="https://1password.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/1password-icon.svg" alt="1Password" height="32"></a></p>
|
package/lib/api.js
CHANGED
|
@@ -19,8 +19,8 @@ const { SourceCode } = require("./languages/js/source-code");
|
|
|
19
19
|
//-----------------------------------------------------------------------------
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Loads the correct ESLint constructor
|
|
23
|
-
* @returns {Promise<ESLint>} The ESLint constructor
|
|
22
|
+
* Loads the correct `ESLint` constructor.
|
|
23
|
+
* @returns {Promise<ESLint>} The ESLint constructor.
|
|
24
24
|
*/
|
|
25
25
|
async function loadESLint() {
|
|
26
26
|
return ESLint;
|
|
@@ -4,14 +4,30 @@
|
|
|
4
4
|
*/
|
|
5
5
|
"use strict";
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
util = require("node:util"),
|
|
7
|
+
const util = require("node:util"),
|
|
9
8
|
table = require("../../shared/text-table");
|
|
10
9
|
|
|
11
10
|
//------------------------------------------------------------------------------
|
|
12
11
|
// Helpers
|
|
13
12
|
//------------------------------------------------------------------------------
|
|
14
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Returns a styling function based on the color option.
|
|
16
|
+
* @param {boolean|undefined} color Indicates whether to use colors.
|
|
17
|
+
* @returns {Function} A function that styles text.
|
|
18
|
+
*/
|
|
19
|
+
function getStyleText(color) {
|
|
20
|
+
if (typeof color === "undefined") {
|
|
21
|
+
return (format, text) =>
|
|
22
|
+
util.styleText(format, text, { validateStream: true });
|
|
23
|
+
}
|
|
24
|
+
if (color) {
|
|
25
|
+
return (format, text) =>
|
|
26
|
+
util.styleText(format, text, { validateStream: false });
|
|
27
|
+
}
|
|
28
|
+
return (_, text) => text;
|
|
29
|
+
}
|
|
30
|
+
|
|
15
31
|
/**
|
|
16
32
|
* Given a word and a count, append an s if count is not one.
|
|
17
33
|
* @param {string} word A word in its singular form.
|
|
@@ -26,7 +42,9 @@ function pluralize(word, count) {
|
|
|
26
42
|
// Public Interface
|
|
27
43
|
//------------------------------------------------------------------------------
|
|
28
44
|
|
|
29
|
-
module.exports = function (results) {
|
|
45
|
+
module.exports = function (results, data) {
|
|
46
|
+
const styleText = getStyleText(data?.color);
|
|
47
|
+
|
|
30
48
|
let output = "\n",
|
|
31
49
|
errorCount = 0,
|
|
32
50
|
warningCount = 0,
|
|
@@ -46,17 +64,17 @@ module.exports = function (results) {
|
|
|
46
64
|
fixableErrorCount += result.fixableErrorCount;
|
|
47
65
|
fixableWarningCount += result.fixableWarningCount;
|
|
48
66
|
|
|
49
|
-
output += `${
|
|
67
|
+
output += `${styleText("underline", result.filePath)}\n`;
|
|
50
68
|
|
|
51
69
|
output += `${table(
|
|
52
70
|
messages.map(message => {
|
|
53
71
|
let messageType;
|
|
54
72
|
|
|
55
73
|
if (message.fatal || message.severity === 2) {
|
|
56
|
-
messageType =
|
|
74
|
+
messageType = styleText("red", "error");
|
|
57
75
|
summaryColor = "red";
|
|
58
76
|
} else {
|
|
59
|
-
messageType =
|
|
77
|
+
messageType = styleText("yellow", "warning");
|
|
60
78
|
}
|
|
61
79
|
|
|
62
80
|
return [
|
|
@@ -65,7 +83,7 @@ module.exports = function (results) {
|
|
|
65
83
|
String(message.column || 0),
|
|
66
84
|
messageType,
|
|
67
85
|
message.message.replace(/([^ ])\.$/u, "$1"),
|
|
68
|
-
|
|
86
|
+
message.ruleId ? styleText("dim", message.ruleId) : "",
|
|
69
87
|
];
|
|
70
88
|
}),
|
|
71
89
|
{
|
|
@@ -78,7 +96,7 @@ module.exports = function (results) {
|
|
|
78
96
|
.split("\n")
|
|
79
97
|
.map(el =>
|
|
80
98
|
el.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) =>
|
|
81
|
-
|
|
99
|
+
styleText("dim", `${p1}:${p2}`),
|
|
82
100
|
),
|
|
83
101
|
)
|
|
84
102
|
.join("\n")}\n\n`;
|
|
@@ -86,37 +104,50 @@ module.exports = function (results) {
|
|
|
86
104
|
|
|
87
105
|
const total = errorCount + warningCount;
|
|
88
106
|
|
|
107
|
+
/*
|
|
108
|
+
* We can't use a single `styleText` call like `styleText([summaryColor, "bold"], text)` here.
|
|
109
|
+
* This is a bug in `util.styleText` in Node.js versions earlier than v22.15.0 (https://github.com/nodejs/node/issues/56717).
|
|
110
|
+
* As a workaround, we use nested `styleText` calls.
|
|
111
|
+
*/
|
|
89
112
|
if (total > 0) {
|
|
90
|
-
output +=
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
pluralize(" problem", total),
|
|
95
|
-
" (",
|
|
96
|
-
errorCount,
|
|
97
|
-
pluralize(" error", errorCount),
|
|
98
|
-
", ",
|
|
99
|
-
warningCount,
|
|
100
|
-
pluralize(" warning", warningCount),
|
|
101
|
-
")\n",
|
|
102
|
-
].join(""),
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
if (fixableErrorCount > 0 || fixableWarningCount > 0) {
|
|
106
|
-
output += chalk[summaryColor].bold(
|
|
113
|
+
output += `${styleText(
|
|
114
|
+
summaryColor,
|
|
115
|
+
styleText(
|
|
116
|
+
"bold",
|
|
107
117
|
[
|
|
108
|
-
"
|
|
109
|
-
|
|
110
|
-
pluralize("
|
|
111
|
-
"
|
|
112
|
-
|
|
113
|
-
pluralize("
|
|
114
|
-
"
|
|
118
|
+
"\u2716 ",
|
|
119
|
+
total,
|
|
120
|
+
pluralize(" problem", total),
|
|
121
|
+
" (",
|
|
122
|
+
errorCount,
|
|
123
|
+
pluralize(" error", errorCount),
|
|
124
|
+
", ",
|
|
125
|
+
warningCount,
|
|
126
|
+
pluralize(" warning", warningCount),
|
|
127
|
+
")",
|
|
115
128
|
].join(""),
|
|
116
|
-
)
|
|
129
|
+
),
|
|
130
|
+
)}\n`;
|
|
131
|
+
|
|
132
|
+
if (fixableErrorCount > 0 || fixableWarningCount > 0) {
|
|
133
|
+
output += `${styleText(
|
|
134
|
+
summaryColor,
|
|
135
|
+
styleText(
|
|
136
|
+
"bold",
|
|
137
|
+
[
|
|
138
|
+
" ",
|
|
139
|
+
fixableErrorCount,
|
|
140
|
+
pluralize(" error", fixableErrorCount),
|
|
141
|
+
" and ",
|
|
142
|
+
fixableWarningCount,
|
|
143
|
+
pluralize(" warning", fixableWarningCount),
|
|
144
|
+
" potentially fixable with the `--fix` option.",
|
|
145
|
+
].join(""),
|
|
146
|
+
),
|
|
147
|
+
)}\n`;
|
|
117
148
|
}
|
|
118
149
|
}
|
|
119
150
|
|
|
120
151
|
// Resets output color, for prevent change on top level
|
|
121
|
-
return total > 0 ?
|
|
152
|
+
return total > 0 ? styleText("reset", output) : "";
|
|
122
153
|
};
|
package/lib/cli.js
CHANGED
|
@@ -454,14 +454,24 @@ const cli = {
|
|
|
454
454
|
const tooManyWarnings =
|
|
455
455
|
options.maxWarnings >= 0 &&
|
|
456
456
|
resultCounts.warningCount > options.maxWarnings;
|
|
457
|
-
const resultsMeta =
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
457
|
+
const resultsMeta = /** @type {ResultsMeta} */ ({});
|
|
458
|
+
|
|
459
|
+
/*
|
|
460
|
+
* `--color` was set, `options.color` is `true`.
|
|
461
|
+
* `--no-color` was set, `options.color` is `false`.
|
|
462
|
+
* Neither option was provided, `options.color` is omitted, so `undefined`.
|
|
463
|
+
*/
|
|
464
|
+
if (options.color !== void 0) {
|
|
465
|
+
debug(`Color setting for output: ${options.color}`);
|
|
466
|
+
resultsMeta.color = options.color;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (tooManyWarnings) {
|
|
470
|
+
resultsMeta.maxWarningsExceeded = {
|
|
471
|
+
maxWarnings: options.maxWarnings,
|
|
472
|
+
foundWarnings: resultCounts.warningCount,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
465
475
|
|
|
466
476
|
if (
|
|
467
477
|
await printResults(
|
package/lib/eslint/eslint.js
CHANGED
|
@@ -1207,6 +1207,7 @@ class ESLint {
|
|
|
1207
1207
|
const { cwd } = privateMembers.get(this).options;
|
|
1208
1208
|
|
|
1209
1209
|
let formatterPath;
|
|
1210
|
+
let isBuiltInFormatter = false;
|
|
1210
1211
|
|
|
1211
1212
|
// if there's a slash, then it's a file (TODO: this check seems dubious for scoped npm packages)
|
|
1212
1213
|
if (!namespace && normalizedFormatName.includes("/")) {
|
|
@@ -1228,6 +1229,7 @@ class ESLint {
|
|
|
1228
1229
|
"formatters",
|
|
1229
1230
|
`${normalizedFormatName}.js`,
|
|
1230
1231
|
);
|
|
1232
|
+
isBuiltInFormatter = true;
|
|
1231
1233
|
}
|
|
1232
1234
|
}
|
|
1233
1235
|
|
|
@@ -1237,7 +1239,7 @@ class ESLint {
|
|
|
1237
1239
|
formatter = (await import(pathToFileURL(formatterPath))).default;
|
|
1238
1240
|
} catch (ex) {
|
|
1239
1241
|
// check for formatters that have been removed
|
|
1240
|
-
if (removedFormatters.has(name)) {
|
|
1242
|
+
if (isBuiltInFormatter && removedFormatters.has(name)) {
|
|
1241
1243
|
ex.message = `The ${name} formatter is no longer part of core ESLint. Install it manually with \`npm install -D eslint-formatter-${name}\``;
|
|
1242
1244
|
} else {
|
|
1243
1245
|
ex.message = `There was a problem loading formatter: ${formatterPath}\nError: ${ex.message}`;
|
|
@@ -1344,7 +1346,7 @@ class ESLint {
|
|
|
1344
1346
|
|
|
1345
1347
|
/**
|
|
1346
1348
|
* Returns whether flat config should be used.
|
|
1347
|
-
* @returns {Promise<
|
|
1349
|
+
* @returns {Promise<true>} Whether flat config should be used.
|
|
1348
1350
|
*/
|
|
1349
1351
|
async function shouldUseFlatConfig() {
|
|
1350
1352
|
return true;
|
package/lib/linter/linter.js
CHANGED
|
@@ -387,9 +387,10 @@ function normalizeTestCase(item) {
|
|
|
387
387
|
* Asserts that the `errors` property of an invalid test case is valid.
|
|
388
388
|
* @param {number | string[]} errors The `errors` property of the invalid test case.
|
|
389
389
|
* @param {string} ruleName The name of the rule being tested.
|
|
390
|
+
* @param {Object} [assertionOptions] The assertion options for the test case.
|
|
390
391
|
* @returns {void}
|
|
391
392
|
*/
|
|
392
|
-
function assertErrorsProperty(errors, ruleName) {
|
|
393
|
+
function assertErrorsProperty(errors, ruleName, assertionOptions = {}) {
|
|
393
394
|
const isNumber = typeof errors === "number";
|
|
394
395
|
const isArray = Array.isArray(errors);
|
|
395
396
|
|
|
@@ -407,12 +408,75 @@ function assertErrorsProperty(errors, ruleName) {
|
|
|
407
408
|
}
|
|
408
409
|
}
|
|
409
410
|
|
|
411
|
+
const { requireMessage = false, requireLocation = false } =
|
|
412
|
+
assertionOptions;
|
|
413
|
+
|
|
410
414
|
if (isArray) {
|
|
411
415
|
assert.ok(
|
|
412
416
|
errors.length !== 0,
|
|
413
417
|
"Invalid cases must have at least one error",
|
|
414
418
|
);
|
|
419
|
+
|
|
420
|
+
for (const [number, error] of errors.entries()) {
|
|
421
|
+
if (typeof error === "string" || error instanceof RegExp) {
|
|
422
|
+
// Just an error message.
|
|
423
|
+
assert.ok(
|
|
424
|
+
requireMessage !== "messageId" && !requireLocation,
|
|
425
|
+
`errors[${number}] should be an object when 'assertionOptions.requireMessage' is 'messageId' or 'assertionOptions.requireLocation' is true.`,
|
|
426
|
+
);
|
|
427
|
+
} else if (typeof error === "object" && error !== null) {
|
|
428
|
+
/*
|
|
429
|
+
* Error object.
|
|
430
|
+
* This may have a message, messageId, data, line, and/or column.
|
|
431
|
+
*/
|
|
432
|
+
|
|
433
|
+
for (const propertyName of Object.keys(error)) {
|
|
434
|
+
assert.ok(
|
|
435
|
+
errorObjectParameters.has(propertyName),
|
|
436
|
+
`Invalid error property name '${propertyName}'. Expected one of ${friendlyErrorObjectParameterList}.`,
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (requireMessage === "message") {
|
|
441
|
+
assert.ok(
|
|
442
|
+
!hasOwnProperty(error, "messageId") &&
|
|
443
|
+
hasOwnProperty(error, "message"),
|
|
444
|
+
`errors[${number}] should specify 'message' (and not 'messageId') when 'assertionOptions.requireMessage' is 'message'.`,
|
|
445
|
+
);
|
|
446
|
+
} else if (requireMessage === "messageId") {
|
|
447
|
+
assert.ok(
|
|
448
|
+
!hasOwnProperty(error, "message") &&
|
|
449
|
+
hasOwnProperty(error, "messageId"),
|
|
450
|
+
`errors[${number}] should specify 'messageId' (and not 'message') when 'assertionOptions.requireMessage' is 'messageId'.`,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (hasOwnProperty(error, "message")) {
|
|
455
|
+
assert.ok(
|
|
456
|
+
!hasOwnProperty(error, "messageId"),
|
|
457
|
+
`errors[${number}] should not specify both 'message' and 'messageId'.`,
|
|
458
|
+
);
|
|
459
|
+
assert.ok(
|
|
460
|
+
!hasOwnProperty(error, "data"),
|
|
461
|
+
`errors[${number}] should not specify both 'data' and 'message'.`,
|
|
462
|
+
);
|
|
463
|
+
} else {
|
|
464
|
+
assert.ok(
|
|
465
|
+
hasOwnProperty(error, "messageId"),
|
|
466
|
+
`errors[${number}] must specify either 'messageId' or 'message'.`,
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
} else {
|
|
470
|
+
assert.fail(
|
|
471
|
+
`errors[${number}] must be a string, RegExp, or an object.`,
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
415
475
|
} else {
|
|
476
|
+
assert.ok(
|
|
477
|
+
!requireMessage && !requireLocation,
|
|
478
|
+
"Invalid cases must have 'errors' value as an array",
|
|
479
|
+
);
|
|
416
480
|
assert.ok(
|
|
417
481
|
errors > 0,
|
|
418
482
|
"Invalid cases must have 'error' value greater than 0",
|
|
@@ -564,13 +628,19 @@ function assertValidTestCase(item, seenTestCases) {
|
|
|
564
628
|
* @param {Object} item The invalid test case object to check.
|
|
565
629
|
* @param {Set<string>} seenTestCases Set of serialized test cases to check for duplicates.
|
|
566
630
|
* @param {string} ruleName The name of the rule being tested.
|
|
631
|
+
* @param {Object} [assertionOptions] The assertion options for the test case.
|
|
567
632
|
* @returns {void}
|
|
568
633
|
* @throws {AssertionError} If the test case is not valid.
|
|
569
634
|
*/
|
|
570
|
-
function assertInvalidTestCase(
|
|
635
|
+
function assertInvalidTestCase(
|
|
636
|
+
item,
|
|
637
|
+
seenTestCases,
|
|
638
|
+
ruleName,
|
|
639
|
+
assertionOptions = {},
|
|
640
|
+
) {
|
|
571
641
|
assertTestCommonProperties(item);
|
|
572
642
|
|
|
573
|
-
assertErrorsProperty(item.errors, ruleName);
|
|
643
|
+
assertErrorsProperty(item.errors, ruleName, assertionOptions);
|
|
574
644
|
|
|
575
645
|
// 'output' is optional, but if it exists it must be a string or null
|
|
576
646
|
if (hasOwnProperty(item, "output")) {
|
|
@@ -763,6 +833,10 @@ class RuleTester {
|
|
|
763
833
|
* @param {string} ruleName The name of the rule to run.
|
|
764
834
|
* @param {RuleDefinition} rule The rule to test.
|
|
765
835
|
* @param {{
|
|
836
|
+
* assertionOptions?: {
|
|
837
|
+
* requireMessage?: boolean | "message" | "messageId",
|
|
838
|
+
* requireLocation?: boolean
|
|
839
|
+
* },
|
|
766
840
|
* valid: (ValidTestCase | string)[],
|
|
767
841
|
* invalid: InvalidTestCase[]
|
|
768
842
|
* }} test The collection of tests to run.
|
|
@@ -1143,6 +1217,9 @@ class RuleTester {
|
|
|
1143
1217
|
* @private
|
|
1144
1218
|
*/
|
|
1145
1219
|
function testInvalidTemplate(item) {
|
|
1220
|
+
const { requireMessage = false, requireLocation = false } =
|
|
1221
|
+
test.assertionOptions ?? {};
|
|
1222
|
+
|
|
1146
1223
|
const ruleHasMetaMessages =
|
|
1147
1224
|
hasOwnProperty(rule, "meta") &&
|
|
1148
1225
|
hasOwnProperty(rule.meta, "messages");
|
|
@@ -1152,6 +1229,11 @@ class RuleTester {
|
|
|
1152
1229
|
.join(", ")}]`
|
|
1153
1230
|
: null;
|
|
1154
1231
|
|
|
1232
|
+
assert.ok(
|
|
1233
|
+
ruleHasMetaMessages || requireMessage !== "messageId",
|
|
1234
|
+
`Assertion options can not use 'requireMessage: "messageId"' if rule under test doesn't define 'meta.messages'.`,
|
|
1235
|
+
);
|
|
1236
|
+
|
|
1155
1237
|
const result = runRuleForItem(item);
|
|
1156
1238
|
const messages = result.messages;
|
|
1157
1239
|
|
|
@@ -1225,22 +1307,7 @@ class RuleTester {
|
|
|
1225
1307
|
* This may have a message, messageId, data, line, and/or column.
|
|
1226
1308
|
*/
|
|
1227
1309
|
|
|
1228
|
-
Object.keys(error).forEach(propertyName => {
|
|
1229
|
-
assert.ok(
|
|
1230
|
-
errorObjectParameters.has(propertyName),
|
|
1231
|
-
`Invalid error property name '${propertyName}'. Expected one of ${friendlyErrorObjectParameterList}.`,
|
|
1232
|
-
);
|
|
1233
|
-
});
|
|
1234
|
-
|
|
1235
1310
|
if (hasOwnProperty(error, "message")) {
|
|
1236
|
-
assert.ok(
|
|
1237
|
-
!hasOwnProperty(error, "messageId"),
|
|
1238
|
-
"Error should not specify both 'message' and a 'messageId'.",
|
|
1239
|
-
);
|
|
1240
|
-
assert.ok(
|
|
1241
|
-
!hasOwnProperty(error, "data"),
|
|
1242
|
-
"Error should not specify both 'data' and 'message'.",
|
|
1243
|
-
);
|
|
1244
1311
|
assertMessageMatches(
|
|
1245
1312
|
message.message,
|
|
1246
1313
|
error.message,
|
|
@@ -1298,33 +1365,34 @@ class RuleTester {
|
|
|
1298
1365
|
`Hydrated message "${rehydratedMessage}" does not match "${message.message}"`,
|
|
1299
1366
|
);
|
|
1300
1367
|
}
|
|
1301
|
-
} else {
|
|
1302
|
-
assert.fail(
|
|
1303
|
-
"Test error must specify either a 'messageId' or 'message'.",
|
|
1304
|
-
);
|
|
1305
1368
|
}
|
|
1306
1369
|
|
|
1370
|
+
const locationProperties = [
|
|
1371
|
+
"line",
|
|
1372
|
+
"column",
|
|
1373
|
+
"endLine",
|
|
1374
|
+
"endColumn",
|
|
1375
|
+
];
|
|
1307
1376
|
const actualLocation = {};
|
|
1308
1377
|
const expectedLocation = {};
|
|
1309
1378
|
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
if (hasOwnProperty(error, "column")) {
|
|
1316
|
-
actualLocation.column = message.column;
|
|
1317
|
-
expectedLocation.column = error.column;
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
if (hasOwnProperty(error, "endLine")) {
|
|
1321
|
-
actualLocation.endLine = message.endLine;
|
|
1322
|
-
expectedLocation.endLine = error.endLine;
|
|
1379
|
+
for (const key of locationProperties) {
|
|
1380
|
+
if (hasOwnProperty(error, key)) {
|
|
1381
|
+
actualLocation[key] = message[key];
|
|
1382
|
+
expectedLocation[key] = error[key];
|
|
1383
|
+
}
|
|
1323
1384
|
}
|
|
1324
1385
|
|
|
1325
|
-
if (
|
|
1326
|
-
|
|
1327
|
-
|
|
1386
|
+
if (requireLocation) {
|
|
1387
|
+
const missingKeys = locationProperties.filter(
|
|
1388
|
+
key =>
|
|
1389
|
+
!hasOwnProperty(error, key) &&
|
|
1390
|
+
hasOwnProperty(message, key),
|
|
1391
|
+
);
|
|
1392
|
+
assert.ok(
|
|
1393
|
+
missingKeys.length === 0,
|
|
1394
|
+
`Error is missing expected location properties: ${missingKeys.join(", ")}`,
|
|
1395
|
+
);
|
|
1328
1396
|
}
|
|
1329
1397
|
|
|
1330
1398
|
if (Object.keys(expectedLocation).length > 0) {
|
|
@@ -1550,11 +1618,6 @@ class RuleTester {
|
|
|
1550
1618
|
}
|
|
1551
1619
|
}
|
|
1552
1620
|
}
|
|
1553
|
-
} else {
|
|
1554
|
-
// Message was an unexpected type
|
|
1555
|
-
assert.fail(
|
|
1556
|
-
`Error should be a string, object, or RegExp, but found (${util.inspect(message)})`,
|
|
1557
|
-
);
|
|
1558
1621
|
}
|
|
1559
1622
|
}
|
|
1560
1623
|
}
|
|
@@ -1631,6 +1694,7 @@ class RuleTester {
|
|
|
1631
1694
|
item,
|
|
1632
1695
|
seenTestCases,
|
|
1633
1696
|
ruleName,
|
|
1697
|
+
test.assertionOptions,
|
|
1634
1698
|
);
|
|
1635
1699
|
testInvalidTemplate(item);
|
|
1636
1700
|
} finally {
|
|
@@ -10,6 +10,30 @@
|
|
|
10
10
|
|
|
11
11
|
const astUtils = require("./utils/ast-utils");
|
|
12
12
|
|
|
13
|
+
//------------------------------------------------------------------------------
|
|
14
|
+
// Helpers
|
|
15
|
+
//------------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Format import names for error messages.
|
|
19
|
+
* @param {string[]} importNames The import names to format.
|
|
20
|
+
* @returns {string} The formatted import names.
|
|
21
|
+
*/
|
|
22
|
+
function formatImportNames(importNames) {
|
|
23
|
+
return new Intl.ListFormat("en-US").format(
|
|
24
|
+
importNames.map(name => `'${name}'`),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns "is" or "are" based on the number of import names.
|
|
30
|
+
* @param {string[]} importNames The import names to check.
|
|
31
|
+
* @returns {string} "is" if one import name, otherwise "are".
|
|
32
|
+
*/
|
|
33
|
+
function isOrAre(importNames) {
|
|
34
|
+
return importNames.length === 1 ? "is" : "are";
|
|
35
|
+
}
|
|
36
|
+
|
|
13
37
|
//------------------------------------------------------------------------------
|
|
14
38
|
// Rule Definition
|
|
15
39
|
//------------------------------------------------------------------------------
|
|
@@ -175,22 +199,22 @@ module.exports = {
|
|
|
175
199
|
"'{{importName}}' import from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
|
|
176
200
|
|
|
177
201
|
patternAndEverything:
|
|
178
|
-
"* import is invalid because
|
|
202
|
+
"* import is invalid because {{importNames}} from '{{importSource}}' {{isOrAre}} restricted from being used by a pattern.",
|
|
179
203
|
|
|
180
204
|
patternAndEverythingWithRegexImportName:
|
|
181
205
|
"* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used.",
|
|
182
206
|
patternAndEverythingWithCustomMessage:
|
|
183
207
|
// eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
|
|
184
|
-
"* import is invalid because
|
|
208
|
+
"* import is invalid because {{importNames}} from '{{importSource}}' {{isOrAre}} restricted from being used by a pattern. {{customMessage}}",
|
|
185
209
|
patternAndEverythingWithRegexImportNameAndCustomMessage:
|
|
186
210
|
// eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
|
|
187
211
|
"* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used. {{customMessage}}",
|
|
188
212
|
|
|
189
213
|
everything:
|
|
190
|
-
"* import is invalid because
|
|
214
|
+
"* import is invalid because {{importNames}} from '{{importSource}}' {{isOrAre}} restricted.",
|
|
191
215
|
everythingWithCustomMessage:
|
|
192
216
|
// eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
|
|
193
|
-
"* import is invalid because
|
|
217
|
+
"* import is invalid because {{importNames}} from '{{importSource}}' {{isOrAre}} restricted. {{customMessage}}",
|
|
194
218
|
|
|
195
219
|
importName:
|
|
196
220
|
"'{{importName}}' import from '{{importSource}}' is restricted.",
|
|
@@ -199,16 +223,16 @@ module.exports = {
|
|
|
199
223
|
"'{{importName}}' import from '{{importSource}}' is restricted. {{customMessage}}",
|
|
200
224
|
|
|
201
225
|
allowedImportName:
|
|
202
|
-
"'{{importName}}' import from '{{importSource}}' is restricted because only
|
|
226
|
+
"'{{importName}}' import from '{{importSource}}' is restricted because only {{allowedImportNames}} {{isOrAre}} allowed.",
|
|
203
227
|
allowedImportNameWithCustomMessage:
|
|
204
228
|
// eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
|
|
205
|
-
"'{{importName}}' import from '{{importSource}}' is restricted because only
|
|
229
|
+
"'{{importName}}' import from '{{importSource}}' is restricted because only {{allowedImportNames}} {{isOrAre}} allowed. {{customMessage}}",
|
|
206
230
|
|
|
207
231
|
everythingWithAllowImportNames:
|
|
208
|
-
"* import is invalid because only
|
|
232
|
+
"* import is invalid because only {{allowedImportNames}} from '{{importSource}}' {{isOrAre}} allowed.",
|
|
209
233
|
everythingWithAllowImportNamesAndCustomMessage:
|
|
210
234
|
// eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
|
|
211
|
-
"* import is invalid because only
|
|
235
|
+
"* import is invalid because only {{allowedImportNames}} from '{{importSource}}' {{isOrAre}} allowed. {{customMessage}}",
|
|
212
236
|
|
|
213
237
|
allowedImportNamePattern:
|
|
214
238
|
"'{{importName}}' import from '{{importSource}}' is restricted because only imports that match the pattern '{{allowedImportNamePattern}}' are allowed from '{{importSource}}'.",
|
|
@@ -452,7 +476,10 @@ module.exports = {
|
|
|
452
476
|
loc: specifier.loc,
|
|
453
477
|
data: {
|
|
454
478
|
importSource,
|
|
455
|
-
importNames:
|
|
479
|
+
importNames: formatImportNames(
|
|
480
|
+
restrictedImportNames,
|
|
481
|
+
),
|
|
482
|
+
isOrAre: isOrAre(restrictedImportNames),
|
|
456
483
|
customMessage,
|
|
457
484
|
},
|
|
458
485
|
});
|
|
@@ -465,7 +492,11 @@ module.exports = {
|
|
|
465
492
|
loc: specifier.loc,
|
|
466
493
|
data: {
|
|
467
494
|
importSource,
|
|
468
|
-
allowedImportNames
|
|
495
|
+
allowedImportNames:
|
|
496
|
+
formatImportNames(
|
|
497
|
+
allowedImportNames,
|
|
498
|
+
),
|
|
499
|
+
isOrAre: isOrAre(allowedImportNames),
|
|
469
500
|
customMessage,
|
|
470
501
|
},
|
|
471
502
|
});
|
|
@@ -525,7 +556,11 @@ module.exports = {
|
|
|
525
556
|
importSource,
|
|
526
557
|
customMessage,
|
|
527
558
|
importName,
|
|
528
|
-
allowedImportNames
|
|
559
|
+
allowedImportNames:
|
|
560
|
+
formatImportNames(
|
|
561
|
+
allowedImportNames,
|
|
562
|
+
),
|
|
563
|
+
isOrAre: isOrAre(allowedImportNames),
|
|
529
564
|
},
|
|
530
565
|
});
|
|
531
566
|
});
|
|
@@ -612,7 +647,10 @@ module.exports = {
|
|
|
612
647
|
loc: specifier.loc,
|
|
613
648
|
data: {
|
|
614
649
|
importSource,
|
|
615
|
-
importNames:
|
|
650
|
+
importNames: formatImportNames(
|
|
651
|
+
restrictedImportNames,
|
|
652
|
+
),
|
|
653
|
+
isOrAre: isOrAre(restrictedImportNames),
|
|
616
654
|
customMessage,
|
|
617
655
|
},
|
|
618
656
|
});
|
|
@@ -625,7 +663,9 @@ module.exports = {
|
|
|
625
663
|
loc: specifier.loc,
|
|
626
664
|
data: {
|
|
627
665
|
importSource,
|
|
628
|
-
allowedImportNames
|
|
666
|
+
allowedImportNames:
|
|
667
|
+
formatImportNames(allowedImportNames),
|
|
668
|
+
isOrAre: isOrAre(allowedImportNames),
|
|
629
669
|
customMessage,
|
|
630
670
|
},
|
|
631
671
|
});
|
|
@@ -713,7 +753,9 @@ module.exports = {
|
|
|
713
753
|
importSource,
|
|
714
754
|
customMessage,
|
|
715
755
|
importName,
|
|
716
|
-
allowedImportNames
|
|
756
|
+
allowedImportNames:
|
|
757
|
+
formatImportNames(allowedImportNames),
|
|
758
|
+
isOrAre: isOrAre(allowedImportNames),
|
|
717
759
|
},
|
|
718
760
|
});
|
|
719
761
|
});
|
|
@@ -336,9 +336,12 @@ module.exports = {
|
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
if (
|
|
339
|
-
targetAssignment.variable.references.some(
|
|
340
|
-
|
|
341
|
-
|
|
339
|
+
targetAssignment.variable.references.some(ref => {
|
|
340
|
+
const type = ref.identifier.type;
|
|
341
|
+
return (
|
|
342
|
+
type !== "Identifier" && type !== "JSXIdentifier"
|
|
343
|
+
);
|
|
344
|
+
})
|
|
342
345
|
) {
|
|
343
346
|
/**
|
|
344
347
|
* Skip checking for a variable that has at least one non-identifier reference.
|
|
@@ -529,7 +532,7 @@ module.exports = {
|
|
|
529
532
|
TryStatement(node) {
|
|
530
533
|
scopeStack.tryStatementBlocks.push(node.block);
|
|
531
534
|
},
|
|
532
|
-
Identifier(node) {
|
|
535
|
+
"Identifier, JSXIdentifier"(node) {
|
|
533
536
|
for (const segment of scopeStack.currentSegments) {
|
|
534
537
|
const segmentInfo = scopeStack.segments[segment.id];
|
|
535
538
|
|
|
@@ -539,7 +542,7 @@ module.exports = {
|
|
|
539
542
|
segmentInfo.last = node;
|
|
540
543
|
}
|
|
541
544
|
},
|
|
542
|
-
"
|
|
545
|
+
"VariableDeclarator[init!=null], AssignmentExpression, UpdateExpression:exit"(
|
|
543
546
|
node,
|
|
544
547
|
) {
|
|
545
548
|
if (scopeStack.currentSegments.size === 0) {
|
|
@@ -704,60 +704,63 @@ function isKeywordToken(token) {
|
|
|
704
704
|
}
|
|
705
705
|
|
|
706
706
|
/**
|
|
707
|
-
*
|
|
708
|
-
* @param {ASTNode}
|
|
709
|
-
* @returns {boolean}
|
|
707
|
+
* Checks whether the given node represents an ES6 export declaration.
|
|
708
|
+
* @param {ASTNode} node A node to check.
|
|
709
|
+
* @returns {boolean} `true` if the node is an export declaration.
|
|
710
710
|
* @private
|
|
711
711
|
*/
|
|
712
|
-
function
|
|
712
|
+
function isExportDeclaration(node) {
|
|
713
713
|
return (
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
astNode.type === "ExportSpecifier"
|
|
714
|
+
node.type === "ExportDefaultDeclaration" ||
|
|
715
|
+
node.type === "ExportNamedDeclaration" ||
|
|
716
|
+
node.type === "ExportAllDeclaration"
|
|
718
717
|
);
|
|
719
718
|
}
|
|
720
719
|
|
|
721
720
|
/**
|
|
722
|
-
*
|
|
723
|
-
* @param {ASTNode} node The
|
|
721
|
+
* Checks for the presence of a JSDoc comment for the given node and returns it.
|
|
722
|
+
* @param {ASTNode} node The node to get the comment for.
|
|
724
723
|
* @param {SourceCode} sourceCode A SourceCode instance to get comments.
|
|
725
724
|
* @returns {Token|null} The Block comment token containing the JSDoc comment for the given node or null if not found.
|
|
726
725
|
* @private
|
|
727
726
|
*/
|
|
728
|
-
function
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
* @returns {Token|null} The Block comment token containing the JSDoc comment for the given node or null if not found.
|
|
733
|
-
* @private
|
|
734
|
-
*/
|
|
735
|
-
function findJSDocComment(astNode) {
|
|
736
|
-
const tokenBefore = sourceCode.getTokenBefore(astNode, {
|
|
737
|
-
includeComments: true,
|
|
738
|
-
});
|
|
727
|
+
function findJSDocComment(node, sourceCode) {
|
|
728
|
+
const tokenBefore = sourceCode.getTokenBefore(node, {
|
|
729
|
+
includeComments: true,
|
|
730
|
+
});
|
|
739
731
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
return tokenBefore;
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
return null;
|
|
732
|
+
if (
|
|
733
|
+
tokenBefore &&
|
|
734
|
+
tokenBefore.type === "Block" &&
|
|
735
|
+
tokenBefore.value.charAt(0) === "*" &&
|
|
736
|
+
node.loc.start.line - tokenBefore.loc.end.line <= 1
|
|
737
|
+
) {
|
|
738
|
+
return tokenBefore;
|
|
751
739
|
}
|
|
740
|
+
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Retrieves the JSDoc comment for a given node.
|
|
746
|
+
* @param {ASTNode} node The node to get the comment for.
|
|
747
|
+
* @param {SourceCode} sourceCode A SourceCode instance to get comments.
|
|
748
|
+
* @returns {Token|null} The Block comment token containing the JSDoc comment for the given node or null if not found.
|
|
749
|
+
* @private
|
|
750
|
+
*/
|
|
751
|
+
function getJSDocComment(node, sourceCode) {
|
|
752
752
|
let parent = node.parent;
|
|
753
753
|
|
|
754
754
|
switch (node.type) {
|
|
755
755
|
case "ClassDeclaration":
|
|
756
756
|
case "FunctionDeclaration":
|
|
757
|
-
return findJSDocComment(
|
|
757
|
+
return findJSDocComment(
|
|
758
|
+
isExportDeclaration(parent) ? parent : node,
|
|
759
|
+
sourceCode,
|
|
760
|
+
);
|
|
758
761
|
|
|
759
762
|
case "ClassExpression":
|
|
760
|
-
return findJSDocComment(parent.parent);
|
|
763
|
+
return findJSDocComment(parent.parent, sourceCode);
|
|
761
764
|
|
|
762
765
|
case "ArrowFunctionExpression":
|
|
763
766
|
case "FunctionExpression":
|
|
@@ -783,11 +786,11 @@ function getJSDocComment(node, sourceCode) {
|
|
|
783
786
|
parent.type !== "FunctionDeclaration" &&
|
|
784
787
|
parent.type !== "Program"
|
|
785
788
|
) {
|
|
786
|
-
return findJSDocComment(parent);
|
|
789
|
+
return findJSDocComment(parent, sourceCode);
|
|
787
790
|
}
|
|
788
791
|
}
|
|
789
792
|
|
|
790
|
-
return findJSDocComment(node);
|
|
793
|
+
return findJSDocComment(node, sourceCode);
|
|
791
794
|
|
|
792
795
|
// falls through
|
|
793
796
|
default:
|
package/lib/types/index.d.ts
CHANGED
|
@@ -115,7 +115,7 @@ export namespace AST {
|
|
|
115
115
|
end: ESTree.Position;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
type Range =
|
|
118
|
+
type Range = SourceRange;
|
|
119
119
|
|
|
120
120
|
interface Program extends ESTree.Program {
|
|
121
121
|
comments: ESTree.Comment[];
|
|
@@ -125,6 +125,11 @@ export namespace AST {
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
interface JSXIdentifier extends ESTree.BaseNode {
|
|
129
|
+
type: "JSXIdentifier";
|
|
130
|
+
name: string;
|
|
131
|
+
}
|
|
132
|
+
|
|
128
133
|
export namespace Scope {
|
|
129
134
|
interface ScopeManager {
|
|
130
135
|
scopes: Scope[];
|
|
@@ -177,7 +182,7 @@ export namespace Scope {
|
|
|
177
182
|
}
|
|
178
183
|
|
|
179
184
|
interface Reference {
|
|
180
|
-
identifier: ESTree.Identifier;
|
|
185
|
+
identifier: ESTree.Identifier | JSXIdentifier;
|
|
181
186
|
from: Scope;
|
|
182
187
|
resolved: Variable | null;
|
|
183
188
|
writeExpr: ESTree.Node | null;
|
|
@@ -1256,9 +1261,8 @@ export namespace ESLint {
|
|
|
1256
1261
|
foundWarnings: number;
|
|
1257
1262
|
}
|
|
1258
1263
|
|
|
1259
|
-
interface LintResultData {
|
|
1264
|
+
interface LintResultData extends ResultsMeta {
|
|
1260
1265
|
cwd: string;
|
|
1261
|
-
maxWarningsExceeded?: MaxWarningsExceeded | undefined;
|
|
1262
1266
|
rulesMeta: {
|
|
1263
1267
|
[ruleId: string]: Rule.RuleMetaData;
|
|
1264
1268
|
};
|
|
@@ -1290,6 +1294,14 @@ export namespace ESLint {
|
|
|
1290
1294
|
* Metadata about results for formatters.
|
|
1291
1295
|
*/
|
|
1292
1296
|
interface ResultsMeta {
|
|
1297
|
+
/**
|
|
1298
|
+
* Whether or not to use color in the formatter output.
|
|
1299
|
+
* - If `--color` was set, this property is `true`.
|
|
1300
|
+
* - If `--no-color` was set, it is `false`.
|
|
1301
|
+
* - If neither option was provided, the property is omitted.
|
|
1302
|
+
*/
|
|
1303
|
+
color?: boolean | undefined;
|
|
1304
|
+
|
|
1293
1305
|
/**
|
|
1294
1306
|
* Present if the maxWarnings threshold was exceeded.
|
|
1295
1307
|
*/
|
|
@@ -1301,9 +1313,9 @@ export namespace ESLint {
|
|
|
1301
1313
|
/**
|
|
1302
1314
|
* Used to call the underlying formatter.
|
|
1303
1315
|
* @param results An array of lint results to format.
|
|
1304
|
-
* @param resultsMeta An object with
|
|
1316
|
+
* @param resultsMeta An object with optional `color` and `maxWarningsExceeded` properties that will be
|
|
1305
1317
|
* passed to the underlying formatter function along with other properties set by ESLint.
|
|
1306
|
-
* This argument can be omitted if `maxWarningsExceeded`
|
|
1318
|
+
* This argument can be omitted if `color` and `maxWarningsExceeded` are not needed.
|
|
1307
1319
|
* @return The formatter output.
|
|
1308
1320
|
*/
|
|
1309
1321
|
format(
|
|
@@ -1332,9 +1344,10 @@ export namespace ESLint {
|
|
|
1332
1344
|
|
|
1333
1345
|
// #endregion
|
|
1334
1346
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1347
|
+
/**
|
|
1348
|
+
* Loads the correct `ESLint` constructor.
|
|
1349
|
+
*/
|
|
1350
|
+
export function loadESLint(): Promise<typeof ESLint>;
|
|
1338
1351
|
|
|
1339
1352
|
// #region RuleTester
|
|
1340
1353
|
|
|
@@ -1342,6 +1355,9 @@ export class RuleTester {
|
|
|
1342
1355
|
static describe: ((...args: any) => any) | null;
|
|
1343
1356
|
static it: ((...args: any) => any) | null;
|
|
1344
1357
|
static itOnly: ((...args: any) => any) | null;
|
|
1358
|
+
static setDefaultConfig(config: Linter.Config): void;
|
|
1359
|
+
static getDefaultConfig(): Linter.Config;
|
|
1360
|
+
static resetDefaultConfig(): void;
|
|
1345
1361
|
|
|
1346
1362
|
constructor(config?: Linter.Config);
|
|
1347
1363
|
|
|
@@ -1351,6 +1367,26 @@ export class RuleTester {
|
|
|
1351
1367
|
tests: {
|
|
1352
1368
|
valid: Array<string | RuleTester.ValidTestCase>;
|
|
1353
1369
|
invalid: RuleTester.InvalidTestCase[];
|
|
1370
|
+
/**
|
|
1371
|
+
* Additional assertions for the "error" matchers of invalid test cases to enforce consistency.
|
|
1372
|
+
*/
|
|
1373
|
+
assertionOptions?: {
|
|
1374
|
+
/**
|
|
1375
|
+
* If true, each `errors` block must check the expected error
|
|
1376
|
+
* message, either via a string in the `errors` array, or via
|
|
1377
|
+
* `message`/`messageId` in an errors object.
|
|
1378
|
+
* `"message"`/`"messageId"` can be used to further limit the
|
|
1379
|
+
* message assertions to the respective versions.
|
|
1380
|
+
*/
|
|
1381
|
+
requireMessage?: boolean | "message" | "messageId";
|
|
1382
|
+
/**
|
|
1383
|
+
* If true, each `errors` block must be an array of objects,
|
|
1384
|
+
* that each check all location properties `line`, `column`,
|
|
1385
|
+
* `endLine`, `endColumn`, the later may be omitted, if the
|
|
1386
|
+
* error does not contain them.
|
|
1387
|
+
*/
|
|
1388
|
+
requireLocation?: boolean;
|
|
1389
|
+
};
|
|
1354
1390
|
},
|
|
1355
1391
|
): void;
|
|
1356
1392
|
|
|
@@ -1360,14 +1396,22 @@ export class RuleTester {
|
|
|
1360
1396
|
}
|
|
1361
1397
|
|
|
1362
1398
|
export namespace RuleTester {
|
|
1363
|
-
interface ValidTestCase
|
|
1399
|
+
interface ValidTestCase
|
|
1400
|
+
extends Omit<
|
|
1401
|
+
Linter.Config,
|
|
1402
|
+
| "name"
|
|
1403
|
+
| "basePath"
|
|
1404
|
+
| "files"
|
|
1405
|
+
| "ignores"
|
|
1406
|
+
| "linterOptions"
|
|
1407
|
+
| "plugins"
|
|
1408
|
+
| "rules"
|
|
1409
|
+
> {
|
|
1364
1410
|
name?: string;
|
|
1365
1411
|
code: string;
|
|
1366
|
-
options?: any;
|
|
1412
|
+
options?: any[];
|
|
1367
1413
|
filename?: string | undefined;
|
|
1368
1414
|
only?: boolean;
|
|
1369
|
-
languageOptions?: Linter.LanguageOptions | undefined;
|
|
1370
|
-
settings?: { [name: string]: any } | undefined;
|
|
1371
1415
|
before?: () => void;
|
|
1372
1416
|
after?: () => void;
|
|
1373
1417
|
}
|
|
@@ -1380,7 +1424,7 @@ export namespace RuleTester {
|
|
|
1380
1424
|
}
|
|
1381
1425
|
|
|
1382
1426
|
interface InvalidTestCase extends ValidTestCase {
|
|
1383
|
-
errors: number | Array<TestCaseError | string>;
|
|
1427
|
+
errors: number | Array<TestCaseError | string | RegExp>;
|
|
1384
1428
|
output?: string | null | undefined;
|
|
1385
1429
|
}
|
|
1386
1430
|
|
|
@@ -1392,7 +1436,7 @@ export namespace RuleTester {
|
|
|
1392
1436
|
column?: number | undefined;
|
|
1393
1437
|
endLine?: number | undefined;
|
|
1394
1438
|
endColumn?: number | undefined;
|
|
1395
|
-
suggestions?: SuggestionOutput[] | undefined;
|
|
1439
|
+
suggestions?: SuggestionOutput[] | number | undefined;
|
|
1396
1440
|
}
|
|
1397
1441
|
}
|
|
1398
1442
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint",
|
|
3
|
-
"version": "10.0.0-
|
|
3
|
+
"version": "10.0.0-beta.0",
|
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"bugs": "https://github.com/eslint/eslint/issues/",
|
|
108
108
|
"dependencies": {
|
|
109
109
|
"@eslint-community/eslint-utils": "^4.8.0",
|
|
110
|
-
"@eslint-community/regexpp": "^4.12.
|
|
110
|
+
"@eslint-community/regexpp": "^4.12.2",
|
|
111
111
|
"@eslint/config-array": "^0.23.0",
|
|
112
112
|
"@eslint/config-helpers": "^0.5.0",
|
|
113
113
|
"@eslint/core": "^1.0.0",
|
|
@@ -117,7 +117,6 @@
|
|
|
117
117
|
"@humanwhocodes/retry": "^0.4.2",
|
|
118
118
|
"@types/estree": "^1.0.6",
|
|
119
119
|
"ajv": "^6.12.4",
|
|
120
|
-
"chalk": "^4.0.0",
|
|
121
120
|
"cross-spawn": "^7.0.6",
|
|
122
121
|
"debug": "^4.3.2",
|
|
123
122
|
"escape-string-regexp": "^4.0.0",
|
|
@@ -144,7 +143,7 @@
|
|
|
144
143
|
"@babel/preset-env": "^7.4.3",
|
|
145
144
|
"@cypress/webpack-preprocessor": "^6.0.2",
|
|
146
145
|
"@eslint/json": "^0.14.0",
|
|
147
|
-
"@eslint/eslintrc": "^3.3.
|
|
146
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
148
147
|
"@trunkio/launcher": "^1.3.4",
|
|
149
148
|
"@types/esquery": "^1.5.4",
|
|
150
149
|
"@types/node": "^22.13.14",
|