@favorodera/eslint-config 0.0.0 → 0.0.2

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
@@ -24,51 +24,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  let eslint_flat_config_utils = require("eslint-flat-config-utils");
25
25
  let defu = require("defu");
26
26
  let eslint_merge_processors = require("eslint-merge-processors");
27
+ let eslint_processor_vue_blocks = require("eslint-processor-vue-blocks");
28
+ eslint_processor_vue_blocks = __toESM(eslint_processor_vue_blocks, 1);
27
29
  let globals = require("globals");
28
30
  globals = __toESM(globals, 1);
29
- //#region src/utils.ts
30
- /**
31
- * Return the default export from a module-like object.
32
- * If the module has no default export, return the original resolved value.
33
- *
34
- * @param module - module or promise resolving to a module
35
- * @returns resolved module default or original module
36
- */
37
- async function getModuleDefault(module) {
38
- const resolvedModule = await module;
39
- return resolvedModule.default || resolvedModule;
40
- }
41
- /**
42
- * Normalize boolean or options value into merged options or null.
43
- * Returns null when the input is false or undefined.
44
- *
45
- * @param value - boolean, options object, or undefined
46
- * @param defaults - defaults to merge with
47
- * @returns merged options or false
48
- */
49
- function resolveOptions(value, defaults) {
50
- if (!value) return false;
51
- return (0, defu.defu)(value === true ? {} : value, defaults);
52
- }
53
- /**
54
- * Rename rules by replacing configured plugin prefixes.
55
- *
56
- * @param rules - rules object to rename
57
- * @param map - prefix map used for renaming
58
- * @returns renamed rules object
59
- */
60
- function renameRules(rules, map) {
61
- return Object.fromEntries(Object.entries(rules).map(([key, value]) => {
62
- for (const [from, to] of Object.entries(map)) if (key.startsWith(`${from}/`)) return [to + key.slice(from.length), value];
63
- return [key, value];
64
- }));
65
- }
66
- //#endregion
67
31
  //#region src/globs.ts
68
32
  /** Glob pattern for JavaScript linting */
69
- const jsGlob = "**/*.?([cm])js";
33
+ const jsGlob = "**/*.{js,cjs,mjs}";
70
34
  /** Glob pattern for TypeScript linting */
71
- const tsGlob = "**/*.?([cm])ts";
35
+ const tsGlob = "**/*.{ts,cts,mts}";
72
36
  /** Glob pattern for Vue linting */
73
37
  const vueGlob = "**/*.vue";
74
38
  /** Glob pattern for Markdown linting */
@@ -78,8 +42,8 @@ const mdGlob = "**/*.md";
78
42
  * Includes common build outputs, dependencies, caches, and temporary files
79
43
  */
80
44
  const ignoresGlob = [
81
- "**/node_modules",
82
- "**/dist",
45
+ "**/node_modules/**",
46
+ "**/dist/**",
83
47
  "**/package-lock.json",
84
48
  "**/yarn.lock",
85
49
  "**/pnpm-lock.yaml",
@@ -115,6 +79,35 @@ const ignoresGlob = [
115
79
  "**/.*/skills"
116
80
  ];
117
81
  //#endregion
82
+ //#region src/utils.ts
83
+ /**
84
+ * Resolves a module (or a promise of one) and returns its default export
85
+ * if present, otherwise returns the module itself.
86
+ *
87
+ * Handles both ESM modules (which wrap exports under `.default`) and
88
+ * CJS / plain-object modules uniformly.
89
+ *
90
+ * @param module - A module or a promise that resolves to one
91
+ * @returns The `.default` export if it exists, otherwise the module itself
92
+ */
93
+ async function importModule(module) {
94
+ const resolved = await module;
95
+ if (resolved !== null && typeof resolved === "object" && "default" in resolved) return resolved.default;
96
+ return resolved;
97
+ }
98
+ /**
99
+ * Normalize boolean or options value into merged options or null.
100
+ * Returns null when the input is false or undefined.
101
+ *
102
+ * @param value - boolean, options object, or undefined
103
+ * @param defaults - defaults to merge with
104
+ * @returns merged options or false
105
+ */
106
+ function resolveOptions(value, defaults) {
107
+ if (!value) return false;
108
+ return (0, defu.defu)(value === true ? {} : value, defaults);
109
+ }
110
+ //#endregion
118
111
  //#region src/configs/vue.ts
119
112
  const sfcBlocksDefaults = { blocks: {
120
113
  styles: true,
@@ -125,22 +118,21 @@ const vueDefaults = {
125
118
  files: [vueGlob],
126
119
  sfcBlocks: sfcBlocksDefaults
127
120
  };
128
- /**
129
- * Vue SFC linting via `vue-eslint-parser`, `eslint-plugin-vue`, `typescript-eslint(parser)`.
130
- * @param options - Vue configuration options
131
- * @returns Promise resolving to Vue ESLint config items
132
- */
133
121
  async function vue(options) {
134
122
  const resolved = (0, defu.defu)(options, vueDefaults);
135
123
  const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
136
- const [vuePlugin, vueParser, tsEsLint, vueBlocksProcessor] = await Promise.all([
137
- getModuleDefault(import("eslint-plugin-vue")),
138
- getModuleDefault(import("vue-eslint-parser")),
139
- getModuleDefault(import("typescript-eslint")),
140
- getModuleDefault(import("eslint-processor-vue-blocks"))
124
+ const [vuePlugin, vueParser, tsEsLint] = await Promise.all([
125
+ importModule(import("eslint-plugin-vue")),
126
+ importModule(import("vue-eslint-parser")),
127
+ importModule(import("typescript-eslint"))
141
128
  ]);
129
+ const inheritedRules = Object.assign({}, ...[
130
+ ...vuePlugin.configs["flat/essential"],
131
+ ...vuePlugin.configs["flat/strongly-recommended"],
132
+ ...vuePlugin.configs["flat/recommended"]
133
+ ].map((config) => config?.rules || {}));
142
134
  return [{
143
- name: "favorodera/vue/rules",
135
+ name: "favorodera/vue",
144
136
  plugins: { vue: vuePlugin },
145
137
  files: resolved.files,
146
138
  languageOptions: {
@@ -167,21 +159,9 @@ async function vue(options) {
167
159
  sourceType: "module"
168
160
  }
169
161
  },
170
- processor: sfcBlocks === false ? vuePlugin.processors[".vue"] : (0, eslint_merge_processors.mergeProcessors)([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]),
162
+ processor: sfcBlocks === false ? vuePlugin.processors[".vue"] : (0, eslint_merge_processors.mergeProcessors)([vuePlugin.processors[".vue"], (0, eslint_processor_vue_blocks.default)(sfcBlocks)]),
171
163
  rules: {
172
- ...vuePlugin.configs.base.rules,
173
- ...vuePlugin.configs["flat/essential"].map((config) => config.rules).reduce((accumulator, currentConfig) => ({
174
- ...accumulator,
175
- ...currentConfig
176
- }), {}),
177
- ...vuePlugin.configs["flat/strongly-recommended"].map((config) => config.rules).reduce((accumulator, currentConfig) => ({
178
- ...accumulator,
179
- ...currentConfig
180
- }), {}),
181
- ...vuePlugin.configs["flat/recommended"].map((config) => config.rules).reduce((accumulator, currentConfig) => ({
182
- ...accumulator,
183
- ...currentConfig
184
- }), {}),
164
+ ...inheritedRules,
185
165
  "vue/block-order": ["error", { order: [
186
166
  "script",
187
167
  "template",
@@ -203,43 +183,6 @@ async function vue(options) {
203
183
  }];
204
184
  }
205
185
  //#endregion
206
- //#region src/configs/typescript.ts
207
- const typescriptDefaults = { files: [tsGlob] };
208
- /**
209
- * Extract and merge rules from a compatible config array.
210
- * @param configs - Array of compatible ESLint configs
211
- * @returns Merged rules object from all configs
212
- */
213
- function extractRules(configs) {
214
- return Object.assign({}, ...configs.map((config) => config.rules || {}));
215
- }
216
- /**
217
- * Typescript linting via `typescript-eslint`.
218
- * @param options - TypeScript configuration options
219
- * @returns Promise resolving to TypeScript ESLint config items
220
- */
221
- async function typescript(options) {
222
- const resolved = (0, defu.defu)(options, typescriptDefaults);
223
- const tsEsLint = await getModuleDefault(import("typescript-eslint"));
224
- return [{
225
- name: "favorodera/typescript/rules",
226
- files: resolved.files,
227
- plugins: { ts: tsEsLint.plugin },
228
- languageOptions: {
229
- parser: tsEsLint.parser,
230
- parserOptions: { sourceType: "module" }
231
- },
232
- rules: {
233
- ...renameRules(extractRules(tsEsLint.configs.strict), { "@typescript-eslint": "ts" }),
234
- ...renameRules(extractRules(tsEsLint.configs.stylistic), { "@typescript-eslint": "ts" }),
235
- "ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
236
- "ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
237
- "ts/array-type": ["error", { default: "array" }],
238
- ...resolved.overrides
239
- }
240
- }];
241
- }
242
- //#endregion
243
186
  //#region src/configs/ignores.ts
244
187
  const defaultPatterns = ignoresGlob;
245
188
  /**
@@ -254,141 +197,25 @@ function ignores(patterns = []) {
254
197
  }];
255
198
  }
256
199
  //#endregion
257
- //#region src/configs/stylistic.ts
258
- const stylisticDefaults = {
259
- indent: 2,
260
- experimental: false,
261
- quotes: "single",
262
- semi: false,
263
- jsx: false
264
- };
265
- /**
266
- * Code style via `@stylistic/eslint-plugin`.
267
- * @param options - Stylistic configuration options
268
- * @returns Promise resolving to stylistic ESLint config items
269
- */
270
- async function stylistic(options) {
271
- const resolved = (0, defu.defu)(options, stylisticDefaults);
272
- const stylePlugin = await getModuleDefault(import("@stylistic/eslint-plugin"));
273
- const customizedStyleConfig = stylePlugin.configs.customize({
274
- pluginName: "style",
275
- ...resolved
276
- });
277
- return [{
278
- name: "favorodera/stylistic/rules",
279
- plugins: { style: stylePlugin },
280
- rules: {
281
- ...customizedStyleConfig.rules,
282
- "style/quotes": [
283
- "error",
284
- "single",
285
- { avoidEscape: true }
286
- ],
287
- "style/no-multiple-empty-lines": ["error", {
288
- max: 2,
289
- maxEOF: 2,
290
- maxBOF: 0
291
- }],
292
- "style/padded-blocks": "off",
293
- "style/no-trailing-spaces": ["error", { skipBlankLines: true }],
294
- "style/brace-style": "off",
295
- "style/generator-star-spacing": ["error", {
296
- after: true,
297
- before: false
298
- }],
299
- "style/yield-star-spacing": ["error", {
300
- after: true,
301
- before: false
302
- }],
303
- ...resolved.overrides
304
- }
305
- }];
306
- }
307
- //#endregion
308
- //#region src/configs/tailwind.ts
309
- const tailwindDefaults = {
310
- files: [
311
- jsGlob,
312
- tsGlob,
313
- vueGlob
314
- ],
315
- settings: { detectComponentClasses: true }
316
- };
317
- /**
318
- * Tailwind linting via `eslint-plugin-better-tailwindcss`.
319
- * @param options - Tailwind configuration options
320
- * @returns Promise resolving to Tailwind ESLint config items
321
- */
322
- async function tailwind(options) {
323
- const resolved = (0, defu.defu)(options, tailwindDefaults);
324
- const tailwindPlugin = await getModuleDefault(import("eslint-plugin-better-tailwindcss"));
325
- return [{
326
- name: "favorodera/tailwind/rules",
327
- plugins: { tailwind: tailwindPlugin },
328
- files: resolved.files,
329
- settings: { tailwindcss: resolved.settings },
330
- rules: {
331
- ...renameRules(tailwindPlugin.configs["recommended-error"].rules, { "better-tailwindcss": "tailwind" }),
332
- ...renameRules(tailwindPlugin.configs["stylistic-error"].rules, { "better-tailwindcss": "tailwind" }),
333
- "tailwind/no-unregistered-classes": "off",
334
- "tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
335
- ...resolved.overrides
336
- }
337
- }];
338
- }
339
- //#endregion
340
- //#region src/configs/comments.ts
341
- const commentsDefaults = { files: [
342
- jsGlob,
343
- tsGlob,
344
- vueGlob
345
- ] };
346
- /**
347
- * Comments linting via `@eslint-community/eslint-plugin-eslint-comments`
348
- * @param options - Comments configuration options
349
- * @returns Promise resolving to comments ESLint config items
350
- */
351
- async function comments(options) {
352
- const resolved = (0, defu.defu)(options, commentsDefaults);
353
- const commentsPlugin = await getModuleDefault(import("@eslint-community/eslint-plugin-eslint-comments"));
354
- return [{
355
- name: "favorodera/comments/rules",
356
- files: resolved.files,
357
- plugins: { comments: commentsPlugin },
358
- rules: {
359
- ...renameRules(commentsPlugin.configs.recommended?.rules || {}, { "@eslint-community/eslint-comments": "comments" }),
360
- "comments/no-aggregating-enable": "error",
361
- "comments/no-duplicate-disable": "error",
362
- "comments/no-unlimited-disable": "error",
363
- "comments/no-unused-enable": "error",
364
- ...resolved.overrides
365
- }
366
- }];
367
- }
368
- //#endregion
369
200
  //#region src/configs/imports.ts
370
201
  const importsDefaults = { files: [
371
202
  jsGlob,
372
203
  tsGlob,
373
204
  vueGlob
374
205
  ] };
375
- /**
376
- * Imports & unused imports linting via `eslint-plugin-import-lite` and `eslint-plugin-unused-imports`.
377
- * @param options - Imports & unused imports configuration options
378
- * @returns Promise resolving to imports & unused imports ESLint config items
379
- */
380
206
  async function imports(options) {
381
207
  const resolved = (0, defu.defu)(options, importsDefaults);
382
- const [importPlugin, unusedImportsPlugin] = await Promise.all([getModuleDefault(import("eslint-plugin-import-lite")), getModuleDefault(import("eslint-plugin-unused-imports"))]);
208
+ const [importPlugin, unusedImportsPlugin] = await Promise.all([importModule(import("eslint-plugin-import-lite")), importModule(import("eslint-plugin-unused-imports"))]);
209
+ const inheritedRules = importPlugin.configs.recommended?.rules || {};
383
210
  return [{
384
- name: "favorodera/imports/rules",
211
+ name: "favorodera/imports",
385
212
  files: resolved.files,
386
213
  plugins: {
387
214
  "import": importPlugin,
388
215
  "unused-imports": unusedImportsPlugin
389
216
  },
390
217
  rules: {
391
- ...renameRules(importPlugin.configs.recommended?.rules || {}, { "import-lite": "import" }),
218
+ ...(0, eslint_flat_config_utils.renamePluginsInRules)(inheritedRules, { "import-lite": "import" }),
392
219
  "import/consistent-type-specifier-style": ["error", "top-level"],
393
220
  "import/first": "error",
394
221
  "import/no-duplicates": "error",
@@ -408,34 +235,6 @@ async function imports(options) {
408
235
  }];
409
236
  }
410
237
  //#endregion
411
- //#region src/configs/markdown.ts
412
- const markdownDefaults = {
413
- files: [mdGlob],
414
- gfm: true
415
- };
416
- /**
417
- * Markdown linting via `@eslint/markdown`.
418
- * @param options - Markdown configuration options
419
- * @returns Promise resolving to Markdown ESLint config items
420
- */
421
- async function markdown(options) {
422
- const resolved = (0, defu.defu)(options, markdownDefaults);
423
- const markdownPlugin = await getModuleDefault(import("@eslint/markdown"));
424
- return [{
425
- name: "favorodera/markdown/rules",
426
- files: resolved.files,
427
- plugins: { md: markdownPlugin },
428
- processor: (0, eslint_merge_processors.mergeProcessors)([markdownPlugin.processors?.markdown, eslint_merge_processors.processorPassThrough]),
429
- language: resolved.gfm ? "md/gfm" : "md/commonmark",
430
- rules: {
431
- ...renameRules(markdownPlugin.configs.recommended[0]?.rules || {}, { markdown: "md" }),
432
- "md/fenced-code-language": "off",
433
- "md/no-missing-label-refs": "off",
434
- ...resolved.overrides
435
- }
436
- }];
437
- }
438
- //#endregion
439
238
  //#region src/configs/javascript.ts
440
239
  const javascriptDefaults = { files: [
441
240
  jsGlob,
@@ -449,9 +248,9 @@ const javascriptDefaults = { files: [
449
248
  */
450
249
  async function javascript(options) {
451
250
  const resolved = (0, defu.defu)(options, javascriptDefaults);
452
- const jsPlugin = await getModuleDefault(import("@eslint/js"));
251
+ const inheritedRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
453
252
  return [{
454
- name: "favorodera/javascript/rules",
253
+ name: "favorodera/javascript",
455
254
  files: resolved.files,
456
255
  languageOptions: {
457
256
  ecmaVersion: "latest",
@@ -466,189 +265,156 @@ async function javascript(options) {
466
265
  }
467
266
  },
468
267
  linterOptions: { reportUnusedDisableDirectives: true },
469
- plugins: { js: jsPlugin },
470
268
  rules: {
471
- ...jsPlugin.configs.recommended.rules,
269
+ ...inheritedRules,
472
270
  "accessor-pairs": ["error", {
473
271
  enforceForClassMembers: true,
474
272
  setWithoutGet: true
475
273
  }],
476
274
  "array-callback-return": "error",
477
275
  "block-scoped-var": "error",
478
- "constructor-super": "error",
479
- "default-case-last": "error",
480
- "dot-notation": ["error", { allowKeywords: true }],
481
- "eqeqeq": ["error", "smart"],
482
- "new-cap": ["error", {
483
- capIsNew: false,
484
- newIsCap: true,
485
- properties: true
486
- }],
487
- "no-alert": "error",
488
- "no-array-constructor": "error",
489
- "no-async-promise-executor": "error",
490
- "no-caller": "error",
491
- "no-case-declarations": "error",
492
- "no-class-assign": "error",
493
- "no-compare-neg-zero": "error",
494
- "no-cond-assign": ["error", "always"],
495
- "no-console": ["error", { allow: ["warn", "error"] }],
496
- "no-const-assign": "error",
497
- "no-control-regex": "error",
498
- "no-debugger": "error",
499
- "no-delete-var": "error",
500
- "no-dupe-args": "error",
501
- "no-dupe-class-members": "error",
502
- "no-dupe-keys": "error",
503
- "no-duplicate-case": "error",
504
- "no-empty": ["error", { allowEmptyCatch: true }],
505
- "no-empty-character-class": "error",
506
- "no-empty-pattern": "error",
507
- "no-eval": "error",
508
- "no-ex-assign": "error",
509
- "no-extend-native": "error",
510
- "no-extra-bind": "error",
511
- "no-extra-boolean-cast": "error",
512
- "no-fallthrough": "error",
513
- "no-func-assign": "error",
514
- "no-global-assign": "error",
515
- "no-implied-eval": "error",
516
- "no-import-assign": "error",
517
- "no-invalid-regexp": "error",
518
- "no-irregular-whitespace": "error",
519
- "no-iterator": "error",
520
- "no-labels": ["error", {
521
- allowLoop: false,
522
- allowSwitch: false
523
- }],
524
- "no-lone-blocks": "error",
525
- "no-loss-of-precision": "error",
526
- "no-misleading-character-class": "error",
527
- "no-multi-str": "error",
528
- "no-new": "error",
529
- "no-new-func": "error",
530
- "no-new-native-nonconstructor": "error",
531
- "no-new-wrappers": "error",
532
- "no-obj-calls": "error",
533
- "no-octal": "error",
534
- "no-octal-escape": "error",
535
- "no-proto": "error",
536
- "no-prototype-builtins": "error",
537
- "no-redeclare": ["error", { builtinGlobals: false }],
538
- "no-regex-spaces": "error",
539
- "no-restricted-globals": [
540
- "error",
541
- {
542
- message: "Use `globalThis` instead.",
543
- name: "global"
544
- },
545
- {
546
- message: "Use `globalThis` instead.",
547
- name: "self"
548
- }
549
- ],
550
- "no-restricted-properties": [
551
- "error",
552
- {
553
- message: "Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.",
554
- property: "__proto__"
555
- },
556
- {
557
- message: "Use `Object.defineProperty` instead.",
558
- property: "__defineGetter__"
559
- },
560
- {
561
- message: "Use `Object.defineProperty` instead.",
562
- property: "__defineSetter__"
563
- },
564
- {
565
- message: "Use `Object.getOwnPropertyDescriptor` instead.",
566
- property: "__lookupGetter__"
567
- },
568
- {
569
- message: "Use `Object.getOwnPropertyDescriptor` instead.",
570
- property: "__lookupSetter__"
571
- }
572
- ],
573
- "no-restricted-syntax": [
574
- "error",
575
- "TSEnumDeclaration[const=true]",
576
- "TSExportAssignment"
577
- ],
578
- "no-self-assign": ["error", { props: true }],
579
- "no-self-compare": "error",
580
- "no-sequences": "error",
581
- "no-shadow-restricted-names": "error",
582
- "no-sparse-arrays": "error",
583
- "no-template-curly-in-string": "error",
584
- "no-this-before-super": "error",
585
- "no-throw-literal": "error",
586
- "no-undef": "error",
587
- "no-undef-init": "error",
588
- "no-unexpected-multiline": "error",
589
- "no-unmodified-loop-condition": "error",
590
- "no-unneeded-ternary": ["error", { defaultAssignment: false }],
591
- "no-unreachable": "error",
592
- "no-unreachable-loop": "error",
593
- "no-unsafe-finally": "error",
594
- "no-unsafe-negation": "error",
595
- "no-unused-expressions": ["error", {
596
- allowShortCircuit: true,
597
- allowTaggedTemplates: true,
598
- allowTernary: true
599
- }],
600
- "no-unused-vars": ["error", {
601
- args: "none",
602
- caughtErrors: "none",
603
- ignoreRestSiblings: true,
604
- vars: "all"
605
- }],
606
- "no-use-before-define": ["error", {
607
- classes: false,
608
- functions: false,
609
- variables: true
610
- }],
611
- "no-useless-backreference": "error",
612
- "no-useless-call": "error",
613
- "no-useless-catch": "error",
614
- "no-useless-computed-key": "error",
615
- "no-useless-constructor": "error",
616
- "no-useless-rename": "error",
617
- "no-useless-return": "error",
618
- "no-var": "error",
619
- "no-with": "error",
620
- "object-shorthand": [
276
+ ...resolved.overrides
277
+ }
278
+ }];
279
+ }
280
+ //#endregion
281
+ //#region src/configs/markdown.ts
282
+ const markdownDefaults = {
283
+ files: [mdGlob],
284
+ gfm: true
285
+ };
286
+ async function markdown(options) {
287
+ const resolved = (0, defu.defu)(options, markdownDefaults);
288
+ const markdownPlugin = await importModule(import("@eslint/markdown"));
289
+ const inheritedRules = Object.assign({}, ...[...markdownPlugin.configs.recommended].map((config) => config?.rules || {}));
290
+ return [{
291
+ name: "favorodera/markdown",
292
+ files: resolved.files,
293
+ plugins: { md: markdownPlugin },
294
+ processor: (0, eslint_merge_processors.mergeProcessors)([markdownPlugin.processors?.markdown, eslint_merge_processors.processorPassThrough]),
295
+ language: resolved.gfm ? "md/gfm" : "md/commonmark",
296
+ rules: {
297
+ ...(0, eslint_flat_config_utils.renamePluginsInRules)(inheritedRules, { markdown: "md" }),
298
+ "md/fenced-code-language": "off",
299
+ "md/no-missing-label-refs": "off",
300
+ ...resolved.overrides
301
+ }
302
+ }];
303
+ }
304
+ //#endregion
305
+ //#region src/configs/stylistic.ts
306
+ const stylisticDefaults = {
307
+ settings: {
308
+ indent: 2,
309
+ experimental: false,
310
+ quotes: "single",
311
+ semi: false,
312
+ jsx: false
313
+ },
314
+ files: [
315
+ jsGlob,
316
+ tsGlob,
317
+ vueGlob
318
+ ]
319
+ };
320
+ async function stylistic(options) {
321
+ const resolved = (0, defu.defu)(options, stylisticDefaults);
322
+ const config = (await importModule(import("@stylistic/eslint-plugin"))).configs.customize({
323
+ pluginName: "style",
324
+ ...resolved.settings
325
+ });
326
+ const inheritedRules = config?.rules || {};
327
+ return [{
328
+ ...config,
329
+ name: "favorodera/stylistic",
330
+ files: resolved.files,
331
+ rules: {
332
+ ...inheritedRules,
333
+ "style/quotes": [
621
334
  "error",
622
- "always",
623
- {
624
- avoidQuotes: true,
625
- ignoreConstructors: false
626
- }
335
+ "single",
336
+ { avoidEscape: true }
627
337
  ],
628
- "one-var": ["error", { initialized: "never" }],
629
- "prefer-arrow-callback": ["error", {
630
- allowNamedFunctions: false,
631
- allowUnboundThis: true
338
+ "style/no-multiple-empty-lines": ["error", {
339
+ max: 2,
340
+ maxEOF: 2,
341
+ maxBOF: 0
632
342
  }],
633
- "prefer-const": ["error", {
634
- destructuring: "all",
635
- ignoreReadBeforeAssign: true
343
+ "style/padded-blocks": "off",
344
+ "style/no-trailing-spaces": ["error", { skipBlankLines: true }],
345
+ "style/brace-style": "off",
346
+ "style/generator-star-spacing": ["error", {
347
+ after: true,
348
+ before: false
636
349
  }],
637
- "prefer-exponentiation-operator": "error",
638
- "prefer-promise-reject-errors": "error",
639
- "prefer-regex-literals": ["error", { disallowRedundantWrapping: true }],
640
- "prefer-rest-params": "error",
641
- "prefer-spread": "error",
642
- "prefer-template": "error",
643
- "symbol-description": "error",
644
- "unicode-bom": ["error", "never"],
645
- "use-isnan": ["error", {
646
- enforceForIndexOf: true,
647
- enforceForSwitchCase: true
350
+ "style/yield-star-spacing": ["error", {
351
+ after: true,
352
+ before: false
648
353
  }],
649
- "valid-typeof": ["error", { requireStringLiterals: true }],
650
- "vars-on-top": "error",
651
- "yoda": ["error", "never"],
354
+ ...resolved.overrides
355
+ }
356
+ }];
357
+ }
358
+ //#endregion
359
+ //#region src/configs/tailwind.ts
360
+ const tailwindDefaults = {
361
+ files: [
362
+ jsGlob,
363
+ tsGlob,
364
+ vueGlob
365
+ ],
366
+ settings: { detectComponentClasses: true }
367
+ };
368
+ /**
369
+ * Tailwind linting via `eslint-plugin-better-tailwindcss`.
370
+ * @param options - Tailwind configuration options
371
+ * @returns Promise resolving to Tailwind ESLint config items
372
+ */
373
+ async function tailwind(options) {
374
+ const resolved = (0, defu.defu)(options, tailwindDefaults);
375
+ const tailwindPlugin = await importModule(import("eslint-plugin-better-tailwindcss"));
376
+ const inheritedRules = {
377
+ ...tailwindPlugin.configs["recommended-error"].rules,
378
+ ...tailwindPlugin.configs["stylistic-error"].rules
379
+ };
380
+ return [{
381
+ name: "favorodera/tailwind",
382
+ files: resolved.files,
383
+ plugins: { tailwind: tailwindPlugin },
384
+ settings: { tailwindcss: resolved.settings },
385
+ rules: {
386
+ ...(0, eslint_flat_config_utils.renamePluginsInRules)(inheritedRules, { "better-tailwindcss": "tailwind" }),
387
+ "tailwind/no-unregistered-classes": "off",
388
+ "tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
389
+ ...resolved.overrides
390
+ }
391
+ }];
392
+ }
393
+ //#endregion
394
+ //#region src/configs/typescript.ts
395
+ const typescriptDefaults = { files: [tsGlob] };
396
+ /**
397
+ * Typescript linting via `typescript-eslint`.
398
+ * @param options - TypeScript configuration options
399
+ * @returns Array of TypeScript ESLint config items
400
+ */
401
+ async function typescript(options) {
402
+ const resolved = (0, defu.defu)(options, typescriptDefaults);
403
+ const tsEsLint = await importModule(import("typescript-eslint"));
404
+ const inheritedRules = Object.assign({}, ...[...tsEsLint.configs.recommended, ...tsEsLint.configs.strict].map((config) => config?.rules || {}));
405
+ return [{
406
+ name: "favorodera/typescript",
407
+ plugins: { ts: tsEsLint.plugin },
408
+ languageOptions: {
409
+ parser: tsEsLint.parser,
410
+ parserOptions: { sourceType: "module" }
411
+ },
412
+ files: resolved.files,
413
+ rules: {
414
+ ...(0, eslint_flat_config_utils.renamePluginsInRules)(inheritedRules, { "@typescript-eslint": "ts" }),
415
+ "ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
416
+ "ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
417
+ "ts/array-type": ["error", { default: "array" }],
652
418
  ...resolved.overrides
653
419
  }
654
420
  }];
@@ -663,27 +429,29 @@ async function javascript(options) {
663
429
  function factory(options = {}) {
664
430
  const configs = [];
665
431
  configs.push(ignores(options.ignores));
666
- const vueOptions = resolveOptions(options.vue, {});
667
- const typescriptOptions = resolveOptions(options.typescript, {});
668
- const stylisticOptions = resolveOptions(options.stylistic, {});
669
- const tailwindOptions = resolveOptions(options.tailwind, {});
670
- const commentsOptions = resolveOptions(options.comments, {});
671
- const importsOptions = resolveOptions(options.imports, {});
672
- const markdownOptions = resolveOptions(options.markdown, {});
673
- const javascriptOptions = resolveOptions(options.javascript, {});
674
- if (vueOptions) configs.push(vue(vueOptions));
675
- if (typescriptOptions) configs.push(typescript(typescriptOptions));
676
- if (stylisticOptions) configs.push(stylistic(stylisticOptions));
677
- if (tailwindOptions) configs.push(tailwind(tailwindOptions));
678
- if (commentsOptions) configs.push(comments(commentsOptions));
679
- if (importsOptions) configs.push(imports(importsOptions));
680
- if (markdownOptions) configs.push(markdown(markdownOptions));
681
- if (javascriptOptions) configs.push(javascript(javascriptOptions));
432
+ const configFunctions = {
433
+ vue,
434
+ typescript,
435
+ stylistic,
436
+ tailwind,
437
+ imports,
438
+ markdown,
439
+ javascript
440
+ };
441
+ for (const [key, configFunction] of Object.entries(configFunctions)) {
442
+ const configOption = options[key];
443
+ const resolved = resolveOptions(configOption ?? true, {});
444
+ if (resolved) configs.push(configFunction(resolved));
445
+ }
682
446
  let composer = new eslint_flat_config_utils.FlatConfigComposer();
683
- composer = composer.append(...configs);
447
+ composer = composer.append(...configs).renamePlugins({
448
+ "better-tailwindcss": "tailwind",
449
+ "@typescript-eslint": "ts",
450
+ "markdown": "md",
451
+ "import-lite": "import"
452
+ });
684
453
  return composer;
685
454
  }
686
455
  //#endregion
687
456
  exports.factory = factory;
688
- exports.getModuleDefault = getModuleDefault;
689
- exports.renameRules = renameRules;
457
+ exports.importModule = importModule;