Skip to content

Commit d2ec358

Browse files
authored
Add support for flat config (#308)
* Add support for flat config * Create soft-shirts-smile.md * fix * fix
1 parent fd5b4f8 commit d2ec358

16 files changed

+326
-7
lines changed

.changeset/soft-shirts-smile.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-yml": minor
3+
---
4+
5+
Add support for flat config

.eslintrc.for-vscode.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"use strict";
2+
3+
module.exports = {
4+
extends: [require.resolve("./.eslintrc.js")],
5+
overrides: [
6+
{
7+
files: ["tests/src/rules/*"],
8+
extends: ["plugin:eslint-rule-tester/recommended-legacy"],
9+
},
10+
],
11+
};

.eslintrc.js

+23
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ module.exports = {
3939
],
4040
},
4141
overrides: [
42+
{
43+
files: ["*.mjs"],
44+
parserOptions: {
45+
sourceType: "module",
46+
},
47+
},
4248
{
4349
files: ["*.ts", "*.mts"],
4450
parser: "@typescript-eslint/parser",
@@ -113,6 +119,12 @@ module.exports = {
113119
require: true,
114120
},
115121
},
122+
{
123+
files: ["*.md/**", "**/*.md/**"],
124+
rules: {
125+
"n/no-missing-import": "off",
126+
},
127+
},
116128
{
117129
files: ["docs/.vitepress/**"],
118130
parserOptions: {
@@ -127,5 +139,16 @@ module.exports = {
127139
"n/file-extension-in-import": "off",
128140
},
129141
},
142+
{
143+
files: ["docs/.vitepress/**/*.*"],
144+
rules: {
145+
"eslint-plugin/require-meta-docs-description": "off",
146+
"eslint-plugin/require-meta-docs-url": "off",
147+
"eslint-plugin/require-meta-type": "off",
148+
"eslint-plugin/prefer-message-ids": "off",
149+
"eslint-plugin/prefer-object-rule": "off",
150+
"eslint-plugin/require-meta-schema": "off",
151+
},
152+
},
130153
],
131154
};

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"github-actions-workflow",
1111
"markdown"
1212
],
13+
"eslint.options": {
14+
"overrideConfigFile": "./.eslintrc.for-vscode.js"
15+
},
1316
"typescript.validate.enable": true,
1417
"javascript.validate.enable": false,
1518
"vetur.validation.script": false,

README.md

+33-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,39 @@ npm install --save-dev eslint eslint-plugin-yml
6565

6666
### Configuration
6767

68-
Use `.eslintrc.*` file to configure rules. See also: [https://eslint.org/docs/user-guide/configuring](https://eslint.org/docs/user-guide/configuring).
68+
#### New (ESLint>=v9) Config (Flat Config)
69+
70+
Use `eslint.config.js` file to configure rules. See also: <https://eslint.org/docs/latest/use/configure/configuration-files-new>.
71+
72+
Example **eslint.config.js**:
73+
74+
```mjs
75+
import eslintPluginYml from 'eslint-plugin-yml';
76+
export default [
77+
// add more generic rule sets here, such as:
78+
// js.configs.recommended,
79+
...eslintPluginYml.configs['flat/recommended'],
80+
{
81+
rules: {
82+
// override/add rules settings here, such as:
83+
// 'yml/rule-name': 'error'
84+
}
85+
}
86+
];
87+
```
88+
89+
This plugin provides configs:
90+
91+
- `*.configs['flat/base']` ... Configuration to enable correct YAML parsing.
92+
- `*.configs['flat/recommended']` ... Above, plus rules to prevent errors or unintended behavior.
93+
- `*.configs['flat/standard']` ... Above, plus rules to enforce the common stylistic conventions.
94+
- `*.configs['flat/prettier']` ... Turn off rules that may conflict with [Prettier](https://prettier.io/).
95+
96+
See [the rule list](https://ota-meshi.github.io/eslint-plugin-yml/rules/) to get the `rules` that this plugin provides.
97+
98+
#### Legacy Config (ESLint<v9)
99+
100+
Use `.eslintrc.*` file to configure rules. See also: <https://eslint.org/docs/latest/use/configure/>.
69101

70102
Example **.eslintrc.js**:
71103

docs/user-guide/index.md

+33-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,39 @@ npm install --save-dev eslint eslint-plugin-yml
1919

2020
### Configuration
2121

22-
Use `.eslintrc.*` file to configure rules. See also: [https://eslint.org/docs/user-guide/configuring](https://eslint.org/docs/user-guide/configuring).
22+
#### New (ESLint>=v9) Config (Flat Config)
23+
24+
Use `eslint.config.js` file to configure rules. See also: <https://eslint.org/docs/latest/use/configure/configuration-files-new>.
25+
26+
Example **eslint.config.js**:
27+
28+
```mjs
29+
import eslintPluginYml from 'eslint-plugin-yml';
30+
export default [
31+
// add more generic rule sets here, such as:
32+
// js.configs.recommended,
33+
...eslintPluginYml.configs['flat/recommended'],
34+
{
35+
rules: {
36+
// override/add rules settings here, such as:
37+
// 'yml/rule-name': 'error'
38+
}
39+
}
40+
];
41+
```
42+
43+
This plugin provides configs:
44+
45+
- `*.configs['flat/base']` ... Configuration to enable correct YAML parsing.
46+
- `*.configs['flat/recommended']` ... Above, plus rules to prevent errors or unintended behavior.
47+
- `*.configs['flat/standard']` ... Above, plus rules to enforce the common stylistic conventions.
48+
- `*.configs['flat/prettier']` ... Turn off rules that may conflict with [Prettier](https://prettier.io/).
49+
50+
See [the rule list](../rules/index.md) to get the `rules` that this plugin provides.
51+
52+
#### Legacy Config (ESLint<v9)
53+
54+
Use `.eslintrc.*` file to configure rules. See also: <https://eslint.org/docs/latest/use/configure/>.
2355

2456
Example **.eslintrc.js**:
2557

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
"homepage": "https://ota-meshi.github.io/eslint-plugin-yml/",
5858
"dependencies": {
5959
"debug": "^4.3.2",
60-
"eslint-compat-utils": "^0.4.0",
60+
"eslint-compat-utils": "^0.5.0",
6161
"lodash": "^4.17.21",
6262
"natural-compare": "^1.4.0",
6363
"yaml-eslint-parser": "^1.2.1"
@@ -90,6 +90,7 @@
9090
"eslint-config-prettier": "^9.0.0",
9191
"eslint-plugin-eslint-comments": "^3.2.0",
9292
"eslint-plugin-eslint-plugin": "^5.0.0",
93+
"eslint-plugin-eslint-rule-tester": "^0.5.1",
9394
"eslint-plugin-json-schema-validator": "^4.7.4",
9495
"eslint-plugin-jsonc": "^2.0.0",
9596
"eslint-plugin-markdown": "^3.0.0",

src/configs/flat/base.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { ESLint } from "eslint";
2+
import * as parser from "yaml-eslint-parser";
3+
export default [
4+
{
5+
files: ["*.yaml", "**/*.yaml", "*.yml", "**/*.yml"],
6+
plugins: {
7+
get yml(): ESLint.Plugin {
8+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- ignore
9+
return require("../../index");
10+
},
11+
},
12+
languageOptions: {
13+
parser,
14+
},
15+
rules: {
16+
// ESLint core rules known to cause problems with YAML.
17+
"no-irregular-whitespace": "off",
18+
"no-unused-vars": "off",
19+
"spaced-comment": "off",
20+
},
21+
},
22+
];

src/configs/flat/prettier.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// IMPORTANT!
2+
// This file has been automatically generated,
3+
// in order to update its content execute "npm run update"
4+
import base from "./base";
5+
export default [
6+
...base,
7+
{
8+
rules: {
9+
// eslint-plugin-yml rules
10+
"yml/block-mapping-colon-indicator-newline": "off",
11+
"yml/block-mapping-question-indicator-newline": "off",
12+
"yml/block-sequence-hyphen-indicator-newline": "off",
13+
"yml/flow-mapping-curly-newline": "off",
14+
"yml/flow-mapping-curly-spacing": "off",
15+
"yml/flow-sequence-bracket-newline": "off",
16+
"yml/flow-sequence-bracket-spacing": "off",
17+
"yml/indent": "off",
18+
"yml/key-spacing": "off",
19+
"yml/no-multiple-empty-lines": "off",
20+
"yml/no-trailing-zeros": "off",
21+
"yml/quotes": "off",
22+
},
23+
},
24+
];

src/configs/flat/recommended.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// IMPORTANT!
2+
// This file has been automatically generated,
3+
// in order to update its content execute "npm run update"
4+
import base from "./base";
5+
export default [
6+
...base,
7+
{
8+
rules: {
9+
// eslint-plugin-yml rules
10+
"yml/no-empty-document": "error",
11+
"yml/no-empty-key": "error",
12+
"yml/no-empty-mapping-value": "error",
13+
"yml/no-empty-sequence-entry": "error",
14+
"yml/no-irregular-whitespace": "error",
15+
"yml/no-tab-indent": "error",
16+
"yml/vue-custom-block/no-parsing-error": "error",
17+
},
18+
},
19+
];

src/configs/flat/standard.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// IMPORTANT!
2+
// This file has been automatically generated,
3+
// in order to update its content execute "npm run update"
4+
import base from "./base";
5+
export default [
6+
...base,
7+
{
8+
rules: {
9+
// eslint-plugin-yml rules
10+
"yml/block-mapping-question-indicator-newline": "error",
11+
"yml/block-mapping": "error",
12+
"yml/block-sequence-hyphen-indicator-newline": "error",
13+
"yml/block-sequence": "error",
14+
"yml/flow-mapping-curly-newline": "error",
15+
"yml/flow-mapping-curly-spacing": "error",
16+
"yml/flow-sequence-bracket-newline": "error",
17+
"yml/flow-sequence-bracket-spacing": "error",
18+
"yml/indent": "error",
19+
"yml/key-spacing": "error",
20+
"yml/no-empty-document": "error",
21+
"yml/no-empty-key": "error",
22+
"yml/no-empty-mapping-value": "error",
23+
"yml/no-empty-sequence-entry": "error",
24+
"yml/no-irregular-whitespace": "error",
25+
"yml/no-tab-indent": "error",
26+
"yml/plain-scalar": "error",
27+
"yml/quotes": "error",
28+
"yml/spaced-comment": "error",
29+
"yml/vue-custom-block/no-parsing-error": "error",
30+
},
31+
},
32+
];

src/index.ts

+8
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,21 @@ import base from "./configs/base";
44
import recommended from "./configs/recommended";
55
import standard from "./configs/standard";
66
import prettier from "./configs/prettier";
7+
import flatBase from "./configs/base";
8+
import flatRecommended from "./configs/flat/recommended";
9+
import flatStandard from "./configs/flat/standard";
10+
import flatPrettier from "./configs/flat/prettier";
711
import * as meta from "./meta";
812

913
const configs = {
1014
base,
1115
recommended,
1216
standard,
1317
prettier,
18+
"flat/base": flatBase,
19+
"flat/recommended": flatRecommended,
20+
"flat/standard": flatStandard,
21+
"flat/prettier": flatPrettier,
1422
};
1523

1624
const rules = ruleList.reduce(

tests/src/configs/standard.ts

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import assert from "assert";
2+
import plugin from "../../../src/index";
3+
import { LegacyESLint, ESLint } from "../../utils/eslint-compat";
4+
5+
const code = `foo: 42`;
6+
describe("`standard` config", () => {
7+
it("legacy `standard` config should work. ", async () => {
8+
const linter = new LegacyESLint({
9+
plugins: {
10+
yml: plugin as never,
11+
},
12+
baseConfig: {
13+
parserOptions: {
14+
ecmaVersion: 2020,
15+
},
16+
extends: ["plugin:yml/recommended", "plugin:yml/standard"],
17+
},
18+
useEslintrc: false,
19+
});
20+
const result = await linter.lintText(code, { filePath: "test.yml" });
21+
const messages = result[0].messages;
22+
23+
assert.deepStrictEqual(
24+
messages.map((m) => ({
25+
ruleId: m.ruleId,
26+
line: m.line,
27+
message: m.message,
28+
})),
29+
[
30+
{
31+
message: "Extra space before value for key 'foo'.",
32+
ruleId: "yml/key-spacing",
33+
line: 1,
34+
},
35+
],
36+
);
37+
});
38+
it("`flat/standard` config should work. ", async () => {
39+
const linter = new ESLint({
40+
overrideConfigFile: true as never,
41+
// @ts-expect-error -- typing bug
42+
overrideConfig: [
43+
...(plugin.configs["flat/recommended"] as never),
44+
...(plugin.configs["flat/standard"] as never),
45+
],
46+
});
47+
const result = await linter.lintText(code, { filePath: "test.yml" });
48+
const messages = result[0].messages;
49+
50+
assert.deepStrictEqual(
51+
messages.map((m) => ({
52+
ruleId: m.ruleId,
53+
line: m.line,
54+
message: m.message,
55+
})),
56+
[
57+
{
58+
message: "Extra space before value for key 'foo'.",
59+
ruleId: "yml/key-spacing",
60+
line: 1,
61+
},
62+
],
63+
);
64+
});
65+
});

tests/utils/eslint-compat.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { getRuleTester } from "eslint-compat-utils/rule-tester";
2-
import { getLegacyESLint } from "eslint-compat-utils/eslint";
2+
import { getLegacyESLint, getESLint } from "eslint-compat-utils/eslint";
33

44
// eslint-disable-next-line @typescript-eslint/naming-convention -- class name
55
export const RuleTester = getRuleTester();
6-
76
// eslint-disable-next-line @typescript-eslint/naming-convention -- class name
87
export const LegacyESLint = getLegacyESLint();
8+
// eslint-disable-next-line @typescript-eslint/naming-convention -- class name
9+
export const ESLint = getESLint();

tests/utils/utils.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export function loadTestCases(
112112
writeFixtures(ruleName, inputFile);
113113
output = fs.readFileSync(outputFile, "utf8");
114114
}
115-
config.output = output;
115+
config.output = output === config.code ? null : output;
116116
}
117117

118118
return config;
@@ -143,7 +143,9 @@ export function loadTestCases(
143143
)) {
144144
it(test.filename || test.code, () => {
145145
const input = yamlESLintParser.parseForESLint(test.code);
146-
const output = yamlESLintParser.parseForESLint(test.output);
146+
const output = yamlESLintParser.parseForESLint(
147+
test.output === null ? test.code : test.output,
148+
);
147149
assert.deepStrictEqual(
148150
yamlESLintParser.getStaticYAMLValue(input.ast),
149151
yamlESLintParser.getStaticYAMLValue(output.ast),

0 commit comments

Comments
 (0)