eslint 8.5.0 → 8.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,351 +0,0 @@
1
- /**
2
- * @fileoverview Used for creating a suggested configuration based on project code.
3
- * @author Ian VanSchooten
4
- */
5
-
6
- "use strict";
7
-
8
- //------------------------------------------------------------------------------
9
- // Requirements
10
- //------------------------------------------------------------------------------
11
-
12
- const equal = require("fast-deep-equal"),
13
- recConfig = require("../../conf/eslint-recommended"),
14
- {
15
- Legacy: {
16
- ConfigOps
17
- }
18
- } = require("@eslint/eslintrc"),
19
- { Linter } = require("../linter"),
20
- configRule = require("./config-rule");
21
-
22
- const debug = require("debug")("eslint:autoconfig");
23
- const linter = new Linter();
24
-
25
- //------------------------------------------------------------------------------
26
- // Data
27
- //------------------------------------------------------------------------------
28
-
29
- const MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only
30
- RECOMMENDED_CONFIG_NAME = "eslint:recommended";
31
-
32
- //------------------------------------------------------------------------------
33
- // Private
34
- //------------------------------------------------------------------------------
35
-
36
- /**
37
- * Information about a rule configuration, in the context of a Registry.
38
- * @typedef {Object} registryItem
39
- * @property {ruleConfig} config A valid configuration for the rule
40
- * @property {number} specificity The number of elements in the ruleConfig array
41
- * @property {number} errorCount The number of errors encountered when linting with the config
42
- */
43
-
44
- /**
45
- * This callback is used to measure execution status in a progress bar
46
- * @callback progressCallback
47
- * @param {number} The total number of times the callback will be called.
48
- */
49
-
50
- /**
51
- * Create registryItems for rules
52
- * @param {rulesConfig} rulesConfig Hash of rule names and arrays of ruleConfig items
53
- * @returns {Object} registryItems for each rule in provided rulesConfig
54
- */
55
- function makeRegistryItems(rulesConfig) {
56
- return Object.keys(rulesConfig).reduce((accumulator, ruleId) => {
57
- accumulator[ruleId] = rulesConfig[ruleId].map(config => ({
58
- config,
59
- specificity: config.length || 1,
60
- errorCount: void 0
61
- }));
62
- return accumulator;
63
- }, {});
64
- }
65
-
66
- /**
67
- * Creates an object in which to store rule configs and error counts
68
- *
69
- * Unless a rulesConfig is provided at construction, the registry will not contain
70
- * any rules, only methods. This will be useful for building up registries manually.
71
- *
72
- * Registry class
73
- */
74
- class Registry {
75
-
76
- /**
77
- * @param {rulesConfig} [rulesConfig] Hash of rule names and arrays of possible configurations
78
- */
79
- constructor(rulesConfig) {
80
- this.rules = (rulesConfig) ? makeRegistryItems(rulesConfig) : {};
81
- }
82
-
83
- /**
84
- * Populate the registry with core rule configs.
85
- *
86
- * It will set the registry's `rule` property to an object having rule names
87
- * as keys and an array of registryItems as values.
88
- * @returns {void}
89
- */
90
- populateFromCoreRules() {
91
- const rulesConfig = configRule.createCoreRuleConfigs(/* noDeprecated = */ true);
92
-
93
- this.rules = makeRegistryItems(rulesConfig);
94
- }
95
-
96
- /**
97
- * Creates sets of rule configurations which can be used for linting
98
- * and initializes registry errors to zero for those configurations (side effect).
99
- *
100
- * This combines as many rules together as possible, such that the first sets
101
- * in the array will have the highest number of rules configured, and later sets
102
- * will have fewer and fewer, as not all rules have the same number of possible
103
- * configurations.
104
- *
105
- * The length of the returned array will be <= MAX_CONFIG_COMBINATIONS.
106
- * @returns {Object[]} "rules" configurations to use for linting
107
- */
108
- buildRuleSets() {
109
- let idx = 0;
110
- const ruleIds = Object.keys(this.rules),
111
- ruleSets = [];
112
-
113
- /**
114
- * Add a rule configuration from the registry to the ruleSets
115
- *
116
- * This is broken out into its own function so that it doesn't need to be
117
- * created inside of the while loop.
118
- * @param {string} rule The ruleId to add.
119
- * @returns {void}
120
- */
121
- const addRuleToRuleSet = function(rule) {
122
-
123
- /*
124
- * This check ensures that there is a rule configuration and that
125
- * it has fewer than the max combinations allowed.
126
- * If it has too many configs, we will only use the most basic of
127
- * the possible configurations.
128
- */
129
- const hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS);
130
-
131
- if (this.rules[rule][idx] && (hasFewCombos || this.rules[rule][idx].specificity <= 2)) {
132
-
133
- /*
134
- * If the rule has too many possible combinations, only take
135
- * simple ones, avoiding objects.
136
- */
137
- if (!hasFewCombos && typeof this.rules[rule][idx].config[1] === "object") {
138
- return;
139
- }
140
-
141
- ruleSets[idx] = ruleSets[idx] || {};
142
- ruleSets[idx][rule] = this.rules[rule][idx].config;
143
-
144
- /*
145
- * Initialize errorCount to zero, since this is a config which
146
- * will be linted.
147
- */
148
- this.rules[rule][idx].errorCount = 0;
149
- }
150
- }.bind(this);
151
-
152
- while (ruleSets.length === idx) {
153
- ruleIds.forEach(addRuleToRuleSet);
154
- idx += 1;
155
- }
156
-
157
- return ruleSets;
158
- }
159
-
160
- /**
161
- * Remove all items from the registry with a non-zero number of errors
162
- *
163
- * Note: this also removes rule configurations which were not linted
164
- * (meaning, they have an undefined errorCount).
165
- * @returns {void}
166
- */
167
- stripFailingConfigs() {
168
- const ruleIds = Object.keys(this.rules),
169
- newRegistry = new Registry();
170
-
171
- newRegistry.rules = Object.assign({}, this.rules);
172
- ruleIds.forEach(ruleId => {
173
- const errorFreeItems = newRegistry.rules[ruleId].filter(registryItem => (registryItem.errorCount === 0));
174
-
175
- if (errorFreeItems.length > 0) {
176
- newRegistry.rules[ruleId] = errorFreeItems;
177
- } else {
178
- delete newRegistry.rules[ruleId];
179
- }
180
- });
181
-
182
- return newRegistry;
183
- }
184
-
185
- /**
186
- * Removes rule configurations which were not included in a ruleSet
187
- * @returns {void}
188
- */
189
- stripExtraConfigs() {
190
- const ruleIds = Object.keys(this.rules),
191
- newRegistry = new Registry();
192
-
193
- newRegistry.rules = Object.assign({}, this.rules);
194
- ruleIds.forEach(ruleId => {
195
- newRegistry.rules[ruleId] = newRegistry.rules[ruleId].filter(registryItem => (typeof registryItem.errorCount !== "undefined"));
196
- });
197
-
198
- return newRegistry;
199
- }
200
-
201
- /**
202
- * Creates a registry of rules which had no error-free configs.
203
- * The new registry is intended to be analyzed to determine whether its rules
204
- * should be disabled or set to warning.
205
- * @returns {Registry} A registry of failing rules.
206
- */
207
- getFailingRulesRegistry() {
208
- const ruleIds = Object.keys(this.rules),
209
- failingRegistry = new Registry();
210
-
211
- ruleIds.forEach(ruleId => {
212
- const failingConfigs = this.rules[ruleId].filter(registryItem => (registryItem.errorCount > 0));
213
-
214
- if (failingConfigs && failingConfigs.length === this.rules[ruleId].length) {
215
- failingRegistry.rules[ruleId] = failingConfigs;
216
- }
217
- });
218
-
219
- return failingRegistry;
220
- }
221
-
222
- /**
223
- * Create an eslint config for any rules which only have one configuration
224
- * in the registry.
225
- * @returns {Object} An eslint config with rules section populated
226
- */
227
- createConfig() {
228
- const ruleIds = Object.keys(this.rules),
229
- config = { rules: {} };
230
-
231
- ruleIds.forEach(ruleId => {
232
- if (this.rules[ruleId].length === 1) {
233
- config.rules[ruleId] = this.rules[ruleId][0].config;
234
- }
235
- });
236
-
237
- return config;
238
- }
239
-
240
- /**
241
- * Return a cloned registry containing only configs with a desired specificity
242
- * @param {number} specificity Only keep configs with this specificity
243
- * @returns {Registry} A registry of rules
244
- */
245
- filterBySpecificity(specificity) {
246
- const ruleIds = Object.keys(this.rules),
247
- newRegistry = new Registry();
248
-
249
- newRegistry.rules = Object.assign({}, this.rules);
250
- ruleIds.forEach(ruleId => {
251
- newRegistry.rules[ruleId] = this.rules[ruleId].filter(registryItem => (registryItem.specificity === specificity));
252
- });
253
-
254
- return newRegistry;
255
- }
256
-
257
- /**
258
- * Lint SourceCodes against all configurations in the registry, and record results
259
- * @param {Object[]} sourceCodes SourceCode objects for each filename
260
- * @param {Object} config ESLint config object
261
- * @param {progressCallback} [cb] Optional callback for reporting execution status
262
- * @returns {Registry} New registry with errorCount populated
263
- */
264
- lintSourceCode(sourceCodes, config, cb) {
265
- let lintedRegistry = new Registry();
266
-
267
- lintedRegistry.rules = Object.assign({}, this.rules);
268
-
269
- const ruleSets = lintedRegistry.buildRuleSets();
270
-
271
- lintedRegistry = lintedRegistry.stripExtraConfigs();
272
-
273
- debug("Linting with all possible rule combinations");
274
-
275
- const filenames = Object.keys(sourceCodes);
276
- const totalFilesLinting = filenames.length * ruleSets.length;
277
-
278
- filenames.forEach(filename => {
279
- debug(`Linting file: ${filename}`);
280
-
281
- let ruleSetIdx = 0;
282
-
283
- ruleSets.forEach(ruleSet => {
284
- const lintConfig = Object.assign({}, config, { rules: ruleSet });
285
- const lintResults = linter.verify(sourceCodes[filename], lintConfig);
286
-
287
- lintResults.forEach(result => {
288
-
289
- /*
290
- * It is possible that the error is from a configuration comment
291
- * in a linted file, in which case there may not be a config
292
- * set in this ruleSetIdx.
293
- * (https://github.com/eslint/eslint/issues/5992)
294
- * (https://github.com/eslint/eslint/issues/7860)
295
- */
296
- if (
297
- lintedRegistry.rules[result.ruleId] &&
298
- lintedRegistry.rules[result.ruleId][ruleSetIdx]
299
- ) {
300
- lintedRegistry.rules[result.ruleId][ruleSetIdx].errorCount += 1;
301
- }
302
- });
303
-
304
- ruleSetIdx += 1;
305
-
306
- if (cb) {
307
- cb(totalFilesLinting); // eslint-disable-line node/callback-return -- End of function
308
- }
309
- });
310
-
311
- // Deallocate for GC
312
- sourceCodes[filename] = null;
313
- });
314
-
315
- return lintedRegistry;
316
- }
317
- }
318
-
319
- /**
320
- * Extract rule configuration into eslint:recommended where possible.
321
- *
322
- * This will return a new config with `["extends": [ ..., "eslint:recommended"]` and
323
- * only the rules which have configurations different from the recommended config.
324
- * @param {Object} config config object
325
- * @returns {Object} config object using `"extends": ["eslint:recommended"]`
326
- */
327
- function extendFromRecommended(config) {
328
- const newConfig = Object.assign({}, config);
329
-
330
- ConfigOps.normalizeToStrings(newConfig);
331
-
332
- const recRules = Object.keys(recConfig.rules).filter(ruleId => ConfigOps.isErrorSeverity(recConfig.rules[ruleId]));
333
-
334
- recRules.forEach(ruleId => {
335
- if (equal(recConfig.rules[ruleId], newConfig.rules[ruleId])) {
336
- delete newConfig.rules[ruleId];
337
- }
338
- });
339
- newConfig.extends.unshift(RECOMMENDED_CONFIG_NAME);
340
- return newConfig;
341
- }
342
-
343
-
344
- //------------------------------------------------------------------------------
345
- // Public Interface
346
- //------------------------------------------------------------------------------
347
-
348
- module.exports = {
349
- Registry,
350
- extendFromRecommended
351
- };
@@ -1,144 +0,0 @@
1
- /**
2
- * @fileoverview Helper to locate and load configuration files.
3
- * @author Nicholas C. Zakas
4
- */
5
-
6
- "use strict";
7
-
8
- //------------------------------------------------------------------------------
9
- // Requirements
10
- //------------------------------------------------------------------------------
11
-
12
- const fs = require("fs"),
13
- path = require("path"),
14
- stringify = require("json-stable-stringify-without-jsonify");
15
-
16
- const debug = require("debug")("eslint:config-file");
17
-
18
- //------------------------------------------------------------------------------
19
- // Helpers
20
- //------------------------------------------------------------------------------
21
-
22
- /**
23
- * Determines sort order for object keys for json-stable-stringify
24
- *
25
- * see: https://github.com/samn/json-stable-stringify#cmp
26
- * @param {Object} a The first comparison object ({key: akey, value: avalue})
27
- * @param {Object} b The second comparison object ({key: bkey, value: bvalue})
28
- * @returns {number} 1 or -1, used in stringify cmp method
29
- */
30
- function sortByKey(a, b) {
31
- return a.key > b.key ? 1 : -1;
32
- }
33
-
34
- //------------------------------------------------------------------------------
35
- // Private
36
- //------------------------------------------------------------------------------
37
-
38
- /**
39
- * Writes a configuration file in JSON format.
40
- * @param {Object} config The configuration object to write.
41
- * @param {string} filePath The filename to write to.
42
- * @returns {void}
43
- * @private
44
- */
45
- function writeJSONConfigFile(config, filePath) {
46
- debug(`Writing JSON config file: ${filePath}`);
47
-
48
- const content = `${stringify(config, { cmp: sortByKey, space: 4 })}\n`;
49
-
50
- fs.writeFileSync(filePath, content, "utf8");
51
- }
52
-
53
- /**
54
- * Writes a configuration file in YAML format.
55
- * @param {Object} config The configuration object to write.
56
- * @param {string} filePath The filename to write to.
57
- * @returns {void}
58
- * @private
59
- */
60
- function writeYAMLConfigFile(config, filePath) {
61
- debug(`Writing YAML config file: ${filePath}`);
62
-
63
- // lazy load YAML to improve performance when not used
64
- const yaml = require("js-yaml");
65
-
66
- const content = yaml.dump(config, { sortKeys: true });
67
-
68
- fs.writeFileSync(filePath, content, "utf8");
69
- }
70
-
71
- /**
72
- * Writes a configuration file in JavaScript format.
73
- * @param {Object} config The configuration object to write.
74
- * @param {string} filePath The filename to write to.
75
- * @throws {Error} If an error occurs linting the config file contents.
76
- * @returns {void}
77
- * @private
78
- */
79
- function writeJSConfigFile(config, filePath) {
80
- debug(`Writing JS config file: ${filePath}`);
81
-
82
- let contentToWrite;
83
- const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};\n`;
84
-
85
- try {
86
- const { CLIEngine } = require("../cli-engine");
87
- const linter = new CLIEngine({
88
- baseConfig: config,
89
- fix: true,
90
- useEslintrc: false
91
- });
92
- const report = linter.executeOnText(stringifiedContent);
93
-
94
- contentToWrite = report.results[0].output || stringifiedContent;
95
- } catch (e) {
96
- debug("Error linting JavaScript config file, writing unlinted version");
97
- const errorMessage = e.message;
98
-
99
- contentToWrite = stringifiedContent;
100
- e.message = "An error occurred while generating your JavaScript config file. ";
101
- e.message += "A config file was still generated, but the config file itself may not follow your linting rules.";
102
- e.message += `\nError: ${errorMessage}`;
103
- throw e;
104
- } finally {
105
- fs.writeFileSync(filePath, contentToWrite, "utf8");
106
- }
107
- }
108
-
109
- /**
110
- * Writes a configuration file.
111
- * @param {Object} config The configuration object to write.
112
- * @param {string} filePath The filename to write to.
113
- * @returns {void}
114
- * @throws {Error} When an unknown file type is specified.
115
- * @private
116
- */
117
- function write(config, filePath) {
118
- switch (path.extname(filePath)) {
119
- case ".js":
120
- case ".cjs":
121
- writeJSConfigFile(config, filePath);
122
- break;
123
-
124
- case ".json":
125
- writeJSONConfigFile(config, filePath);
126
- break;
127
-
128
- case ".yaml":
129
- case ".yml":
130
- writeYAMLConfigFile(config, filePath);
131
- break;
132
-
133
- default:
134
- throw new Error("Can't write to unknown file type.");
135
- }
136
- }
137
-
138
- //------------------------------------------------------------------------------
139
- // Public Interface
140
- //------------------------------------------------------------------------------
141
-
142
- module.exports = {
143
- write
144
- };