]> git.proxmox.com Git - pve-eslint.git/blame - eslint/tests/lib/init/autoconfig.js
import eslint 7.28.0
[pve-eslint.git] / eslint / tests / lib / init / autoconfig.js
CommitLineData
eb39fafa
DC
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
12const assert = require("chai").assert,
13 autoconfig = require("../../../lib/init/autoconfig"),
14 sourceCodeUtils = require("../../../lib/init/source-code-utils"),
56c4a2cb
DC
15 baseDefaultOptions = require("../../../conf/default-cli-options"),
16 recommendedConfig = require("../../conf/eslint-recommended");
eb39fafa
DC
17
18const defaultOptions = Object.assign({}, baseDefaultOptions, { cwd: process.cwd() });
19
20//------------------------------------------------------------------------------
21// Data
22//------------------------------------------------------------------------------
23
24const SOURCE_CODE_FIXTURE_FILENAME = "./tests/fixtures/autoconfig/source.js";
25const CONFIG_COMMENTS_FILENAME = "./tests/fixtures/autoconfig/source-with-comments.js";
26const SEVERITY = 2;
27
28//------------------------------------------------------------------------------
29// Tests
30//------------------------------------------------------------------------------
31
32const rulesConfig = {
33 semi: [SEVERITY, [SEVERITY, "always"], [SEVERITY, "never"]],
34 "semi-spacing": [SEVERITY,
35 [SEVERITY, { before: true, after: true }],
36 [SEVERITY, { before: true, after: false }],
37 [SEVERITY, { before: false, after: true }],
38 [SEVERITY, { before: false, after: false }]
39 ],
40 quotes: [SEVERITY,
41 [SEVERITY, "single"],
42 [SEVERITY, "double"],
43 [SEVERITY, "backtick"],
44 [SEVERITY, "single", "avoid-escape"],
45 [SEVERITY, "double", "avoid-escape"],
46 [SEVERITY, "backtick", "avoid-escape"]]
47};
48
49const errorRulesConfig = {
50 "no-unused-vars": [SEVERITY],
51 "semi-spacing": [SEVERITY,
52 [SEVERITY, { before: true, after: true }],
53 [SEVERITY, { before: true, after: false }],
54 [SEVERITY, { before: false, after: true }],
55 [SEVERITY, { before: false, after: false }]
56 ]
57};
58
59describe("autoconfig", () => {
60
61 describe("Registry", () => {
62
63 it("should set up a registry for rules in a provided rulesConfig", () => {
64 const expectedRules = Object.keys(rulesConfig);
65 const registry = new autoconfig.Registry(rulesConfig);
66
67 assert.strictEqual(Object.keys(registry.rules).length, 3);
68 assert.sameMembers(Object.keys(registry.rules), expectedRules);
69 assert.isArray(registry.rules.semi);
70 assert.isArray(registry.rules["semi-spacing"]);
71 assert.isArray(registry.rules.quotes);
72 assert.lengthOf(registry.rules.semi, 3);
73 assert.lengthOf(registry.rules["semi-spacing"], 5);
74 assert.lengthOf(registry.rules.quotes, 7);
75 });
76
77 it("should not have any rules if constructed without a config argument", () => {
78 const registry = new autoconfig.Registry();
79
80 assert.isObject(registry.rules);
81 assert.lengthOf(Object.keys(registry.rules), 0);
82 });
83
84 it("should create registryItems for each rule with the proper keys", () => {
85 const registry = new autoconfig.Registry(rulesConfig);
86
87 assert.isObject(registry.rules.semi[0]);
88 assert.isObject(registry.rules["semi-spacing"][0]);
89 assert.isObject(registry.rules.quotes[0]);
90 assert.property(registry.rules.semi[0], "config");
91 assert.property(registry.rules.semi[0], "specificity");
92 assert.property(registry.rules.semi[0], "errorCount");
93 });
94
95 it("should populate the config property correctly", () => {
96 const registry = new autoconfig.Registry(rulesConfig);
97
98 assert.strictEqual(registry.rules.quotes[0].config, SEVERITY);
99 assert.deepStrictEqual(registry.rules.quotes[1].config, [SEVERITY, "single"]);
100 assert.deepStrictEqual(registry.rules.quotes[2].config, [SEVERITY, "double"]);
101 assert.deepStrictEqual(registry.rules.quotes[3].config, [SEVERITY, "backtick"]);
102 assert.deepStrictEqual(registry.rules.quotes[4].config, [SEVERITY, "single", "avoid-escape"]);
103 assert.deepStrictEqual(registry.rules.quotes[5].config, [SEVERITY, "double", "avoid-escape"]);
104 assert.deepStrictEqual(registry.rules.quotes[6].config, [SEVERITY, "backtick", "avoid-escape"]);
105 });
106
107 it("should assign the correct specificity", () => {
108 const registry = new autoconfig.Registry(rulesConfig);
109
110 assert.strictEqual(registry.rules.quotes[0].specificity, 1);
111 assert.strictEqual(registry.rules.quotes[1].specificity, 2);
112 assert.strictEqual(registry.rules.quotes[6].specificity, 3);
113 });
114
115 it("should initially leave the errorCount as undefined", () => {
116 const registry = new autoconfig.Registry(rulesConfig);
117
118 assert.isUndefined(registry.rules.quotes[0].errorCount);
119 assert.isUndefined(registry.rules.quotes[1].errorCount);
120 assert.isUndefined(registry.rules.quotes[6].errorCount);
121 });
122
123 describe("populateFromCoreRules()", () => {
124
125 it("should add core rules to registry", () => {
126 const registry = new autoconfig.Registry();
127
128 registry.populateFromCoreRules();
129 const finalRuleCount = Object.keys(registry.rules).length;
130
131 assert(finalRuleCount > 0);
132 assert.include(Object.keys(registry.rules), "eqeqeq");
133 });
134
5422a9cc
TL
135 it("should not add deprecated rules", () => {
136 const registry = new autoconfig.Registry();
137
138 registry.populateFromCoreRules();
139
140 const { rules } = registry;
141
142 assert.notProperty(rules, "id-blacklist");
143 assert.notProperty(rules, "no-negated-in-lhs");
144 assert.notProperty(rules, "no-process-exit");
145 assert.notProperty(rules, "no-spaced-func");
146 assert.notProperty(rules, "prefer-reflect");
147 });
148
eb39fafa
DC
149 it("should not add duplicate rules", () => {
150 const registry = new autoconfig.Registry(rulesConfig);
151
152 registry.populateFromCoreRules();
153 const semiCount = Object.keys(registry.rules).filter(ruleId => ruleId === "semi").length;
154
155 assert.strictEqual(semiCount, 1);
156 });
157 });
158
159 describe("buildRuleSets()", () => {
160 let ruleSets;
161
162 beforeEach(() => {
163 const registry = new autoconfig.Registry(rulesConfig);
164
165 ruleSets = registry.buildRuleSets();
166 });
167
168 it("should create an array of rule configuration sets", () => {
169 assert.isArray(ruleSets);
170 });
171
172 it("should include configs for each rule (at least for the first set)", () => {
173 assert.sameMembers(Object.keys(ruleSets[0]), ["semi", "semi-spacing", "quotes"]);
174 });
175
176 it("should create the first set from default rule configs (severity only)", () => {
177 assert.deepStrictEqual(ruleSets[0], { semi: SEVERITY, "semi-spacing": SEVERITY, quotes: SEVERITY });
178 });
179
180 it("should create as many ruleSets as the highest number of configs in a rule", () => {
181
182 // `quotes` has 7 possible configurations
183 assert.lengthOf(ruleSets, 7);
184 });
185 });
186
187 describe("lintSourceCode()", () => {
188 let registry;
189
190 beforeEach(() => {
191 const config = { ignore: false };
192 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
193
194 registry = new autoconfig.Registry(rulesConfig);
195 registry = registry.lintSourceCode(sourceCode, defaultOptions);
196 });
197
198 it("should populate the errorCount of all registryItems", () => {
199 const expectedRules = ["semi", "semi-spacing", "quotes"];
200
201 assert.sameMembers(Object.keys(registry.rules), expectedRules);
202 expectedRules.forEach(ruleId => {
203 assert(registry.rules[ruleId].length > 0);
204 registry.rules[ruleId].forEach(conf => {
205 assert.isNumber(conf.errorCount);
206 });
207 });
208 });
209
210 it("should correctly set the error count of configurations", () => {
211 assert.strictEqual(registry.rules.semi[0].config, SEVERITY);
212 assert.strictEqual(registry.rules.semi[0].errorCount, 0);
213 assert.deepStrictEqual(registry.rules.semi[2].config, [SEVERITY, "never"]);
214 assert.strictEqual(registry.rules.semi[2].errorCount, 3);
215 });
216
217 it("should respect inline eslint config comments (and not crash when they make linting errors)", () => {
218 const config = { ignore: false };
219 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(CONFIG_COMMENTS_FILENAME, config);
220 const expectedRegistry = [
221 { config: 2, specificity: 1, errorCount: 3 },
222 { config: [2, "always"], specificity: 2, errorCount: 3 },
223 { config: [2, "never"], specificity: 2, errorCount: 3 }
224 ];
225
226 registry = new autoconfig.Registry(rulesConfig);
227 registry = registry.lintSourceCode(sourceCode, defaultOptions);
228
229 assert.deepStrictEqual(registry.rules.semi, expectedRegistry);
230 });
231 });
232
233 describe("stripFailingConfigs()", () => {
234 let registry;
235
236 beforeEach(() => {
237 const config = { ignore: false };
238 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
239
240 registry = new autoconfig.Registry(rulesConfig);
241 registry = registry.lintSourceCode(sourceCode, defaultOptions);
242 registry = registry.stripFailingConfigs();
243 });
244
245 it("should remove all registryItems with a non-zero errorCount", () => {
246 assert.lengthOf(registry.rules.semi, 2);
247 assert.lengthOf(registry.rules["semi-spacing"], 3);
248 assert.lengthOf(registry.rules.quotes, 1);
249 registry.rules.semi.forEach(registryItem => {
250 assert.strictEqual(registryItem.errorCount, 0);
251 });
252 registry.rules["semi-spacing"].forEach(registryItem => {
253 assert.strictEqual(registryItem.errorCount, 0);
254 });
255 registry.rules.quotes.forEach(registryItem => {
256 assert.strictEqual(registryItem.errorCount, 0);
257 });
258 });
259 });
260
261 describe("getFailingRulesRegistry()", () => {
262 let failingRegistry;
263
264 beforeEach(() => {
265 const config = { ignore: false };
266 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
267 let registry = new autoconfig.Registry(errorRulesConfig);
268
269 registry = registry.lintSourceCode(sourceCode, defaultOptions);
270 failingRegistry = registry.getFailingRulesRegistry();
271 });
272
273 it("should return a registry with no registryItems with an errorCount of zero", () => {
274 const failingRules = Object.keys(failingRegistry.rules);
275
276 assert.deepStrictEqual(failingRules, ["no-unused-vars"]);
277 assert.lengthOf(failingRegistry.rules["no-unused-vars"], 1);
278 assert(failingRegistry.rules["no-unused-vars"][0].errorCount > 0);
279 });
280 });
281
282 describe("createConfig()", () => {
283 let createdConfig;
284
285 beforeEach(() => {
286 const config = { ignore: false };
287 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
288 let registry = new autoconfig.Registry(rulesConfig);
289
290 registry = registry.lintSourceCode(sourceCode, defaultOptions);
291 registry = registry.stripFailingConfigs();
292 createdConfig = registry.createConfig();
293 });
294
295 it("should create a config with a rules property", () => {
296 assert.property(createdConfig, "rules");
297 });
298
299 it("should add rules which have only one registryItem to the config", () => {
300 const configuredRules = Object.keys(createdConfig.rules);
301
302 assert.deepStrictEqual(configuredRules, ["quotes"]);
303 });
304
305 it("should set the configuration of the rule to the registryItem's `config` value", () => {
306 assert.deepStrictEqual(createdConfig.rules.quotes, [2, "double", "avoid-escape"]);
307 });
308
309 it("should not care how many errors the config has", () => {
310 const config = { ignore: false };
311 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
312 let registry = new autoconfig.Registry(errorRulesConfig);
313
314 registry = registry.lintSourceCode(sourceCode, defaultOptions);
315 const failingRegistry = registry.getFailingRulesRegistry();
316
317 createdConfig = failingRegistry.createConfig();
318 const configuredRules = Object.keys(createdConfig.rules);
319
320 assert.deepStrictEqual(configuredRules, ["no-unused-vars"]);
321 });
322 });
323
324 describe("filterBySpecificity()", () => {
325 let registry;
326
327 beforeEach(() => {
328 registry = new autoconfig.Registry(rulesConfig);
329 });
330
331 it("should return a registry where all configs have a desired specificity", () => {
332 const filteredRegistry1 = registry.filterBySpecificity(1);
333 const filteredRegistry2 = registry.filterBySpecificity(2);
334 const filteredRegistry3 = registry.filterBySpecificity(3);
335
336 assert.lengthOf(filteredRegistry1.rules.semi, 1);
337 assert.lengthOf(filteredRegistry1.rules["semi-spacing"], 1);
338 assert.lengthOf(filteredRegistry1.rules.quotes, 1);
339 assert.lengthOf(filteredRegistry2.rules.semi, 2);
340 assert.lengthOf(filteredRegistry2.rules["semi-spacing"], 4);
341 assert.lengthOf(filteredRegistry2.rules.quotes, 3);
342 assert.lengthOf(filteredRegistry3.rules.quotes, 3);
343 });
344 });
345 });
56c4a2cb
DC
346
347 describe("extendFromRecommended()", () => {
348 it("should return a configuration which has `extends` key with Array type value", () => {
349 const oldConfig = { extends: [], rules: {} };
350 const newConfig = autoconfig.extendFromRecommended(oldConfig);
351
352 assert.exists(newConfig.extends);
353 assert.isArray(newConfig.extends);
354 });
355
356 it("should return a configuration which has array property `extends`", () => {
357 const oldConfig = { extends: [], rules: {} };
358 const newConfig = autoconfig.extendFromRecommended(oldConfig);
359
360 assert.include(newConfig.extends, "eslint:recommended");
361 });
362
363 it("should return a configuration which preserves the previous extending configurations", () => {
364 const oldConfig = { extends: ["previous:configuration1", "previous:configuration2"], rules: {} };
365 const newConfig = autoconfig.extendFromRecommended(oldConfig);
366
367 assert.includeMembers(newConfig.extends, oldConfig.extends);
368 });
369
370 it("should return a configuration which has `eslint:recommended` at the first of `extends`", () => {
371 const oldConfig = { extends: ["previous:configuration1", "previous:configuration2"], rules: {} };
372 const newConfig = autoconfig.extendFromRecommended(oldConfig);
373 const [firstExtendInNewConfig] = newConfig.extends;
374
375 assert.strictEqual(firstExtendInNewConfig, "eslint:recommended");
376 });
377
378 it("should return a configuration which not includes rules configured in `eslint:recommended`", () => {
379 const oldConfig = { extends: [], rules: { ...recommendedConfig.rules } };
380 const newConfig = autoconfig.extendFromRecommended(oldConfig);
381
382 assert.notInclude(newConfig.rules, oldConfig.rules);
383 });
384 });
eb39fafa 385});