Skip to content

Commit b08170b

Browse files
nzakasbtmills
andauthored
Update: Implement FlatConfigArray (refs #13481) (#14321)
* Update: Implement FlatConfigArray (refs #13481) * Upgrade config-array package * Add schemas for linterOptions, processor, plugins * Continue implementing config schemas * RulesSchema start * Add initial finalization step * Default config * Strict mode * Start rule validation * Finish FlatConfigArray implementation * Remove too-new syntax * Fix default config * fix test * Update tests/lib/config/flat-config-array.js Co-authored-by: Brandon Mills <[email protected]> * Update tests/lib/config/flat-config-array.js Co-authored-by: Brandon Mills <[email protected]> * Update tests/lib/config/flat-config-array.js Co-authored-by: Brandon Mills <[email protected]> * Update tests/lib/config/flat-config-array.js Co-authored-by: Brandon Mills <[email protected]> * Update tests * fix test * Allow old-style plugin names * Fix reportUnusedDisableDirectives and add JSDoc * Add more tests * address review comments * Ignore only .git directory * Allow null for global settings * writeable -> writable * Remove incorrect comment * Validate severity-only rule options * Add key to global error message * deeply merge parserOptions and settings * Rename defaultResultConfig * Normalize and fix rule validations * Fix rule options merging * Fix various errors * Rebase onto master Co-authored-by: Brandon Mills <[email protected]>
1 parent f113cdd commit b08170b

6 files changed

Lines changed: 2249 additions & 0 deletions

File tree

lib/config/default-config.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @fileoverview Default configuration
3+
* @author Nicholas C. Zakas
4+
*/
5+
6+
"use strict";
7+
8+
//-----------------------------------------------------------------------------
9+
// Requirements
10+
//-----------------------------------------------------------------------------
11+
12+
const Rules = require("../rules");
13+
14+
//-----------------------------------------------------------------------------
15+
// Helpers
16+
//-----------------------------------------------------------------------------
17+
18+
19+
exports.defaultConfig = [
20+
{
21+
plugins: {
22+
"@": {
23+
parsers: {
24+
espree: require("espree")
25+
},
26+
27+
/*
28+
* Because we try to delay loading rules until absolutely
29+
* necessary, a proxy allows us to hook into the lazy-loading
30+
* aspect of the rules map while still keeping all of the
31+
* relevant configuration inside of the config array.
32+
*/
33+
rules: new Proxy({}, {
34+
get(target, property) {
35+
return Rules.get(property);
36+
},
37+
38+
has(target, property) {
39+
return Rules.has(property);
40+
}
41+
})
42+
}
43+
},
44+
ignores: [
45+
"**/node_modules/**",
46+
".git/**"
47+
],
48+
languageOptions: {
49+
parser: "@/espree"
50+
}
51+
}
52+
];

lib/config/flat-config-array.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* @fileoverview Flat Config Array
3+
* @author Nicholas C. Zakas
4+
*/
5+
6+
"use strict";
7+
8+
//-----------------------------------------------------------------------------
9+
// Requirements
10+
//-----------------------------------------------------------------------------
11+
12+
const { ConfigArray, ConfigArraySymbol } = require("@humanwhocodes/config-array");
13+
const { flatConfigSchema } = require("./flat-config-schema");
14+
const { RuleValidator } = require("./rule-validator");
15+
const { defaultConfig } = require("./default-config");
16+
const recommendedConfig = require("../../conf/eslint-recommended");
17+
const allConfig = require("../../conf/eslint-all");
18+
19+
//-----------------------------------------------------------------------------
20+
// Helpers
21+
//-----------------------------------------------------------------------------
22+
23+
const ruleValidator = new RuleValidator();
24+
25+
/**
26+
* Splits a plugin identifier in the form a/b/c into two parts: a/b and c.
27+
* @param {string} identifier The identifier to parse.
28+
* @returns {{objectName: string, pluginName: string}} The parts of the plugin
29+
* name.
30+
*/
31+
function splitPluginIdentifier(identifier) {
32+
const parts = identifier.split("/");
33+
34+
return {
35+
objectName: parts.pop(),
36+
pluginName: parts.join("/")
37+
};
38+
}
39+
40+
//-----------------------------------------------------------------------------
41+
// Exports
42+
//-----------------------------------------------------------------------------
43+
44+
/**
45+
* Represents an array containing configuration information for ESLint.
46+
*/
47+
class FlatConfigArray extends ConfigArray {
48+
49+
/**
50+
* Creates a new instance.
51+
* @param {*[]} configs An array of configuration information.
52+
* @param {{basePath: string, baseConfig: FlatConfig}} options The options
53+
* to use for the config array instance.
54+
*/
55+
constructor(configs, { basePath, baseConfig = defaultConfig }) {
56+
super(configs, {
57+
basePath,
58+
schema: flatConfigSchema
59+
});
60+
61+
this.unshift(baseConfig);
62+
}
63+
64+
/* eslint-disable class-methods-use-this */
65+
/**
66+
* Replaces a config with another config to allow us to put strings
67+
* in the config array that will be replaced by objects before
68+
* normalization.
69+
* @param {Object} config The config to preprocess.
70+
* @returns {Object} The preprocessed config.
71+
*/
72+
[ConfigArraySymbol.preprocessConfig](config) {
73+
if (config === "eslint:recommended") {
74+
return recommendedConfig;
75+
}
76+
77+
if (config === "eslint:all") {
78+
return allConfig;
79+
}
80+
81+
return config;
82+
}
83+
84+
/**
85+
* Finalizes the config by replacing plugin references with their objects
86+
* and validating rule option schemas.
87+
* @param {Object} config The config to finalize.
88+
* @returns {Object} The finalized config.
89+
* @throws {TypeError} If the config is invalid.
90+
*/
91+
[ConfigArraySymbol.finalizeConfig](config) {
92+
93+
const { plugins, languageOptions, processor } = config;
94+
95+
// Check parser value
96+
if (languageOptions && languageOptions.parser && typeof languageOptions.parser === "string") {
97+
const { pluginName, objectName: parserName } = splitPluginIdentifier(languageOptions.parser);
98+
99+
if (!plugins || !plugins[pluginName] || !plugins[pluginName].parsers || !plugins[pluginName].parsers[parserName]) {
100+
throw new TypeError(`Key "parser": Could not find "${parserName}" in plugin "${pluginName}".`);
101+
}
102+
103+
languageOptions.parser = plugins[pluginName].parsers[parserName];
104+
}
105+
106+
// Check processor value
107+
if (processor && typeof processor === "string") {
108+
const { pluginName, objectName: processorName } = splitPluginIdentifier(processor);
109+
110+
if (!plugins || !plugins[pluginName] || !plugins[pluginName].processors || !plugins[pluginName].processors[processorName]) {
111+
throw new TypeError(`Key "processor": Could not find "${processorName}" in plugin "${pluginName}".`);
112+
}
113+
114+
config.processor = plugins[pluginName].processors[processorName];
115+
}
116+
117+
ruleValidator.validate(config);
118+
119+
return config;
120+
}
121+
/* eslint-enable class-methods-use-this */
122+
123+
}
124+
125+
exports.FlatConfigArray = FlatConfigArray;

0 commit comments

Comments
 (0)