@pplancq/eslint-config 6.1.4 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,34 @@
1
+ ## 6.2.0 (2026-10-26)
2
+
3
+ ### 🎉 Features
4
+
5
+ - **eslint-config:** migrate import rules to eslint-plugin-import-x ([#1938](https://github.com/pplancq/dev-tools/pull/1938))
6
+ - **eslint-config:** migrate JSX a11y rules to eslint-plugin-jsx-a11y-x ([#1937](https://github.com/pplancq/dev-tools/pull/1937))
7
+
8
+ ### 🐞 Bug Fixes
9
+
10
+ - **eslint-config:** support disableStyleOnly without eslint-plugin-prettier ([#1956](https://github.com/pplancq/dev-tools/pull/1956))
11
+ - **eslint-config:** remove unneeded eslint-import-resolver-node dependency ([#1939](https://github.com/pplancq/dev-tools/pull/1939))
12
+
13
+ ### 📦 Dependencies
14
+
15
+ - **deps:** update typescript-eslint mono repo to ^8.71.2 ([#1952](https://github.com/pplancq/dev-tools/pull/1952))
16
+ - **deps:** update dependency @vitest/eslint-plugin to ^1.6.28 ([#1962](https://github.com/pplancq/dev-tools/pull/1962))
17
+ - **deps:** update typescript-eslint mono repo to ^8.71.1 ([#1934](https://github.com/pplancq/dev-tools/pull/1934))
18
+ - **deps:** update dependency eslint-plugin-playwright to ^2.12.1 ([#1932](https://github.com/pplancq/dev-tools/pull/1932))
19
+
20
+ ### ❤️ Thank You
21
+
22
+ - Paul PLANCQ
23
+ - pplancq @pplancq
24
+
25
+ ## 6.1.5 (2026-10-06)
26
+
27
+ ### 📦 Dependencies
28
+
29
+ - **deps:** update dependency globals to ^17.13.0 ([#1922](https://github.com/pplancq/dev-tools/pull/1922))
30
+ - **deps:** update typescript-eslint mono repo to ^8.71.0 ([#1924](https://github.com/pplancq/dev-tools/pull/1924))
31
+
1
32
  ## 6.1.4 (2026-09-30)
2
33
 
3
34
  ### 📦 Dependencies
package/README.md CHANGED
@@ -48,10 +48,24 @@ The following options can be passed to the `defineConfig` function. All options
48
48
  | unitTestFiles | ['**/*.{test,spec,steps}.{js,jsx,ts,tsx}'] | Patterns for unit test files |
49
49
  | unitE2eFiles | ['tests/**/*.{test,spec}.{js,jsx,ts,tsx}'] | Patterns for end-to-end (E2E) test files (ex: Playwright) |
50
50
  | enableReact | false | Enables rules for React and Testing Library files |
51
+ | rulesNaming | 'legacy' | Naming of the rules of the plugins replaced by a fork (`eslint-plugin-import-x` and `eslint-plugin-jsx-a11y-x`). 'legacy' (default) keeps the historical rule names (`import/xxx`, `jsx-a11y/xxx`)<br/>'modern' uses the forks namespaces (`import-x/xxx`, `jsx-a11y-x/xxx`), as listed in the [rules documentation](./docs/rules.md). See [Rules naming](#rules-naming) |
51
52
  | enableVitest | false | Enables rules for Vitest files |
52
53
  | enablePlaywright | false | Enables rules for Playwright E2E test files |
53
54
  | enablePrettier | 'off' | 'off' disables Prettier integration (default). Recommended when using Prettier separately; install `eslint-config-prettier` to disable conflicting ESLint formatting rules<br/>'on' enables Prettier as an ESLint rule. **Deprecated**, will be removed in the next major release<br/>'disableStyleOnly' disables conflicting ESLint formatting rules without running Prettier as an ESLint rule. Recommended transition option to keep the same behavior as `'on'` while running Prettier separately |
54
- | extendConfig | [] | Extends the ESLint configuration |
55
+ | extendConfig | [] | Extends the ESLint configuration. With `rulesNaming: 'legacy'`, the `import/*` settings it contains are copied to `import-x/*` |
56
+
57
+ ### Rules naming
58
+
59
+ The `import` and `jsx-a11y` plugins are replaced by their maintained forks, [`eslint-plugin-import-x`](https://github.com/un-ts/eslint-plugin-import-x) and [`eslint-plugin-jsx-a11y-x`](https://github.com/eslint-community/eslint-plugin-jsx-a11y-x), which support ESLint 10. The `rulesNaming` option lets you migrate without breaking your configuration:
60
+
61
+ | `rulesNaming` | Rules | Settings |
62
+ | -------------------- | -------------------------------- | ------------------------ |
63
+ | `'legacy'` (default) | `import/xxx`, `jsx-a11y/xxx` | `import-x/*` (see below) |
64
+ | `'modern'` | `import-x/xxx`, `jsx-a11y-x/xxx` | `import-x/*` |
65
+
66
+ - The [rules documentation](./docs/rules.md) lists the `modern` names. With `'legacy'`, replace `import-x/` by `import/` and `jsx-a11y-x/` by `jsx-a11y/`.
67
+ - `eslint-plugin-import-x` only reads the `import-x/*` settings, whatever the rules namespace. In `legacy` mode, the `import/*` settings found in `extendConfig` (for example `import/resolver`) are copied automatically to `import-x/*` and a warning lists them.
68
+ - The default will become `'modern'` in the next major release. See the [Migration Guide](./MIGRATION.md#rules-naming-rulesnaming) to migrate now.
55
69
 
56
70
  ### Prettier Configuration
57
71
 
@@ -82,4 +96,6 @@ For a complete list of all active ESLint rules in each configuration, please ref
82
96
 
83
97
  ## Migration
84
98
 
99
+ To switch to the forks naming (`rulesNaming: 'modern'`), please refer to the [Migration Guide](./MIGRATION.md#rules-naming-rulesnaming).
100
+
85
101
  If you are upgrading from version 3 to version 4 of `@pplancq/eslint-config`, please refer to the [Migration Guide](./MIGRATION.md#migration-guide-pplancqeslint-config-v3-to-v4) for detailed instructions.
package/main.js CHANGED
@@ -6,12 +6,13 @@ import { playwrightRules } from "./rules/playwright.js";
6
6
  import { reactJsxA11yRules } from "./rules/react-jsx-a11y.js";
7
7
  import { reactRules, reactTestRules, reactTypescriptRules } from "./rules/react.js";
8
8
  import { typescriptRules } from "./rules/typescript.js";
9
+ import { mapLegacyImportSettings, prefix } from "./rules/utils.js";
9
10
  import { vitestRules } from "./rules/vitest.js";
10
11
 
11
- let prettierRules = {};
12
+ let createPrettierRules = () => ({});
12
13
  try {
13
14
  const prettierConfig = await import("./rules/prettier.js");
14
- prettierRules = prettierConfig.prettierRules;
15
+ createPrettierRules = prettierConfig.prettierRules;
15
16
  } catch {
16
17
  // eslint-plugin-prettier is not installed
17
18
  }
@@ -27,6 +28,49 @@ const isColorSupported =
27
28
  const yellow = isColorSupported ? (text) => `\x1b[33m${text}\x1b[39m` : (text) => text;
28
29
  const bold = isColorSupported ? (text) => `\x1b[1m${text}\x1b[22m` : (text) => text;
29
30
 
31
+ const warn = (message) => console.warn(`${bold(yellow("WARNING:"))} ${message}`);
32
+
33
+ const resolveNamespaces = (rulesNaming) => {
34
+ const modern = rulesNaming === "modern";
35
+
36
+ return {
37
+ jsxA11y: modern ? "jsx-a11y-x" : "jsx-a11y",
38
+ import: modern ? "import-x" : "import",
39
+ };
40
+ };
41
+
42
+ const warnLegacyNaming = (enableReact) => {
43
+ const legacyNames = enableReact ? "'import/xxx' and 'jsx-a11y/xxx'" : "'import/xxx'";
44
+ const modernNames = enableReact ? "'import-x/xxx' and 'jsx-a11y-x/xxx'" : "'import-x/xxx'";
45
+
46
+ warn(
47
+ `[rulesNaming: 'legacy'] the rules use the legacy ${legacyNames} names. In the next major release, the default will become 'modern' (${modernNames}). Set rulesNaming: 'modern' to migrate now.`,
48
+ );
49
+ };
50
+
51
+ const resolvePrettierRules = (enablePrettier) => {
52
+ const prettierRules = createPrettierRules();
53
+
54
+ if (enablePrettier === "disableStyleOnly" && prettierRules.rules?.["prettier/prettier"] !== undefined) {
55
+ prettierRules.rules["prettier/prettier"] = "off";
56
+ }
57
+
58
+ return prettierRules;
59
+ };
60
+
61
+ const resolveExtendConfig = (extendConfig) => {
62
+ const { configs, mapped } = mapLegacyImportSettings(extendConfig);
63
+
64
+ if (mapped.length > 0) {
65
+ const settings = mapped.map((setting) => `'${setting}'`).join(", ");
66
+ warn(
67
+ `[rulesNaming: 'legacy'] eslint-plugin-import-x only reads the 'import-x/*' settings. The following settings were copied automatically: ${settings}. Rename them to 'import-x/*' in your configuration.`,
68
+ );
69
+ }
70
+
71
+ return configs;
72
+ };
73
+
30
74
  /**
31
75
  * define eslint flat config.
32
76
  *
@@ -35,6 +79,12 @@ const bold = isColorSupported ? (text) => `\x1b[1m${text}\x1b[22m` : (text) => t
35
79
  * @param {string[]} [options.unitTestFiles=['**\/*.{test,spec,steps}.{js,jsx,ts,tsx}']]
36
80
  * @param {string[]} [options.unitE2eFiles=['tests/**\/*.{test,spec}.{js,jsx,ts,tsx}']]
37
81
  * @param {boolean} [options.enableReact=false]
82
+ * @param {'legacy' | 'modern'} [options.rulesNaming='legacy']
83
+ * - `'legacy'`: registers `eslint-plugin-import-x` under the `import` namespace (rules named `import/xxx`)
84
+ * and `eslint-plugin-jsx-a11y-x` under the `jsx-a11y` namespace (rules named `jsx-a11y/xxx`).
85
+ * The `import/*` settings found in `extendConfig` are copied to `import-x/*`, the only prefix `eslint-plugin-import-x` reads.
86
+ * - `'modern'`: registers `eslint-plugin-import-x` under its own namespace (rules named `import-x/xxx`)
87
+ * and `eslint-plugin-jsx-a11y-x` under its own namespace (rules named `jsx-a11y-x/xxx`).
38
88
  * @param {boolean} [options.enableVitest=false]
39
89
  * @param {boolean} [options.enablePlaywright=false]
40
90
  * @param {'off' | 'on' | 'disableStyleOnly'} [options.enablePrettier='off']
@@ -54,46 +104,52 @@ export const defineConfig = ({
54
104
  unitTestFiles = ["**/*.{test,spec,steps}.{js,jsx,ts,tsx}"],
55
105
  unitE2eFiles = ["tests/**/*.{test,spec}.{js,jsx,ts,tsx}"],
56
106
  enableReact = false,
107
+ rulesNaming = "legacy",
57
108
  enableVitest = false,
58
109
  enablePlaywright = false,
59
110
  enablePrettier = "off",
60
111
  extendConfig = [],
61
112
  } = {}) => {
62
- typescriptRules.files = tsFiles;
63
- reactTypescriptRules.files = tsFiles;
64
- reactTestRules.files = unitTestFiles;
65
- vitestRules.files = unitTestFiles;
66
- playwrightRules.files = unitE2eFiles;
113
+ const ns = resolveNamespaces(rulesNaming);
114
+ const legacyNaming = rulesNaming === "legacy";
67
115
 
68
116
  if (enablePrettier === "on") {
69
- console.warn(
70
- `${bold(yellow("WARNING:"))} [enablePrettier: 'on'] is deprecated and will be removed in the next major release. Use 'disableStyleOnly' and run Prettier separately for formatting.`,
117
+ warn(
118
+ "[enablePrettier: 'on'] is deprecated and will be removed in the next major release. Use 'disableStyleOnly' and run Prettier separately for formatting.",
71
119
  );
72
120
  }
73
121
 
74
- if (enablePrettier === "disableStyleOnly") {
75
- prettierRules.rules["prettier/prettier"] = "off";
122
+ if (legacyNaming) {
123
+ warnLegacyNaming(enableReact);
76
124
  }
77
125
 
126
+ const extendedConfig = legacyNaming ? resolveExtendConfig(extendConfig) : extendConfig;
127
+
128
+ const prettierRules = resolvePrettierRules(enablePrettier);
129
+
78
130
  return [
79
- importRules,
80
- baseRules,
81
- enableReact && reactJsxA11yRules,
82
- typescriptRules,
83
- enableReact && reactRules,
84
- enableReact && reactTypescriptRules,
85
- enableReact && reactTestRules,
131
+ importRules(ns),
132
+ baseRules(),
133
+ enableReact && reactJsxA11yRules(ns),
134
+ typescriptRules({ files: tsFiles, ...ns }),
135
+ enableReact && reactRules(ns),
136
+ enableReact && reactTypescriptRules({ files: tsFiles, ...ns }),
137
+ enableReact && reactTestRules({ files: unitTestFiles }),
86
138
  enablePrettier !== "off" && prettierRules,
87
139
  enablePrettier !== "off" && eslintConfigPrettier,
88
- enableVitest && vitestRules,
89
- enablePlaywright && playwrightRules,
140
+ enableVitest && vitestRules({ files: unitTestFiles, ...ns }),
141
+ enablePlaywright && playwrightRules({ files: unitE2eFiles }),
90
142
  {
91
143
  files: ["eslint.config.*"],
92
- rules: {
93
- "import/no-extraneous-dependencies": "off",
94
- "import/no-default-export": "off",
95
- },
144
+ rules: prefix(
145
+ {
146
+ "import-x/no-extraneous-dependencies": "off",
147
+ "import-x/no-default-export": "off",
148
+ },
149
+ "import-x",
150
+ ns.import,
151
+ ),
96
152
  },
97
- ...extendConfig,
153
+ ...extendedConfig,
98
154
  ].filter(Boolean);
99
155
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pplancq/eslint-config",
3
- "version": "6.1.4",
3
+ "version": "6.2.0",
4
4
  "license": "MIT",
5
5
  "description": "pplancq eslint config",
6
6
  "author": "pplancq <paul.plancq@outlook.fr>",
@@ -11,6 +11,8 @@
11
11
  },
12
12
  "scripts": {
13
13
  "docs:generate": "node scripts/generate-docs.mjs",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
14
16
  "lint:eslint": "eslint \"**/*.{js,mjs}\"",
15
17
  "lint:eslint:fix": "eslint \"**/*.{js,mjs}\" --fix",
16
18
  "lint:prettier": "prettier . --check --ignore-unknown",
@@ -37,19 +39,19 @@
37
39
  "config"
38
40
  ],
39
41
  "dependencies": {
40
- "@typescript-eslint/eslint-plugin": "^8.70.1",
41
- "@typescript-eslint/parser": "^8.70.1",
42
- "@vitest/eslint-plugin": "^1.6.27",
42
+ "@typescript-eslint/eslint-plugin": "^8.71.2",
43
+ "@typescript-eslint/parser": "^8.71.2",
44
+ "@vitest/eslint-plugin": "^1.6.28",
43
45
  "eslint-config-prettier": "^10.1.8",
44
46
  "eslint-import-resolver-typescript": "^4.4.5",
45
- "eslint-plugin-import": "^2.32.0",
47
+ "eslint-plugin-import-x": "^4.17.1",
46
48
  "eslint-plugin-jest-dom": "^5.10.1",
47
- "eslint-plugin-jsx-a11y": "^6.10.2",
48
- "eslint-plugin-playwright": "^2.12.0",
49
+ "eslint-plugin-jsx-a11y-x": "^0.2.0",
50
+ "eslint-plugin-playwright": "^2.12.1",
49
51
  "eslint-plugin-react": "^7.37.5",
50
52
  "eslint-plugin-react-hooks": "^7.1.1",
51
53
  "eslint-plugin-testing-library": "^7.16.2",
52
- "globals": "^17.12.0"
54
+ "globals": "^17.13.0"
53
55
  },
54
56
  "peerDependencies": {
55
57
  "eslint": "^9.14.0",
@@ -65,9 +67,10 @@
65
67
  },
66
68
  "devDependencies": {
67
69
  "eslint": "^9.39.5",
68
- "eslint-plugin-prettier": "^5.5.6",
69
- "lint-staged": "^17.5.1",
70
- "prettier": "^3.9.9"
70
+ "eslint-plugin-prettier": "^5.5.7",
71
+ "lint-staged": "^17.6.0",
72
+ "prettier": "^3.9.10",
73
+ "vitest": "^5.0.5"
71
74
  },
72
75
  "engines": {
73
76
  "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
package/rules/base.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import globals from "globals";
2
2
 
3
- export const baseRules = {
3
+ export const baseRules = () => ({
4
4
  languageOptions: {
5
5
  ecmaVersion: "latest",
6
6
  sourceType: "module",
@@ -1455,4 +1455,4 @@ export const baseRules = {
1455
1455
  "wrap-regex": "off",
1456
1456
  "yield-star-spacing": ["error", "after"],
1457
1457
  },
1458
- };
1458
+ });