123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- /**
- * @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"];
- // check for special settings for eslint:all and eslint:recommended:
- if (eslintrcConfig.settings) {
- if (eslintrcConfig.settings["eslint:all"] === true) {
- return ["eslint:all"];
- }
- if (eslintrcConfig.settings["eslint:recommended"] === true) {
- return ["eslint:recommended"];
- }
- }
- // 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(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(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
- } = {}) {
- this.baseDirectory = baseDirectory;
- this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
- this[cafactory] = new ConfigArrayFactory({
- cwd: baseDirectory,
- resolvePluginsRelativeTo,
- getEslintAllConfig: () => ({ settings: { "eslint:all": true } }),
- getEslintRecommendedConfig: () => ({ settings: { "eslint:recommended": true } })
- });
- }
- /**
- * 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} A flag-config object 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} A flag-config object 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} A flag-config object representing the plugins.
- */
- plugins(...plugins) {
- return this.config({
- plugins
- });
- }
- }
- export { FlatCompat };
|