Skip to content

Commit

Permalink
feat: Use plugin metadata for flat config serialization (#16992)
Browse files Browse the repository at this point in the history
* feat: Use plugin metadata for flat config serialization

Updates `FlatConfigArray` to look for meta information on plugins when
serializing a config.

Fixes #16284

* Update docs/src/extend/plugins.md

Co-authored-by: Nitin Kumar <snitin315@gmail.com>

* Rebase

---------

Co-authored-by: Nitin Kumar <snitin315@gmail.com>
  • Loading branch information
nzakas and snitin315 committed Mar 23, 2023
1 parent b3634f6 commit 1665c02
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 1 deletion.
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

0 comments on commit 1665c02

Please sign in to comment.