@ethang/eslint-config 19.2.7 → 19.2.9

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/README.md CHANGED
@@ -5,9 +5,9 @@
5
5
  > [!CAUTION]
6
6
  > Do not use this with Prettier! Styling rules are included.
7
7
 
8
- - 883 errored rules.
8
+ - 885 errored rules.
9
9
  - 289 rules from [eslint-plugin-sonarjs](https://github.com/SonarSource/SonarJS/blob/master/packages/jsts/src/rules/README.md)
10
- - 144 rules from [@eslint/js](https://github.com/eslint/eslint/tree/main/packages/js)
10
+ - 145 rules from [@eslint/js](https://github.com/eslint/eslint/tree/main/packages/js)
11
11
  - 113 rules from [sindresorhus/eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn)
12
12
  - 104 rules from [@typescript/eslint](https://github.com/typescript-eslint/typescript-eslint)
13
13
  - 91 rules from [@stylistic/eslint-plugin](https://eslint.style/)
@@ -22,6 +22,7 @@
22
22
  - 2 rules from [@eslint/json](https://github.com/eslint/json)
23
23
  - 1 rule from [eslint-plugin-depend](https://github.com/es-tooling/eslint-plugin-depend/tree/main)
24
24
  - 1 rule from [eslint-plugin-compat](https://github.com/amilajack/eslint-plugin-compat)
25
+ - 1 rule from [@ethang/eslint-plugin](https://github.com/eglove/eslint-plugin)
25
26
 
26
27
  # Add Even More!
27
28
 
@@ -0,0 +1,45 @@
1
+ import { getTypeImportStrings } from "./list-utils.mjs";
2
+ import { createConfig } from "./create-config.js";
3
+ import { writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+
6
+ export const createConfigFile = async (listConfigs, fileName) => {
7
+ let configFile = "";
8
+
9
+ const imports = listConfigs
10
+ .map((list) => {
11
+ const importStrings = getTypeImportStrings(list.name);
12
+
13
+ if (list.options?.extraImports?.length > 0) {
14
+ importStrings.push(...list.options.extraImports);
15
+ }
16
+
17
+ return importStrings;
18
+ })
19
+ .flat();
20
+
21
+ const importList = [
22
+ 'import { ignores, languageOptions } from "./constants.js";',
23
+ ...imports,
24
+ ].sort((a, b) => a.localeCompare(b));
25
+
26
+ importList.forEach((item) => {
27
+ configFile += `${item}\n`;
28
+ });
29
+
30
+ const configs = await Promise.all(
31
+ listConfigs.map((list) => {
32
+ return createConfig(list.name, list.options);
33
+ }),
34
+ );
35
+
36
+ configFile += `\nexport default tseslint.config(
37
+ ${configs.join("\n")}
38
+ );\n`;
39
+
40
+ writeFileSync(
41
+ join(import.meta.dirname, `../${fileName}`),
42
+ configFile,
43
+ "utf8",
44
+ );
45
+ };
@@ -0,0 +1,50 @@
1
+ import {
2
+ getList,
3
+ getListJson,
4
+ getListPlugins,
5
+ getTypeFiles,
6
+ } from "./list-utils.mjs";
7
+ import { getLatestReact } from "./get-react-version.js";
8
+
9
+ export const createConfig = async (type, options = {}) => {
10
+ let config = "";
11
+ let settings;
12
+
13
+ if (options.includeReactVersion) {
14
+ const react = await getLatestReact();
15
+ settings = JSON.stringify({
16
+ react: { version: react.version },
17
+ }).slice(1, -1);
18
+ }
19
+
20
+ const list = getList(type);
21
+ const ruleJson = getListJson(list);
22
+
23
+ let optionals = "";
24
+
25
+ if (options.includeIgnores) {
26
+ optionals += "\nignores,";
27
+ }
28
+
29
+ if (options.includeLanguageOptions) {
30
+ optionals += "\nlanguageOptions,";
31
+ }
32
+
33
+ if (options.includeReactVersion && settings) {
34
+ optionals += `\nsettings: {
35
+ ${settings}
36
+ },`;
37
+ }
38
+
39
+ config += `{
40
+ files: ["${getTypeFiles(type)}"],${optionals}
41
+ plugins: {
42
+ ${getListPlugins(list)}
43
+ },
44
+ rules: {
45
+ ${ruleJson}
46
+ },
47
+ },`;
48
+
49
+ return config;
50
+ };
@@ -0,0 +1,70 @@
1
+ import { ruleList } from "./rule-list.mjs";
2
+
3
+ export const getList = (type) => {
4
+ return ruleList
5
+ .filter((list) => list.type === type)
6
+ .sort((a, b) => a.order - b.order);
7
+ };
8
+
9
+ export const getListImportStrings = (list) => {
10
+ return list
11
+ .map((item) => {
12
+ return item.importString;
13
+ })
14
+ .filter(Boolean);
15
+ };
16
+
17
+ export const getTypeImportStrings = (type) => {
18
+ return ruleList
19
+ .filter((list) => list.type === type)
20
+ .map((item) => item.importString)
21
+ .filter(Boolean);
22
+ };
23
+
24
+ export const getListJson = (list) => {
25
+ return list
26
+ .map((list) => {
27
+ return JSON.stringify(list.list).slice(1, -1);
28
+ })
29
+ .join(",");
30
+ };
31
+
32
+ export const getTypeFiles = (type) => {
33
+ switch (type) {
34
+ case "core": {
35
+ return ["**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts}"];
36
+ }
37
+
38
+ case "markdown": {
39
+ return ["**/*.md"];
40
+ }
41
+
42
+ case "json": {
43
+ return ["**/*.{json,jsonc,json5}"];
44
+ }
45
+
46
+ case "react": {
47
+ return ["**/*.{jsx,tsx}"];
48
+ }
49
+
50
+ case "astro": {
51
+ return ["**/*.{astro}"];
52
+ }
53
+
54
+ case "solid": {
55
+ return ["**/*.{jsx,tsx}"];
56
+ }
57
+ }
58
+ };
59
+
60
+ export const getListPlugins = (list) => {
61
+ let pluginString = "";
62
+
63
+ for (const item of list) {
64
+ if (item.pluginName && item.pluginValue) {
65
+ pluginString += `"${item.pluginName}": ${item.pluginValue},`;
66
+ }
67
+ }
68
+
69
+ return pluginString;
70
+ };
@@ -0,0 +1,240 @@
1
+ import { dependRules } from "../setup/depend.js";
2
+ import { barrelRules } from "../setup/barrel.js";
3
+ import { compatRules } from "../setup/compat.js";
4
+ import { eslintRules } from "../setup/eslint.js";
5
+ import { nRules } from "../setup/n.js";
6
+ import { typescriptRules } from "../setup/typescript-eslint.js";
7
+ import { unicornRules } from "../setup/unicorn.js";
8
+ import { lodashRules } from "../setup/lodash.js";
9
+ import { sonarRules } from "../setup/sonar.js";
10
+ import { tanstackQueryRules } from "../setup/tanstack-query.js";
11
+ import { tailwindRules } from "../setup/tailwind.js";
12
+ import { stylisticRules } from "../setup/stylistic.js";
13
+ import { perfectionistRules } from "../setup/perfectionist.js";
14
+ import { a11yRules } from "../setup/a11y.js";
15
+ import { markdownRules } from "../setup/markdown.js";
16
+ import { jsonRules } from "../setup/json.js";
17
+ import { ethangRules } from "../setup/ethang.js";
18
+ import { astroRules } from "../setup/astro.js";
19
+ import { reactHookRules, reactRules } from "../setup/react.js";
20
+ import { solidRules } from "../setup/solid.js";
21
+ import { deprecatedRules } from "../setup/deprecated.js";
22
+
23
+ export const ruleList = [
24
+ {
25
+ list: dependRules,
26
+ name: "eslint-plugin-depend",
27
+ url: "https://github.com/es-tooling/eslint-plugin-depend/tree/main",
28
+ type: "core",
29
+ importString: 'import depend from "eslint-plugin-depend";',
30
+ order: 0,
31
+ pluginName: "depend",
32
+ pluginValue: "depend",
33
+ },
34
+ {
35
+ list: barrelRules,
36
+ name: "eslint-plugin-barrel-files",
37
+ url: "https://github.com/thepassle/eslint-plugin-barrel-files",
38
+ type: "core",
39
+ importString: 'import barrel from "eslint-plugin-barrel-files";',
40
+ order: 1,
41
+ pluginName: "barrel",
42
+ pluginValue: "barrel",
43
+ },
44
+ {
45
+ list: compatRules,
46
+ name: "eslint-plugin-compat",
47
+ url: "https://github.com/amilajack/eslint-plugin-compat",
48
+ type: "core",
49
+ importString: 'import compat from "eslint-plugin-compat";',
50
+ order: 2,
51
+ pluginName: "compat",
52
+ pluginValue: "compat",
53
+ },
54
+ {
55
+ list: eslintRules,
56
+ name: "@eslint/js",
57
+ url: "https://github.com/eslint/eslint/tree/main/packages/js",
58
+ type: "core",
59
+ importString: undefined,
60
+ order: 3,
61
+ pluginName: undefined,
62
+ pluginValue: undefined,
63
+ },
64
+ {
65
+ list: nRules,
66
+ name: "eslint-plugin-n",
67
+ url: "https://github.com/eslint-community/eslint-plugin-n",
68
+ type: "core",
69
+ importString: 'import n from "eslint-plugin-n";',
70
+ order: 4,
71
+ pluginName: "n",
72
+ pluginValue: "n",
73
+ },
74
+ {
75
+ list: typescriptRules,
76
+ name: "@typescript/eslint",
77
+ url: "https://github.com/typescript-eslint/typescript-eslint",
78
+ type: "core",
79
+ importString: 'import tseslint from "typescript-eslint";',
80
+ order: 5,
81
+ pluginName: "@typescript-eslint",
82
+ pluginValue: "tseslint.plugin",
83
+ },
84
+ {
85
+ list: unicornRules,
86
+ name: "sindresorhus/eslint-plugin-unicorn",
87
+ url: "https://github.com/sindresorhus/eslint-plugin-unicorn",
88
+ type: "core",
89
+ importString: 'import unicorn from "eslint-plugin-unicorn";',
90
+ order: 6,
91
+ pluginName: "unicorn",
92
+ pluginValue: "unicorn",
93
+ },
94
+ {
95
+ list: lodashRules,
96
+ name: "eslint-plugin-lodash",
97
+ url: "https://github.com/wix-incubator/eslint-plugin-lodash",
98
+ type: "core",
99
+ importString: 'import lodashConfig from "eslint-plugin-lodash";',
100
+ order: 7,
101
+ pluginName: "lodash",
102
+ pluginValue: "lodashConfig",
103
+ },
104
+ {
105
+ list: sonarRules,
106
+ name: "eslint-plugin-sonarjs",
107
+ url: "https://github.com/SonarSource/SonarJS/blob/master/packages/jsts/src/rules/README.md",
108
+ type: "core",
109
+ importString: 'import sonar from "eslint-plugin-sonarjs";',
110
+ order: 8,
111
+ pluginName: "sonar",
112
+ pluginValue: "sonar",
113
+ },
114
+ {
115
+ list: ethangRules,
116
+ name: "@ethang/eslint-plugin",
117
+ url: "https://github.com/eglove/eslint-plugin",
118
+ type: "core",
119
+ importString: 'import ethang from "@ethang/eslint-plugin";',
120
+ order: 9,
121
+ pluginName: "ethang",
122
+ pluginValue: "ethang",
123
+ },
124
+ {
125
+ list: tanstackQueryRules,
126
+ name: "@tanstack/eslint-plugin-query",
127
+ url: "https://tanstack.com/query/latest/docs/eslint/eslint-plugin-query",
128
+ type: "core",
129
+ importString: 'import tanstack from "@tanstack/eslint-plugin-query";',
130
+ order: 10,
131
+ pluginName: "@tanstack/query",
132
+ pluginValue: "tanstack",
133
+ },
134
+ {
135
+ list: tailwindRules,
136
+ name: "eslint-plugin-tailwindcss",
137
+ url: "https://github.com/francoismassart/eslint-plugin-tailwindcss",
138
+ type: "core",
139
+ importString: 'import tailwind from "eslint-plugin-tailwindcss";',
140
+ order: 11,
141
+ pluginName: "tailwind",
142
+ pluginValue: "tailwind",
143
+ },
144
+ {
145
+ list: stylisticRules,
146
+ name: "@stylistic/eslint-plugin",
147
+ url: "https://eslint.style/",
148
+ type: "core",
149
+ importString: 'import stylistic from "@stylistic/eslint-plugin";',
150
+ order: 12,
151
+ pluginName: "stylistic",
152
+ pluginValue: "stylistic",
153
+ },
154
+ {
155
+ list: perfectionistRules,
156
+ name: "eslint-plugin-perfectionist",
157
+ url: "https://github.com/azat-io/eslint-plugin-perfectionist",
158
+ type: "core",
159
+ importString: 'import perfectionist from "eslint-plugin-perfectionist";',
160
+ order: 13,
161
+ pluginName: "perfectionist",
162
+ pluginValue: "perfectionist",
163
+ },
164
+ {
165
+ list: a11yRules,
166
+ name: "jsx-a11y",
167
+ url: "https://github.com/jsx-eslint/eslint-plugin-jsx-a11y",
168
+ type: "core",
169
+ importString: 'import a11y from "eslint-plugin-jsx-a11y/lib/index.js";',
170
+ order: 14,
171
+ pluginName: "a11y",
172
+ pluginValue: "a11y",
173
+ },
174
+ {
175
+ list: deprecatedRules,
176
+ name: "@eslint/js",
177
+ url: "https://github.com/eslint/eslint/tree/main/packages/js",
178
+ type: "core",
179
+ importString: undefined,
180
+ order: 15,
181
+ pluginName: undefined,
182
+ pluginValue: undefined,
183
+ },
184
+ {
185
+ list: markdownRules,
186
+ name: "@eslint/markdown",
187
+ url: "https://github.com/eslint/markdown",
188
+ type: "markdown",
189
+ importString: 'import markdown from "@eslint/markdown";',
190
+ order: 0,
191
+ pluginName: "markdown",
192
+ pluginValue: "markdown",
193
+ },
194
+ {
195
+ list: jsonRules,
196
+ name: "@eslint/json",
197
+ url: "https://github.com/eslint/json",
198
+ type: "json",
199
+ importString: 'import json from "@eslint/json";',
200
+ order: 0,
201
+ pluginName: "json",
202
+ pluginValue: "json",
203
+ },
204
+ {
205
+ list: astroRules,
206
+ name: "eslint-plugin-astro",
207
+ url: "https://github.com/ota-meshi/eslint-plugin-astro",
208
+ type: "astro",
209
+ importString: 'import astro from "eslint-plugin-astro";',
210
+ pluginName: "astro",
211
+ pluginValue: "astro",
212
+ },
213
+ {
214
+ list: reactRules,
215
+ name: "@eslint-react/eslint-plugin",
216
+ url: "https://eslint-react.xyz/",
217
+ type: "react",
218
+ importString: 'import react from "@eslint-react/eslint-plugin";',
219
+ pluginName: "react",
220
+ pluginValue: "react",
221
+ },
222
+ {
223
+ list: reactHookRules,
224
+ name: "eslint-plugin-react-hooks",
225
+ url: "https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks",
226
+ type: "react",
227
+ importString: 'import reactHooks from "eslint-plugin-react-hooks";',
228
+ pluginName: "react-hooks",
229
+ pluginValue: "reactHooks",
230
+ },
231
+ {
232
+ list: solidRules,
233
+ name: "eslint-plugin-solid",
234
+ url: "https://github.com/solidjs-community/eslint-plugin-solid",
235
+ type: "solid",
236
+ importString: 'import solid from "eslint-plugin-solid";',
237
+ pluginName: "solid",
238
+ pluginValue: "solid",
239
+ },
240
+ ];
@@ -1,25 +1,7 @@
1
- import { dependRules } from "../setup/depend.js";
2
- import { barrelRules } from "../setup/barrel.js";
3
- import { compatRules } from "../setup/compat.js";
4
- import { eslintRules } from "../setup/eslint.js";
5
- import { nRules } from "../setup/n.js";
6
- import { typescriptRules } from "../setup/typescript-eslint.js";
7
- import { unicornRules } from "../setup/unicorn.js";
8
- import { lodashRules } from "../setup/lodash.js";
9
- import { sonarRules } from "../setup/sonar.js";
10
- import { tanstackQueryRules } from "../setup/tanstack-query.js";
11
- import { tailwindRules } from "../setup/tailwind.js";
12
- import { stylisticRules } from "../setup/stylistic.js";
13
- import { perfectionistRules } from "../setup/perfectionist.js";
14
- import { a11yRules } from "../setup/a11y.js";
15
1
  import { writeFileSync } from "node:fs";
16
2
  import { join } from "node:path";
17
3
  import { MarkdownGenerator } from "@ethang/markdown-generator/markdown-generator.js";
18
- import { markdownRules } from "../setup/markdown.js";
19
- import { jsonRules } from "../setup/json.js";
20
- import { astroRules } from "../setup/astro.js";
21
- import { reactRules } from "../setup/react.js";
22
- import { solidRules } from "../setup/solid.js";
4
+ import { getList } from "./list-utils.mjs";
23
5
 
24
6
  export const updateReadme = () => {
25
7
  const md = new MarkdownGenerator();
@@ -42,109 +24,51 @@ export const updateReadme = () => {
42
24
  return count;
43
25
  };
44
26
 
45
- const ruleList = [
46
- {
47
- list: dependRules,
48
- name: "eslint-plugin-depend",
49
- url: "https://github.com/es-tooling/eslint-plugin-depend/tree/main",
50
- },
51
- {
52
- list: barrelRules,
53
- name: "eslint-plugin-barrel-files",
54
- url: "https://github.com/thepassle/eslint-plugin-barrel-files",
55
- },
56
- {
57
- list: compatRules,
58
- name: "eslint-plugin-compat",
59
- url: "https://github.com/amilajack/eslint-plugin-compat",
60
- },
61
- {
62
- list: eslintRules,
63
- name: "@eslint/js",
64
- url: "https://github.com/eslint/eslint/tree/main/packages/js",
65
- },
66
- {
67
- list: nRules,
68
- name: "eslint-plugin-n",
69
- url: "https://github.com/eslint-community/eslint-plugin-n",
70
- },
71
- {
72
- list: typescriptRules,
73
- name: "@typescript/eslint",
74
- url: "https://github.com/typescript-eslint/typescript-eslint",
75
- },
76
- {
77
- list: unicornRules,
78
- name: "sindresorhus/eslint-plugin-unicorn",
79
- url: "https://github.com/sindresorhus/eslint-plugin-unicorn",
80
- },
81
- {
82
- list: lodashRules,
83
- name: "eslint-plugin-lodash",
84
- url: "https://github.com/wix-incubator/eslint-plugin-lodash",
85
- },
86
- {
87
- list: sonarRules,
88
- name: "eslint-plugin-sonarjs",
89
- url: "https://github.com/SonarSource/SonarJS/blob/master/packages/jsts/src/rules/README.md",
90
- },
91
- {
92
- list: tanstackQueryRules,
93
- name: "@tanstack/eslint-plugin-query",
94
- url: "https://tanstack.com/query/latest/docs/eslint/eslint-plugin-query",
95
- },
96
- {
97
- list: tailwindRules,
98
- name: "eslint-plugin-tailwindcss",
99
- url: "https://github.com/francoismassart/eslint-plugin-tailwindcss",
100
- },
101
- {
102
- list: stylisticRules,
103
- name: "@stylistic/eslint-plugin",
104
- url: "https://eslint.style/",
105
- },
106
- {
107
- list: perfectionistRules,
108
- name: "eslint-plugin-perfectionist",
109
- url: "https://github.com/azat-io/eslint-plugin-perfectionist",
110
- },
111
- {
112
- list: a11yRules,
113
- name: "jsx-a11y",
114
- url: "https://github.com/jsx-eslint/eslint-plugin-jsx-a11y",
115
- },
116
- {
117
- list: markdownRules,
118
- name: "@eslint/markdown",
119
- url: "https://github.com/eslint/markdown",
120
- },
121
- {
122
- list: jsonRules,
123
- name: "@eslint/json",
124
- url: "https://github.com/eslint/json",
125
- },
27
+ const coreRules = [
28
+ ...getList("core"),
29
+ ...getList("json"),
30
+ ...getList("markdown"),
126
31
  ];
127
32
 
128
33
  let total = 0;
129
- for (const list of ruleList) {
34
+ for (const list of coreRules) {
130
35
  const count = getRuleCount(list.list);
131
36
  total += count;
132
37
  list["count"] = count;
133
38
  }
134
- ruleList.sort((a, b) => {
39
+ coreRules.sort((a, b) => {
135
40
  return b.count - a.count;
136
41
  });
137
42
 
138
43
  const ruleDocs = [`${total} errored rules.`];
139
- for (const list of ruleList) {
44
+ for (const list of coreRules) {
45
+ if (list.count < 1) {
46
+ continue;
47
+ }
48
+
140
49
  ruleDocs.push(
141
50
  `${list.count} ${list.count <= 1 ? "rule" : "rules"} from [${list.name}](${list.url})`,
142
51
  );
143
52
  }
144
53
 
145
- const astroCount = getRuleCount(astroRules);
146
- const reactCount = getRuleCount(reactRules);
147
- const solidCount = getRuleCount(solidRules);
54
+ const astroRules = getList("astro");
55
+ const reactRules = getList("react");
56
+ const solidRules = getList("solid");
57
+
58
+ let astroCount = 0;
59
+ for (const astroRule of astroRules) {
60
+ astroCount += getRuleCount(astroRule.list);
61
+ }
62
+
63
+ let reactCount = 0;
64
+ for (const reactRule of reactRules) {
65
+ reactCount += getRuleCount(reactRule.list);
66
+ }
67
+
68
+ let solidCount = 0;
69
+ for (const solidRule of solidRules) {
70
+ solidCount += getRuleCount(solidRule.list);
71
+ }
148
72
 
149
73
  md.unorderedList(ruleDocs);
150
74
  md.newLine();
@@ -153,17 +77,29 @@ export const updateReadme = () => {
153
77
  `${astroCount} rules for **Astro**`,
154
78
  [
155
79
  '`import astroConfig from "@ethang/eslint-config/config.astro.js";`',
156
- `${astroCount} rules from [eslint-plugin-astro](https://github.com/ota-meshi/eslint-plugin-astro)`,
80
+ ...astroRules
81
+ .filter((rule) => getRuleCount(rule.list) > 0)
82
+ .map((rule) => {
83
+ return `${getRuleCount(rule.list)} rules from [${rule.name}](${rule.url})`;
84
+ }),
157
85
  ],
158
86
  `${reactCount} rules for **React**`,
159
87
  [
160
88
  '`import reactConfig from "@ethang/eslint-config/config.react.js";`',
161
- `${reactCount} rules from [@eslint-react/eslint-plugin](https://eslint-react.xyz/)`,
89
+ ...reactRules
90
+ .filter((rule) => getRuleCount(rule.list) > 0)
91
+ .map((rule) => {
92
+ return `${getRuleCount(rule.list)} rules from [${rule.name}](${rule.url})`;
93
+ }),
162
94
  ],
163
95
  `${solidCount} rules for **Solid**`,
164
96
  [
165
97
  '`import solidConfig from "@ethang/eslint-config/config.solid.js";`',
166
- `${solidCount} rules from [eslint-plugin-solid](https://github.com/solidjs-community/eslint-plugin-solid)`,
98
+ ...solidRules
99
+ .filter((rule) => getRuleCount(rule.list) > 0)
100
+ .map((rule) => {
101
+ return `${getRuleCount(rule.list)} rules from [${rule.name}](${rule.url})`;
102
+ }),
167
103
  ],
168
104
  ]);
169
105
  md.newLine();
@@ -1,135 +1,83 @@
1
- import { dependRules } from "../setup/depend.js";
2
- import { barrelRules } from "../setup/barrel.js";
3
- import { compatRules } from "../setup/compat.js";
4
- import { eslintRules } from "../setup/eslint.js";
5
- import { nRules } from "../setup/n.js";
6
- import { typescriptRules } from "../setup/typescript-eslint.js";
7
- import { unicornRules } from "../setup/unicorn.js";
8
- import { lodashRules } from "../setup/lodash.js";
9
- import { sonarRules } from "../setup/sonar.js";
10
- import { tanstackQueryRules } from "../setup/tanstack-query.js";
11
- import { tailwindRules } from "../setup/tailwind.js";
12
- import { stylisticRules } from "../setup/stylistic.js";
13
- import { perfectionistRules } from "../setup/perfectionist.js";
14
- import { a11yRules } from "../setup/a11y.js";
15
- import { writeFileSync } from "node:fs";
16
- import { join } from "node:path";
17
- import { deprecatedRules } from "../setup/deprecated.js";
18
- import { markdownRules } from "../setup/markdown.js";
19
- import { jsonRules } from "../setup/json.js";
20
- import { getLatestReact } from "./get-react-version.mjs";
1
+ import { createConfigFile } from "./create-config-file.js";
21
2
 
22
- export const updateRules = async () => {
23
- let configFile = "";
24
- const react = await getLatestReact();
25
- const settings = JSON.stringify({
26
- react: { version: react.version },
27
- }).slice(1, -1);
28
-
29
- const jsRules = {
30
- ...dependRules,
31
- ...barrelRules,
32
- ...compatRules,
33
- ...eslintRules,
34
- ...nRules,
35
- ...typescriptRules,
36
- ...unicornRules,
37
- ...lodashRules,
38
- ...sonarRules,
39
- ...tanstackQueryRules,
40
- ...tailwindRules,
41
- ...stylisticRules,
42
- ...perfectionistRules,
43
- ...a11yRules,
44
- ...deprecatedRules,
45
- };
46
-
47
- const jsRulesJon = JSON.stringify(jsRules).slice(1, -1);
48
- const markdownRulesJson = JSON.stringify(markdownRules).slice(1, -1);
49
- const jsonRulesJson = JSON.stringify(jsonRules).slice(1, -1);
50
-
51
- const importList = [
52
- 'import parser from "@typescript-eslint/parser";',
53
- 'import a11y from "eslint-plugin-jsx-a11y/lib/index.js";',
54
- 'import n from "eslint-plugin-n";',
55
- 'import unicorn from "eslint-plugin-unicorn";',
56
- 'import tseslint from "typescript-eslint";',
57
- 'import sonar from "eslint-plugin-sonarjs";',
58
- 'import tanstack from "@tanstack/eslint-plugin-query";',
59
- 'import perfectionist from "eslint-plugin-perfectionist";',
60
- 'import depend from "eslint-plugin-depend";',
61
- 'import barrel from "eslint-plugin-barrel-files";',
62
- 'import compat from "eslint-plugin-compat";',
63
- 'import lodashConfig from "eslint-plugin-lodash";',
64
- 'import tailwind from "eslint-plugin-tailwindcss";',
65
- 'import stylistic from "@stylistic/eslint-plugin";',
66
- 'import markdown from "@eslint/markdown";',
67
- 'import json from "@eslint/json";',
68
- 'import { ignores } from "./constants.js";',
69
- ].sort((a, b) => {
70
- return a.localeCompare(b);
71
- });
72
-
73
- importList.forEach((item) => {
74
- configFile += `${item}\n`;
75
- });
76
-
77
- configFile += `\nexport const languageOptions = {
78
- parser,
79
- parserOptions: {
80
- project: true,
81
- tsconfigRootDir: import.meta.dirname,
3
+ export const coreFile = [
4
+ {
5
+ name: "core",
6
+ label: "Core",
7
+ importString: 'import config from "@ethang/eslint-config/eslint.config.js',
8
+ options: {
9
+ includeReactVersion: true,
10
+ includeLanguageOptions: true,
11
+ includeIgnores: true,
12
+ },
82
13
  },
83
- };
14
+ {
15
+ name: "markdown",
16
+ },
17
+ {
18
+ name: "json",
19
+ },
20
+ ];
84
21
 
85
- export default tseslint.config(
22
+ const astroFile = [
86
23
  {
87
- files: ["**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts}"],
88
- ignores,
89
- languageOptions,
90
- settings: {
91
- ${settings}
92
- },
93
- plugins: {
94
- "@tanstack/query": tanstack,
95
- "@typescript-eslint": tseslint.plugin,
96
- a11y,
97
- barrel,
98
- compat,
99
- depend,
100
- lodash: lodashConfig,
101
- n,
102
- perfectionist,
103
- sonar,
104
- stylistic,
105
- tailwind,
106
- unicorn,
107
- },
108
- rules: {
109
- ${jsRulesJon}
24
+ name: "astro",
25
+ label: "Astro",
26
+ importString:
27
+ 'import astroConfig from "@ethang/eslint-config/config.astro.js',
28
+ options: {
29
+ includeIgnores: true,
30
+ includeLanguageOptions: true,
31
+ extraImports: ['import tseslint from "typescript-eslint";'],
110
32
  },
111
33
  },
34
+ ];
35
+
36
+ const reactFile = [
112
37
  {
113
- files: ["**/*.md"],
114
- plugins: {
115
- markdown,
116
- },
117
- rules: {
118
- ${markdownRulesJson}
38
+ name: "react",
39
+ label: "React",
40
+ importString:
41
+ 'import reactConfig from "@ethang/eslint-config/config.react.js',
42
+ options: {
43
+ includeReactVersion: true,
44
+ includeIgnores: true,
45
+ includeLanguageOptions: true,
46
+ extraImports: ['import tseslint from "typescript-eslint";'],
119
47
  },
120
48
  },
49
+ ];
50
+
51
+ const solidFile = [
121
52
  {
122
- files: ["**/*.{json,jsonc,json5}"],
123
- plugins: { json },
124
- rules: {
125
- ${jsonRulesJson}
53
+ name: "solid",
54
+ label: "Solid",
55
+ importString:
56
+ 'import reactConfig from "@ethang/eslint-config/config.solid.js',
57
+ options: {
58
+ includeIgnores: true,
59
+ includeLanguageOptions: true,
60
+ extraImports: ['import tseslint from "typescript-eslint";'],
126
61
  },
127
62
  },
128
- );\n`;
63
+ ];
129
64
 
130
- writeFileSync(
131
- join(import.meta.dirname, "../eslint.config.js"),
132
- configFile,
133
- "utf8",
134
- );
65
+ export const secondaryRules = {
66
+ astro: astroFile,
67
+ react: reactFile,
68
+ solid: solidFile,
69
+ };
70
+
71
+ export const allRules = {
72
+ core: coreFile,
73
+ ...secondaryRules,
74
+ };
75
+
76
+ export const updateRules = async () => {
77
+ await Promise.all([
78
+ createConfigFile(coreFile, "eslint.config.js"),
79
+ createConfigFile(astroFile, "config.astro.js"),
80
+ createConfigFile(reactFile, "config.react.js"),
81
+ createConfigFile(solidFile, "config.solid.js"),
82
+ ]);
135
83
  };
package/build.mjs CHANGED
@@ -2,9 +2,6 @@
2
2
  import { projectBuilder } from "@ethang/project-builder/project-builder.js";
3
3
  import { updateRules } from "./build/update-rules.js";
4
4
  import { updateReadme } from "./build/update-readme.js";
5
- import { updateReactRules } from "./build/update-react-rules.js";
6
- import { updateSolidRules } from "./build/update-solid-rules.js";
7
- import { updateAstroRules } from "./build/update-astro-rules.js";
8
5
 
9
6
  await projectBuilder("eslint-config-ethang", "master", {
10
7
  isLibrary: true,
@@ -12,9 +9,6 @@ await projectBuilder("eslint-config-ethang", "master", {
12
9
  postInstall: async () => {
13
10
  console.log("Updating Rules...");
14
11
  await updateRules();
15
- await updateReactRules();
16
- updateSolidRules();
17
- updateAstroRules();
18
12
  updateReadme();
19
13
  },
20
14
  tsupOptions: {
package/config.astro.js CHANGED
@@ -1,5 +1,4 @@
1
- import { ignores } from "./constants.js";
2
- import { languageOptions } from "./eslint.config.js";
1
+ import { ignores, languageOptions } from "./constants.js";
3
2
  import astro from "eslint-plugin-astro";
4
3
  import tseslint from "typescript-eslint";
5
4
 
@@ -7,7 +6,9 @@ export default tseslint.config({
7
6
  files: ["**/*.{astro}"],
8
7
  ignores,
9
8
  languageOptions,
10
- plugins: { astro },
9
+ plugins: {
10
+ astro: astro,
11
+ },
11
12
  rules: {
12
13
  "astro/missing-client-only-directive-value": "error",
13
14
  "astro/no-conflict-set-directives": "error",
package/config.react.js CHANGED
@@ -1,5 +1,4 @@
1
- import { ignores } from "./constants.js";
2
- import { languageOptions } from "./eslint.config.js";
1
+ import { ignores, languageOptions } from "./constants.js";
3
2
  import react from "@eslint-react/eslint-plugin";
4
3
  import reactHooks from "eslint-plugin-react-hooks";
5
4
  import tseslint from "typescript-eslint";
@@ -8,16 +7,14 @@ export default tseslint.config({
8
7
  files: ["**/*.{jsx,tsx}"],
9
8
  ignores,
10
9
  languageOptions,
11
- plugins: {
12
- react,
13
- "react-hooks": reactHooks,
14
- },
15
10
  settings: {
16
11
  react: { version: "18.3.1" },
17
12
  },
13
+ plugins: {
14
+ react: react,
15
+ "react-hooks": reactHooks,
16
+ },
18
17
  rules: {
19
- "react-hooks/rules-of-hooks": "off",
20
- "react-hooks/exhaustive-deps": "off",
21
18
  "react/avoid-shorthand-boolean": "off",
22
19
  "react/avoid-shorthand-fragment": "off",
23
20
  "react/ensure-forward-ref-using-ref": "error",
@@ -92,5 +89,7 @@ export default tseslint.config({
92
89
  "react/debug/function-component": "off",
93
90
  "react/debug/is-from-react": "off",
94
91
  "react/debug/react-hooks": "off",
92
+ "react-hooks/rules-of-hooks": "off",
93
+ "react-hooks/exhaustive-deps": "off",
95
94
  },
96
95
  });
package/config.solid.js CHANGED
@@ -1,5 +1,4 @@
1
- import { ignores } from "./constants.js";
2
- import { languageOptions } from "./eslint.config.js";
1
+ import { ignores, languageOptions } from "./constants.js";
3
2
  import solid from "eslint-plugin-solid";
4
3
  import tseslint from "typescript-eslint";
5
4
 
@@ -7,7 +6,9 @@ export default tseslint.config({
7
6
  files: ["**/*.{jsx,tsx}"],
8
7
  ignores,
9
8
  languageOptions,
10
- plugins: { solid },
9
+ plugins: {
10
+ solid: solid,
11
+ },
11
12
  rules: {
12
13
  "solid/components-return-once": "error",
13
14
  "solid/event-handlers": "error",
package/constants.js CHANGED
@@ -1 +1,11 @@
1
+ import { parser } from "typescript-eslint";
2
+
1
3
  export const ignores = ["eslint.config.js", "node_modules", "dist"];
4
+
5
+ export const languageOptions = {
6
+ parser,
7
+ parserOptions: {
8
+ project: true,
9
+ tsconfigRootDir: import.meta.dirname,
10
+ },
11
+ };
package/eslint.config.js CHANGED
@@ -1,13 +1,13 @@
1
- import { ignores } from "./constants.js";
1
+ import { ignores, languageOptions } from "./constants.js";
2
2
  import a11y from "eslint-plugin-jsx-a11y/lib/index.js";
3
3
  import barrel from "eslint-plugin-barrel-files";
4
4
  import compat from "eslint-plugin-compat";
5
5
  import depend from "eslint-plugin-depend";
6
+ import ethang from "@ethang/eslint-plugin";
6
7
  import json from "@eslint/json";
7
8
  import lodashConfig from "eslint-plugin-lodash";
8
9
  import markdown from "@eslint/markdown";
9
10
  import n from "eslint-plugin-n";
10
- import parser from "@typescript-eslint/parser";
11
11
  import perfectionist from "eslint-plugin-perfectionist";
12
12
  import sonar from "eslint-plugin-sonarjs";
13
13
  import stylistic from "@stylistic/eslint-plugin";
@@ -16,14 +16,6 @@ import tanstack from "@tanstack/eslint-plugin-query";
16
16
  import tseslint from "typescript-eslint";
17
17
  import unicorn from "eslint-plugin-unicorn";
18
18
 
19
- export const languageOptions = {
20
- parser,
21
- parserOptions: {
22
- project: true,
23
- tsconfigRootDir: import.meta.dirname,
24
- },
25
- };
26
-
27
19
  export default tseslint.config(
28
20
  {
29
21
  files: ["**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts}"],
@@ -33,19 +25,20 @@ export default tseslint.config(
33
25
  react: { version: "18.3.1" },
34
26
  },
35
27
  plugins: {
36
- "@tanstack/query": tanstack,
28
+ depend: depend,
29
+ barrel: barrel,
30
+ compat: compat,
31
+ n: n,
37
32
  "@typescript-eslint": tseslint.plugin,
38
- a11y,
39
- barrel,
40
- compat,
41
- depend,
33
+ unicorn: unicorn,
42
34
  lodash: lodashConfig,
43
- n,
44
- perfectionist,
45
- sonar,
46
- stylistic,
47
- tailwind,
48
- unicorn,
35
+ sonar: sonar,
36
+ ethang: ethang,
37
+ "@tanstack/query": tanstack,
38
+ tailwind: tailwind,
39
+ stylistic: stylistic,
40
+ perfectionist: perfectionist,
41
+ a11y: a11y,
49
42
  },
50
43
  rules: {
51
44
  "depend/ban-dependencies": ["error", { allowed: ["lodash"] }],
@@ -116,7 +109,7 @@ export default tseslint.config(
116
109
  "no-dupe-else-if": "error",
117
110
  "no-dupe-keys": "error",
118
111
  "no-duplicate-case": "error",
119
- "no-duplicate-imports": "off",
112
+ "no-duplicate-imports": "error",
120
113
  "no-else-return": "error",
121
114
  "no-empty": "error",
122
115
  "no-empty-character-class": "error",
@@ -938,6 +931,7 @@ export default tseslint.config(
938
931
  "sonar/x-powered-by": "error",
939
932
  "sonar/xml-parser-xxe": "error",
940
933
  "sonar/xpath": "off",
934
+ "ethang/handle-native-error": "error",
941
935
  "@tanstack/query/exhaustive-deps": "error",
942
936
  "@tanstack/query/stable-query-client": "error",
943
937
  "@tanstack/query/no-rest-destructuring": "error",
@@ -1257,7 +1251,7 @@ export default tseslint.config(
1257
1251
  {
1258
1252
  files: ["**/*.md"],
1259
1253
  plugins: {
1260
- markdown,
1254
+ markdown: markdown,
1261
1255
  },
1262
1256
  rules: {
1263
1257
  "markdown/fenced-code-language": "error",
@@ -1271,7 +1265,9 @@ export default tseslint.config(
1271
1265
  },
1272
1266
  {
1273
1267
  files: ["**/*.{json,jsonc,json5}"],
1274
- plugins: { json },
1268
+ plugins: {
1269
+ json: json,
1270
+ },
1275
1271
  rules: {
1276
1272
  "json/no-duplicate-keys": "error",
1277
1273
  "json/no-empty-keys": "error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethang/eslint-config",
3
- "version": "19.2.7",
3
+ "version": "19.2.9",
4
4
  "repository": {
5
5
  "url": "git+https://github.com/eglove/eslint-config-ethang.git"
6
6
  },
@@ -17,6 +17,7 @@
17
17
  "@eslint/js": "^9.9.1",
18
18
  "@eslint/json": "^0.4.0",
19
19
  "@eslint/markdown": "^6.0.0",
20
+ "@ethang/eslint-plugin": "^0.0.6",
20
21
  "@stylistic/eslint-plugin": "^2.7.2",
21
22
  "@tanstack/eslint-plugin-query": "^5.53.0",
22
23
  "@typescript-eslint/parser": "^8.3.0",
@@ -30,7 +31,7 @@
30
31
  "eslint-plugin-n": "^17.10.2",
31
32
  "eslint-plugin-perfectionist": "^3.3.0",
32
33
  "eslint-plugin-react-hooks": "^4.6.2",
33
- "eslint-plugin-solid": "^0.14.2",
34
+ "eslint-plugin-solid": "^0.14.3",
34
35
  "eslint-plugin-sonarjs": "2.0.2",
35
36
  "eslint-plugin-tailwindcss": "^3.17.4",
36
37
  "eslint-plugin-unicorn": "^55.0.0",
@@ -39,7 +40,7 @@
39
40
  },
40
41
  "devDependencies": {
41
42
  "@ethang/markdown-generator": "^1.1.1",
42
- "@ethang/project-builder": "^2.5.1",
43
+ "@ethang/project-builder": "^2.5.8",
43
44
  "@tsconfig/node-lts": "^20.1.3",
44
45
  "@tsconfig/strictest": "^2.0.5",
45
46
  "prettier": "^3.3.3"
@@ -49,6 +50,7 @@
49
50
  "@eslint/js": "^9.9.1",
50
51
  "@eslint/json": "^0.4.0",
51
52
  "@eslint/markdown": "^6.0.0",
53
+ "@ethang/eslint-plugin": "^0.0.6",
52
54
  "@stylistic/eslint-plugin": "^2.7.2",
53
55
  "@tanstack/eslint-plugin-query": "^5.53.0",
54
56
  "@typescript-eslint/parser": "^8.3.0",
@@ -62,7 +64,7 @@
62
64
  "eslint-plugin-n": "^17.10.2",
63
65
  "eslint-plugin-perfectionist": "^3.3.0",
64
66
  "eslint-plugin-react-hooks": "^4.6.2",
65
- "eslint-plugin-solid": "^0.14.2",
67
+ "eslint-plugin-solid": "^0.14.3",
66
68
  "eslint-plugin-sonarjs": "2.0.2",
67
69
  "eslint-plugin-tailwindcss": "^3.17.4",
68
70
  "eslint-plugin-unicorn": "^55.0.0",
package/setup/eslint.js CHANGED
@@ -30,7 +30,6 @@ const changedRules = [
30
30
  { name: "max-params", rule: "off" },
31
31
  { name: "new-cap", rule: "off" },
32
32
  { name: "no-array-constructor", rule: "off" },
33
- { name: "no-duplicate-imports", rule: "off" },
34
33
  { name: "no-empty-function", rule: "off" },
35
34
  { name: "no-implicit-globals", rule: "off" },
36
35
  { name: "no-implied-eval", rule: "off" },
@@ -0,0 +1,6 @@
1
+ import ethang from "@ethang/eslint-plugin";
2
+ import { genRules } from "./gen-rules.js";
3
+
4
+ const ruleNames = Object.keys(ethang.rules);
5
+
6
+ export const ethangRules = genRules(ruleNames, [], "ethang");
package/setup/react.js CHANGED
@@ -25,6 +25,9 @@ const customHookRules = [
25
25
  const hookGen = genRules(reactHookRuleNames, customHookRules, "react-hooks");
26
26
 
27
27
  export const reactRules = {
28
- ...hookGen,
29
28
  ...reactGen,
30
29
  };
30
+
31
+ export const reactHookRules = {
32
+ ...hookGen,
33
+ };
@@ -1,39 +0,0 @@
1
- import { writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { astroRules } from "../setup/astro.js";
4
-
5
- export const updateAstroRules = () => {
6
- let configFile = "";
7
-
8
- const rulesJson = JSON.stringify(astroRules).slice(1, -1);
9
-
10
- const importList = [
11
- 'import astro from "eslint-plugin-astro";',
12
- 'import tseslint from "typescript-eslint";',
13
- 'import { languageOptions } from "./eslint.config.js";',
14
- 'import { ignores } from "./constants.js";',
15
- ].sort((a, b) => {
16
- return a.localeCompare(b);
17
- });
18
-
19
- importList.forEach((item) => {
20
- configFile += `${item}\n`;
21
- });
22
-
23
- configFile += `\nexport default tseslint.config({
24
- files: ["**/*.{astro}"],
25
- ignores,
26
- languageOptions,
27
- plugins: { astro },
28
- rules: {
29
- ${rulesJson}
30
- },
31
- });
32
- `;
33
-
34
- writeFileSync(
35
- join(import.meta.dirname, "../config.astro.js"),
36
- configFile,
37
- "utf8",
38
- );
39
- };
@@ -1,51 +0,0 @@
1
- import { reactRules } from "../setup/react.js";
2
- import { writeFileSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { getLatestReact } from "./get-react-version.mjs";
5
-
6
- export const updateReactRules = async () => {
7
- let configFile = "";
8
- const react = await getLatestReact();
9
- const settings = JSON.stringify({
10
- react: { version: react.version },
11
- }).slice(1, -1);
12
-
13
- const rulesJson = JSON.stringify(reactRules).slice(1, -1);
14
-
15
- const importList = [
16
- 'import react from "@eslint-react/eslint-plugin";',
17
- 'import reactHooks from "eslint-plugin-react-hooks";',
18
- 'import tseslint from "typescript-eslint";',
19
- 'import { languageOptions } from "./eslint.config.js";',
20
- 'import { ignores } from "./constants.js";',
21
- ].sort((a, b) => {
22
- return a.localeCompare(b);
23
- });
24
-
25
- importList.forEach((item) => {
26
- configFile += `${item}\n`;
27
- });
28
-
29
- configFile += `\nexport default tseslint.config({
30
- files: ["**/*.{jsx,tsx}"],
31
- ignores,
32
- languageOptions,
33
- plugins: {
34
- react,
35
- "react-hooks": reactHooks,
36
- },
37
- settings: {
38
- ${settings}
39
- },
40
- rules: {
41
- ${rulesJson}
42
- },
43
- });
44
- `;
45
-
46
- writeFileSync(
47
- join(import.meta.dirname, "../config.react.js"),
48
- configFile,
49
- "utf8",
50
- );
51
- };
@@ -1,39 +0,0 @@
1
- import { solidRules } from "../setup/solid.js";
2
- import { writeFileSync } from "node:fs";
3
- import { join } from "node:path";
4
-
5
- export const updateSolidRules = () => {
6
- let configFile = "";
7
-
8
- const rulesJson = JSON.stringify(solidRules).slice(1, -1);
9
-
10
- const importList = [
11
- 'import solid from "eslint-plugin-solid";',
12
- 'import tseslint from "typescript-eslint";',
13
- 'import { languageOptions } from "./eslint.config.js";',
14
- 'import { ignores } from "./constants.js";',
15
- ].sort((a, b) => {
16
- return a.localeCompare(b);
17
- });
18
-
19
- importList.forEach((item) => {
20
- configFile += `${item}\n`;
21
- });
22
-
23
- configFile += `\nexport default tseslint.config({
24
- files: ["**/*.{jsx,tsx}"],
25
- ignores,
26
- languageOptions,
27
- plugins: { solid },
28
- rules: {
29
- ${rulesJson},
30
- },
31
- });
32
- `;
33
-
34
- writeFileSync(
35
- join(import.meta.dirname, "../config.solid.js"),
36
- configFile,
37
- "utf8",
38
- );
39
- };
package/update-rules.mjs DELETED
@@ -1,11 +0,0 @@
1
- import { updateRules } from "./build/update-rules.js";
2
- import { updateReactRules } from "./build/update-react-rules.js";
3
- import { updateSolidRules } from "./build/update-solid-rules.js";
4
- import { updateAstroRules } from "./build/update-astro-rules.js";
5
- import { updateReadme } from "./build/update-readme.js";
6
-
7
- await updateRules();
8
- await updateReactRules();
9
- updateSolidRules();
10
- updateAstroRules();
11
- updateReadme();