.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / @eslint / eslintrc / lib / flat-compat.js
1 /**
2  * @fileoverview Compatibility class for flat config.
3  * @author Nicholas C. Zakas
4  */
5
6 "use strict";
7
8 //-----------------------------------------------------------------------------
9 // Requirements
10 //-----------------------------------------------------------------------------
11
12 const path = require("path");
13 const environments = require("../conf/environments");
14 const createDebug = require("debug");
15 const { ConfigArrayFactory } = require("./config-array-factory");
16
17 //-----------------------------------------------------------------------------
18 // Helpers
19 //-----------------------------------------------------------------------------
20
21 /** @typedef {import("../../shared/types").Environment} Environment */
22 /** @typedef {import("../../shared/types").Processor} Processor */
23
24 const debug = createDebug("eslintrc:flat-compat");
25 const cafactory = Symbol("cafactory");
26
27 /**
28  * Translates an ESLintRC-style config object into a flag-config-style config
29  * object.
30  * @param {Object} eslintrcConfig An ESLintRC-style config object.
31  * @param {Object} options Options to help translate the config.
32  * @param {string} options.resolveConfigRelativeTo To the directory to resolve
33  *      configs from.
34  * @param {string} options.resolvePluginsRelativeTo The directory to resolve
35  *      plugins from.
36  * @param {ReadOnlyMap<string,Environment>} options.pluginEnvironments A map of plugin environment
37  *      names to objects.
38  * @param {ReadOnlyMap<string,Processor>} options.pluginProcessors A map of plugin processor
39  *      names to objects.
40  * @returns {Object} A flag-config-style config object.
41  */
42 function translateESLintRC(eslintrcConfig, {
43     resolveConfigRelativeTo,
44     resolvePluginsRelativeTo,
45     pluginEnvironments,
46     pluginProcessors
47 }) {
48
49     const flatConfig = {};
50     const configs = [];
51     const languageOptions = {};
52     const linterOptions = {};
53     const keysToCopy = ["settings", "rules", "processor"];
54     const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
55     const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"];
56
57     // check for special settings for eslint:all and eslint:recommended:
58     if (eslintrcConfig.settings) {
59         if (eslintrcConfig.settings["eslint:all"] === true) {
60             return ["eslint:all"];
61         }
62
63         if (eslintrcConfig.settings["eslint:recommended"] === true) {
64             return ["eslint:recommended"];
65         }
66     }
67
68     // copy over simple translations
69     for (const key of keysToCopy) {
70         if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
71             flatConfig[key] = eslintrcConfig[key];
72         }
73     }
74
75     // copy over languageOptions
76     for (const key of languageOptionsKeysToCopy) {
77         if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
78
79             // create the languageOptions key in the flat config
80             flatConfig.languageOptions = languageOptions;
81
82             if (key === "parser") {
83                 debug(`Resolving parser '${languageOptions[key]}' relative to ${resolveConfigRelativeTo}`);
84
85                 if (eslintrcConfig[key].error) {
86                     throw eslintrcConfig[key].error;
87                 }
88
89                 languageOptions[key] = eslintrcConfig[key].definition;
90                 continue;
91             }
92
93             // clone any object values that are in the eslintrc config
94             if (eslintrcConfig[key] && typeof eslintrcConfig[key] === "object") {
95                 languageOptions[key] = {
96                     ...eslintrcConfig[key]
97                 };
98             } else {
99                 languageOptions[key] = eslintrcConfig[key];
100             }
101         }
102     }
103
104     // copy over linterOptions
105     for (const key of linterOptionsKeysToCopy) {
106         if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
107             flatConfig.linterOptions = linterOptions;
108             linterOptions[key] = eslintrcConfig[key];
109         }
110     }
111
112     // move ecmaVersion a level up
113     if (languageOptions.parserOptions) {
114
115         if ("ecmaVersion" in languageOptions.parserOptions) {
116             languageOptions.ecmaVersion = languageOptions.parserOptions.ecmaVersion;
117             delete languageOptions.parserOptions.ecmaVersion;
118         }
119
120         if ("sourceType" in languageOptions.parserOptions) {
121             languageOptions.sourceType = languageOptions.parserOptions.sourceType;
122             delete languageOptions.parserOptions.sourceType;
123         }
124
125         // check to see if we even need parserOptions anymore and remove it if not
126         if (Object.keys(languageOptions.parserOptions).length === 0) {
127             delete languageOptions.parserOptions;
128         }
129     }
130
131     // overrides
132     if (eslintrcConfig.criteria) {
133         flatConfig.files = [absoluteFilePath => eslintrcConfig.criteria.test(absoluteFilePath)];
134     }
135
136     // translate plugins
137     if (eslintrcConfig.plugins && typeof eslintrcConfig.plugins === "object") {
138         debug(`Translating plugins: ${eslintrcConfig.plugins}`);
139
140         flatConfig.plugins = {};
141
142         for (const pluginName of Object.keys(eslintrcConfig.plugins)) {
143
144             debug(`Translating plugin: ${pluginName}`);
145             debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
146
147             const { definition: plugin, error } = eslintrcConfig.plugins[pluginName];
148
149             if (error) {
150                 throw error;
151             }
152
153             flatConfig.plugins[pluginName] = plugin;
154
155             // create a config for any processors
156             if (plugin.processors) {
157                 for (const processorName of Object.keys(plugin.processors)) {
158                     if (processorName.startsWith(".")) {
159                         debug(`Assigning processor: ${pluginName}/${processorName}`);
160
161                         configs.unshift({
162                             files: [`**/*${processorName}`],
163                             processor: pluginProcessors.get(`${pluginName}/${processorName}`)
164                         });
165                     }
166
167                 }
168             }
169         }
170     }
171
172     // translate env - must come after plugins
173     if (eslintrcConfig.env && typeof eslintrcConfig.env === "object") {
174         for (const envName of Object.keys(eslintrcConfig.env)) {
175
176             // only add environments that are true
177             if (eslintrcConfig.env[envName]) {
178                 debug(`Translating environment: ${envName}`);
179
180                 if (environments.has(envName)) {
181
182                     // built-in environments should be defined first
183                     configs.unshift(...translateESLintRC(environments.get(envName), {
184                         resolveConfigRelativeTo,
185                         resolvePluginsRelativeTo
186                     }));
187                 } else if (pluginEnvironments.has(envName)) {
188
189                     // if the environment comes from a plugin, it should come after the plugin config
190                     configs.push(...translateESLintRC(pluginEnvironments.get(envName), {
191                         resolveConfigRelativeTo,
192                         resolvePluginsRelativeTo
193                     }));
194                 }
195             }
196         }
197     }
198
199     // only add if there are actually keys in the config
200     if (Object.keys(flatConfig).length > 0) {
201         configs.push(flatConfig);
202     }
203
204     return configs;
205 }
206
207
208 //-----------------------------------------------------------------------------
209 // Exports
210 //-----------------------------------------------------------------------------
211
212 /**
213  * A compatibility class for working with configs.
214  */
215 class FlatCompat {
216
217     constructor({
218         baseDirectory = process.cwd(),
219         resolvePluginsRelativeTo = baseDirectory
220     } = {}) {
221         this.baseDirectory = baseDirectory;
222         this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
223         this[cafactory] = new ConfigArrayFactory({
224             cwd: baseDirectory,
225             resolvePluginsRelativeTo,
226             eslintAllPath: path.resolve(__dirname, "../conf/eslint-all.js"),
227             eslintRecommendedPath: path.resolve(__dirname, "../conf/eslint-recommended.js")
228         });
229     }
230
231     /**
232      * Translates an ESLintRC-style config into a flag-config-style config.
233      * @param {Object} eslintrcConfig The ESLintRC-style config object.
234      * @returns {Object} A flag-config-style config object.
235      */
236     config(eslintrcConfig) {
237         const eslintrcArray = this[cafactory].create(eslintrcConfig, {
238             basePath: this.baseDirectory
239         });
240
241         const flatArray = [];
242         let hasIgnorePatterns = false;
243
244         eslintrcArray.forEach(configData => {
245             if (configData.type === "config") {
246                 hasIgnorePatterns = hasIgnorePatterns || configData.ignorePattern;
247                 flatArray.push(...translateESLintRC(configData, {
248                     resolveConfigRelativeTo: path.join(this.baseDirectory, "__placeholder.js"),
249                     resolvePluginsRelativeTo: path.join(this.resolvePluginsRelativeTo, "__placeholder.js"),
250                     pluginEnvironments: eslintrcArray.pluginEnvironments,
251                     pluginProcessors: eslintrcArray.pluginProcessors
252                 }));
253             }
254         });
255
256         // combine ignorePatterns to emulate ESLintRC behavior better
257         if (hasIgnorePatterns) {
258             flatArray.unshift({
259                 ignores: [filePath => {
260
261                     // Compute the final config for this file.
262                     // This filters config array elements by `files`/`excludedFiles` then merges the elements.
263                     const finalConfig = eslintrcArray.extractConfig(filePath);
264
265                     // Test the `ignorePattern` properties of the final config.
266                     return Boolean(finalConfig.ignores) && finalConfig.ignores(filePath);
267                 }]
268             });
269         }
270
271         return flatArray;
272     }
273
274     /**
275      * Translates the `env` section of an ESLintRC-style config.
276      * @param {Object} envConfig The `env` section of an ESLintRC config.
277      * @returns {Object} A flag-config object representing the environments.
278      */
279     env(envConfig) {
280         return this.config({
281             env: envConfig
282         });
283     }
284
285     /**
286      * Translates the `extends` section of an ESLintRC-style config.
287      * @param {...string} configsToExtend The names of the configs to load.
288      * @returns {Object} A flag-config object representing the config.
289      */
290     extends(...configsToExtend) {
291         return this.config({
292             extends: configsToExtend
293         });
294     }
295
296     /**
297      * Translates the `plugins` section of an ESLintRC-style config.
298      * @param {...string} plugins The names of the plugins to load.
299      * @returns {Object} A flag-config object representing the plugins.
300      */
301     plugins(...plugins) {
302         return this.config({
303             plugins
304         });
305     }
306 }
307
308 exports.FlatCompat = FlatCompat;