You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
7.3 KiB
222 lines
7.3 KiB
/** |
|
* @fileoverview Flat Config Array |
|
* @author Nicholas C. Zakas |
|
*/ |
|
|
|
"use strict"; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Requirements |
|
//----------------------------------------------------------------------------- |
|
|
|
const { ConfigArray, ConfigArraySymbol } = require("@eslint/config-array"); |
|
const { flatConfigSchema } = require("./flat-config-schema"); |
|
const { defaultConfig } = require("./default-config"); |
|
const { Config } = require("./config"); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Helpers |
|
//----------------------------------------------------------------------------- |
|
|
|
/** |
|
* Fields that are considered metadata and not part of the config object. |
|
*/ |
|
const META_FIELDS = new Set(["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 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) { |
|
return new Config(config); |
|
} |
|
/* eslint-enable class-methods-use-this -- Desired as instance method */ |
|
|
|
} |
|
|
|
exports.FlatConfigArray = FlatConfigArray;
|
|
|