@ghettoddos/eslint-config 4.1.1 → 5.0.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/dist/index.d.mts +13275 -10092
- package/dist/index.mjs +308 -331
- package/dist/{lib-C63e_zBF.mjs → lib-C1Uxp5ZW.mjs} +2879 -2331
- package/package.json +52 -67
package/dist/index.mjs
CHANGED
|
@@ -5,18 +5,21 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import fs$1 from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { isPackageExists } from "local-pkg";
|
|
8
|
-
import createCommand from "eslint-plugin-command/config";
|
|
9
8
|
import pluginE18e from "@e18e/eslint-plugin";
|
|
10
9
|
import pluginComments from "@eslint-community/eslint-plugin-eslint-comments";
|
|
11
10
|
import pluginAntfu from "eslint-plugin-antfu";
|
|
11
|
+
import pluginBaselineJs from "eslint-plugin-baseline-js";
|
|
12
|
+
import pluginDeMorgan from "eslint-plugin-de-morgan";
|
|
12
13
|
import pluginImportLite from "eslint-plugin-import-lite";
|
|
13
14
|
import pluginNode from "eslint-plugin-n";
|
|
14
15
|
import pluginPerfectionist from "eslint-plugin-perfectionist";
|
|
15
16
|
import pluginUnicorn from "eslint-plugin-unicorn";
|
|
16
17
|
import pluginUnusedImports from "eslint-plugin-unused-imports";
|
|
18
|
+
import createCommand from "eslint-plugin-command/config";
|
|
17
19
|
import globals from "globals";
|
|
18
20
|
import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
|
|
19
21
|
import { configs } from "eslint-plugin-regexp";
|
|
22
|
+
import pluginSonarJs from "eslint-plugin-sonarjs";
|
|
20
23
|
//#region node_modules/.pnpm/find-up-simple@1.0.1/node_modules/find-up-simple/index.js
|
|
21
24
|
const toPath = (urlOrPath) => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
|
|
22
25
|
async function findUp(name, { cwd = process.cwd(), type = "file", stopAt } = {}) {
|
|
@@ -50,6 +53,26 @@ function findUpSync(name, { cwd = process.cwd(), type = "file", stopAt } = {}) {
|
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
//#endregion
|
|
56
|
+
//#region src/configs/baseline.ts
|
|
57
|
+
async function baseline(options = {}) {
|
|
58
|
+
const { available, baseline, ignoreFeatures = ["functions-caller-arguments"], overrides = {} } = options;
|
|
59
|
+
return [{
|
|
60
|
+
name: "baseline/rules",
|
|
61
|
+
plugins: { "baseline-js": pluginBaselineJs },
|
|
62
|
+
rules: {
|
|
63
|
+
"baseline-js/use-baseline": ["warn", {
|
|
64
|
+
available,
|
|
65
|
+
baseline,
|
|
66
|
+
ignoreFeatures,
|
|
67
|
+
includeJsBuiltins: { preset: "auto" },
|
|
68
|
+
includeWebApis: { preset: "auto" },
|
|
69
|
+
...options
|
|
70
|
+
}],
|
|
71
|
+
...overrides
|
|
72
|
+
}
|
|
73
|
+
}];
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
53
76
|
//#region src/configs/command.ts
|
|
54
77
|
async function command() {
|
|
55
78
|
return [{
|
|
@@ -72,6 +95,14 @@ async function comments() {
|
|
|
72
95
|
}];
|
|
73
96
|
}
|
|
74
97
|
//#endregion
|
|
98
|
+
//#region src/configs/de-morgan.ts
|
|
99
|
+
async function deMorgan() {
|
|
100
|
+
return [{
|
|
101
|
+
...pluginDeMorgan.configs.recommended,
|
|
102
|
+
name: "de-morgan/rules"
|
|
103
|
+
}];
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
75
106
|
//#region src/globs.ts
|
|
76
107
|
const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
|
|
77
108
|
const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
|
|
@@ -82,6 +113,7 @@ const GLOB_TSX = "**/*.?([cm])tsx";
|
|
|
82
113
|
const GLOB_STYLE = "**/*.{c,le,sc}ss";
|
|
83
114
|
const GLOB_CSS = "**/*.css";
|
|
84
115
|
const GLOB_POSTCSS = "**/*.{p,post}css";
|
|
116
|
+
const GLOB_LESS = "**/*.less";
|
|
85
117
|
const GLOB_SCSS = "**/*.scss";
|
|
86
118
|
const GLOB_JSON = "**/*.json";
|
|
87
119
|
const GLOB_JSON5 = "**/*.json5";
|
|
@@ -94,6 +126,7 @@ const GLOB_TOML = "**/*.toml";
|
|
|
94
126
|
const GLOB_XML = "**/*.xml";
|
|
95
127
|
const GLOB_SVG = "**/*.svg";
|
|
96
128
|
const GLOB_HTML = "**/*.htm?(l)";
|
|
129
|
+
const GLOB_GRAPHQL = "**/*.{g,graph}ql";
|
|
97
130
|
const GLOB_MARKDOWN_CODE = `${GLOB_MARKDOWN}/${GLOB_SRC}`;
|
|
98
131
|
const GLOB_TESTS = [
|
|
99
132
|
`**/__tests__/**/*.${GLOB_SRC_EXT}`,
|
|
@@ -108,6 +141,7 @@ const GLOB_ALL_SRC = [
|
|
|
108
141
|
GLOB_JSON,
|
|
109
142
|
GLOB_JSON5,
|
|
110
143
|
GLOB_MARKDOWN,
|
|
144
|
+
GLOB_VUE,
|
|
111
145
|
GLOB_YAML,
|
|
112
146
|
GLOB_XML,
|
|
113
147
|
GLOB_HTML
|
|
@@ -137,13 +171,17 @@ const GLOB_EXCLUDE = [
|
|
|
137
171
|
"**/.output",
|
|
138
172
|
"**/.vite-inspect",
|
|
139
173
|
"**/.yarn",
|
|
140
|
-
"**/vite.config.*.timestamp-*",
|
|
141
174
|
"**/CHANGELOG*.md",
|
|
142
|
-
"**/*.min.*",
|
|
143
175
|
"**/LICENSE*",
|
|
176
|
+
"**/*.min.*",
|
|
144
177
|
"**/__snapshots__",
|
|
178
|
+
"**/vite.config.*.timestamp-*",
|
|
145
179
|
"**/auto-import?(s).d.ts",
|
|
146
|
-
"**/components.d.ts"
|
|
180
|
+
"**/components.d.ts",
|
|
181
|
+
"**/.context",
|
|
182
|
+
"**/.claude",
|
|
183
|
+
"**/.agents",
|
|
184
|
+
"**/.*/skills"
|
|
147
185
|
];
|
|
148
186
|
//#endregion
|
|
149
187
|
//#region src/configs/disables.ts
|
|
@@ -154,10 +192,28 @@ async function disables() {
|
|
|
154
192
|
name: "disables/scripts",
|
|
155
193
|
rules: {
|
|
156
194
|
"antfu/no-top-level-await": "off",
|
|
195
|
+
"baseline-js/use-baseline": "off",
|
|
157
196
|
"no-console": "off",
|
|
158
197
|
"ts/explicit-function-return-type": "off"
|
|
159
198
|
}
|
|
160
199
|
},
|
|
200
|
+
{
|
|
201
|
+
files: [`**/cli/${GLOB_SRC}`, `**/cli.${GLOB_SRC_EXT}`],
|
|
202
|
+
name: "disables/cli",
|
|
203
|
+
rules: {
|
|
204
|
+
"antfu/no-top-level-await": "off",
|
|
205
|
+
"baseline-js/use-baseline": "off",
|
|
206
|
+
"no-console": "off"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
files: ["**/bin/**/*", `**/bin.${GLOB_SRC_EXT}`],
|
|
211
|
+
name: "disables/bin",
|
|
212
|
+
rules: {
|
|
213
|
+
"antfu/no-import-dist": "off",
|
|
214
|
+
"antfu/no-import-node-modules-by-path": "off"
|
|
215
|
+
}
|
|
216
|
+
},
|
|
161
217
|
{
|
|
162
218
|
files: ["**/*.d.?([cm])ts"],
|
|
163
219
|
name: "disables/dts",
|
|
@@ -171,10 +227,43 @@ async function disables() {
|
|
|
171
227
|
files: ["**/*.js", "**/*.cjs"],
|
|
172
228
|
name: "disables/cjs",
|
|
173
229
|
rules: { "ts/no-require-imports": "off" }
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
files: [`**/*.config.${GLOB_SRC_EXT}`, `**/*.config.*.${GLOB_SRC_EXT}`],
|
|
233
|
+
name: "disables/config-files",
|
|
234
|
+
rules: {
|
|
235
|
+
"antfu/no-top-level-await": "off",
|
|
236
|
+
"baseline-js/use-baseline": "off",
|
|
237
|
+
"no-console": "off",
|
|
238
|
+
"ts/explicit-function-return-type": "off"
|
|
239
|
+
}
|
|
174
240
|
}
|
|
175
241
|
];
|
|
176
242
|
}
|
|
177
243
|
//#endregion
|
|
244
|
+
//#region src/configs/e18e.ts
|
|
245
|
+
async function e18e(options = {}) {
|
|
246
|
+
const { isInEditor = false, modernization = true, type = "app", moduleReplacements = type === "lib" && isInEditor, overrides = {}, performanceImprovements = true } = options;
|
|
247
|
+
const configs = pluginE18e.configs;
|
|
248
|
+
return [{
|
|
249
|
+
name: "e18e/rules",
|
|
250
|
+
plugins: { e18e: pluginE18e },
|
|
251
|
+
rules: {
|
|
252
|
+
...modernization ? { ...configs.modernization.rules } : {},
|
|
253
|
+
...moduleReplacements ? { ...configs.moduleReplacements.rules } : {},
|
|
254
|
+
...performanceImprovements ? { ...configs.performanceImprovements.rules } : {},
|
|
255
|
+
...type === "lib" ? {} : { "e18e/prefer-static-regex": "off" },
|
|
256
|
+
"e18e/prefer-array-at": "off",
|
|
257
|
+
"e18e/prefer-array-from-map": "off",
|
|
258
|
+
"e18e/prefer-array-to-reversed": "off",
|
|
259
|
+
"e18e/prefer-array-to-sorted": "off",
|
|
260
|
+
"e18e/prefer-array-to-spliced": "off",
|
|
261
|
+
"e18e/prefer-spread-syntax": "off",
|
|
262
|
+
...overrides
|
|
263
|
+
}
|
|
264
|
+
}];
|
|
265
|
+
}
|
|
266
|
+
//#endregion
|
|
178
267
|
//#region src/utils.ts
|
|
179
268
|
const scopeUrl = fileURLToPath(new URL(".", import.meta.url));
|
|
180
269
|
const isCwdInScope = isPackageExists("@ghettoddos/eslint-config");
|
|
@@ -198,12 +287,6 @@ const parserPlain = {
|
|
|
198
287
|
})
|
|
199
288
|
};
|
|
200
289
|
/**
|
|
201
|
-
* Combine array and non-array configs into a single array.
|
|
202
|
-
*/
|
|
203
|
-
async function combine(...configs) {
|
|
204
|
-
return (await Promise.all(configs)).flat();
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
290
|
* Rename plugin prefixes in a rule object.
|
|
208
291
|
* Accepts a map of prefixes to rename.
|
|
209
292
|
*
|
|
@@ -238,7 +321,10 @@ async function ensurePackages(packages) {
|
|
|
238
321
|
if (process.env.CI || process.stdout.isTTY === false || isCwdInScope === false) return;
|
|
239
322
|
const nonExistingPackages = packages.filter((i) => i && !isPackageInScope(i));
|
|
240
323
|
if (nonExistingPackages.length === 0) return;
|
|
241
|
-
|
|
324
|
+
const p = await import("@clack/prompts");
|
|
325
|
+
const packagePlural = nonExistingPackages.length === 1 ? "Package is" : "Packages are";
|
|
326
|
+
const pkgs = nonExistingPackages.join(", ");
|
|
327
|
+
if (await p.confirm({ message: `${packagePlural} required for this config: ${pkgs}. Do you want to install them?` })) await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
|
|
242
328
|
}
|
|
243
329
|
function isInEditorEnv() {
|
|
244
330
|
if (process.env.CI) return false;
|
|
@@ -248,27 +334,19 @@ function isInEditorEnv() {
|
|
|
248
334
|
function isInGitHooksOrLintStaged() {
|
|
249
335
|
return !!(process.env.GIT_PARAMS || process.env.VSCODE_GIT_COMMAND || process.env.npm_lifecycle_script?.startsWith("lint-staged"));
|
|
250
336
|
}
|
|
251
|
-
function resolveSubOptions(options, key) {
|
|
252
|
-
return typeof options[key] === "boolean" ? {} : options[key] || {};
|
|
253
|
-
}
|
|
254
|
-
function getOverrides(options, key) {
|
|
255
|
-
const sub = resolveSubOptions(options, key);
|
|
256
|
-
return {
|
|
257
|
-
...options.overrides?.[key],
|
|
258
|
-
..."overrides" in sub ? sub.overrides : {}
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
337
|
//#endregion
|
|
262
338
|
//#region src/configs/stylistic.ts
|
|
263
339
|
const StylisticConfigDefaults = {
|
|
264
340
|
experimental: false,
|
|
265
341
|
indent: 2,
|
|
266
342
|
jsx: true,
|
|
343
|
+
printWidth: 100,
|
|
267
344
|
quotes: "single",
|
|
268
|
-
semi: false
|
|
345
|
+
semi: false,
|
|
346
|
+
tabWidth: 4
|
|
269
347
|
};
|
|
270
348
|
async function stylistic(options = {}) {
|
|
271
|
-
const { experimental, indent, jsx, overrides = {}, quotes, semi } = {
|
|
349
|
+
const { experimental, indent, jsx, lessOpinionated = false, overrides = {}, printWidth, quotes, semi, tabWidth } = {
|
|
272
350
|
...StylisticConfigDefaults,
|
|
273
351
|
...options
|
|
274
352
|
};
|
|
@@ -291,13 +369,23 @@ async function stylistic(options = {}) {
|
|
|
291
369
|
...config.rules,
|
|
292
370
|
...experimental ? {} : { "antfu/consistent-list-newline": "error" },
|
|
293
371
|
"antfu/consistent-chaining": "error",
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
372
|
+
...lessOpinionated ? { curly: ["error", "all"] } : {
|
|
373
|
+
"antfu/curly": "error",
|
|
374
|
+
"antfu/if-newline": "error",
|
|
375
|
+
"antfu/top-level-function": "error"
|
|
376
|
+
},
|
|
297
377
|
"style/generator-star-spacing": ["error", {
|
|
298
378
|
after: true,
|
|
299
379
|
before: false
|
|
300
380
|
}],
|
|
381
|
+
"style/max-len": ["warn", {
|
|
382
|
+
code: printWidth,
|
|
383
|
+
ignoreComments: true,
|
|
384
|
+
ignoreRegExpLiterals: true,
|
|
385
|
+
ignoreTrailingComments: true,
|
|
386
|
+
ignoreUrls: true,
|
|
387
|
+
tabWidth: typeof indent === "number" ? indent : indent === "tab" ? tabWidth : 2
|
|
388
|
+
}],
|
|
301
389
|
"style/yield-star-spacing": ["error", {
|
|
302
390
|
after: true,
|
|
303
391
|
before: false
|
|
@@ -320,6 +408,7 @@ async function formatters(options = {}, stylistic = {}) {
|
|
|
320
408
|
const isPrettierPluginXmlInScope = isPackageInScope("@prettier/plugin-xml");
|
|
321
409
|
options = {
|
|
322
410
|
css: true,
|
|
411
|
+
graphql: true,
|
|
323
412
|
html: true,
|
|
324
413
|
markdown: true,
|
|
325
414
|
svg: isPrettierPluginXmlInScope,
|
|
@@ -327,13 +416,13 @@ async function formatters(options = {}, stylistic = {}) {
|
|
|
327
416
|
};
|
|
328
417
|
}
|
|
329
418
|
await ensurePackages(["eslint-plugin-format", options.xml || options.svg ? "@prettier/plugin-xml" : void 0]);
|
|
330
|
-
const { indent, quotes, semi } = {
|
|
419
|
+
const { indent, printWidth, quotes, semi } = {
|
|
331
420
|
...StylisticConfigDefaults,
|
|
332
421
|
...stylistic
|
|
333
422
|
};
|
|
334
423
|
const prettierOptions = Object.assign({
|
|
335
424
|
endOfLine: "auto",
|
|
336
|
-
printWidth:
|
|
425
|
+
printWidth: typeof printWidth === "number" ? printWidth : 100,
|
|
337
426
|
semi,
|
|
338
427
|
singleQuote: quotes === "single",
|
|
339
428
|
tabWidth: typeof indent === "number" ? indent : 2,
|
|
@@ -360,6 +449,11 @@ async function formatters(options = {}, stylistic = {}) {
|
|
|
360
449
|
languageOptions: { parser: parserPlain },
|
|
361
450
|
name: "formatter/scss",
|
|
362
451
|
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "scss" })] }
|
|
452
|
+
}, {
|
|
453
|
+
files: [GLOB_LESS],
|
|
454
|
+
languageOptions: { parser: parserPlain },
|
|
455
|
+
name: "formatter/less",
|
|
456
|
+
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "less" })] }
|
|
363
457
|
});
|
|
364
458
|
if (options.html) configs.push({
|
|
365
459
|
files: [GLOB_HTML],
|
|
@@ -400,6 +494,12 @@ async function formatters(options = {}, stylistic = {}) {
|
|
|
400
494
|
parser: "markdown"
|
|
401
495
|
})] }
|
|
402
496
|
});
|
|
497
|
+
if (options.graphql) configs.push({
|
|
498
|
+
files: [GLOB_GRAPHQL],
|
|
499
|
+
languageOptions: { parser: parserPlain },
|
|
500
|
+
name: "formatter/graphql",
|
|
501
|
+
rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "graphql" })] }
|
|
502
|
+
});
|
|
403
503
|
return configs;
|
|
404
504
|
}
|
|
405
505
|
//#endregion
|
|
@@ -761,37 +861,6 @@ async function jsonc(options = {}) {
|
|
|
761
861
|
}];
|
|
762
862
|
}
|
|
763
863
|
//#endregion
|
|
764
|
-
//#region src/constants.ts
|
|
765
|
-
const ReactRefreshAllowConstantExportPackages = ["vite"];
|
|
766
|
-
const RemixPackages = [
|
|
767
|
-
"@remix-run/node",
|
|
768
|
-
"@remix-run/react",
|
|
769
|
-
"@remix-run/serve",
|
|
770
|
-
"@remix-run/dev"
|
|
771
|
-
];
|
|
772
|
-
const ReactRouterPackages = [
|
|
773
|
-
"@react-router/node",
|
|
774
|
-
"@react-router/react",
|
|
775
|
-
"@react-router/serve",
|
|
776
|
-
"@react-router/dev"
|
|
777
|
-
];
|
|
778
|
-
const NextJsPackages = ["next"];
|
|
779
|
-
const ReactNativePackages = ["react-native", "expo"];
|
|
780
|
-
const ReactPackages = [
|
|
781
|
-
...RemixPackages,
|
|
782
|
-
...ReactRouterPackages,
|
|
783
|
-
...NextJsPackages,
|
|
784
|
-
...ReactNativePackages,
|
|
785
|
-
"react"
|
|
786
|
-
];
|
|
787
|
-
const ReactCompilerPackages = ["babel-plugin-react-compiler"];
|
|
788
|
-
const VuePackages = [
|
|
789
|
-
"vue",
|
|
790
|
-
"nuxt",
|
|
791
|
-
"vitepress",
|
|
792
|
-
"@slidev/cli"
|
|
793
|
-
];
|
|
794
|
-
//#endregion
|
|
795
864
|
//#region src/configs/jsx.ts
|
|
796
865
|
async function jsx(options = {}) {
|
|
797
866
|
const { a11y } = options;
|
|
@@ -806,13 +875,13 @@ async function jsx(options = {}) {
|
|
|
806
875
|
await ensurePackages(["eslint-plugin-jsx-a11y"]);
|
|
807
876
|
const jsxA11yPlugin = await interopDefault(import("eslint-plugin-jsx-a11y"));
|
|
808
877
|
const a11yConfig = jsxA11yPlugin.flatConfigs.recommended;
|
|
809
|
-
const isUsingNext =
|
|
878
|
+
const isUsingNext = isPackageExists("next");
|
|
810
879
|
const a11yRules = {
|
|
811
880
|
...a11yConfig.rules || {},
|
|
812
|
-
"jsx-a11y/alt-text": ["
|
|
881
|
+
...isUsingNext ? { "jsx-a11y/alt-text": ["warn", {
|
|
813
882
|
elements: ["img"],
|
|
814
|
-
img: [
|
|
815
|
-
}],
|
|
883
|
+
img: ["Image"]
|
|
884
|
+
}] } : {},
|
|
816
885
|
...typeof a11y === "object" && a11y.overrides ? a11y.overrides : {}
|
|
817
886
|
};
|
|
818
887
|
return [{
|
|
@@ -865,21 +934,6 @@ async function markdown(options = {}) {
|
|
|
865
934
|
...overridesMarkdown
|
|
866
935
|
}
|
|
867
936
|
},
|
|
868
|
-
{
|
|
869
|
-
files,
|
|
870
|
-
name: "markdown/disables/markdown",
|
|
871
|
-
rules: {
|
|
872
|
-
"command/command": "off",
|
|
873
|
-
"no-irregular-whitespace": "off",
|
|
874
|
-
"perfectionist/sort-exports": "off",
|
|
875
|
-
"perfectionist/sort-imports": "off",
|
|
876
|
-
"regexp/no-legacy-features": "off",
|
|
877
|
-
"regexp/no-missing-g-flag": "off",
|
|
878
|
-
"regexp/no-useless-dollar-replacements": "off",
|
|
879
|
-
"regexp/no-useless-flag": "off",
|
|
880
|
-
"style/indent": "off"
|
|
881
|
-
}
|
|
882
|
-
},
|
|
883
937
|
{
|
|
884
938
|
files: [GLOB_MARKDOWN_CODE, ...componentExts.map((ext) => `${GLOB_MARKDOWN}/**/*.${ext}`)],
|
|
885
939
|
languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
|
|
@@ -918,41 +972,32 @@ async function markdown(options = {}) {
|
|
|
918
972
|
}
|
|
919
973
|
//#endregion
|
|
920
974
|
//#region src/configs/nextjs.ts
|
|
975
|
+
function normalizeRules(rules) {
|
|
976
|
+
return Object.fromEntries(Object.entries(rules).map(([key, value]) => [key, typeof value === "string" ? [value] : value]));
|
|
977
|
+
}
|
|
921
978
|
async function nextjs(options = {}) {
|
|
922
979
|
const { files = [GLOB_SRC], overrides = {} } = options;
|
|
923
980
|
await ensurePackages(["@next/eslint-plugin-next"]);
|
|
981
|
+
const pluginNextJS = await interopDefault(import("@next/eslint-plugin-next"));
|
|
982
|
+
function getRules(name) {
|
|
983
|
+
const rules = pluginNextJS.configs?.[name]?.rules;
|
|
984
|
+
if (!rules) throw new Error(`[@ghettoddos/eslint-config] Failed to find config ${name} in @next/eslint-plugin-next`);
|
|
985
|
+
return normalizeRules(rules);
|
|
986
|
+
}
|
|
924
987
|
return [{
|
|
925
|
-
name: "
|
|
926
|
-
plugins: { next:
|
|
988
|
+
name: "nextjs/setup",
|
|
989
|
+
plugins: { next: pluginNextJS }
|
|
927
990
|
}, {
|
|
928
991
|
files,
|
|
929
992
|
languageOptions: {
|
|
930
993
|
parserOptions: { ecmaFeatures: { jsx: true } },
|
|
931
994
|
sourceType: "module"
|
|
932
995
|
},
|
|
933
|
-
name: "
|
|
996
|
+
name: "nextjs/rules",
|
|
934
997
|
rules: {
|
|
935
|
-
"
|
|
936
|
-
"
|
|
937
|
-
"
|
|
938
|
-
"next/next-script-for-ga": "warn",
|
|
939
|
-
"next/no-assign-module-variable": "error",
|
|
940
|
-
"next/no-async-client-component": "warn",
|
|
941
|
-
"next/no-before-interactive-script-outside-document": "warn",
|
|
942
|
-
"next/no-css-tags": "warn",
|
|
943
|
-
"next/no-document-import-in-page": "error",
|
|
944
|
-
"next/no-duplicate-head": "error",
|
|
945
|
-
"next/no-head-element": "warn",
|
|
946
|
-
"next/no-head-import-in-document": "error",
|
|
947
|
-
"next/no-html-link-for-pages": "warn",
|
|
948
|
-
"next/no-img-element": "warn",
|
|
949
|
-
"next/no-page-custom-font": "warn",
|
|
950
|
-
"next/no-script-component-in-head": "error",
|
|
951
|
-
"next/no-styled-jsx-in-document": "warn",
|
|
952
|
-
"next/no-sync-scripts": "warn",
|
|
953
|
-
"next/no-title-in-document-head": "warn",
|
|
954
|
-
"next/no-typos": "warn",
|
|
955
|
-
"next/no-unwanted-polyfillio": "warn",
|
|
998
|
+
...getRules("recommended"),
|
|
999
|
+
...getRules("core-web-vitals"),
|
|
1000
|
+
"node/prefer-global/process": "off",
|
|
956
1001
|
...overrides
|
|
957
1002
|
},
|
|
958
1003
|
settings: { react: { version: "detect" } }
|
|
@@ -1159,41 +1204,87 @@ async function pnpm(options) {
|
|
|
1159
1204
|
return configs;
|
|
1160
1205
|
}
|
|
1161
1206
|
//#endregion
|
|
1207
|
+
//#region src/configs/prefer-early-return.ts
|
|
1208
|
+
const defaultMaximumStatements = 1;
|
|
1209
|
+
const pluginPreferEarlyReturn = { rules: { "prefer-early-return": {
|
|
1210
|
+
create(context) {
|
|
1211
|
+
const maxStatements = (context.options[0] || { maximumStatements: defaultMaximumStatements }).maximumStatements;
|
|
1212
|
+
function isLonelyIfStatement(statement) {
|
|
1213
|
+
return statement.type === "IfStatement" && statement.alternate == null;
|
|
1214
|
+
}
|
|
1215
|
+
function isOffendingConsequent(consequent) {
|
|
1216
|
+
return consequent.type === "ExpressionStatement" && maxStatements === 0 || consequent.type === "BlockStatement" && consequent.body.length > maxStatements;
|
|
1217
|
+
}
|
|
1218
|
+
function isOffendingIfStatement(statement) {
|
|
1219
|
+
return isLonelyIfStatement(statement) && isOffendingConsequent(statement.consequent);
|
|
1220
|
+
}
|
|
1221
|
+
function hasSimplifiableConditionalBody(functionBody) {
|
|
1222
|
+
const body = functionBody.body;
|
|
1223
|
+
return functionBody.type === "BlockStatement" && body.length === 1 && isOffendingIfStatement(body[0]);
|
|
1224
|
+
}
|
|
1225
|
+
function checkFunctionBody(functionNode) {
|
|
1226
|
+
const body = functionNode.body;
|
|
1227
|
+
if (hasSimplifiableConditionalBody(body)) context.report(body, "Prefer an early return to a conditionally-wrapped function body");
|
|
1228
|
+
}
|
|
1229
|
+
return {
|
|
1230
|
+
ArrowFunctionExpression: checkFunctionBody,
|
|
1231
|
+
FunctionDeclaration: checkFunctionBody,
|
|
1232
|
+
FunctionExpression: checkFunctionBody
|
|
1233
|
+
};
|
|
1234
|
+
},
|
|
1235
|
+
meta: {
|
|
1236
|
+
docs: {
|
|
1237
|
+
category: "Best Practices",
|
|
1238
|
+
description: "Prefer early returns over full-body conditional wrapping in function declarations.",
|
|
1239
|
+
recommended: false,
|
|
1240
|
+
uri: "https://github.com/Shopify/web-configs/blob/main/packages/eslint-plugin/docs/rules/prefer-early-return.md"
|
|
1241
|
+
},
|
|
1242
|
+
schema: [{
|
|
1243
|
+
additionalProperties: false,
|
|
1244
|
+
properties: { maximumStatements: { type: "integer" } },
|
|
1245
|
+
type: "object"
|
|
1246
|
+
}]
|
|
1247
|
+
}
|
|
1248
|
+
} } };
|
|
1249
|
+
async function preferEarlyReturn() {
|
|
1250
|
+
return [{
|
|
1251
|
+
name: "prefer-early-return/rules",
|
|
1252
|
+
plugins: { "prefer-early-return": pluginPreferEarlyReturn },
|
|
1253
|
+
rules: { "prefer-early-return/prefer-early-return": "error" }
|
|
1254
|
+
}];
|
|
1255
|
+
}
|
|
1256
|
+
//#endregion
|
|
1162
1257
|
//#region src/configs/react.ts
|
|
1258
|
+
const ReactRefreshAllowConstantExportPackages = ["vite"];
|
|
1259
|
+
const RemixPackages = [
|
|
1260
|
+
"@remix-run/node",
|
|
1261
|
+
"@remix-run/react",
|
|
1262
|
+
"@remix-run/serve",
|
|
1263
|
+
"@remix-run/dev"
|
|
1264
|
+
];
|
|
1265
|
+
const ReactRouterPackages = [
|
|
1266
|
+
"@react-router/node",
|
|
1267
|
+
"@react-router/react",
|
|
1268
|
+
"@react-router/serve",
|
|
1269
|
+
"@react-router/dev"
|
|
1270
|
+
];
|
|
1271
|
+
const NextJsPackages = ["next"];
|
|
1163
1272
|
async function react(options = {}) {
|
|
1164
|
-
const { files = [GLOB_SRC], filesTypeAware = [GLOB_TS, GLOB_TSX], ignoresTypeAware = [`${GLOB_MARKDOWN}/**`], overrides = {}, tsconfigPath
|
|
1165
|
-
await ensurePackages([
|
|
1166
|
-
"@eslint-react/eslint-plugin",
|
|
1167
|
-
"eslint-plugin-react-hooks",
|
|
1168
|
-
"eslint-plugin-react-refresh"
|
|
1169
|
-
]);
|
|
1273
|
+
const { files = [GLOB_SRC], filesTypeAware = [GLOB_TS, GLOB_TSX], ignoresTypeAware = [`${GLOB_MARKDOWN}/**`], overrides = {}, tsconfigPath } = options;
|
|
1274
|
+
await ensurePackages(["@eslint-react/eslint-plugin", "eslint-plugin-react-refresh"]);
|
|
1170
1275
|
const isTypeAware = !!tsconfigPath;
|
|
1171
|
-
const typeAwareRules = {
|
|
1172
|
-
|
|
1173
|
-
"react/no-implicit-key": "error"
|
|
1174
|
-
};
|
|
1175
|
-
const [pluginReact, pluginReactHooks, pluginReactRefresh] = await Promise.all([
|
|
1176
|
-
interopDefault(import("@eslint-react/eslint-plugin")),
|
|
1177
|
-
interopDefault(import("eslint-plugin-react-hooks")),
|
|
1178
|
-
interopDefault(import("eslint-plugin-react-refresh"))
|
|
1179
|
-
]);
|
|
1276
|
+
const typeAwareRules = { "react/no-leaked-conditional-rendering": "error" };
|
|
1277
|
+
const [pluginReact, pluginReactRefresh] = await Promise.all([interopDefault(import("@eslint-react/eslint-plugin")), interopDefault(import("eslint-plugin-react-refresh"))]);
|
|
1180
1278
|
const isAllowConstantExport = ReactRefreshAllowConstantExportPackages.some((i) => isPackageExists(i));
|
|
1181
1279
|
const isUsingRemix = RemixPackages.some((i) => isPackageExists(i));
|
|
1182
1280
|
const isUsingReactRouter = ReactRouterPackages.some((i) => isPackageExists(i));
|
|
1183
1281
|
const isUsingNext = NextJsPackages.some((i) => isPackageExists(i));
|
|
1184
|
-
const plugins = pluginReact.configs.all.plugins;
|
|
1185
1282
|
return [
|
|
1186
1283
|
{
|
|
1187
1284
|
name: "react/setup",
|
|
1188
1285
|
plugins: {
|
|
1189
|
-
"react": plugins["@eslint-react"],
|
|
1190
|
-
"react-
|
|
1191
|
-
"react-hooks": pluginReactHooks,
|
|
1192
|
-
"react-hooks-extra": plugins["@eslint-react/hooks-extra"],
|
|
1193
|
-
"react-naming-convention": plugins["@eslint-react/naming-convention"],
|
|
1194
|
-
"react-refresh": pluginReactRefresh,
|
|
1195
|
-
"react-rsc": plugins["@eslint-react/rsc"],
|
|
1196
|
-
"react-web-api": plugins["@eslint-react/web-api"]
|
|
1286
|
+
"react": pluginReact.configs.all.plugins["@eslint-react"],
|
|
1287
|
+
"react-refresh": pluginReactRefresh
|
|
1197
1288
|
}
|
|
1198
1289
|
},
|
|
1199
1290
|
{
|
|
@@ -1204,89 +1295,7 @@ async function react(options = {}) {
|
|
|
1204
1295
|
},
|
|
1205
1296
|
name: "react/rules",
|
|
1206
1297
|
rules: {
|
|
1207
|
-
|
|
1208
|
-
"react/jsx-no-comment-textnodes": "warn",
|
|
1209
|
-
"react/jsx-no-duplicate-props": "warn",
|
|
1210
|
-
"react/jsx-uses-react": "warn",
|
|
1211
|
-
"react/jsx-uses-vars": "warn",
|
|
1212
|
-
"react/no-access-state-in-setstate": "error",
|
|
1213
|
-
"react/no-array-index-key": "warn",
|
|
1214
|
-
"react/no-children-count": "warn",
|
|
1215
|
-
"react/no-children-for-each": "warn",
|
|
1216
|
-
"react/no-children-map": "warn",
|
|
1217
|
-
"react/no-children-only": "warn",
|
|
1218
|
-
"react/no-children-to-array": "warn",
|
|
1219
|
-
"react/no-clone-element": "warn",
|
|
1220
|
-
"react/no-component-will-mount": "error",
|
|
1221
|
-
"react/no-component-will-receive-props": "error",
|
|
1222
|
-
"react/no-component-will-update": "error",
|
|
1223
|
-
"react/no-context-provider": "warn",
|
|
1224
|
-
"react/no-create-ref": "error",
|
|
1225
|
-
"react/no-default-props": "error",
|
|
1226
|
-
"react/no-direct-mutation-state": "error",
|
|
1227
|
-
"react/no-forward-ref": "warn",
|
|
1228
|
-
"react/no-missing-key": "error",
|
|
1229
|
-
"react/no-nested-component-definitions": "error",
|
|
1230
|
-
"react/no-nested-lazy-component-declarations": "error",
|
|
1231
|
-
"react/no-prop-types": "error",
|
|
1232
|
-
"react/no-redundant-should-component-update": "error",
|
|
1233
|
-
"react/no-set-state-in-component-did-mount": "warn",
|
|
1234
|
-
"react/no-set-state-in-component-did-update": "warn",
|
|
1235
|
-
"react/no-set-state-in-component-will-update": "warn",
|
|
1236
|
-
"react/no-string-refs": "error",
|
|
1237
|
-
"react/no-unnecessary-use-prefix": "warn",
|
|
1238
|
-
"react/no-unsafe-component-will-mount": "warn",
|
|
1239
|
-
"react/no-unsafe-component-will-receive-props": "warn",
|
|
1240
|
-
"react/no-unsafe-component-will-update": "warn",
|
|
1241
|
-
"react/no-unused-class-component-members": "warn",
|
|
1242
|
-
"react/no-use-context": "warn",
|
|
1243
|
-
"react/no-useless-forward-ref": "warn",
|
|
1244
|
-
"react/prefer-use-state-lazy-initialization": "warn",
|
|
1245
|
-
"react/prefer-namespace-import": "error",
|
|
1246
|
-
"react/jsx-shorthand-boolean": "warn",
|
|
1247
|
-
"react/prefer-destructuring-assignment": "warn",
|
|
1248
|
-
"react/no-missing-context-display-name": "warn",
|
|
1249
|
-
"react/no-missing-component-display-name": "warn",
|
|
1250
|
-
"react-rsc/function-definition": "error",
|
|
1251
|
-
"react-dom/no-dangerously-set-innerhtml": "warn",
|
|
1252
|
-
"react-dom/no-dangerously-set-innerhtml-with-children": "error",
|
|
1253
|
-
"react-dom/no-find-dom-node": "error",
|
|
1254
|
-
"react-dom/no-flush-sync": "error",
|
|
1255
|
-
"react-dom/no-hydrate": "error",
|
|
1256
|
-
"react-dom/no-namespace": "error",
|
|
1257
|
-
"react-dom/no-render": "error",
|
|
1258
|
-
"react-dom/no-render-return-value": "error",
|
|
1259
|
-
"react-dom/no-script-url": "warn",
|
|
1260
|
-
"react-dom/no-unsafe-iframe-sandbox": "warn",
|
|
1261
|
-
"react-dom/no-use-form-state": "error",
|
|
1262
|
-
"react-dom/no-void-elements-with-children": "error",
|
|
1263
|
-
"react-hooks-extra/no-direct-set-state-in-use-effect": "warn",
|
|
1264
|
-
"react-naming-convention/context-name": "warn",
|
|
1265
|
-
"react-naming-convention/ref-name": "warn",
|
|
1266
|
-
"react-naming-convention/use-state": "warn",
|
|
1267
|
-
"react-web-api/no-leaked-event-listener": "warn",
|
|
1268
|
-
"react-web-api/no-leaked-interval": "warn",
|
|
1269
|
-
"react-web-api/no-leaked-resize-observer": "warn",
|
|
1270
|
-
"react-web-api/no-leaked-timeout": "warn",
|
|
1271
|
-
"react-hooks/rules-of-hooks": "error",
|
|
1272
|
-
"react-hooks/exhaustive-deps": "warn",
|
|
1273
|
-
...reactCompiler ? {
|
|
1274
|
-
"react-hooks/config": "error",
|
|
1275
|
-
"react-hooks/error-boundaries": "error",
|
|
1276
|
-
"react-hooks/component-hook-factories": "error",
|
|
1277
|
-
"react-hooks/gating": "error",
|
|
1278
|
-
"react-hooks/globals": "error",
|
|
1279
|
-
"react-hooks/immutability": "error",
|
|
1280
|
-
"react-hooks/preserve-manual-memoization": "error",
|
|
1281
|
-
"react-hooks/purity": "error",
|
|
1282
|
-
"react-hooks/refs": "error",
|
|
1283
|
-
"react-hooks/set-state-in-effect": "error",
|
|
1284
|
-
"react-hooks/set-state-in-render": "error",
|
|
1285
|
-
"react-hooks/static-components": "error",
|
|
1286
|
-
"react-hooks/unsupported-syntax": "warn",
|
|
1287
|
-
"react-hooks/use-memo": "error",
|
|
1288
|
-
"react-hooks/incompatible-library": "warn"
|
|
1289
|
-
} : {},
|
|
1298
|
+
...pluginReact.configs.recommended.rules,
|
|
1290
1299
|
"react-refresh/only-export-components": ["error", {
|
|
1291
1300
|
allowConstantExport: isAllowConstantExport,
|
|
1292
1301
|
allowExportNames: [...isUsingNext ? [
|
|
@@ -1323,12 +1332,8 @@ async function react(options = {}) {
|
|
|
1323
1332
|
files: filesTypeAware,
|
|
1324
1333
|
name: "react/typescript",
|
|
1325
1334
|
rules: {
|
|
1326
|
-
"react-
|
|
1327
|
-
"react-
|
|
1328
|
-
"react/jsx-no-duplicate-props": "off",
|
|
1329
|
-
"react/jsx-no-undef": "off",
|
|
1330
|
-
"react/jsx-uses-react": "off",
|
|
1331
|
-
"react/jsx-uses-vars": "off"
|
|
1335
|
+
"react/dom-no-string-style-prop": "off",
|
|
1336
|
+
"react/dom-no-unknown-property": "off"
|
|
1332
1337
|
}
|
|
1333
1338
|
},
|
|
1334
1339
|
...isTypeAware ? [{
|
|
@@ -1340,71 +1345,6 @@ async function react(options = {}) {
|
|
|
1340
1345
|
];
|
|
1341
1346
|
}
|
|
1342
1347
|
//#endregion
|
|
1343
|
-
//#region src/configs/react-native.ts
|
|
1344
|
-
async function reactNative(options = {}) {
|
|
1345
|
-
const { expo = isPackageExists("expo"), files = [GLOB_SRC], overrides = {} } = options;
|
|
1346
|
-
await ensurePackages([
|
|
1347
|
-
"@react-native/eslint-plugin",
|
|
1348
|
-
"eslint-plugin-react-native",
|
|
1349
|
-
...expo ? ["eslint-plugin-expo"] : []
|
|
1350
|
-
]);
|
|
1351
|
-
const [pluginReactNative, pluginReactNativeCommunity, pluginExpo] = await Promise.all([
|
|
1352
|
-
interopDefault(import("@react-native/eslint-plugin")),
|
|
1353
|
-
interopDefault(import("eslint-plugin-react-native")),
|
|
1354
|
-
...expo ? [interopDefault(import("eslint-plugin-expo"))] : []
|
|
1355
|
-
]);
|
|
1356
|
-
return [{
|
|
1357
|
-
name: "react-native/setup",
|
|
1358
|
-
plugins: {
|
|
1359
|
-
"react-native": pluginReactNative,
|
|
1360
|
-
"react-native-community": pluginReactNativeCommunity,
|
|
1361
|
-
...expo ? { expo: pluginExpo } : {}
|
|
1362
|
-
}
|
|
1363
|
-
}, {
|
|
1364
|
-
files,
|
|
1365
|
-
languageOptions: {
|
|
1366
|
-
globals: {
|
|
1367
|
-
...globals.browser,
|
|
1368
|
-
"__DEV__": "readonly",
|
|
1369
|
-
"alert": false,
|
|
1370
|
-
"cancelAnimationFrame": false,
|
|
1371
|
-
"cancelIdleCallback": false,
|
|
1372
|
-
"clearImmediate": false,
|
|
1373
|
-
"ErrorUtils": false,
|
|
1374
|
-
"fetch": false,
|
|
1375
|
-
"FormData": false,
|
|
1376
|
-
"navigator": false,
|
|
1377
|
-
"process": false,
|
|
1378
|
-
"requestAnimationFrame": false,
|
|
1379
|
-
"requestIdleCallback": false,
|
|
1380
|
-
"setImmediate": false,
|
|
1381
|
-
"shared-node-browser": true,
|
|
1382
|
-
"window": false,
|
|
1383
|
-
"XMLHttpRequest": false
|
|
1384
|
-
},
|
|
1385
|
-
parserOptions: { ecmaFeatures: { jsx: true } },
|
|
1386
|
-
sourceType: "module"
|
|
1387
|
-
},
|
|
1388
|
-
name: "react-native/rules",
|
|
1389
|
-
rules: {
|
|
1390
|
-
"node/prefer-global/process": "off",
|
|
1391
|
-
"react-native-community/no-inline-styles": "warn",
|
|
1392
|
-
"react-native-community/no-raw-text": "warn",
|
|
1393
|
-
"react-native-community/no-single-element-style-arrays": "warn",
|
|
1394
|
-
"react-native-community/no-unused-styles": "warn",
|
|
1395
|
-
"react-native/no-deep-imports": "error",
|
|
1396
|
-
"ts/no-require-imports": ["warn", { allow: ["\\.(aac|aiff|avif|bmp|caf|db|gif|heic|html|jpeg|jpg|json|m4a|m4v|mov|mp3|mp4|mpeg|mpg|otf|pdf|png|psd|svg|ttf|wav|webm|webp|xml|yaml|yml|zip)$"] }],
|
|
1397
|
-
...expo ? {
|
|
1398
|
-
"expo/no-dynamic-env-var": "error",
|
|
1399
|
-
"expo/no-env-var-destructuring": "error",
|
|
1400
|
-
"expo/use-dom-exports": "error"
|
|
1401
|
-
} : {},
|
|
1402
|
-
...overrides
|
|
1403
|
-
},
|
|
1404
|
-
settings: { react: { version: "detect" } }
|
|
1405
|
-
}];
|
|
1406
|
-
}
|
|
1407
|
-
//#endregion
|
|
1408
1348
|
//#region src/configs/regexp.ts
|
|
1409
1349
|
async function regexp(options = {}) {
|
|
1410
1350
|
const config = configs["flat/recommended"];
|
|
@@ -1422,6 +1362,18 @@ async function regexp(options = {}) {
|
|
|
1422
1362
|
}];
|
|
1423
1363
|
}
|
|
1424
1364
|
//#endregion
|
|
1365
|
+
//#region src/configs/sonarjs.ts
|
|
1366
|
+
async function sonarjs(options = {}) {
|
|
1367
|
+
return [{
|
|
1368
|
+
name: "sonarjs/rules",
|
|
1369
|
+
plugins: { sonarjs: pluginSonarJs },
|
|
1370
|
+
rules: {
|
|
1371
|
+
...pluginSonarJs.configs.recommended.rules,
|
|
1372
|
+
...options.overrides
|
|
1373
|
+
}
|
|
1374
|
+
}];
|
|
1375
|
+
}
|
|
1376
|
+
//#endregion
|
|
1425
1377
|
//#region src/configs/sort.ts
|
|
1426
1378
|
/**
|
|
1427
1379
|
* Sort package.json
|
|
@@ -1656,29 +1608,63 @@ function sortTsconfig() {
|
|
|
1656
1608
|
}
|
|
1657
1609
|
//#endregion
|
|
1658
1610
|
//#region src/configs/tailwindcss.ts
|
|
1659
|
-
|
|
1660
|
-
|
|
1611
|
+
let _pluginTailwindCSS;
|
|
1612
|
+
async function tailwindcss(options) {
|
|
1613
|
+
const { detectComponentClasses, entryPoint, overrides = {}, rootFontSize, selectors, stylistic = true, tsconfigPath } = options;
|
|
1661
1614
|
await ensurePackages(["eslint-plugin-better-tailwindcss"]);
|
|
1662
1615
|
const [pluginTailwindCSS] = await Promise.all([interopDefault(import("eslint-plugin-better-tailwindcss"))]);
|
|
1663
|
-
|
|
1616
|
+
_pluginTailwindCSS = _pluginTailwindCSS || {
|
|
1617
|
+
...pluginTailwindCSS,
|
|
1618
|
+
rules: {
|
|
1619
|
+
...pluginTailwindCSS.rules,
|
|
1620
|
+
"multiline-classname": {
|
|
1621
|
+
create(context) {
|
|
1622
|
+
return { JSXAttribute(node) {
|
|
1623
|
+
if (node.name?.type !== "JSXIdentifier") return;
|
|
1624
|
+
if (node.name.name !== "className") return;
|
|
1625
|
+
if (node.value?.type === "Literal" && typeof node.value.value === "string" && node.value.value.includes("\n")) {
|
|
1626
|
+
const raw = node.value.value;
|
|
1627
|
+
context.report({
|
|
1628
|
+
fix(fixer) {
|
|
1629
|
+
const escaped = raw.replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
1630
|
+
return fixer.replaceText(node.value, `{\`${escaped}\`}`);
|
|
1631
|
+
},
|
|
1632
|
+
message: "Multiline className strings can cause hydration errors. Use a template literal/expression instead.",
|
|
1633
|
+
node: node.value
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
} };
|
|
1637
|
+
},
|
|
1638
|
+
meta: {
|
|
1639
|
+
fixable: "code",
|
|
1640
|
+
schema: [],
|
|
1641
|
+
type: "suggestion"
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
};
|
|
1646
|
+
const { indent = 2, printWidth = 100, tabWidth = 4 } = typeof stylistic === "boolean" ? {} : stylistic;
|
|
1664
1647
|
return [{
|
|
1665
1648
|
name: "tailwindcss",
|
|
1666
|
-
plugins: { tailwindcss:
|
|
1649
|
+
plugins: { "better-tailwindcss": _pluginTailwindCSS },
|
|
1667
1650
|
rules: {
|
|
1668
1651
|
...stylistic ? {
|
|
1669
|
-
|
|
1670
|
-
"tailwindcss/enforce-consistent-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1652
|
+
...pluginTailwindCSS.configs.stylistic.rules,
|
|
1653
|
+
"better-tailwindcss/enforce-consistent-line-wrapping": ["warn", {
|
|
1654
|
+
indent: typeof indent === "number" ? indent : indent === "tab" ? "tab" : 2,
|
|
1655
|
+
printWidth,
|
|
1656
|
+
tabWidth: typeof indent === "number" ? indent : indent === "tab" ? tabWidth : 2
|
|
1657
|
+
}],
|
|
1658
|
+
"better-tailwindcss/multiline-classname": "error"
|
|
1675
1659
|
} : {},
|
|
1676
|
-
|
|
1677
|
-
"tailwindcss/no-unknown-classes": "error",
|
|
1660
|
+
...pluginTailwindCSS.configs.correctness.rules,
|
|
1678
1661
|
...overrides
|
|
1679
1662
|
},
|
|
1680
1663
|
settings: { "better-tailwindcss": {
|
|
1664
|
+
detectComponentClasses,
|
|
1681
1665
|
entryPoint,
|
|
1666
|
+
rootFontSize,
|
|
1667
|
+
selectors,
|
|
1682
1668
|
tsconfig: tsconfigPath
|
|
1683
1669
|
} }
|
|
1684
1670
|
}];
|
|
@@ -1713,6 +1699,7 @@ async function test(options = {}) {
|
|
|
1713
1699
|
"test/prefer-hooks-in-order": "error",
|
|
1714
1700
|
"test/prefer-lowercase-title": "error",
|
|
1715
1701
|
"antfu/no-top-level-await": "off",
|
|
1702
|
+
"baseline-js/use-baseline": "off",
|
|
1716
1703
|
"e18e/prefer-static-regex": "off",
|
|
1717
1704
|
"no-unused-expressions": "off",
|
|
1718
1705
|
"node/prefer-global/process": "off",
|
|
@@ -1893,8 +1880,8 @@ async function typescript(options = {}) {
|
|
|
1893
1880
|
}
|
|
1894
1881
|
}] : [],
|
|
1895
1882
|
...erasableOnly ? [{
|
|
1896
|
-
name: "
|
|
1897
|
-
plugins: { "erasable-syntax-only": await interopDefault(import("./lib-
|
|
1883
|
+
name: "typescript/erasable-syntax-only",
|
|
1884
|
+
plugins: { "erasable-syntax-only": await interopDefault(import("./lib-C1Uxp5ZW.mjs")) },
|
|
1898
1885
|
rules: {
|
|
1899
1886
|
"erasable-syntax-only/enums": "error",
|
|
1900
1887
|
"erasable-syntax-only/import-aliases": "error",
|
|
@@ -1956,11 +1943,6 @@ async function vue(options = {}) {
|
|
|
1956
1943
|
const { a11y = false, files = [GLOB_VUE], overrides = {}, stylistic = true, vueVersion = 3 } = options;
|
|
1957
1944
|
const sfcBlocks = options.sfcBlocks === true ? {} : options.sfcBlocks ?? {};
|
|
1958
1945
|
const { indent = 2 } = typeof stylistic === "boolean" ? {} : stylistic;
|
|
1959
|
-
await ensurePackages([
|
|
1960
|
-
"eslint-plugin-vue",
|
|
1961
|
-
"vue-eslint-parser",
|
|
1962
|
-
"eslint-processor-vue-blocks"
|
|
1963
|
-
]);
|
|
1964
1946
|
if (a11y) await ensurePackages(["eslint-plugin-vuejs-accessibility"]);
|
|
1965
1947
|
const [pluginVue, parserVue, processorVueBlocks, pluginVueA11y] = await Promise.all([
|
|
1966
1948
|
interopDefault(import("eslint-plugin-vue")),
|
|
@@ -2203,22 +2185,6 @@ async function yaml(options = {}) {
|
|
|
2203
2185
|
}];
|
|
2204
2186
|
}
|
|
2205
2187
|
//#endregion
|
|
2206
|
-
//#region src/configs/e18e.ts
|
|
2207
|
-
async function e18e(options = {}) {
|
|
2208
|
-
const { isInEditor = false, modernization = true, type = "app", moduleReplacements = type === "lib" && isInEditor, overrides = {}, performanceImprovements = true } = options;
|
|
2209
|
-
const configs = pluginE18e.configs;
|
|
2210
|
-
return [{
|
|
2211
|
-
name: "antfu/e18e/rules",
|
|
2212
|
-
plugins: { e18e: pluginE18e },
|
|
2213
|
-
rules: {
|
|
2214
|
-
...modernization ? { ...configs.modernization.rules } : {},
|
|
2215
|
-
...moduleReplacements ? { ...configs.moduleReplacements.rules } : {},
|
|
2216
|
-
...performanceImprovements ? { ...configs.performanceImprovements.rules } : {},
|
|
2217
|
-
...overrides
|
|
2218
|
-
}
|
|
2219
|
-
}];
|
|
2220
|
-
}
|
|
2221
|
-
//#endregion
|
|
2222
2188
|
//#region src/factory.ts
|
|
2223
2189
|
const flatConfigProps = [
|
|
2224
2190
|
"name",
|
|
@@ -2229,15 +2195,17 @@ const flatConfigProps = [
|
|
|
2229
2195
|
"rules",
|
|
2230
2196
|
"settings"
|
|
2231
2197
|
];
|
|
2198
|
+
const VuePackages = [
|
|
2199
|
+
"vue",
|
|
2200
|
+
"nuxt",
|
|
2201
|
+
"vitepress",
|
|
2202
|
+
"@slidev/cli"
|
|
2203
|
+
];
|
|
2232
2204
|
const defaultPluginRenaming = {
|
|
2233
2205
|
"@eslint-react": "react",
|
|
2234
|
-
"@eslint-react/dom": "react-dom",
|
|
2235
|
-
"@eslint-react/hooks-extra": "react-hooks-extra",
|
|
2236
|
-
"@eslint-react/naming-convention": "react-naming-convention",
|
|
2237
2206
|
"@next/next": "next",
|
|
2238
2207
|
"@stylistic": "style",
|
|
2239
2208
|
"@typescript-eslint": "ts",
|
|
2240
|
-
"better-tailwindcss": "tailwindcss",
|
|
2241
2209
|
"import-lite": "import",
|
|
2242
2210
|
"n": "node",
|
|
2243
2211
|
"vitest": "test",
|
|
@@ -2254,7 +2222,7 @@ const defaultPluginRenaming = {
|
|
|
2254
2222
|
* The merged ESLint configurations.
|
|
2255
2223
|
*/
|
|
2256
2224
|
function config(options = {}, ...userConfigs) {
|
|
2257
|
-
const { autoRenamePlugins = true, componentExts = [], e18e: enableE18e = true, gitignore: enableGitignore = true, ignores: userIgnores = [], imports: enableImports = true, jsdoc: enableJsdoc = true, jsx: enableJsx = true, nextjs:
|
|
2225
|
+
const { autoRenamePlugins = true, baseline: enableBaseLineJs = false, componentExts = [], e18e: enableE18e = true, gitignore: enableGitignore = true, ignores: userIgnores = [], imports: enableImports = true, jsdoc: enableJsdoc = true, jsx: enableJsx = true, nextjs: enableNextjs = isPackageExists("next"), node: enableNode = true, pnpm: enableCatalogs = !!findUpSync("pnpm-workspace.yaml"), react: enableReact = false, regexp: enableRegexp = true, sonarjs: enableSonarJs = false, tailwindcss: enableTailwindCSS = isPackageExists("tailwindcss"), type: appType = "app", typescript: enableTypeScript = isPackageExists("typescript") || isPackageExists("@typescript/native-preview"), unicorn: enableUnicorn = true, unocss: enableUnoCSS = false, vue: enableVue = VuePackages.some((i) => isPackageExists(i)) } = options;
|
|
2258
2226
|
let isInEditor = options.isInEditor;
|
|
2259
2227
|
if (isInEditor == null) {
|
|
2260
2228
|
isInEditor = isInEditorEnv();
|
|
@@ -2276,17 +2244,19 @@ function config(options = {}, ...userConfigs) {
|
|
|
2276
2244
|
configs.push(ignores(userIgnores, !enableTypeScript), javascript({
|
|
2277
2245
|
isInEditor,
|
|
2278
2246
|
overrides: getOverrides(options, "javascript")
|
|
2279
|
-
}), comments(), command(), perfectionist());
|
|
2247
|
+
}), comments(), command(), deMorgan(), preferEarlyReturn(), perfectionist());
|
|
2280
2248
|
if (enableNode) configs.push(node());
|
|
2281
2249
|
if (enableJsdoc) configs.push(jsdoc({ stylistic: stylisticOptions }));
|
|
2282
2250
|
if (enableImports) configs.push(imports({
|
|
2283
2251
|
stylistic: stylisticOptions,
|
|
2284
2252
|
...resolveSubOptions(options, "imports")
|
|
2285
2253
|
}));
|
|
2254
|
+
if (enableBaseLineJs) configs.push(baseline({ ...resolveSubOptions(options, "baseline") }));
|
|
2286
2255
|
if (enableE18e) configs.push(e18e({
|
|
2287
2256
|
isInEditor,
|
|
2288
2257
|
...enableE18e === true ? {} : enableE18e
|
|
2289
2258
|
}));
|
|
2259
|
+
if (enableSonarJs) configs.push(sonarjs({ ...resolveSubOptions(options, "sonarjs") }));
|
|
2290
2260
|
if (enableUnicorn) configs.push(unicorn(enableUnicorn === true ? {} : enableUnicorn));
|
|
2291
2261
|
if (enableVue) componentExts.push("vue");
|
|
2292
2262
|
if (enableJsx) configs.push(jsx(enableJsx === true ? {} : enableJsx));
|
|
@@ -2298,6 +2268,7 @@ function config(options = {}, ...userConfigs) {
|
|
|
2298
2268
|
}));
|
|
2299
2269
|
if (stylisticOptions) configs.push(stylistic({
|
|
2300
2270
|
...stylisticOptions,
|
|
2271
|
+
lessOpinionated: options.lessOpinionated,
|
|
2301
2272
|
overrides: getOverrides(options, "stylistic")
|
|
2302
2273
|
}));
|
|
2303
2274
|
if (enableRegexp) configs.push(regexp(typeof enableRegexp === "boolean" ? {} : enableRegexp));
|
|
@@ -2317,11 +2288,7 @@ function config(options = {}, ...userConfigs) {
|
|
|
2317
2288
|
overrides: getOverrides(options, "react"),
|
|
2318
2289
|
tsconfigPath
|
|
2319
2290
|
}));
|
|
2320
|
-
if (
|
|
2321
|
-
...resolveSubOptions(options, "reactNative"),
|
|
2322
|
-
overrides: getOverrides(options, "reactNative")
|
|
2323
|
-
}));
|
|
2324
|
-
if (enableNext) configs.push(nextjs({ overrides: getOverrides(options, "nextjs") }));
|
|
2291
|
+
if (enableNextjs) configs.push(nextjs({ overrides: getOverrides(options, "nextjs") }));
|
|
2325
2292
|
if (enableUnoCSS) configs.push(unocss({
|
|
2326
2293
|
...resolveSubOptions(options, "unocss"),
|
|
2327
2294
|
overrides: getOverrides(options, "unocss")
|
|
@@ -2367,6 +2334,7 @@ function config(options = {}, ...userConfigs) {
|
|
|
2367
2334
|
if (Object.keys(fusedConfig).length) configs.push([fusedConfig]);
|
|
2368
2335
|
let composer = new FlatConfigComposer();
|
|
2369
2336
|
composer = composer.append(...configs, ...userConfigs);
|
|
2337
|
+
if (options.markdown ?? true) composer = composer.setDefaultIgnores((prev) => [...prev, GLOB_MARKDOWN]);
|
|
2370
2338
|
if (autoRenamePlugins) composer = composer.renamePlugins(defaultPluginRenaming);
|
|
2371
2339
|
if (isInEditor) composer = composer.disableRulesFix([
|
|
2372
2340
|
"unused-imports/no-unused-imports",
|
|
@@ -2375,9 +2343,17 @@ function config(options = {}, ...userConfigs) {
|
|
|
2375
2343
|
], { builtinRules: () => import(["eslint", "use-at-your-own-risk"].join("/")).then((r) => r.builtinRules) });
|
|
2376
2344
|
return composer;
|
|
2377
2345
|
}
|
|
2346
|
+
function resolveSubOptions(options, key) {
|
|
2347
|
+
return typeof options[key] === "boolean" ? {} : options[key] || {};
|
|
2348
|
+
}
|
|
2349
|
+
function getOverrides(options, key) {
|
|
2350
|
+
const sub = resolveSubOptions(options, key);
|
|
2351
|
+
return { ..."overrides" in sub ? sub.overrides : {} };
|
|
2352
|
+
}
|
|
2378
2353
|
//#endregion
|
|
2379
2354
|
//#region src/config-presets.ts
|
|
2380
2355
|
const CONFIG_PRESET_FULL_ON = {
|
|
2356
|
+
baseline: true,
|
|
2381
2357
|
formatters: true,
|
|
2382
2358
|
gitignore: true,
|
|
2383
2359
|
imports: true,
|
|
@@ -2388,11 +2364,11 @@ const CONFIG_PRESET_FULL_ON = {
|
|
|
2388
2364
|
nextjs: true,
|
|
2389
2365
|
node: true,
|
|
2390
2366
|
pnpm: true,
|
|
2391
|
-
react:
|
|
2392
|
-
reactNative: { expo: true },
|
|
2367
|
+
react: true,
|
|
2393
2368
|
regexp: true,
|
|
2369
|
+
sonarjs: true,
|
|
2394
2370
|
stylistic: { experimental: true },
|
|
2395
|
-
tailwindcss:
|
|
2371
|
+
tailwindcss: { entryPoint: "fixtures/stub.css" },
|
|
2396
2372
|
test: true,
|
|
2397
2373
|
toml: true,
|
|
2398
2374
|
typescript: {
|
|
@@ -2405,6 +2381,7 @@ const CONFIG_PRESET_FULL_ON = {
|
|
|
2405
2381
|
yaml: true
|
|
2406
2382
|
};
|
|
2407
2383
|
const CONFIG_PRESET_FULL_OFF = {
|
|
2384
|
+
baseline: false,
|
|
2408
2385
|
formatters: false,
|
|
2409
2386
|
gitignore: false,
|
|
2410
2387
|
imports: false,
|
|
@@ -2416,8 +2393,8 @@ const CONFIG_PRESET_FULL_OFF = {
|
|
|
2416
2393
|
node: false,
|
|
2417
2394
|
pnpm: false,
|
|
2418
2395
|
react: false,
|
|
2419
|
-
reactNative: false,
|
|
2420
2396
|
regexp: false,
|
|
2397
|
+
sonarjs: false,
|
|
2421
2398
|
stylistic: false,
|
|
2422
2399
|
tailwindcss: false,
|
|
2423
2400
|
test: false,
|
|
@@ -2432,4 +2409,4 @@ const CONFIG_PRESET_FULL_OFF = {
|
|
|
2432
2409
|
//#region src/index.ts
|
|
2433
2410
|
var src_default = config;
|
|
2434
2411
|
//#endregion
|
|
2435
|
-
export { CONFIG_PRESET_FULL_OFF, CONFIG_PRESET_FULL_ON, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_SVG, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, StylisticConfigDefaults,
|
|
2412
|
+
export { CONFIG_PRESET_FULL_OFF, CONFIG_PRESET_FULL_ON, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_GRAPHQL, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_SVG, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, StylisticConfigDefaults, baseline, command, comments, config, deMorgan, src_default as default, defaultPluginRenaming, disables, e18e, ensurePackages, formatters, getOverrides, ignores, imports, interopDefault, isInEditorEnv, isInGitHooksOrLintStaged, isPackageInScope, javascript, jsdoc, jsonc, jsx, markdown, nextjs, node, parserPlain, perfectionist, pnpm, preferEarlyReturn, react, regexp, renameRules, resolveSubOptions, sonarjs, sortPackageJson, sortTsconfig, stylistic, tailwindcss, test, toml, typescript, unicorn, unocss, vue, yaml };
|