@favorodera/eslint-config 0.0.2 → 0.0.4

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
@@ -4,17 +4,31 @@ import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
4
4
  import vueBlocksProcessor from "eslint-processor-vue-blocks";
5
5
  import globals from "globals";
6
6
  //#region src/globs.ts
7
- /** Glob pattern for JavaScript linting */
7
+ /** Glob pattern for matching JavaScript files */
8
8
  const jsGlob = "**/*.{js,cjs,mjs}";
9
- /** Glob pattern for TypeScript linting */
9
+ /** Glob pattern for matching TypeScript files */
10
10
  const tsGlob = "**/*.{ts,cts,mts}";
11
- /** Glob pattern for Vue linting */
11
+ /** Glob pattern for matching Vue single-file components */
12
12
  const vueGlob = "**/*.vue";
13
- /** Glob pattern for Markdown linting */
13
+ /** Glob pattern for matching Markdown files */
14
14
  const mdGlob = "**/*.md";
15
+ /** Glob pattern for matching virtual files extracted from Markdown */
16
+ const mdInMdGlob = "**/*.md/*.md";
17
+ /** Glob pattern for matching code blocks embedded in Markdown files */
18
+ const codeInMdGlob = "**/*.md/**/*.{js,cjs,mjs,ts,cts,mts,vue}";
19
+ /** Glob pattern for matching JSON files */
20
+ const jsonGlob = "**/*.json";
21
+ /** Glob pattern for matching JSON5 files */
22
+ const json5Glob = "**/*.json5";
23
+ /** Glob pattern for matching JSON with Comments files */
24
+ const jsoncGlob = "**/*.jsonc";
25
+ /** Glob patterns for matching TypeScript configuration files */
26
+ const tsConfigGlob = ["**/tsconfig.json", "**/tsconfig.*.json"];
27
+ /** Glob pattern for matching package.json files */
28
+ const packageJsonGlob = "**/package.json";
15
29
  /**
16
- * Default glob patterns for files and directories to ignore
17
- * Includes common build outputs, dependencies, caches, and temporary files
30
+ * Common glob patterns for files and directories that should be ignored by ESLint.
31
+ * Includes node_modules, build outputs, lock files, temporary files, and tool-specific caches.
18
32
  */
19
33
  const ignoresGlob = [
20
34
  "**/node_modules/**",
@@ -61,9 +75,9 @@ const ignoresGlob = [
61
75
  *
62
76
  * Handles both ESM modules (which wrap exports under `.default`) and
63
77
  * CJS / plain-object modules uniformly.
64
- *
65
- * @param module - A module or a promise that resolves to one
66
- * @returns The `.default` export if it exists, otherwise the module itself
78
+ * @template TModule The type of the module being imported.
79
+ * @param module A module or a promise that resolves to one.
80
+ * @returns The `.default` export if it exists, otherwise the module itself.
67
81
  */
68
82
  async function importModule(module) {
69
83
  const resolved = await module;
@@ -73,15 +87,23 @@ async function importModule(module) {
73
87
  /**
74
88
  * Normalize boolean or options value into merged options or null.
75
89
  * Returns null when the input is false or undefined.
76
- *
77
- * @param value - boolean, options object, or undefined
78
- * @param defaults - defaults to merge with
79
- * @returns merged options or false
90
+ * @template TOptions The type of the options object.
91
+ * @param value The configuration value, which can be a boolean, an options object, or undefined.
92
+ * @param defaults The default options to merge with if `value` is true or an object.
93
+ * @returns The merged options object, or false if the feature is disabled.
80
94
  */
81
95
  function resolveOptions(value, defaults) {
82
96
  if (!value) return false;
83
97
  return defu(value === true ? {} : value, defaults);
84
98
  }
99
+ /**
100
+ * Extracts and merges the rules from multiple ESLint configuration arrays.
101
+ * @param configArrays Rest parameter representing multiple arrays of ESLint flat config items.
102
+ * @returns A single object containing all the merged rules from the provided configurations.
103
+ */
104
+ function extractRules(...configArrays) {
105
+ return Object.assign({}, ...configArrays.flat().map((config) => config?.rules || {}));
106
+ }
85
107
  //#endregion
86
108
  //#region src/configs/vue.ts
87
109
  const sfcBlocksDefaults = { blocks: {
@@ -93,6 +115,12 @@ const vueDefaults = {
93
115
  files: [vueGlob],
94
116
  sfcBlocks: sfcBlocksDefaults
95
117
  };
118
+ /**
119
+ * Constructs the flat config items for Vue linting, setting up the custom template parser,
120
+ * Vue block processors, and rules to enforce recommended component syntax.
121
+ * @param options Vue configuration options.
122
+ * @returns Promise resolving to Vue ESLint config items.
123
+ */
96
124
  async function vue(options) {
97
125
  const resolved = defu(options, vueDefaults);
98
126
  const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
@@ -101,32 +129,31 @@ async function vue(options) {
101
129
  importModule(import("vue-eslint-parser")),
102
130
  importModule(import("typescript-eslint"))
103
131
  ]);
104
- const inheritedRules = Object.assign({}, ...[
105
- ...vuePlugin.configs["flat/essential"],
106
- ...vuePlugin.configs["flat/strongly-recommended"],
107
- ...vuePlugin.configs["flat/recommended"]
108
- ].map((config) => config?.rules || {}));
132
+ const baseRules = extractRules(vuePlugin.configs["flat/essential"], vuePlugin.configs["flat/strongly-recommended"], vuePlugin.configs["flat/recommended"]);
133
+ const processor = sfcBlocks === false ? vuePlugin.processors[".vue"] : mergeProcessors([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]);
109
134
  return [{
110
- name: "favorodera/vue",
135
+ name: "favorodera/vue/setup",
111
136
  plugins: { vue: vuePlugin },
137
+ languageOptions: { globals: {
138
+ computed: "readonly",
139
+ defineEmits: "readonly",
140
+ defineExpose: "readonly",
141
+ defineProps: "readonly",
142
+ onMounted: "readonly",
143
+ onUnmounted: "readonly",
144
+ reactive: "readonly",
145
+ ref: "readonly",
146
+ shallowReactive: "readonly",
147
+ shallowRef: "readonly",
148
+ toRef: "readonly",
149
+ toRefs: "readonly",
150
+ watch: "readonly",
151
+ watchEffect: "readonly"
152
+ } }
153
+ }, {
154
+ name: "favorodera/vue/rules",
112
155
  files: resolved.files,
113
156
  languageOptions: {
114
- globals: {
115
- computed: "readonly",
116
- defineEmits: "readonly",
117
- defineExpose: "readonly",
118
- defineProps: "readonly",
119
- onMounted: "readonly",
120
- onUnmounted: "readonly",
121
- reactive: "readonly",
122
- ref: "readonly",
123
- shallowReactive: "readonly",
124
- shallowRef: "readonly",
125
- toRef: "readonly",
126
- toRefs: "readonly",
127
- watch: "readonly",
128
- watchEffect: "readonly"
129
- },
130
157
  parser: vueParser,
131
158
  parserOptions: {
132
159
  parser: tsEsLint.parser,
@@ -134,9 +161,9 @@ async function vue(options) {
134
161
  sourceType: "module"
135
162
  }
136
163
  },
137
- processor: sfcBlocks === false ? vuePlugin.processors[".vue"] : mergeProcessors([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]),
164
+ processor,
138
165
  rules: {
139
- ...inheritedRules,
166
+ ...baseRules,
140
167
  "vue/block-order": ["error", { order: [
141
168
  "script",
142
169
  "template",
@@ -162,7 +189,7 @@ async function vue(options) {
162
189
  const defaultPatterns = ignoresGlob;
163
190
  /**
164
191
  * Globs for ignoring files and directories from ESLint scanning.
165
- * @param patterns - Additional ignore patterns or a function to modify the defaults.
192
+ * @param patterns Additional ignore patterns or a function to modify the defaults.
166
193
  * @returns An array containing the ignore flat config item.
167
194
  */
168
195
  function ignores(patterns = []) {
@@ -178,19 +205,27 @@ const importsDefaults = { files: [
178
205
  tsGlob,
179
206
  vueGlob
180
207
  ] };
208
+ /**
209
+ * Constructs the flat config items for imports linting, providing plugin setup and
210
+ * specific rules to enforce consistent import ordering and unused variable checks.
211
+ * @param options Configuration options for imports linting.
212
+ * @returns Promise resolving to imports ESLint config items.
213
+ */
181
214
  async function imports(options) {
182
215
  const resolved = defu(options, importsDefaults);
183
216
  const [importPlugin, unusedImportsPlugin] = await Promise.all([importModule(import("eslint-plugin-import-lite")), importModule(import("eslint-plugin-unused-imports"))]);
184
- const inheritedRules = importPlugin.configs.recommended?.rules || {};
217
+ const baseRules = importPlugin.configs.recommended?.rules || {};
185
218
  return [{
186
- name: "favorodera/imports",
187
- files: resolved.files,
219
+ name: "favorodera/imports/setup",
188
220
  plugins: {
189
221
  "import": importPlugin,
190
222
  "unused-imports": unusedImportsPlugin
191
- },
223
+ }
224
+ }, {
225
+ name: "favorodera/imports/rules",
226
+ files: resolved.files,
192
227
  rules: {
193
- ...renamePluginsInRules(inheritedRules, { "import-lite": "import" }),
228
+ ...renamePluginsInRules(baseRules, { "import-lite": "import" }),
194
229
  "import/consistent-type-specifier-style": ["error", "top-level"],
195
230
  "import/first": "error",
196
231
  "import/no-duplicates": "error",
@@ -217,16 +252,16 @@ const javascriptDefaults = { files: [
217
252
  vueGlob
218
253
  ] };
219
254
  /**
220
- * Javascript linting via `eslint`
221
- * @param options - Javascript configuration options
222
- * @returns Promise resolving to javascript ESLint config items
255
+ * Constructs the flat config items for core JavaScript linting, setting up the required
256
+ * language options, globals, and recommended baseline rules.
257
+ * @param options Javascript configuration options.
258
+ * @returns Promise resolving to javascript ESLint config items.
223
259
  */
224
260
  async function javascript(options) {
225
261
  const resolved = defu(options, javascriptDefaults);
226
- const inheritedRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
262
+ const baseRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
227
263
  return [{
228
- name: "favorodera/javascript",
229
- files: resolved.files,
264
+ name: "favorodera/javascript/setup",
230
265
  languageOptions: {
231
266
  ecmaVersion: "latest",
232
267
  sourceType: "module",
@@ -239,9 +274,12 @@ async function javascript(options) {
239
274
  window: "readonly"
240
275
  }
241
276
  },
242
- linterOptions: { reportUnusedDisableDirectives: true },
277
+ linterOptions: { reportUnusedDisableDirectives: true }
278
+ }, {
279
+ name: "favorodera/javascript/rules",
280
+ files: resolved.files,
243
281
  rules: {
244
- ...inheritedRules,
282
+ ...baseRules,
245
283
  "accessor-pairs": ["error", {
246
284
  enforceForClassMembers: true,
247
285
  setWithoutGet: true
@@ -258,23 +296,66 @@ const markdownDefaults = {
258
296
  files: [mdGlob],
259
297
  gfm: true
260
298
  };
299
+ /**
300
+ * Constructs the flat config items for Markdown linting, extracting and linting
301
+ * embedded code blocks within the document according to specified rules.
302
+ * @param options Markdown configuration options.
303
+ * @returns Promise resolving to Markdown ESLint config items.
304
+ */
261
305
  async function markdown(options) {
262
306
  const resolved = defu(options, markdownDefaults);
263
307
  const markdownPlugin = await importModule(import("@eslint/markdown"));
264
- const inheritedRules = Object.assign({}, ...[...markdownPlugin.configs.recommended].map((config) => config?.rules || {}));
265
- return [{
266
- name: "favorodera/markdown",
267
- files: resolved.files,
268
- plugins: { md: markdownPlugin },
269
- processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
270
- language: resolved.gfm ? "md/gfm" : "md/commonmark",
271
- rules: {
272
- ...renamePluginsInRules(inheritedRules, { markdown: "md" }),
273
- "md/fenced-code-language": "off",
274
- "md/no-missing-label-refs": "off",
275
- ...resolved.overrides
308
+ const baseRules = extractRules(markdownPlugin.configs.recommended);
309
+ return [
310
+ {
311
+ name: "favorodera/markdown/setup",
312
+ plugins: { md: markdownPlugin }
313
+ },
314
+ {
315
+ name: "favorodera/markdown/rules",
316
+ files: resolved.files,
317
+ language: resolved.gfm ? "md/gfm" : "md/commonmark",
318
+ ignores: [mdInMdGlob],
319
+ processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
320
+ rules: {
321
+ ...renamePluginsInRules(baseRules, { markdown: "md" }),
322
+ "md/fenced-code-language": "off",
323
+ "md/no-missing-label-refs": "off",
324
+ ...resolved.overrides
325
+ }
326
+ },
327
+ {
328
+ name: "favorodera/markdown/disables/code",
329
+ files: [codeInMdGlob],
330
+ languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
331
+ rules: {
332
+ "no-alert": "off",
333
+ "no-console": "off",
334
+ "no-labels": "off",
335
+ "no-lone-blocks": "off",
336
+ "no-restricted-syntax": "off",
337
+ "no-undef": "off",
338
+ "no-unused-expressions": "off",
339
+ "no-unused-labels": "off",
340
+ "no-unused-vars": "off",
341
+ "node/prefer-global/process": "off",
342
+ "style/comma-dangle": "off",
343
+ "style/eol-last": "off",
344
+ "style/padding-line-between-statements": "off",
345
+ "ts/consistent-type-imports": "off",
346
+ "ts/explicit-function-return-type": "off",
347
+ "ts/no-namespace": "off",
348
+ "ts/no-redeclare": "off",
349
+ "ts/no-require-imports": "off",
350
+ "ts/no-unused-expressions": "off",
351
+ "ts/no-unused-vars": "off",
352
+ "ts/no-use-before-define": "off",
353
+ "unicode-bom": "off",
354
+ "unused-imports/no-unused-imports": "off",
355
+ "unused-imports/no-unused-vars": "off"
356
+ }
276
357
  }
277
- }];
358
+ ];
278
359
  }
279
360
  //#endregion
280
361
  //#region src/configs/stylistic.ts
@@ -292,19 +373,27 @@ const stylisticDefaults = {
292
373
  vueGlob
293
374
  ]
294
375
  };
376
+ /**
377
+ * Constructs the flat config items for Stylistic linting, applying customized
378
+ * formatting settings such as quotes, indentation, and spacing.
379
+ * @param options Stylistic configuration options.
380
+ * @returns Promise resolving to stylistic ESLint config items.
381
+ */
295
382
  async function stylistic(options) {
296
383
  const resolved = defu(options, stylisticDefaults);
297
- const config = (await importModule(import("@stylistic/eslint-plugin"))).configs.customize({
384
+ const stylePlugin = await importModule(import("@stylistic/eslint-plugin"));
385
+ const baseRules = stylePlugin.configs.customize({
298
386
  pluginName: "style",
299
387
  ...resolved.settings
300
- });
301
- const inheritedRules = config?.rules || {};
388
+ })?.rules || {};
302
389
  return [{
303
- ...config,
304
- name: "favorodera/stylistic",
390
+ name: "favorodera/stylistic/setup",
391
+ plugins: { style: stylePlugin }
392
+ }, {
393
+ name: "favorodera/stylistic/rules",
305
394
  files: resolved.files,
306
395
  rules: {
307
- ...inheritedRules,
396
+ ...baseRules,
308
397
  "style/quotes": [
309
398
  "error",
310
399
  "single",
@@ -341,24 +430,27 @@ const tailwindDefaults = {
341
430
  settings: { detectComponentClasses: true }
342
431
  };
343
432
  /**
344
- * Tailwind linting via `eslint-plugin-better-tailwindcss`.
345
- * @param options - Tailwind configuration options
346
- * @returns Promise resolving to Tailwind ESLint config items
433
+ * Constructs the flat config items for Tailwind CSS linting, providing custom settings
434
+ * to parse and lint utility classes, and enforcing consistent ordering.
435
+ * @param options Tailwind configuration options.
436
+ * @returns Promise resolving to Tailwind ESLint config items.
347
437
  */
348
438
  async function tailwind(options) {
349
439
  const resolved = defu(options, tailwindDefaults);
350
440
  const tailwindPlugin = await importModule(import("eslint-plugin-better-tailwindcss"));
351
- const inheritedRules = {
441
+ const baseRules = {
352
442
  ...tailwindPlugin.configs["recommended-error"].rules,
353
443
  ...tailwindPlugin.configs["stylistic-error"].rules
354
444
  };
355
445
  return [{
356
- name: "favorodera/tailwind",
357
- files: resolved.files,
446
+ name: "favorodera/tailwind/setup",
358
447
  plugins: { tailwind: tailwindPlugin },
359
- settings: { tailwindcss: resolved.settings },
448
+ settings: { tailwindcss: resolved.settings }
449
+ }, {
450
+ name: "favorodera/tailwind/rules",
451
+ files: resolved.files,
360
452
  rules: {
361
- ...renamePluginsInRules(inheritedRules, { "better-tailwindcss": "tailwind" }),
453
+ ...renamePluginsInRules(baseRules, { "better-tailwindcss": "tailwind" }),
362
454
  "tailwind/no-unregistered-classes": "off",
363
455
  "tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
364
456
  ...resolved.overrides
@@ -369,27 +461,371 @@ async function tailwind(options) {
369
461
  //#region src/configs/typescript.ts
370
462
  const typescriptDefaults = { files: [tsGlob] };
371
463
  /**
372
- * Typescript linting via `typescript-eslint`.
373
- * @param options - TypeScript configuration options
374
- * @returns Array of TypeScript ESLint config items
464
+ * Constructs the flat config items for TypeScript linting, initializing the parser
465
+ * and extending the recommended and strict type-aware rule sets.
466
+ * @param options TypeScript configuration options.
467
+ * @returns Promise resolving to TypeScript ESLint config items.
375
468
  */
376
469
  async function typescript(options) {
377
470
  const resolved = defu(options, typescriptDefaults);
378
471
  const tsEsLint = await importModule(import("typescript-eslint"));
379
- const inheritedRules = Object.assign({}, ...[...tsEsLint.configs.recommended, ...tsEsLint.configs.strict].map((config) => config?.rules || {}));
472
+ const baseRules = extractRules(tsEsLint.configs.recommended, tsEsLint.configs.strict);
380
473
  return [{
381
- name: "favorodera/typescript",
382
- plugins: { ts: tsEsLint.plugin },
474
+ name: "favorodera/typescript/setup",
475
+ plugins: { ts: tsEsLint.plugin }
476
+ }, {
477
+ name: "favorodera/typescript/rules",
478
+ files: resolved.files,
383
479
  languageOptions: {
384
480
  parser: tsEsLint.parser,
385
481
  parserOptions: { sourceType: "module" }
386
482
  },
387
- files: resolved.files,
388
483
  rules: {
389
- ...renamePluginsInRules(inheritedRules, { "@typescript-eslint": "ts" }),
484
+ ...renamePluginsInRules(baseRules, { "@typescript-eslint": "ts" }),
390
485
  "ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
391
486
  "ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
392
- "ts/array-type": ["error", { default: "array" }],
487
+ "ts/array-type": ["error", {
488
+ default: "generic",
489
+ readonly: "generic"
490
+ }],
491
+ ...resolved.overrides
492
+ }
493
+ }];
494
+ }
495
+ //#endregion
496
+ //#region src/configs/jsonc.ts
497
+ const jsoncDefaults = { files: [
498
+ json5Glob,
499
+ jsoncGlob,
500
+ jsonGlob
501
+ ] };
502
+ /**
503
+ * Constructs the flat config items for JSON, JSON5, and JSONC linting, setting up
504
+ * the custom parser, rule validations, and sorting rules for package.json/tsconfig.json.
505
+ * @param options JSONC configuration options.
506
+ * @returns Promise resolving to JSONC ESLint config items.
507
+ */
508
+ async function jsonc(options) {
509
+ const resolved = defu(options, jsoncDefaults);
510
+ return [
511
+ {
512
+ name: "favorodera/jsonc/setup",
513
+ plugins: { jsonc: await importModule(import("eslint-plugin-jsonc")) }
514
+ },
515
+ {
516
+ name: "favorodera/jsonc/rules",
517
+ files: resolved.files,
518
+ language: "jsonc/x",
519
+ rules: {
520
+ "jsonc/no-bigint-literals": "error",
521
+ "jsonc/no-binary-expression": "error",
522
+ "jsonc/no-binary-numeric-literals": "error",
523
+ "jsonc/no-dupe-keys": "error",
524
+ "jsonc/no-escape-sequence-in-identifier": "error",
525
+ "jsonc/no-floating-decimal": "error",
526
+ "jsonc/no-hexadecimal-numeric-literals": "error",
527
+ "jsonc/no-infinity": "error",
528
+ "jsonc/no-multi-str": "error",
529
+ "jsonc/no-nan": "error",
530
+ "jsonc/no-number-props": "error",
531
+ "jsonc/no-numeric-separators": "error",
532
+ "jsonc/no-octal": "error",
533
+ "jsonc/no-octal-escape": "error",
534
+ "jsonc/no-octal-numeric-literals": "error",
535
+ "jsonc/no-parenthesized": "error",
536
+ "jsonc/no-plus-sign": "error",
537
+ "jsonc/no-regexp-literals": "error",
538
+ "jsonc/no-sparse-arrays": "error",
539
+ "jsonc/no-template-literals": "error",
540
+ "jsonc/no-undefined-value": "error",
541
+ "jsonc/no-unicode-codepoint-escapes": "error",
542
+ "jsonc/no-useless-escape": "error",
543
+ "jsonc/space-unary-ops": "error",
544
+ "jsonc/valid-json-number": "error",
545
+ "jsonc/vue-custom-block/no-parsing-error": "error",
546
+ "jsonc/array-bracket-spacing": ["error", "never"],
547
+ "jsonc/comma-dangle": ["error", "never"],
548
+ "jsonc/comma-style": ["error", "last"],
549
+ "jsonc/indent": ["error", 2],
550
+ "jsonc/key-spacing": ["error", {
551
+ afterColon: true,
552
+ beforeColon: false
553
+ }],
554
+ "jsonc/object-curly-newline": ["error", {
555
+ consistent: true,
556
+ multiline: true
557
+ }],
558
+ "jsonc/object-curly-spacing": ["error", "always"],
559
+ "jsonc/object-property-newline": ["error", { allowAllPropertiesOnSameLine: true }],
560
+ "jsonc/quote-props": "error",
561
+ "jsonc/quotes": "error",
562
+ ...resolved.overrides
563
+ }
564
+ },
565
+ {
566
+ name: "favorodera/jsonc/sort/package-json",
567
+ files: [packageJsonGlob],
568
+ rules: {
569
+ "jsonc/sort-array-values": ["error", {
570
+ order: { type: "asc" },
571
+ pathPattern: "^files$"
572
+ }],
573
+ "jsonc/sort-keys": [
574
+ "error",
575
+ {
576
+ order: [
577
+ "publisher",
578
+ "name",
579
+ "displayName",
580
+ "type",
581
+ "version",
582
+ "private",
583
+ "packageManager",
584
+ "description",
585
+ "author",
586
+ "contributors",
587
+ "license",
588
+ "funding",
589
+ "homepage",
590
+ "repository",
591
+ "bugs",
592
+ "keywords",
593
+ "categories",
594
+ "sideEffects",
595
+ "imports",
596
+ "exports",
597
+ "main",
598
+ "module",
599
+ "unpkg",
600
+ "jsdelivr",
601
+ "types",
602
+ "typesVersions",
603
+ "bin",
604
+ "icon",
605
+ "files",
606
+ "engines",
607
+ "activationEvents",
608
+ "contributes",
609
+ "scripts",
610
+ "peerDependencies",
611
+ "peerDependenciesMeta",
612
+ "dependencies",
613
+ "optionalDependencies",
614
+ "devDependencies",
615
+ "pnpm",
616
+ "overrides",
617
+ "resolutions",
618
+ "husky",
619
+ "simple-git-hooks",
620
+ "lint-staged",
621
+ "eslintConfig"
622
+ ],
623
+ pathPattern: "^$"
624
+ },
625
+ {
626
+ order: { type: "asc" },
627
+ pathPattern: "^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$"
628
+ },
629
+ {
630
+ order: { type: "asc" },
631
+ pathPattern: "^(?:resolutions|overrides|pnpm.overrides)$"
632
+ },
633
+ {
634
+ order: { type: "asc" },
635
+ pathPattern: "^workspaces\\.catalog$"
636
+ },
637
+ {
638
+ order: { type: "asc" },
639
+ pathPattern: "^workspaces\\.catalogs\\.[^.]+$"
640
+ },
641
+ {
642
+ order: [
643
+ "types",
644
+ "import",
645
+ "require",
646
+ "default"
647
+ ],
648
+ pathPattern: "^exports.*$"
649
+ },
650
+ {
651
+ order: [
652
+ "pre-commit",
653
+ "prepare-commit-msg",
654
+ "commit-msg",
655
+ "post-commit",
656
+ "pre-rebase",
657
+ "post-rewrite",
658
+ "post-checkout",
659
+ "post-merge",
660
+ "pre-push",
661
+ "pre-auto-gc"
662
+ ],
663
+ pathPattern: "^(?:gitHooks|husky|simple-git-hooks)$"
664
+ }
665
+ ]
666
+ }
667
+ },
668
+ {
669
+ name: "favorodera/jsonc/sort/tsconfig-json",
670
+ files: tsConfigGlob,
671
+ rules: { "jsonc/sort-keys": [
672
+ "error",
673
+ {
674
+ order: [
675
+ "extends",
676
+ "compilerOptions",
677
+ "references",
678
+ "files",
679
+ "include",
680
+ "exclude"
681
+ ],
682
+ pathPattern: "^$"
683
+ },
684
+ {
685
+ order: [
686
+ "incremental",
687
+ "composite",
688
+ "tsBuildInfoFile",
689
+ "disableSourceOfProjectReferenceRedirect",
690
+ "disableSolutionSearching",
691
+ "disableReferencedProjectLoad",
692
+ "target",
693
+ "jsx",
694
+ "jsxFactory",
695
+ "jsxFragmentFactory",
696
+ "jsxImportSource",
697
+ "lib",
698
+ "moduleDetection",
699
+ "noLib",
700
+ "reactNamespace",
701
+ "useDefineForClassFields",
702
+ "emitDecoratorMetadata",
703
+ "experimentalDecorators",
704
+ "libReplacement",
705
+ "baseUrl",
706
+ "rootDir",
707
+ "rootDirs",
708
+ "customConditions",
709
+ "module",
710
+ "moduleResolution",
711
+ "moduleSuffixes",
712
+ "noResolve",
713
+ "paths",
714
+ "resolveJsonModule",
715
+ "resolvePackageJsonExports",
716
+ "resolvePackageJsonImports",
717
+ "typeRoots",
718
+ "types",
719
+ "allowArbitraryExtensions",
720
+ "allowImportingTsExtensions",
721
+ "allowUmdGlobalAccess",
722
+ "allowJs",
723
+ "checkJs",
724
+ "maxNodeModuleJsDepth",
725
+ "strict",
726
+ "strictBindCallApply",
727
+ "strictFunctionTypes",
728
+ "strictNullChecks",
729
+ "strictPropertyInitialization",
730
+ "allowUnreachableCode",
731
+ "allowUnusedLabels",
732
+ "alwaysStrict",
733
+ "exactOptionalPropertyTypes",
734
+ "noFallthroughCasesInSwitch",
735
+ "noImplicitAny",
736
+ "noImplicitOverride",
737
+ "noImplicitReturns",
738
+ "noImplicitThis",
739
+ "noPropertyAccessFromIndexSignature",
740
+ "noUncheckedIndexedAccess",
741
+ "noUnusedLocals",
742
+ "noUnusedParameters",
743
+ "useUnknownInCatchVariables",
744
+ "declaration",
745
+ "declarationDir",
746
+ "declarationMap",
747
+ "downlevelIteration",
748
+ "emitBOM",
749
+ "emitDeclarationOnly",
750
+ "importHelpers",
751
+ "importsNotUsedAsValues",
752
+ "inlineSourceMap",
753
+ "inlineSources",
754
+ "mapRoot",
755
+ "newLine",
756
+ "noEmit",
757
+ "noEmitHelpers",
758
+ "noEmitOnError",
759
+ "outDir",
760
+ "outFile",
761
+ "preserveConstEnums",
762
+ "preserveValueImports",
763
+ "removeComments",
764
+ "sourceMap",
765
+ "sourceRoot",
766
+ "stripInternal",
767
+ "allowSyntheticDefaultImports",
768
+ "esModuleInterop",
769
+ "forceConsistentCasingInFileNames",
770
+ "isolatedDeclarations",
771
+ "isolatedModules",
772
+ "preserveSymlinks",
773
+ "verbatimModuleSyntax",
774
+ "erasableSyntaxOnly",
775
+ "skipDefaultLibCheck",
776
+ "skipLibCheck"
777
+ ],
778
+ pathPattern: "^compilerOptions$"
779
+ }
780
+ ] }
781
+ }
782
+ ];
783
+ }
784
+ //#endregion
785
+ //#region src/configs/jsdoc.ts
786
+ const jsdocDefaults = { files: [
787
+ jsGlob,
788
+ tsGlob,
789
+ vueGlob
790
+ ] };
791
+ /**
792
+ * Constructs the flat config items for JSDoc linting, ensuring comments follow
793
+ * proper styling, parameter checks, and types alignment.
794
+ * @param options JSDoc configuration options.
795
+ * @returns Promise resolving to JSDoc ESLint config items.
796
+ */
797
+ async function jsdoc(options) {
798
+ const resolved = defu(options, jsdocDefaults);
799
+ const jsdocPlugin = await importModule(import("eslint-plugin-jsdoc"));
800
+ const baseRules = {
801
+ ...jsdocPlugin.configs["flat/recommended-typescript-error"]?.rules,
802
+ ...jsdocPlugin.configs["flat/stylistic-typescript-error"]?.rules
803
+ };
804
+ return [{
805
+ name: "favorodera/jsdoc/setup",
806
+ plugins: { jsdoc: jsdocPlugin }
807
+ }, {
808
+ name: "favorodera/tailwind/rules",
809
+ files: resolved.files,
810
+ rules: {
811
+ ...baseRules || {},
812
+ "jsdoc/check-access": "warn",
813
+ "jsdoc/check-param-names": "warn",
814
+ "jsdoc/check-property-names": "warn",
815
+ "jsdoc/check-types": "warn",
816
+ "jsdoc/empty-tags": "warn",
817
+ "jsdoc/implements-on-classes": "warn",
818
+ "jsdoc/no-defaults": "warn",
819
+ "jsdoc/no-multi-asterisks": "warn",
820
+ "jsdoc/require-param-name": "warn",
821
+ "jsdoc/require-property": "warn",
822
+ "jsdoc/require-property-description": "warn",
823
+ "jsdoc/require-property-name": "warn",
824
+ "jsdoc/require-returns-check": "warn",
825
+ "jsdoc/require-returns-description": "warn",
826
+ "jsdoc/require-yields-check": "warn",
827
+ "jsdoc/check-alignment": "warn",
828
+ "jsdoc/multiline-blocks": "warn",
393
829
  ...resolved.overrides
394
830
  }
395
831
  }];
@@ -397,9 +833,10 @@ async function typescript(options) {
397
833
  //#endregion
398
834
  //#region src/factory.ts
399
835
  /**
400
- * Factory to create a flat ESLint config
401
- * @param options - Configuration options for the ESLint config
402
- * @returns Flat ESLint config composer
836
+ * Factory to create a flat ESLint config.
837
+ * It builds an ESLint config by sequentially adding sub-configs based on the provided options.
838
+ * @param options Configuration options for enabling/disabling or configuring specific rule sets.
839
+ * @returns A flat config composer instance that can be exported directly or further modified.
403
840
  */
404
841
  function factory(options = {}) {
405
842
  const configs = [];
@@ -411,7 +848,9 @@ function factory(options = {}) {
411
848
  tailwind,
412
849
  imports,
413
850
  markdown,
414
- javascript
851
+ javascript,
852
+ jsonc,
853
+ jsdoc
415
854
  };
416
855
  for (const [key, configFunction] of Object.entries(configFunctions)) {
417
856
  const configOption = options[key];