build: update npm install command to use --legacy-peer-deps

This change modifies the build scripts to use --legacy-peer-deps flag when installing npm dependencies to resolve potential peer dependency conflicts during the build process. The change is applied to both bash (build.sh) and batch (build.bat) build scripts.
This commit is contained in:
Luiz Costa
2025-11-18 10:23:55 -03:00
parent 20129a1ac7
commit ac4f232e5e
787 changed files with 82341 additions and 121690 deletions
+14 -27
View File
@@ -8,14 +8,12 @@ This repository contains the legacy ESLintRC configuration file format for ESLin
You can install the package as follows:
```shell
npm install @eslint/eslintrc -D
```
npm install @eslint/eslintrc --save-dev
# or
yarn add @eslint/eslintrc -D
# or
pnpm install @eslint/eslintrc -D
# or
bun install @eslint/eslintrc -D
```
## Usage (ESM)
@@ -35,14 +33,14 @@ const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname, // optional; default: process.cwd()
resolvePluginsRelativeTo: __dirname, // optional
recommendedConfig: js.configs.recommended, // optional unless you're using "eslint:recommended"
allConfig: js.configs.all, // optional unless you're using "eslint:all"
recommendedConfig: js.configs.recommended, // optional
allConfig: js.configs.all, // optional
});
export default [
// mimic ESLintRC-style extends
...compat.extends("standard", "example", "plugin:react/recommended"),
...compat.extends("standard", "example"),
// mimic environments
...compat.env({
@@ -51,11 +49,11 @@ export default [
}),
// mimic plugins
...compat.plugins("jsx-a11y", "react"),
...compat.plugins("airbnb", "react"),
// translate an entire config
...compat.config({
plugins: ["jsx-a11y", "react"],
plugins: ["airbnb", "react"],
extends: "standard",
env: {
es2020: true,
@@ -79,14 +77,14 @@ const js = require("@eslint/js");
const compat = new FlatCompat({
baseDirectory: __dirname, // optional; default: process.cwd()
resolvePluginsRelativeTo: __dirname, // optional
recommendedConfig: js.configs.recommended, // optional unless using "eslint:recommended"
allConfig: js.configs.all, // optional unless using "eslint:all"
recommendedConfig: js.configs.recommended, // optional
allConfig: js.configs.all, // optional
});
module.exports = [
// mimic ESLintRC-style extends
...compat.extends("standard", "example", "plugin:react/recommended"),
...compat.extends("standard", "example"),
// mimic environments
...compat.env({
@@ -95,11 +93,11 @@ module.exports = [
}),
// mimic plugins
...compat.plugins("jsx-a11y", "react"),
...compat.plugins("airbnb", "react"),
// translate an entire config
...compat.config({
plugins: ["jsx-a11y", "react"],
plugins: ["airbnb", "react"],
extends: "standard",
env: {
es2020: true,
@@ -112,17 +110,6 @@ module.exports = [
];
```
## Troubleshooting
**TypeError: Missing parameter 'recommendedConfig' in FlatCompat constructor**
The `recommendedConfig` option is required when any config uses `eslint:recommended`, including any config in an `extends` clause. To fix this, follow the example above using `@eslint/js` to provide the `eslint:recommended` config.
**TypeError: Missing parameter 'allConfig' in FlatCompat constructor**
The `allConfig` option is required when any config uses `eslint:all`, including any config in an `extends` clause. To fix this, follow the example above using `@eslint/js` to provide the `eslint:all` config.
## License
MIT License
+1 -1
View File
@@ -23,7 +23,7 @@ function getDiff(current, prev) {
const retv = {};
for (const [key, value] of Object.entries(current)) {
if (!Object.hasOwn(prev, key)) {
if (!Object.hasOwnProperty.call(prev, key)) {
retv[key] = value;
}
}
+31 -139
View File
@@ -2,8 +2,8 @@
Object.defineProperty(exports, '__esModule', { value: true });
var util = require('node:util');
var path = require('node:path');
var util = require('util');
var path = require('path');
var Ajv = require('ajv');
var globals = require('globals');
@@ -29,7 +29,7 @@ const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
map[value] = index;
return map;
}, {}),
VALID_SEVERITIES = new Set([0, 1, 2, "off", "warn", "error"]);
VALID_SEVERITIES = [0, 1, 2, "off", "warn", "error"];
//------------------------------------------------------------------------------
// Public Interface
@@ -99,7 +99,7 @@ function isValidSeverity(ruleConfig) {
if (typeof severity === "string") {
severity = severity.toLowerCase();
}
return VALID_SEVERITIES.has(severity);
return VALID_SEVERITIES.indexOf(severity) !== -1;
}
/**
@@ -381,69 +381,12 @@ var ajvOrig = (additionalOptions = {}) => {
});
ajv.addMetaSchema(metaSchema);
// eslint-disable-next-line no-underscore-dangle -- part of the API
// eslint-disable-next-line no-underscore-dangle
ajv._opts.defaultMeta = metaSchema.id;
return ajv;
};
/**
* @fileoverview Applies default rule options
* @author JoshuaKGoldberg
*/
/**
* Check if the variable contains an object strictly rejecting arrays
* @param {unknown} value an object
* @returns {boolean} Whether value is an object
*/
function isObjectNotArray(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
/**
* Deeply merges second on top of first, creating a new {} object if needed.
* @param {T} first Base, default value.
* @param {U} second User-specified value.
* @returns {T | U | (T & U)} Merged equivalent of second on top of first.
*/
function deepMergeObjects(first, second) {
if (second === void 0) {
return first;
}
if (!isObjectNotArray(first) || !isObjectNotArray(second)) {
return second;
}
const result = { ...first, ...second };
for (const key of Object.keys(second)) {
if (Object.prototype.propertyIsEnumerable.call(first, key)) {
result[key] = deepMergeObjects(first[key], second[key]);
}
}
return result;
}
/**
* Deeply merges second on top of first, creating a new [] array if needed.
* @param {T[] | undefined} first Base, default values.
* @param {U[] | undefined} second User-specified values.
* @returns {(T | U | (T & U))[]} Merged equivalent of second on top of first.
*/
function deepMergeArrays(first, second) {
if (!first || !second) {
return second || first || [];
}
return [
...first.map((value, i) => deepMergeObjects(value, second[i])),
...second.slice(first.length)
];
}
/**
* @fileoverview Defines a schema for configs.
* @author Sylvan Mably
@@ -541,7 +484,7 @@ function getDiff(current, prev) {
const retv = {};
for (const [key, value] of Object.entries(current)) {
if (!Object.hasOwn(prev, key)) {
if (!Object.hasOwnProperty.call(prev, key)) {
retv[key] = value;
}
}
@@ -754,20 +697,10 @@ const severityMap = {
const validated = new WeakSet();
// JSON schema that disallows passing any options
const noOptionsSchema = Object.freeze({
type: "array",
minItems: 0,
maxItems: 0
});
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* Validator for configuration objects.
*/
class ConfigValidator {
constructor({ builtInRules = new Map() } = {}) {
this.builtInRules = builtInRules;
@@ -775,36 +708,17 @@ class ConfigValidator {
/**
* Gets a complete options schema for a rule.
* @param {Rule} rule A rule object
* @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
* @returns {Object|null} JSON Schema for the rule's options.
* `null` if rule wasn't passed or its `meta.schema` is `false`.
* @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
* @returns {Object} JSON Schema for the rule's options.
*/
getRuleOptionsSchema(rule) {
if (!rule) {
return null;
}
if (!rule.meta) {
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
}
const schema = rule.schema || rule.meta && rule.meta.schema;
const schema = rule.meta.schema;
if (typeof schema === "undefined") {
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
}
// `schema:false` is an allowed explicit opt-out of options validation for the rule
if (schema === false) {
return null;
}
if (typeof schema !== "object" || schema === null) {
throw new TypeError("Rule's `meta.schema` must be an array or object");
}
// ESLint-specific array form needs to be converted into a valid JSON Schema definition
// Given a tuple of schemas, insert warning level at the beginning
if (Array.isArray(schema)) {
if (schema.length) {
return {
@@ -814,20 +728,22 @@ class ConfigValidator {
maxItems: schema.length
};
}
return {
type: "array",
minItems: 0,
maxItems: 0
};
// `schema:[]` is an explicit way to specify that the rule does not accept any options
return { ...noOptionsSchema };
}
// `schema:<object>` is assumed to be a valid JSON Schema definition
return schema;
// Given a full schema, leave it alone
return schema || null;
}
/**
* Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
* @param {options} options The given options for the rule.
* @returns {number|string} The rule's severity value
* @throws {Error} If the severity is invalid.
*/
validateRuleSeverity(options) {
const severity = Array.isArray(options) ? options[0] : options;
@@ -846,32 +762,20 @@ class ConfigValidator {
* @param {{create: Function}} rule The rule to validate
* @param {Array} localOptions The options for the rule, excluding severity
* @returns {void}
* @throws {Error} If the options are invalid.
*/
validateRuleSchema(rule, localOptions) {
if (!ruleValidators.has(rule)) {
try {
const schema = this.getRuleOptionsSchema(rule);
const schema = this.getRuleOptionsSchema(rule);
if (schema) {
ruleValidators.set(rule, ajv.compile(schema));
}
} catch (err) {
const errorWithCode = new Error(err.message, { cause: err });
errorWithCode.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
throw errorWithCode;
if (schema) {
ruleValidators.set(rule, ajv.compile(schema));
}
}
const validateRule = ruleValidators.get(rule);
if (validateRule) {
const mergedOptions = deepMergeArrays(rule.meta?.defaultOptions, localOptions);
validateRule(mergedOptions);
validateRule(localOptions);
if (validateRule.errors) {
throw new Error(validateRule.errors.map(
error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
@@ -888,7 +792,6 @@ class ConfigValidator {
* @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
* no source is prepended to the message.
* @returns {void}
* @throws {Error} If the options are invalid.
*/
validateRuleOptions(rule, ruleId, options, source = null) {
try {
@@ -898,21 +801,13 @@ class ConfigValidator {
this.validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
}
} catch (err) {
let enhancedMessage = err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
? `Error while processing options validation schema of rule '${ruleId}': ${err.message}`
: `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
const enhancedMessage = `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
if (typeof source === "string") {
enhancedMessage = `${source}:\n\t${enhancedMessage}`;
throw new Error(`${source}:\n\t${enhancedMessage}`);
} else {
throw new Error(enhancedMessage);
}
const enhancedError = new Error(enhancedMessage, { cause: err });
if (err.code) {
enhancedError.code = err.code;
}
throw enhancedError;
}
}
@@ -920,9 +815,8 @@ class ConfigValidator {
* Validates an environment object
* @param {Object} environment The environment config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(envId:string) => Object} [getAdditionalEnv] A map from strings to loaded environments.
* @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded environments.
* @returns {void}
* @throws {Error} If the environment is invalid.
*/
validateEnvironment(
environment,
@@ -950,7 +844,7 @@ class ConfigValidator {
* Validates a rules config object
* @param {Object} rulesConfig The rules config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(ruleId:string) => Object} getAdditionalRule A map from strings to loaded rules
* @param {function(ruleId:string): Object} getAdditionalRule A map from strings to loaded rules
* @returns {void}
*/
validateRules(
@@ -994,9 +888,8 @@ class ConfigValidator {
* Validate `processor` configuration.
* @param {string|undefined} processorName The processor name.
* @param {string} source The name of config file.
* @param {(id:string) => Processor} getProcessor The getter of defined processors.
* @param {function(id:string): Processor} getProcessor The getter of defined processors.
* @returns {void}
* @throws {Error} If the processor is invalid.
*/
validateProcessor(processorName, source, getProcessor) {
if (processorName && !getProcessor(processorName)) {
@@ -1035,7 +928,6 @@ class ConfigValidator {
* @param {Object} config The config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @returns {void}
* @throws {Error} If the config is invalid.
*/
validateConfigSchema(config, source = null) {
validateSchema = validateSchema || ajv.compile(configSchema);
@@ -1044,7 +936,7 @@ class ConfigValidator {
throw new Error(`ESLint configuration in ${source} is invalid:\n${this.formatErrors(validateSchema.errors)}`);
}
if (Object.hasOwn(config, "ecmaFeatures")) {
if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
}
}
@@ -1053,8 +945,8 @@ class ConfigValidator {
* Validates an entire config object.
* @param {Object} config The config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(ruleId:string) => Object} [getAdditionalRule] A map from strings to loaded rules.
* @param {(envId:string) => Object} [getAdditionalEnv] A map from strings to loaded envs.
* @param {function(ruleId:string): Object} [getAdditionalRule] A map from strings to loaded rules.
* @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded envs.
* @returns {void}
*/
validate(config, source, getAdditionalRule, getAdditionalEnv) {
File diff suppressed because one or more lines are too long
+69 -181
View File
@@ -3,18 +3,18 @@
Object.defineProperty(exports, '__esModule', { value: true });
var debugOrig = require('debug');
var fs = require('node:fs');
var fs = require('fs');
var importFresh = require('import-fresh');
var Module = require('node:module');
var path = require('node:path');
var Module = require('module');
var path = require('path');
var stripComments = require('strip-json-comments');
var assert = require('node:assert');
var assert = require('assert');
var ignore = require('ignore');
var util = require('node:util');
var util = require('util');
var minimatch = require('minimatch');
var Ajv = require('ajv');
var globals = require('globals');
var os = require('node:os');
var os = require('os');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -142,9 +142,6 @@ const DotPatterns = Object.freeze([".*", "!.eslintrc.*", "!../"]);
// Public
//------------------------------------------------------------------------------
/**
* Represents a set of glob patterns to ignore against a base path.
*/
class IgnorePattern {
/**
@@ -181,7 +178,9 @@ class IgnorePattern {
debug$3("Create with: %o", ignorePatterns);
const basePath = getCommonAncestorPath(ignorePatterns.map(p => p.basePath));
const patterns = ignorePatterns.flatMap(p => p.getPatternsRelativeTo(basePath));
const patterns = [].concat(
...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
);
const ig = ignore__default["default"]({ allowRelativePaths: true }).add([...DotPatterns, ...patterns]);
const dotIg = ignore__default["default"]({ allowRelativePaths: true }).add(patterns);
@@ -381,10 +380,10 @@ class ExtractedConfig {
*/
toCompatibleObjectAsConfigFileContent() {
const {
/* eslint-disable no-unused-vars -- needed to make `config` correct */
/* eslint-disable no-unused-vars */
configNameOfNoInlineConfig: _ignore1,
processor: _ignore2,
/* eslint-enable no-unused-vars -- needed to make `config` correct */
/* eslint-enable no-unused-vars */
ignores,
...config
} = this;
@@ -576,7 +575,6 @@ class PluginConflictError extends Error {
* @param {Record<string, DependentPlugin>} target The destination to merge
* @param {Record<string, DependentPlugin>|undefined} source The source to merge.
* @returns {void}
* @throws {PluginConflictError} When a plugin was conflicted.
*/
function mergePlugins(target, source) {
if (!isNonNullObject(source)) {
@@ -657,7 +655,6 @@ function mergeRuleConfigs(target, source) {
* @param {ConfigArray} instance The config elements.
* @param {number[]} indices The indices to use.
* @returns {ExtractedConfig} The extracted config.
* @throws {Error} When a plugin is conflicted.
*/
function createConfig(instance, indices) {
const config = new ExtractedConfig();
@@ -719,18 +716,31 @@ function createConfig(instance, indices) {
* @param {string} pluginId The plugin ID for prefix.
* @param {Record<string,T>} defs The definitions to collect.
* @param {Map<string, U>} map The map to output.
* @param {function(T): U} [normalize] The normalize function for each value.
* @returns {void}
*/
function collect(pluginId, defs, map) {
function collect(pluginId, defs, map, normalize) {
if (defs) {
const prefix = pluginId && `${pluginId}/`;
for (const [key, value] of Object.entries(defs)) {
map.set(`${prefix}${key}`, value);
map.set(
`${prefix}${key}`,
normalize ? normalize(value) : value
);
}
}
}
/**
* Normalize a rule definition.
* @param {Function|Rule} rule The rule definition to normalize.
* @returns {Rule} The normalized rule definition.
*/
function normalizePluginRule(rule) {
return typeof rule === "function" ? { create: rule } : rule;
}
/**
* Delete the mutation methods from a given map.
* @param {Map<any, any>} map The map object to delete.
@@ -772,7 +782,7 @@ function initPluginMemberMaps(elements, slots) {
collect(pluginId, plugin.environments, slots.envMap);
collect(pluginId, plugin.processors, slots.processorMap);
collect(pluginId, plugin.rules, slots.ruleMap);
collect(pluginId, plugin.rules, slots.ruleMap, normalizePluginRule);
}
}
@@ -991,8 +1001,8 @@ class ConfigDependency {
this.importerPath = importerPath;
}
// eslint-disable-next-line jsdoc/require-description
/**
* Converts this instance to a JSON compatible object.
* @returns {Object} a JSON compatible object.
*/
toJSON() {
@@ -1006,14 +1016,14 @@ class ConfigDependency {
return obj;
}
// eslint-disable-next-line jsdoc/require-description
/**
* Custom inspect method for Node.js `console.log()`.
* @returns {Object} an object to display by `console.log()`.
*/
[util__default["default"].inspect.custom]() {
const {
definition: _ignore1, // eslint-disable-line no-unused-vars -- needed to make `obj` correct
original: _ignore2, // eslint-disable-line no-unused-vars -- needed to make `obj` correct
definition: _ignore1, // eslint-disable-line no-unused-vars
original: _ignore2, // eslint-disable-line no-unused-vars
...obj
} = this;
@@ -1112,7 +1122,6 @@ class OverrideTester {
* @param {string|string[]} excludedFiles The glob patterns for excluded files.
* @param {string} basePath The path to the base directory to test paths.
* @returns {OverrideTester|null} The created instance or `null`.
* @throws {Error} When invalid patterns are given.
*/
static create(files, excludedFiles, basePath) {
const includePatterns = normalizePatterns(files);
@@ -1202,7 +1211,6 @@ class OverrideTester {
* Test if a given path is matched or not.
* @param {string} filePath The absolute path to the target file.
* @returns {boolean} `true` if the path was matched.
* @throws {Error} When invalid `filePath` is given.
*/
test(filePath) {
if (typeof filePath !== "string" || !path__default["default"].isAbsolute(filePath)) {
@@ -1216,8 +1224,8 @@ class OverrideTester {
));
}
// eslint-disable-next-line jsdoc/require-description
/**
* Converts this instance to a JSON compatible object.
* @returns {Object} a JSON compatible object.
*/
toJSON() {
@@ -1233,8 +1241,8 @@ class OverrideTester {
};
}
// eslint-disable-next-line jsdoc/require-description
/**
* Custom inspect method for Node.js `console.log()`.
* @returns {Object} an object to display by `console.log()`.
*/
[util__default["default"].inspect.custom]() {
@@ -1262,7 +1270,7 @@ const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
map[value] = index;
return map;
}, {}),
VALID_SEVERITIES = new Set([0, 1, 2, "off", "warn", "error"]);
VALID_SEVERITIES = [0, 1, 2, "off", "warn", "error"];
//------------------------------------------------------------------------------
// Public Interface
@@ -1332,7 +1340,7 @@ function isValidSeverity(ruleConfig) {
if (typeof severity === "string") {
severity = severity.toLowerCase();
}
return VALID_SEVERITIES.has(severity);
return VALID_SEVERITIES.indexOf(severity) !== -1;
}
/**
@@ -1614,69 +1622,12 @@ var ajvOrig = (additionalOptions = {}) => {
});
ajv.addMetaSchema(metaSchema);
// eslint-disable-next-line no-underscore-dangle -- part of the API
// eslint-disable-next-line no-underscore-dangle
ajv._opts.defaultMeta = metaSchema.id;
return ajv;
};
/**
* @fileoverview Applies default rule options
* @author JoshuaKGoldberg
*/
/**
* Check if the variable contains an object strictly rejecting arrays
* @param {unknown} value an object
* @returns {boolean} Whether value is an object
*/
function isObjectNotArray(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
/**
* Deeply merges second on top of first, creating a new {} object if needed.
* @param {T} first Base, default value.
* @param {U} second User-specified value.
* @returns {T | U | (T & U)} Merged equivalent of second on top of first.
*/
function deepMergeObjects(first, second) {
if (second === void 0) {
return first;
}
if (!isObjectNotArray(first) || !isObjectNotArray(second)) {
return second;
}
const result = { ...first, ...second };
for (const key of Object.keys(second)) {
if (Object.prototype.propertyIsEnumerable.call(first, key)) {
result[key] = deepMergeObjects(first[key], second[key]);
}
}
return result;
}
/**
* Deeply merges second on top of first, creating a new [] array if needed.
* @param {T[] | undefined} first Base, default values.
* @param {U[] | undefined} second User-specified values.
* @returns {(T | U | (T & U))[]} Merged equivalent of second on top of first.
*/
function deepMergeArrays(first, second) {
if (!first || !second) {
return second || first || [];
}
return [
...first.map((value, i) => deepMergeObjects(value, second[i])),
...second.slice(first.length)
];
}
/**
* @fileoverview Defines a schema for configs.
* @author Sylvan Mably
@@ -1774,7 +1725,7 @@ function getDiff(current, prev) {
const retv = {};
for (const [key, value] of Object.entries(current)) {
if (!Object.hasOwn(prev, key)) {
if (!Object.hasOwnProperty.call(prev, key)) {
retv[key] = value;
}
}
@@ -1987,20 +1938,10 @@ const severityMap = {
const validated = new WeakSet();
// JSON schema that disallows passing any options
const noOptionsSchema = Object.freeze({
type: "array",
minItems: 0,
maxItems: 0
});
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* Validator for configuration objects.
*/
class ConfigValidator {
constructor({ builtInRules = new Map() } = {}) {
this.builtInRules = builtInRules;
@@ -2008,36 +1949,17 @@ class ConfigValidator {
/**
* Gets a complete options schema for a rule.
* @param {Rule} rule A rule object
* @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
* @returns {Object|null} JSON Schema for the rule's options.
* `null` if rule wasn't passed or its `meta.schema` is `false`.
* @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
* @returns {Object} JSON Schema for the rule's options.
*/
getRuleOptionsSchema(rule) {
if (!rule) {
return null;
}
if (!rule.meta) {
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
}
const schema = rule.schema || rule.meta && rule.meta.schema;
const schema = rule.meta.schema;
if (typeof schema === "undefined") {
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
}
// `schema:false` is an allowed explicit opt-out of options validation for the rule
if (schema === false) {
return null;
}
if (typeof schema !== "object" || schema === null) {
throw new TypeError("Rule's `meta.schema` must be an array or object");
}
// ESLint-specific array form needs to be converted into a valid JSON Schema definition
// Given a tuple of schemas, insert warning level at the beginning
if (Array.isArray(schema)) {
if (schema.length) {
return {
@@ -2047,20 +1969,22 @@ class ConfigValidator {
maxItems: schema.length
};
}
return {
type: "array",
minItems: 0,
maxItems: 0
};
// `schema:[]` is an explicit way to specify that the rule does not accept any options
return { ...noOptionsSchema };
}
// `schema:<object>` is assumed to be a valid JSON Schema definition
return schema;
// Given a full schema, leave it alone
return schema || null;
}
/**
* Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
* @param {options} options The given options for the rule.
* @returns {number|string} The rule's severity value
* @throws {Error} If the severity is invalid.
*/
validateRuleSeverity(options) {
const severity = Array.isArray(options) ? options[0] : options;
@@ -2079,32 +2003,20 @@ class ConfigValidator {
* @param {{create: Function}} rule The rule to validate
* @param {Array} localOptions The options for the rule, excluding severity
* @returns {void}
* @throws {Error} If the options are invalid.
*/
validateRuleSchema(rule, localOptions) {
if (!ruleValidators.has(rule)) {
try {
const schema = this.getRuleOptionsSchema(rule);
const schema = this.getRuleOptionsSchema(rule);
if (schema) {
ruleValidators.set(rule, ajv.compile(schema));
}
} catch (err) {
const errorWithCode = new Error(err.message, { cause: err });
errorWithCode.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
throw errorWithCode;
if (schema) {
ruleValidators.set(rule, ajv.compile(schema));
}
}
const validateRule = ruleValidators.get(rule);
if (validateRule) {
const mergedOptions = deepMergeArrays(rule.meta?.defaultOptions, localOptions);
validateRule(mergedOptions);
validateRule(localOptions);
if (validateRule.errors) {
throw new Error(validateRule.errors.map(
error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
@@ -2121,7 +2033,6 @@ class ConfigValidator {
* @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
* no source is prepended to the message.
* @returns {void}
* @throws {Error} If the options are invalid.
*/
validateRuleOptions(rule, ruleId, options, source = null) {
try {
@@ -2131,21 +2042,13 @@ class ConfigValidator {
this.validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
}
} catch (err) {
let enhancedMessage = err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
? `Error while processing options validation schema of rule '${ruleId}': ${err.message}`
: `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
const enhancedMessage = `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
if (typeof source === "string") {
enhancedMessage = `${source}:\n\t${enhancedMessage}`;
throw new Error(`${source}:\n\t${enhancedMessage}`);
} else {
throw new Error(enhancedMessage);
}
const enhancedError = new Error(enhancedMessage, { cause: err });
if (err.code) {
enhancedError.code = err.code;
}
throw enhancedError;
}
}
@@ -2153,9 +2056,8 @@ class ConfigValidator {
* Validates an environment object
* @param {Object} environment The environment config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(envId:string) => Object} [getAdditionalEnv] A map from strings to loaded environments.
* @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded environments.
* @returns {void}
* @throws {Error} If the environment is invalid.
*/
validateEnvironment(
environment,
@@ -2183,7 +2085,7 @@ class ConfigValidator {
* Validates a rules config object
* @param {Object} rulesConfig The rules config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(ruleId:string) => Object} getAdditionalRule A map from strings to loaded rules
* @param {function(ruleId:string): Object} getAdditionalRule A map from strings to loaded rules
* @returns {void}
*/
validateRules(
@@ -2227,9 +2129,8 @@ class ConfigValidator {
* Validate `processor` configuration.
* @param {string|undefined} processorName The processor name.
* @param {string} source The name of config file.
* @param {(id:string) => Processor} getProcessor The getter of defined processors.
* @param {function(id:string): Processor} getProcessor The getter of defined processors.
* @returns {void}
* @throws {Error} If the processor is invalid.
*/
validateProcessor(processorName, source, getProcessor) {
if (processorName && !getProcessor(processorName)) {
@@ -2268,7 +2169,6 @@ class ConfigValidator {
* @param {Object} config The config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @returns {void}
* @throws {Error} If the config is invalid.
*/
validateConfigSchema(config, source = null) {
validateSchema = validateSchema || ajv.compile(configSchema);
@@ -2277,7 +2177,7 @@ class ConfigValidator {
throw new Error(`ESLint configuration in ${source} is invalid:\n${this.formatErrors(validateSchema.errors)}`);
}
if (Object.hasOwn(config, "ecmaFeatures")) {
if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
}
}
@@ -2286,8 +2186,8 @@ class ConfigValidator {
* Validates an entire config object.
* @param {Object} config The config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(ruleId:string) => Object} [getAdditionalRule] A map from strings to loaded rules.
* @param {(envId:string) => Object} [getAdditionalEnv] A map from strings to loaded envs.
* @param {function(ruleId:string): Object} [getAdditionalRule] A map from strings to loaded rules.
* @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded envs.
* @returns {void}
*/
validate(config, source, getAdditionalRule, getAdditionalEnv) {
@@ -2440,7 +2340,6 @@ const createRequire = Module__default["default"].createRequire;
* @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
* a file rather than a directory, but the file need not actually exist.
* @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
* @throws {Error} When the module cannot be resolved.
*/
function resolve(moduleName, relativeToPath) {
try {
@@ -2701,7 +2600,7 @@ function loadPackageJSONConfigFile(filePath) {
try {
const packageData = loadJSONConfigFile(filePath);
if (!Object.hasOwn(packageData, "eslintConfig")) {
if (!Object.hasOwnProperty.call(packageData, "eslintConfig")) {
throw Object.assign(
new Error("package.json file doesn't have 'eslintConfig' field."),
{ code: "ESLINT_CONFIG_FIELD_NOT_FOUND" }
@@ -2720,7 +2619,6 @@ function loadPackageJSONConfigFile(filePath) {
* Loads a `.eslintignore` from a file.
* @param {string} filePath The filename to load.
* @returns {string[]} The ignore patterns from the file.
* @throws {Error} If the file cannot be read.
* @private
*/
function loadESLintIgnoreFile(filePath) {
@@ -2793,7 +2691,7 @@ function loadConfigFile(filePath) {
function writeDebugLogForLoading(request, relativeTo, filePath) {
/* istanbul ignore next */
if (debug$2.enabled) {
let nameAndVersion = null; // eslint-disable-line no-useless-assignment -- known bug in the rule
let nameAndVersion = null;
try {
const packageJsonPath = resolve(
@@ -2958,7 +2856,6 @@ class ConfigArrayFactory {
* @param {Object} [options] The options.
* @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
* @param {string} [options.name] The config name.
* @throws {Error} If the config file is invalid.
* @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
*/
loadInDirectory(directoryPath, { basePath, name } = {}) {
@@ -3044,7 +2941,6 @@ class ConfigArrayFactory {
/**
* Load `.eslintignore` file in the current working directory.
* @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
* @throws {Error} If the ignore file is invalid.
*/
loadDefaultESLintIgnore() {
const slots = internalSlotsMap$1.get(this);
@@ -3057,7 +2953,7 @@ class ConfigArrayFactory {
if (fs__default["default"].existsSync(packageJsonPath)) {
const data = loadJSONConfigFile(packageJsonPath);
if (Object.hasOwn(data, "eslintIgnore")) {
if (Object.hasOwnProperty.call(data, "eslintIgnore")) {
if (!Array.isArray(data.eslintIgnore)) {
throw new Error("Package.json eslintIgnore property requires an array of paths");
}
@@ -3246,7 +3142,6 @@ class ConfigArrayFactory {
* @param {string} extendName The name of a base config.
* @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
* @returns {IterableIterator<ConfigArrayElement>} The normalized config.
* @throws {Error} If the extended config file can't be loaded.
* @private
*/
_loadExtends(extendName, ctx) {
@@ -3270,7 +3165,6 @@ class ConfigArrayFactory {
* @param {string} extendName The name of a base config.
* @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
* @returns {IterableIterator<ConfigArrayElement>} The normalized config.
* @throws {Error} If the extended config file can't be loaded.
* @private
*/
_loadExtendedBuiltInConfig(extendName, ctx) {
@@ -3320,7 +3214,6 @@ class ConfigArrayFactory {
* @param {string} extendName The name of a base config.
* @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
* @returns {IterableIterator<ConfigArrayElement>} The normalized config.
* @throws {Error} If the extended config file can't be loaded.
* @private
*/
_loadExtendedPluginConfig(extendName, ctx) {
@@ -3358,7 +3251,6 @@ class ConfigArrayFactory {
* @param {string} extendName The name of a base config.
* @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
* @returns {IterableIterator<ConfigArrayElement>} The normalized config.
* @throws {Error} If the extended config file can't be loaded.
* @private
*/
_loadExtendedShareableConfig(extendName, ctx) {
@@ -3780,7 +3672,7 @@ function createCLIConfigArray({
*/
class ConfigurationNotFoundError extends Error {
// eslint-disable-next-line jsdoc/require-description
/**
* @param {string} directoryPath The directory path.
*/
@@ -3932,7 +3824,6 @@ class CascadingConfigArrayFactory {
* @param {string} directoryPath The path to a leaf directory.
* @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories.
* @returns {ConfigArray} The loaded config.
* @throws {Error} If a config file is invalid.
* @private
*/
_loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) {
@@ -4034,7 +3925,6 @@ class CascadingConfigArrayFactory {
* @param {string} directoryPath The path to the leaf directory to find config files.
* @param {boolean} ignoreNotFoundError If `true` then it doesn't throw `ConfigurationNotFoundError`.
* @returns {ConfigArray} The loaded config.
* @throws {Error} If a config file is invalid.
* @private
*/
_finalizeConfigArray(configArray, directoryPath, ignoreNotFoundError) {
@@ -4071,7 +3961,7 @@ class CascadingConfigArrayFactory {
!directoryPath.startsWith(homePath)
) {
const lastElement =
personalConfigArray.at(-1);
personalConfigArray[personalConfigArray.length - 1];
emitDeprecationWarning(
lastElement.filePath,
@@ -4143,7 +4033,6 @@ const cafactory = Symbol("cafactory");
* @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor
* names to objects.
* @returns {Object} A flag-config-style config object.
* @throws {Error} If a plugin or environment cannot be resolved.
*/
function translateESLintRC(eslintrcConfig, {
resolveConfigRelativeTo,
@@ -4326,7 +4215,7 @@ class FlatCompat {
this[cafactory] = new ConfigArrayFactory({
cwd: baseDirectory,
resolvePluginsRelativeTo,
getEslintAllConfig() {
getEslintAllConfig: () => {
if (!allConfig) {
throw new TypeError("Missing parameter 'allConfig' in FlatCompat constructor.");
@@ -4334,7 +4223,7 @@ class FlatCompat {
return allConfig;
},
getEslintRecommendedConfig() {
getEslintRecommendedConfig: () => {
if (!recommendedConfig) {
throw new TypeError("Missing parameter 'recommendedConfig' in FlatCompat constructor.");
@@ -4442,7 +4331,6 @@ const Legacy = {
OverrideTester,
getUsedExtractedConfigs,
environments,
loadConfigFile,
// shared
ConfigOps,
File diff suppressed because one or more lines are too long
-76
View File
@@ -1,76 +0,0 @@
/**
* @fileoverview This file contains the core types for ESLint. It was initially extracted
* from the `@types/eslint__eslintrc` package.
*/
/*
* MIT License
* Copyright (c) Microsoft Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE
*/
import type { Linter } from "eslint";
/**
* A compatibility class for working with configs.
*/
export class FlatCompat {
constructor({
baseDirectory,
resolvePluginsRelativeTo,
recommendedConfig,
allConfig,
}?: {
/**
* default: process.cwd()
*/
baseDirectory?: string;
resolvePluginsRelativeTo?: string;
recommendedConfig?: Linter.LegacyConfig;
allConfig?: Linter.LegacyConfig;
});
/**
* Translates an ESLintRC-style config into a flag-config-style config.
* @param eslintrcConfig The ESLintRC-style config object.
* @returns A flag-config-style config object.
*/
config(eslintrcConfig: Linter.LegacyConfig): Linter.Config[];
/**
* Translates the `env` section of an ESLintRC-style config.
* @param envConfig The `env` section of an ESLintRC config.
* @returns An array of flag-config objects representing the environments.
*/
env(envConfig: { [name: string]: boolean }): Linter.Config[];
/**
* Translates the `extends` section of an ESLintRC-style config.
* @param configsToExtend The names of the configs to load.
* @returns An array of flag-config objects representing the config.
*/
extends(...configsToExtend: string[]): Linter.Config[];
/**
* Translates the `plugins` section of an ESLintRC-style config.
* @param plugins The names of the plugins to load.
* @returns An array of flag-config objects representing the plugins.
*/
plugins(...plugins: string[]): Linter.Config[];
}
@@ -23,8 +23,8 @@
//------------------------------------------------------------------------------
import debugOrig from "debug";
import os from "node:os";
import path from "node:path";
import os from "os";
import path from "path";
import { ConfigArrayFactory } from "./config-array-factory.js";
import {
@@ -193,7 +193,7 @@ function createCLIConfigArray({
*/
class ConfigurationNotFoundError extends Error {
// eslint-disable-next-line jsdoc/require-description
/**
* @param {string} directoryPath The directory path.
*/
@@ -345,7 +345,6 @@ class CascadingConfigArrayFactory {
* @param {string} directoryPath The path to a leaf directory.
* @param {boolean} configsExistInSubdirs `true` if configurations exist in subdirectories.
* @returns {ConfigArray} The loaded config.
* @throws {Error} If a config file is invalid.
* @private
*/
_loadConfigInAncestors(directoryPath, configsExistInSubdirs = false) {
@@ -447,7 +446,6 @@ class CascadingConfigArrayFactory {
* @param {string} directoryPath The path to the leaf directory to find config files.
* @param {boolean} ignoreNotFoundError If `true` then it doesn't throw `ConfigurationNotFoundError`.
* @returns {ConfigArray} The loaded config.
* @throws {Error} If a config file is invalid.
* @private
*/
_finalizeConfigArray(configArray, directoryPath, ignoreNotFoundError) {
@@ -484,7 +482,7 @@ class CascadingConfigArrayFactory {
!directoryPath.startsWith(homePath)
) {
const lastElement =
personalConfigArray.at(-1);
personalConfigArray[personalConfigArray.length - 1];
emitDeprecationWarning(
lastElement.filePath,
+7 -18
View File
@@ -39,10 +39,10 @@
//------------------------------------------------------------------------------
import debugOrig from "debug";
import fs from "node:fs";
import fs from "fs";
import importFresh from "import-fresh";
import { createRequire } from "node:module";
import path from "node:path";
import { createRequire } from "module";
import path from "path";
import stripComments from "strip-json-comments";
import {
@@ -254,7 +254,7 @@ function loadPackageJSONConfigFile(filePath) {
try {
const packageData = loadJSONConfigFile(filePath);
if (!Object.hasOwn(packageData, "eslintConfig")) {
if (!Object.hasOwnProperty.call(packageData, "eslintConfig")) {
throw Object.assign(
new Error("package.json file doesn't have 'eslintConfig' field."),
{ code: "ESLINT_CONFIG_FIELD_NOT_FOUND" }
@@ -273,7 +273,6 @@ function loadPackageJSONConfigFile(filePath) {
* Loads a `.eslintignore` from a file.
* @param {string} filePath The filename to load.
* @returns {string[]} The ignore patterns from the file.
* @throws {Error} If the file cannot be read.
* @private
*/
function loadESLintIgnoreFile(filePath) {
@@ -346,7 +345,7 @@ function loadConfigFile(filePath) {
function writeDebugLogForLoading(request, relativeTo, filePath) {
/* istanbul ignore next */
if (debug.enabled) {
let nameAndVersion = null; // eslint-disable-line no-useless-assignment -- known bug in the rule
let nameAndVersion = null;
try {
const packageJsonPath = ModuleResolver.resolve(
@@ -511,7 +510,6 @@ class ConfigArrayFactory {
* @param {Object} [options] The options.
* @param {string} [options.basePath] The base path to resolve relative paths in `overrides[].files`, `overrides[].excludedFiles`, and `ignorePatterns`.
* @param {string} [options.name] The config name.
* @throws {Error} If the config file is invalid.
* @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
*/
loadInDirectory(directoryPath, { basePath, name } = {}) {
@@ -597,7 +595,6 @@ class ConfigArrayFactory {
/**
* Load `.eslintignore` file in the current working directory.
* @returns {ConfigArray} Loaded config. An empty `ConfigArray` if any config doesn't exist.
* @throws {Error} If the ignore file is invalid.
*/
loadDefaultESLintIgnore() {
const slots = internalSlotsMap.get(this);
@@ -610,7 +607,7 @@ class ConfigArrayFactory {
if (fs.existsSync(packageJsonPath)) {
const data = loadJSONConfigFile(packageJsonPath);
if (Object.hasOwn(data, "eslintIgnore")) {
if (Object.hasOwnProperty.call(data, "eslintIgnore")) {
if (!Array.isArray(data.eslintIgnore)) {
throw new Error("Package.json eslintIgnore property requires an array of paths");
}
@@ -799,7 +796,6 @@ class ConfigArrayFactory {
* @param {string} extendName The name of a base config.
* @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
* @returns {IterableIterator<ConfigArrayElement>} The normalized config.
* @throws {Error} If the extended config file can't be loaded.
* @private
*/
_loadExtends(extendName, ctx) {
@@ -823,7 +819,6 @@ class ConfigArrayFactory {
* @param {string} extendName The name of a base config.
* @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
* @returns {IterableIterator<ConfigArrayElement>} The normalized config.
* @throws {Error} If the extended config file can't be loaded.
* @private
*/
_loadExtendedBuiltInConfig(extendName, ctx) {
@@ -873,7 +868,6 @@ class ConfigArrayFactory {
* @param {string} extendName The name of a base config.
* @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
* @returns {IterableIterator<ConfigArrayElement>} The normalized config.
* @throws {Error} If the extended config file can't be loaded.
* @private
*/
_loadExtendedPluginConfig(extendName, ctx) {
@@ -911,7 +905,6 @@ class ConfigArrayFactory {
* @param {string} extendName The name of a base config.
* @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
* @returns {IterableIterator<ConfigArrayElement>} The normalized config.
* @throws {Error} If the extended config file can't be loaded.
* @private
*/
_loadExtendedShareableConfig(extendName, ctx) {
@@ -1155,8 +1148,4 @@ class ConfigArrayFactory {
}
}
export {
ConfigArrayFactory,
createContext,
loadConfigFile
};
export { ConfigArrayFactory, createContext };
+16 -5
View File
@@ -178,7 +178,6 @@ class PluginConflictError extends Error {
* @param {Record<string, DependentPlugin>} target The destination to merge
* @param {Record<string, DependentPlugin>|undefined} source The source to merge.
* @returns {void}
* @throws {PluginConflictError} When a plugin was conflicted.
*/
function mergePlugins(target, source) {
if (!isNonNullObject(source)) {
@@ -259,7 +258,6 @@ function mergeRuleConfigs(target, source) {
* @param {ConfigArray} instance The config elements.
* @param {number[]} indices The indices to use.
* @returns {ExtractedConfig} The extracted config.
* @throws {Error} When a plugin is conflicted.
*/
function createConfig(instance, indices) {
const config = new ExtractedConfig();
@@ -321,18 +319,31 @@ function createConfig(instance, indices) {
* @param {string} pluginId The plugin ID for prefix.
* @param {Record<string,T>} defs The definitions to collect.
* @param {Map<string, U>} map The map to output.
* @param {function(T): U} [normalize] The normalize function for each value.
* @returns {void}
*/
function collect(pluginId, defs, map) {
function collect(pluginId, defs, map, normalize) {
if (defs) {
const prefix = pluginId && `${pluginId}/`;
for (const [key, value] of Object.entries(defs)) {
map.set(`${prefix}${key}`, value);
map.set(
`${prefix}${key}`,
normalize ? normalize(value) : value
);
}
}
}
/**
* Normalize a rule definition.
* @param {Function|Rule} rule The rule definition to normalize.
* @returns {Rule} The normalized rule definition.
*/
function normalizePluginRule(rule) {
return typeof rule === "function" ? { create: rule } : rule;
}
/**
* Delete the mutation methods from a given map.
* @param {Map<any, any>} map The map object to delete.
@@ -374,7 +385,7 @@ function initPluginMemberMaps(elements, slots) {
collect(pluginId, plugin.environments, slots.envMap);
collect(pluginId, plugin.processors, slots.processorMap);
collect(pluginId, plugin.rules, slots.ruleMap);
collect(pluginId, plugin.rules, slots.ruleMap, normalizePluginRule);
}
}
@@ -15,7 +15,7 @@
* @author Toru Nagashima <https://github.com/mysticatea>
*/
import util from "node:util";
import util from "util";
/**
* The class is to store parsers or plugins.
@@ -88,8 +88,8 @@ class ConfigDependency {
this.importerPath = importerPath;
}
// eslint-disable-next-line jsdoc/require-description
/**
* Converts this instance to a JSON compatible object.
* @returns {Object} a JSON compatible object.
*/
toJSON() {
@@ -103,14 +103,14 @@ class ConfigDependency {
return obj;
}
// eslint-disable-next-line jsdoc/require-description
/**
* Custom inspect method for Node.js `console.log()`.
* @returns {Object} an object to display by `console.log()`.
*/
[util.inspect.custom]() {
const {
definition: _ignore1, // eslint-disable-line no-unused-vars -- needed to make `obj` correct
original: _ignore2, // eslint-disable-line no-unused-vars -- needed to make `obj` correct
definition: _ignore1, // eslint-disable-line no-unused-vars
original: _ignore2, // eslint-disable-line no-unused-vars
...obj
} = this;
@@ -120,10 +120,10 @@ class ExtractedConfig {
*/
toCompatibleObjectAsConfigFileContent() {
const {
/* eslint-disable no-unused-vars -- needed to make `config` correct */
/* eslint-disable no-unused-vars */
configNameOfNoInlineConfig: _ignore1,
processor: _ignore2,
/* eslint-enable no-unused-vars -- needed to make `config` correct */
/* eslint-enable no-unused-vars */
ignores,
...config
} = this;
+5 -6
View File
@@ -32,8 +32,8 @@
// Requirements
//------------------------------------------------------------------------------
import assert from "node:assert";
import path from "node:path";
import assert from "assert";
import path from "path";
import ignore from "ignore";
import debugOrig from "debug";
@@ -117,9 +117,6 @@ const DotPatterns = Object.freeze([".*", "!.eslintrc.*", "!../"]);
// Public
//------------------------------------------------------------------------------
/**
* Represents a set of glob patterns to ignore against a base path.
*/
class IgnorePattern {
/**
@@ -156,7 +153,9 @@ class IgnorePattern {
debug("Create with: %o", ignorePatterns);
const basePath = getCommonAncestorPath(ignorePatterns.map(p => p.basePath));
const patterns = ignorePatterns.flatMap(p => p.getPatternsRelativeTo(basePath));
const patterns = [].concat(
...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
);
const ig = ignore({ allowRelativePaths: true }).add([...DotPatterns, ...patterns]);
const dotIg = ignore({ allowRelativePaths: true }).add(patterns);
@@ -17,9 +17,9 @@
* @author Toru Nagashima <https://github.com/mysticatea>
*/
import assert from "node:assert";
import path from "node:path";
import util from "node:util";
import assert from "assert";
import path from "path";
import util from "util";
import minimatch from "minimatch";
const { Minimatch } = minimatch;
@@ -94,7 +94,6 @@ class OverrideTester {
* @param {string|string[]} excludedFiles The glob patterns for excluded files.
* @param {string} basePath The path to the base directory to test paths.
* @returns {OverrideTester|null} The created instance or `null`.
* @throws {Error} When invalid patterns are given.
*/
static create(files, excludedFiles, basePath) {
const includePatterns = normalizePatterns(files);
@@ -184,7 +183,6 @@ class OverrideTester {
* Test if a given path is matched or not.
* @param {string} filePath The absolute path to the target file.
* @returns {boolean} `true` if the path was matched.
* @throws {Error} When invalid `filePath` is given.
*/
test(filePath) {
if (typeof filePath !== "string" || !path.isAbsolute(filePath)) {
@@ -198,8 +196,8 @@ class OverrideTester {
));
}
// eslint-disable-next-line jsdoc/require-description
/**
* Converts this instance to a JSON compatible object.
* @returns {Object} a JSON compatible object.
*/
toJSON() {
@@ -215,8 +213,8 @@ class OverrideTester {
};
}
// eslint-disable-next-line jsdoc/require-description
/**
* Custom inspect method for Node.js `console.log()`.
* @returns {Object} an object to display by `console.log()`.
*/
[util.inspect.custom]() {
+3 -4
View File
@@ -8,7 +8,7 @@
//-----------------------------------------------------------------------------
import createDebug from "debug";
import path from "node:path";
import path from "path";
import environments from "../conf/environments.js";
import { ConfigArrayFactory } from "./config-array-factory.js";
@@ -37,7 +37,6 @@ const cafactory = Symbol("cafactory");
* @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor
* names to objects.
* @returns {Object} A flag-config-style config object.
* @throws {Error} If a plugin or environment cannot be resolved.
*/
function translateESLintRC(eslintrcConfig, {
resolveConfigRelativeTo,
@@ -220,7 +219,7 @@ class FlatCompat {
this[cafactory] = new ConfigArrayFactory({
cwd: baseDirectory,
resolvePluginsRelativeTo,
getEslintAllConfig() {
getEslintAllConfig: () => {
if (!allConfig) {
throw new TypeError("Missing parameter 'allConfig' in FlatCompat constructor.");
@@ -228,7 +227,7 @@ class FlatCompat {
return allConfig;
},
getEslintRecommendedConfig() {
getEslintRecommendedConfig: () => {
if (!recommendedConfig) {
throw new TypeError("Missing parameter 'recommendedConfig' in FlatCompat constructor.");
+1 -3
View File
@@ -8,8 +8,7 @@
import {
ConfigArrayFactory,
createContext as createConfigArrayFactoryContext,
loadConfigFile
createContext as createConfigArrayFactoryContext
} from "./config-array-factory.js";
import { CascadingConfigArrayFactory } from "./cascading-config-array-factory.js";
@@ -40,7 +39,6 @@ const Legacy = {
OverrideTester,
getUsedExtractedConfigs,
environments,
loadConfigFile,
// shared
ConfigOps,
+1 -1
View File
@@ -184,7 +184,7 @@ export default (additionalOptions = {}) => {
});
ajv.addMetaSchema(metaSchema);
// eslint-disable-next-line no-underscore-dangle -- part of the API
// eslint-disable-next-line no-underscore-dangle
ajv._opts.defaultMeta = metaSchema.id;
return ajv;
+2 -2
View File
@@ -13,7 +13,7 @@ const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
map[value] = index;
return map;
}, {}),
VALID_SEVERITIES = new Set([0, 1, 2, "off", "warn", "error"]);
VALID_SEVERITIES = [0, 1, 2, "off", "warn", "error"];
//------------------------------------------------------------------------------
// Public Interface
@@ -83,7 +83,7 @@ function isValidSeverity(ruleConfig) {
if (typeof severity === "string") {
severity = severity.toLowerCase();
}
return VALID_SEVERITIES.has(severity);
return VALID_SEVERITIES.indexOf(severity) !== -1;
}
/**
+27 -85
View File
@@ -3,23 +3,16 @@
* @author Brandon Mills
*/
/* eslint class-methods-use-this: "off" -- not needed in this file */
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
/** @typedef {import("../shared/types").Rule} Rule */
/* eslint class-methods-use-this: "off" */
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
import util from "node:util";
import util from "util";
import * as ConfigOps from "./config-ops.js";
import { emitDeprecationWarning } from "./deprecation-warnings.js";
import ajvOrig from "./ajv.js";
import { deepMergeArrays } from "./deep-merge-arrays.js";
import configSchema from "../../conf/config-schema.js";
import BuiltInEnvironments from "../../conf/environments.js";
@@ -40,20 +33,10 @@ const severityMap = {
const validated = new WeakSet();
// JSON schema that disallows passing any options
const noOptionsSchema = Object.freeze({
type: "array",
minItems: 0,
maxItems: 0
});
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* Validator for configuration objects.
*/
export default class ConfigValidator {
constructor({ builtInRules = new Map() } = {}) {
this.builtInRules = builtInRules;
@@ -61,36 +44,17 @@ export default class ConfigValidator {
/**
* Gets a complete options schema for a rule.
* @param {Rule} rule A rule object
* @throws {TypeError} If `meta.schema` is specified but is not an array, object or `false`.
* @returns {Object|null} JSON Schema for the rule's options.
* `null` if rule wasn't passed or its `meta.schema` is `false`.
* @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
* @returns {Object} JSON Schema for the rule's options.
*/
getRuleOptionsSchema(rule) {
if (!rule) {
return null;
}
if (!rule.meta) {
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
}
const schema = rule.schema || rule.meta && rule.meta.schema;
const schema = rule.meta.schema;
if (typeof schema === "undefined") {
return { ...noOptionsSchema }; // default if `meta.schema` is not specified
}
// `schema:false` is an allowed explicit opt-out of options validation for the rule
if (schema === false) {
return null;
}
if (typeof schema !== "object" || schema === null) {
throw new TypeError("Rule's `meta.schema` must be an array or object");
}
// ESLint-specific array form needs to be converted into a valid JSON Schema definition
// Given a tuple of schemas, insert warning level at the beginning
if (Array.isArray(schema)) {
if (schema.length) {
return {
@@ -100,20 +64,22 @@ export default class ConfigValidator {
maxItems: schema.length
};
}
return {
type: "array",
minItems: 0,
maxItems: 0
};
// `schema:[]` is an explicit way to specify that the rule does not accept any options
return { ...noOptionsSchema };
}
// `schema:<object>` is assumed to be a valid JSON Schema definition
return schema;
// Given a full schema, leave it alone
return schema || null;
}
/**
* Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
* @param {options} options The given options for the rule.
* @returns {number|string} The rule's severity value
* @throws {Error} If the severity is invalid.
*/
validateRuleSeverity(options) {
const severity = Array.isArray(options) ? options[0] : options;
@@ -132,32 +98,20 @@ export default class ConfigValidator {
* @param {{create: Function}} rule The rule to validate
* @param {Array} localOptions The options for the rule, excluding severity
* @returns {void}
* @throws {Error} If the options are invalid.
*/
validateRuleSchema(rule, localOptions) {
if (!ruleValidators.has(rule)) {
try {
const schema = this.getRuleOptionsSchema(rule);
const schema = this.getRuleOptionsSchema(rule);
if (schema) {
ruleValidators.set(rule, ajv.compile(schema));
}
} catch (err) {
const errorWithCode = new Error(err.message, { cause: err });
errorWithCode.code = "ESLINT_INVALID_RULE_OPTIONS_SCHEMA";
throw errorWithCode;
if (schema) {
ruleValidators.set(rule, ajv.compile(schema));
}
}
const validateRule = ruleValidators.get(rule);
if (validateRule) {
const mergedOptions = deepMergeArrays(rule.meta?.defaultOptions, localOptions);
validateRule(mergedOptions);
validateRule(localOptions);
if (validateRule.errors) {
throw new Error(validateRule.errors.map(
error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
@@ -174,7 +128,6 @@ export default class ConfigValidator {
* @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
* no source is prepended to the message.
* @returns {void}
* @throws {Error} If the options are invalid.
*/
validateRuleOptions(rule, ruleId, options, source = null) {
try {
@@ -184,21 +137,13 @@ export default class ConfigValidator {
this.validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
}
} catch (err) {
let enhancedMessage = err.code === "ESLINT_INVALID_RULE_OPTIONS_SCHEMA"
? `Error while processing options validation schema of rule '${ruleId}': ${err.message}`
: `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
const enhancedMessage = `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;
if (typeof source === "string") {
enhancedMessage = `${source}:\n\t${enhancedMessage}`;
throw new Error(`${source}:\n\t${enhancedMessage}`);
} else {
throw new Error(enhancedMessage);
}
const enhancedError = new Error(enhancedMessage, { cause: err });
if (err.code) {
enhancedError.code = err.code;
}
throw enhancedError;
}
}
@@ -206,9 +151,8 @@ export default class ConfigValidator {
* Validates an environment object
* @param {Object} environment The environment config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(envId:string) => Object} [getAdditionalEnv] A map from strings to loaded environments.
* @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded environments.
* @returns {void}
* @throws {Error} If the environment is invalid.
*/
validateEnvironment(
environment,
@@ -236,7 +180,7 @@ export default class ConfigValidator {
* Validates a rules config object
* @param {Object} rulesConfig The rules config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(ruleId:string) => Object} getAdditionalRule A map from strings to loaded rules
* @param {function(ruleId:string): Object} getAdditionalRule A map from strings to loaded rules
* @returns {void}
*/
validateRules(
@@ -280,9 +224,8 @@ export default class ConfigValidator {
* Validate `processor` configuration.
* @param {string|undefined} processorName The processor name.
* @param {string} source The name of config file.
* @param {(id:string) => Processor} getProcessor The getter of defined processors.
* @param {function(id:string): Processor} getProcessor The getter of defined processors.
* @returns {void}
* @throws {Error} If the processor is invalid.
*/
validateProcessor(processorName, source, getProcessor) {
if (processorName && !getProcessor(processorName)) {
@@ -321,7 +264,6 @@ export default class ConfigValidator {
* @param {Object} config The config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @returns {void}
* @throws {Error} If the config is invalid.
*/
validateConfigSchema(config, source = null) {
validateSchema = validateSchema || ajv.compile(configSchema);
@@ -330,7 +272,7 @@ export default class ConfigValidator {
throw new Error(`ESLint configuration in ${source} is invalid:\n${this.formatErrors(validateSchema.errors)}`);
}
if (Object.hasOwn(config, "ecmaFeatures")) {
if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
}
}
@@ -339,8 +281,8 @@ export default class ConfigValidator {
* Validates an entire config object.
* @param {Object} config The config object to validate.
* @param {string} source The name of the configuration source to report in any errors.
* @param {(ruleId:string) => Object} [getAdditionalRule] A map from strings to loaded rules.
* @param {(envId:string) => Object} [getAdditionalEnv] A map from strings to loaded envs.
* @param {function(ruleId:string): Object} [getAdditionalRule] A map from strings to loaded rules.
* @param {function(envId:string): Object} [getAdditionalEnv] A map from strings to loaded envs.
* @returns {void}
*/
validate(config, source, getAdditionalRule, getAdditionalEnv) {
-58
View File
@@ -1,58 +0,0 @@
/**
* @fileoverview Applies default rule options
* @author JoshuaKGoldberg
*/
/**
* Check if the variable contains an object strictly rejecting arrays
* @param {unknown} value an object
* @returns {boolean} Whether value is an object
*/
function isObjectNotArray(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
/**
* Deeply merges second on top of first, creating a new {} object if needed.
* @param {T} first Base, default value.
* @param {U} second User-specified value.
* @returns {T | U | (T & U)} Merged equivalent of second on top of first.
*/
function deepMergeObjects(first, second) {
if (second === void 0) {
return first;
}
if (!isObjectNotArray(first) || !isObjectNotArray(second)) {
return second;
}
const result = { ...first, ...second };
for (const key of Object.keys(second)) {
if (Object.prototype.propertyIsEnumerable.call(first, key)) {
result[key] = deepMergeObjects(first[key], second[key]);
}
}
return result;
}
/**
* Deeply merges second on top of first, creating a new [] array if needed.
* @param {T[] | undefined} first Base, default values.
* @param {U[] | undefined} second User-specified values.
* @returns {(T | U | (T & U))[]} Merged equivalent of second on top of first.
*/
function deepMergeArrays(first, second) {
if (!first || !second) {
return second || first || [];
}
return [
...first.map((value, i) => deepMergeObjects(value, second[i])),
...second.slice(first.length)
];
}
export { deepMergeArrays };
+1 -1
View File
@@ -7,7 +7,7 @@
// Requirements
//------------------------------------------------------------------------------
import path from "node:path";
import path from "path";
//------------------------------------------------------------------------------
// Private
@@ -3,7 +3,7 @@
* @author Teddy Katz
*/
import Module from "node:module";
import Module from "module";
/*
* `Module.createRequire` is added in v12.2.0. It supports URL as well.
@@ -17,7 +17,6 @@ const createRequire = Module.createRequire;
* @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
* a file rather than a directory, but the file need not actually exist.
* @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
* @throws {Error} When the module cannot be resolved.
*/
function resolve(moduleName, relativeToPath) {
try {
-76
View File
@@ -1,76 +0,0 @@
/**
* @fileoverview This file contains the core types for ESLint. It was initially extracted
* from the `@types/eslint__eslintrc` package.
*/
/*
* MIT License
* Copyright (c) Microsoft Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE
*/
import type { Linter } from "eslint";
/**
* A compatibility class for working with configs.
*/
export class FlatCompat {
constructor({
baseDirectory,
resolvePluginsRelativeTo,
recommendedConfig,
allConfig,
}?: {
/**
* default: process.cwd()
*/
baseDirectory?: string;
resolvePluginsRelativeTo?: string;
recommendedConfig?: Linter.LegacyConfig;
allConfig?: Linter.LegacyConfig;
});
/**
* Translates an ESLintRC-style config into a flag-config-style config.
* @param eslintrcConfig The ESLintRC-style config object.
* @returns A flag-config-style config object.
*/
config(eslintrcConfig: Linter.LegacyConfig): Linter.Config[];
/**
* Translates the `env` section of an ESLintRC-style config.
* @param envConfig The `env` section of an ESLintRC config.
* @returns An array of flag-config objects representing the environments.
*/
env(envConfig: { [name: string]: boolean }): Linter.Config[];
/**
* Translates the `extends` section of an ESLintRC-style config.
* @param configsToExtend The names of the configs to load.
* @returns An array of flag-config objects representing the config.
*/
extends(...configsToExtend: string[]): Linter.Config[];
/**
* Translates the `plugins` section of an ESLintRC-style config.
* @param plugins The names of the plugins to load.
* @returns An array of flag-config objects representing the plugins.
*/
plugins(...plugins: string[]): Linter.Config[];
}
+13 -15
View File
@@ -1,15 +1,13 @@
{
"name": "@eslint/eslintrc",
"version": "3.3.1",
"version": "2.1.4",
"description": "The legacy ESLintRC config file format for ESLint",
"type": "module",
"main": "./dist/eslintrc.cjs",
"types": "./dist/eslintrc.d.cts",
"exports": {
".": {
"import": "./lib/index.js",
"require": "./dist/eslintrc.cjs",
"types": "./lib/types/index.d.ts"
"require": "./dist/eslintrc.cjs"
},
"./package.json": "./package.json",
"./universal": {
@@ -28,7 +26,7 @@
"access": "public"
},
"scripts": {
"build": "rollup -c && node -e \"fs.copyFileSync('./lib/types/index.d.ts', './dist/eslintrc.d.cts')\"",
"build": "rollup -c",
"lint": "eslint . --report-unused-disable-directives",
"lint:fix": "npm run lint -- --fix",
"prepare": "npm run build",
@@ -37,8 +35,7 @@
"release:generate:beta": "eslint-generate-prerelease beta",
"release:generate:rc": "eslint-generate-prerelease rc",
"release:publish": "eslint-publish-release",
"test": "mocha -R progress -c 'tests/lib/*.cjs' && c8 mocha -R progress -c 'tests/lib/**/*.js'",
"test:types": "tsc -p tests/lib/types/tsconfig.json"
"test": "mocha -R progress -c 'tests/lib/*.cjs' && c8 mocha -R progress -c 'tests/lib/**/*.js'"
},
"repository": "eslint/eslintrc",
"funding": "https://opencollective.com/eslint",
@@ -56,22 +53,23 @@
"devDependencies": {
"c8": "^7.7.3",
"chai": "^4.3.4",
"eslint": "^9.20.1",
"eslint-config-eslint": "^11.0.0",
"eslint": "^7.31.0",
"eslint-config-eslint": "^7.0.0",
"eslint-plugin-jsdoc": "^35.4.1",
"eslint-plugin-node": "^11.1.0",
"eslint-release": "^3.2.0",
"fs-teardown": "^0.1.3",
"mocha": "^9.0.3",
"rollup": "^2.70.1",
"shelljs": "^0.8.5",
"shelljs": "^0.8.4",
"sinon": "^11.1.2",
"temp-dir": "^2.0.0",
"typescript": "^5.7.3"
"temp-dir": "^2.0.0"
},
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^10.0.1",
"globals": "^14.0.0",
"espree": "^9.6.0",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
@@ -79,6 +77,6 @@
"strip-json-comments": "^3.1.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
}
+1 -2
View File
@@ -1,5 +1,3 @@
/* global module, require -- required for CJS file */
// Jest (and probably some other runtimes with custom implementations of
// `require`) doesn't support `exports` in `package.json`, so this file is here
// to help them load this module. Note that it is also `.js` and not `.cjs` for
@@ -7,4 +5,5 @@
// since Jest doesn't respect `module` outside of ESM mode it still works in
// this case (and the `require` in _this_ file does specify the extension).
// eslint-disable-next-line no-undef
module.exports = require("./dist/eslintrc-universal.cjs");