123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- /**
- * @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 recommendedConfig = require("../../conf/eslint-recommended");
- //-----------------------------------------------------------------------------
- // Helpers
- //-----------------------------------------------------------------------------
- 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("/")
- };
- }
- const originalBaseConfig = Symbol("originalBaseConfig");
- //-----------------------------------------------------------------------------
- // 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
- });
- if (baseConfig[Symbol.iterator]) {
- this.unshift(...baseConfig);
- } else {
- this.unshift(baseConfig);
- }
- /**
- * 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 });
- }
- /* 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") {
- return recommendedConfig;
- }
- if (config === "eslint:all") {
- /*
- * Load `eslint-all.js` here instead of at the top level to avoid loading all rule modules
- * when it isn't necessary. `eslint-all.js` reads `meta` of rule objects to filter out deprecated ones,
- * so requiring `eslint-all.js` module loads all rule modules as a consequence.
- */
- return require("../../conf/eslint-all");
- }
- /*
- * If `shouldIgnore` is false, we remove any ignore patterns specified
- * in the config so long as it's not a default config and it doesn't
- * have a `files` entry.
- */
- if (
- !this.shouldIgnore &&
- !this[originalBaseConfig].includes(config) &&
- config.ignores &&
- !config.files
- ) {
- /* 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) {
- if (typeof languageOptions.parser === "string") {
- const { pluginName, objectName: localParserName } = splitPluginIdentifier(languageOptions.parser);
- parserName = languageOptions.parser;
- if (!plugins || !plugins[pluginName] || !plugins[pluginName].parsers || !plugins[pluginName].parsers[localParserName]) {
- throw new TypeError(`Key "parser": Could not find "${localParserName}" in plugin "${pluginName}".`);
- }
- languageOptions.parser = plugins[pluginName].parsers[localParserName];
- } 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 {
- 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("Caching is not supported when parser is an object.");
- }
- if (invalidProcessor) {
- throw new Error("Caching is not supported when processor is an object.");
- }
- return {
- ...this,
- plugins: Object.keys(plugins),
- 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;
|