@favorodera/eslint-config 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4,18 +4,17 @@ 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 */
8
7
  const jsGlob = "**/*.{js,cjs,mjs}";
9
- /** Glob pattern for TypeScript linting */
10
8
  const tsGlob = "**/*.{ts,cts,mts}";
11
- /** Glob pattern for Vue linting */
12
9
  const vueGlob = "**/*.vue";
13
- /** Glob pattern for Markdown linting */
14
10
  const mdGlob = "**/*.md";
15
- /**
16
- * Default glob patterns for files and directories to ignore
17
- * Includes common build outputs, dependencies, caches, and temporary files
18
- */
11
+ const mdInMdGlob = "**/*.md/*.md";
12
+ const codeInMdGlob = "**/*.md/**/*.{js,cjs,mjs,ts,cts,mts,vue}";
13
+ const jsonGlob = "**/*.json";
14
+ const json5Glob = "**/*.json5";
15
+ const jsoncGlob = "**/*.jsonc";
16
+ const tsConfigGlob = ["**/tsconfig.json", "**/tsconfig.*.json"];
17
+ const packageJsonGlob = "**/package.json";
19
18
  const ignoresGlob = [
20
19
  "**/node_modules/**",
21
20
  "**/dist/**",
@@ -82,6 +81,9 @@ function resolveOptions(value, defaults) {
82
81
  if (!value) return false;
83
82
  return defu(value === true ? {} : value, defaults);
84
83
  }
84
+ function extractRules(...configArrays) {
85
+ return Object.assign({}, ...configArrays.flat().map((config) => config?.rules || {}));
86
+ }
85
87
  //#endregion
86
88
  //#region src/configs/vue.ts
87
89
  const sfcBlocksDefaults = { blocks: {
@@ -101,32 +103,31 @@ async function vue(options) {
101
103
  importModule(import("vue-eslint-parser")),
102
104
  importModule(import("typescript-eslint"))
103
105
  ]);
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 || {}));
106
+ const baseRules = extractRules(vuePlugin.configs["flat/essential"], vuePlugin.configs["flat/strongly-recommended"], vuePlugin.configs["flat/recommended"]);
107
+ const processor = sfcBlocks === false ? vuePlugin.processors[".vue"] : mergeProcessors([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]);
109
108
  return [{
110
- name: "favorodera/vue",
109
+ name: "favorodera/vue/setup",
111
110
  plugins: { vue: vuePlugin },
111
+ languageOptions: { globals: {
112
+ computed: "readonly",
113
+ defineEmits: "readonly",
114
+ defineExpose: "readonly",
115
+ defineProps: "readonly",
116
+ onMounted: "readonly",
117
+ onUnmounted: "readonly",
118
+ reactive: "readonly",
119
+ ref: "readonly",
120
+ shallowReactive: "readonly",
121
+ shallowRef: "readonly",
122
+ toRef: "readonly",
123
+ toRefs: "readonly",
124
+ watch: "readonly",
125
+ watchEffect: "readonly"
126
+ } }
127
+ }, {
128
+ name: "favorodera/vue/rules",
112
129
  files: resolved.files,
113
130
  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
131
  parser: vueParser,
131
132
  parserOptions: {
132
133
  parser: tsEsLint.parser,
@@ -134,9 +135,9 @@ async function vue(options) {
134
135
  sourceType: "module"
135
136
  }
136
137
  },
137
- processor: sfcBlocks === false ? vuePlugin.processors[".vue"] : mergeProcessors([vuePlugin.processors[".vue"], vueBlocksProcessor(sfcBlocks)]),
138
+ processor,
138
139
  rules: {
139
- ...inheritedRules,
140
+ ...baseRules,
140
141
  "vue/block-order": ["error", { order: [
141
142
  "script",
142
143
  "template",
@@ -181,16 +182,18 @@ const importsDefaults = { files: [
181
182
  async function imports(options) {
182
183
  const resolved = defu(options, importsDefaults);
183
184
  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 || {};
185
+ const baseRules = importPlugin.configs.recommended?.rules || {};
185
186
  return [{
186
- name: "favorodera/imports",
187
- files: resolved.files,
187
+ name: "favorodera/imports/setup",
188
188
  plugins: {
189
189
  "import": importPlugin,
190
190
  "unused-imports": unusedImportsPlugin
191
- },
191
+ }
192
+ }, {
193
+ name: "favorodera/imports/rules",
194
+ files: resolved.files,
192
195
  rules: {
193
- ...renamePluginsInRules(inheritedRules, { "import-lite": "import" }),
196
+ ...renamePluginsInRules(baseRules, { "import-lite": "import" }),
194
197
  "import/consistent-type-specifier-style": ["error", "top-level"],
195
198
  "import/first": "error",
196
199
  "import/no-duplicates": "error",
@@ -223,10 +226,9 @@ const javascriptDefaults = { files: [
223
226
  */
224
227
  async function javascript(options) {
225
228
  const resolved = defu(options, javascriptDefaults);
226
- const inheritedRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
229
+ const baseRules = (await importModule(import("@eslint/js"))).configs.recommended.rules;
227
230
  return [{
228
- name: "favorodera/javascript",
229
- files: resolved.files,
231
+ name: "favorodera/javascript/setup",
230
232
  languageOptions: {
231
233
  ecmaVersion: "latest",
232
234
  sourceType: "module",
@@ -239,9 +241,12 @@ async function javascript(options) {
239
241
  window: "readonly"
240
242
  }
241
243
  },
242
- linterOptions: { reportUnusedDisableDirectives: true },
244
+ linterOptions: { reportUnusedDisableDirectives: true }
245
+ }, {
246
+ name: "favorodera/javascript/rules",
247
+ files: resolved.files,
243
248
  rules: {
244
- ...inheritedRules,
249
+ ...baseRules,
245
250
  "accessor-pairs": ["error", {
246
251
  enforceForClassMembers: true,
247
252
  setWithoutGet: true
@@ -261,20 +266,57 @@ const markdownDefaults = {
261
266
  async function markdown(options) {
262
267
  const resolved = defu(options, markdownDefaults);
263
268
  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
269
+ const baseRules = extractRules(markdownPlugin.configs.recommended);
270
+ return [
271
+ {
272
+ name: "favorodera/markdown/setup",
273
+ plugins: { md: markdownPlugin }
274
+ },
275
+ {
276
+ name: "favorodera/markdown/rules",
277
+ files: resolved.files,
278
+ language: resolved.gfm ? "md/gfm" : "md/commonmark",
279
+ ignores: [mdInMdGlob],
280
+ processor: mergeProcessors([markdownPlugin.processors?.markdown, processorPassThrough]),
281
+ rules: {
282
+ ...renamePluginsInRules(baseRules, { markdown: "md" }),
283
+ "md/fenced-code-language": "off",
284
+ "md/no-missing-label-refs": "off",
285
+ ...resolved.overrides
286
+ }
287
+ },
288
+ {
289
+ name: "favorodera/markdown/disables/code",
290
+ files: [codeInMdGlob],
291
+ languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
292
+ rules: {
293
+ "no-alert": "off",
294
+ "no-console": "off",
295
+ "no-labels": "off",
296
+ "no-lone-blocks": "off",
297
+ "no-restricted-syntax": "off",
298
+ "no-undef": "off",
299
+ "no-unused-expressions": "off",
300
+ "no-unused-labels": "off",
301
+ "no-unused-vars": "off",
302
+ "node/prefer-global/process": "off",
303
+ "style/comma-dangle": "off",
304
+ "style/eol-last": "off",
305
+ "style/padding-line-between-statements": "off",
306
+ "ts/consistent-type-imports": "off",
307
+ "ts/explicit-function-return-type": "off",
308
+ "ts/no-namespace": "off",
309
+ "ts/no-redeclare": "off",
310
+ "ts/no-require-imports": "off",
311
+ "ts/no-unused-expressions": "off",
312
+ "ts/no-unused-vars": "off",
313
+ "ts/no-use-before-define": "off",
314
+ "unicode-bom": "off",
315
+ "unused-imports/no-unused-imports": "off",
316
+ "unused-imports/no-unused-vars": "off"
317
+ }
276
318
  }
277
- }];
319
+ ];
278
320
  }
279
321
  //#endregion
280
322
  //#region src/configs/stylistic.ts
@@ -294,17 +336,19 @@ const stylisticDefaults = {
294
336
  };
295
337
  async function stylistic(options) {
296
338
  const resolved = defu(options, stylisticDefaults);
297
- const config = (await importModule(import("@stylistic/eslint-plugin"))).configs.customize({
339
+ const stylePlugin = await importModule(import("@stylistic/eslint-plugin"));
340
+ const baseRules = stylePlugin.configs.customize({
298
341
  pluginName: "style",
299
342
  ...resolved.settings
300
- });
301
- const inheritedRules = config?.rules || {};
343
+ })?.rules || {};
302
344
  return [{
303
- ...config,
304
- name: "favorodera/stylistic",
345
+ name: "favorodera/stylistic/setup",
346
+ plugins: { style: stylePlugin }
347
+ }, {
348
+ name: "favorodera/stylistic/rules",
305
349
  files: resolved.files,
306
350
  rules: {
307
- ...inheritedRules,
351
+ ...baseRules,
308
352
  "style/quotes": [
309
353
  "error",
310
354
  "single",
@@ -348,17 +392,19 @@ const tailwindDefaults = {
348
392
  async function tailwind(options) {
349
393
  const resolved = defu(options, tailwindDefaults);
350
394
  const tailwindPlugin = await importModule(import("eslint-plugin-better-tailwindcss"));
351
- const inheritedRules = {
395
+ const baseRules = {
352
396
  ...tailwindPlugin.configs["recommended-error"].rules,
353
397
  ...tailwindPlugin.configs["stylistic-error"].rules
354
398
  };
355
399
  return [{
356
- name: "favorodera/tailwind",
357
- files: resolved.files,
400
+ name: "favorodera/tailwind/setup",
358
401
  plugins: { tailwind: tailwindPlugin },
359
- settings: { tailwindcss: resolved.settings },
402
+ settings: { tailwindcss: resolved.settings }
403
+ }, {
404
+ name: "favorodera/tailwind/rules",
405
+ files: resolved.files,
360
406
  rules: {
361
- ...renamePluginsInRules(inheritedRules, { "better-tailwindcss": "tailwind" }),
407
+ ...renamePluginsInRules(baseRules, { "better-tailwindcss": "tailwind" }),
362
408
  "tailwind/no-unregistered-classes": "off",
363
409
  "tailwind/enforce-consistent-line-wrapping": ["error", { group: "emptyLine" }],
364
410
  ...resolved.overrides
@@ -376,25 +422,313 @@ const typescriptDefaults = { files: [tsGlob] };
376
422
  async function typescript(options) {
377
423
  const resolved = defu(options, typescriptDefaults);
378
424
  const tsEsLint = await importModule(import("typescript-eslint"));
379
- const inheritedRules = Object.assign({}, ...[...tsEsLint.configs.recommended, ...tsEsLint.configs.strict].map((config) => config?.rules || {}));
425
+ const baseRules = extractRules(tsEsLint.configs.recommended, tsEsLint.configs.strict);
380
426
  return [{
381
- name: "favorodera/typescript",
382
- plugins: { ts: tsEsLint.plugin },
427
+ name: "favorodera/typescript/setup",
428
+ plugins: { ts: tsEsLint.plugin }
429
+ }, {
430
+ name: "favorodera/typescript/rules",
431
+ files: resolved.files,
383
432
  languageOptions: {
384
433
  parser: tsEsLint.parser,
385
434
  parserOptions: { sourceType: "module" }
386
435
  },
387
- files: resolved.files,
388
436
  rules: {
389
- ...renamePluginsInRules(inheritedRules, { "@typescript-eslint": "ts" }),
437
+ ...renamePluginsInRules(baseRules, { "@typescript-eslint": "ts" }),
390
438
  "ts/consistent-type-imports": ["error", { prefer: "type-imports" }],
391
439
  "ts/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
392
- "ts/array-type": ["error", { default: "array" }],
440
+ "ts/array-type": ["error", {
441
+ default: "generic",
442
+ readonly: "generic"
443
+ }],
393
444
  ...resolved.overrides
394
445
  }
395
446
  }];
396
447
  }
397
448
  //#endregion
449
+ //#region src/configs/jsonc.ts
450
+ const jsoncDefaults = { files: [
451
+ json5Glob,
452
+ jsoncGlob,
453
+ jsonGlob
454
+ ] };
455
+ async function jsonc(options) {
456
+ const resolved = defu(options, jsoncDefaults);
457
+ return [
458
+ {
459
+ name: "favorodera/jsonc/setup",
460
+ plugins: { jsonc: await importModule(import("eslint-plugin-jsonc")) }
461
+ },
462
+ {
463
+ name: "favorodera/jsonc/rules",
464
+ files: resolved.files,
465
+ language: "jsonc/x",
466
+ rules: {
467
+ "jsonc/no-bigint-literals": "error",
468
+ "jsonc/no-binary-expression": "error",
469
+ "jsonc/no-binary-numeric-literals": "error",
470
+ "jsonc/no-dupe-keys": "error",
471
+ "jsonc/no-escape-sequence-in-identifier": "error",
472
+ "jsonc/no-floating-decimal": "error",
473
+ "jsonc/no-hexadecimal-numeric-literals": "error",
474
+ "jsonc/no-infinity": "error",
475
+ "jsonc/no-multi-str": "error",
476
+ "jsonc/no-nan": "error",
477
+ "jsonc/no-number-props": "error",
478
+ "jsonc/no-numeric-separators": "error",
479
+ "jsonc/no-octal": "error",
480
+ "jsonc/no-octal-escape": "error",
481
+ "jsonc/no-octal-numeric-literals": "error",
482
+ "jsonc/no-parenthesized": "error",
483
+ "jsonc/no-plus-sign": "error",
484
+ "jsonc/no-regexp-literals": "error",
485
+ "jsonc/no-sparse-arrays": "error",
486
+ "jsonc/no-template-literals": "error",
487
+ "jsonc/no-undefined-value": "error",
488
+ "jsonc/no-unicode-codepoint-escapes": "error",
489
+ "jsonc/no-useless-escape": "error",
490
+ "jsonc/space-unary-ops": "error",
491
+ "jsonc/valid-json-number": "error",
492
+ "jsonc/vue-custom-block/no-parsing-error": "error",
493
+ "jsonc/array-bracket-spacing": ["error", "never"],
494
+ "jsonc/comma-dangle": ["error", "never"],
495
+ "jsonc/comma-style": ["error", "last"],
496
+ "jsonc/indent": ["error", 2],
497
+ "jsonc/key-spacing": ["error", {
498
+ afterColon: true,
499
+ beforeColon: false
500
+ }],
501
+ "jsonc/object-curly-newline": ["error", {
502
+ consistent: true,
503
+ multiline: true
504
+ }],
505
+ "jsonc/object-curly-spacing": ["error", "always"],
506
+ "jsonc/object-property-newline": ["error", { allowAllPropertiesOnSameLine: true }],
507
+ "jsonc/quote-props": "error",
508
+ "jsonc/quotes": "error",
509
+ ...resolved.overrides
510
+ }
511
+ },
512
+ {
513
+ name: "favorodera/jsonc/sort/package-json",
514
+ files: [packageJsonGlob],
515
+ rules: {
516
+ "jsonc/sort-array-values": ["error", {
517
+ order: { type: "asc" },
518
+ pathPattern: "^files$"
519
+ }],
520
+ "jsonc/sort-keys": [
521
+ "error",
522
+ {
523
+ order: [
524
+ "publisher",
525
+ "name",
526
+ "displayName",
527
+ "type",
528
+ "version",
529
+ "private",
530
+ "packageManager",
531
+ "description",
532
+ "author",
533
+ "contributors",
534
+ "license",
535
+ "funding",
536
+ "homepage",
537
+ "repository",
538
+ "bugs",
539
+ "keywords",
540
+ "categories",
541
+ "sideEffects",
542
+ "imports",
543
+ "exports",
544
+ "main",
545
+ "module",
546
+ "unpkg",
547
+ "jsdelivr",
548
+ "types",
549
+ "typesVersions",
550
+ "bin",
551
+ "icon",
552
+ "files",
553
+ "engines",
554
+ "activationEvents",
555
+ "contributes",
556
+ "scripts",
557
+ "peerDependencies",
558
+ "peerDependenciesMeta",
559
+ "dependencies",
560
+ "optionalDependencies",
561
+ "devDependencies",
562
+ "pnpm",
563
+ "overrides",
564
+ "resolutions",
565
+ "husky",
566
+ "simple-git-hooks",
567
+ "lint-staged",
568
+ "eslintConfig"
569
+ ],
570
+ pathPattern: "^$"
571
+ },
572
+ {
573
+ order: { type: "asc" },
574
+ pathPattern: "^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$"
575
+ },
576
+ {
577
+ order: { type: "asc" },
578
+ pathPattern: "^(?:resolutions|overrides|pnpm.overrides)$"
579
+ },
580
+ {
581
+ order: { type: "asc" },
582
+ pathPattern: "^workspaces\\.catalog$"
583
+ },
584
+ {
585
+ order: { type: "asc" },
586
+ pathPattern: "^workspaces\\.catalogs\\.[^.]+$"
587
+ },
588
+ {
589
+ order: [
590
+ "types",
591
+ "import",
592
+ "require",
593
+ "default"
594
+ ],
595
+ pathPattern: "^exports.*$"
596
+ },
597
+ {
598
+ order: [
599
+ "pre-commit",
600
+ "prepare-commit-msg",
601
+ "commit-msg",
602
+ "post-commit",
603
+ "pre-rebase",
604
+ "post-rewrite",
605
+ "post-checkout",
606
+ "post-merge",
607
+ "pre-push",
608
+ "pre-auto-gc"
609
+ ],
610
+ pathPattern: "^(?:gitHooks|husky|simple-git-hooks)$"
611
+ }
612
+ ]
613
+ }
614
+ },
615
+ {
616
+ name: "favorodera/jsonc/sort/tsconfig-json",
617
+ files: tsConfigGlob,
618
+ rules: { "jsonc/sort-keys": [
619
+ "error",
620
+ {
621
+ order: [
622
+ "extends",
623
+ "compilerOptions",
624
+ "references",
625
+ "files",
626
+ "include",
627
+ "exclude"
628
+ ],
629
+ pathPattern: "^$"
630
+ },
631
+ {
632
+ order: [
633
+ "incremental",
634
+ "composite",
635
+ "tsBuildInfoFile",
636
+ "disableSourceOfProjectReferenceRedirect",
637
+ "disableSolutionSearching",
638
+ "disableReferencedProjectLoad",
639
+ "target",
640
+ "jsx",
641
+ "jsxFactory",
642
+ "jsxFragmentFactory",
643
+ "jsxImportSource",
644
+ "lib",
645
+ "moduleDetection",
646
+ "noLib",
647
+ "reactNamespace",
648
+ "useDefineForClassFields",
649
+ "emitDecoratorMetadata",
650
+ "experimentalDecorators",
651
+ "libReplacement",
652
+ "baseUrl",
653
+ "rootDir",
654
+ "rootDirs",
655
+ "customConditions",
656
+ "module",
657
+ "moduleResolution",
658
+ "moduleSuffixes",
659
+ "noResolve",
660
+ "paths",
661
+ "resolveJsonModule",
662
+ "resolvePackageJsonExports",
663
+ "resolvePackageJsonImports",
664
+ "typeRoots",
665
+ "types",
666
+ "allowArbitraryExtensions",
667
+ "allowImportingTsExtensions",
668
+ "allowUmdGlobalAccess",
669
+ "allowJs",
670
+ "checkJs",
671
+ "maxNodeModuleJsDepth",
672
+ "strict",
673
+ "strictBindCallApply",
674
+ "strictFunctionTypes",
675
+ "strictNullChecks",
676
+ "strictPropertyInitialization",
677
+ "allowUnreachableCode",
678
+ "allowUnusedLabels",
679
+ "alwaysStrict",
680
+ "exactOptionalPropertyTypes",
681
+ "noFallthroughCasesInSwitch",
682
+ "noImplicitAny",
683
+ "noImplicitOverride",
684
+ "noImplicitReturns",
685
+ "noImplicitThis",
686
+ "noPropertyAccessFromIndexSignature",
687
+ "noUncheckedIndexedAccess",
688
+ "noUnusedLocals",
689
+ "noUnusedParameters",
690
+ "useUnknownInCatchVariables",
691
+ "declaration",
692
+ "declarationDir",
693
+ "declarationMap",
694
+ "downlevelIteration",
695
+ "emitBOM",
696
+ "emitDeclarationOnly",
697
+ "importHelpers",
698
+ "importsNotUsedAsValues",
699
+ "inlineSourceMap",
700
+ "inlineSources",
701
+ "mapRoot",
702
+ "newLine",
703
+ "noEmit",
704
+ "noEmitHelpers",
705
+ "noEmitOnError",
706
+ "outDir",
707
+ "outFile",
708
+ "preserveConstEnums",
709
+ "preserveValueImports",
710
+ "removeComments",
711
+ "sourceMap",
712
+ "sourceRoot",
713
+ "stripInternal",
714
+ "allowSyntheticDefaultImports",
715
+ "esModuleInterop",
716
+ "forceConsistentCasingInFileNames",
717
+ "isolatedDeclarations",
718
+ "isolatedModules",
719
+ "preserveSymlinks",
720
+ "verbatimModuleSyntax",
721
+ "erasableSyntaxOnly",
722
+ "skipDefaultLibCheck",
723
+ "skipLibCheck"
724
+ ],
725
+ pathPattern: "^compilerOptions$"
726
+ }
727
+ ] }
728
+ }
729
+ ];
730
+ }
731
+ //#endregion
398
732
  //#region src/factory.ts
399
733
  /**
400
734
  * Factory to create a flat ESLint config
@@ -411,7 +745,8 @@ function factory(options = {}) {
411
745
  tailwind,
412
746
  imports,
413
747
  markdown,
414
- javascript
748
+ javascript,
749
+ jsonc
415
750
  };
416
751
  for (const [key, configFunction] of Object.entries(configFunctions)) {
417
752
  const configOption = options[key];