source: imaps-frontend/node_modules/eslint/lib/config/flat-config-array.js@ 0c6b92a

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

  • Property mode set to 100644
File size: 12.1 KB
Line 
1/**
2 * @fileoverview Flat Config Array
3 * @author Nicholas C. Zakas
4 */
5
6"use strict";
7
8//-----------------------------------------------------------------------------
9// Requirements
10//-----------------------------------------------------------------------------
11
12const { ConfigArray, ConfigArraySymbol } = require("@humanwhocodes/config-array");
13const { flatConfigSchema } = require("./flat-config-schema");
14const { RuleValidator } = require("./rule-validator");
15const { defaultConfig } = require("./default-config");
16const jsPlugin = require("@eslint/js");
17
18//-----------------------------------------------------------------------------
19// Helpers
20//-----------------------------------------------------------------------------
21
22/**
23 * Fields that are considered metadata and not part of the config object.
24 */
25const META_FIELDS = new Set(["name"]);
26
27const ruleValidator = new RuleValidator();
28
29/**
30 * Splits a plugin identifier in the form a/b/c into two parts: a/b and c.
31 * @param {string} identifier The identifier to parse.
32 * @returns {{objectName: string, pluginName: string}} The parts of the plugin
33 * name.
34 */
35function splitPluginIdentifier(identifier) {
36 const parts = identifier.split("/");
37
38 return {
39 objectName: parts.pop(),
40 pluginName: parts.join("/")
41 };
42}
43
44/**
45 * Returns the name of an object in the config by reading its `meta` key.
46 * @param {Object} object The object to check.
47 * @returns {string?} The name of the object if found or `null` if there
48 * is no name.
49 */
50function getObjectId(object) {
51
52 // first check old-style name
53 let name = object.name;
54
55 if (!name) {
56
57 if (!object.meta) {
58 return null;
59 }
60
61 name = object.meta.name;
62
63 if (!name) {
64 return null;
65 }
66 }
67
68 // now check for old-style version
69 let version = object.version;
70
71 if (!version) {
72 version = object.meta && object.meta.version;
73 }
74
75 // if there's a version then append that
76 if (version) {
77 return `${name}@${version}`;
78 }
79
80 return name;
81}
82
83/**
84 * Wraps a config error with details about where the error occurred.
85 * @param {Error} error The original error.
86 * @param {number} originalLength The original length of the config array.
87 * @param {number} baseLength The length of the base config.
88 * @returns {TypeError} The new error with details.
89 */
90function wrapConfigErrorWithDetails(error, originalLength, baseLength) {
91
92 let location = "user-defined";
93 let configIndex = error.index;
94
95 /*
96 * A config array is set up in this order:
97 * 1. Base config
98 * 2. Original configs
99 * 3. User-defined configs
100 * 4. CLI-defined configs
101 *
102 * So we need to adjust the index to account for the base config.
103 *
104 * - If the index is less than the base length, it's in the base config
105 * (as specified by `baseConfig` argument to `FlatConfigArray` constructor).
106 * - If the index is greater than the base length but less than the original
107 * length + base length, it's in the original config. The original config
108 * is passed to the `FlatConfigArray` constructor as the first argument.
109 * - Otherwise, it's in the user-defined config, which is loaded from the
110 * config file and merged with any command-line options.
111 */
112 if (error.index < baseLength) {
113 location = "base";
114 } else if (error.index < originalLength + baseLength) {
115 location = "original";
116 configIndex = error.index - baseLength;
117 } else {
118 configIndex = error.index - originalLength - baseLength;
119 }
120
121 return new TypeError(
122 `${error.message.slice(0, -1)} at ${location} index ${configIndex}.`,
123 { cause: error }
124 );
125}
126
127const originalBaseConfig = Symbol("originalBaseConfig");
128const originalLength = Symbol("originalLength");
129const baseLength = Symbol("baseLength");
130
131//-----------------------------------------------------------------------------
132// Exports
133//-----------------------------------------------------------------------------
134
135/**
136 * Represents an array containing configuration information for ESLint.
137 */
138class FlatConfigArray extends ConfigArray {
139
140 /**
141 * Creates a new instance.
142 * @param {*[]} configs An array of configuration information.
143 * @param {{basePath: string, shouldIgnore: boolean, baseConfig: FlatConfig}} options The options
144 * to use for the config array instance.
145 */
146 constructor(configs, {
147 basePath,
148 shouldIgnore = true,
149 baseConfig = defaultConfig
150 } = {}) {
151 super(configs, {
152 basePath,
153 schema: flatConfigSchema
154 });
155
156 /**
157 * The original length of the array before any modifications.
158 * @type {number}
159 */
160 this[originalLength] = this.length;
161
162 if (baseConfig[Symbol.iterator]) {
163 this.unshift(...baseConfig);
164 } else {
165 this.unshift(baseConfig);
166 }
167
168 /**
169 * The length of the array after applying the base config.
170 * @type {number}
171 */
172 this[baseLength] = this.length - this[originalLength];
173
174 /**
175 * The base config used to build the config array.
176 * @type {Array<FlatConfig>}
177 */
178 this[originalBaseConfig] = baseConfig;
179 Object.defineProperty(this, originalBaseConfig, { writable: false });
180
181 /**
182 * Determines if `ignores` fields should be honored.
183 * If true, then all `ignores` fields are honored.
184 * if false, then only `ignores` fields in the baseConfig are honored.
185 * @type {boolean}
186 */
187 this.shouldIgnore = shouldIgnore;
188 Object.defineProperty(this, "shouldIgnore", { writable: false });
189 }
190
191 /**
192 * Normalizes the array by calling the superclass method and catching/rethrowing
193 * any ConfigError exceptions with additional details.
194 * @param {any} [context] The context to use to normalize the array.
195 * @returns {Promise<FlatConfigArray>} A promise that resolves when the array is normalized.
196 */
197 normalize(context) {
198 return super.normalize(context)
199 .catch(error => {
200 if (error.name === "ConfigError") {
201 throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
202 }
203
204 throw error;
205
206 });
207 }
208
209 /**
210 * Normalizes the array by calling the superclass method and catching/rethrowing
211 * any ConfigError exceptions with additional details.
212 * @param {any} [context] The context to use to normalize the array.
213 * @returns {FlatConfigArray} The current instance.
214 * @throws {TypeError} If the config is invalid.
215 */
216 normalizeSync(context) {
217
218 try {
219
220 return super.normalizeSync(context);
221
222 } catch (error) {
223
224 if (error.name === "ConfigError") {
225 throw wrapConfigErrorWithDetails(error, this[originalLength], this[baseLength]);
226 }
227
228 throw error;
229
230 }
231
232 }
233
234 /* eslint-disable class-methods-use-this -- Desired as instance method */
235 /**
236 * Replaces a config with another config to allow us to put strings
237 * in the config array that will be replaced by objects before
238 * normalization.
239 * @param {Object} config The config to preprocess.
240 * @returns {Object} The preprocessed config.
241 */
242 [ConfigArraySymbol.preprocessConfig](config) {
243 if (config === "eslint:recommended") {
244
245 // if we are in a Node.js environment warn the user
246 if (typeof process !== "undefined" && process.emitWarning) {
247 process.emitWarning("The 'eslint:recommended' string configuration is deprecated and will be replaced by the @eslint/js package's 'recommended' config.");
248 }
249
250 return jsPlugin.configs.recommended;
251 }
252
253 if (config === "eslint:all") {
254
255 // if we are in a Node.js environment warn the user
256 if (typeof process !== "undefined" && process.emitWarning) {
257 process.emitWarning("The 'eslint:all' string configuration is deprecated and will be replaced by the @eslint/js package's 'all' config.");
258 }
259
260 return jsPlugin.configs.all;
261 }
262
263 /*
264 * If a config object has `ignores` and no other non-meta fields, then it's an object
265 * for global ignores. If `shouldIgnore` is false, that object shouldn't apply,
266 * so we'll remove its `ignores`.
267 */
268 if (
269 !this.shouldIgnore &&
270 !this[originalBaseConfig].includes(config) &&
271 config.ignores &&
272 Object.keys(config).filter(key => !META_FIELDS.has(key)).length === 1
273 ) {
274 /* eslint-disable-next-line no-unused-vars -- need to strip off other keys */
275 const { ignores, ...otherKeys } = config;
276
277 return otherKeys;
278 }
279
280 return config;
281 }
282
283 /**
284 * Finalizes the config by replacing plugin references with their objects
285 * and validating rule option schemas.
286 * @param {Object} config The config to finalize.
287 * @returns {Object} The finalized config.
288 * @throws {TypeError} If the config is invalid.
289 */
290 [ConfigArraySymbol.finalizeConfig](config) {
291
292 const { plugins, languageOptions, processor } = config;
293 let parserName, processorName;
294 let invalidParser = false,
295 invalidProcessor = false;
296
297 // Check parser value
298 if (languageOptions && languageOptions.parser) {
299 const { parser } = languageOptions;
300
301 if (typeof parser === "object") {
302 parserName = getObjectId(parser);
303
304 if (!parserName) {
305 invalidParser = true;
306 }
307
308 } else {
309 invalidParser = true;
310 }
311 }
312
313 // Check processor value
314 if (processor) {
315 if (typeof processor === "string") {
316 const { pluginName, objectName: localProcessorName } = splitPluginIdentifier(processor);
317
318 processorName = processor;
319
320 if (!plugins || !plugins[pluginName] || !plugins[pluginName].processors || !plugins[pluginName].processors[localProcessorName]) {
321 throw new TypeError(`Key "processor": Could not find "${localProcessorName}" in plugin "${pluginName}".`);
322 }
323
324 config.processor = plugins[pluginName].processors[localProcessorName];
325 } else if (typeof processor === "object") {
326 processorName = getObjectId(processor);
327
328 if (!processorName) {
329 invalidProcessor = true;
330 }
331
332 } else {
333 invalidProcessor = true;
334 }
335 }
336
337 ruleValidator.validate(config);
338
339 // apply special logic for serialization into JSON
340 /* eslint-disable object-shorthand -- shorthand would change "this" value */
341 Object.defineProperty(config, "toJSON", {
342 value: function() {
343
344 if (invalidParser) {
345 throw new Error("Could not serialize parser object (missing 'meta' object).");
346 }
347
348 if (invalidProcessor) {
349 throw new Error("Could not serialize processor object (missing 'meta' object).");
350 }
351
352 return {
353 ...this,
354 plugins: Object.entries(plugins).map(([namespace, plugin]) => {
355
356 const pluginId = getObjectId(plugin);
357
358 if (!pluginId) {
359 return namespace;
360 }
361
362 return `${namespace}:${pluginId}`;
363 }),
364 languageOptions: {
365 ...languageOptions,
366 parser: parserName
367 },
368 processor: processorName
369 };
370 }
371 });
372 /* eslint-enable object-shorthand -- ok to enable now */
373
374 return config;
375 }
376 /* eslint-enable class-methods-use-this -- Desired as instance method */
377
378}
379
380exports.FlatConfigArray = FlatConfigArray;
Note: See TracBrowser for help on using the repository browser.