@favorodera/eslint-config 0.0.4 → 0.0.5

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.cjs CHANGED
@@ -23,11 +23,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  //#endregion
24
24
  let eslint_flat_config_utils = require("eslint-flat-config-utils");
25
25
  let defu = require("defu");
26
+ let globals = require("globals");
27
+ globals = __toESM(globals, 1);
26
28
  let eslint_merge_processors = require("eslint-merge-processors");
27
29
  let eslint_processor_vue_blocks = require("eslint-processor-vue-blocks");
28
30
  eslint_processor_vue_blocks = __toESM(eslint_processor_vue_blocks, 1);
29
- let globals = require("globals");
30
- globals = __toESM(globals, 1);
31
31
  //#region src/globs.ts
32
32
  /** Glob pattern for matching JavaScript files */
33
33
  const jsGlob = "**/*.{js,cjs,mjs}";
@@ -51,11 +51,9 @@ const jsoncGlob = "**/*.jsonc";
51
51
  const tsConfigGlob = ["**/tsconfig.json", "**/tsconfig.*.json"];
52
52
  /** Glob pattern for matching package.json files */
53
53
  const packageJsonGlob = "**/package.json";
54
- /**
55
- * Common glob patterns for files and directories that should be ignored by ESLint.
56
- * Includes node_modules, build outputs, lock files, temporary files, and tool-specific caches.
57
- */
58
- const ignoresGlob = [
54
+ //#endregion
55
+ //#region src/configs/ignores.ts
56
+ const defaultPatterns = [
59
57
  "**/node_modules/**",
60
58
  "**/dist/**",
61
59
  "**/package-lock.json",
@@ -92,9 +90,28 @@ const ignoresGlob = [
92
90
  "**/.agents",
93
91
  "**/.*/skills"
94
92
  ];
93
+ /**
94
+ * Globs for ignoring files and directories from ESLint scanning.
95
+ * @param patterns Additional ignore patterns or a function to modify the defaults.
96
+ * @returns An array containing the ignore flat config item.
97
+ */
98
+ function ignores(patterns = []) {
99
+ return [{
100
+ ignores: typeof patterns === "function" ? patterns(defaultPatterns) : [...defaultPatterns, ...patterns],
101
+ name: "favorodera/ignores"
102
+ }];
103
+ }
95
104
  //#endregion
96
105
  //#region src/utils.ts
97
106
  /**
107
+ * Extracts and merges the rules from multiple ESLint configuration arrays.
108
+ * @param configArrays Rest parameter representing multiple arrays of ESLint flat config items.
109
+ * @returns A single object containing all the merged rules from the provided configurations.
110
+ */
111
+ function extractRules(...configArrays) {
112
+ return Object.assign({}, ...configArrays.flat().map((config) => config?.rules || {}));
113
+ }
114
+ /**
98
115
  * Resolves a module (or a promise of one) and returns its default export
99
116
  * if present, otherwise returns the module itself.
100
117
  *
@@ -121,108 +138,6 @@ function resolveOptions(value, defaults) {
121
138
  if (!value) return false;
122
139
  return (0, defu.defu)(value === true ? {} : value, defaults);
123
140
  }
124
- /**
125
- * Extracts and merges the rules from multiple ESLint configuration arrays.
126
- * @param configArrays Rest parameter representing multiple arrays of ESLint flat config items.
127
- * @returns A single object containing all the merged rules from the provided configurations.
128
- */
129
- function extractRules(...configArrays) {
130
- return Object.assign({}, ...configArrays.flat().map((config) => config?.rules || {}));
131
- }
132
- //#endregion
133
- //#region src/configs/vue.ts
134
- const sfcBlocksDefaults = { blocks: {
135
- styles: true,
136
- customBlocks: true,
137
- template: false
138
- } };
139
- const vueDefaults = {
140
- files: [vueGlob],
141
- sfcBlocks: sfcBlocksDefaults
142
- };
143
- /**
144
- * Constructs the flat config items for Vue linting, setting up the custom template parser,
145
- * Vue block processors, and rules to enforce recommended component syntax.
146
- * @param options Vue configuration options.
147
- * @returns Promise resolving to Vue ESLint config items.
148
- */
149
- async function vue(options) {
150
- const resolved = (0, defu.defu)(options, vueDefaults);
151
- const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
152
- const [vuePlugin, vueParser, tsEsLint] = await Promise.all([
153
- importModule(import("eslint-plugin-vue")),
154
- importModule(import("vue-eslint-parser")),
155
- importModule(import("typescript-eslint"))
156
- ]);
157
- const baseRules = extractRules(vuePlugin.configs["flat/essential"], vuePlugin.configs["flat/strongly-recommended"], vuePlugin.configs["flat/recommended"]);
158
- const processor = sfcBlocks === false ? vuePlugin.processors[".vue"] : (0, eslint_merge_processors.mergeProcessors)([vuePlugin.processors[".vue"], (0, eslint_processor_vue_blocks.default)(sfcBlocks)]);
159
- return [{
160
- name: "favorodera/vue/setup",
161
- plugins: { vue: vuePlugin },
162
- languageOptions: { globals: {
163
- computed: "readonly",
164
- defineEmits: "readonly",
165
- defineExpose: "readonly",
166
- defineProps: "readonly",
167
- onMounted: "readonly",
168
- onUnmounted: "readonly",
169
- reactive: "readonly",
170
- ref: "readonly",
171
- shallowReactive: "readonly",
172
- shallowRef: "readonly",
173
- toRef: "readonly",
174
- toRefs: "readonly",
175
- watch: "readonly",
176
- watchEffect: "readonly"
177
- } }
178
- }, {
179
- name: "favorodera/vue/rules",
180
- files: resolved.files,
181
- languageOptions: {
182
- parser: vueParser,
183
- parserOptions: {
184
- parser: tsEsLint.parser,
185
- extraFileExtensions: [".vue"],
186
- sourceType: "module"
187
- }
188
- },
189
- processor,
190
- rules: {
191
- ...baseRules,
192
- "vue/block-order": ["error", { order: [
193
- "script",
194
- "template",
195
- "style"
196
- ] }],
197
- "vue/component-name-in-template-casing": ["error", "PascalCase"],
198
- "vue/component-options-name-casing": ["error", "PascalCase"],
199
- "vue/multi-word-component-names": "off",
200
- "vue/block-tag-newline": ["error", {
201
- multiline: "ignore",
202
- singleline: "ignore"
203
- }],
204
- "vue/multiline-html-element-content-newline": ["error", {
205
- allowEmptyLines: true,
206
- ignores: ["pre", "textarea"]
207
- }],
208
- ...resolved.overrides
209
- }
210
- }];
211
- }
212
- //#endregion
213
- //#region src/configs/ignores.ts
214
- const defaultPatterns = ignoresGlob;
215
- /**
216
- * Globs for ignoring files and directories from ESLint scanning.
217
- * @param patterns Additional ignore patterns or a function to modify the defaults.
218
- * @returns An array containing the ignore flat config item.
219
- */
220
- function ignores(patterns = []) {
221
- return [{
222
- name: "favorodera/ignores",
223
- ignores: typeof patterns === "function" ? patterns(defaultPatterns) : [...defaultPatterns, ...patterns]
224
- }];
225
- }
226
141
  //#endregion
227
142
  //#region src/configs/imports.ts
228
143
  const importsDefaults = { files: [
@@ -247,16 +162,16 @@ async function imports(options) {
247
162
  "unused-imports": unusedImportsPlugin
248
163
  }
249
164
  }, {
250
- name: "favorodera/imports/rules",
251
165
  files: resolved.files,
166
+ name: "favorodera/imports/rules",
252
167
  rules: {
253
168
  ...(0, eslint_flat_config_utils.renamePluginsInRules)(baseRules, { "import-lite": "import" }),
254
- "import/consistent-type-specifier-style": ["error", "top-level"],
169
+ "import/consistent-type-specifier-style": ["error", "prefer-top-level"],
255
170
  "import/first": "error",
171
+ "import/newline-after-import": ["error", { count: 1 }],
256
172
  "import/no-duplicates": "error",
257
173
  "import/no-mutable-exports": "error",
258
174
  "import/no-named-default": "error",
259
- "import/newline-after-import": ["error", { count: 1 }],
260
175
  "unused-imports/no-unused-imports": "error",
261
176
  "unused-imports/no-unused-vars": ["error", {
262
177
  args: "after-used",
@@ -286,10 +201,8 @@ async function javascript(options) {
286
201
  const resolved = (0, defu.defu)(options, javascriptDefaults);
287
202
  const baseRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
288
203
  return [{
289
- name: "favorodera/javascript/setup",
290
204
  languageOptions: {
291
205
  ecmaVersion: "latest",
292
- sourceType: "module",
293
206
  globals: {
294
207
  ...globals.default.browser,
295
208
  ...globals.default.es2021,
@@ -297,12 +210,14 @@ async function javascript(options) {
297
210
  document: "readonly",
298
211
  navigator: "readonly",
299
212
  window: "readonly"
300
- }
213
+ },
214
+ sourceType: "module"
301
215
  },
302
- linterOptions: { reportUnusedDisableDirectives: true }
216
+ linterOptions: { reportUnusedDisableDirectives: true },
217
+ name: "favorodera/javascript/setup"
303
218
  }, {
304
- name: "favorodera/javascript/rules",
305
219
  files: resolved.files,
220
+ name: "favorodera/javascript/rules",
306
221
  rules: {
307
222
  ...baseRules,
308
223
  "accessor-pairs": ["error", {
@@ -316,232 +231,87 @@ async function javascript(options) {
316
231
  }];
317
232
  }
318
233
  //#endregion
319
- //#region src/configs/markdown.ts
320
- const markdownDefaults = {
321
- files: [mdGlob],
322
- gfm: true
323
- };
234
+ //#region src/configs/jsdoc.ts
235
+ const jsdocDefaults = { files: [
236
+ jsGlob,
237
+ tsGlob,
238
+ vueGlob
239
+ ] };
324
240
  /**
325
- * Constructs the flat config items for Markdown linting, extracting and linting
326
- * embedded code blocks within the document according to specified rules.
327
- * @param options Markdown configuration options.
328
- * @returns Promise resolving to Markdown ESLint config items.
241
+ * Constructs the flat config items for JSDoc linting, ensuring comments follow
242
+ * proper styling, parameter checks, and types alignment.
243
+ * @param options JSDoc configuration options.
244
+ * @returns Promise resolving to JSDoc ESLint config items.
329
245
  */
330
- async function markdown(options) {
331
- const resolved = (0, defu.defu)(options, markdownDefaults);
332
- const markdownPlugin = await importModule(import("@eslint/markdown"));
333
- const baseRules = extractRules(markdownPlugin.configs.recommended);
246
+ async function jsdoc(options) {
247
+ const resolved = (0, defu.defu)(options, jsdocDefaults);
248
+ const jsdocPlugin = await importModule(import("eslint-plugin-jsdoc"));
249
+ const baseRules = {
250
+ ...jsdocPlugin.configs["flat/recommended-typescript-error"]?.rules,
251
+ ...jsdocPlugin.configs["flat/stylistic-typescript-error"]?.rules
252
+ };
253
+ return [{
254
+ name: "favorodera/jsdoc/setup",
255
+ plugins: { jsdoc: jsdocPlugin }
256
+ }, {
257
+ files: resolved.files,
258
+ name: "favorodera/tailwind/rules",
259
+ rules: {
260
+ ...baseRules,
261
+ "jsdoc/check-access": "warn",
262
+ "jsdoc/check-alignment": "warn",
263
+ "jsdoc/check-param-names": "warn",
264
+ "jsdoc/check-property-names": "warn",
265
+ "jsdoc/check-types": "warn",
266
+ "jsdoc/empty-tags": "warn",
267
+ "jsdoc/implements-on-classes": "warn",
268
+ "jsdoc/multiline-blocks": "warn",
269
+ "jsdoc/no-defaults": "warn",
270
+ "jsdoc/no-multi-asterisks": "warn",
271
+ "jsdoc/require-param-name": "warn",
272
+ "jsdoc/require-property": "warn",
273
+ "jsdoc/require-property-description": "warn",
274
+ "jsdoc/require-property-name": "warn",
275
+ "jsdoc/require-returns-check": "warn",
276
+ "jsdoc/require-returns-description": "warn",
277
+ "jsdoc/require-yields-check": "warn",
278
+ ...resolved.overrides
279
+ }
280
+ }];
281
+ }
282
+ //#endregion
283
+ //#region src/configs/jsonc.ts
284
+ const jsoncDefaults = { files: [
285
+ json5Glob,
286
+ jsoncGlob,
287
+ jsonGlob
288
+ ] };
289
+ /**
290
+ * Constructs the flat config items for JSON, JSON5, and JSONC linting, setting up
291
+ * the custom parser, rule validations, and sorting rules for package.json/tsconfig.json.
292
+ * @param options JSONC configuration options.
293
+ * @returns Promise resolving to JSONC ESLint config items.
294
+ */
295
+ async function jsonc(options) {
296
+ const resolved = (0, defu.defu)(options, jsoncDefaults);
334
297
  return [
335
298
  {
336
- name: "favorodera/markdown/setup",
337
- plugins: { md: markdownPlugin }
299
+ name: "favorodera/jsonc/setup",
300
+ plugins: { jsonc: await importModule(import("eslint-plugin-jsonc")) }
338
301
  },
339
302
  {
340
- name: "favorodera/markdown/rules",
341
303
  files: resolved.files,
342
- language: resolved.gfm ? "md/gfm" : "md/commonmark",
343
- ignores: [mdInMdGlob],
344
- processor: (0, eslint_merge_processors.mergeProcessors)([markdownPlugin.processors?.markdown, eslint_merge_processors.processorPassThrough]),
345
- rules: {
346
- ...(0, eslint_flat_config_utils.renamePluginsInRules)(baseRules, { markdown: "md" }),
347
- "md/fenced-code-language": "off",
348
- "md/no-missing-label-refs": "off",
349
- ...resolved.overrides
350
- }
351
- },
352
- {
353
- name: "favorodera/markdown/disables/code",
354
- files: [codeInMdGlob],
355
- languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
356
- rules: {
357
- "no-alert": "off",
358
- "no-console": "off",
359
- "no-labels": "off",
360
- "no-lone-blocks": "off",
361
- "no-restricted-syntax": "off",
362
- "no-undef": "off",
363
- "no-unused-expressions": "off",
364
- "no-unused-labels": "off",
365
- "no-unused-vars": "off",
366
- "node/prefer-global/process": "off",
367
- "style/comma-dangle": "off",
368
- "style/eol-last": "off",
369
- "style/padding-line-between-statements": "off",
370
- "ts/consistent-type-imports": "off",
371
- "ts/explicit-function-return-type": "off",
372
- "ts/no-namespace": "off",
373
- "ts/no-redeclare": "off",
374
- "ts/no-require-imports": "off",
375
- "ts/no-unused-expressions": "off",
376
- "ts/no-unused-vars": "off",
377
- "ts/no-use-before-define": "off",
378
- "unicode-bom": "off",
379
- "unused-imports/no-unused-imports": "off",
380
- "unused-imports/no-unused-vars": "off"
381
- }
382
- }
383
- ];
384
- }
385
- //#endregion
386
- //#region src/configs/stylistic.ts
387
- const stylisticDefaults = {
388
- settings: {
389
- indent: 2,
390
- experimental: false,
391
- quotes: "single",
392
- semi: false,
393
- jsx: false
394
- },
395
- files: [
396
- jsGlob,
397
- tsGlob,
398
- vueGlob
399
- ]
400
- };
401
- /**
402
- * Constructs the flat config items for Stylistic linting, applying customized
403
- * formatting settings such as quotes, indentation, and spacing.
404
- * @param options Stylistic configuration options.
405
- * @returns Promise resolving to stylistic ESLint config items.
406
- */
407
- async function stylistic(options) {
408
- const resolved = (0, defu.defu)(options, stylisticDefaults);
409
- const stylePlugin = await importModule(import("@stylistic/eslint-plugin"));
410
- const baseRules = stylePlugin.configs.customize({
411
- pluginName: "style",
412
- ...resolved.settings
413
- })?.rules || {};
414
- return [{
415
- name: "favorodera/stylistic/setup",
416
- plugins: { style: stylePlugin }
417
- }, {
418
- name: "favorodera/stylistic/rules",
419
- files: resolved.files,
420
- rules: {
421
- ...baseRules,
422
- "style/quotes": [
423
- "error",
424
- "single",
425
- { avoidEscape: true }
426
- ],
427
- "style/no-multiple-empty-lines": ["error", {
428
- max: 2,
429
- maxEOF: 2,
430
- maxBOF: 0
431
- }],
432
- "style/padded-blocks": "off",
433
- "style/no-trailing-spaces": ["error", { skipBlankLines: true }],
434
- "style/brace-style": "off",
435
- "style/generator-star-spacing": ["error", {
436
- after: true,
437
- before: false
438
- }],
439
- "style/yield-star-spacing": ["error", {
440
- after: true,
441
- before: false
442
- }],
443
- ...resolved.overrides
444
- }
445
- }];
446
- }
447
- //#endregion
448
- //#region src/configs/tailwind.ts
449
- const tailwindDefaults = {
450
- files: [
451
- jsGlob,
452
- tsGlob,
453
- vueGlob
454
- ],
455
- settings: { detectComponentClasses: true }
456
- };
457
- /**
458
- * Constructs the flat config items for Tailwind CSS linting, providing custom settings
459
- * to parse and lint utility classes, and enforcing consistent ordering.
460
- * @param options Tailwind configuration options.
461
- * @returns Promise resolving to Tailwind ESLint config items.
462
- */
463
- async function tailwind(options) {
464
- const resolved = (0, defu.defu)(options, tailwindDefaults);
465
- const tailwindPlugin = await importModule(import("eslint-plugin-better-tailwindcss"));
466
- const baseRules = {
467
- ...tailwindPlugin.configs["recommended-error"].rules,
468
- ...tailwindPlugin.configs["stylistic-error"].rules
469
- };
470
- return [{
471
- name: "favorodera/tailwind/setup",
472
- plugins: { tailwind: tailwindPlugin },
473
- settings: { tailwindcss: resolved.settings }
474
- }, {
475
- name: "favorodera/tailwind/rules",
476
- files: resolved.files,
477
- rules: {
478
- ...(0, eslint_flat_config_utils.renamePluginsInRules)(baseRules, { "better-tailwindcss": "tailwind" }),
479
- "tailwind/no-unregistered-classes": "off",
480
- "tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
481
- ...resolved.overrides
482
- }
483
- }];
484
- }
485
- //#endregion
486
- //#region src/configs/typescript.ts
487
- const typescriptDefaults = { files: [tsGlob] };
488
- /**
489
- * Constructs the flat config items for TypeScript linting, initializing the parser
490
- * and extending the recommended and strict type-aware rule sets.
491
- * @param options TypeScript configuration options.
492
- * @returns Promise resolving to TypeScript ESLint config items.
493
- */
494
- async function typescript(options) {
495
- const resolved = (0, defu.defu)(options, typescriptDefaults);
496
- const tsEsLint = await importModule(import("typescript-eslint"));
497
- const baseRules = extractRules(tsEsLint.configs.recommended, tsEsLint.configs.strict);
498
- return [{
499
- name: "favorodera/typescript/setup",
500
- plugins: { ts: tsEsLint.plugin }
501
- }, {
502
- name: "favorodera/typescript/rules",
503
- files: resolved.files,
504
- languageOptions: {
505
- parser: tsEsLint.parser,
506
- parserOptions: { sourceType: "module" }
507
- },
508
- rules: {
509
- ...(0, eslint_flat_config_utils.renamePluginsInRules)(baseRules, { "@typescript-eslint": "ts" }),
510
- "ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
511
- "ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
512
- "ts/array-type": ["error", {
513
- default: "generic",
514
- readonly: "generic"
515
- }],
516
- ...resolved.overrides
517
- }
518
- }];
519
- }
520
- //#endregion
521
- //#region src/configs/jsonc.ts
522
- const jsoncDefaults = { files: [
523
- json5Glob,
524
- jsoncGlob,
525
- jsonGlob
526
- ] };
527
- /**
528
- * Constructs the flat config items for JSON, JSON5, and JSONC linting, setting up
529
- * the custom parser, rule validations, and sorting rules for package.json/tsconfig.json.
530
- * @param options JSONC configuration options.
531
- * @returns Promise resolving to JSONC ESLint config items.
532
- */
533
- async function jsonc(options) {
534
- const resolved = (0, defu.defu)(options, jsoncDefaults);
535
- return [
536
- {
537
- name: "favorodera/jsonc/setup",
538
- plugins: { jsonc: await importModule(import("eslint-plugin-jsonc")) }
539
- },
540
- {
541
- name: "favorodera/jsonc/rules",
542
- files: resolved.files,
543
- language: "jsonc/x",
304
+ language: "jsonc/x",
305
+ name: "favorodera/jsonc/rules",
544
306
  rules: {
307
+ "jsonc/array-bracket-spacing": ["error", "never"],
308
+ "jsonc/comma-dangle": ["error", "never"],
309
+ "jsonc/comma-style": ["error", "last"],
310
+ "jsonc/indent": ["error", 2],
311
+ "jsonc/key-spacing": ["error", {
312
+ afterColon: true,
313
+ beforeColon: false
314
+ }],
545
315
  "jsonc/no-bigint-literals": "error",
546
316
  "jsonc/no-binary-expression": "error",
547
317
  "jsonc/no-binary-numeric-literals": "error",
@@ -565,17 +335,6 @@ async function jsonc(options) {
565
335
  "jsonc/no-undefined-value": "error",
566
336
  "jsonc/no-unicode-codepoint-escapes": "error",
567
337
  "jsonc/no-useless-escape": "error",
568
- "jsonc/space-unary-ops": "error",
569
- "jsonc/valid-json-number": "error",
570
- "jsonc/vue-custom-block/no-parsing-error": "error",
571
- "jsonc/array-bracket-spacing": ["error", "never"],
572
- "jsonc/comma-dangle": ["error", "never"],
573
- "jsonc/comma-style": ["error", "last"],
574
- "jsonc/indent": ["error", 2],
575
- "jsonc/key-spacing": ["error", {
576
- afterColon: true,
577
- beforeColon: false
578
- }],
579
338
  "jsonc/object-curly-newline": ["error", {
580
339
  consistent: true,
581
340
  multiline: true
@@ -584,12 +343,15 @@ async function jsonc(options) {
584
343
  "jsonc/object-property-newline": ["error", { allowAllPropertiesOnSameLine: true }],
585
344
  "jsonc/quote-props": "error",
586
345
  "jsonc/quotes": "error",
346
+ "jsonc/space-unary-ops": "error",
347
+ "jsonc/valid-json-number": "error",
348
+ "jsonc/vue-custom-block/no-parsing-error": "error",
587
349
  ...resolved.overrides
588
350
  }
589
351
  },
590
352
  {
591
- name: "favorodera/jsonc/sort/package-json",
592
353
  files: [packageJsonGlob],
354
+ name: "favorodera/jsonc/sort/package-json",
593
355
  rules: {
594
356
  "jsonc/sort-array-values": ["error", {
595
357
  order: { type: "asc" },
@@ -657,11 +419,11 @@ async function jsonc(options) {
657
419
  },
658
420
  {
659
421
  order: { type: "asc" },
660
- pathPattern: "^workspaces\\.catalog$"
422
+ pathPattern: String.raw`^workspaces\.catalog$`
661
423
  },
662
424
  {
663
425
  order: { type: "asc" },
664
- pathPattern: "^workspaces\\.catalogs\\.[^.]+$"
426
+ pathPattern: String.raw`^workspaces\.catalogs\.[^.]+$`
665
427
  },
666
428
  {
667
429
  order: [
@@ -691,8 +453,8 @@ async function jsonc(options) {
691
453
  }
692
454
  },
693
455
  {
694
- name: "favorodera/jsonc/sort/tsconfig-json",
695
456
  files: tsConfigGlob,
457
+ name: "favorodera/jsonc/sort/tsconfig-json",
696
458
  rules: { "jsonc/sort-keys": [
697
459
  "error",
698
460
  {
@@ -807,50 +569,434 @@ async function jsonc(options) {
807
569
  ];
808
570
  }
809
571
  //#endregion
810
- //#region src/configs/jsdoc.ts
811
- const jsdocDefaults = { files: [
572
+ //#region src/configs/markdown.ts
573
+ const markdownDefaults = {
574
+ files: [mdGlob],
575
+ gfm: true
576
+ };
577
+ /**
578
+ * Constructs the flat config items for Markdown linting, extracting and linting
579
+ * embedded code blocks within the document according to specified rules.
580
+ * @param options Markdown configuration options.
581
+ * @returns Promise resolving to Markdown ESLint config items.
582
+ */
583
+ async function markdown(options) {
584
+ const resolved = (0, defu.defu)(options, markdownDefaults);
585
+ const markdownPlugin = await importModule(import("@eslint/markdown"));
586
+ const baseRules = extractRules(markdownPlugin.configs.recommended);
587
+ return [
588
+ {
589
+ name: "favorodera/markdown/setup",
590
+ plugins: { md: markdownPlugin }
591
+ },
592
+ {
593
+ files: resolved.files,
594
+ ignores: [mdInMdGlob],
595
+ language: resolved.gfm ? "md/gfm" : "md/commonmark",
596
+ name: "favorodera/markdown/rules",
597
+ processor: (0, eslint_merge_processors.mergeProcessors)([markdownPlugin.processors?.markdown, eslint_merge_processors.processorPassThrough]),
598
+ rules: {
599
+ ...(0, eslint_flat_config_utils.renamePluginsInRules)(baseRules, { markdown: "md" }),
600
+ "md/fenced-code-language": "off",
601
+ "md/no-missing-label-refs": "off",
602
+ ...resolved.overrides
603
+ }
604
+ },
605
+ {
606
+ files: [codeInMdGlob],
607
+ languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
608
+ name: "favorodera/markdown/disables/code",
609
+ rules: {
610
+ "no-alert": "off",
611
+ "no-console": "off",
612
+ "no-labels": "off",
613
+ "no-lone-blocks": "off",
614
+ "no-restricted-syntax": "off",
615
+ "no-undef": "off",
616
+ "no-unused-expressions": "off",
617
+ "no-unused-labels": "off",
618
+ "no-unused-vars": "off",
619
+ "node/prefer-global/process": "off",
620
+ "style/comma-dangle": "off",
621
+ "style/eol-last": "off",
622
+ "style/padding-line-between-statements": "off",
623
+ "ts/consistent-type-imports": "off",
624
+ "ts/explicit-function-return-type": "off",
625
+ "ts/no-namespace": "off",
626
+ "ts/no-redeclare": "off",
627
+ "ts/no-require-imports": "off",
628
+ "ts/no-unused-expressions": "off",
629
+ "ts/no-unused-vars": "off",
630
+ "ts/no-use-before-define": "off",
631
+ "unicode-bom": "off",
632
+ "unused-imports/no-unused-imports": "off",
633
+ "unused-imports/no-unused-vars": "off"
634
+ }
635
+ }
636
+ ];
637
+ }
638
+ //#endregion
639
+ //#region src/configs/node.ts
640
+ const nodeDefaults = { files: [
812
641
  jsGlob,
813
642
  tsGlob,
814
643
  vueGlob
815
644
  ] };
816
645
  /**
817
- * Constructs the flat config items for JSDoc linting, ensuring comments follow
818
- * proper styling, parameter checks, and types alignment.
819
- * @param options JSDoc configuration options.
820
- * @returns Promise resolving to JSDoc ESLint config items.
646
+ * Constructs the flat config items for Node.js linting, providing rules
647
+ * to enforce best practices for Node.js environments.
648
+ * @param options Node configuration options.
649
+ * @returns Promise resolving to Node ESLint config items.
821
650
  */
822
- async function jsdoc(options) {
823
- const resolved = (0, defu.defu)(options, jsdocDefaults);
824
- const jsdocPlugin = await importModule(import("eslint-plugin-jsdoc"));
825
- const baseRules = {
826
- ...jsdocPlugin.configs["flat/recommended-typescript-error"]?.rules,
827
- ...jsdocPlugin.configs["flat/stylistic-typescript-error"]?.rules
828
- };
651
+ async function node(options) {
652
+ const resolved = (0, defu.defu)(options, nodeDefaults);
653
+ const nodePlugin = await importModule(import("eslint-plugin-n"));
654
+ const baseRules = nodePlugin.configs?.["flat/recommended"]?.rules || {};
829
655
  return [{
830
- name: "favorodera/jsdoc/setup",
831
- plugins: { jsdoc: jsdocPlugin }
656
+ name: "favorodera/node/setup",
657
+ plugins: { node: nodePlugin }
658
+ }, {
659
+ files: resolved.files,
660
+ name: "favorodera/node/rules",
661
+ rules: {
662
+ ...(0, eslint_flat_config_utils.renamePluginsInRules)(baseRules, { n: "node" }),
663
+ "node/handle-callback-err": ["error", "^(err|error)$"],
664
+ "node/no-deprecated-api": "error",
665
+ "node/no-exports-assign": "error",
666
+ "node/no-missing-import": "off",
667
+ "node/no-new-require": "error",
668
+ "node/no-path-concat": "error",
669
+ "node/no-unpublished-import": "off",
670
+ "node/prefer-global/buffer": ["error", "never"],
671
+ "node/prefer-global/process": ["error", "never"],
672
+ "node/process-exit-as-throw": "error",
673
+ ...resolved.overrides
674
+ }
675
+ }];
676
+ }
677
+ //#endregion
678
+ //#region src/configs/perfectionist.ts
679
+ const perfectionistDefaults = { files: [
680
+ jsGlob,
681
+ tsGlob,
682
+ vueGlob
683
+ ] };
684
+ /**
685
+ * Constructs the flat config items for Perfectionist linting, providing rules
686
+ * to naturally sort objects, imports, classes, and other elements in your code.
687
+ * @param options Perfectionist configuration options.
688
+ * @returns Promise resolving to Perfectionist ESLint config items.
689
+ */
690
+ async function perfectionist(options) {
691
+ const resolved = (0, defu.defu)(options, perfectionistDefaults);
692
+ const perfectionistPlugin = await importModule(import("eslint-plugin-perfectionist"));
693
+ const baseRules = perfectionistPlugin.configs["recommended-natural"]?.rules || {};
694
+ return [{
695
+ name: "favorodera/perfectionist/setup",
696
+ plugins: { perfectionist: perfectionistPlugin }
697
+ }, {
698
+ files: resolved.files,
699
+ name: "favorodera/perfectionist/rules",
700
+ rules: {
701
+ ...baseRules,
702
+ "perfectionist/sort-exports": ["error", {
703
+ order: "asc",
704
+ type: "natural"
705
+ }],
706
+ "perfectionist/sort-imports": ["error", {
707
+ groups: [
708
+ "type-import",
709
+ [
710
+ "type-parent",
711
+ "type-sibling",
712
+ "type-index",
713
+ "type-internal"
714
+ ],
715
+ "value-builtin",
716
+ "value-external",
717
+ "value-internal",
718
+ [
719
+ "value-parent",
720
+ "value-sibling",
721
+ "value-index"
722
+ ],
723
+ "side-effect",
724
+ "ts-equals-import",
725
+ "unknown"
726
+ ],
727
+ newlinesBetween: "ignore",
728
+ newlinesInside: "ignore",
729
+ order: "asc",
730
+ type: "natural"
731
+ }],
732
+ "perfectionist/sort-named-exports": ["error", {
733
+ order: "asc",
734
+ type: "natural"
735
+ }],
736
+ "perfectionist/sort-named-imports": ["error", {
737
+ order: "asc",
738
+ type: "natural"
739
+ }],
740
+ ...resolved.overrides
741
+ }
742
+ }];
743
+ }
744
+ //#endregion
745
+ //#region src/configs/stylistic.ts
746
+ const stylisticDefaults = {
747
+ files: [
748
+ jsGlob,
749
+ tsGlob,
750
+ vueGlob
751
+ ],
752
+ settings: {
753
+ experimental: false,
754
+ indent: 2,
755
+ jsx: false,
756
+ quotes: "single",
757
+ semi: false
758
+ }
759
+ };
760
+ /**
761
+ * Constructs the flat config items for Stylistic linting, applying customized
762
+ * formatting settings such as quotes, indentation, and spacing.
763
+ * @param options Stylistic configuration options.
764
+ * @returns Promise resolving to stylistic ESLint config items.
765
+ */
766
+ async function stylistic(options) {
767
+ const resolved = (0, defu.defu)(options, stylisticDefaults);
768
+ const stylePlugin = await importModule(import("@stylistic/eslint-plugin"));
769
+ const baseRules = stylePlugin.configs.customize({
770
+ pluginName: "style",
771
+ ...resolved.settings
772
+ })?.rules || {};
773
+ return [{
774
+ name: "favorodera/stylistic/setup",
775
+ plugins: { style: stylePlugin }
776
+ }, {
777
+ files: resolved.files,
778
+ name: "favorodera/stylistic/rules",
779
+ rules: {
780
+ ...baseRules,
781
+ "style/brace-style": "off",
782
+ "style/generator-star-spacing": ["error", {
783
+ after: true,
784
+ before: false
785
+ }],
786
+ "style/no-multiple-empty-lines": ["error", {
787
+ max: 2,
788
+ maxBOF: 0,
789
+ maxEOF: 2
790
+ }],
791
+ "style/no-trailing-spaces": ["error", { skipBlankLines: true }],
792
+ "style/padded-blocks": "off",
793
+ "style/quotes": [
794
+ "error",
795
+ "single",
796
+ { avoidEscape: true }
797
+ ],
798
+ "style/yield-star-spacing": ["error", {
799
+ after: true,
800
+ before: false
801
+ }],
802
+ ...resolved.overrides
803
+ }
804
+ }];
805
+ }
806
+ //#endregion
807
+ //#region src/configs/tailwind.ts
808
+ const tailwindDefaults = {
809
+ files: [
810
+ jsGlob,
811
+ tsGlob,
812
+ vueGlob
813
+ ],
814
+ settings: { detectComponentClasses: true }
815
+ };
816
+ /**
817
+ * Constructs the flat config items for Tailwind CSS linting, providing custom settings
818
+ * to parse and lint utility classes, and enforcing consistent ordering.
819
+ * @param options Tailwind configuration options.
820
+ * @returns Promise resolving to Tailwind ESLint config items.
821
+ */
822
+ async function tailwind(options) {
823
+ const resolved = (0, defu.defu)(options, tailwindDefaults);
824
+ const tailwindPlugin = await importModule(import("eslint-plugin-better-tailwindcss"));
825
+ const baseRules = {
826
+ ...tailwindPlugin.configs["recommended-error"].rules,
827
+ ...tailwindPlugin.configs["stylistic-error"].rules
828
+ };
829
+ return [{
830
+ name: "favorodera/tailwind/setup",
831
+ plugins: { tailwind: tailwindPlugin },
832
+ settings: { tailwindcss: resolved.settings }
832
833
  }, {
834
+ files: resolved.files,
833
835
  name: "favorodera/tailwind/rules",
836
+ rules: {
837
+ ...(0, eslint_flat_config_utils.renamePluginsInRules)(baseRules, { "better-tailwindcss": "tailwind" }),
838
+ "tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
839
+ "tailwind/no-unregistered-classes": "off",
840
+ ...resolved.overrides
841
+ }
842
+ }];
843
+ }
844
+ //#endregion
845
+ //#region src/configs/typescript.ts
846
+ const typescriptDefaults = { files: [tsGlob] };
847
+ /**
848
+ * Constructs the flat config items for TypeScript linting, initializing the parser
849
+ * and extending the recommended and strict type-aware rule sets.
850
+ * @param options TypeScript configuration options.
851
+ * @returns Promise resolving to TypeScript ESLint config items.
852
+ */
853
+ async function typescript(options) {
854
+ const resolved = (0, defu.defu)(options, typescriptDefaults);
855
+ const tsEsLint = await importModule(import("typescript-eslint"));
856
+ const baseRules = extractRules(tsEsLint.configs.recommended, tsEsLint.configs.strict);
857
+ return [{
858
+ name: "favorodera/typescript/setup",
859
+ plugins: { ts: tsEsLint.plugin }
860
+ }, {
834
861
  files: resolved.files,
862
+ languageOptions: {
863
+ parser: tsEsLint.parser,
864
+ parserOptions: { sourceType: "module" }
865
+ },
866
+ name: "favorodera/typescript/rules",
835
867
  rules: {
836
- ...baseRules || {},
837
- "jsdoc/check-access": "warn",
838
- "jsdoc/check-param-names": "warn",
839
- "jsdoc/check-property-names": "warn",
840
- "jsdoc/check-types": "warn",
841
- "jsdoc/empty-tags": "warn",
842
- "jsdoc/implements-on-classes": "warn",
843
- "jsdoc/no-defaults": "warn",
844
- "jsdoc/no-multi-asterisks": "warn",
845
- "jsdoc/require-param-name": "warn",
846
- "jsdoc/require-property": "warn",
847
- "jsdoc/require-property-description": "warn",
848
- "jsdoc/require-property-name": "warn",
849
- "jsdoc/require-returns-check": "warn",
850
- "jsdoc/require-returns-description": "warn",
851
- "jsdoc/require-yields-check": "warn",
852
- "jsdoc/check-alignment": "warn",
853
- "jsdoc/multiline-blocks": "warn",
868
+ ...(0, eslint_flat_config_utils.renamePluginsInRules)(baseRules, { "@typescript-eslint": "ts" }),
869
+ "ts/array-type": ["error", {
870
+ default: "generic",
871
+ readonly: "generic"
872
+ }],
873
+ "ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
874
+ "ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
875
+ ...resolved.overrides
876
+ }
877
+ }];
878
+ }
879
+ //#endregion
880
+ //#region src/configs/unicorn.ts
881
+ const unicornDefaults = { files: [
882
+ jsGlob,
883
+ tsGlob,
884
+ vueGlob
885
+ ] };
886
+ /**
887
+ * Constructs the flat config items for Unicorn linting, providing a collection of
888
+ * awesome ESLint rules to improve code quality and enforce best practices.
889
+ * @param options Unicorn configuration options.
890
+ * @returns Promise resolving to Unicorn ESLint config items.
891
+ */
892
+ async function unicorn(options) {
893
+ const resolved = (0, defu.defu)(options, unicornDefaults);
894
+ const unicornPlugin = await importModule(import("eslint-plugin-unicorn"));
895
+ const baseRules = unicornPlugin.configs["unopinionated"]?.rules || {};
896
+ return [{
897
+ name: "favorodera/unicorn/setup",
898
+ plugins: { unicorn: unicornPlugin }
899
+ }, {
900
+ files: resolved.files,
901
+ languageOptions: { globals: globals.default.builtin },
902
+ name: "favorodera/unicorn/rules",
903
+ rules: {
904
+ ...baseRules,
905
+ "unicorn/consistent-empty-array-spread": "error",
906
+ "unicorn/error-message": "error",
907
+ "unicorn/escape-case": "error",
908
+ "unicorn/new-for-builtins": "error",
909
+ "unicorn/no-instanceof-builtins": "error",
910
+ "unicorn/no-new-array": "error",
911
+ "unicorn/no-new-buffer": "error",
912
+ "unicorn/number-literal-case": "error",
913
+ "unicorn/prefer-dom-node-text-content": "error",
914
+ "unicorn/prefer-includes": "error",
915
+ "unicorn/prefer-node-protocol": "error",
916
+ "unicorn/prefer-number-properties": "error",
917
+ "unicorn/prefer-string-starts-ends-with": "error",
918
+ "unicorn/prefer-type-error": "error",
919
+ "unicorn/throw-new-error": "error",
920
+ ...resolved.overrides
921
+ }
922
+ }];
923
+ }
924
+ //#endregion
925
+ //#region src/configs/vue.ts
926
+ const sfcBlocksDefaults = { blocks: {
927
+ customBlocks: true,
928
+ styles: true,
929
+ template: false
930
+ } };
931
+ const vueDefaults = {
932
+ files: [vueGlob],
933
+ sfcBlocks: sfcBlocksDefaults
934
+ };
935
+ /**
936
+ * Constructs the flat config items for Vue linting, setting up the custom template parser,
937
+ * Vue block processors, and rules to enforce recommended component syntax.
938
+ * @param options Vue configuration options.
939
+ * @returns Promise resolving to Vue ESLint config items.
940
+ */
941
+ async function vue(options) {
942
+ const resolved = (0, defu.defu)(options, vueDefaults);
943
+ const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
944
+ const [vuePlugin, vueParser, tsEsLint] = await Promise.all([
945
+ importModule(import("eslint-plugin-vue")),
946
+ importModule(import("vue-eslint-parser")),
947
+ importModule(import("typescript-eslint"))
948
+ ]);
949
+ const baseRules = extractRules(vuePlugin.configs["flat/essential"], vuePlugin.configs["flat/strongly-recommended"], vuePlugin.configs["flat/recommended"]);
950
+ const processor = sfcBlocks === false ? vuePlugin.processors[".vue"] : (0, eslint_merge_processors.mergeProcessors)([vuePlugin.processors[".vue"], (0, eslint_processor_vue_blocks.default)(sfcBlocks)]);
951
+ return [{
952
+ languageOptions: { globals: {
953
+ computed: "readonly",
954
+ defineEmits: "readonly",
955
+ defineExpose: "readonly",
956
+ defineProps: "readonly",
957
+ onMounted: "readonly",
958
+ onUnmounted: "readonly",
959
+ reactive: "readonly",
960
+ ref: "readonly",
961
+ shallowReactive: "readonly",
962
+ shallowRef: "readonly",
963
+ toRef: "readonly",
964
+ toRefs: "readonly",
965
+ watch: "readonly",
966
+ watchEffect: "readonly"
967
+ } },
968
+ name: "favorodera/vue/setup",
969
+ plugins: { vue: vuePlugin }
970
+ }, {
971
+ files: resolved.files,
972
+ languageOptions: {
973
+ parser: vueParser,
974
+ parserOptions: {
975
+ extraFileExtensions: [".vue"],
976
+ parser: tsEsLint.parser,
977
+ sourceType: "module"
978
+ }
979
+ },
980
+ name: "favorodera/vue/rules",
981
+ processor,
982
+ rules: {
983
+ ...baseRules,
984
+ "vue/block-order": ["error", { order: [
985
+ "script",
986
+ "template",
987
+ "style"
988
+ ] }],
989
+ "vue/block-tag-newline": ["error", {
990
+ multiline: "ignore",
991
+ singleline: "ignore"
992
+ }],
993
+ "vue/component-name-in-template-casing": ["error", "PascalCase"],
994
+ "vue/component-options-name-casing": ["error", "PascalCase"],
995
+ "vue/multi-word-component-names": "off",
996
+ "vue/multiline-html-element-content-newline": ["error", {
997
+ allowEmptyLines: true,
998
+ ignores: ["pre", "textarea"]
999
+ }],
854
1000
  ...resolved.overrides
855
1001
  }
856
1002
  }];
@@ -864,18 +1010,20 @@ async function jsdoc(options) {
864
1010
  * @returns A flat config composer instance that can be exported directly or further modified.
865
1011
  */
866
1012
  function factory(options = {}) {
867
- const configs = [];
868
- configs.push(ignores(options.ignores));
1013
+ const configs = [ignores(options.ignores)];
869
1014
  const configFunctions = {
870
- vue,
871
- typescript,
872
- stylistic,
873
- tailwind,
874
1015
  imports,
875
- markdown,
876
1016
  javascript,
1017
+ jsdoc,
877
1018
  jsonc,
878
- jsdoc
1019
+ markdown,
1020
+ node,
1021
+ perfectionist,
1022
+ stylistic,
1023
+ tailwind,
1024
+ typescript,
1025
+ unicorn,
1026
+ vue
879
1027
  };
880
1028
  for (const [key, configFunction] of Object.entries(configFunctions)) {
881
1029
  const configOption = options[key];
@@ -884,10 +1032,11 @@ function factory(options = {}) {
884
1032
  }
885
1033
  let composer = new eslint_flat_config_utils.FlatConfigComposer();
886
1034
  composer = composer.append(...configs).renamePlugins({
887
- "better-tailwindcss": "tailwind",
888
1035
  "@typescript-eslint": "ts",
1036
+ "better-tailwindcss": "tailwind",
1037
+ "import-lite": "import",
889
1038
  "markdown": "md",
890
- "import-lite": "import"
1039
+ "n": "node"
891
1040
  });
892
1041
  return composer;
893
1042
  }