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.
381 lines
12 KiB
JavaScript
381 lines
12 KiB
JavaScript
/**
|
|
* @fileoverview Flat Config Array
|
|
* @author Nicholas C. Zakas
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Requirements
|
|
//-----------------------------------------------------------------------------
|
|
|
|
const { ConfigArray, ConfigArraySymbol } = require("@humanwhocodes/config-array");
|
|
const { flatConfigSchema } = require("./flat-config-schema");
|
|
const { RuleValidator } = require("./rule-validator");
|
|
const { defaultConfig } = require("./default-config");
|
|
const jsPlugin = require("@eslint/js");
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Helpers
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Fields that are considered metadata and not part of the config object.
|
|
*/
|
|
const META_FIELDS = new Set(["name"]);
|
|
|
|
const ruleValidator = new RuleValidator();
|
|
|
|
/**
|
|
* Splits a plugin identifier in the form a/b/c into two parts: a/b and c.
|
|
* @param {string} identifier The identifier to parse.
|
|
* @returns {{objectName: string, pluginName: string}} The parts of the plugin
|
|
* name.
|
|
*/
|
|
function splitPluginIdentifier(identifier) {
|
|
const parts = identifier.split("/");
|
|
|
|
return {
|
|
objectName: parts.pop(),
|
|
pluginName: parts.join("/")
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns the name of an object in the config by reading its `meta` key.
|
|
* @param {Object} object The object to check.
|
|
* @returns {string?} The name of the object if found or `null` if there
|
|
* is no name.
|
|
*/
|
|
function getObjectId(object) {
|
|
|
|
// first check old-style name
|
|
let name = object.name;
|
|
|
|
if (!name) {
|
|
|
|
if (!object.meta) {
|
|
return null;
|
|
}
|
|
|
|
name = object.meta.name;
|
|
|
|
if (!name) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// now check for old-style version
|
|
let version = object.version;
|
|
|
|
if (!version) {
|
|
version = object.meta && object.meta.version;
|
|
}
|
|
|
|
// if there's a version then append that
|
|
if (version) {
|
|
return `${name}@${version}`;
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* Wraps a config error with details about where the error occurred.
|
|
* @param {Error} error The original error.
|
|
* @param {number} originalLength The original length of the config array.
|
|
* @param {number} baseLength The length of the base config.
|
|
* @returns {TypeError} The new error with details.
|
|
*/
|
|
function wrapConfigErrorWithDetails(error, originalLength, baseLength) {
|
|
|
|
let location = "user-defined";
|
|
let configIndex = error.index;
|
|
|
|
/*
|
|
* A config array is set up in this order:
|
|
* 1. Base config
|
|
* 2. Original configs
|
|
* 3. User-defined configs
|
|
* 4. CLI-defined configs
|
|
*
|
|
* So we need to adjust the index to account for the base config.
|
|
*
|
|
* - If the index is less than the base length, it's in the base config
|
|
* (as specified by `baseConfig` argument to `FlatConfigArray` constructor).
|
|
* - If the index is greater than the base length but less than the original
|
|
* length + base length, it's in the original config. The original config
|
|
* is passed to the `FlatConfigArray` constructor as the first argument.
|
|
* - Otherwise, it's in the user-defined config, which is loaded from the
|
|
* config file and merged with any command-line options.
|
|
*/
|
|
if (error.index < baseLength) {
|
|
location = "base";
|
|
} else if (error.index < originalLength + baseLength) {
|
|
location = "original";
|
|
configIndex = error.index - baseLength;
|
|
} else {
|
|
configIndex = error.index - originalLength - baseLength;
|
|
}
|
|
|
|
return new TypeError(
|
|
`${error.message.slice(0, -1)} at ${location} index ${configIndex}.`,
|
|
{ cause: error }
|
|
);
|
|
}
|
|
|
|
const originalBaseConfig = Symbol("originalBaseConfig");
|
|
const originalLength = Symbol("originalLength");
|
|
const baseLength = Symbol("baseLength");
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Exports
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Represents an array containing configuration information for ESLint.
|
|
*/
|
|
class FlatConfigArray extends ConfigArray {
|
|
|
|
/**
|
|
* Creates a new instance.
|
|
* @param {*[]} configs An array of configuration information.
|
|
* @param {{basePath: string, shouldIgnore: boolean, baseConfig: FlatConfig}} options The options
|
|
* to use for the config array instance.
|
|
*/
|
|
constructor(configs, {
|
|
basePath,
|
|
shouldIgnore = true,
|
|
baseConfig = defaultConfig
|
|
} = {}) {
|
|
super(configs, {
|
|
basePath,
|
|
schema: flatConfigSchema
|
|
});
|
|
|
|
/**
|
|
* The original length of the array before any modifications.
|
|
* @type {number}
|
|
*/
|
|
this[originalLength] = this.length;
|
|
|
|
if (baseConfig[Symbol.iterator]) {
|
|
this.unshift(...baseConfig);
|
|
} else {
|
|
this.unshift(baseConfig);
|
|
}
|
|
|
|
/**
|
|
* The length of the array after applying the base config.
|
|
* @type {number}
|
|
*/
|
|
this[baseLength] = this.length - this[originalLength];
|
|
|
|
/**
|
|
* The base config used to build the config array.
|
|
* @type {Array<FlatConfig>}
|
|
*/
|
|
this[originalBaseConfig] = baseConfig;
|
|
Object.defineProperty(this, originalBaseConfig, { writable: false });
|
|
|
|
/**
|
|
* Determines if `ignores` fields should be honored.
|
|
* If true, then all `ignores` fields are honored.
|
|
* if false, then only `ignores` fields in the baseConfig are honored.
|
|
* @type {boolean}
|
|
*/
|
|
this.shouldIgnore = shouldIgnore;
|
|
Object.defineProperty(this, "shouldIgnore", { writable: false });
|
|
}
|
|
|
|
/**
|
|
* Normalizes the array by calling the superclass method and catching/rethrowing
|
|
* any ConfigError exceptions with additional details.
|
|
* @param {any} [context] The context to use to normalize the array.
|
|
* @returns {Promise<FlatConfigArray>} A promise that resolves when the array is normalized.
|
|
*/
|
|
normalize(context) {
|
|
return super.normalize(context)
|
|
.catch(error => {
|
|
if (error.name === "ConfigError") {
|
|
throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
|
|
}
|
|
|
|
throw error;
|
|
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Normalizes the array by calling the superclass method and catching/rethrowing
|
|
* any ConfigError exceptions with additional details.
|
|
* @param {any} [context] The context to use to normalize the array.
|
|
* @returns {FlatConfigArray} The current instance.
|
|
* @throws {TypeError} If the config is invalid.
|
|
*/
|
|
normalizeSync(context) {
|
|
|
|
try {
|
|
|
|
return super.normalizeSync(context);
|
|
|
|
} catch (error) {
|
|
|
|
if (error.name === "ConfigError") {
|
|
throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
|
|
}
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* eslint-disable class-methods-use-this -- Desired as instance method */
|
|
/**
|
|
* Replaces a config with another config to allow us to put strings
|
|
* in the config array that will be replaced by objects before
|
|
* normalization.
|
|
* @param {Object} config The config to preprocess.
|
|
* @returns {Object} The preprocessed config.
|
|
*/
|
|
[ConfigArraySymbol.preprocessConfig](config) {
|
|
if (config === "eslint:recommended") {
|
|
|
|
// if we are in a Node.js environment warn the user
|
|
if (typeof process !== "undefined" && process.emitWarning) {
|
|
process.emitWarning("The 'eslint:recommended' string configuration is deprecated and will be replaced by the @eslint/js package's 'recommended' config.");
|
|
}
|
|
|
|
return jsPlugin.configs.recommended;
|
|
}
|
|
|
|
if (config === "eslint:all") {
|
|
|
|
// if we are in a Node.js environment warn the user
|
|
if (typeof process !== "undefined" && process.emitWarning) {
|
|
process.emitWarning("The 'eslint:all' string configuration is deprecated and will be replaced by the @eslint/js package's 'all' config.");
|
|
}
|
|
|
|
return jsPlugin.configs.all;
|
|
}
|
|
|
|
/*
|
|
* If a config object has `ignores` and no other non-meta fields, then it's an object
|
|
* for global ignores. If `shouldIgnore` is false, that object shouldn't apply,
|
|
* so we'll remove its `ignores`.
|
|
*/
|
|
if (
|
|
!this.shouldIgnore &&
|
|
!this[originalBaseConfig].includes(config) &&
|
|
config.ignores &&
|
|
Object.keys(config).filter(key => !META_FIELDS.has(key)).length === 1
|
|
) {
|
|
/* eslint-disable-next-line no-unused-vars -- need to strip off other keys */
|
|
const { ignores, ...otherKeys } = config;
|
|
|
|
return otherKeys;
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
/**
|
|
* Finalizes the config by replacing plugin references with their objects
|
|
* and validating rule option schemas.
|
|
* @param {Object} config The config to finalize.
|
|
* @returns {Object} The finalized config.
|
|
* @throws {TypeError} If the config is invalid.
|
|
*/
|
|
[ConfigArraySymbol.finalizeConfig](config) {
|
|
|
|
const { plugins, languageOptions, processor } = config;
|
|
let parserName, processorName;
|
|
let invalidParser = false,
|
|
invalidProcessor = false;
|
|
|
|
// Check parser value
|
|
if (languageOptions && languageOptions.parser) {
|
|
const { parser } = languageOptions;
|
|
|
|
if (typeof parser === "object") {
|
|
parserName = getObjectId(parser);
|
|
|
|
if (!parserName) {
|
|
invalidParser = true;
|
|
}
|
|
|
|
} else {
|
|
invalidParser = true;
|
|
}
|
|
}
|
|
|
|
// Check processor value
|
|
if (processor) {
|
|
if (typeof processor === "string") {
|
|
const { pluginName, objectName: localProcessorName } = splitPluginIdentifier(processor);
|
|
|
|
processorName = processor;
|
|
|
|
if (!plugins || !plugins[pluginName] || !plugins[pluginName].processors || !plugins[pluginName].processors[localProcessorName]) {
|
|
throw new TypeError(`Key "processor": Could not find "${localProcessorName}" in plugin "${pluginName}".`);
|
|
}
|
|
|
|
config.processor = plugins[pluginName].processors[localProcessorName];
|
|
} else if (typeof processor === "object") {
|
|
processorName = getObjectId(processor);
|
|
|
|
if (!processorName) {
|
|
invalidProcessor = true;
|
|
}
|
|
|
|
} else {
|
|
invalidProcessor = true;
|
|
}
|
|
}
|
|
|
|
ruleValidator.validate(config);
|
|
|
|
// apply special logic for serialization into JSON
|
|
/* eslint-disable object-shorthand -- shorthand would change "this" value */
|
|
Object.defineProperty(config, "toJSON", {
|
|
value: function() {
|
|
|
|
if (invalidParser) {
|
|
throw new Error("Could not serialize parser object (missing 'meta' object).");
|
|
}
|
|
|
|
if (invalidProcessor) {
|
|
throw new Error("Could not serialize processor object (missing 'meta' object).");
|
|
}
|
|
|
|
return {
|
|
...this,
|
|
plugins: Object.entries(plugins).map(([namespace, plugin]) => {
|
|
|
|
const pluginId = getObjectId(plugin);
|
|
|
|
if (!pluginId) {
|
|
return namespace;
|
|
}
|
|
|
|
return `${namespace}:${pluginId}`;
|
|
}),
|
|
languageOptions: {
|
|
...languageOptions,
|
|
parser: parserName
|
|
},
|
|
processor: processorName
|
|
};
|
|
}
|
|
});
|
|
/* eslint-enable object-shorthand -- ok to enable now */
|
|
|
|
return config;
|
|
}
|
|
/* eslint-enable class-methods-use-this -- Desired as instance method */
|
|
|
|
}
|
|
|
|
exports.FlatConfigArray = FlatConfigArray;
|