Skip to content

Commit

Permalink
Update: Implement FlatConfigArray (refs #13481) (#14321)
Browse files Browse the repository at this point in the history
* 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 <btmills@users.noreply.github.com>

* Update tests/lib/config/flat-config-array.js

Co-authored-by: Brandon Mills <btmills@users.noreply.github.com>

* Update tests/lib/config/flat-config-array.js

Co-authored-by: Brandon Mills <btmills@users.noreply.github.com>

* Update tests/lib/config/flat-config-array.js

Co-authored-by: Brandon Mills <btmills@users.noreply.github.com>

* 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 <btmills@users.noreply.github.com>
  • Loading branch information
nzakas and btmills committed Jun 26, 2021
1 parent f113cdd commit b08170b
Show file tree
Hide file tree
Showing 6 changed files with 2,249 additions and 0 deletions.
52 changes: 52 additions & 0 deletions lib/config/default-config.js
@@ -0,0 +1,52 @@
/**
* @fileoverview Default configuration
* @author Nicholas C. Zakas
*/

"use strict";

//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------

const Rules = require("../rules");

//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------


exports.defaultConfig = [
{
plugins: {
"@": {
parsers: {
espree: require("espree")
},

/*
* Because we try to delay loading rules until absolutely
* necessary, a proxy allows us to hook into the lazy-loading
* aspect of the rules map while still keeping all of the
* relevant configuration inside of the config array.
*/
rules: new Proxy({}, {
get(target, property) {
return Rules.get(property);
},

has(target, property) {
return Rules.has(property);
}
})
}
},
ignores: [
"**/node_modules/**",
".git/**"
],
languageOptions: {
parser: "@/espree"
}
}
];
125 changes: 125 additions & 0 deletions lib/config/flat-config-array.js
@@ -0,0 +1,125 @@
/**
* @fileoverview Flat Config Array
* @author Nicholas C. Zakas
*/

"use strict";

//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------

const { ConfigArray, ConfigArraySymbol } = require("@humanwhocodes/config-array");
const { flatConfigSchema } = require("./flat-config-schema");
const { RuleValidator } = require("./rule-validator");
const { defaultConfig } = require("./default-config");
const recommendedConfig = require("../../conf/eslint-recommended");
const allConfig = require("../../conf/eslint-all");

//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------

const ruleValidator = new RuleValidator();

/**
* Splits a plugin identifier in the form a/b/c into two parts: a/b and c.
* @param {string} identifier The identifier to parse.
* @returns {{objectName: string, pluginName: string}} The parts of the plugin
* name.
*/
function splitPluginIdentifier(identifier) {
const parts = identifier.split("/");

return {
objectName: parts.pop(),
pluginName: parts.join("/")
};
}

//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------

/**
* Represents an array containing configuration information for ESLint.
*/
class FlatConfigArray extends ConfigArray {

/**
* Creates a new instance.
* @param {*[]} configs An array of configuration information.
* @param {{basePath: string, baseConfig: FlatConfig}} options The options
* to use for the config array instance.
*/
constructor(configs, { basePath, baseConfig = defaultConfig }) {
super(configs, {
basePath,
schema: flatConfigSchema
});

this.unshift(baseConfig);
}

/* eslint-disable class-methods-use-this */
/**
* Replaces a config with another config to allow us to put strings
* in the config array that will be replaced by objects before
* normalization.
* @param {Object} config The config to preprocess.
* @returns {Object} The preprocessed config.
*/
[ConfigArraySymbol.preprocessConfig](config) {
if (config === "eslint:recommended") {
return recommendedConfig;
}

if (config === "eslint:all") {
return allConfig;
}

return config;
}

/**
* Finalizes the config by replacing plugin references with their objects
* and validating rule option schemas.
* @param {Object} config The config to finalize.
* @returns {Object} The finalized config.
* @throws {TypeError} If the config is invalid.
*/
[ConfigArraySymbol.finalizeConfig](config) {

const { plugins, languageOptions, processor } = config;

// Check parser value
if (languageOptions && languageOptions.parser && typeof languageOptions.parser === "string") {
const { pluginName, objectName: parserName } = splitPluginIdentifier(languageOptions.parser);

if (!plugins || !plugins[pluginName] || !plugins[pluginName].parsers || !plugins[pluginName].parsers[parserName]) {
throw new TypeError(`Key "parser": Could not find "${parserName}" in plugin "${pluginName}".`);
}

languageOptions.parser = plugins[pluginName].parsers[parserName];
}

// Check processor value
if (processor && typeof processor === "string") {
const { pluginName, objectName: processorName } = splitPluginIdentifier(processor);

if (!plugins || !plugins[pluginName] || !plugins[pluginName].processors || !plugins[pluginName].processors[processorName]) {
throw new TypeError(`Key "processor": Could not find "${processorName}" in plugin "${pluginName}".`);
}

config.processor = plugins[pluginName].processors[processorName];
}

ruleValidator.validate(config);

return config;
}
/* eslint-enable class-methods-use-this */

}

exports.FlatConfigArray = FlatConfigArray;

0 comments on commit b08170b

Please sign in to comment.