Permalink
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
codeql-action/node_modules/@eslint/eslintrc/lib/flat-compat.js
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
318 lines (261 sloc)
11 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileoverview Compatibility class for flat config. | |
* @author Nicholas C. Zakas | |
*/ | |
//----------------------------------------------------------------------------- | |
// Requirements | |
//----------------------------------------------------------------------------- | |
import createDebug from "debug"; | |
import path from "path"; | |
import environments from "../conf/environments.js"; | |
import { ConfigArrayFactory } from "./config-array-factory.js"; | |
//----------------------------------------------------------------------------- | |
// Helpers | |
//----------------------------------------------------------------------------- | |
/** @typedef {import("../../shared/types").Environment} Environment */ | |
/** @typedef {import("../../shared/types").Processor} Processor */ | |
const debug = createDebug("eslintrc:flat-compat"); | |
const cafactory = Symbol("cafactory"); | |
/** | |
* Translates an ESLintRC-style config object into a flag-config-style config | |
* object. | |
* @param {Object} eslintrcConfig An ESLintRC-style config object. | |
* @param {Object} options Options to help translate the config. | |
* @param {string} options.resolveConfigRelativeTo To the directory to resolve | |
* configs from. | |
* @param {string} options.resolvePluginsRelativeTo The directory to resolve | |
* plugins from. | |
* @param {ReadOnlyMap<string,Environment>} options.pluginEnvironments A map of plugin environment | |
* names to objects. | |
* @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor | |
* names to objects. | |
* @returns {Object} A flag-config-style config object. | |
*/ | |
function translateESLintRC(eslintrcConfig, { | |
resolveConfigRelativeTo, | |
resolvePluginsRelativeTo, | |
pluginEnvironments, | |
pluginProcessors | |
}) { | |
const flatConfig = {}; | |
const configs = []; | |
const languageOptions = {}; | |
const linterOptions = {}; | |
const keysToCopy = ["settings", "rules", "processor"]; | |
const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"]; | |
const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"]; | |
// copy over simple translations | |
for (const key of keysToCopy) { | |
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") { | |
flatConfig[key] = eslintrcConfig[key]; | |
} | |
} | |
// copy over languageOptions | |
for (const key of languageOptionsKeysToCopy) { | |
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") { | |
// create the languageOptions key in the flat config | |
flatConfig.languageOptions = languageOptions; | |
if (key === "parser") { | |
debug(`Resolving parser '${languageOptions[key]}' relative to ${resolveConfigRelativeTo}`); | |
if (eslintrcConfig[key].error) { | |
throw eslintrcConfig[key].error; | |
} | |
languageOptions[key] = eslintrcConfig[key].definition; | |
continue; | |
} | |
// clone any object values that are in the eslintrc config | |
if (eslintrcConfig[key] && typeof eslintrcConfig[key] === "object") { | |
languageOptions[key] = { | |
...eslintrcConfig[key] | |
}; | |
} else { | |
languageOptions[key] = eslintrcConfig[key]; | |
} | |
} | |
} | |
// copy over linterOptions | |
for (const key of linterOptionsKeysToCopy) { | |
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") { | |
flatConfig.linterOptions = linterOptions; | |
linterOptions[key] = eslintrcConfig[key]; | |
} | |
} | |
// move ecmaVersion a level up | |
if (languageOptions.parserOptions) { | |
if ("ecmaVersion" in languageOptions.parserOptions) { | |
languageOptions.ecmaVersion = languageOptions.parserOptions.ecmaVersion; | |
delete languageOptions.parserOptions.ecmaVersion; | |
} | |
if ("sourceType" in languageOptions.parserOptions) { | |
languageOptions.sourceType = languageOptions.parserOptions.sourceType; | |
delete languageOptions.parserOptions.sourceType; | |
} | |
// check to see if we even need parserOptions anymore and remove it if not | |
if (Object.keys(languageOptions.parserOptions).length === 0) { | |
delete languageOptions.parserOptions; | |
} | |
} | |
// overrides | |
if (eslintrcConfig.criteria) { | |
flatConfig.files = [absoluteFilePath => eslintrcConfig.criteria.test(absoluteFilePath)]; | |
} | |
// translate plugins | |
if (eslintrcConfig.plugins && typeof eslintrcConfig.plugins === "object") { | |
debug(`Translating plugins: ${eslintrcConfig.plugins}`); | |
flatConfig.plugins = {}; | |
for (const pluginName of Object.keys(eslintrcConfig.plugins)) { | |
debug(`Translating plugin: ${pluginName}`); | |
debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`); | |
const { definition: plugin, error } = eslintrcConfig.plugins[pluginName]; | |
if (error) { | |
throw error; | |
} | |
flatConfig.plugins[pluginName] = plugin; | |
// create a config for any processors | |
if (plugin.processors) { | |
for (const processorName of Object.keys(plugin.processors)) { | |
if (processorName.startsWith(".")) { | |
debug(`Assigning processor: ${pluginName}/${processorName}`); | |
configs.unshift({ | |
files: [`**/*${processorName}`], | |
processor: pluginProcessors.get(`${pluginName}/${processorName}`) | |
}); | |
} | |
} | |
} | |
} | |
} | |
// translate env - must come after plugins | |
if (eslintrcConfig.env && typeof eslintrcConfig.env === "object") { | |
for (const envName of Object.keys(eslintrcConfig.env)) { | |
// only add environments that are true | |
if (eslintrcConfig.env[envName]) { | |
debug(`Translating environment: ${envName}`); | |
if (environments.has(envName)) { | |
// built-in environments should be defined first | |
configs.unshift(...translateESLintRC({ | |
criteria: eslintrcConfig.criteria, | |
...environments.get(envName) | |
}, { | |
resolveConfigRelativeTo, | |
resolvePluginsRelativeTo | |
})); | |
} else if (pluginEnvironments.has(envName)) { | |
// if the environment comes from a plugin, it should come after the plugin config | |
configs.push(...translateESLintRC({ | |
criteria: eslintrcConfig.criteria, | |
...pluginEnvironments.get(envName) | |
}, { | |
resolveConfigRelativeTo, | |
resolvePluginsRelativeTo | |
})); | |
} | |
} | |
} | |
} | |
// only add if there are actually keys in the config | |
if (Object.keys(flatConfig).length > 0) { | |
configs.push(flatConfig); | |
} | |
return configs; | |
} | |
//----------------------------------------------------------------------------- | |
// Exports | |
//----------------------------------------------------------------------------- | |
/** | |
* A compatibility class for working with configs. | |
*/ | |
class FlatCompat { | |
constructor({ | |
baseDirectory = process.cwd(), | |
resolvePluginsRelativeTo = baseDirectory, | |
recommendedConfig, | |
allConfig | |
} = {}) { | |
this.baseDirectory = baseDirectory; | |
this.resolvePluginsRelativeTo = resolvePluginsRelativeTo; | |
this[cafactory] = new ConfigArrayFactory({ | |
cwd: baseDirectory, | |
resolvePluginsRelativeTo, | |
getEslintAllConfig: () => { | |
if (!allConfig) { | |
throw new TypeError("Missing parameter 'allConfig' in FlatCompat constructor."); | |
} | |
return allConfig; | |
}, | |
getEslintRecommendedConfig: () => { | |
if (!recommendedConfig) { | |
throw new TypeError("Missing parameter 'recommendedConfig' in FlatCompat constructor."); | |
} | |
return recommendedConfig; | |
} | |
}); | |
} | |
/** | |
* Translates an ESLintRC-style config into a flag-config-style config. | |
* @param {Object} eslintrcConfig The ESLintRC-style config object. | |
* @returns {Object} A flag-config-style config object. | |
*/ | |
config(eslintrcConfig) { | |
const eslintrcArray = this[cafactory].create(eslintrcConfig, { | |
basePath: this.baseDirectory | |
}); | |
const flatArray = []; | |
let hasIgnorePatterns = false; | |
eslintrcArray.forEach(configData => { | |
if (configData.type === "config") { | |
hasIgnorePatterns = hasIgnorePatterns || configData.ignorePattern; | |
flatArray.push(...translateESLintRC(configData, { | |
resolveConfigRelativeTo: path.join(this.baseDirectory, "__placeholder.js"), | |
resolvePluginsRelativeTo: path.join(this.resolvePluginsRelativeTo, "__placeholder.js"), | |
pluginEnvironments: eslintrcArray.pluginEnvironments, | |
pluginProcessors: eslintrcArray.pluginProcessors | |
})); | |
} | |
}); | |
// combine ignorePatterns to emulate ESLintRC behavior better | |
if (hasIgnorePatterns) { | |
flatArray.unshift({ | |
ignores: [filePath => { | |
// Compute the final config for this file. | |
// This filters config array elements by `files`/`excludedFiles` then merges the elements. | |
const finalConfig = eslintrcArray.extractConfig(filePath); | |
// Test the `ignorePattern` properties of the final config. | |
return Boolean(finalConfig.ignores) && finalConfig.ignores(filePath); | |
}] | |
}); | |
} | |
return flatArray; | |
} | |
/** | |
* Translates the `env` section of an ESLintRC-style config. | |
* @param {Object} envConfig The `env` section of an ESLintRC config. | |
* @returns {Object[]} An array of flag-config objects representing the environments. | |
*/ | |
env(envConfig) { | |
return this.config({ | |
env: envConfig | |
}); | |
} | |
/** | |
* Translates the `extends` section of an ESLintRC-style config. | |
* @param {...string} configsToExtend The names of the configs to load. | |
* @returns {Object[]} An array of flag-config objects representing the config. | |
*/ | |
extends(...configsToExtend) { | |
return this.config({ | |
extends: configsToExtend | |
}); | |
} | |
/** | |
* Translates the `plugins` section of an ESLintRC-style config. | |
* @param {...string} plugins The names of the plugins to load. | |
* @returns {Object[]} An array of flag-config objects representing the plugins. | |
*/ | |
plugins(...plugins) { | |
return this.config({ | |
plugins | |
}); | |
} | |
} | |
export { FlatCompat }; |