Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use plugin metadata for flat config serialization #16992

Merged
merged 3 commits into from Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/src/extend/plugins.md
Expand Up @@ -18,6 +18,34 @@ Each plugin is an npm module with a name in the format of `eslint-plugin-<plugin

The easiest way to start creating a plugin is to use the [Yeoman generator](https://www.npmjs.com/package/generator-eslint). The generator will guide you through setting up the skeleton of a plugin.

### Metadata in Plugins

For easier debugging and more effective caching of plugins, it's recommended to provide a name and version in a `meta` object at the root of your plugin, like this:

```js
// preferred location of name and version
module.exports = {
meta: {
name: "eslint-plugin-custom",
version: "1.2.3"
}
};
```

The `meta.name` property should match the npm package name for your plugin and the `meta.version` property should match the npm package version for your plugin. The easiest way to accomplish this is by reading this information from your `package.json`.

As an alternative, you can also expose `name` and `version` properties at the root of your plugin, such as:

```js
// alternate location of name and version
module.exports = {
name: "eslint-plugin-custom",
version: "1.2.3"
};
```

While the `meta` object is the preferred way to provide the plugin name and version, this format is also acceptable and is provided for backward compatibility.

### Rules in Plugins

Plugins can expose custom rules for use in ESLint. To do so, the plugin must export a `rules` object containing a key-value mapping of rule ID to rule. The rule ID does not have to follow any naming convention (so it can just be `dollar-sign`, for instance). To learn more about creating custom rules in plugins, refer to [Custom Rules](custom-rules).
Expand Down
11 changes: 10 additions & 1 deletion lib/config/flat-config-array.js
Expand Up @@ -245,7 +245,16 @@ class FlatConfigArray extends ConfigArray {

return {
...this,
plugins: Object.keys(plugins),
plugins: Object.entries(plugins).map(([namespace, plugin]) => {

const pluginId = getObjectId(plugin);

if (!pluginId) {
return namespace;
}

return `${namespace}:${pluginId}`;
}),
languageOptions: {
...languageOptions,
parser: parserName
Expand Down
66 changes: 66 additions & 0 deletions tests/lib/config/flat-config-array.js
Expand Up @@ -221,6 +221,72 @@ describe("FlatConfigArray", () => {
assert.strictEqual(stringify(actual), stringify(expected));
});

it("should convert config with plugin name/version into normalized JSON object", () => {

const configs = new FlatConfigArray([{
plugins: {
a: {},
b: {
name: "b-plugin",
version: "2.3.1"
}
}
}]);

configs.normalizeSync();

const config = configs.getConfig("foo.js");
const expected = {
plugins: ["@", "a", "b:b-plugin@2.3.1"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: `espree@${espree.version}`,
parserOptions: {}
},
processor: void 0
};
const actual = config.toJSON();

assert.deepStrictEqual(actual, expected);

assert.strictEqual(stringify(actual), stringify(expected));
});

it("should convert config with plugin meta into normalized JSON object", () => {

const configs = new FlatConfigArray([{
plugins: {
a: {},
b: {
meta: {
name: "b-plugin",
version: "2.3.1"
}
}
}
}]);

configs.normalizeSync();

const config = configs.getConfig("foo.js");
const expected = {
plugins: ["@", "a", "b:b-plugin@2.3.1"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: `espree@${espree.version}`,
parserOptions: {}
},
processor: void 0
};
const actual = config.toJSON();

assert.deepStrictEqual(actual, expected);

assert.strictEqual(stringify(actual), stringify(expected));
});

it("should throw an error when config with unnamed parser object is normalized", () => {

const configs = new FlatConfigArray([{
Expand Down