eslint 8.55.0 → 9.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -15
- package/conf/rule-type-list.json +3 -1
- package/lib/api.js +1 -1
- package/lib/cli-engine/cli-engine.js +15 -4
- package/lib/cli-engine/formatters/formatters-meta.json +1 -29
- package/lib/cli.js +52 -10
- package/lib/config/default-config.js +3 -0
- package/lib/config/flat-config-array.js +0 -20
- package/lib/config/flat-config-helpers.js +41 -20
- package/lib/config/flat-config-schema.js +57 -26
- package/lib/config/rule-validator.js +27 -4
- package/lib/eslint/eslint-helpers.js +35 -22
- package/lib/eslint/eslint.js +856 -373
- package/lib/eslint/index.js +2 -2
- package/lib/eslint/legacy-eslint.js +722 -0
- package/lib/linter/apply-disable-directives.js +33 -5
- package/lib/linter/config-comment-parser.js +36 -2
- package/lib/linter/linter.js +100 -120
- package/lib/linter/rules.js +6 -15
- package/lib/options.js +17 -1
- package/lib/rule-tester/rule-tester.js +240 -272
- package/lib/rules/index.js +0 -2
- package/lib/rules/no-constant-binary-expression.js +1 -1
- package/lib/rules/no-constructor-return.js +1 -1
- package/lib/rules/no-empty-static-block.js +1 -1
- package/lib/rules/no-extra-semi.js +1 -1
- package/lib/rules/no-implicit-coercion.js +17 -1
- package/lib/rules/no-inner-declarations.js +1 -1
- package/lib/rules/no-invalid-regexp.js +1 -1
- package/lib/rules/no-invalid-this.js +1 -1
- package/lib/rules/no-mixed-spaces-and-tabs.js +1 -1
- package/lib/rules/no-new-native-nonconstructor.js +1 -1
- package/lib/rules/no-new-symbol.js +8 -1
- package/lib/rules/no-promise-executor-return.js +9 -6
- package/lib/rules/no-restricted-properties.js +15 -28
- package/lib/rules/no-sequences.js +1 -0
- package/lib/rules/no-unused-private-class-members.js +1 -1
- package/lib/shared/config-validator.js +44 -11
- package/lib/shared/severity.js +49 -0
- package/lib/shared/types.js +1 -1
- package/lib/source-code/source-code.js +3 -102
- package/lib/unsupported-api.js +3 -5
- package/package.json +12 -14
- package/lib/cli-engine/formatters/checkstyle.js +0 -60
- package/lib/cli-engine/formatters/compact.js +0 -60
- package/lib/cli-engine/formatters/jslint-xml.js +0 -41
- package/lib/cli-engine/formatters/junit.js +0 -82
- package/lib/cli-engine/formatters/tap.js +0 -95
- package/lib/cli-engine/formatters/unix.js +0 -58
- package/lib/cli-engine/formatters/visualstudio.js +0 -63
- package/lib/eslint/flat-eslint.js +0 -1149
- package/lib/rule-tester/flat-rule-tester.js +0 -1122
- package/lib/rules/require-jsdoc.js +0 -122
- package/lib/rules/valid-jsdoc.js +0 -516
@@ -9,11 +9,7 @@
|
|
9
9
|
// Requirements
|
10
10
|
//-----------------------------------------------------------------------------
|
11
11
|
|
12
|
-
|
13
|
-
* Note: This can be removed in ESLint v9 because structuredClone is available globally
|
14
|
-
* starting in Node.js v17.
|
15
|
-
*/
|
16
|
-
const structuredClone = require("@ungap/structured-clone").default;
|
12
|
+
const { normalizeSeverityToNumber } = require("../shared/severity");
|
17
13
|
|
18
14
|
//-----------------------------------------------------------------------------
|
19
15
|
// Type Definitions
|
@@ -52,6 +48,15 @@ function isNonNullObject(value) {
|
|
52
48
|
return typeof value === "object" && value !== null;
|
53
49
|
}
|
54
50
|
|
51
|
+
/**
|
52
|
+
* Check if a value is a non-null non-array object.
|
53
|
+
* @param {any} value The value to check.
|
54
|
+
* @returns {boolean} `true` if the value is a non-null non-array object.
|
55
|
+
*/
|
56
|
+
function isNonArrayObject(value) {
|
57
|
+
return isNonNullObject(value) && !Array.isArray(value);
|
58
|
+
}
|
59
|
+
|
55
60
|
/**
|
56
61
|
* Check if a value is undefined.
|
57
62
|
* @param {any} value The value to check.
|
@@ -62,19 +67,27 @@ function isUndefined(value) {
|
|
62
67
|
}
|
63
68
|
|
64
69
|
/**
|
65
|
-
* Deeply merges two objects.
|
70
|
+
* Deeply merges two non-array objects.
|
66
71
|
* @param {Object} first The base object.
|
67
72
|
* @param {Object} second The overrides object.
|
73
|
+
* @param {Map<string, Map<string, Object>>} [mergeMap] Maps the combination of first and second arguments to a merged result.
|
68
74
|
* @returns {Object} An object with properties from both first and second.
|
69
75
|
*/
|
70
|
-
function deepMerge(first
|
76
|
+
function deepMerge(first, second, mergeMap = new Map()) {
|
71
77
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
+
let secondMergeMap = mergeMap.get(first);
|
79
|
+
|
80
|
+
if (secondMergeMap) {
|
81
|
+
const result = secondMergeMap.get(second);
|
82
|
+
|
83
|
+
if (result) {
|
84
|
+
|
85
|
+
// If this combination of first and second arguments has been already visited, return the previously created result.
|
86
|
+
return result;
|
87
|
+
}
|
88
|
+
} else {
|
89
|
+
secondMergeMap = new Map();
|
90
|
+
mergeMap.set(first, secondMergeMap);
|
78
91
|
}
|
79
92
|
|
80
93
|
/*
|
@@ -88,27 +101,25 @@ function deepMerge(first = {}, second = {}) {
|
|
88
101
|
...second
|
89
102
|
};
|
90
103
|
|
104
|
+
delete result.__proto__; // eslint-disable-line no-proto -- don't merge own property "__proto__"
|
105
|
+
|
106
|
+
// Store the pending result for this combination of first and second arguments.
|
107
|
+
secondMergeMap.set(second, result);
|
108
|
+
|
91
109
|
for (const key of Object.keys(second)) {
|
92
110
|
|
93
111
|
// avoid hairy edge case
|
94
|
-
if (key === "__proto__") {
|
112
|
+
if (key === "__proto__" || !Object.prototype.propertyIsEnumerable.call(first, key)) {
|
95
113
|
continue;
|
96
114
|
}
|
97
115
|
|
98
116
|
const firstValue = first[key];
|
99
117
|
const secondValue = second[key];
|
100
118
|
|
101
|
-
if (
|
102
|
-
result[key] = deepMerge(firstValue, secondValue);
|
103
|
-
} else if (isUndefined(
|
104
|
-
|
105
|
-
result[key] = deepMerge(
|
106
|
-
Array.isArray(secondValue) ? [] : {},
|
107
|
-
secondValue
|
108
|
-
);
|
109
|
-
} else if (!isUndefined(secondValue)) {
|
110
|
-
result[key] = secondValue;
|
111
|
-
}
|
119
|
+
if (isNonArrayObject(firstValue) && isNonArrayObject(secondValue)) {
|
120
|
+
result[key] = deepMerge(firstValue, secondValue, mergeMap);
|
121
|
+
} else if (isUndefined(secondValue)) {
|
122
|
+
result[key] = firstValue;
|
112
123
|
}
|
113
124
|
}
|
114
125
|
|
@@ -262,6 +273,26 @@ const booleanSchema = {
|
|
262
273
|
validate: "boolean"
|
263
274
|
};
|
264
275
|
|
276
|
+
const ALLOWED_SEVERITIES = new Set(["error", "warn", "off", 2, 1, 0]);
|
277
|
+
|
278
|
+
/** @type {ObjectPropertySchema} */
|
279
|
+
const disableDirectiveSeveritySchema = {
|
280
|
+
merge(first, second) {
|
281
|
+
const value = second === void 0 ? first : second;
|
282
|
+
|
283
|
+
if (typeof value === "boolean") {
|
284
|
+
return value ? "warn" : "off";
|
285
|
+
}
|
286
|
+
|
287
|
+
return normalizeSeverityToNumber(value);
|
288
|
+
},
|
289
|
+
validate(value) {
|
290
|
+
if (!(ALLOWED_SEVERITIES.has(value) || typeof value === "boolean")) {
|
291
|
+
throw new TypeError("Expected one of: \"error\", \"warn\", \"off\", 0, 1, 2, or a boolean.");
|
292
|
+
}
|
293
|
+
}
|
294
|
+
};
|
295
|
+
|
265
296
|
/** @type {ObjectPropertySchema} */
|
266
297
|
const deepObjectAssignSchema = {
|
267
298
|
merge(first = {}, second = {}) {
|
@@ -534,7 +565,7 @@ const flatConfigSchema = {
|
|
534
565
|
linterOptions: {
|
535
566
|
schema: {
|
536
567
|
noInlineConfig: booleanSchema,
|
537
|
-
reportUnusedDisableDirectives:
|
568
|
+
reportUnusedDisableDirectives: disableDirectiveSeveritySchema
|
538
569
|
}
|
539
570
|
},
|
540
571
|
languageOptions: {
|
@@ -66,6 +66,25 @@ function throwRuleNotFoundError({ pluginName, ruleName }, config) {
|
|
66
66
|
throw new TypeError(errorMessage);
|
67
67
|
}
|
68
68
|
|
69
|
+
/**
|
70
|
+
* The error type when a rule has an invalid `meta.schema`.
|
71
|
+
*/
|
72
|
+
class InvalidRuleOptionsSchemaError extends Error {
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Creates a new instance.
|
76
|
+
* @param {string} ruleId Id of the rule that has an invalid `meta.schema`.
|
77
|
+
* @param {Error} processingError Error caught while processing the `meta.schema`.
|
78
|
+
*/
|
79
|
+
constructor(ruleId, processingError) {
|
80
|
+
super(
|
81
|
+
`Error while processing options validation schema of rule '${ruleId}': ${processingError.message}`,
|
82
|
+
{ cause: processingError }
|
83
|
+
);
|
84
|
+
this.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
69
88
|
//-----------------------------------------------------------------------------
|
70
89
|
// Exports
|
71
90
|
//-----------------------------------------------------------------------------
|
@@ -130,10 +149,14 @@ class RuleValidator {
|
|
130
149
|
|
131
150
|
// Precompile and cache validator the first time
|
132
151
|
if (!this.validators.has(rule)) {
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
152
|
+
try {
|
153
|
+
const schema = getRuleOptionsSchema(rule);
|
154
|
+
|
155
|
+
if (schema) {
|
156
|
+
this.validators.set(rule, ajv.compile(schema));
|
157
|
+
}
|
158
|
+
} catch (err) {
|
159
|
+
throw new InvalidRuleOptionsSchemaError(ruleId, err);
|
137
160
|
}
|
138
161
|
}
|
139
162
|
|
@@ -105,20 +105,30 @@ class AllFilesIgnoredError extends Error {
|
|
105
105
|
|
106
106
|
/**
|
107
107
|
* Check if a given value is a non-empty string or not.
|
108
|
-
* @param {any}
|
109
|
-
* @returns {boolean} `true` if `
|
108
|
+
* @param {any} value The value to check.
|
109
|
+
* @returns {boolean} `true` if `value` is a non-empty string.
|
110
110
|
*/
|
111
|
-
function isNonEmptyString(
|
112
|
-
return typeof
|
111
|
+
function isNonEmptyString(value) {
|
112
|
+
return typeof value === "string" && value.trim() !== "";
|
113
113
|
}
|
114
114
|
|
115
115
|
/**
|
116
116
|
* Check if a given value is an array of non-empty strings or not.
|
117
|
-
* @param {any}
|
118
|
-
* @returns {boolean} `true` if `
|
117
|
+
* @param {any} value The value to check.
|
118
|
+
* @returns {boolean} `true` if `value` is an array of non-empty strings.
|
119
|
+
*/
|
120
|
+
function isArrayOfNonEmptyString(value) {
|
121
|
+
return Array.isArray(value) && value.length && value.every(isNonEmptyString);
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Check if a given value is an empty array or an array of non-empty strings.
|
126
|
+
* @param {any} value The value to check.
|
127
|
+
* @returns {boolean} `true` if `value` is an empty array or an array of non-empty
|
128
|
+
* strings.
|
119
129
|
*/
|
120
|
-
function
|
121
|
-
return Array.isArray(
|
130
|
+
function isEmptyArrayOrArrayOfNonEmptyString(value) {
|
131
|
+
return Array.isArray(value) && value.every(isNonEmptyString);
|
122
132
|
}
|
123
133
|
|
124
134
|
//-----------------------------------------------------------------------------
|
@@ -655,9 +665,9 @@ class ESLintInvalidOptionsError extends Error {
|
|
655
665
|
|
656
666
|
/**
|
657
667
|
* Validates and normalizes options for the wrapped CLIEngine instance.
|
658
|
-
* @param {
|
668
|
+
* @param {ESLintOptions} options The options to process.
|
659
669
|
* @throws {ESLintInvalidOptionsError} If of any of a variety of type errors.
|
660
|
-
* @returns {
|
670
|
+
* @returns {ESLintOptions} The normalized options.
|
661
671
|
*/
|
662
672
|
function processOptions({
|
663
673
|
allowInlineConfig = true, // ← we cannot use `overrideConfig.noInlineConfig` instead because `allowInlineConfig` has side-effect that suppress warnings that show inline configs are ignored.
|
@@ -675,8 +685,9 @@ function processOptions({
|
|
675
685
|
overrideConfig = null,
|
676
686
|
overrideConfigFile = null,
|
677
687
|
plugins = {},
|
678
|
-
reportUnusedDisableDirectives = null, // ← should be null by default because if it's a string then it overrides the 'reportUnusedDisableDirectives' setting in config files. And we cannot use `overrideConfig.reportUnusedDisableDirectives` instead because we cannot configure the `error` severity with that.
|
679
688
|
warnIgnored = true,
|
689
|
+
passOnNoPatterns = false,
|
690
|
+
ruleFilter = () => true,
|
680
691
|
...unknownOptions
|
681
692
|
}) {
|
682
693
|
const errors = [];
|
@@ -720,6 +731,9 @@ function processOptions({
|
|
720
731
|
if (unknownOptionKeys.includes("rulePaths")) {
|
721
732
|
errors.push("'rulePaths' has been removed. Please define your rules using plugins.");
|
722
733
|
}
|
734
|
+
if (unknownOptionKeys.includes("reportUnusedDisableDirectives")) {
|
735
|
+
errors.push("'reportUnusedDisableDirectives' has been removed. Please use the 'overrideConfig.linterOptions.reportUnusedDisableDirectives' option instead.");
|
736
|
+
}
|
723
737
|
}
|
724
738
|
if (typeof allowInlineConfig !== "boolean") {
|
725
739
|
errors.push("'allowInlineConfig' must be a boolean.");
|
@@ -757,7 +771,7 @@ function processOptions({
|
|
757
771
|
if (typeof ignore !== "boolean") {
|
758
772
|
errors.push("'ignore' must be a boolean.");
|
759
773
|
}
|
760
|
-
if (!
|
774
|
+
if (!isEmptyArrayOrArrayOfNonEmptyString(ignorePatterns) && ignorePatterns !== null) {
|
761
775
|
errors.push("'ignorePatterns' must be an array of non-empty strings or null.");
|
762
776
|
}
|
763
777
|
if (typeof overrideConfig !== "object") {
|
@@ -766,6 +780,9 @@ function processOptions({
|
|
766
780
|
if (!isNonEmptyString(overrideConfigFile) && overrideConfigFile !== null && overrideConfigFile !== true) {
|
767
781
|
errors.push("'overrideConfigFile' must be a non-empty string, null, or true.");
|
768
782
|
}
|
783
|
+
if (typeof passOnNoPatterns !== "boolean") {
|
784
|
+
errors.push("'passOnNoPatterns' must be a boolean.");
|
785
|
+
}
|
769
786
|
if (typeof plugins !== "object") {
|
770
787
|
errors.push("'plugins' must be an object or null.");
|
771
788
|
} else if (plugins !== null && Object.keys(plugins).includes("")) {
|
@@ -774,17 +791,12 @@ function processOptions({
|
|
774
791
|
if (Array.isArray(plugins)) {
|
775
792
|
errors.push("'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.");
|
776
793
|
}
|
777
|
-
if (
|
778
|
-
reportUnusedDisableDirectives !== "error" &&
|
779
|
-
reportUnusedDisableDirectives !== "warn" &&
|
780
|
-
reportUnusedDisableDirectives !== "off" &&
|
781
|
-
reportUnusedDisableDirectives !== null
|
782
|
-
) {
|
783
|
-
errors.push("'reportUnusedDisableDirectives' must be any of \"error\", \"warn\", \"off\", and null.");
|
784
|
-
}
|
785
794
|
if (typeof warnIgnored !== "boolean") {
|
786
795
|
errors.push("'warnIgnored' must be a boolean.");
|
787
796
|
}
|
797
|
+
if (typeof ruleFilter !== "function") {
|
798
|
+
errors.push("'ruleFilter' must be a function.");
|
799
|
+
}
|
788
800
|
if (errors.length > 0) {
|
789
801
|
throw new ESLintInvalidOptionsError(errors);
|
790
802
|
}
|
@@ -806,8 +818,9 @@ function processOptions({
|
|
806
818
|
globInputPaths,
|
807
819
|
ignore,
|
808
820
|
ignorePatterns,
|
809
|
-
|
810
|
-
warnIgnored
|
821
|
+
passOnNoPatterns,
|
822
|
+
warnIgnored,
|
823
|
+
ruleFilter
|
811
824
|
};
|
812
825
|
}
|
813
826
|
|