@favorodera/eslint-config 0.1.4 → 1.0.1

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { FlatConfigComposer, renamePluginsInRules } from "eslint-flat-config-utils";
1
+ import { FlatConfigComposer } from "eslint-flat-config-utils";
2
2
  import { defu } from "defu";
3
3
  import globals from "globals";
4
4
  import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
@@ -15,7 +15,7 @@ const mdGlob = "**/*.md";
15
15
  /** Glob pattern for matching virtual files extracted from Markdown */
16
16
  const mdInMdGlob = "**/*.md/*.md";
17
17
  /** Glob pattern for matching code blocks embedded in Markdown files */
18
- const codeInMdGlob = "**/*.md/*.{js,cjs,mjs,ts,cts,mts,vue}";
18
+ const codeInMdGlob = "**/*.md/**/*.{js,cjs,mjs,ts,cts,mts,vue}";
19
19
  /** Glob pattern for matching scripts files */
20
20
  const scriptsGlob = "**/*.{js,cjs,mjs,ts,cts,mts}";
21
21
  /** Glob pattern for matching test files */
@@ -76,6 +76,99 @@ const ignoresGlob = [
76
76
  "**/.*/skills"
77
77
  ];
78
78
  //#endregion
79
+ //#region src/configs/disables.ts
80
+ /**
81
+ * Centralized disable configs applied **last** in the composer chain
82
+ * so they always override any rule enabled by preceding configs.
83
+ * @returns Config items that turn off specific rules for targeted file globs.
84
+ */
85
+ function disables() {
86
+ return [
87
+ {
88
+ files: [
89
+ json5Glob,
90
+ jsoncGlob,
91
+ jsonGlob
92
+ ],
93
+ name: "favorodera/disables/jsonc",
94
+ rules: { "no-irregular-whitespace": "off" }
95
+ },
96
+ {
97
+ files: [mdGlob],
98
+ ignores: [mdInMdGlob],
99
+ languageOptions: { frontmatter: "yaml" },
100
+ name: "favorodera/disables/markdown",
101
+ rules: { "md/no-missing-atx-heading-space": "off" }
102
+ },
103
+ {
104
+ files: [codeInMdGlob],
105
+ languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
106
+ name: "favorodera/disables/code-in-markdown",
107
+ rules: {
108
+ "no-alert": "off",
109
+ "no-console": "off",
110
+ "no-labels": "off",
111
+ "no-lone-blocks": "off",
112
+ "no-restricted-syntax": "off",
113
+ "no-undef": "off",
114
+ "no-unused-expressions": "off",
115
+ "no-unused-labels": "off",
116
+ "no-unused-vars": "off",
117
+ "unicode-bom": "off",
118
+ "node/prefer-global/process": "off",
119
+ "style/comma-dangle": "off",
120
+ "style/eol-last": "off",
121
+ "style/line-comment-position": "off",
122
+ "style/padding-line-between-statements": "off",
123
+ "ts/consistent-type-imports": "off",
124
+ "ts/explicit-function-return-type": "off",
125
+ "ts/no-namespace": "off",
126
+ "ts/no-redeclare": "off",
127
+ "ts/no-require-imports": "off",
128
+ "ts/no-unused-expressions": "off",
129
+ "ts/no-unused-vars": "off",
130
+ "ts/no-use-before-define": "off",
131
+ "unused-imports/no-unused-imports": "off",
132
+ "unused-imports/no-unused-vars": "off",
133
+ "vue/no-unused-vars": "off",
134
+ "jsdoc/require-jsdoc": "off"
135
+ }
136
+ },
137
+ {
138
+ files: [
139
+ jsGlob,
140
+ tsGlob,
141
+ vueGlob
142
+ ],
143
+ name: "favorodera/disables/js-ts-vue",
144
+ rules: {
145
+ "jsdoc/require-throws-type": "off",
146
+ "node/no-missing-import": "off",
147
+ "node/no-missing-require": "off",
148
+ "node/no-process-exit": "off",
149
+ "tailwind/enforce-consistent-important-position": "off",
150
+ "tailwind/enforce-consistent-variable-syntax": "off",
151
+ "tailwind/enforce-shorthand-classes": "off",
152
+ "unicorn/filename-case": "off",
153
+ "unicorn/no-process-exit": "off",
154
+ "unicorn/prevent-abbreviations": "off",
155
+ "no-unused-vars": "off",
156
+ "ts/no-unused-vars": "off"
157
+ }
158
+ },
159
+ {
160
+ files: [vueGlob],
161
+ name: "favorodera/disables/vue",
162
+ rules: { "vue/multi-word-component-names": "off" }
163
+ },
164
+ {
165
+ files: [testGlob],
166
+ name: "favorodera/disables/test",
167
+ rules: { "no-unused-expressions": "off" }
168
+ }
169
+ ];
170
+ }
171
+ //#endregion
79
172
  //#region src/configs/ignores.ts
80
173
  const defaultPatterns = ignoresGlob;
81
174
  /**
@@ -126,57 +219,70 @@ function resolveOptions(value, defaults) {
126
219
  if (!value) return false;
127
220
  return defu(value === true ? {} : value, defaults);
128
221
  }
222
+ /**
223
+ * Creates a new object that omits the specified keys from the target object.
224
+ * @template TTarget The type of the target object.
225
+ * @template TTargetKeys The type of the keys to omit from the target object.
226
+ * @param target The target object from which to omit the specified keys.
227
+ * @param keys An array of keys to omit from the target object.
228
+ * @returns A new object that contains all properties of the target object except for the specified keys.
229
+ */
230
+ function omit(target, keys) {
231
+ const targetClone = { ...target };
232
+ for (const key of keys) Reflect.deleteProperty(targetClone, key);
233
+ return targetClone;
234
+ }
129
235
  //#endregion
130
236
  //#region src/configs/imports.ts
131
- const importsDefaults = { files: [
132
- jsGlob,
133
- tsGlob,
134
- vueGlob
135
- ] };
136
237
  /**
137
238
  * Constructs the flat config items for imports linting, providing plugin setup and
138
239
  * specific rules to enforce consistent import ordering and quality.
139
- * @param options Configuration options for imports linting.
140
240
  * @returns Promise resolving to imports ESLint config items.
141
241
  */
142
- async function imports(options) {
143
- const resolved = defu(options, importsDefaults);
242
+ async function imports() {
144
243
  const importPlugin = await importModule(import("eslint-plugin-import-lite"));
145
- const baseRules = importPlugin.configs.recommended?.rules || {};
244
+ const files = [
245
+ jsGlob,
246
+ tsGlob,
247
+ vueGlob
248
+ ];
249
+ const recommendedConfig = importPlugin.configs.recommended;
250
+ const { rules = {} } = recommendedConfig;
146
251
  return [{
147
- name: "favorodera/imports/setup",
148
- plugins: { import: importPlugin }
252
+ ...omit(recommendedConfig, [
253
+ "rules",
254
+ "files",
255
+ "name"
256
+ ]),
257
+ name: "favorodera/imports/setup"
149
258
  }, {
150
- files: resolved.files,
259
+ files,
151
260
  name: "favorodera/imports/rules",
152
261
  rules: {
153
- ...renamePluginsInRules(baseRules, { "import-lite": "import" }),
262
+ ...rules,
154
263
  "import/consistent-type-specifier-style": ["error", "prefer-top-level"],
155
264
  "import/first": "error",
156
265
  "import/newline-after-import": ["error", { count: 1 }],
157
266
  "import/no-duplicates": ["error", { "prefer-inline": true }],
158
267
  "import/no-mutable-exports": "error",
159
- "import/no-named-default": "error",
160
- ...resolved.overrides
268
+ "import/no-named-default": "error"
161
269
  }
162
270
  }];
163
271
  }
164
272
  //#endregion
165
273
  //#region src/configs/javascript.ts
166
- const javascriptDefaults = { files: [
167
- jsGlob,
168
- tsGlob,
169
- vueGlob
170
- ] };
171
274
  /**
172
275
  * Constructs the flat config items for core JavaScript linting, setting up the required
173
276
  * language options, globals, and recommended baseline rules.
174
- * @param options Javascript configuration options.
175
277
  * @returns Promise resolving to javascript ESLint config items.
176
278
  */
177
- async function javascript(options) {
178
- const resolved = defu(options, javascriptDefaults);
179
- const baseRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
279
+ async function javascript() {
280
+ const jsPlugin = await importModule(import("@eslint/js"));
281
+ const files = [
282
+ jsGlob,
283
+ tsGlob,
284
+ vueGlob
285
+ ];
180
286
  return [{
181
287
  languageOptions: {
182
288
  ecmaVersion: "latest",
@@ -193,15 +299,16 @@ async function javascript(options) {
193
299
  linterOptions: { reportUnusedDisableDirectives: true },
194
300
  name: "favorodera/javascript/setup"
195
301
  }, {
196
- files: resolved.files,
302
+ files,
197
303
  name: "favorodera/javascript/rules",
198
304
  rules: {
199
- ...baseRules,
200
- "array-callback-return": "error",
305
+ ...jsPlugin.configs.recommended.rules,
306
+ "array-callback-return": ["error", { allowImplicit: true }],
201
307
  "block-scoped-var": "error",
202
308
  "default-case-last": "error",
203
309
  "dot-notation": "error",
204
310
  "eqeqeq": "error",
311
+ "getter-return": ["error", { allowImplicit: true }],
205
312
  "new-cap": "error",
206
313
  "no-alert": "error",
207
314
  "no-array-constructor": "error",
@@ -284,75 +391,88 @@ async function javascript(options) {
284
391
  "unicode-bom": "error",
285
392
  "valid-typeof": ["error", { requireStringLiterals: true }],
286
393
  "vars-on-top": "error",
287
- "yoda": "error",
288
- ...resolved.overrides
394
+ "yoda": "error"
289
395
  }
290
396
  }];
291
397
  }
292
398
  //#endregion
293
399
  //#region src/configs/jsdoc.ts
294
- const jsdocDefaults = { files: [
295
- jsGlob,
296
- tsGlob,
297
- vueGlob
298
- ] };
299
400
  /**
300
401
  * Constructs the flat config items for JSDoc linting, ensuring comments follow
301
402
  * proper styling, parameter checks, and types alignment.
302
- * @param options JSDoc configuration options.
303
403
  * @returns Promise resolving to JSDoc ESLint config items.
304
404
  */
305
- async function jsdoc(options) {
306
- const resolved = defu(options, jsdocDefaults);
405
+ async function jsdoc() {
307
406
  const jsdocPlugin = await importModule(import("eslint-plugin-jsdoc"));
308
- const baseRules = {
309
- ...jsdocPlugin.configs["flat/recommended-typescript-error"]?.rules,
310
- ...jsdocPlugin.configs["flat/stylistic-typescript-error"]?.rules
407
+ const files = [
408
+ jsGlob,
409
+ tsGlob,
410
+ vueGlob
411
+ ];
412
+ const recommendedConfig = jsdocPlugin.configs["flat/recommended-typescript-error"];
413
+ const stylisticConfig = jsdocPlugin.configs["flat/stylistic-typescript-error"];
414
+ const { rules: recommendedRules = {} } = recommendedConfig;
415
+ const recommendedRest = omit(recommendedConfig, [
416
+ "rules",
417
+ "files",
418
+ "name"
419
+ ]);
420
+ const { rules: stylisticRules = {} } = stylisticConfig;
421
+ const stylisticRest = omit(stylisticConfig, [
422
+ "rules",
423
+ "files",
424
+ "name"
425
+ ]);
426
+ const rules = {
427
+ ...recommendedRules,
428
+ ...stylisticRules
311
429
  };
312
- return [{
313
- name: "favorodera/jsdoc/setup",
314
- plugins: { jsdoc: jsdocPlugin }
315
- }, {
316
- files: resolved.files,
317
- name: "favorodera/jsdoc/rules",
318
- rules: {
319
- ...baseRules,
320
- "jsdoc/check-indentation": "error",
321
- "jsdoc/check-template-names": "error",
322
- "jsdoc/imports-as-dependencies": "error",
323
- "jsdoc/lines-before-block": ["error", { ignoreSingleLines: false }],
324
- "jsdoc/multiline-blocks": "error",
325
- "jsdoc/no-bad-blocks": "error",
326
- "jsdoc/no-blank-block-descriptions": "error",
327
- "jsdoc/no-blank-blocks": "error",
328
- "jsdoc/require-throws-type": "off",
329
- "jsdoc/sort-tags": "error",
330
- ...resolved.overrides
430
+ return [
431
+ {
432
+ ...recommendedRest,
433
+ name: "favorodera/jsdoc/recommended/setup"
434
+ },
435
+ {
436
+ ...stylisticRest,
437
+ name: "favorodera/jsdoc/stylistic/setup"
438
+ },
439
+ {
440
+ files,
441
+ name: "favorodera/jsdoc/rules",
442
+ rules: {
443
+ ...rules,
444
+ "jsdoc/check-indentation": "error",
445
+ "jsdoc/check-template-names": "error",
446
+ "jsdoc/imports-as-dependencies": "error",
447
+ "jsdoc/lines-before-block": ["error", { ignoreSingleLines: false }],
448
+ "jsdoc/multiline-blocks": "error",
449
+ "jsdoc/no-bad-blocks": "error",
450
+ "jsdoc/no-blank-block-descriptions": "error",
451
+ "jsdoc/no-blank-blocks": "error",
452
+ "jsdoc/sort-tags": "error"
453
+ }
331
454
  }
332
- }];
455
+ ];
333
456
  }
334
457
  //#endregion
335
458
  //#region src/configs/jsonc.ts
336
- const jsoncDefaults = { files: [
337
- json5Glob,
338
- jsoncGlob,
339
- jsonGlob
340
- ] };
341
459
  /**
342
460
  * Constructs the flat config items for JSON, JSON5, and JSONC linting, setting up
343
461
  * the custom parser, rule validations, and sorting rules for package.json/tsconfig.json.
344
- * @param options JSONC configuration options.
345
462
  * @returns Promise resolving to JSONC ESLint config items.
346
463
  */
347
- async function jsonc(options) {
348
- const resolved = defu(options, jsoncDefaults);
464
+ async function jsonc() {
349
465
  return [
350
466
  {
351
467
  name: "favorodera/jsonc/setup",
352
468
  plugins: { jsonc: await importModule(import("eslint-plugin-jsonc")) }
353
469
  },
354
470
  {
355
- files: resolved.files,
471
+ files: [
472
+ json5Glob,
473
+ jsoncGlob,
474
+ jsonGlob
475
+ ],
356
476
  language: "jsonc/x",
357
477
  name: "favorodera/jsonc/rules",
358
478
  rules: {
@@ -400,8 +520,7 @@ async function jsonc(options) {
400
520
  "jsonc/quotes": "error",
401
521
  "jsonc/space-unary-ops": "error",
402
522
  "jsonc/valid-json-number": "error",
403
- "jsonc/vue-custom-block/no-parsing-error": "error",
404
- ...resolved.overrides
523
+ "jsonc/vue-custom-block/no-parsing-error": "error"
405
524
  }
406
525
  },
407
526
  {
@@ -620,21 +739,12 @@ async function jsonc(options) {
620
739
  pathPattern: "^compilerOptions$"
621
740
  }
622
741
  ] }
623
- },
624
- {
625
- files: resolved.files,
626
- language: "jsonc/x",
627
- name: "favorodera/jsonc/disables",
628
- rules: { "no-irregular-whitespace": "off" }
629
742
  }
630
743
  ];
631
744
  }
632
745
  //#endregion
633
746
  //#region src/configs/markdown.ts
634
- const markdownDefaults = {
635
- files: [mdGlob],
636
- gfm: true
637
- };
747
+ const markdownDefaults = { gfm: true };
638
748
  /**
639
749
  * Constructs the flat config items for Markdown linting, extracting and linting
640
750
  * embedded code blocks within the document according to specified rules.
@@ -644,139 +754,87 @@ const markdownDefaults = {
644
754
  async function markdown(options) {
645
755
  const resolved = defu(options, markdownDefaults);
646
756
  const markdownPlugin = await importModule(import("@eslint/markdown"));
647
- const baseRules = extractRules(markdownPlugin.configs.recommended);
648
- return [
649
- {
650
- name: "favorodera/markdown/setup",
651
- plugins: { md: markdownPlugin }
652
- },
653
- {
654
- files: resolved.files,
655
- ignores: [mdInMdGlob],
656
- language: resolved.gfm ? "md/gfm" : "md/commonmark",
657
- languageOptions: { frontmatter: "yaml" },
658
- name: "favorodera/markdown/rules",
659
- processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
660
- rules: {
661
- ...renamePluginsInRules(baseRules, { markdown: "md" }),
662
- "md/fenced-code-language": "off",
663
- "md/no-missing-label-refs": "off",
664
- ...resolved.overrides
665
- }
666
- },
667
- {
668
- files: [codeInMdGlob],
669
- languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
670
- name: "favorodera/markdown/code-in-md/disables",
671
- rules: {
672
- "no-alert": "off",
673
- "no-console": "off",
674
- "no-labels": "off",
675
- "no-lone-blocks": "off",
676
- "no-restricted-syntax": "off",
677
- "no-undef": "off",
678
- "no-unused-expressions": "off",
679
- "no-unused-labels": "off",
680
- "no-unused-vars": "off",
681
- "unicode-bom": "off",
682
- "node/prefer-global/process": "off",
683
- "style/comma-dangle": "off",
684
- "style/eol-last": "off",
685
- "style/padding-line-between-statements": "off",
686
- "ts/consistent-type-imports": "off",
687
- "ts/explicit-function-return-type": "off",
688
- "ts/no-namespace": "off",
689
- "ts/no-redeclare": "off",
690
- "ts/no-require-imports": "off",
691
- "ts/no-unused-expressions": "off",
692
- "ts/no-unused-vars": "off",
693
- "ts/no-use-before-define": "off",
694
- "unused-imports/no-unused-imports": "off",
695
- "unused-imports/no-unused-vars": "off",
696
- "vue/no-unused-vars": "off",
697
- "jsdoc/require-jsdoc": "off"
698
- }
699
- }
700
- ];
757
+ const [recommendedConfig] = markdownPlugin.configs.recommended;
758
+ const { rules = {} } = recommendedConfig;
759
+ return [{
760
+ ...omit(recommendedConfig, [
761
+ "rules",
762
+ "files",
763
+ "name",
764
+ "language"
765
+ ]),
766
+ name: "favorodera/markdown/setup"
767
+ }, {
768
+ files: [mdGlob],
769
+ ignores: [mdInMdGlob],
770
+ language: resolved.gfm ? "md/gfm" : "md/commonmark",
771
+ languageOptions: { frontmatter: "yaml" },
772
+ name: "favorodera/markdown/rules",
773
+ processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
774
+ rules
775
+ }];
701
776
  }
702
777
  //#endregion
703
778
  //#region src/configs/node.ts
704
- const nodeDefaults = { files: [
705
- jsGlob,
706
- tsGlob,
707
- vueGlob
708
- ] };
709
779
  /**
710
780
  * Constructs the flat config items for Node.js linting, providing rules
711
781
  * to enforce best practices for Node.js environments.
712
- * @param options Node configuration options.
713
782
  * @returns Promise resolving to Node ESLint config items.
714
783
  */
715
- async function node(options) {
716
- const resolved = defu(options, nodeDefaults);
784
+ async function node() {
717
785
  const nodePlugin = await importModule(import("eslint-plugin-n"));
718
- const baseRules = nodePlugin.configs?.["flat/recommended-module"]?.rules || {};
719
- return [
720
- {
721
- name: "favorodera/node/setup",
722
- plugins: { node: nodePlugin }
723
- },
724
- {
725
- files: resolved.files,
726
- name: "favorodera/node/rules",
727
- rules: {
728
- ...renamePluginsInRules(baseRules, { n: "node" }),
729
- "node/callback-return": "error",
730
- "node/handle-callback-err": ["error", "^(err|error)$"],
731
- "node/no-callback-literal": "error",
732
- "node/no-new-require": "error",
733
- "node/no-path-concat": "error",
734
- "node/no-unpublished-import": "error",
735
- "node/prefer-global/buffer": "error",
736
- "node/prefer-global/console": "error",
737
- "node/prefer-global/crypto": "error",
738
- "node/prefer-global/process": "error",
739
- "node/prefer-global/text-decoder": "error",
740
- "node/prefer-global/text-encoder": "error",
741
- "node/prefer-global/timers": "error",
742
- "node/prefer-global/url": "error",
743
- "node/prefer-global/url-search-params": "error",
744
- "node/prefer-node-protocol": "error",
745
- "node/prefer-promises/dns": "error",
746
- "node/prefer-promises/fs": "error",
747
- "node/no-process-exit": "off",
748
- ...resolved.overrides
749
- }
750
- },
751
- {
752
- files: [tsGlob, vueGlob],
753
- name: "favorodera/node/disables",
754
- rules: {
755
- "node/no-missing-import": "off",
756
- "node/no-missing-require": "off"
757
- }
758
- }
786
+ const files = [
787
+ jsGlob,
788
+ tsGlob,
789
+ vueGlob
759
790
  ];
791
+ const recommendedConfig = nodePlugin.configs["flat/recommended-module"];
792
+ const { rules = {} } = recommendedConfig;
793
+ return [{
794
+ ...omit(recommendedConfig, [
795
+ "rules",
796
+ "files",
797
+ "name"
798
+ ]),
799
+ name: "favorodera/node/setup"
800
+ }, {
801
+ files,
802
+ name: "favorodera/node/rules",
803
+ rules: {
804
+ ...rules,
805
+ "node/callback-return": "error",
806
+ "node/handle-callback-err": ["error", "^(err|error)$"],
807
+ "node/no-callback-literal": "error",
808
+ "node/no-new-require": "error",
809
+ "node/no-path-concat": "error",
810
+ "node/no-unpublished-import": "error",
811
+ "node/prefer-global/buffer": "error",
812
+ "node/prefer-global/console": "error",
813
+ "node/prefer-global/crypto": "error",
814
+ "node/prefer-global/process": "error",
815
+ "node/prefer-global/text-decoder": "error",
816
+ "node/prefer-global/text-encoder": "error",
817
+ "node/prefer-global/timers": "error",
818
+ "node/prefer-global/url": "error",
819
+ "node/prefer-global/url-search-params": "error",
820
+ "node/prefer-node-protocol": "error",
821
+ "node/prefer-promises/dns": "error",
822
+ "node/prefer-promises/fs": "error"
823
+ }
824
+ }];
760
825
  }
761
826
  //#endregion
762
827
  //#region src/configs/perfectionist.ts
763
828
  const perfectionistDefaults = {
764
- files: [
765
- jsGlob,
766
- tsGlob,
767
- vueGlob
768
- ],
769
- settings: {
770
- ignoreCase: true,
771
- locales: "en-US",
772
- newlinesBetween: "ignore",
773
- newlinesInside: "ignore",
774
- order: "asc",
775
- partitionByComment: true,
776
- partitionByNewLine: true,
777
- specialCharacters: "keep",
778
- type: "natural"
779
- }
829
+ ignoreCase: true,
830
+ locales: "en-US",
831
+ newlinesBetween: "ignore",
832
+ newlinesInside: "ignore",
833
+ order: "asc",
834
+ partitionByComment: true,
835
+ partitionByNewLine: true,
836
+ specialCharacters: "keep",
837
+ type: "natural"
780
838
  };
781
839
  /**
782
840
  * Constructs the flat config items for Perfectionist linting, providing rules
@@ -787,19 +845,27 @@ const perfectionistDefaults = {
787
845
  async function perfectionist(options) {
788
846
  const resolved = defu(options, perfectionistDefaults);
789
847
  const perfectionistPlugin = await importModule(import("eslint-plugin-perfectionist"));
790
- const safeType = resolved.settings?.type ?? "natural";
791
- const baseRules = perfectionistPlugin.configs[`recommended-${safeType}`]?.rules || {};
848
+ const files = [
849
+ jsGlob,
850
+ tsGlob,
851
+ vueGlob
852
+ ];
853
+ const safeType = resolved.type ?? "natural";
854
+ const presetConfig = perfectionistPlugin.configs[`recommended-${safeType}`];
855
+ const { rules = {} } = presetConfig;
792
856
  return [{
857
+ ...omit(presetConfig, [
858
+ "rules",
859
+ "settings",
860
+ "files",
861
+ "name"
862
+ ]),
793
863
  name: "favorodera/perfectionist/setup",
794
- plugins: { perfectionist: perfectionistPlugin },
795
- settings: { perfectionist: resolved.settings }
864
+ settings: { perfectionist: resolved }
796
865
  }, {
797
- files: resolved.files,
866
+ files,
798
867
  name: "favorodera/perfectionist/rules",
799
- rules: {
800
- ...baseRules,
801
- ...resolved.overrides
802
- }
868
+ rules
803
869
  }];
804
870
  }
805
871
  //#endregion
@@ -840,6 +906,15 @@ async function pnpm() {
840
906
  name: "favorodera/pnpm/pnpm-workspace-yaml",
841
907
  rules: {
842
908
  "pnpm/yaml-enforce-settings": ["error", { settings: {
909
+ allowBuilds: {
910
+ "@parcel/watcher": true,
911
+ "@tailwindcss/oxide": true,
912
+ "better-sqlite3": true,
913
+ "esbuild": true,
914
+ "sharp": true,
915
+ "unrs-resolver": true,
916
+ "vue-demi": true
917
+ },
843
918
  shellEmulator: true,
844
919
  trustPolicy: "no-downgrade"
845
920
  } }],
@@ -853,19 +928,12 @@ async function pnpm() {
853
928
  //#endregion
854
929
  //#region src/configs/stylistic.ts
855
930
  const stylisticDefaults = {
856
- files: [
857
- jsGlob,
858
- tsGlob,
859
- vueGlob
860
- ],
861
- settings: {
862
- braceStyle: "1tbs",
863
- experimental: false,
864
- indent: 2,
865
- jsx: false,
866
- quotes: "single",
867
- semi: false
868
- }
931
+ braceStyle: "1tbs",
932
+ experimental: false,
933
+ indent: 2,
934
+ jsx: false,
935
+ quotes: "single",
936
+ semi: false
869
937
  };
870
938
  /**
871
939
  * Constructs the flat config items for Stylistic linting, applying customized
@@ -876,18 +944,28 @@ const stylisticDefaults = {
876
944
  async function stylistic(options) {
877
945
  const resolved = defu(options, stylisticDefaults);
878
946
  const stylePlugin = await importModule(import("@stylistic/eslint-plugin"));
879
- const baseRules = stylePlugin.configs.customize({
947
+ const files = [
948
+ jsGlob,
949
+ tsGlob,
950
+ vueGlob
951
+ ];
952
+ const recommendedConfig = stylePlugin.configs.customize({
880
953
  pluginName: "style",
881
- ...resolved.settings
882
- })?.rules || {};
954
+ ...resolved
955
+ });
956
+ const { rules = {} } = recommendedConfig;
883
957
  return [{
884
- name: "favorodera/stylistic/setup",
885
- plugins: { style: stylePlugin }
958
+ ...omit(recommendedConfig, [
959
+ "rules",
960
+ "files",
961
+ "name"
962
+ ]),
963
+ name: "favorodera/stylistic/setup"
886
964
  }, {
887
- files: resolved.files,
965
+ files,
888
966
  name: "favorodera/stylistic/rules",
889
967
  rules: {
890
- ...baseRules,
968
+ ...rules,
891
969
  "style/array-bracket-newline": "error",
892
970
  "style/array-element-newline": "error",
893
971
  "style/curly-newline": ["error", "always"],
@@ -905,21 +983,13 @@ async function stylistic(options) {
905
983
  "style/object-curly-newline": "error",
906
984
  "style/semi-style": "error",
907
985
  "style/switch-colon-spacing": "error",
908
- "style/wrap-regex": "error",
909
- ...resolved.overrides
986
+ "style/wrap-regex": "error"
910
987
  }
911
988
  }];
912
989
  }
913
990
  //#endregion
914
991
  //#region src/configs/tailwind.ts
915
- const tailwindDefaults = {
916
- files: [
917
- jsGlob,
918
- tsGlob,
919
- vueGlob
920
- ],
921
- settings: { detectComponentClasses: true }
922
- };
992
+ const tailwindDefaults = { detectComponentClasses: true };
923
993
  /**
924
994
  * Constructs the flat config items for Tailwind CSS linting, providing custom settings
925
995
  * to parse and lint utility classes, and enforcing consistent ordering.
@@ -929,147 +999,152 @@ const tailwindDefaults = {
929
999
  async function tailwind(options) {
930
1000
  const resolved = defu(options, tailwindDefaults);
931
1001
  const tailwindPlugin = await importModule(import("eslint-plugin-better-tailwindcss"));
932
- const baseRules = {
933
- ...tailwindPlugin.configs["recommended-error"].rules,
934
- ...tailwindPlugin.configs["stylistic-error"].rules
1002
+ const files = [
1003
+ jsGlob,
1004
+ tsGlob,
1005
+ vueGlob
1006
+ ];
1007
+ const recommendedConfig = tailwindPlugin.configs["recommended-error"];
1008
+ const stylisticConfig = tailwindPlugin.configs["stylistic-error"];
1009
+ const { rules: recommendedRules } = recommendedConfig;
1010
+ const recommendedRest = omit(recommendedConfig, ["rules"]);
1011
+ const { rules: stylisticRules } = stylisticConfig;
1012
+ const stylisticRest = omit(stylisticConfig, ["rules"]);
1013
+ const rules = {
1014
+ ...recommendedRules,
1015
+ ...stylisticRules
935
1016
  };
936
- return [{
937
- name: "favorodera/tailwind/setup",
938
- plugins: { tailwind: tailwindPlugin },
939
- settings: { "better-tailwindcss": resolved.settings }
940
- }, {
941
- files: resolved.files,
942
- name: "favorodera/tailwind/rules",
943
- rules: {
944
- ...renamePluginsInRules(baseRules, { "better-tailwindcss": "tailwind" }),
945
- "tailwind/enforce-consistent-class-order": ["error", {
946
- componentClassOrder: "asc",
947
- componentClassPosition: "start",
948
- order: "strict",
949
- unknownClassOrder: "asc",
950
- unknownClassPosition: "start"
951
- }],
952
- "tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
953
- "tailwind/enforce-consistent-variant-order": "error",
954
- "tailwind/enforce-logical-properties": "error",
955
- "tailwind/enforce-consistent-important-position": "off",
956
- "tailwind/enforce-consistent-variable-syntax": "off",
957
- "tailwind/enforce-shorthand-classes": "off",
958
- ...resolved.overrides
1017
+ return [
1018
+ {
1019
+ ...recommendedRest,
1020
+ name: "favorodera/tailwind/recommended/setup"
1021
+ },
1022
+ {
1023
+ ...stylisticRest,
1024
+ name: "favorodera/tailwind/stylistic/setup"
1025
+ },
1026
+ {
1027
+ files,
1028
+ name: "favorodera/tailwind/rules",
1029
+ rules: {
1030
+ ...rules,
1031
+ "tailwind/enforce-consistent-class-order": ["error", {
1032
+ componentClassOrder: "asc",
1033
+ componentClassPosition: "start",
1034
+ order: "strict",
1035
+ unknownClassOrder: "asc",
1036
+ unknownClassPosition: "start"
1037
+ }],
1038
+ "tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
1039
+ "tailwind/enforce-consistent-variant-order": "error",
1040
+ "tailwind/enforce-logical-properties": "error"
1041
+ },
1042
+ settings: { "better-tailwindcss": resolved }
959
1043
  }
960
- }];
1044
+ ];
961
1045
  }
962
1046
  //#endregion
963
1047
  //#region src/configs/test.ts
964
- const testDefaults = { files: [testGlob] };
965
1048
  /**
966
1049
  * Constructs the flat config items for test linting, extending
967
1050
  * the recommended Vitest rule sets.
968
- * @param options Test configuration options.
969
1051
  * @returns Promise resolving to test ESLint config items.
970
1052
  */
971
- async function test(options) {
972
- const resolved = defu(options, testDefaults);
1053
+ async function test() {
973
1054
  const testPlugin = await importModule(import("@vitest/eslint-plugin"));
974
- const baseRules = extractRules(testPlugin.configs.recommended);
975
- return [
976
- {
977
- name: "favorodera/test/setup",
978
- plugins: { test: testPlugin }
979
- },
980
- {
981
- files: resolved.files,
982
- name: "favorodera/test/rules",
983
- rules: {
984
- ...renamePluginsInRules(baseRules, { vitest: "test" }),
985
- "test/consistent-each-for": ["error", {
986
- describe: "for",
987
- it: "for",
988
- suite: "for",
989
- test: "for"
990
- }],
991
- "test/consistent-test-it": ["error", {
992
- fn: "it",
993
- withinDescribe: "it"
994
- }],
995
- "test/consistent-vitest-vi": "error",
996
- "test/hoisted-apis-on-top": "error",
997
- "test/max-expects": "error",
998
- "test/max-nested-describe": "error",
999
- "test/no-alias-methods": "error",
1000
- "test/no-conditional-in-test": "error",
1001
- "test/no-conditional-tests": "error",
1002
- "test/no-duplicate-hooks": "error",
1003
- "test/no-hooks": "error",
1004
- "test/no-large-snapshots": "warn",
1005
- "test/no-test-prefixes": "error",
1006
- "test/no-test-return-statement": "error",
1007
- "test/padding-around-all": "error",
1008
- "test/prefer-called-times": "error",
1009
- "test/prefer-called-with": "error",
1010
- "test/prefer-comparison-matcher": "error",
1011
- "test/prefer-each": "error",
1012
- "test/prefer-equality-matcher": "error",
1013
- "test/prefer-expect-resolves": "error",
1014
- "test/prefer-expect-type-of": "error",
1015
- "test/prefer-hooks-in-order": "error",
1016
- "test/prefer-hooks-on-top": "error",
1017
- "test/prefer-import-in-mock": "error",
1018
- "test/prefer-importing-vitest-globals": "error",
1019
- "test/prefer-lowercase-title": "error",
1020
- "test/prefer-mock-promise-shorthand": "error",
1021
- "test/prefer-mock-return-shorthand": "error",
1022
- "test/prefer-snapshot-hint": "error",
1023
- "test/prefer-spy-on": "error",
1024
- "test/prefer-strict-boolean-matchers": "error",
1025
- "test/prefer-strict-equal": "error",
1026
- "test/prefer-to-be": "error",
1027
- "test/prefer-to-be-object": "error",
1028
- "test/prefer-to-contain": "error",
1029
- "test/prefer-to-have-been-called-times": "error",
1030
- "test/prefer-to-have-length": "error",
1031
- "test/prefer-todo": "error",
1032
- "test/prefer-vi-mocked": "error",
1033
- "test/require-awaited-expect-poll": "error",
1034
- "test/require-hook": "error",
1035
- "test/require-to-throw-message": "error",
1036
- "test/require-top-level-describe": "error",
1037
- "test/warn-todo": "warn",
1038
- ...resolved.overrides
1039
- }
1040
- },
1041
- {
1042
- files: resolved.files,
1043
- name: "favorodera/test/disables",
1044
- rules: { "no-unused-expressions": "off" }
1055
+ const files = [testGlob];
1056
+ const recommendedConfig = testPlugin.configs.recommended;
1057
+ const { rules } = recommendedConfig;
1058
+ return [{
1059
+ ...omit(recommendedConfig, ["rules", "name"]),
1060
+ name: "favorodera/test/setup"
1061
+ }, {
1062
+ files,
1063
+ name: "favorodera/test/rules",
1064
+ rules: {
1065
+ ...rules,
1066
+ "test/consistent-each-for": ["error", {
1067
+ describe: "for",
1068
+ it: "for",
1069
+ suite: "for",
1070
+ test: "for"
1071
+ }],
1072
+ "test/consistent-test-it": ["error", {
1073
+ fn: "it",
1074
+ withinDescribe: "it"
1075
+ }],
1076
+ "test/consistent-vitest-vi": "error",
1077
+ "test/hoisted-apis-on-top": "error",
1078
+ "test/max-expects": "error",
1079
+ "test/max-nested-describe": "error",
1080
+ "test/no-alias-methods": "error",
1081
+ "test/no-conditional-in-test": "error",
1082
+ "test/no-conditional-tests": "error",
1083
+ "test/no-duplicate-hooks": "error",
1084
+ "test/no-hooks": "error",
1085
+ "test/no-large-snapshots": "warn",
1086
+ "test/no-test-prefixes": "error",
1087
+ "test/no-test-return-statement": "error",
1088
+ "test/padding-around-all": "error",
1089
+ "test/prefer-called-times": "error",
1090
+ "test/prefer-called-with": "error",
1091
+ "test/prefer-comparison-matcher": "error",
1092
+ "test/prefer-each": "error",
1093
+ "test/prefer-equality-matcher": "error",
1094
+ "test/prefer-expect-resolves": "error",
1095
+ "test/prefer-expect-type-of": "error",
1096
+ "test/prefer-hooks-in-order": "error",
1097
+ "test/prefer-hooks-on-top": "error",
1098
+ "test/prefer-import-in-mock": "error",
1099
+ "test/prefer-importing-vitest-globals": "error",
1100
+ "test/prefer-lowercase-title": "error",
1101
+ "test/prefer-mock-promise-shorthand": "error",
1102
+ "test/prefer-mock-return-shorthand": "error",
1103
+ "test/prefer-snapshot-hint": "error",
1104
+ "test/prefer-spy-on": "error",
1105
+ "test/prefer-strict-boolean-matchers": "error",
1106
+ "test/prefer-strict-equal": "error",
1107
+ "test/prefer-to-be": "error",
1108
+ "test/prefer-to-be-object": "error",
1109
+ "test/prefer-to-contain": "error",
1110
+ "test/prefer-to-have-been-called-times": "error",
1111
+ "test/prefer-to-have-length": "error",
1112
+ "test/prefer-todo": "error",
1113
+ "test/prefer-vi-mocked": "error",
1114
+ "test/require-awaited-expect-poll": "error",
1115
+ "test/require-hook": "error",
1116
+ "test/require-to-throw-message": "error",
1117
+ "test/require-top-level-describe": "error",
1118
+ "test/warn-todo": "warn"
1045
1119
  }
1046
- ];
1120
+ }];
1047
1121
  }
1048
1122
  //#endregion
1049
1123
  //#region src/configs/typescript.ts
1050
- const typescriptDefaults = { files: [tsGlob] };
1051
1124
  /**
1052
1125
  * Constructs the flat config items for TypeScript linting, initializing the parser
1053
1126
  * and extending the recommended and strict type-aware rule sets.
1054
- * @param options TypeScript configuration options.
1055
1127
  * @returns Promise resolving to TypeScript ESLint config items.
1056
1128
  */
1057
- async function typescript(options) {
1058
- const resolved = defu(options, typescriptDefaults);
1129
+ async function typescript() {
1059
1130
  const tsEsLint = await importModule(import("typescript-eslint"));
1060
- const baseRules = extractRules(tsEsLint.configs.strict, tsEsLint.configs.stylistic);
1131
+ const files = [tsGlob];
1132
+ const [baseConfig, eslintRecommended, strictConfig] = tsEsLint.configs.strict;
1133
+ const stylisticConfig = tsEsLint.configs.stylistic[2];
1134
+ const baseRest = omit(baseConfig, ["rules", "name"]);
1135
+ const rules = {
1136
+ ...eslintRecommended?.rules,
1137
+ ...strictConfig?.rules,
1138
+ ...stylisticConfig?.rules
1139
+ };
1061
1140
  return [{
1062
- name: "favorodera/typescript/setup",
1063
- plugins: { ts: tsEsLint.plugin }
1141
+ ...baseRest,
1142
+ name: "favorodera/typescript/setup"
1064
1143
  }, {
1065
- files: resolved.files,
1066
- languageOptions: {
1067
- parser: tsEsLint.parser,
1068
- parserOptions: { sourceType: "module" }
1069
- },
1144
+ files,
1070
1145
  name: "favorodera/typescript/rules",
1071
1146
  rules: {
1072
- ...renamePluginsInRules(baseRules, { "@typescript-eslint": "ts" }),
1147
+ ...rules,
1073
1148
  "ts/array-type": ["error", {
1074
1149
  default: "generic",
1075
1150
  readonly: "generic"
@@ -1079,88 +1154,68 @@ async function typescript(options) {
1079
1154
  "ts/method-signature-style": "error",
1080
1155
  "ts/no-import-type-side-effects": "error",
1081
1156
  "ts/no-loop-func": "error",
1082
- "ts/no-redeclare": "error",
1083
- ...resolved.overrides
1157
+ "ts/no-redeclare": "error"
1084
1158
  }
1085
1159
  }];
1086
1160
  }
1087
1161
  //#endregion
1088
1162
  //#region src/configs/unicorn.ts
1089
- const unicornDefaults = { files: [
1090
- jsGlob,
1091
- tsGlob,
1092
- vueGlob
1093
- ] };
1094
1163
  /**
1095
1164
  * Constructs the flat config items for Unicorn linting, providing a collection of
1096
1165
  * awesome ESLint rules to improve code quality and enforce best practices.
1097
- * @param options Unicorn configuration options.
1098
1166
  * @returns Promise resolving to Unicorn ESLint config items.
1099
1167
  */
1100
- async function unicorn(options) {
1101
- const resolved = defu(options, unicornDefaults);
1168
+ async function unicorn() {
1102
1169
  const unicornPlugin = await importModule(import("eslint-plugin-unicorn"));
1103
- const baseRules = unicornPlugin.configs.recommended?.rules || {};
1170
+ const files = [
1171
+ jsGlob,
1172
+ tsGlob,
1173
+ vueGlob
1174
+ ];
1175
+ const recommendedConfig = unicornPlugin.configs.recommended;
1176
+ const { rules = {} } = recommendedConfig;
1104
1177
  return [{
1105
- name: "favorodera/unicorn/setup",
1106
- plugins: { unicorn: unicornPlugin }
1178
+ ...omit(recommendedConfig, [
1179
+ "rules",
1180
+ "files",
1181
+ "name"
1182
+ ]),
1183
+ name: "favorodera/unicorn/setup"
1107
1184
  }, {
1108
- files: resolved.files,
1109
- languageOptions: { globals: globals.builtin },
1185
+ files,
1110
1186
  name: "favorodera/unicorn/rules",
1111
- rules: {
1112
- ...baseRules,
1113
- "unicorn/filename-case": "off",
1114
- "unicorn/no-process-exit": "off",
1115
- "unicorn/prevent-abbreviations": "off",
1116
- ...resolved.overrides
1117
- }
1187
+ rules
1118
1188
  }];
1119
1189
  }
1120
1190
  //#endregion
1121
1191
  //#region src/configs/unused-imports.ts
1122
- const unusedImportsDefaults = { files: [
1123
- jsGlob,
1124
- tsGlob,
1125
- vueGlob
1126
- ] };
1127
1192
  /**
1128
1193
  * Constructs the flat config items for unused imports linting, providing plugin setup and
1129
1194
  * specific rules to detect and remove unused imports and variables.
1130
- * @param options Configuration options for unused imports linting.
1131
1195
  * @returns Promise resolving to unused imports ESLint config items.
1132
1196
  */
1133
- async function unusedImports(options) {
1134
- const resolved = defu(options, unusedImportsDefaults);
1135
- return [
1136
- {
1137
- name: "favorodera/unused-imports/setup",
1138
- plugins: { "unused-imports": await importModule(import("eslint-plugin-unused-imports")) }
1139
- },
1140
- {
1141
- files: resolved.files,
1142
- name: "favorodera/unused-imports/rules",
1143
- rules: {
1144
- "unused-imports/no-unused-imports": "error",
1145
- "unused-imports/no-unused-vars": ["error", {
1146
- args: "after-used",
1147
- argsIgnorePattern: "^_",
1148
- ignoreRestSiblings: true,
1149
- vars: "all",
1150
- varsIgnorePattern: "^_"
1151
- }],
1152
- ...resolved.overrides
1153
- }
1154
- },
1155
- {
1156
- files: resolved.files,
1157
- name: "favorodera/unused-imports/disables",
1158
- rules: {
1159
- "no-unused-vars": "off",
1160
- "ts/no-unused-vars": "off"
1161
- }
1197
+ async function unusedImports() {
1198
+ return [{
1199
+ name: "favorodera/unused-imports/setup",
1200
+ plugins: { "unused-imports": await importModule(import("eslint-plugin-unused-imports")) }
1201
+ }, {
1202
+ files: [
1203
+ jsGlob,
1204
+ tsGlob,
1205
+ vueGlob
1206
+ ],
1207
+ name: "favorodera/unused-imports/rules",
1208
+ rules: {
1209
+ "unused-imports/no-unused-imports": "error",
1210
+ "unused-imports/no-unused-vars": ["error", {
1211
+ args: "after-used",
1212
+ argsIgnorePattern: "^_",
1213
+ ignoreRestSiblings: true,
1214
+ vars: "all",
1215
+ varsIgnorePattern: "^_"
1216
+ }]
1162
1217
  }
1163
- ];
1218
+ }];
1164
1219
  }
1165
1220
  //#endregion
1166
1221
  //#region src/configs/vue.ts
@@ -1169,167 +1224,195 @@ const sfcBlocksDefaults = { blocks: {
1169
1224
  styles: true,
1170
1225
  template: false
1171
1226
  } };
1172
- const vueDefaults = {
1173
- files: [vueGlob],
1174
- sfcBlocks: sfcBlocksDefaults
1175
- };
1227
+ const vueDefaults = { sfcBlocks: sfcBlocksDefaults };
1176
1228
  /**
1177
- * Constructs the flat config items for Vue linting, setting up the custom template parser,
1229
+ * Constructs the flat config items for Vue and accessibility linting, setting up the custom template parser,
1178
1230
  * Vue block processors, and rules to enforce recommended component syntax.
1179
1231
  * @param options Vue configuration options.
1180
1232
  * @returns Promise resolving to Vue ESLint config items.
1181
1233
  */
1182
1234
  async function vue(options) {
1183
- const resolved = defu(options, vueDefaults);
1184
- const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
1185
- const [vuePlugin, vueParser, tsEsLint] = await Promise.all([
1235
+ const sfcBlocks = resolveOptions(defu(options, vueDefaults).sfcBlocks, sfcBlocksDefaults);
1236
+ const [vuePlugin, vueParser, tsEsLint, a11yPlugin] = await Promise.all([
1186
1237
  importModule(import("eslint-plugin-vue")),
1187
1238
  importModule(import("vue-eslint-parser")),
1188
- importModule(import("typescript-eslint"))
1239
+ importModule(import("typescript-eslint")),
1240
+ importModule(import("eslint-plugin-vuejs-accessibility"))
1241
+ ]);
1242
+ const vueRecommendedConfig = vuePlugin.configs["flat/recommended-error"];
1243
+ const a11yRecommendedConfig = a11yPlugin.configs["flat/recommended"];
1244
+ const [vueBase] = vueRecommendedConfig;
1245
+ const vueBaseRest = omit(vueBase, [
1246
+ "rules",
1247
+ "files",
1248
+ "name"
1189
1249
  ]);
1190
- const baseRules = extractRules(vuePlugin.configs["flat/recommended-error"]);
1250
+ const vueRules = extractRules(vueRecommendedConfig);
1251
+ const [a11yBase] = a11yRecommendedConfig;
1252
+ const a11yBaseRest = omit(a11yBase, ["name"]);
1253
+ const a11yRules = extractRules(a11yRecommendedConfig);
1191
1254
  const processor = sfcBlocks === false ? vuePlugin.processors[".vue"] : mergeProcessors([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]);
1192
- return [{
1193
- languageOptions: { globals: {
1194
- computed: "readonly",
1195
- defineEmits: "readonly",
1196
- defineExpose: "readonly",
1197
- defineProps: "readonly",
1198
- onMounted: "readonly",
1199
- onUnmounted: "readonly",
1200
- reactive: "readonly",
1201
- ref: "readonly",
1202
- shallowReactive: "readonly",
1203
- shallowRef: "readonly",
1204
- toRef: "readonly",
1205
- toRefs: "readonly",
1206
- watch: "readonly",
1207
- watchEffect: "readonly"
1208
- } },
1209
- name: "favorodera/vue/setup",
1210
- plugins: { vue: vuePlugin }
1211
- }, {
1212
- files: resolved.files,
1213
- languageOptions: {
1214
- parser: vueParser,
1215
- parserOptions: {
1216
- extraFileExtensions: [".vue"],
1217
- parser: tsEsLint.parser,
1218
- sourceType: "module"
1219
- }
1255
+ return [
1256
+ {
1257
+ ...vueBaseRest,
1258
+ languageOptions: { globals: {
1259
+ computed: "readonly",
1260
+ defineEmits: "readonly",
1261
+ defineExpose: "readonly",
1262
+ defineProps: "readonly",
1263
+ onMounted: "readonly",
1264
+ onUnmounted: "readonly",
1265
+ reactive: "readonly",
1266
+ ref: "readonly",
1267
+ shallowReactive: "readonly",
1268
+ shallowRef: "readonly",
1269
+ toRef: "readonly",
1270
+ toRefs: "readonly",
1271
+ watch: "readonly",
1272
+ watchEffect: "readonly"
1273
+ } },
1274
+ name: "favorodera/vue/setup"
1220
1275
  },
1221
- name: "favorodera/vue/rules",
1222
- processor,
1223
- rules: {
1224
- ...baseRules,
1225
- "vue/block-lang": ["error", { script: { lang: "ts" } }],
1226
- "vue/block-order": ["error", { order: [
1227
- "script",
1228
- "template",
1229
- "style"
1230
- ] }],
1231
- "vue/block-tag-newline": ["error", {
1232
- multiline: "always",
1233
- singleline: "always"
1234
- }],
1235
- "vue/comment-directive": ["error", { reportUnusedDisableDirectives: true }],
1236
- "vue/define-macros-order": ["error", {
1237
- defineExposeLast: true,
1238
- order: [
1239
- "defineOptions",
1240
- "definePage",
1241
- "defineSlots",
1242
- "defineEmits",
1243
- "defineProps",
1244
- "defineModel"
1245
- ]
1246
- }],
1247
- "vue/define-props-declaration": ["error", "type-based"],
1248
- "vue/define-props-destructuring": ["error", { destructure: "never" }],
1249
- "vue/multi-word-component-names": "off",
1250
- "vue/next-tick-style": ["error", "promise"],
1251
- "vue/no-import-compiler-macros": "error",
1252
- "vue/no-negated-v-if-condition": "error",
1253
- "vue/no-reserved-component-names": ["error", {
1254
- disallowVue3BuiltInComponents: true,
1255
- disallowVueBuiltInComponents: true,
1256
- htmlElementCaseSensitive: false
1257
- }],
1258
- "vue/no-root-v-if": "error",
1259
- "vue/no-template-target-blank": "error",
1260
- "vue/no-unused-emit-declarations": "error",
1261
- "vue/no-unused-properties": "error",
1262
- "vue/no-unused-refs": "error",
1263
- "vue/no-use-v-else-with-v-for": "error",
1264
- "vue/no-useless-mustaches": "error",
1265
- "vue/no-useless-v-bind": "error",
1266
- "vue/padding-line-between-blocks": "error",
1267
- "vue/padding-line-between-tags": ["error", [
1268
- {
1269
- blankLine: "always",
1270
- next: "*:multi-line",
1271
- prev: "*:single-line"
1272
- },
1273
- {
1274
- blankLine: "always",
1275
- next: "*:single-line",
1276
- prev: "*:multi-line"
1277
- },
1278
- {
1279
- blankLine: "always",
1280
- next: "*:multi-line",
1281
- prev: "*:multi-line"
1282
- },
1283
- {
1284
- blankLine: "never",
1285
- next: "*:single-line",
1286
- prev: "*:single-line"
1276
+ {
1277
+ ...a11yBaseRest,
1278
+ name: "favorodera/vue/a11y/setup"
1279
+ },
1280
+ {
1281
+ files: [vueGlob],
1282
+ languageOptions: {
1283
+ parser: vueParser,
1284
+ parserOptions: {
1285
+ extraFileExtensions: [".vue"],
1286
+ parser: tsEsLint.parser,
1287
+ sourceType: "module"
1287
1288
  }
1288
- ]],
1289
- "vue/prefer-prop-type-boolean-first": "error",
1290
- "vue/prefer-separate-static-class": "error",
1291
- "vue/prefer-single-event-payload": "error",
1292
- "vue/prefer-use-template-ref": "error",
1293
- "vue/slot-name-casing": ["error", "kebab-case"],
1294
- "vue/v-for-delimiter-style": ["error", "in"],
1295
- ...resolved.overrides
1289
+ },
1290
+ name: "favorodera/vue/rules",
1291
+ processor,
1292
+ rules: {
1293
+ ...vueRules,
1294
+ "vue/block-lang": ["error", { script: { lang: "ts" } }],
1295
+ "vue/block-order": ["error", { order: [
1296
+ "script",
1297
+ "template",
1298
+ "style"
1299
+ ] }],
1300
+ "vue/block-tag-newline": ["error", {
1301
+ multiline: "always",
1302
+ singleline: "always"
1303
+ }],
1304
+ "vue/comment-directive": ["error", { reportUnusedDisableDirectives: true }],
1305
+ "vue/define-macros-order": ["error", {
1306
+ defineExposeLast: true,
1307
+ order: [
1308
+ "defineOptions",
1309
+ "definePage",
1310
+ "defineSlots",
1311
+ "defineEmits",
1312
+ "defineProps",
1313
+ "defineModel"
1314
+ ]
1315
+ }],
1316
+ "vue/define-props-declaration": ["error", "type-based"],
1317
+ "vue/define-props-destructuring": ["error", { destructure: "never" }],
1318
+ "vue/next-tick-style": ["error", "promise"],
1319
+ "vue/no-import-compiler-macros": "error",
1320
+ "vue/no-negated-v-if-condition": "error",
1321
+ "vue/no-reserved-component-names": ["error", {
1322
+ disallowVue3BuiltInComponents: true,
1323
+ disallowVueBuiltInComponents: true,
1324
+ htmlElementCaseSensitive: false
1325
+ }],
1326
+ "vue/no-root-v-if": "error",
1327
+ "vue/no-template-target-blank": "error",
1328
+ "vue/no-unused-emit-declarations": "error",
1329
+ "vue/no-unused-properties": "error",
1330
+ "vue/no-unused-refs": "error",
1331
+ "vue/no-use-v-else-with-v-for": "error",
1332
+ "vue/no-useless-mustaches": "error",
1333
+ "vue/no-useless-v-bind": "error",
1334
+ "vue/padding-line-between-blocks": "error",
1335
+ "vue/padding-line-between-tags": ["error", [
1336
+ {
1337
+ blankLine: "always",
1338
+ next: "*:multi-line",
1339
+ prev: "*:single-line"
1340
+ },
1341
+ {
1342
+ blankLine: "always",
1343
+ next: "*:single-line",
1344
+ prev: "*:multi-line"
1345
+ },
1346
+ {
1347
+ blankLine: "always",
1348
+ next: "*:multi-line",
1349
+ prev: "*:multi-line"
1350
+ },
1351
+ {
1352
+ blankLine: "never",
1353
+ next: "*:single-line",
1354
+ prev: "*:single-line"
1355
+ }
1356
+ ]],
1357
+ "vue/prefer-prop-type-boolean-first": "error",
1358
+ "vue/prefer-separate-static-class": "error",
1359
+ "vue/prefer-single-event-payload": "error",
1360
+ "vue/prefer-use-template-ref": "error",
1361
+ "vue/slot-name-casing": ["error", "kebab-case"],
1362
+ "vue/v-for-delimiter-style": ["error", "in"]
1363
+ }
1364
+ },
1365
+ {
1366
+ files: [vueGlob],
1367
+ name: "favorodera/vue/a11y/rules",
1368
+ rules: {
1369
+ ...a11yRules,
1370
+ "vue-a11y/no-aria-hidden-on-focusable": "error",
1371
+ "vue-a11y/no-onchange": "error",
1372
+ "vue-a11y/no-role-presentation-on-focusable": "error"
1373
+ }
1296
1374
  }
1297
- }];
1375
+ ];
1298
1376
  }
1299
1377
  //#endregion
1300
1378
  //#region src/configs/yaml.ts
1301
- const yamlDefaults = { files: [yamlGlob] };
1302
1379
  /**
1303
1380
  * Constructs the flat config items for YAML linting, setting up
1304
1381
  * the custom parser and rule validations.
1305
- * @param options YAML configuration options.
1306
1382
  * @returns Promise resolving to YAML ESLint config items.
1307
1383
  */
1308
- async function yaml(options) {
1309
- const resolved = defu(options, yamlDefaults);
1384
+ async function yaml() {
1310
1385
  const [yamlPlugin, yamlParser] = await Promise.all([importModule(import("eslint-plugin-yml")), importModule(import("yaml-eslint-parser"))]);
1311
- const baseRules = extractRules(yamlPlugin.configs.standard);
1386
+ const standardConfig = yamlPlugin.configs.standard;
1387
+ const [pluginConfig] = standardConfig;
1388
+ const pluginRest = omit(pluginConfig, [
1389
+ "rules",
1390
+ "files",
1391
+ "name"
1392
+ ]);
1393
+ const rules = extractRules(standardConfig);
1312
1394
  return [
1313
1395
  {
1314
- name: "favorodera/yaml/setup",
1315
- plugins: { yaml: yamlPlugin }
1396
+ ...pluginRest,
1397
+ name: "favorodera/yaml/setup"
1316
1398
  },
1317
1399
  {
1318
- files: resolved.files,
1400
+ files: [yamlGlob],
1401
+ language: "yaml/yaml",
1319
1402
  languageOptions: { parser: yamlParser },
1320
1403
  name: "favorodera/yaml/rules",
1321
1404
  rules: {
1322
- ...renamePluginsInRules(baseRules, { yml: "yaml" }),
1405
+ ...rules,
1323
1406
  "yaml/quotes": ["error", {
1324
1407
  avoidEscape: true,
1325
1408
  prefer: "single"
1326
1409
  }],
1327
- "yaml/require-string-key": "error",
1328
- ...resolved.overrides
1410
+ "yaml/require-string-key": "error"
1329
1411
  }
1330
1412
  },
1331
1413
  {
1332
1414
  files: [pnpmWorkspaceGlob],
1415
+ language: "yaml/yaml",
1333
1416
  languageOptions: { parser: yamlParser },
1334
1417
  name: "favorodera/yaml/sort/pnpm-workspace-yaml",
1335
1418
  rules: { "yaml/sort-keys": [
@@ -1437,16 +1520,17 @@ function factory(options = {}) {
1437
1520
  if (resolved) configs.push(configFunction(resolved));
1438
1521
  }
1439
1522
  let composer = new FlatConfigComposer();
1440
- composer = composer.append(...configs).renamePlugins({
1523
+ composer = composer.append(...configs).append(...disables()).renamePlugins({
1441
1524
  "@typescript-eslint": "ts",
1442
1525
  "better-tailwindcss": "tailwind",
1443
1526
  "import-lite": "import",
1444
1527
  "markdown": "md",
1445
1528
  "n": "node",
1446
1529
  "vitest": "test",
1530
+ "vuejs-accessibility": "vue-a11y",
1447
1531
  "yml": "yaml"
1448
1532
  });
1449
1533
  return composer;
1450
1534
  }
1451
1535
  //#endregion
1452
- export { codeInMdGlob, extractRules, factory, ignoresGlob, importModule, jsGlob, json5Glob, jsonGlob, jsoncGlob, mdGlob, mdInMdGlob, packageJsonGlob, pnpmWorkspaceGlob, scriptsGlob, testGlob, tsConfigGlob, tsGlob, vueGlob, yamlGlob };
1536
+ export { codeInMdGlob, extractRules, factory, ignoresGlob, importModule, jsGlob, json5Glob, jsonGlob, jsoncGlob, mdGlob, mdInMdGlob, omit, packageJsonGlob, pnpmWorkspaceGlob, scriptsGlob, testGlob, tsConfigGlob, tsGlob, vueGlob, yamlGlob };