@ntnyq/eslint-config 5.0.0-beta.1 → 5.0.0-beta.3

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.js ADDED
@@ -0,0 +1,3136 @@
1
+ import { FlatConfigComposer } from "eslint-flat-config-utils";
2
+ import { mergeProcessors, mergeProcessors as mergeProcessors$1, processorPassThrough } from "eslint-merge-processors";
3
+ import { configs as configsTypeScript, parser as parserTypeScript, plugin as pluginTypeScript } from "typescript-eslint";
4
+ import * as parserVue from "vue-eslint-parser";
5
+ import * as parserToml from "toml-eslint-parser";
6
+ import * as parserYaml from "yaml-eslint-parser";
7
+ import * as parserPlain from "eslint-parser-plain";
8
+ import * as parserJsonc from "jsonc-eslint-parser";
9
+ import * as pluginRegexp from "eslint-plugin-regexp";
10
+ import pluginNode from "eslint-plugin-n";
11
+ import pluginVue from "eslint-plugin-vue";
12
+ import pluginYml from "eslint-plugin-yml";
13
+ import pluginSvgo from "eslint-plugin-svgo";
14
+ import pluginToml from "eslint-plugin-toml";
15
+ import pluginMarkdown from "@eslint/markdown";
16
+ import pluginAntfu from "eslint-plugin-antfu";
17
+ import pluginJsdoc from "eslint-plugin-jsdoc";
18
+ import pluginJsonc from "eslint-plugin-jsonc";
19
+ import pluginNtnyq from "eslint-plugin-ntnyq";
20
+ import pluginPinia from "eslint-plugin-pinia";
21
+ import pluginDepend from "eslint-plugin-depend";
22
+ import pluginUnoCSS from "@unocss/eslint-plugin";
23
+ import pluginVitest from "@vitest/eslint-plugin";
24
+ import pluginUnicorn from "eslint-plugin-unicorn";
25
+ import pluginImportX from "eslint-plugin-import-x";
26
+ import pluginPrettier from "eslint-plugin-prettier";
27
+ import pluginDeMorgan from "eslint-plugin-de-morgan";
28
+ import pluginNoOnlyTests from "eslint-plugin-no-only-tests";
29
+ import pluginGitHubAction from "eslint-plugin-github-action";
30
+ import pluginPerfectionist from "eslint-plugin-perfectionist";
31
+ import pluginComments from "@eslint-community/eslint-plugin-eslint-comments";
32
+ import processorVueBlocks from "eslint-processor-vue-blocks";
33
+ import { resolve } from "node:path";
34
+ import process from "node:process";
35
+ import { isPackageExists } from "local-pkg";
36
+ import { builtinCommands, defineCommand } from "eslint-plugin-command/commands";
37
+ import createCommandConfig from "eslint-plugin-command/config";
38
+ import { createTypeScriptImportResolver } from "eslint-import-resolver-typescript";
39
+ import globals from "globals";
40
+ import createGitIgnoreConfig from "eslint-config-flat-gitignore";
41
+ import jsConfig from "@eslint/js";
42
+
43
+ //#region src/globs.ts
44
+ /**
45
+ * @file globs constants
46
+ */
47
+ const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
48
+ const GLOB_SRC = `**/*.${GLOB_SRC_EXT}`;
49
+ const GLOB_JS = "**/*.?([cm])js";
50
+ const GLOB_JSX = `${GLOB_JS}x`;
51
+ const GLOB_JSX_ONLY = "**/*.jsx";
52
+ const GLOB_TS = "**/*.?([cm])ts";
53
+ const GLOB_TSX = `${GLOB_TS}x`;
54
+ const GLOB_TSX_ONLY = "**/*.tsx";
55
+ const GLOB_DTS = "**/*.d.?([cm])ts";
56
+ const GLOB_TYPES = [
57
+ GLOB_DTS,
58
+ `**/types/${GLOB_TS}`,
59
+ `**/types.ts`
60
+ ];
61
+ const GLOB_TYPE_TEST = [`**/*.test-d.${GLOB_SRC_EXT}`, `**/*.spec-d.${GLOB_SRC_EXT}`];
62
+ const GLOB_TEST = [
63
+ `**/*.test.${GLOB_SRC_EXT}`,
64
+ `**/*.spec.${GLOB_SRC_EXT}`,
65
+ `**/*.bench.${GLOB_SRC_EXT}`,
66
+ `**/*.benchmark.${GLOB_SRC_EXT}`,
67
+ ...GLOB_TYPE_TEST
68
+ ];
69
+ const GLOB_STYLE = "**/*.{c,le,sc}ss";
70
+ const GLOB_CSS = "**/*.css";
71
+ const GLOB_LESS = "**/*.less";
72
+ const GLOB_SCSS = "**/*.scss";
73
+ const GLOB_POSTCSS = "**/*.{p,post}css";
74
+ const GLOB_JSON = "**/*.json";
75
+ const GLOB_JSON5 = "**/*.json5";
76
+ const GLOB_JSONC = "**/*.jsonc";
77
+ const GLOB_PACKAGE_JSON = "**/package.json";
78
+ const GLOB_JSON_SCHEMA = ["**/*.schema.json", "**/schemas/*.json"];
79
+ const GLOB_TSCONFIG_JSON = ["**/tsconfig.json", "**/tsconfig.*.json"];
80
+ const GLOB_YAML = "**/*.y?(a)ml";
81
+ const GLOB_PNPM_WORKSPACE_YAML = "**/pnpm-workspace.yaml";
82
+ const GLOB_SVG = "**/*.svg";
83
+ const GLOB_VUE = "**/*.vue";
84
+ const GLOB_SVELTE = "**/*.svelte";
85
+ const GLOB_TOML = "**/*.toml";
86
+ const GLOB_HTML = "**/*.htm?(l)";
87
+ const GLOB_ASTRO = "**/*.astro";
88
+ const GLOB_ASTRO_TS = "**/*.astro/*.ts";
89
+ const GLOB_MARKDOWN = "**/*.md";
90
+ const GLOB_MARKDOWN_CODE = `${GLOB_MARKDOWN}/${GLOB_SRC}`;
91
+ const GLOB_MARKDOWN_NESTED = `${GLOB_MARKDOWN}/*.md`;
92
+ const GLOB_ALL_SRC = [
93
+ GLOB_SRC,
94
+ GLOB_STYLE,
95
+ GLOB_JSON,
96
+ GLOB_JSON5,
97
+ GLOB_VUE,
98
+ GLOB_YAML,
99
+ GLOB_TOML,
100
+ GLOB_HTML,
101
+ GLOB_MARKDOWN
102
+ ];
103
+ const GLOB_PINIA_STORE = `**/store?(s)/*.${GLOB_SRC_EXT}`;
104
+ const GLOB_GITHUB_ACTION = "**/.github/workflows/*.y?(a)ml";
105
+ const GLOB_NODE_MODULES = "**/node_modules/**";
106
+ const GLOB_DIST = "**/dist/**";
107
+ const GLOB_LOCKFILE = [
108
+ "**/package-lock.json",
109
+ "**/yarn.lock",
110
+ "**/pnpm-lock.yaml",
111
+ "**/bun.lock?(b)",
112
+ "**/deno.lock"
113
+ ];
114
+ const GLOB_EXCLUDE = [
115
+ GLOB_NODE_MODULES,
116
+ GLOB_DIST,
117
+ ...GLOB_LOCKFILE,
118
+ "!.github",
119
+ "!.vitepress",
120
+ "!.vuepress",
121
+ "!.vscode",
122
+ "**/CHANGELOG*.md",
123
+ "**/*.min.*",
124
+ "**/LICENSE*",
125
+ "**/__snapshots__",
126
+ "**/auto-import?(s).d.ts",
127
+ "**/components.d.ts",
128
+ "**/typed-router.d.ts",
129
+ "**/uni-pages.d.ts",
130
+ "**/coverage",
131
+ "**/fixtures",
132
+ "**/output",
133
+ "**/public",
134
+ "**/static",
135
+ "**/?(.)temp",
136
+ "**/?(.)cache",
137
+ "**/.eslintcache",
138
+ "**/.stylelintcache",
139
+ "**/.eslint-config-inspector",
140
+ "**/.vite-inspect",
141
+ "**/.nuxt",
142
+ "**/.wxt",
143
+ "**/.output",
144
+ "**/.tsup",
145
+ "**/.nitro",
146
+ "**/.vercel",
147
+ "**/.wrangler",
148
+ "**/.changeset",
149
+ "**/.npmrc",
150
+ "**/.yarnrc",
151
+ "**/.husky",
152
+ "**/src-tauri/gen",
153
+ "**/src-tauri/target"
154
+ ];
155
+
156
+ //#endregion
157
+ //#region src/configs/vue.ts
158
+ const sharedRules = {
159
+ ...pluginVue.configs.base.rules,
160
+ ...pluginVue.configs.essential.rules,
161
+ ...pluginVue.configs["strongly-recommended"].rules,
162
+ ...pluginVue.configs.recommended.rules
163
+ };
164
+ const disabledRules$1 = {
165
+ "vue/multi-word-component-names": "off",
166
+ "vue/no-setup-props-reactivity-loss": "off",
167
+ "vue/no-v-html": "off",
168
+ "vue/no-v-text-v-html-on-component": "off",
169
+ "vue/require-default-prop": "off",
170
+ "vue/require-prop-types": "off"
171
+ };
172
+ const extensionRules = {
173
+ "vue/array-bracket-spacing": ["error", "never"],
174
+ "vue/arrow-spacing": ["error", {
175
+ after: true,
176
+ before: true
177
+ }],
178
+ "vue/block-spacing": ["error", "always"],
179
+ "vue/brace-style": [
180
+ "error",
181
+ "stroustrup",
182
+ { allowSingleLine: true }
183
+ ],
184
+ "vue/comma-dangle": ["error", "always-multiline"],
185
+ "vue/comma-spacing": ["error", {
186
+ after: true,
187
+ before: false
188
+ }],
189
+ "vue/comma-style": ["error", "last"],
190
+ "vue/dot-location": ["error", "property"],
191
+ "vue/dot-notation": ["error", { allowKeywords: true }],
192
+ "vue/eqeqeq": ["error", "smart"],
193
+ "vue/key-spacing": ["error", {
194
+ afterColon: true,
195
+ beforeColon: false
196
+ }],
197
+ "vue/keyword-spacing": ["error", {
198
+ after: true,
199
+ before: true
200
+ }],
201
+ "vue/no-constant-condition": "error",
202
+ "vue/no-empty-pattern": "error",
203
+ "vue/no-extra-parens": ["error", "functions"],
204
+ "vue/no-loss-of-precision": "error",
205
+ "vue/no-restricted-syntax": [
206
+ "error",
207
+ "DebuggerStatement",
208
+ "LabeledStatement",
209
+ "WithStatement"
210
+ ],
211
+ "vue/no-sparse-arrays": "error",
212
+ "vue/object-curly-newline": ["error", {
213
+ consistent: true,
214
+ multiline: true
215
+ }],
216
+ "vue/object-curly-spacing": ["error", "always"],
217
+ "vue/object-property-newline": ["error", { allowMultiplePropertiesPerLine: true }],
218
+ "vue/object-shorthand": [
219
+ "error",
220
+ "always",
221
+ {
222
+ avoidQuotes: true,
223
+ ignoreConstructors: false
224
+ }
225
+ ],
226
+ "vue/operator-linebreak": ["error", "before"],
227
+ "vue/prefer-template": "error",
228
+ "vue/quote-props": ["error", "consistent-as-needed"],
229
+ "vue/space-in-parens": ["error", "never"],
230
+ "vue/space-infix-ops": "error",
231
+ "vue/space-unary-ops": ["error", {
232
+ nonwords: false,
233
+ words: true
234
+ }],
235
+ "vue/template-curly-spacing": "error"
236
+ };
237
+ const unCategorizedRules = {
238
+ "vue/block-order": ["error", { order: [
239
+ "script",
240
+ "template",
241
+ "style"
242
+ ] }],
243
+ "vue/block-tag-newline": ["error", {
244
+ multiline: "always",
245
+ singleline: "always"
246
+ }],
247
+ "vue/component-api-style": ["error", ["script-setup", "composition"]],
248
+ "vue/component-name-in-template-casing": [
249
+ "error",
250
+ "PascalCase",
251
+ {
252
+ ignores: ["slot", "component"],
253
+ registeredComponentsOnly: false
254
+ }
255
+ ],
256
+ "vue/component-options-name-casing": ["error", "PascalCase"],
257
+ "vue/custom-event-name-casing": ["error", "camelCase"],
258
+ "vue/define-emits-declaration": ["error", "type-literal"],
259
+ "vue/define-macros-order": ["error", {
260
+ defineExposeLast: true,
261
+ order: [
262
+ "defineProps",
263
+ "defineEmits",
264
+ "defineOptions",
265
+ "defineSlots",
266
+ "defineModel"
267
+ ]
268
+ }],
269
+ "vue/define-props-declaration": ["error", "type-based"],
270
+ "vue/enforce-style-attribute": ["error", { allow: ["scoped", "plain"] }],
271
+ "vue/html-button-has-type": ["error", {
272
+ button: true,
273
+ reset: true,
274
+ submit: true
275
+ }],
276
+ "vue/html-comment-content-newline": [
277
+ "error",
278
+ {
279
+ multiline: "always",
280
+ singleline: "ignore"
281
+ },
282
+ { exceptions: ["*"] }
283
+ ],
284
+ "vue/html-comment-content-spacing": [
285
+ "error",
286
+ "always",
287
+ { exceptions: ["-"] }
288
+ ],
289
+ "vue/html-comment-indent": ["error", 2],
290
+ "vue/next-tick-style": ["error", "promise"],
291
+ "vue/no-deprecated-delete-set": "error",
292
+ "vue/no-deprecated-model-definition": ["error", { allowVue3Compat: true }],
293
+ "vue/no-duplicate-attr-inheritance": ["error", { checkMultiRootNodes: true }],
294
+ "vue/no-empty-component-block": "error",
295
+ "vue/no-irregular-whitespace": "error",
296
+ "vue/no-multiple-objects-in-class": "error",
297
+ "vue/no-ref-object-reactivity-loss": "error",
298
+ "vue/no-required-prop-with-default": ["error", { autofix: true }],
299
+ "vue/no-restricted-v-bind": ["error", "/^v-/"],
300
+ "vue/no-static-inline-styles": ["error", { allowBinding: true }],
301
+ "vue/no-unused-emit-declarations": "error",
302
+ "vue/no-use-v-else-with-v-for": "error",
303
+ "vue/no-useless-v-bind": "error",
304
+ "vue/no-v-text": "error",
305
+ "vue/padding-line-between-blocks": "error",
306
+ "vue/prefer-define-options": "error",
307
+ "vue/prefer-prop-type-boolean-first": "error",
308
+ "vue/prefer-separate-static-class": "error",
309
+ "vue/prefer-true-attribute-shorthand": ["error", "always"],
310
+ "vue/prefer-use-template-ref": "error",
311
+ "vue/require-macro-variable-name": ["error", {
312
+ defineEmits: "emits",
313
+ defineProps: "props",
314
+ defineSlots: "slots",
315
+ useAttrs: "attrs",
316
+ useSlots: "slots"
317
+ }],
318
+ "vue/require-typed-object-prop": "error",
319
+ "vue/slot-name-casing": ["error", "kebab-case"],
320
+ "vue/v-for-delimiter-style": ["error", "in"],
321
+ "vue/valid-define-options": "error"
322
+ };
323
+ /**
324
+ * Config for vue files
325
+ *
326
+ * @see {@link https://github.com/vuejs/eslint-plugin-vue}
327
+ *
328
+ * @param options - {@link ConfigVueOptions}
329
+ * @returns ESLint configs
330
+ */
331
+ const configVue = (options = {}) => {
332
+ const { files = [GLOB_VUE], extraFileExtensions = [] } = options;
333
+ const sfcBlocks = options.sfcBlocks === true ? {} : options.sfcBlocks ?? {};
334
+ function getVueProcessor() {
335
+ const processorVueSFC = pluginVue.processors[".vue"];
336
+ if (!sfcBlocks) return processorVueSFC;
337
+ return mergeProcessors$1([processorVueSFC, processorVueBlocks({
338
+ ...sfcBlocks,
339
+ blocks: {
340
+ styles: true,
341
+ ...sfcBlocks.blocks
342
+ }
343
+ })]);
344
+ }
345
+ return [{
346
+ name: "ntnyq/vue/setup",
347
+ plugins: {
348
+ "@typescript-eslint": pluginTypeScript,
349
+ vue: pluginVue
350
+ }
351
+ }, {
352
+ name: "ntnyq/vue/rules",
353
+ files,
354
+ processor: getVueProcessor(),
355
+ languageOptions: {
356
+ parser: parserVue,
357
+ parserOptions: {
358
+ ecmaVersion: "latest",
359
+ extraFileExtensions,
360
+ parser: parserTypeScript,
361
+ sourceType: "module",
362
+ ecmaFeatures: { jsx: true }
363
+ }
364
+ },
365
+ rules: {
366
+ ...sharedRules,
367
+ "vue/attributes-order": ["error", {
368
+ alphabetical: false,
369
+ order: [
370
+ "EVENTS",
371
+ "TWO_WAY_BINDING",
372
+ "OTHER_DIRECTIVES",
373
+ "LIST_RENDERING",
374
+ "CONDITIONALS",
375
+ "CONTENT",
376
+ "SLOT",
377
+ "UNIQUE",
378
+ "DEFINITION",
379
+ "ATTR_DYNAMIC",
380
+ "RENDER_MODIFIERS",
381
+ "GLOBAL",
382
+ "ATTR_STATIC",
383
+ "ATTR_SHORTHAND_BOOL"
384
+ ]
385
+ }],
386
+ "vue/html-self-closing": ["error", {
387
+ math: "always",
388
+ svg: "always",
389
+ html: {
390
+ component: "always",
391
+ normal: "always",
392
+ void: "always"
393
+ }
394
+ }],
395
+ "vue/max-attributes-per-line": ["error", {
396
+ multiline: 1,
397
+ singleline: 1
398
+ }],
399
+ "vue/order-in-components": ["error", { order: [
400
+ "el",
401
+ "name",
402
+ "key",
403
+ "parent",
404
+ "functional",
405
+ ["provide", "inject"],
406
+ ["delimiters", "comments"],
407
+ [
408
+ "components",
409
+ "directives",
410
+ "filters"
411
+ ],
412
+ "extends",
413
+ "mixins",
414
+ "layout",
415
+ "middleware",
416
+ "validate",
417
+ "scrollToTop",
418
+ "transition",
419
+ "loading",
420
+ "inheritAttrs",
421
+ "model",
422
+ ["props", "propsData"],
423
+ "slots",
424
+ "expose",
425
+ "emits",
426
+ "setup",
427
+ "asyncData",
428
+ "computed",
429
+ "data",
430
+ "fetch",
431
+ "head",
432
+ "methods",
433
+ ["template", "render"],
434
+ "watch",
435
+ "watchQuery",
436
+ "LIFECYCLE_HOOKS",
437
+ "renderError",
438
+ "ROUTER_GUARDS"
439
+ ] }],
440
+ "vue/prop-name-casing": ["error", "camelCase"],
441
+ "vue/this-in-template": ["error", "never"],
442
+ ...disabledRules$1,
443
+ ...extensionRules,
444
+ ...unCategorizedRules,
445
+ ...options.overrides
446
+ }
447
+ }];
448
+ };
449
+
450
+ //#endregion
451
+ //#region src/configs/yml.ts
452
+ /**
453
+ * @see {@link https://github.com/ota-meshi/eslint-plugin-yml/blob/master/src/configs/base.ts}
454
+ */
455
+ const disabledCoreRules$1 = {
456
+ "no-irregular-whitespace": "off",
457
+ "no-unused-vars": "off",
458
+ "spaced-comment": "off"
459
+ };
460
+ /**
461
+ * Config for yml, yaml files
462
+ *
463
+ * @see {@link https://ota-meshi.github.io/eslint-plugin-yml}
464
+ *
465
+ * @param options - {@link ConfigYmlOptions}
466
+ * @returns ESLint configs
467
+ */
468
+ const configYml = (options = {}) => {
469
+ const { files = [GLOB_YAML] } = options;
470
+ return [{
471
+ name: "ntnyq/yml",
472
+ files,
473
+ plugins: { yml: pluginYml },
474
+ languageOptions: { parser: parserYaml },
475
+ rules: {
476
+ "yml/no-empty-mapping-value": "off",
477
+ "yml/block-mapping": "error",
478
+ "yml/block-mapping-question-indicator-newline": "error",
479
+ "yml/block-sequence": "error",
480
+ "yml/block-sequence-hyphen-indicator-newline": "error",
481
+ "yml/flow-mapping-curly-newline": "error",
482
+ "yml/flow-mapping-curly-spacing": "error",
483
+ "yml/flow-sequence-bracket-newline": "error",
484
+ "yml/flow-sequence-bracket-spacing": "error",
485
+ "yml/indent": "error",
486
+ "yml/key-spacing": "error",
487
+ "yml/no-empty-document": "error",
488
+ "yml/no-empty-key": "error",
489
+ "yml/no-empty-sequence-entry": "error",
490
+ "yml/no-irregular-whitespace": "error",
491
+ "yml/no-tab-indent": "error",
492
+ "yml/plain-scalar": "error",
493
+ "yml/quotes": ["error", {
494
+ avoidEscape: false,
495
+ prefer: "single"
496
+ }],
497
+ "yml/spaced-comment": "error",
498
+ "yml/vue-custom-block/no-parsing-error": "error",
499
+ ...disabledCoreRules$1,
500
+ ...options.prettier ? {
501
+ "yml/block-mapping-colon-indicator-newline": "off",
502
+ "yml/block-mapping-question-indicator-newline": "off",
503
+ "yml/block-sequence-hyphen-indicator-newline": "off",
504
+ "yml/flow-mapping-curly-newline": "off",
505
+ "yml/flow-mapping-curly-spacing": "off",
506
+ "yml/flow-sequence-bracket-newline": "off",
507
+ "yml/flow-sequence-bracket-spacing": "off",
508
+ "yml/indent": "off",
509
+ "yml/key-spacing": "off",
510
+ "yml/no-multiple-empty-lines": "off",
511
+ "yml/no-trailing-zeros": "off",
512
+ "yml/quotes": "off"
513
+ } : {},
514
+ ...options.overrides
515
+ }
516
+ }];
517
+ };
518
+
519
+ //#endregion
520
+ //#region src/utils/env.ts
521
+ const hasPinia = () => isPackageExists("pinia");
522
+ const hasVitest = () => isPackageExists("vitest");
523
+ const hasTypeScript = () => isPackageExists("typescript");
524
+ const hasShadcnVue = () => (isPackageExists("radix-vue") || isPackageExists("reka-ui")) && isPackageExists("class-variance-authority") && isPackageExists("clsx");
525
+ const hasUnoCSS = () => isPackageExists("unocss") || isPackageExists("@unocss/postcss") || isPackageExists("@unocss/webpack") || isPackageExists("@unocss/nuxt");
526
+ const hasVue = () => isPackageExists("vue") || isPackageExists("nuxt") || isPackageExists("vitepress") || isPackageExists("vuepress") || isPackageExists("@slidev/cli") || isPackageExists("vue", { paths: [resolve(process.cwd(), "playground"), resolve(process.cwd(), "docs")] });
527
+
528
+ //#endregion
529
+ //#region src/utils/resolveSubOptions.ts
530
+ function resolveSubOptions(options, key) {
531
+ return typeof options[key] === "boolean" ? {} : options[key] || {};
532
+ }
533
+
534
+ //#endregion
535
+ //#region src/utils/getOverrides.ts
536
+ function getOverrides(options, key) {
537
+ const subOptions = resolveSubOptions(options, key);
538
+ return "overrides" in subOptions && subOptions.overrides ? subOptions.overrides : {};
539
+ }
540
+
541
+ //#endregion
542
+ //#region src/utils/combineConfigs.ts
543
+ async function combineConfigs(...configs) {
544
+ const resolved = await Promise.all(configs);
545
+ return resolved.flat();
546
+ }
547
+
548
+ //#endregion
549
+ //#region src/utils/isInGitHooksOrRunBySpecifyPackages.ts
550
+ const CHECKED_RUNNER_PACKAGES = [
551
+ "nano-staged",
552
+ "lint-staged",
553
+ "lefthook",
554
+ "tsx"
555
+ ];
556
+ function isInGitHooksOrRunBySpecifyPackages() {
557
+ return !!(process.env.GIT_PARAMS || process.env.VSCODE_GIT_COMMAND || CHECKED_RUNNER_PACKAGES.some((packageName) => process.env.npm_lifecycle_script?.startsWith(packageName)));
558
+ }
559
+
560
+ //#endregion
561
+ //#region src/utils/ensurePackages.ts
562
+ const isCwdInScope = isPackageExists("@ntnyq/eslint-config");
563
+ function isPackageInScope(name) {
564
+ return isPackageExists(name, { paths: [import.meta.dirname] });
565
+ }
566
+ async function ensurePackages(packages) {
567
+ if (process.env.CI || !process.stdout.isTTY || isInGitHooksOrRunBySpecifyPackages() || !isCwdInScope) return;
568
+ const nonExistingPackages = packages.filter((pkg) => !!pkg && !isPackageInScope(pkg));
569
+ if (nonExistingPackages.length === 0) return;
570
+ const { confirm } = await import("@clack/prompts");
571
+ const confirmInstall = await confirm({ message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?` });
572
+ if (confirmInstall) try {
573
+ const { installPackage } = await import("@antfu/install-pkg");
574
+ await installPackage(nonExistingPackages, { dev: true });
575
+ } catch (err) {
576
+ console.log(err);
577
+ }
578
+ }
579
+
580
+ //#endregion
581
+ //#region src/utils/interopDefault.ts
582
+ /**
583
+ * Interop default export from a module
584
+ * @param mod - The module
585
+ * @returns The default export
586
+ */
587
+ async function interopDefault(mod) {
588
+ const resolved = await mod;
589
+ return resolved.default || resolved;
590
+ }
591
+
592
+ //#endregion
593
+ //#region src/utils/mergePrettierOptions.ts
594
+ function mergePrettierOptions(options = {}, overrides = {}) {
595
+ const result = {
596
+ ...options,
597
+ ...overrides,
598
+ plugins: [...options.plugins || [], ...overrides.plugins || []]
599
+ };
600
+ return result;
601
+ }
602
+
603
+ //#endregion
604
+ //#region src/configs/html.ts
605
+ /**
606
+ * Config for html files
607
+ *
608
+ * @see {@link https://github.com/yeonjuan/html-eslint}
609
+ *
610
+ * @param options - {@link ConfigHtmlOptions}
611
+ * @returns ESLint configs
612
+ */
613
+ const configHtml = async (options = {}) => {
614
+ await ensurePackages(["@html-eslint/parser", "@html-eslint/eslint-plugin"]);
615
+ const [parserHtml, pluginHtml] = await Promise.all([interopDefault(import("@html-eslint/parser")), interopDefault(import("@html-eslint/eslint-plugin"))]);
616
+ const { files = [GLOB_HTML] } = options;
617
+ return [{
618
+ name: "ntnyq/html",
619
+ files,
620
+ plugins: { "@html-eslint": pluginHtml },
621
+ languageOptions: { parser: parserHtml },
622
+ rules: {
623
+ "@html-eslint/attrs-newline": "error",
624
+ "@html-eslint/element-newline": ["error", { inline: [`$inline`] }],
625
+ "@html-eslint/indent": "error",
626
+ "@html-eslint/no-duplicate-attrs": "error",
627
+ "@html-eslint/no-duplicate-id": "error",
628
+ "@html-eslint/no-extra-spacing-attrs": "error",
629
+ "@html-eslint/no-multiple-h1": "error",
630
+ "@html-eslint/no-obsolete-tags": "error",
631
+ "@html-eslint/quotes": "error",
632
+ "@html-eslint/require-closing-tags": "error",
633
+ "@html-eslint/require-doctype": "error",
634
+ "@html-eslint/require-img-alt": "error",
635
+ "@html-eslint/require-lang": "error",
636
+ "@html-eslint/require-li-container": "error",
637
+ "@html-eslint/require-title": "error",
638
+ "@html-eslint/use-baseline": "error",
639
+ ...options.overrides
640
+ }
641
+ }];
642
+ };
643
+
644
+ //#endregion
645
+ //#region src/configs/node.ts
646
+ /**
647
+ * Config for common files
648
+ *
649
+ * @see {@link https://github.com/eslint-community/eslint-plugin-n}
650
+ *
651
+ * @param options - {@link ConfigNodeOptions}
652
+ * @returns ESLint configs
653
+ */
654
+ const configNode = (options = {}) => [{
655
+ name: "ntnyq/node",
656
+ plugins: { node: pluginNode },
657
+ rules: {
658
+ "node/handle-callback-err": ["error", "^(err|error)$"],
659
+ "node/no-deprecated-api": "error",
660
+ "node/no-exports-assign": "error",
661
+ "node/no-new-require": "error",
662
+ "node/no-path-concat": "error",
663
+ "node/prefer-global/buffer": ["error", "never"],
664
+ "node/prefer-global/process": ["error", "never"],
665
+ "node/process-exit-as-throw": "error",
666
+ ...options.overrides
667
+ }
668
+ }];
669
+
670
+ //#endregion
671
+ //#region src/configs/pnpm.ts
672
+ /**
673
+ * Config for pnpm package manager
674
+ *
675
+ * @see {@link https://github.com/antfu/pnpm-workspace-utils/tree/main/packages/eslint-plugin-pnpm}
676
+ *
677
+ * @param options - {@link ConfigPnpmOptions}
678
+ * @returns ESLint configs
679
+ */
680
+ const configPnpm = async (options = {}) => {
681
+ await ensurePackages(["eslint-plugin-pnpm"]);
682
+ const pluginPnpm = await interopDefault(import("eslint-plugin-pnpm"));
683
+ const { filesJson = [GLOB_PACKAGE_JSON], filesYaml = [GLOB_PNPM_WORKSPACE_YAML] } = options;
684
+ return [{
685
+ name: "ntnyq/pnpm/package-json",
686
+ files: filesJson,
687
+ plugins: { pnpm: pluginPnpm },
688
+ languageOptions: { parser: parserJsonc },
689
+ rules: {
690
+ "pnpm/json-enforce-catalog": ["error", { autofix: true }],
691
+ "pnpm/json-valid-catalog": "error",
692
+ ...options.overridesJsonRules
693
+ }
694
+ }, {
695
+ name: "ntnyq/pnpm/pnpm-workspace-yaml",
696
+ files: filesYaml,
697
+ plugins: { pnpm: pluginPnpm },
698
+ languageOptions: { parser: parserYaml },
699
+ rules: {
700
+ "pnpm/yaml-no-duplicate-catalog-item": "error",
701
+ "pnpm/yaml-no-unused-catalog-item": "error",
702
+ ...options.overridesYamlRules
703
+ }
704
+ }];
705
+ };
706
+
707
+ //#endregion
708
+ //#region src/configs/sort.ts
709
+ /**
710
+ * Config for sort keys and values
711
+ *
712
+ * @param options - {@link ConfigSortOptions}
713
+ * @returns ESLint configs
714
+ */
715
+ const configSort = (options = {}) => {
716
+ const configs = [];
717
+ const { additionalJsonFiles = [], additionalYamlFiles = [], i18nLocale: enableSortI18nLocale = true, jsonSchema: enableSortJsonSchema = true, packageJson: enableSortPackageJson = true, pnpmWorkspace: enableSortPnpmWorkspace = true, tsconfig: enableSortTsconfig = true } = options;
718
+ if (enableSortTsconfig) configs.push({
719
+ name: "ntnyq/sort/tsconfig",
720
+ files: [...GLOB_TSCONFIG_JSON],
721
+ rules: { "jsonc/sort-keys": [
722
+ "error",
723
+ {
724
+ pathPattern: "^$",
725
+ order: [
726
+ "extends",
727
+ "compilerOptions",
728
+ "references",
729
+ "files",
730
+ "include",
731
+ "exclude",
732
+ "vueCompilerOptions",
733
+ { order: { type: "asc" } }
734
+ ]
735
+ },
736
+ {
737
+ pathPattern: "^compilerOptions$",
738
+ order: [
739
+ "incremental",
740
+ "composite",
741
+ "tsBuildInfoFile",
742
+ "disableSourceOfProjectReferenceRedirect",
743
+ "disableSolutionSearching",
744
+ "disableReferencedProjectLoad",
745
+ "target",
746
+ "lib",
747
+ "jsx",
748
+ "experimentalDecorators",
749
+ "emitDecoratorMetadata",
750
+ "jsxFactory",
751
+ "jsxFragmentFactory",
752
+ "jsxImportSource",
753
+ "reactNamespace",
754
+ "noLib",
755
+ "useDefineForClassFields",
756
+ "moduleDetection",
757
+ "module",
758
+ "rootDir",
759
+ "moduleResolution",
760
+ "baseUrl",
761
+ "paths",
762
+ "rootDirs",
763
+ "typeRoots",
764
+ "types",
765
+ "allowUmdGlobalAccess",
766
+ "moduleSuffixes",
767
+ "allowImportingTsExtensions",
768
+ "resolvePackageJsonExports",
769
+ "resolvePackageJsonImports",
770
+ "customConditions",
771
+ "resolveJsonModule",
772
+ "allowArbitraryExtensions",
773
+ "noResolve",
774
+ "erasableSyntaxOnly",
775
+ "libReplacement",
776
+ "allowJs",
777
+ "checkJs",
778
+ "maxNodeModuleJsDepth",
779
+ "declaration",
780
+ "declarationMap",
781
+ "emitDeclarationOnly",
782
+ "sourceMap",
783
+ "inlineSourceMap",
784
+ "outFile",
785
+ "outDir",
786
+ "removeComments",
787
+ "noEmit",
788
+ "importHelpers",
789
+ "importsNotUsedAsValues",
790
+ "downlevelIteration",
791
+ "sourceRoot",
792
+ "mapRoot",
793
+ "inlineSources",
794
+ "emitBOM",
795
+ "newLine",
796
+ "stripInternal",
797
+ "noEmitHelpers",
798
+ "noEmitOnError",
799
+ "preserveConstEnums",
800
+ "declarationDir",
801
+ "preserveValueImports",
802
+ "isolatedDeclarations",
803
+ "isolatedModules",
804
+ "verbatimModuleSyntax",
805
+ "allowSyntheticDefaultImports",
806
+ "esModuleInterop",
807
+ "preserveSymlinks",
808
+ "forceConsistentCasingInFileNames",
809
+ "strict",
810
+ "strictBindCallApply",
811
+ "strictFunctionTypes",
812
+ "strictNullChecks",
813
+ "strictPropertyInitialization",
814
+ "allowUnreachableCode",
815
+ "allowUnusedLabels",
816
+ "alwaysStrict",
817
+ "exactOptionalPropertyTypes",
818
+ "noFallthroughCasesInSwitch",
819
+ "noImplicitAny",
820
+ "noImplicitOverride",
821
+ "noImplicitReturns",
822
+ "noImplicitThis",
823
+ "noPropertyAccessFromIndexSignature",
824
+ "noUncheckedIndexedAccess",
825
+ "noUnusedLocals",
826
+ "noUnusedParameters",
827
+ "useUnknownInCatchVariables",
828
+ "skipDefaultLibCheck",
829
+ "skipLibCheck",
830
+ { order: { type: "asc" } }
831
+ ]
832
+ },
833
+ {
834
+ order: { type: "asc" },
835
+ pathPattern: "^vueCompilerOptions$"
836
+ }
837
+ ] }
838
+ });
839
+ if (enableSortPackageJson) configs.push({
840
+ name: "ntnyq/sort/package-json",
841
+ files: [GLOB_PACKAGE_JSON],
842
+ rules: {
843
+ "jsonc/sort-array-values": ["error", {
844
+ order: { type: "asc" },
845
+ pathPattern: "^(?:files|keywords|activationEvents|contributes.*)$"
846
+ }],
847
+ "jsonc/sort-keys": [
848
+ "error",
849
+ {
850
+ pathPattern: "^$",
851
+ order: [
852
+ "publisher",
853
+ "name",
854
+ "displayName",
855
+ "preview",
856
+ "type",
857
+ "config",
858
+ "version",
859
+ "private",
860
+ "packageManager",
861
+ "workspaces",
862
+ "description",
863
+ "keywords",
864
+ "license",
865
+ "licenses",
866
+ "author",
867
+ "contributors",
868
+ "maintainers",
869
+ "homepage",
870
+ "repository",
871
+ "bugs",
872
+ "funding",
873
+ "exports",
874
+ "imports",
875
+ "main",
876
+ "module",
877
+ "unpkg",
878
+ "jsdelivr",
879
+ "types",
880
+ "typesVersions",
881
+ "bin",
882
+ "icon",
883
+ "files",
884
+ "directories",
885
+ "publishConfig",
886
+ "sideEffects",
887
+ "scripts",
888
+ "peerDependencies",
889
+ "peerDependenciesMeta",
890
+ "bundledDependencies",
891
+ "bundleDependencies",
892
+ "dependencies",
893
+ "optionalDependencies",
894
+ "devDependencies",
895
+ "activationEvents",
896
+ "contributes",
897
+ "categories",
898
+ "galleryBanner",
899
+ "badges",
900
+ "markdown",
901
+ "qna",
902
+ "sponsor",
903
+ "extensionPack",
904
+ "extensionDependencies",
905
+ "extensionKind",
906
+ "pricing",
907
+ "capabilities",
908
+ "engines",
909
+ "pnpm",
910
+ "overrides",
911
+ "resolutions",
912
+ "husky",
913
+ "prettier",
914
+ "nano-staged",
915
+ "lint-staged",
916
+ "eslintConfig",
917
+ { order: { type: "asc" } }
918
+ ]
919
+ },
920
+ {
921
+ order: { type: "asc" },
922
+ pathPattern: "^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$"
923
+ },
924
+ {
925
+ order: { type: "asc" },
926
+ pathPattern: "^(?:resolutions|overrides|pnpm.overrides)$"
927
+ },
928
+ {
929
+ pathPattern: "^exports.*$",
930
+ order: [
931
+ "./package.json",
932
+ "types",
933
+ "import",
934
+ "require",
935
+ "default",
936
+ { order: { type: "asc" } }
937
+ ]
938
+ },
939
+ {
940
+ order: { type: "asc" },
941
+ pathPattern: "^contributes.*$"
942
+ },
943
+ {
944
+ pathPattern: "^publishConfig.*$",
945
+ order: [
946
+ "./package.json",
947
+ "types",
948
+ "import",
949
+ "require",
950
+ "default",
951
+ { order: { type: "asc" } }
952
+ ]
953
+ },
954
+ {
955
+ order: { type: "asc" },
956
+ pathPattern: "^scripts$"
957
+ },
958
+ {
959
+ pathPattern: "^(?:gitHooks|husky|simple-git-hooks)$",
960
+ order: [
961
+ "pre-commit",
962
+ "prepare-commit-msg",
963
+ "commit-msg",
964
+ "post-commit",
965
+ "pre-rebase",
966
+ "post-rewrite",
967
+ "post-checkout",
968
+ "post-merge",
969
+ "pre-push",
970
+ "pre-auto-gc",
971
+ { order: { type: "asc" } }
972
+ ]
973
+ }
974
+ ]
975
+ }
976
+ });
977
+ if (enableSortI18nLocale) configs.push({
978
+ name: "ntnyq/sort/i18n-locale/json",
979
+ files: ["**/{i18n,langs,locales}/*.json"],
980
+ rules: { "jsonc/sort-keys": ["error", {
981
+ order: { type: "asc" },
982
+ pathPattern: ".*"
983
+ }] }
984
+ }, {
985
+ name: "ntnyq/sort/i18n-locale/yaml",
986
+ files: ["**/{i18n,langs,locales}/*.y?(a)ml"],
987
+ rules: { "yml/sort-keys": ["error", {
988
+ order: { type: "asc" },
989
+ pathPattern: ".*"
990
+ }] }
991
+ });
992
+ /**
993
+ * @see {@link https://json-schema.org/draft-07/schema}
994
+ */
995
+ if (enableSortJsonSchema) configs.push({
996
+ name: "ntnyq/sort/json-schema",
997
+ files: [...GLOB_JSON_SCHEMA],
998
+ rules: {
999
+ "jsonc/sort-array-values": ["error", {
1000
+ order: { type: "asc" },
1001
+ pathPattern: "^(?:required)$"
1002
+ }],
1003
+ "jsonc/sort-keys": [
1004
+ "error",
1005
+ {
1006
+ pathPattern: "^$",
1007
+ order: [
1008
+ "$schema",
1009
+ "$comment",
1010
+ "$id",
1011
+ "$ref",
1012
+ "title",
1013
+ "description",
1014
+ "type",
1015
+ "definitions",
1016
+ "properties",
1017
+ "required",
1018
+ "additionalProperties",
1019
+ { order: { type: "asc" } }
1020
+ ]
1021
+ },
1022
+ {
1023
+ order: { type: "asc" },
1024
+ pathPattern: "^(?:definitions|properties)$"
1025
+ }
1026
+ ]
1027
+ }
1028
+ });
1029
+ if (enableSortPnpmWorkspace) configs.push({
1030
+ name: "ntnyq/sort/pnpm-workspace",
1031
+ files: [GLOB_PNPM_WORKSPACE_YAML],
1032
+ rules: {
1033
+ "yml/sort-keys": [
1034
+ "error",
1035
+ {
1036
+ pathPattern: "^$",
1037
+ order: [
1038
+ "packages",
1039
+ "catalog",
1040
+ "catalogs",
1041
+ "allowedDeprecatedVersions",
1042
+ "overrides",
1043
+ "onlyBuiltDependencies",
1044
+ "patchedDependencies",
1045
+ "peerDependencyRules",
1046
+ "allowNonAppliedPatches",
1047
+ "auditConfig",
1048
+ "configDependencies",
1049
+ "executionEnv",
1050
+ "ignoredBuiltDependencies",
1051
+ "ignoredOptionalDependencies",
1052
+ "neverBuiltDependencies",
1053
+ "onlyBuiltDependenciesFile",
1054
+ "packageExtensions",
1055
+ "requiredScripts",
1056
+ "supportedArchitectures",
1057
+ "updateConfig",
1058
+ { order: { type: "asc" } }
1059
+ ]
1060
+ },
1061
+ {
1062
+ order: { type: "asc" },
1063
+ pathPattern: "^(?:catalog|overrides|patchedDependencies|peerDependencyRules)$"
1064
+ },
1065
+ {
1066
+ allowLineSeparatedGroups: true,
1067
+ order: { type: "asc" },
1068
+ pathPattern: "^catalogs$"
1069
+ }
1070
+ ],
1071
+ "yml/sort-sequence-values": ["error", {
1072
+ order: [".", { order: { type: "asc" } }],
1073
+ pathPattern: "^(?:packages|onlyBuiltDependencies|peerDependencyRules.ignoreMissing)$"
1074
+ }]
1075
+ }
1076
+ });
1077
+ if (additionalJsonFiles.length) configs.push({
1078
+ name: "ntnyq/sort/additional-json",
1079
+ files: additionalJsonFiles,
1080
+ rules: { "jsonc/sort-keys": ["error", {
1081
+ pathPattern: ".*",
1082
+ order: ["$schema", { order: { type: "asc" } }]
1083
+ }] }
1084
+ });
1085
+ if (additionalYamlFiles.length) configs.push({
1086
+ name: "ntnyq/sort/additional-yaml",
1087
+ files: additionalYamlFiles,
1088
+ rules: { "yml/sort-keys": ["error", {
1089
+ order: { type: "asc" },
1090
+ pathPattern: ".*"
1091
+ }] }
1092
+ });
1093
+ return configs;
1094
+ };
1095
+
1096
+ //#endregion
1097
+ //#region src/configs/svgo.ts
1098
+ /**
1099
+ * Config for svg files
1100
+ *
1101
+ * @see {@link https://github.com/ntnyq/eslint-plugin-svgo}
1102
+ *
1103
+ * @param options - {@link ConfigSVGOOptions}
1104
+ * @returns ESLint configs
1105
+ */
1106
+ const configSVGO = (options = {}) => {
1107
+ const { files = [GLOB_SVG], ignores = [] } = options;
1108
+ return [{
1109
+ name: "ntnyq/svgo",
1110
+ files,
1111
+ ignores,
1112
+ plugins: { svgo: pluginSvgo },
1113
+ languageOptions: { parser: parserPlain },
1114
+ rules: { "svgo/svgo": "error" }
1115
+ }];
1116
+ };
1117
+
1118
+ //#endregion
1119
+ //#region src/configs/test.ts
1120
+ /**
1121
+ * Config for test files
1122
+ *
1123
+ * @see {@link https://github.com/vitest-dev/eslint-plugin-vitest}
1124
+ *
1125
+ * @param options - {@link ConfigTestOptions}
1126
+ * @returns ESLint configs
1127
+ */
1128
+ const configTest = (options = {}) => {
1129
+ const { files = [...GLOB_TEST], vitest: enableVitest = hasVitest() } = options;
1130
+ const configs = [{
1131
+ name: "ntnyq/test/setup",
1132
+ plugins: { "no-only-tests": pluginNoOnlyTests }
1133
+ }, {
1134
+ name: "ntnyq/test/base",
1135
+ files,
1136
+ rules: {
1137
+ "max-lines-per-function": "off",
1138
+ "no-unused-expressions": "off",
1139
+ "no-only-tests/no-only-tests": "error",
1140
+ ...options.overrides
1141
+ }
1142
+ }];
1143
+ if (enableVitest) configs.push({
1144
+ name: "ntnyq/test/vitest",
1145
+ files,
1146
+ plugins: { vitest: pluginVitest },
1147
+ settings: {},
1148
+ rules: {
1149
+ ...pluginVitest.configs.recommended.rules,
1150
+ "vitest/expect-expect": ["error", { assertFunctionNames: [
1151
+ "expect",
1152
+ "assert",
1153
+ "expectTypeOf",
1154
+ "assertType"
1155
+ ] }],
1156
+ ...options.overridesVitestRules
1157
+ }
1158
+ });
1159
+ return configs;
1160
+ };
1161
+
1162
+ //#endregion
1163
+ //#region src/configs/toml.ts
1164
+ /**
1165
+ * Config for toml files
1166
+ *
1167
+ * @see {@link https://ota-meshi.github.io/eslint-plugin-toml}
1168
+ *
1169
+ * @param options - {@link ConfigTomlOptions}
1170
+ * @returns ESLint configs
1171
+ */
1172
+ const configToml = (options = {}) => {
1173
+ const { files = [GLOB_TOML] } = options;
1174
+ return [{
1175
+ name: "ntnyq/toml",
1176
+ files,
1177
+ plugins: { toml: pluginToml },
1178
+ languageOptions: { parser: parserToml },
1179
+ rules: {
1180
+ "toml/array-bracket-newline": "error",
1181
+ "toml/array-bracket-spacing": ["error", "never"],
1182
+ "toml/array-element-newline": ["error", "never"],
1183
+ "toml/comma-style": "error",
1184
+ "toml/indent": ["error", 2],
1185
+ "toml/inline-table-curly-spacing": "error",
1186
+ "toml/key-spacing": "error",
1187
+ "toml/keys-order": "error",
1188
+ "toml/no-space-dots": "error",
1189
+ "toml/no-unreadable-number-separator": "error",
1190
+ "toml/padding-line-between-pairs": "error",
1191
+ "toml/padding-line-between-tables": "error",
1192
+ "toml/precision-of-fractional-seconds": "error",
1193
+ "toml/precision-of-integer": "error",
1194
+ "toml/quoted-keys": "error",
1195
+ "toml/spaced-comment": "error",
1196
+ "toml/table-bracket-spacing": "error",
1197
+ "toml/tables-order": "error",
1198
+ "toml/vue-custom-block/no-parsing-error": "error",
1199
+ ...options.overrides
1200
+ }
1201
+ }];
1202
+ };
1203
+
1204
+ //#endregion
1205
+ //#region src/configs/antfu.ts
1206
+ /**
1207
+ * Config for common files
1208
+ *
1209
+ * @see {@link https://github.com/antfu/eslint-plugin-antfu}
1210
+ *
1211
+ * @param options - {@link ConfigAntfuOptions}
1212
+ * @returns ESLint configs
1213
+ */
1214
+ const configAntfu = (options = {}) => [{
1215
+ name: "ntnyq/antfu",
1216
+ plugins: { antfu: pluginAntfu },
1217
+ rules: {
1218
+ "antfu/import-dedupe": "error",
1219
+ "antfu/indent-unindent": "error",
1220
+ "antfu/no-import-dist": "error",
1221
+ "antfu/no-import-node-modules-by-path": "error",
1222
+ ...options.overrides
1223
+ }
1224
+ }];
1225
+
1226
+ //#endregion
1227
+ //#region src/configs/astro.ts
1228
+ /**
1229
+ * Config for astro files
1230
+ *
1231
+ * @see {@link https://github.com/ota-meshi/eslint-plugin-astro}
1232
+ *
1233
+ * @param options - {@link ConfigAstroOptions}
1234
+ * @returns ESLint configs
1235
+ */
1236
+ const configAstro = async (options = {}) => {
1237
+ await ensurePackages(["astro-eslint-parser", "eslint-plugin-astro"]);
1238
+ const [parserAstro, pluginAstro] = await Promise.all([interopDefault(import("astro-eslint-parser")), interopDefault(import("eslint-plugin-astro"))]);
1239
+ const { files = [GLOB_ASTRO], extraFileExtensions = [] } = options;
1240
+ return [{
1241
+ name: "ntnyq/astro",
1242
+ files,
1243
+ plugins: { astro: pluginAstro },
1244
+ processor: pluginAstro.processors["client-side-ts"],
1245
+ languageOptions: {
1246
+ parser: parserAstro,
1247
+ sourceType: "module",
1248
+ globals: { ...pluginAstro.environments.astro.globals },
1249
+ parserOptions: {
1250
+ extraFileExtensions,
1251
+ parser: parserTypeScript
1252
+ }
1253
+ },
1254
+ rules: {
1255
+ "astro/missing-client-only-directive-value": "error",
1256
+ "astro/no-conflict-set-directives": "error",
1257
+ "astro/no-deprecated-astro-canonicalurl": "error",
1258
+ "astro/no-deprecated-astro-fetchcontent": "error",
1259
+ "astro/no-deprecated-astro-resolve": "error",
1260
+ "astro/no-deprecated-getentrybyslug": "error",
1261
+ "astro/no-unused-define-vars-in-style": "error",
1262
+ "astro/valid-compile": "error",
1263
+ ...options.overrides
1264
+ }
1265
+ }];
1266
+ };
1267
+
1268
+ //#endregion
1269
+ //#region src/configs/jsdoc.ts
1270
+ /**
1271
+ * JavaScript specific rules
1272
+ */
1273
+ const javscriptRules = {
1274
+ "jsdoc/no-types": "off",
1275
+ "jsdoc/no-undefined-types": "error",
1276
+ "jsdoc/require-param-type": "error",
1277
+ "jsdoc/require-property-type": "error",
1278
+ "jsdoc/require-returns-type": "error"
1279
+ };
1280
+ /**
1281
+ * TypeScript specific rules
1282
+ */
1283
+ const typescriptRules = {
1284
+ "jsdoc/no-undefined-types": "off",
1285
+ "jsdoc/require-param-type": "off",
1286
+ "jsdoc/require-property-type": "off",
1287
+ "jsdoc/require-returns-type": "off",
1288
+ "jsdoc/no-types": "error"
1289
+ };
1290
+ /**
1291
+ * Config for jsdoc
1292
+ *
1293
+ * @see {@link https://github.com/gajus/eslint-plugin-jsdoc}
1294
+ *
1295
+ * @param options - {@link ConfigJsdocOptions}
1296
+ * @returns ESLint configs
1297
+ */
1298
+ const configJsdoc = (options = {}) => [{
1299
+ name: "ntnyq/jsdoc",
1300
+ plugins: { jsdoc: pluginJsdoc },
1301
+ rules: {
1302
+ "jsdoc/tag-lines": "off",
1303
+ "jsdoc/text-escaping": "off",
1304
+ "jsdoc/check-access": "warn",
1305
+ "jsdoc/implements-on-classes": "warn",
1306
+ "jsdoc/require-param-name": "warn",
1307
+ "jsdoc/require-property": "warn",
1308
+ "jsdoc/require-property-description": "warn",
1309
+ "jsdoc/require-property-name": "warn",
1310
+ "jsdoc/require-returns-check": "warn",
1311
+ "jsdoc/require-returns-description": "warn",
1312
+ "jsdoc/require-yields-check": "warn",
1313
+ "jsdoc/check-alignment": "error",
1314
+ "jsdoc/check-line-alignment": "error",
1315
+ "jsdoc/check-param-names": "error",
1316
+ "jsdoc/check-property-names": "error",
1317
+ "jsdoc/check-tag-names": ["error", { definedTags: [
1318
+ "vite-ignore",
1319
+ "unocss-include",
1320
+ "pg",
1321
+ "perfectionist-group",
1322
+ "regex101",
1323
+ "compatibility",
1324
+ "category",
1325
+ "experimental",
1326
+ "internal"
1327
+ ] }],
1328
+ "jsdoc/check-types": "error",
1329
+ "jsdoc/empty-tags": "error",
1330
+ "jsdoc/multiline-blocks": "error",
1331
+ "jsdoc/no-bad-blocks": ["error", { ignore: [
1332
+ "ts-check",
1333
+ "ts-expect-error",
1334
+ "ts-ignore",
1335
+ "ts-nocheck",
1336
+ "vite-ignore"
1337
+ ] }],
1338
+ "jsdoc/no-blank-block-descriptions": "error",
1339
+ "jsdoc/no-blank-blocks": "error",
1340
+ "jsdoc/no-defaults": "error",
1341
+ "jsdoc/no-multi-asterisks": "error",
1342
+ "jsdoc/require-asterisk-prefix": "error",
1343
+ "jsdoc/require-hyphen-before-param-description": "error",
1344
+ ...options.typescript ? typescriptRules : javscriptRules,
1345
+ ...options.overrides
1346
+ }
1347
+ }];
1348
+
1349
+ //#endregion
1350
+ //#region src/configs/jsonc.ts
1351
+ /**
1352
+ * @see {@link https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/configs/base.ts}
1353
+ */
1354
+ const disabledCoreRules = {
1355
+ "no-unused-expressions": "off",
1356
+ "no-unused-vars": "off",
1357
+ strict: "off"
1358
+ };
1359
+ /**
1360
+ * Config for json, jsonc and json5 files
1361
+ *
1362
+ * @see {@link https://ota-meshi.github.io/eslint-plugin-jsonc}
1363
+ *
1364
+ * @param options - {@link ConfigJsoncOptions}
1365
+ * @returns ESLint configs
1366
+ */
1367
+ const configJsonc = (options = {}) => {
1368
+ const { files = [
1369
+ GLOB_JSON,
1370
+ GLOB_JSON5,
1371
+ GLOB_JSONC
1372
+ ] } = options;
1373
+ return [{
1374
+ name: "ntnyq/jsonc",
1375
+ files,
1376
+ plugins: { jsonc: pluginJsonc },
1377
+ languageOptions: { parser: parserJsonc },
1378
+ rules: {
1379
+ "jsonc/array-bracket-spacing": ["error", "never"],
1380
+ "jsonc/comma-dangle": ["error", "never"],
1381
+ "jsonc/comma-style": ["error", "last"],
1382
+ "jsonc/indent": ["error", 2],
1383
+ "jsonc/key-spacing": ["error", {
1384
+ afterColon: true,
1385
+ beforeColon: false
1386
+ }],
1387
+ "jsonc/no-bigint-literals": "error",
1388
+ "jsonc/no-binary-expression": "error",
1389
+ "jsonc/no-binary-numeric-literals": "error",
1390
+ "jsonc/no-dupe-keys": "error",
1391
+ "jsonc/no-escape-sequence-in-identifier": "error",
1392
+ "jsonc/no-floating-decimal": "error",
1393
+ "jsonc/no-hexadecimal-numeric-literals": "error",
1394
+ "jsonc/no-infinity": "error",
1395
+ "jsonc/no-multi-str": "error",
1396
+ "jsonc/no-nan": "error",
1397
+ "jsonc/no-number-props": "error",
1398
+ "jsonc/no-numeric-separators": "error",
1399
+ "jsonc/no-octal": "error",
1400
+ "jsonc/no-octal-escape": "error",
1401
+ "jsonc/no-octal-numeric-literals": "error",
1402
+ "jsonc/no-parenthesized": "error",
1403
+ "jsonc/no-plus-sign": "error",
1404
+ "jsonc/no-regexp-literals": "error",
1405
+ "jsonc/no-sparse-arrays": "error",
1406
+ "jsonc/no-template-literals": "error",
1407
+ "jsonc/no-undefined-value": "error",
1408
+ "jsonc/no-unicode-codepoint-escapes": "error",
1409
+ "jsonc/no-useless-escape": "error",
1410
+ "jsonc/object-curly-newline": ["error", {
1411
+ consistent: true,
1412
+ multiline: true
1413
+ }],
1414
+ "jsonc/object-curly-spacing": ["error", "always"],
1415
+ "jsonc/object-property-newline": ["error", { allowMultiplePropertiesPerLine: true }],
1416
+ "jsonc/quote-props": "error",
1417
+ "jsonc/quotes": "error",
1418
+ "jsonc/space-unary-ops": "error",
1419
+ "jsonc/valid-json-number": "error",
1420
+ "jsonc/vue-custom-block/no-parsing-error": "error",
1421
+ ...disabledCoreRules,
1422
+ ...options.prettier ? {
1423
+ "jsonc/array-bracket-newline": "off",
1424
+ "jsonc/array-bracket-spacing": "off",
1425
+ "jsonc/array-element-newline": "off",
1426
+ "jsonc/comma-dangle": "off",
1427
+ "jsonc/comma-style": "off",
1428
+ "jsonc/indent": "off",
1429
+ "jsonc/key-spacing": "off",
1430
+ "jsonc/no-floating-decimal": "off",
1431
+ "jsonc/object-curly-newline": "off",
1432
+ "jsonc/object-curly-spacing": "off",
1433
+ "jsonc/object-property-newline": "off",
1434
+ "jsonc/quote-props": "off",
1435
+ "jsonc/quotes": "off",
1436
+ "jsonc/space-unary-ops": "off"
1437
+ } : {},
1438
+ ...options.overrides
1439
+ }
1440
+ }];
1441
+ };
1442
+
1443
+ //#endregion
1444
+ //#region src/configs/ntnyq.ts
1445
+ /**
1446
+ * Config for common files
1447
+ *
1448
+ * @see {@link https://github.com/ntnyq/eslint-plugin-ntnyq}
1449
+ *
1450
+ * @param options - {@link ConfigNtnyqOptions}
1451
+ * @returns ESLint configs
1452
+ */
1453
+ const configNtnyq = (options = {}) => [{
1454
+ name: "ntnyq/ntnyq",
1455
+ plugins: { ntnyq: pluginNtnyq },
1456
+ rules: {
1457
+ "ntnyq/no-duplicate-exports": "error",
1458
+ "ntnyq/prefer-newline-after-file-header": "error",
1459
+ ...options.overrides
1460
+ }
1461
+ }];
1462
+
1463
+ //#endregion
1464
+ //#region src/configs/pinia.ts
1465
+ /**
1466
+ * Config for pinia store
1467
+ *
1468
+ * @see {@link https://github.com/lisilinhart/eslint-plugin-pinia}
1469
+ *
1470
+ * @param options - {@link ConfigPiniaOptions}
1471
+ * @returns ESLint configs
1472
+ */
1473
+ const configPinia = (options = {}) => {
1474
+ const { files = [GLOB_PINIA_STORE] } = options;
1475
+ return [{
1476
+ name: "ntnyq/pinia",
1477
+ files,
1478
+ plugins: { pinia: pluginPinia },
1479
+ rules: {
1480
+ "pinia/never-export-initialized-store": "error",
1481
+ "pinia/no-duplicate-store-ids": "error",
1482
+ "pinia/no-return-global-properties": "error",
1483
+ "pinia/no-store-to-refs-in-store": "error",
1484
+ "pinia/prefer-single-store-per-file": "error",
1485
+ "pinia/prefer-use-store-naming-convention": ["error", {
1486
+ checkStoreNameMismatch: true,
1487
+ storeSuffix: "Store"
1488
+ }],
1489
+ "pinia/require-setup-store-properties-export": "error",
1490
+ ...options.overrides
1491
+ }
1492
+ }];
1493
+ };
1494
+
1495
+ //#endregion
1496
+ //#region src/configs/depend.ts
1497
+ /**
1498
+ * Config for optimisations dependency
1499
+ *
1500
+ * @see {@link https://github.com/es-tooling/eslint-plugin-depend}
1501
+ * @see {@link https://github.com/es-tooling/module-replacements}
1502
+ *
1503
+ * @param options - {@link ConfigDependOptions}
1504
+ * @returns ESLint configs
1505
+ */
1506
+ const configDepend = (options = {}) => {
1507
+ const { files = [GLOB_SRC], allowed = [], packageJson: enableCheckPackageJson = true } = options;
1508
+ const configs = [{
1509
+ name: "ntnyq/depend",
1510
+ files,
1511
+ plugins: { depend: pluginDepend },
1512
+ rules: {
1513
+ "depend/ban-dependencies": ["error", { allowed }],
1514
+ ...options.overrides
1515
+ }
1516
+ }];
1517
+ if (enableCheckPackageJson) configs.push({
1518
+ name: "ntnyq/depend/package-json",
1519
+ files: [GLOB_PACKAGE_JSON],
1520
+ plugins: { depend: pluginDepend },
1521
+ languageOptions: { parser: parserJsonc },
1522
+ rules: {
1523
+ "depend/ban-dependencies": ["error", { allowed }],
1524
+ ...options.overrides
1525
+ }
1526
+ });
1527
+ return configs;
1528
+ };
1529
+
1530
+ //#endregion
1531
+ //#region src/constants/prettier.ts
1532
+ /**
1533
+ * Options from `@ntnyq/prettier-config`
1534
+ *
1535
+ * @see {@link https://github.com/ntnyq/configs/blob/main/packages/prettier-config/index.js}
1536
+ */
1537
+ const PRETTIER_DEFAULT_OPTIONS = {
1538
+ arrowParens: "avoid",
1539
+ bracketSameLine: false,
1540
+ bracketSpacing: true,
1541
+ embeddedLanguageFormatting: "auto",
1542
+ endOfLine: "lf",
1543
+ experimentalOperatorPosition: "start",
1544
+ experimentalTernaries: false,
1545
+ htmlWhitespaceSensitivity: "css",
1546
+ insertPragma: false,
1547
+ jsxSingleQuote: true,
1548
+ objectWrap: "preserve",
1549
+ printWidth: 80,
1550
+ proseWrap: "preserve",
1551
+ quoteProps: "as-needed",
1552
+ rangeEnd: Number.POSITIVE_INFINITY,
1553
+ rangeStart: 0,
1554
+ requirePragma: false,
1555
+ semi: false,
1556
+ singleAttributePerLine: true,
1557
+ singleQuote: true,
1558
+ tabWidth: 2,
1559
+ trailingComma: "all",
1560
+ useTabs: false,
1561
+ vueIndentScriptAndStyle: false
1562
+ };
1563
+
1564
+ //#endregion
1565
+ //#region src/constants/perfectionist.ts
1566
+ /**
1567
+ * Shared perfectionist plugin settings
1568
+ */
1569
+ const pluginSettings = {
1570
+ fallbackSort: {
1571
+ order: "asc",
1572
+ type: "alphabetical"
1573
+ },
1574
+ ignoreCase: true,
1575
+ order: "asc",
1576
+ partitionByNewLine: false,
1577
+ specialCharacters: "keep",
1578
+ type: "alphabetical"
1579
+ };
1580
+ /**
1581
+ * Shared perfectionist rule options for some rules
1582
+ */
1583
+ const partialRuleOptions = {
1584
+ newlinesBetween: "ignore",
1585
+ partitionByComment: ["@pg", "@perfectionist-group"]
1586
+ };
1587
+ /**
1588
+ * Shared option `groups` for rule `sort-objects`
1589
+ *
1590
+ * @see {@link https://perfectionist.dev/rules/sort-objects}
1591
+ */
1592
+ const sortObjectsGroups = [
1593
+ "property",
1594
+ "multiline-property",
1595
+ "method",
1596
+ "multiline-method",
1597
+ "unknown"
1598
+ ];
1599
+ /**
1600
+ * Shared option `groups` for rules
1601
+ * - `sort-interfaces`
1602
+ * - `sort-object-types`
1603
+ *
1604
+ * @see {@link https://perfectionist.dev/rules/sort-interfaces}
1605
+ * @see {@link https://perfectionist.dev/rules/sort-object-types}
1606
+ */
1607
+ const sortInterfacesOrObjectTypesGroups = [
1608
+ "required-property",
1609
+ "optional-property",
1610
+ "required-method",
1611
+ "optional-method",
1612
+ "required-multiline-property",
1613
+ "optional-multiline-property",
1614
+ "required-multiline-method",
1615
+ "optional-multiline-method",
1616
+ "unknown",
1617
+ "index-signature",
1618
+ "multiline-index-signature"
1619
+ ];
1620
+ /**
1621
+ * Shared option `groups` for rules:
1622
+ * - `sort-intersection-types`
1623
+ * - `sort-union-types`
1624
+ *
1625
+ * Philosophy: keep simple thing first except null & undefined
1626
+ *
1627
+ * @see {@link https://perfectionist.dev/rules/sort-intersection-types}
1628
+ * @see {@link https://perfectionist.dev/rules/sort-union-types}
1629
+ */
1630
+ const sortIntersectionTypesOrUnionTypesGroups = [
1631
+ "literal",
1632
+ "keyword",
1633
+ "named",
1634
+ "intersection",
1635
+ "conditional",
1636
+ "function",
1637
+ "import",
1638
+ "object",
1639
+ "operator",
1640
+ "tuple",
1641
+ "union",
1642
+ "nullish"
1643
+ ];
1644
+ /**
1645
+ * Shared option `groups` for rule `sort-imports`
1646
+ *
1647
+ * @see {@link https://perfectionist.dev/rules/sort-imports}
1648
+ */
1649
+ const sortImportsTypes = [
1650
+ "side-effect-style",
1651
+ "value-style",
1652
+ "value-builtin",
1653
+ "value-external",
1654
+ "value-subpath",
1655
+ "value-internal",
1656
+ "value-parent",
1657
+ "value-sibling",
1658
+ "value-index",
1659
+ "ts-equals-import",
1660
+ "side-effect",
1661
+ "type-builtin",
1662
+ "type-external",
1663
+ "type-subpath",
1664
+ "type-internal",
1665
+ "type-parent",
1666
+ "type-sibling",
1667
+ "type-index",
1668
+ "unknown"
1669
+ ];
1670
+ /**
1671
+ * Shared option `groups` for rule `sort-exports`
1672
+ *
1673
+ * @see {@link https://perfectionist.dev/rules/sort-exports}
1674
+ */
1675
+ const sortExportsGroups = [
1676
+ "value-export",
1677
+ "type-export",
1678
+ "unknown"
1679
+ ];
1680
+ /**
1681
+ * Shared option `groups` for rule `sort-named-exports`
1682
+ *
1683
+ * @see {@link https://perfectionist.dev/rules/sort-named-exports}
1684
+ */
1685
+ const sortNamedExportsGroups = [
1686
+ "value-export",
1687
+ "type-export",
1688
+ "unknown"
1689
+ ];
1690
+ /**
1691
+ * Shared option `groups` for rule `sort-named-imports`
1692
+ *
1693
+ * @see {@link https://perfectionist.dev/rules/sort-named-imports}
1694
+ */
1695
+ const sortNamedImportsGroups = [
1696
+ "value-import",
1697
+ "type-import",
1698
+ "unknown"
1699
+ ];
1700
+ /**
1701
+ * Shared option `groups` for rule `sort-classes`
1702
+ *
1703
+ * // TODO: implement this
1704
+ *
1705
+ * @see {@link https://perfectionist.dev/rules/sort-classes}
1706
+ */
1707
+ const sortClassesGroups = ["unknown"];
1708
+ /**
1709
+ * Shared constants about eslint-plugin-perfectionist
1710
+ */
1711
+ const PERFECTIONIST = Object.freeze({
1712
+ partialRuleOptions,
1713
+ pluginSettings,
1714
+ sortClassesGroups,
1715
+ sortExportsGroups,
1716
+ sortImportsTypes,
1717
+ sortInterfacesOrObjectTypesGroups,
1718
+ sortIntersectionTypesOrUnionTypesGroups,
1719
+ sortNamedExportsGroups,
1720
+ sortNamedImportsGroups,
1721
+ sortObjectsGroups
1722
+ });
1723
+
1724
+ //#endregion
1725
+ //#region src/configs/format.ts
1726
+ /**
1727
+ * Config to use a formatter
1728
+ *
1729
+ * @see {@link https://github.com/antfu/eslint-plugin-format}
1730
+ *
1731
+ * @param options - {@link ConfigFormatOptions}
1732
+ * @returns ESLint configs
1733
+ */
1734
+ const configFormat = async (options = {}) => {
1735
+ await ensurePackages(["eslint-plugin-format"]);
1736
+ const pluginFormat = await interopDefault(import("eslint-plugin-format"));
1737
+ const { css: enableCSS = true, html: enableHTML = true, prettierOptions = {} } = options;
1738
+ const sharedPrettierOptions = {
1739
+ ...PRETTIER_DEFAULT_OPTIONS,
1740
+ ...prettierOptions
1741
+ };
1742
+ const configs = [{
1743
+ name: "ntnyq/format/setup",
1744
+ plugins: { format: pluginFormat }
1745
+ }];
1746
+ if (enableCSS) configs.push({
1747
+ name: "ntnyq/format/css",
1748
+ files: [GLOB_CSS, GLOB_POSTCSS],
1749
+ languageOptions: { parser: parserPlain },
1750
+ rules: { "format/prettier": ["error", mergePrettierOptions(sharedPrettierOptions, { parser: "css" })] }
1751
+ }, {
1752
+ name: "ntnyq/format/scss",
1753
+ files: [GLOB_SCSS],
1754
+ languageOptions: { parser: parserPlain },
1755
+ rules: { "format/prettier": ["error", mergePrettierOptions(sharedPrettierOptions, { parser: "scss" })] }
1756
+ }, {
1757
+ name: "ntnyq/format/less",
1758
+ files: [GLOB_LESS],
1759
+ languageOptions: { parser: parserPlain },
1760
+ rules: { "format/prettier": ["error", mergePrettierOptions(sharedPrettierOptions, { parser: "less" })] }
1761
+ });
1762
+ if (enableHTML) configs.push({
1763
+ name: "ntnyq/format/html",
1764
+ files: [GLOB_HTML],
1765
+ languageOptions: { parser: parserPlain },
1766
+ rules: { "format/prettier": ["error", mergePrettierOptions(sharedPrettierOptions, { parser: "html" })] }
1767
+ });
1768
+ return configs;
1769
+ };
1770
+
1771
+ //#endregion
1772
+ //#region src/configs/regexp.ts
1773
+ /**
1774
+ * Config for regexp
1775
+ *
1776
+ * @see {@link https://github.com/ota-meshi/eslint-plugin-regexp}
1777
+ *
1778
+ * @param options - {@link ConfigRegexpOptions}
1779
+ * @returns ESLint configs
1780
+ */
1781
+ const configRegexp = (options = {}) => {
1782
+ const recommendedConfig = pluginRegexp.configs["flat/recommended"];
1783
+ const recommendedRules$1 = { ...recommendedConfig.rules };
1784
+ if (options.severity === "warn") {
1785
+ for (const key in recommendedRules$1) if (recommendedRules$1[key] === "error") recommendedRules$1[key] = "warn";
1786
+ }
1787
+ return [{
1788
+ ...recommendedConfig,
1789
+ name: "ntnyq/regexp",
1790
+ rules: {
1791
+ ...recommendedRules$1,
1792
+ ...options.overrides
1793
+ }
1794
+ }];
1795
+ };
1796
+
1797
+ //#endregion
1798
+ //#region src/configs/svelte.ts
1799
+ /**
1800
+ * Config for svelte files
1801
+ *
1802
+ * @see {@link https://github.com/ota-meshi/eslint-plugin-svelte}
1803
+ *
1804
+ * @param options - {@link ConfigSvelteOptions}
1805
+ * @returns ESLint configs
1806
+ */
1807
+ const configSvelte = async (options = {}) => {
1808
+ await ensurePackages(["svelte-eslint-parser", "eslint-plugin-svelte"]);
1809
+ const [parserSvelte, pluginSvelte] = await Promise.all([interopDefault(import("svelte-eslint-parser")), interopDefault(import("eslint-plugin-svelte"))]);
1810
+ const { files = [GLOB_SVELTE], extraFileExtensions = [] } = options;
1811
+ return [{
1812
+ name: "ntnyq/svelte",
1813
+ files,
1814
+ plugins: { svelte: pluginSvelte },
1815
+ processor: pluginSvelte.processors[".svelte"],
1816
+ languageOptions: {
1817
+ parser: parserSvelte,
1818
+ sourceType: "module",
1819
+ parserOptions: {
1820
+ extraFileExtensions,
1821
+ parser: parserTypeScript
1822
+ }
1823
+ },
1824
+ rules: {
1825
+ "import-x/no-mutable-exports": "off",
1826
+ "no-undef": "off",
1827
+ "no-unused-vars": ["error", {
1828
+ args: "none",
1829
+ caughtErrors: "none",
1830
+ ignoreRestSiblings: true,
1831
+ vars: "all",
1832
+ varsIgnorePattern: "^(\\$\\$Props$|\\$\\$Events$|\\$\\$Slots$)"
1833
+ }],
1834
+ "svelte/comment-directive": "error",
1835
+ "svelte/derived-has-same-inputs-outputs": "error",
1836
+ "svelte/html-closing-bracket-spacing": "error",
1837
+ "svelte/html-quotes": ["error", {
1838
+ prefer: "double",
1839
+ dynamic: {
1840
+ avoidInvalidUnquotedInHTML: false,
1841
+ quoted: true
1842
+ }
1843
+ }],
1844
+ "svelte/indent": ["error", {
1845
+ alignAttributesVertically: true,
1846
+ indent: 2,
1847
+ indentScript: false
1848
+ }],
1849
+ "svelte/mustache-spacing": ["error", {
1850
+ attributesAndProps: "never",
1851
+ directiveExpressions: "always",
1852
+ textExpressions: "always",
1853
+ tags: {
1854
+ closingBrace: "always",
1855
+ openingBrace: "always"
1856
+ }
1857
+ }],
1858
+ "svelte/no-at-debug-tags": "error",
1859
+ "svelte/no-at-html-tags": "error",
1860
+ "svelte/no-dupe-else-if-blocks": "error",
1861
+ "svelte/no-dupe-style-properties": "error",
1862
+ "svelte/no-dupe-use-directives": "error",
1863
+ "svelte/no-dynamic-slot-name": "error",
1864
+ "svelte/no-export-load-in-svelte-module-in-kit-pages": "error",
1865
+ "svelte/no-inner-declarations": "error",
1866
+ "svelte/no-not-function-handler": "error",
1867
+ "svelte/no-object-in-text-mustaches": "error",
1868
+ "svelte/no-reactive-functions": "error",
1869
+ "svelte/no-reactive-literals": "error",
1870
+ "svelte/no-shorthand-style-property-overrides": "error",
1871
+ "svelte/no-spaces-around-equal-signs-in-attribute": "error",
1872
+ "svelte/no-trailing-spaces": "error",
1873
+ "svelte/no-unknown-style-directive-property": "error",
1874
+ "svelte/no-unused-svelte-ignore": "error",
1875
+ "svelte/no-useless-mustaches": "error",
1876
+ "svelte/require-store-callbacks-use-set-param": "error",
1877
+ "svelte/spaced-html-comment": "error",
1878
+ "svelte/system": "error",
1879
+ "svelte/valid-each-key": "error",
1880
+ ...options.overrides
1881
+ }
1882
+ }];
1883
+ };
1884
+
1885
+ //#endregion
1886
+ //#region src/configs/unocss.ts
1887
+ /**
1888
+ * Config for UnoCSS
1889
+ *
1890
+ * @see {@link https://github.com/unocss/unocss/tree/main/packages-integrations/eslint-plugin}
1891
+ *
1892
+ * @param options - {@link ConfigUnoCSSOptions}
1893
+ * @returns ESLint configs
1894
+ */
1895
+ const configUnoCSS = (options = {}) => [{
1896
+ name: "ntnyq/unocss",
1897
+ plugins: { unocss: pluginUnoCSS },
1898
+ rules: {
1899
+ "unocss/order-attributify": options.attributify ? "error" : "off",
1900
+ "unocss/order": "error",
1901
+ ...options.overrides
1902
+ }
1903
+ }];
1904
+
1905
+ //#endregion
1906
+ //#region src/commands/regexper.ts
1907
+ const regexper = defineCommand({
1908
+ name: "regexper",
1909
+ match: /(\b|\s|^)(@regexper)(\s\S+)?(\b|\s|$)/,
1910
+ action(ctx) {
1911
+ const literal = ctx.findNodeBelow((node) => {
1912
+ return node.type === "Literal" && "regex" in node;
1913
+ });
1914
+ if (!literal) return ctx.reportError("Unable to find a regexp literal to generate");
1915
+ const [_fullStr = "", spaceBefore = "", commandStr = "", existingUrl = "", _spaceAfter = ""] = ctx.matches;
1916
+ const url = `https://regexper.com/#${encodeURIComponent(literal.raw)}`;
1917
+ if (existingUrl.trim() === url.trim()) return;
1918
+ const indexStart = ctx.comment.range[0] + ctx.matches.index + spaceBefore.length + 2;
1919
+ const indexEnd = indexStart + commandStr.length + existingUrl.length;
1920
+ ctx.report({
1921
+ loc: {
1922
+ start: ctx.source.getLocFromIndex(indexStart),
1923
+ end: ctx.source.getLocFromIndex(indexEnd)
1924
+ },
1925
+ removeComment: false,
1926
+ message: "Update the regexper link",
1927
+ fix(fixer) {
1928
+ return fixer.replaceTextRange([indexStart, indexEnd], `@regexper ${url}`);
1929
+ }
1930
+ });
1931
+ }
1932
+ });
1933
+
1934
+ //#endregion
1935
+ //#region src/commands/index.ts
1936
+ const commands = [regexper];
1937
+
1938
+ //#endregion
1939
+ //#region src/configs/command.ts
1940
+ /**
1941
+ * Config for useing comments as codemod
1942
+ *
1943
+ * @see {@link https://github.com/antfu/eslint-plugin-command}
1944
+ *
1945
+ * @param options - {@link ConfigCommandOptions}
1946
+ * @returns ESLint configs
1947
+ */
1948
+ const configCommand = (options = {}) => [{
1949
+ ...createCommandConfig({
1950
+ ...options,
1951
+ commands: [
1952
+ ...builtinCommands,
1953
+ ...commands,
1954
+ ...options.commands || []
1955
+ ]
1956
+ }),
1957
+ name: "ntnyq/command"
1958
+ }];
1959
+
1960
+ //#endregion
1961
+ //#region src/configs/ignores.ts
1962
+ /**
1963
+ * Config for ignore files from linting
1964
+ *
1965
+ * @see https://eslint.org/docs/latest/use/configure/configuration-files-new#globally-ignoring-files-with-ignores
1966
+ *
1967
+ * @param customIgnores - {@link ConfigIgnoresOptions}
1968
+ * @returns ESLint configs
1969
+ */
1970
+ const configIgnores = (customIgnores = []) => [{
1971
+ name: "ntnyq/ignores",
1972
+ ignores: [...GLOB_EXCLUDE, ...customIgnores]
1973
+ }];
1974
+
1975
+ //#endregion
1976
+ //#region src/configs/importX.ts
1977
+ /**
1978
+ * Config for imports and exports
1979
+ *
1980
+ * @see {@link https://github.com/un-ts/eslint-plugin-import-x}
1981
+ *
1982
+ * @param options - {@link ConfigImportXOptions}
1983
+ * @returns ESLint configs
1984
+ */
1985
+ const configImportX = (options = {}) => {
1986
+ const { preferTypeScriptResolver = true, typescript: enableTypeScript } = options;
1987
+ return [{
1988
+ name: "ntnyq/import-x",
1989
+ plugins: { "import-x": pluginImportX },
1990
+ settings: { "import-x/resolver-next": [enableTypeScript && preferTypeScriptResolver ? createTypeScriptImportResolver({ extensions: [
1991
+ ".ts",
1992
+ ".tsx",
1993
+ ".d.ts",
1994
+ ".js",
1995
+ ".jsx",
1996
+ ".json",
1997
+ ".node"
1998
+ ] }) : pluginImportX.createNodeResolver({ extensions: [
1999
+ ".js",
2000
+ ".mjs",
2001
+ ".ts",
2002
+ ".mts",
2003
+ ".d.ts",
2004
+ ".json"
2005
+ ] })] },
2006
+ rules: {
2007
+ "import-x/no-absolute-path": "off",
2008
+ "import-x/no-named-as-default-member": "off",
2009
+ "import-x/no-named-default": "off",
2010
+ "import-x/no-unresolved": "off",
2011
+ "import-x/order": "off",
2012
+ "import-x/consistent-type-specifier-style": ["error", "prefer-top-level"],
2013
+ "import-x/export": "error",
2014
+ "import-x/first": "error",
2015
+ "import-x/newline-after-import": "error",
2016
+ "import-x/no-duplicates": "error",
2017
+ "import-x/no-mutable-exports": "error",
2018
+ "import-x/no-self-import": "error",
2019
+ ...options.overrides
2020
+ }
2021
+ }];
2022
+ };
2023
+
2024
+ //#endregion
2025
+ //#region src/configs/unicorn.ts
2026
+ const disabledRules = {
2027
+ "unicorn/better-regex": "off",
2028
+ "unicorn/explicit-length-check": "off",
2029
+ "unicorn/no-array-callback-reference": "off",
2030
+ "unicorn/prefer-global-this": "off",
2031
+ "unicorn/prefer-top-level-await": "off"
2032
+ };
2033
+ /**
2034
+ * Config for powerful rules
2035
+ *
2036
+ * @see {@link https://github.com/sindresorhus/eslint-plugin-unicorn}
2037
+ *
2038
+ * @param options - {@link ConfigUnicornOptions}
2039
+ * @returns ESLint configs
2040
+ */
2041
+ const configUnicorn = (options = {}) => [{
2042
+ name: "ntnyq/unicorn",
2043
+ plugins: { unicorn: pluginUnicorn },
2044
+ rules: {
2045
+ "unicorn/consistent-assert": "error",
2046
+ "unicorn/consistent-existence-index-check": "error",
2047
+ "unicorn/error-message": "error",
2048
+ "unicorn/escape-case": "error",
2049
+ "unicorn/new-for-builtins": "error",
2050
+ "unicorn/no-accessor-recursion": "error",
2051
+ "unicorn/no-console-spaces": "error",
2052
+ "unicorn/no-for-loop": "error",
2053
+ "unicorn/no-hex-escape": "error",
2054
+ "unicorn/no-instanceof-builtins": "error",
2055
+ "unicorn/no-lonely-if": "error",
2056
+ "unicorn/no-new-buffer": "error",
2057
+ "unicorn/no-static-only-class": "error",
2058
+ "unicorn/no-typeof-undefined": "error",
2059
+ "unicorn/no-unnecessary-await": "error",
2060
+ "unicorn/prefer-import-meta-properties": "error",
2061
+ "unicorn/prefer-includes": "error",
2062
+ "unicorn/prefer-keyboard-event-key": "error",
2063
+ "unicorn/prefer-math-min-max": "error",
2064
+ "unicorn/prefer-math-trunc": "error",
2065
+ "unicorn/prefer-modern-math-apis": "error",
2066
+ "unicorn/prefer-negative-index": "error",
2067
+ "unicorn/prefer-node-protocol": "error",
2068
+ "unicorn/prefer-optional-catch-binding": "error",
2069
+ "unicorn/prefer-prototype-methods": "error",
2070
+ "unicorn/prefer-reflect-apply": "error",
2071
+ "unicorn/prefer-structured-clone": "error",
2072
+ "unicorn/switch-case-braces": ["error", "avoid"],
2073
+ "unicorn/catch-error-name": ["error", {
2074
+ name: "err",
2075
+ ignore: ["^_."]
2076
+ }],
2077
+ "unicorn/custom-error-definition": "error",
2078
+ "unicorn/prefer-type-error": "error",
2079
+ "unicorn/throw-new-error": "error",
2080
+ "unicorn/no-zero-fractions": "error",
2081
+ "unicorn/number-literal-case": "error",
2082
+ "unicorn/prefer-number-properties": "error",
2083
+ "unicorn/prefer-regexp-test": "error",
2084
+ "unicorn/consistent-date-clone": "error",
2085
+ "unicorn/prefer-date-now": "error",
2086
+ "unicorn/prefer-code-point": "error",
2087
+ "unicorn/prefer-string-slice": "error",
2088
+ "unicorn/prefer-string-starts-ends-with": "error",
2089
+ "unicorn/prefer-string-trim-start-end": "error",
2090
+ "unicorn/no-invalid-remove-event-listener": "error",
2091
+ "unicorn/prefer-add-event-listener": "error",
2092
+ "unicorn/prefer-dom-node-append": "error",
2093
+ "unicorn/prefer-dom-node-dataset": "error",
2094
+ "unicorn/prefer-dom-node-remove": "error",
2095
+ "unicorn/prefer-dom-node-text-content": "error",
2096
+ "unicorn/prefer-modern-dom-apis": "error",
2097
+ "unicorn/prefer-query-selector": "error",
2098
+ "unicorn/no-array-method-this-argument": "error",
2099
+ "unicorn/no-new-array": "error",
2100
+ "unicorn/no-unnecessary-array-flat-depth": "error",
2101
+ "unicorn/no-unnecessary-array-splice-count": "error",
2102
+ "unicorn/no-unnecessary-slice-end": "error",
2103
+ "unicorn/prefer-array-find": "error",
2104
+ "unicorn/prefer-array-flat-map": "error",
2105
+ "unicorn/prefer-array-index-of": "error",
2106
+ "unicorn/prefer-array-some": "error",
2107
+ "unicorn/prefer-single-call": "error",
2108
+ "unicorn/require-array-join-separator": "error",
2109
+ "unicorn/prefer-set-has": "error",
2110
+ "unicorn/prefer-set-size": "error",
2111
+ ...disabledRules,
2112
+ ...options.overrides
2113
+ }
2114
+ }];
2115
+
2116
+ //#endregion
2117
+ //#region src/configs/deMorgan.ts
2118
+ /**
2119
+ * Config for optimize logic
2120
+ *
2121
+ * @see {@link https://github.com/azat-io/eslint-plugin-de-morgan}
2122
+ *
2123
+ * @param options - {@link ConfigDeMorganOptions}
2124
+ * @returns ESLint configs
2125
+ */
2126
+ const configDeMorgan = (options = {}) => [{
2127
+ ...pluginDeMorgan.configs.recommended,
2128
+ name: "ntnyq/de-morgan",
2129
+ rules: {
2130
+ ...pluginDeMorgan.configs.recommended.rules,
2131
+ ...options.overrides
2132
+ }
2133
+ }];
2134
+
2135
+ //#endregion
2136
+ //#region src/configs/markdown.ts
2137
+ /**
2138
+ * Config for markdown files
2139
+ *
2140
+ * @see {@link https://github.com/eslint/markdown}
2141
+ *
2142
+ * @param options - {@link ConfigMarkdownOptions}
2143
+ * @returns ESLint configs
2144
+ */
2145
+ const configMarkdown = (options = {}) => {
2146
+ const { files = [GLOB_MARKDOWN_CODE], extraFileExtensions = [] } = options;
2147
+ const configs = [
2148
+ ...pluginMarkdown.configs.processor.map((config) => ({
2149
+ ...config,
2150
+ name: `ntnyq/${config.name}`
2151
+ })),
2152
+ {
2153
+ name: "ntnyq/markdown/processor",
2154
+ files,
2155
+ ignores: [GLOB_MARKDOWN_NESTED],
2156
+ processor: mergeProcessors([pluginMarkdown.processors.markdown, processorPassThrough])
2157
+ },
2158
+ {
2159
+ name: "ntnyq/markdown/parser",
2160
+ files,
2161
+ languageOptions: { parser: parserPlain }
2162
+ },
2163
+ {
2164
+ name: "ntnyq/markdown/disabled",
2165
+ files: [...files, ...extraFileExtensions.map((ext) => `${GLOB_MARKDOWN}/**/*${ext}`)],
2166
+ languageOptions: { parserOptions: {
2167
+ project: false,
2168
+ projectService: false,
2169
+ ecmaFeatures: { impliedStrict: true }
2170
+ } },
2171
+ rules: {
2172
+ "@typescript-eslint/consistent-type-imports": "off",
2173
+ "@typescript-eslint/no-extraneous-class": "off",
2174
+ "@typescript-eslint/no-namespace": "off",
2175
+ "@typescript-eslint/no-redeclare": "off",
2176
+ "@typescript-eslint/no-require-imports": "off",
2177
+ "@typescript-eslint/no-unused-expressions": "off",
2178
+ "@typescript-eslint/no-unused-vars": "off",
2179
+ "@typescript-eslint/no-use-before-define": "off",
2180
+ "import-x/no-unresolved": "off",
2181
+ "no-alert": "off",
2182
+ "no-console": "off",
2183
+ "no-restricted-imports": "off",
2184
+ "no-undef": "off",
2185
+ "no-unused-expressions": "off",
2186
+ "no-unused-vars": "off",
2187
+ "node/prefer-global/buffer": "off",
2188
+ "node/prefer-global/process": "off",
2189
+ "unused-imports/no-unused-imports": "off",
2190
+ "unused-imports/no-unused-vars": "off",
2191
+ ...configsTypeScript.disableTypeChecked.rules,
2192
+ ...options.overrides
2193
+ }
2194
+ }
2195
+ ];
2196
+ return configs;
2197
+ };
2198
+
2199
+ //#endregion
2200
+ //#region src/configs/prettier.ts
2201
+ /**
2202
+ * Config for using prettier
2203
+ *
2204
+ * @see {@link https://github.com/prettier/eslint-plugin-prettier}
2205
+ *
2206
+ * @param options - {@link ConfigPrettierOptions}
2207
+ * @returns ESLint configs
2208
+ */
2209
+ const configPrettier = (options = {}) => {
2210
+ const { disabledFiles = [
2211
+ GLOB_SVG,
2212
+ GLOB_TOML,
2213
+ GLOB_ASTRO,
2214
+ GLOB_SVELTE
2215
+ ], userDisabledFiles = [] } = options;
2216
+ return [{
2217
+ name: "ntnyq/prettier",
2218
+ plugins: { prettier: pluginPrettier },
2219
+ rules: {
2220
+ "vue/array-bracket-newline": "off",
2221
+ "vue/array-bracket-spacing": "off",
2222
+ "vue/array-element-newline": "off",
2223
+ "vue/arrow-spacing": "off",
2224
+ "vue/block-spacing": "off",
2225
+ "vue/block-tag-newline": "off",
2226
+ "vue/brace-style": "off",
2227
+ "vue/comma-dangle": "off",
2228
+ "vue/comma-spacing": "off",
2229
+ "vue/comma-style": "off",
2230
+ "vue/dot-location": "off",
2231
+ "vue/func-call-spacing": "off",
2232
+ "vue/html-closing-bracket-newline": "off",
2233
+ "vue/html-closing-bracket-spacing": "off",
2234
+ "vue/html-end-tags": "off",
2235
+ "vue/html-indent": "off",
2236
+ "vue/html-quotes": "off",
2237
+ "vue/key-spacing": "off",
2238
+ "vue/keyword-spacing": "off",
2239
+ "vue/max-attributes-per-line": "off",
2240
+ "vue/multiline-html-element-content-newline": "off",
2241
+ "vue/multiline-ternary": "off",
2242
+ "vue/mustache-interpolation-spacing": "off",
2243
+ "vue/no-extra-parens": "off",
2244
+ "vue/no-multi-spaces": "off",
2245
+ "vue/no-spaces-around-equal-signs-in-attribute": "off",
2246
+ "vue/object-curly-newline": "off",
2247
+ "vue/object-curly-spacing": "off",
2248
+ "vue/object-property-newline": "off",
2249
+ "vue/operator-linebreak": "off",
2250
+ "vue/quote-props": "off",
2251
+ "vue/script-indent": "off",
2252
+ "vue/singleline-html-element-content-newline": "off",
2253
+ "vue/space-in-parens": "off",
2254
+ "vue/space-infix-ops": "off",
2255
+ "vue/space-unary-ops": "off",
2256
+ "vue/template-curly-spacing": "off",
2257
+ ...pluginPrettier.configs.recommended.rules,
2258
+ "prettier/prettier": options.severity || "warn",
2259
+ ...options.overrides
2260
+ }
2261
+ }, {
2262
+ name: "ntnyq/prettier/disabled",
2263
+ files: [...disabledFiles, ...userDisabledFiles],
2264
+ plugins: { prettier: pluginPrettier },
2265
+ rules: { "prettier/prettier": "off" }
2266
+ }];
2267
+ };
2268
+
2269
+ //#endregion
2270
+ //#region src/configs/specials.ts
2271
+ /**
2272
+ * Config for special files
2273
+ *
2274
+ * @param options - {@link ConfigSpecialsOptions}
2275
+ * @returns ESLint configs
2276
+ */
2277
+ const configSpecials = (options = {}) => {
2278
+ const { shadcnVue: enableShadcnVue = hasShadcnVue() } = options;
2279
+ const configs = [
2280
+ {
2281
+ name: "ntnyq/specials/scripts",
2282
+ files: [`**/scripts/${GLOB_SRC}`],
2283
+ rules: {
2284
+ "@typescript-eslint/explicit-function-return-type": "off",
2285
+ "no-console": "off",
2286
+ ...options.overridesScriptsRules
2287
+ }
2288
+ },
2289
+ {
2290
+ name: "ntnyq/specials/cli",
2291
+ files: [`**/cli/${GLOB_SRC}`, `**/cli.${GLOB_SRC_EXT}`],
2292
+ rules: {
2293
+ "@typescript-eslint/explicit-function-return-type": "off",
2294
+ "no-console": "off",
2295
+ ...options.overridesCliRules
2296
+ }
2297
+ },
2298
+ {
2299
+ name: "ntnyq/specials/bin",
2300
+ files: [`**/bin/${GLOB_SRC}`, `**/bin.${GLOB_SRC_EXT}`],
2301
+ rules: {
2302
+ "@typescript-eslint/explicit-function-return-type": "off",
2303
+ "antfu/no-import-dist": "off",
2304
+ "no-console": "off",
2305
+ ...options.overridesBinRules
2306
+ }
2307
+ },
2308
+ {
2309
+ name: "ntnyq/specials/userscript",
2310
+ files: [`**/*.user.${GLOB_SRC_EXT}`],
2311
+ languageOptions: { globals: { ...globals.greasemonkey } },
2312
+ rules: {
2313
+ camelcase: ["error", { allow: ["^GM_.+"] }],
2314
+ ...options.overridesUserScriptsRules
2315
+ }
2316
+ },
2317
+ {
2318
+ name: "ntnyq/specials/config-file",
2319
+ files: [`**/*.config*.${GLOB_SRC_EXT}`],
2320
+ plugins: {
2321
+ "import-x": pluginImportX,
2322
+ perfectionist: pluginPerfectionist
2323
+ },
2324
+ settings: { perfectionist: PERFECTIONIST.pluginSettings },
2325
+ rules: {
2326
+ "@typescript-eslint/explicit-function-return-type": "off",
2327
+ "import-x/no-default-export": "off",
2328
+ "no-console": "off",
2329
+ "perfectionist/sort-objects": ["error", {
2330
+ ...PERFECTIONIST.partialRuleOptions,
2331
+ groups: PERFECTIONIST.sortObjectsGroups
2332
+ }],
2333
+ ...options.overridesConfigFileRules
2334
+ }
2335
+ }
2336
+ ];
2337
+ if (enableShadcnVue) {
2338
+ const shadcnOptions = resolveSubOptions(options, "shadcnVue");
2339
+ configs.push({
2340
+ name: "ntnyq/specials/shadcn-vue",
2341
+ files: shadcnOptions.files || ["**/components/ui/**/*.ts", "**/components/ui/**/*.vue"],
2342
+ rules: {
2343
+ "@typescript-eslint/consistent-type-imports": "off",
2344
+ "@typescript-eslint/no-unused-vars": "off",
2345
+ "import-x/consistent-type-specifier-style": "off",
2346
+ "vue/define-emits-declaration": "off",
2347
+ "vue/html-button-has-type": "off",
2348
+ "vue/no-duplicate-attr-inheritance": "off",
2349
+ "vue/prefer-use-template-ref": "off",
2350
+ ...shadcnOptions.overridesRules
2351
+ }
2352
+ });
2353
+ }
2354
+ if (options.specialCaseConfigs) configs.push(...options.specialCaseConfigs);
2355
+ return configs;
2356
+ };
2357
+
2358
+ //#endregion
2359
+ //#region src/configs/gitignore.ts
2360
+ /**
2361
+ * Config for respect `.gitignore`
2362
+ *
2363
+ * @see {@link https://github.com/antfu/eslint-config-flat-gitignore}
2364
+ *
2365
+ * @param options - {@link ConfigGitIgnoreOptions}
2366
+ * @returns ESLint configs
2367
+ */
2368
+ const configGitIgnore = (options = {}) => {
2369
+ options.strict ??= false;
2370
+ return [{
2371
+ ...createGitIgnoreConfig(options),
2372
+ name: "ntnyq/gitignore"
2373
+ }];
2374
+ };
2375
+
2376
+ //#endregion
2377
+ //#region src/configs/javascript.ts
2378
+ const strictRules = {
2379
+ complexity: ["error", { max: 30 }],
2380
+ "max-depth": ["error", { max: 5 }],
2381
+ "max-lines": ["error", {
2382
+ max: 1e3,
2383
+ skipBlankLines: true,
2384
+ skipComments: true
2385
+ }],
2386
+ "max-lines-per-function": ["error", {
2387
+ max: 200,
2388
+ skipBlankLines: true,
2389
+ skipComments: true
2390
+ }],
2391
+ "max-nested-callbacks": ["error", { max: 10 }],
2392
+ "max-params": ["error", { max: 5 }]
2393
+ };
2394
+ /**
2395
+ * Config for JavaScript
2396
+ *
2397
+ * @see {@link https://github.com/eslint/eslint/tree/main/packages/js}
2398
+ *
2399
+ * @param options - {@link ConfigJavaScriptOptions}
2400
+ * @returns ESLint configs
2401
+ */
2402
+ const configJavaScript = (options = {}) => [{
2403
+ ...jsConfig.configs.recommended,
2404
+ name: "ntnyq/js/recommended"
2405
+ }, {
2406
+ name: "ntnyq/js/core",
2407
+ languageOptions: {
2408
+ sourceType: "module",
2409
+ globals: {
2410
+ ...globals.browser,
2411
+ ...globals.es2021,
2412
+ ...globals.node
2413
+ }
2414
+ },
2415
+ rules: {
2416
+ "consistent-return": "off",
2417
+ "no-return-assign": "off",
2418
+ "no-useless-escape": "off",
2419
+ "require-await": "off",
2420
+ "sort-imports": "off",
2421
+ "accessor-pairs": ["error", {
2422
+ enforceForClassMembers: true,
2423
+ setWithoutGet: true
2424
+ }],
2425
+ "array-callback-return": "error",
2426
+ "block-scoped-var": "error",
2427
+ camelcase: ["error", {
2428
+ allow: ["^UNSAFE_"],
2429
+ ignoreGlobals: true,
2430
+ properties: "never"
2431
+ }],
2432
+ "constructor-super": "error",
2433
+ curly: ["error", "multi-line"],
2434
+ "default-case-last": "error",
2435
+ "dot-notation": ["error", { allowKeywords: true }],
2436
+ eqeqeq: ["error", "smart"],
2437
+ "new-cap": ["error", {
2438
+ capIsNew: false,
2439
+ newIsCap: true,
2440
+ properties: true
2441
+ }],
2442
+ "no-alert": "error",
2443
+ "no-array-constructor": "error",
2444
+ "no-async-promise-executor": "error",
2445
+ "no-caller": "error",
2446
+ "no-case-declarations": "error",
2447
+ "no-class-assign": "error",
2448
+ "no-compare-neg-zero": "error",
2449
+ "no-cond-assign": "error",
2450
+ "no-const-assign": "error",
2451
+ "no-constant-condition": ["error", { checkLoops: false }],
2452
+ "no-control-regex": "error",
2453
+ "no-debugger": "error",
2454
+ "no-delete-var": "error",
2455
+ "no-dupe-args": "error",
2456
+ "no-dupe-class-members": "error",
2457
+ "no-dupe-keys": "error",
2458
+ "no-duplicate-case": "error",
2459
+ "no-empty": ["error", { allowEmptyCatch: true }],
2460
+ "no-empty-character-class": "error",
2461
+ "no-empty-pattern": "error",
2462
+ "no-empty-static-block": "error",
2463
+ "no-eval": "error",
2464
+ "no-ex-assign": "error",
2465
+ "no-extend-native": "error",
2466
+ "no-extra-bind": "error",
2467
+ "no-extra-boolean-cast": "error",
2468
+ "no-fallthrough": "error",
2469
+ "no-func-assign": "error",
2470
+ "no-global-assign": "error",
2471
+ "no-implied-eval": "error",
2472
+ "no-import-assign": "error",
2473
+ "no-invalid-regexp": "error",
2474
+ "no-irregular-whitespace": "error",
2475
+ "no-iterator": "error",
2476
+ "no-labels": ["error", {
2477
+ allowLoop: false,
2478
+ allowSwitch: false
2479
+ }],
2480
+ "no-lone-blocks": "error",
2481
+ "no-loss-of-precision": "error",
2482
+ "no-misleading-character-class": "error",
2483
+ "no-multi-str": "error",
2484
+ "no-new": "error",
2485
+ "no-new-func": "error",
2486
+ "no-new-native-nonconstructor": "error",
2487
+ "no-new-wrappers": "error",
2488
+ "no-obj-calls": "error",
2489
+ "no-octal": "error",
2490
+ "no-octal-escape": "error",
2491
+ "no-proto": "error",
2492
+ "no-prototype-builtins": "error",
2493
+ "no-redeclare": ["error", { builtinGlobals: false }],
2494
+ "no-regex-spaces": "error",
2495
+ "no-self-assign": ["error", { props: true }],
2496
+ "no-self-compare": "error",
2497
+ "no-sequences": "error",
2498
+ "no-shadow-restricted-names": "error",
2499
+ "no-sparse-arrays": "error",
2500
+ "no-template-curly-in-string": "error",
2501
+ "no-this-before-super": "error",
2502
+ "no-throw-literal": "error",
2503
+ "no-undef": "error",
2504
+ "no-undef-init": "error",
2505
+ "no-unexpected-multiline": "error",
2506
+ "no-unmodified-loop-condition": "error",
2507
+ "no-unneeded-ternary": ["error", { defaultAssignment: false }],
2508
+ "no-unreachable": "error",
2509
+ "no-unreachable-loop": "error",
2510
+ "no-unsafe-finally": "error",
2511
+ "no-unsafe-negation": "error",
2512
+ "no-unused-expressions": ["error", {
2513
+ allowShortCircuit: true,
2514
+ allowTaggedTemplates: true,
2515
+ allowTernary: true
2516
+ }],
2517
+ "no-unused-vars": ["error", {
2518
+ args: "none",
2519
+ caughtErrors: "none",
2520
+ ignoreRestSiblings: true,
2521
+ vars: "all"
2522
+ }],
2523
+ "no-use-before-define": ["error", {
2524
+ allowNamedExports: false,
2525
+ classes: false,
2526
+ functions: false,
2527
+ variables: true
2528
+ }],
2529
+ "no-useless-backreference": "error",
2530
+ "no-useless-call": "error",
2531
+ "no-useless-catch": "error",
2532
+ "no-useless-computed-key": "error",
2533
+ "no-useless-constructor": "error",
2534
+ "no-useless-rename": "error",
2535
+ "no-useless-return": "error",
2536
+ "no-var": "error",
2537
+ "no-void": "error",
2538
+ "no-with": "error",
2539
+ "object-shorthand": [
2540
+ "error",
2541
+ "always",
2542
+ {
2543
+ avoidQuotes: true,
2544
+ ignoreConstructors: false
2545
+ }
2546
+ ],
2547
+ "one-var": ["error", "never"],
2548
+ "prefer-arrow-callback": ["error", {
2549
+ allowNamedFunctions: false,
2550
+ allowUnboundThis: true
2551
+ }],
2552
+ "prefer-const": ["error", {
2553
+ destructuring: "all",
2554
+ ignoreReadBeforeAssign: true
2555
+ }],
2556
+ "prefer-promise-reject-errors": "error",
2557
+ "prefer-regex-literals": ["error", { disallowRedundantWrapping: true }],
2558
+ "prefer-rest-params": "error",
2559
+ "prefer-spread": "error",
2560
+ "prefer-template": "error",
2561
+ "symbol-description": "error",
2562
+ "unicode-bom": ["error", "never"],
2563
+ "use-isnan": ["error", {
2564
+ enforceForIndexOf: true,
2565
+ enforceForSwitchCase: true
2566
+ }],
2567
+ "valid-typeof": ["error", { requireStringLiterals: true }],
2568
+ "vars-on-top": "error",
2569
+ yoda: ["error", "never"],
2570
+ ...options.strict ? strictRules : {},
2571
+ ...options.overrides
2572
+ }
2573
+ }];
2574
+ const configJSX = () => [{
2575
+ name: "ntnyq/jsx",
2576
+ files: [GLOB_JSX_ONLY],
2577
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } }
2578
+ }];
2579
+
2580
+ //#endregion
2581
+ //#region src/configs/typescript.ts
2582
+ /**
2583
+ * @see {@link https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/recommended-type-checked.ts}
2584
+ */
2585
+ const typeAwareRules = {
2586
+ "@typescript-eslint/strict-boolean-expressions": "off",
2587
+ "dot-notation": "off",
2588
+ "no-implied-eval": "off",
2589
+ "no-throw-literal": "off",
2590
+ "require-await": "off",
2591
+ "@typescript-eslint/await-thenable": "error",
2592
+ "@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
2593
+ "@typescript-eslint/no-duplicate-type-constituents": "error",
2594
+ "@typescript-eslint/no-floating-promises": "error",
2595
+ "@typescript-eslint/no-for-in-array": "error",
2596
+ "@typescript-eslint/no-implied-eval": "error",
2597
+ "@typescript-eslint/no-misused-promises": "error",
2598
+ "@typescript-eslint/no-misused-spread": "error",
2599
+ "@typescript-eslint/no-redundant-type-constituents": "error",
2600
+ "@typescript-eslint/no-unnecessary-type-assertion": "error",
2601
+ "@typescript-eslint/no-unsafe-argument": "error",
2602
+ "@typescript-eslint/no-unsafe-assignment": "error",
2603
+ "@typescript-eslint/no-unsafe-call": "error",
2604
+ "@typescript-eslint/no-unsafe-member-access": "error",
2605
+ "@typescript-eslint/no-unsafe-return": "error",
2606
+ "@typescript-eslint/only-throw-error": "error",
2607
+ "@typescript-eslint/promise-function-async": "error",
2608
+ "@typescript-eslint/require-await": "error",
2609
+ "@typescript-eslint/restrict-plus-operands": "error",
2610
+ "@typescript-eslint/restrict-template-expressions": "error",
2611
+ "@typescript-eslint/return-await": ["error", "in-try-catch"],
2612
+ "@typescript-eslint/switch-exhaustiveness-check": "error",
2613
+ "@typescript-eslint/triple-slash-reference": "error",
2614
+ "@typescript-eslint/unbound-method": "error"
2615
+ };
2616
+ /**
2617
+ * typescript-eslint recommended rules
2618
+ */
2619
+ const recommendedRules = configsTypeScript.recommended.reduce((rules, config) => {
2620
+ return {
2621
+ ...rules,
2622
+ ...config.rules || {}
2623
+ };
2624
+ }, {});
2625
+ /**
2626
+ * Config for TypeScript files
2627
+ *
2628
+ * @see {@link https://github.com/typescript-eslint/typescript-eslint}
2629
+ *
2630
+ * @param options - {@link ConfigTypeScriptOptions}
2631
+ * @returns ESLint configs
2632
+ */
2633
+ const configTypeScript = (options = {}) => {
2634
+ /**
2635
+ * @see {@link https://typescript-eslint.io/troubleshooting/typed-linting}
2636
+ */
2637
+ const enableTypeAwareLint = !!options?.tsconfigPath;
2638
+ const { allowDefaultProject = [], extraFileExtensions = [], filesTypeAware = [GLOB_TS, GLOB_TSX], ignoresTypeAware = [GLOB_ASTRO, `${GLOB_MARKDOWN}/**`], overridesTypeAwareRules = {}, parserOptions = {} } = options;
2639
+ const files = options.files ?? [
2640
+ GLOB_TS,
2641
+ GLOB_TSX,
2642
+ ...extraFileExtensions.map((ext) => `**/*${ext}`)
2643
+ ];
2644
+ function createParserConfig(enableTypeAware = false, files$1 = [], ignores = []) {
2645
+ const typescriptParserOptions = {
2646
+ extraFileExtensions,
2647
+ sourceType: "module",
2648
+ ...enableTypeAware ? {
2649
+ tsconfigRootDir: process.cwd(),
2650
+ projectService: {
2651
+ allowDefaultProject: ["./*.js", ...allowDefaultProject],
2652
+ defaultProject: options.tsconfigPath
2653
+ }
2654
+ } : {},
2655
+ ...parserOptions
2656
+ };
2657
+ const parserConfig = {
2658
+ name: `ntnyq/ts/${enableTypeAware ? "parser-type-aware" : "parser"}`,
2659
+ files: files$1,
2660
+ ignores: [...ignores],
2661
+ languageOptions: {
2662
+ parser: parserTypeScript,
2663
+ parserOptions: typescriptParserOptions
2664
+ }
2665
+ };
2666
+ return parserConfig;
2667
+ }
2668
+ return [
2669
+ {
2670
+ name: "ntnyq/ts/setup",
2671
+ plugins: {
2672
+ "@typescript-eslint": pluginTypeScript,
2673
+ antfu: pluginAntfu
2674
+ }
2675
+ },
2676
+ ...enableTypeAwareLint ? [createParserConfig(false, files), createParserConfig(true, filesTypeAware, ignoresTypeAware)] : [createParserConfig(false, files)],
2677
+ {
2678
+ name: "ntnyq/ts/rules",
2679
+ files,
2680
+ rules: {
2681
+ ...recommendedRules,
2682
+ "@typescript-eslint/consistent-indexed-object-style": "off",
2683
+ "@typescript-eslint/explicit-function-return-type": "off",
2684
+ "@typescript-eslint/explicit-member-accessibility": "off",
2685
+ "@typescript-eslint/explicit-module-boundary-types": "off",
2686
+ "@typescript-eslint/naming-convention": "off",
2687
+ "@typescript-eslint/no-empty-function": "off",
2688
+ "@typescript-eslint/no-explicit-any": "off",
2689
+ "@typescript-eslint/no-namespace": "off",
2690
+ "@typescript-eslint/no-non-null-assertion": "off",
2691
+ "@typescript-eslint/triple-slash-reference": "off",
2692
+ "default-param-last": "off",
2693
+ "no-redeclare": "off",
2694
+ "no-unused-vars": "off",
2695
+ "no-use-before-define": "off",
2696
+ "no-useless-constructor": "off",
2697
+ "@typescript-eslint/prefer-as-const": "warn",
2698
+ "@typescript-eslint/ban-ts-comment": ["error", {
2699
+ minimumDescriptionLength: 1,
2700
+ "ts-check": false,
2701
+ "ts-expect-error": "allow-with-description",
2702
+ "ts-ignore": "allow-with-description",
2703
+ "ts-nocheck": "allow-with-description"
2704
+ }],
2705
+ "@typescript-eslint/ban-tslint-comment": "error",
2706
+ "@typescript-eslint/consistent-generic-constructors": ["error", "constructor"],
2707
+ "@typescript-eslint/consistent-type-assertions": ["error", {
2708
+ assertionStyle: "as",
2709
+ objectLiteralTypeAssertions: "allow-as-parameter"
2710
+ }],
2711
+ "@typescript-eslint/consistent-type-imports": ["error", {
2712
+ disallowTypeAnnotations: false,
2713
+ fixStyle: "separate-type-imports",
2714
+ prefer: "type-imports"
2715
+ }],
2716
+ "@typescript-eslint/default-param-last": "error",
2717
+ "@typescript-eslint/no-empty-object-type": ["error", {
2718
+ allowInterfaces: "always",
2719
+ allowObjectTypes: "always"
2720
+ }],
2721
+ "@typescript-eslint/no-redeclare": ["error", {
2722
+ builtinGlobals: false,
2723
+ ignoreDeclarationMerge: true
2724
+ }],
2725
+ "@typescript-eslint/no-unused-expressions": ["error", {
2726
+ allowShortCircuit: true,
2727
+ allowTaggedTemplates: true,
2728
+ allowTernary: true
2729
+ }],
2730
+ "@typescript-eslint/no-unused-vars": ["error", {
2731
+ args: "after-used",
2732
+ argsIgnorePattern: "^_",
2733
+ caughtErrors: "all",
2734
+ caughtErrorsIgnorePattern: "^_",
2735
+ destructuredArrayIgnorePattern: "^_",
2736
+ ignoreRestSiblings: true,
2737
+ varsIgnorePattern: "^_"
2738
+ }],
2739
+ "@typescript-eslint/no-use-before-define": ["error", {
2740
+ allowNamedExports: false,
2741
+ classes: false,
2742
+ enums: true,
2743
+ functions: false,
2744
+ ignoreTypeReferences: false,
2745
+ typedefs: false,
2746
+ variables: true
2747
+ }],
2748
+ "@typescript-eslint/no-useless-constructor": "error",
2749
+ ...options.overrides
2750
+ }
2751
+ },
2752
+ ...enableTypeAwareLint ? [{
2753
+ name: "ntnyq/ts/rules/type-aware",
2754
+ files: [...filesTypeAware],
2755
+ ignores: [...ignoresTypeAware],
2756
+ rules: {
2757
+ ...typeAwareRules,
2758
+ ...overridesTypeAwareRules
2759
+ }
2760
+ }] : [],
2761
+ {
2762
+ name: "ntnyq/ts/types",
2763
+ files: [...GLOB_TYPES],
2764
+ rules: {
2765
+ "@typescript-eslint/no-use-before-define": "off",
2766
+ "import-x/newline-after-import": "off",
2767
+ "import-x/no-duplicates": "off",
2768
+ "no-restricted-syntax": "off",
2769
+ "no-use-before-define": "off",
2770
+ "no-var": "off",
2771
+ "vars-on-top": "off"
2772
+ }
2773
+ }
2774
+ ];
2775
+ };
2776
+
2777
+ //#endregion
2778
+ //#region src/configs/eslintPlugin.ts
2779
+ /**
2780
+ * Config for eslint plugin
2781
+ *
2782
+ * @see {@link https://github.com/eslint-community/eslint-plugin-eslint-plugin}
2783
+ *
2784
+ * @param options - {@link ConfigESLintPluginOptions}
2785
+ * @returns ESLint configs
2786
+ */
2787
+ const configESLintPlugin = async (options = {}) => {
2788
+ await ensurePackages(["eslint-plugin-eslint-plugin"]);
2789
+ const pluginESLintPlugin = await interopDefault(import("eslint-plugin-eslint-plugin"));
2790
+ return [{
2791
+ ...pluginESLintPlugin.configs["flat/all"],
2792
+ name: "ntnyq/eslint-plugin",
2793
+ rules: {
2794
+ ...pluginESLintPlugin.configs["flat/all"].rules,
2795
+ "eslint-plugin/require-meta-docs-url": "off",
2796
+ ...options.overrides
2797
+ }
2798
+ }];
2799
+ };
2800
+
2801
+ //#endregion
2802
+ //#region src/configs/githubAction.ts
2803
+ /**
2804
+ * Config for github action files
2805
+ *
2806
+ * @see {@link https://github.com/ntnyq/eslint-plugin-github-action}
2807
+ *
2808
+ * @param options - {@link ConfigGitHubActionOptions}
2809
+ * @returns ESLint configs
2810
+ */
2811
+ const configGitHubAction = (options = {}) => {
2812
+ const { files = [GLOB_GITHUB_ACTION] } = options;
2813
+ return [{
2814
+ name: "ntnyq/github-action",
2815
+ files,
2816
+ plugins: { "github-action": pluginGitHubAction },
2817
+ languageOptions: { parser: parserYaml },
2818
+ rules: {
2819
+ "github-action/no-invalid-key": "error",
2820
+ "github-action/prefer-file-extension": "error",
2821
+ "github-action/require-action-name": "error",
2822
+ "github-action/valid-timeout-minutes": "error",
2823
+ "github-action/valid-trigger-events": "error",
2824
+ ...options.overrides
2825
+ }
2826
+ }];
2827
+ };
2828
+
2829
+ //#endregion
2830
+ //#region src/configs/perfectionist.ts
2831
+ /**
2832
+ * Config for sorting imports, exports, objects and etc
2833
+ *
2834
+ * @see {@link https://github.com/azat-io/eslint-plugin-perfectionist}
2835
+ *
2836
+ * @param options - {@link ConfigPerfectionistOptions}
2837
+ * @returns ESLint configs
2838
+ */
2839
+ const configPerfectionist = (options = {}) => {
2840
+ const { partitionByComment = PERFECTIONIST.partialRuleOptions.partitionByComment, sortConstants: enableSortConstants = true, sortEnums: enableSortEnums = true, sortTypes: enableSortTypes = true } = options;
2841
+ const sharedOptionsWithNewlinesBetween = {
2842
+ newlinesBetween: "ignore",
2843
+ partitionByComment
2844
+ };
2845
+ const commonRules = {
2846
+ "perfectionist/sort-exports": ["error", {
2847
+ ...sharedOptionsWithNewlinesBetween,
2848
+ groups: PERFECTIONIST.sortExportsGroups,
2849
+ type: "line-length"
2850
+ }],
2851
+ "perfectionist/sort-imports": ["error", {
2852
+ ...sharedOptionsWithNewlinesBetween,
2853
+ groups: PERFECTIONIST.sortImportsTypes,
2854
+ internalPattern: [
2855
+ "^~/.+",
2856
+ "^@/.+",
2857
+ "^#.+"
2858
+ ]
2859
+ }],
2860
+ "perfectionist/sort-named-exports": ["error", {
2861
+ ...sharedOptionsWithNewlinesBetween,
2862
+ groups: PERFECTIONIST.sortNamedExportsGroups,
2863
+ ignoreAlias: false
2864
+ }],
2865
+ "perfectionist/sort-named-imports": ["error", {
2866
+ ...sharedOptionsWithNewlinesBetween,
2867
+ groups: PERFECTIONIST.sortNamedImportsGroups,
2868
+ ignoreAlias: false
2869
+ }]
2870
+ };
2871
+ const sharedRules$1 = { "perfectionist/sort-enums": ["error", { ...sharedOptionsWithNewlinesBetween }] };
2872
+ const sortEnumsRules = { "perfectionist/sort-modules": ["error", { ...sharedOptionsWithNewlinesBetween }] };
2873
+ const sortTypesRules = {
2874
+ "perfectionist/sort-heritage-clauses": "error",
2875
+ "perfectionist/sort-interfaces": ["error", {
2876
+ ...sharedOptionsWithNewlinesBetween,
2877
+ groups: PERFECTIONIST.sortInterfacesOrObjectTypesGroups
2878
+ }],
2879
+ "perfectionist/sort-intersection-types": ["error", {
2880
+ ...sharedOptionsWithNewlinesBetween,
2881
+ groups: PERFECTIONIST.sortIntersectionTypesOrUnionTypesGroups
2882
+ }],
2883
+ "perfectionist/sort-object-types": ["error", {
2884
+ ...sharedOptionsWithNewlinesBetween,
2885
+ groups: PERFECTIONIST.sortInterfacesOrObjectTypesGroups
2886
+ }],
2887
+ "perfectionist/sort-union-types": ["error", {
2888
+ ...sharedOptionsWithNewlinesBetween,
2889
+ groups: PERFECTIONIST.sortIntersectionTypesOrUnionTypesGroups
2890
+ }]
2891
+ };
2892
+ const sortConstantsRules = {
2893
+ "perfectionist/sort-maps": ["error", { ...sharedOptionsWithNewlinesBetween }],
2894
+ "perfectionist/sort-objects": ["error", {
2895
+ ...sharedOptionsWithNewlinesBetween,
2896
+ groups: PERFECTIONIST.sortObjectsGroups
2897
+ }],
2898
+ "perfectionist/sort-sets": ["error", { ...sharedOptionsWithNewlinesBetween }]
2899
+ };
2900
+ const extraRules = {
2901
+ "perfectionist/sort-array-includes": ["error", {
2902
+ ...sharedOptionsWithNewlinesBetween,
2903
+ groups: ["literal", "spread"]
2904
+ }],
2905
+ "perfectionist/sort-classes": ["error", {
2906
+ ...sharedOptionsWithNewlinesBetween,
2907
+ groups: PERFECTIONIST.sortClassesGroups
2908
+ }],
2909
+ "perfectionist/sort-decorators": ["error", { partitionByComment }],
2910
+ "perfectionist/sort-jsx-props": ["error", { groups: [
2911
+ "shorthand",
2912
+ "multiline",
2913
+ "unknown"
2914
+ ] }],
2915
+ "perfectionist/sort-switch-case": "error",
2916
+ "perfectionist/sort-variable-declarations": ["error", { partitionByComment }]
2917
+ };
2918
+ const configs = [{
2919
+ name: options.all ? "ntnyq/perfectionist/all" : "ntnyq/perfectionist/common",
2920
+ plugins: { perfectionist: pluginPerfectionist },
2921
+ settings: { perfectionist: PERFECTIONIST.pluginSettings },
2922
+ rules: {
2923
+ ...commonRules,
2924
+ ...options.all ? {
2925
+ ...sharedRules$1,
2926
+ ...sortEnumsRules,
2927
+ ...sortTypesRules,
2928
+ ...sortConstantsRules,
2929
+ ...extraRules
2930
+ } : {},
2931
+ ...options.overrides
2932
+ }
2933
+ }];
2934
+ if (options.all) return configs;
2935
+ if (enableSortEnums) configs.push({
2936
+ name: "ntnyq/perfectionist/enums",
2937
+ files: [`**/enums/${GLOB_SRC}`, `**/enums.${GLOB_SRC_EXT}`],
2938
+ plugins: { perfectionist: pluginPerfectionist },
2939
+ settings: { perfectionist: PERFECTIONIST.pluginSettings },
2940
+ rules: {
2941
+ ...sharedRules$1,
2942
+ ...sortEnumsRules,
2943
+ ...options.overridesEnumsRules
2944
+ }
2945
+ });
2946
+ if (enableSortTypes) configs.push({
2947
+ name: "ntnyq/perfectionist/types",
2948
+ files: [...GLOB_TYPES],
2949
+ plugins: { perfectionist: pluginPerfectionist },
2950
+ settings: { perfectionist: PERFECTIONIST.pluginSettings },
2951
+ rules: {
2952
+ ...sharedRules$1,
2953
+ ...sortTypesRules,
2954
+ ...options.overridesTypesRules
2955
+ }
2956
+ });
2957
+ if (enableSortConstants) configs.push({
2958
+ name: "ntnyq/perfectionist/constants",
2959
+ files: [`**/constants/${GLOB_SRC}`, `**/constants.${GLOB_SRC_EXT}`],
2960
+ plugins: { perfectionist: pluginPerfectionist },
2961
+ settings: { perfectionist: PERFECTIONIST.pluginSettings },
2962
+ rules: {
2963
+ ...sharedRules$1,
2964
+ ...sortConstantsRules,
2965
+ ...options.overridesConstantsRules
2966
+ }
2967
+ });
2968
+ return configs;
2969
+ };
2970
+
2971
+ //#endregion
2972
+ //#region src/configs/unusedImports.ts
2973
+ /**
2974
+ * Config for remove unused imports
2975
+ *
2976
+ * @see {@link https://github.com/sweepline/eslint-plugin-unused-imports}
2977
+ *
2978
+ * @param options - {@link ConfigUnusedImportsOptions}
2979
+ * @returns ESLint configs
2980
+ */
2981
+ const configUnusedImports = async (options = {}) => {
2982
+ await ensurePackages(["eslint-plugin-unused-imports"]);
2983
+ const pluginUnusedImports = await interopDefault(import("eslint-plugin-unused-imports"));
2984
+ return [{
2985
+ name: "ntnyq/unused-imports",
2986
+ plugins: { "unused-imports": pluginUnusedImports },
2987
+ rules: {
2988
+ "@typescript-eslint/no-unused-vars": "off",
2989
+ "unused-imports/no-unused-imports": "error",
2990
+ "unused-imports/no-unused-vars": ["error", {
2991
+ args: "after-used",
2992
+ argsIgnorePattern: "^_",
2993
+ caughtErrors: "all",
2994
+ caughtErrorsIgnorePattern: "^_",
2995
+ destructuredArrayIgnorePattern: "^_",
2996
+ ignoreRestSiblings: true,
2997
+ vars: "all",
2998
+ varsIgnorePattern: "^_"
2999
+ }],
3000
+ ...options.overrides
3001
+ }
3002
+ }];
3003
+ };
3004
+
3005
+ //#endregion
3006
+ //#region src/configs/eslintComments.ts
3007
+ /**
3008
+ * Config for eslint comments
3009
+ *
3010
+ * @see {@link https://github.com/eslint-community/eslint-plugin-eslint-comments}
3011
+ *
3012
+ * @param options - {@link ConfigESLintCommentsOptions}
3013
+ * @returns ESLint configs
3014
+ */
3015
+ const configESLintComments = (options = {}) => [{
3016
+ name: "ntnyq/eslint-comments",
3017
+ plugins: { "@eslint-community/eslint-comments": pluginComments },
3018
+ rules: {
3019
+ ...pluginComments.configs.recommended.rules,
3020
+ "@eslint-community/eslint-comments/disable-enable-pair": ["error", { allowWholeFile: true }],
3021
+ ...options.overrides
3022
+ }
3023
+ }];
3024
+
3025
+ //#endregion
3026
+ //#region src/core.ts
3027
+ /**
3028
+ * Config factory
3029
+ */
3030
+ function defineESLintConfig(options = {}, ...userConfigs) {
3031
+ const { shareable = {}, vue: enableVue = hasVue(), pinia: enablePinia = hasPinia(), test: enableTest = hasVitest(), unocss: enableUnoCSS = hasUnoCSS(), typescript: enableTypeScript = hasTypeScript(), yml: enableYML = true, sort: enableSort = true, toml: enableTOML = true, jsonc: enableJSONC = true, antfu: enableAntfu = true, ntnyq: enableNtnyq = true, depend: enableDepend = true, regexp: enableRegexp = true, unicorn: enableUnicorn = true, deMorgan: enableDeMorgan = true, prettier: enablePrettier = true, markdown: enableMarkdown = true, gitignore: enableGitIgnore = true, githubAction: enableGitHubAction = true, perfectionist: enablePerfectionist = true, pnpm: enablePnpm = false, svgo: enableSVGO = false, html: enableHTML = false, astro: enableAstro = false, svelte: enableSvelte = false, eslintPlugin: enableESLintPlugin = false } = options;
3032
+ const configs = [];
3033
+ const { extraFileExtensions = [] } = shareable;
3034
+ if (enableVue) extraFileExtensions.push(".vue");
3035
+ if (enableAstro) extraFileExtensions.push(".astro");
3036
+ if (enableSvelte) extraFileExtensions.push(".svelte");
3037
+ if (enableGitIgnore) configs.push(configGitIgnore(resolveSubOptions(options, "gitignore")));
3038
+ configs.push(configIgnores(options.ignores), configJSX(), configNode({ overrides: getOverrides(options, "node") }), configCommand(resolveSubOptions(options, "command")), configImportX({
3039
+ ...resolveSubOptions(options, "importX"),
3040
+ typescript: !!enableTypeScript,
3041
+ overrides: getOverrides(options, "importX")
3042
+ }), configJsdoc({
3043
+ typescript: !!enableTypeScript,
3044
+ overrides: getOverrides(options, "jsdoc"),
3045
+ ...resolveSubOptions(options, "jsdoc")
3046
+ }), configESLintComments({ overrides: getOverrides(options, "eslintComments") }), configJavaScript({
3047
+ ...resolveSubOptions(options, "javascript"),
3048
+ overrides: getOverrides(options, "javascript")
3049
+ }));
3050
+ if (enablePerfectionist) configs.push(configPerfectionist({
3051
+ ...resolveSubOptions(options, "perfectionist"),
3052
+ overrides: getOverrides(options, "perfectionist")
3053
+ }));
3054
+ if (enableUnicorn) configs.push(configUnicorn({ overrides: getOverrides(options, "unicorn") }));
3055
+ if (enablePinia) configs.push(configPinia({
3056
+ ...resolveSubOptions(options, "pinia"),
3057
+ overrides: getOverrides(options, "pinia")
3058
+ }));
3059
+ if (enableDeMorgan) configs.push(configDeMorgan({ overrides: getOverrides(options, "deMorgan") }));
3060
+ if (enableRegexp) configs.push(configRegexp({
3061
+ ...resolveSubOptions(options, "regexp"),
3062
+ overrides: getOverrides(options, "regexp")
3063
+ }));
3064
+ if (enableTypeScript) configs.push(configTypeScript({
3065
+ ...resolveSubOptions(options, "typescript"),
3066
+ overrides: getOverrides(options, "typescript"),
3067
+ extraFileExtensions
3068
+ }));
3069
+ if (enableVue) configs.push(configVue({
3070
+ ...resolveSubOptions(options, "vue"),
3071
+ typescript: !!enableTypeScript,
3072
+ overrides: getOverrides(options, "vue"),
3073
+ extraFileExtensions
3074
+ }));
3075
+ if (enableYML) configs.push(configYml({
3076
+ prettier: !!enablePrettier,
3077
+ ...resolveSubOptions(options, "yml"),
3078
+ overrides: getOverrides(options, "yml")
3079
+ }));
3080
+ if (enableTOML) configs.push(configToml({
3081
+ ...resolveSubOptions(options, "toml"),
3082
+ overrides: getOverrides(options, "toml")
3083
+ }));
3084
+ if (enableJSONC) configs.push(configJsonc({
3085
+ prettier: !!enablePrettier,
3086
+ ...resolveSubOptions(options, "jsonc"),
3087
+ overrides: getOverrides(options, "jsonc")
3088
+ }));
3089
+ if (enableAstro) configs.push(configAstro({
3090
+ ...resolveSubOptions(options, "astro"),
3091
+ typescript: !!enableTypeScript,
3092
+ overrides: getOverrides(options, "astro"),
3093
+ extraFileExtensions
3094
+ }));
3095
+ if (enableSvelte) configs.push(configSvelte({
3096
+ ...resolveSubOptions(options, "svelte"),
3097
+ typescript: !!enableTypeScript,
3098
+ overrides: getOverrides(options, "svelte"),
3099
+ extraFileExtensions
3100
+ }));
3101
+ if (enableSort) configs.push(configSort(resolveSubOptions(options, "sort")));
3102
+ if (enableTest) configs.push(configTest({
3103
+ ...resolveSubOptions(options, "test"),
3104
+ overrides: getOverrides(options, "test")
3105
+ }));
3106
+ if (enableUnoCSS) configs.push(configUnoCSS({ overrides: getOverrides(options, "unocss") }));
3107
+ if (enableMarkdown) configs.push(configMarkdown({
3108
+ ...resolveSubOptions(options, "markdown"),
3109
+ overrides: getOverrides(options, "markdown"),
3110
+ extraFileExtensions
3111
+ }));
3112
+ if (enableAntfu) configs.push(configAntfu({ overrides: getOverrides(options, "antfu") }));
3113
+ if (enableDepend) configs.push(configDepend({
3114
+ ...resolveSubOptions(options, "depend"),
3115
+ overrides: getOverrides(options, "depend")
3116
+ }));
3117
+ if (enableNtnyq) configs.push(configNtnyq({ overrides: getOverrides(options, "ntnyq") }));
3118
+ if (enableGitHubAction) configs.push(configGitHubAction({ overrides: getOverrides(options, "githubAction") }));
3119
+ if (enableESLintPlugin) configs.push(configESLintPlugin({ overrides: getOverrides(options, "eslintPlugin") }));
3120
+ if (enablePnpm) configs.push(configPnpm(resolveSubOptions(options, "pnpm")));
3121
+ if (enableSVGO) configs.push(configSVGO(resolveSubOptions(options, "svgo")));
3122
+ if (enableHTML) configs.push(configHtml({
3123
+ ...resolveSubOptions(options, "html"),
3124
+ overrides: getOverrides(options, "html")
3125
+ }));
3126
+ const specialsConfigs = configSpecials(resolveSubOptions(options, "specials"));
3127
+ const prettierConfigs = enablePrettier ? configPrettier({
3128
+ ...resolveSubOptions(options, "prettier"),
3129
+ overrides: getOverrides(options, "prettier")
3130
+ }) : [];
3131
+ const composer = new FlatConfigComposer(...configs, ...userConfigs, ...specialsConfigs, ...prettierConfigs);
3132
+ return composer;
3133
+ }
3134
+
3135
+ //#endregion
3136
+ export { GLOB_ALL_SRC, GLOB_ASTRO, GLOB_ASTRO_TS, GLOB_CSS, GLOB_DIST, GLOB_DTS, GLOB_EXCLUDE, GLOB_GITHUB_ACTION, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSON_SCHEMA, GLOB_JSX, GLOB_JSX_ONLY, GLOB_LESS, GLOB_LOCKFILE, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_NESTED, GLOB_NODE_MODULES, GLOB_PACKAGE_JSON, GLOB_PINIA_STORE, GLOB_PNPM_WORKSPACE_YAML, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_SVELTE, GLOB_SVG, GLOB_TEST, GLOB_TOML, GLOB_TS, GLOB_TSCONFIG_JSON, GLOB_TSX, GLOB_TSX_ONLY, GLOB_TYPES, GLOB_TYPE_TEST, GLOB_VUE, GLOB_YAML, PERFECTIONIST, PRETTIER_DEFAULT_OPTIONS, combineConfigs, configAntfu, configAstro, configCommand, configDeMorgan, configDepend, configESLintComments, configESLintPlugin, configFormat, configGitHubAction, configGitIgnore, configHtml, configIgnores, configImportX, configJSX, configJavaScript, configJsdoc, configJsonc, configMarkdown, configNode, configNtnyq, configPerfectionist, configPinia, configPnpm, configPrettier, configRegexp, configSVGO, configSort, configSpecials, configSvelte, configTest, configToml, configTypeScript, configUnicorn, configUnoCSS, configUnusedImports, configVue, configYml, configsTypeScript, defineESLintConfig, ensurePackages, getOverrides, hasPinia, hasShadcnVue, hasTypeScript, hasUnoCSS, hasVitest, hasVue, interopDefault, isInGitHooksOrRunBySpecifyPackages, mergePrettierOptions, mergeProcessors, parserJsonc, parserPlain, parserToml, parserTypeScript, parserVue, parserYaml, pluginAntfu, pluginComments, pluginDeMorgan, pluginDepend, pluginGitHubAction, pluginImportX, pluginJsdoc, pluginJsonc, pluginMarkdown, pluginNoOnlyTests, pluginNode, pluginNtnyq, pluginPerfectionist, pluginPinia, pluginPrettier, pluginRegexp, pluginSvgo, pluginToml, pluginTypeScript, pluginUnicorn, pluginUnoCSS, pluginVitest, pluginVue, pluginYml, processorPassThrough, processorVueBlocks, resolveSubOptions };