@favorodera/eslint-config 0.0.3 → 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/README.md CHANGED
@@ -1 +1,144 @@
1
- # Eslint Config
1
+ <div align="center">
2
+ <h1>ESLint Config</h1>
3
+ <p><strong>Opinionated, type-safe flat ESLint configuration factory</strong></p>
4
+ <p>
5
+ <a href="https://github.com/favorodera/eslint-config/blob/main/LICENSE"><img src="https://img.shields.io/github/license/favorodera/eslint-config.svg?style=plastic&label=License&color=blue" alt="License"></a>
6
+ <a href="https://github.com/favorodera/eslint-config/stargazers"><img src="https://img.shields.io/github/stars/favorodera/eslint-config.svg?style=plastic&label=Stars&color=blue" alt="GitHub Stars"></a>
7
+ <a href="https://www.npmjs.com/package/@favorodera/eslint-config"><img src="https://img.shields.io/npm/v/@favorodera/eslint-config.svg?style=plastic&label=Version&color=blue" alt="NPM Version"></a>
8
+ </p>
9
+ </div>
10
+
11
+ <br>
12
+
13
+ An opinionated, highly customizable ESLint flat configuration factory. It provides a seamless, type-safe linting experience out-of-the-box for Vue, TypeScript, Tailwind CSS, Markdown, and more.
14
+
15
+ ## Features
16
+
17
+ - **Flat Config First** — Built from the ground up for ESLint's new flat config system.
18
+ - **TypeScript Support** — Robust linting for TypeScript out of the box.
19
+ - **Vue Integration** — First-class support for Vue 3 single-file components.
20
+ - **Stylistic Rules** — Consistent code styling powered by ESLint Stylistic.
21
+ - **Tailwind CSS** — Built-in rules for Tailwind classes sorting and best practices.
22
+ - **Auto-formatting** — Formats JSON, JSONC, Markdown, and JS/TS automatically.
23
+ - **Type-safe Rules** — Rules are generated with JSDoc comments, giving you rich auto-complete and descriptions right in your IDE.
24
+ - **Highly Configurable** — Easily enable or disable specific rulesets based on your project's needs.
25
+
26
+ ## Supported Configs
27
+
28
+ The following configurations are bundled and enabled by default (they can be individually disabled or customized):
29
+
30
+ - **JavaScript** — Core ESLint rules (`@eslint/js`)
31
+ - **TypeScript** — Type-aware linting (`typescript-eslint`)
32
+ - **Vue** — Single-file component support (`eslint-plugin-vue`, `vue-eslint-parser`)
33
+ - **Stylistic** — Formatting rules (`@stylistic/eslint-plugin`)
34
+ - **Tailwind CSS** — Utility class linting and sorting (`eslint-plugin-better-tailwindcss`)
35
+ - **Imports** — Auto-sorting and unused imports removal (`eslint-plugin-import-lite`, `eslint-plugin-unused-imports`)
36
+ - **Markdown** — Linting for markdown files and embedded code blocks (`@eslint/markdown`)
37
+ - **JSON/JSONC/JSON5** — Formatting and sorting for JSON files like `package.json` (`eslint-plugin-jsonc`)
38
+ - **JSDoc** — Standardized comment formatting (`eslint-plugin-jsdoc`)
39
+
40
+ ## Usage
41
+
42
+ ### Install
43
+
44
+ <details>
45
+ <summary><b>pnpm</b></summary>
46
+
47
+ ```bash
48
+ pnpm install -D eslint @favorodera/eslint-config
49
+ ```
50
+ </details>
51
+
52
+ <details>
53
+ <summary><b>npm</b></summary>
54
+
55
+ ```bash
56
+ npm install -D eslint @favorodera/eslint-config
57
+ ```
58
+ </details>
59
+
60
+ <details>
61
+ <summary><b>yarn</b></summary>
62
+
63
+ ```bash
64
+ yarn add -D eslint @favorodera/eslint-config
65
+ ```
66
+ </details>
67
+
68
+ <details>
69
+ <summary><b>bun</b></summary>
70
+
71
+ ```bash
72
+ bun add -D eslint @favorodera/eslint-config
73
+ ```
74
+ </details>
75
+
76
+ ### Configure
77
+
78
+ Create an `eslint.config.mjs` (or `eslint.config.ts`) file in the root of your project. Since all configurations are enabled by default, you only need to pass options if you want to disable or customize something:
79
+
80
+ ```javascript
81
+ import { factory } from '@favorodera/eslint-config'
82
+
83
+ export default factory({
84
+ // All configs are true by default!
85
+
86
+ // Example: Disable tailwind if you aren't using it
87
+ tailwind: false,
88
+
89
+ // Example: Customize specific rulesets
90
+ stylistic: {
91
+ settings: {
92
+ quotes: 'double',
93
+ indent: 4
94
+ }
95
+ }
96
+ })
97
+ ```
98
+
99
+ ## Development
100
+
101
+ ### Prerequisites
102
+
103
+ - [Node.js](https://nodejs.org/) v22 or later
104
+ - [pnpm](https://pnpm.io/installation) v11 or later
105
+
106
+ ### Getting Started
107
+
108
+ ```bash
109
+ # Install all dependencies
110
+ pnpm install
111
+
112
+ # Start compiler in watch mode and open ESLint config inspector
113
+ pnpm dev
114
+
115
+ # Build the project
116
+ pnpm build
117
+
118
+ # Lint, typecheck, build, and test in one go
119
+ pnpm ready
120
+ ```
121
+
122
+ ### Useful Commands
123
+
124
+ | Command | What it does |
125
+ |---------|-------------|
126
+ | `pnpm dev` | Generates types, starts watch mode, and opens `@eslint/config-inspector` |
127
+ | `pnpm build` | Production build using `tsdown` |
128
+ | `pnpm script:generate-rules-types` | Extracts and generates type definitions for all ESLint rules |
129
+ | `pnpm lint` | Lint the repository |
130
+ | `pnpm typecheck` | Type-check without emitting files |
131
+ | `pnpm test` | Run test suites with Vitest |
132
+ | `pnpm ready` | Full pipeline: install → build → lint → typecheck → test |
133
+
134
+ ## Contributing & Issues
135
+
136
+ Feel free to open an issue or submit a pull request if you'd like to improve the rules, add new features, or fix a bug. Please ensure you run `pnpm ready` before submitting your PR to make sure tests and linting pass.
137
+
138
+ ## Inspiration
139
+
140
+ This project takes heavy inspiration from [antfu/eslint-config](https://github.com/antfu/eslint-config) and similar modern ESLint presets, adapting their best patterns into a custom set of opinionated rules.
141
+
142
+ ## License
143
+
144
+ [MIT](./LICENSE) &copy; [Favour Emeka](https://github.com/favorodera)
package/dist/index.cjs CHANGED
@@ -29,17 +29,32 @@ eslint_processor_vue_blocks = __toESM(eslint_processor_vue_blocks, 1);
29
29
  let globals = require("globals");
30
30
  globals = __toESM(globals, 1);
31
31
  //#region src/globs.ts
32
+ /** Glob pattern for matching JavaScript files */
32
33
  const jsGlob = "**/*.{js,cjs,mjs}";
34
+ /** Glob pattern for matching TypeScript files */
33
35
  const tsGlob = "**/*.{ts,cts,mts}";
36
+ /** Glob pattern for matching Vue single-file components */
34
37
  const vueGlob = "**/*.vue";
38
+ /** Glob pattern for matching Markdown files */
35
39
  const mdGlob = "**/*.md";
40
+ /** Glob pattern for matching virtual files extracted from Markdown */
36
41
  const mdInMdGlob = "**/*.md/*.md";
42
+ /** Glob pattern for matching code blocks embedded in Markdown files */
37
43
  const codeInMdGlob = "**/*.md/**/*.{js,cjs,mjs,ts,cts,mts,vue}";
44
+ /** Glob pattern for matching JSON files */
38
45
  const jsonGlob = "**/*.json";
46
+ /** Glob pattern for matching JSON5 files */
39
47
  const json5Glob = "**/*.json5";
48
+ /** Glob pattern for matching JSON with Comments files */
40
49
  const jsoncGlob = "**/*.jsonc";
50
+ /** Glob patterns for matching TypeScript configuration files */
41
51
  const tsConfigGlob = ["**/tsconfig.json", "**/tsconfig.*.json"];
52
+ /** Glob pattern for matching package.json files */
42
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
+ */
43
58
  const ignoresGlob = [
44
59
  "**/node_modules/**",
45
60
  "**/dist/**",
@@ -85,9 +100,9 @@ const ignoresGlob = [
85
100
  *
86
101
  * Handles both ESM modules (which wrap exports under `.default`) and
87
102
  * CJS / plain-object modules uniformly.
88
- *
89
- * @param module - A module or a promise that resolves to one
90
- * @returns The `.default` export if it exists, otherwise the module itself
103
+ * @template TModule The type of the module being imported.
104
+ * @param module A module or a promise that resolves to one.
105
+ * @returns The `.default` export if it exists, otherwise the module itself.
91
106
  */
92
107
  async function importModule(module) {
93
108
  const resolved = await module;
@@ -97,15 +112,20 @@ async function importModule(module) {
97
112
  /**
98
113
  * Normalize boolean or options value into merged options or null.
99
114
  * Returns null when the input is false or undefined.
100
- *
101
- * @param value - boolean, options object, or undefined
102
- * @param defaults - defaults to merge with
103
- * @returns merged options or false
115
+ * @template TOptions The type of the options object.
116
+ * @param value The configuration value, which can be a boolean, an options object, or undefined.
117
+ * @param defaults The default options to merge with if `value` is true or an object.
118
+ * @returns The merged options object, or false if the feature is disabled.
104
119
  */
105
120
  function resolveOptions(value, defaults) {
106
121
  if (!value) return false;
107
122
  return (0, defu.defu)(value === true ? {} : value, defaults);
108
123
  }
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
+ */
109
129
  function extractRules(...configArrays) {
110
130
  return Object.assign({}, ...configArrays.flat().map((config) => config?.rules || {}));
111
131
  }
@@ -120,6 +140,12 @@ const vueDefaults = {
120
140
  files: [vueGlob],
121
141
  sfcBlocks: sfcBlocksDefaults
122
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
+ */
123
149
  async function vue(options) {
124
150
  const resolved = (0, defu.defu)(options, vueDefaults);
125
151
  const sfcBlocks = resolveOptions(resolved.sfcBlocks, sfcBlocksDefaults);
@@ -188,7 +214,7 @@ async function vue(options) {
188
214
  const defaultPatterns = ignoresGlob;
189
215
  /**
190
216
  * Globs for ignoring files and directories from ESLint scanning.
191
- * @param patterns - Additional ignore patterns or a function to modify the defaults.
217
+ * @param patterns Additional ignore patterns or a function to modify the defaults.
192
218
  * @returns An array containing the ignore flat config item.
193
219
  */
194
220
  function ignores(patterns = []) {
@@ -204,6 +230,12 @@ const importsDefaults = { files: [
204
230
  tsGlob,
205
231
  vueGlob
206
232
  ] };
233
+ /**
234
+ * Constructs the flat config items for imports linting, providing plugin setup and
235
+ * specific rules to enforce consistent import ordering and unused variable checks.
236
+ * @param options Configuration options for imports linting.
237
+ * @returns Promise resolving to imports ESLint config items.
238
+ */
207
239
  async function imports(options) {
208
240
  const resolved = (0, defu.defu)(options, importsDefaults);
209
241
  const [importPlugin, unusedImportsPlugin] = await Promise.all([importModule(import("eslint-plugin-import-lite")), importModule(import("eslint-plugin-unused-imports"))]);
@@ -245,9 +277,10 @@ const javascriptDefaults = { files: [
245
277
  vueGlob
246
278
  ] };
247
279
  /**
248
- * Javascript linting via `eslint`
249
- * @param options - Javascript configuration options
250
- * @returns Promise resolving to javascript ESLint config items
280
+ * Constructs the flat config items for core JavaScript linting, setting up the required
281
+ * language options, globals, and recommended baseline rules.
282
+ * @param options Javascript configuration options.
283
+ * @returns Promise resolving to javascript ESLint config items.
251
284
  */
252
285
  async function javascript(options) {
253
286
  const resolved = (0, defu.defu)(options, javascriptDefaults);
@@ -288,6 +321,12 @@ const markdownDefaults = {
288
321
  files: [mdGlob],
289
322
  gfm: true
290
323
  };
324
+ /**
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.
329
+ */
291
330
  async function markdown(options) {
292
331
  const resolved = (0, defu.defu)(options, markdownDefaults);
293
332
  const markdownPlugin = await importModule(import("@eslint/markdown"));
@@ -359,6 +398,12 @@ const stylisticDefaults = {
359
398
  vueGlob
360
399
  ]
361
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
+ */
362
407
  async function stylistic(options) {
363
408
  const resolved = (0, defu.defu)(options, stylisticDefaults);
364
409
  const stylePlugin = await importModule(import("@stylistic/eslint-plugin"));
@@ -410,9 +455,10 @@ const tailwindDefaults = {
410
455
  settings: { detectComponentClasses: true }
411
456
  };
412
457
  /**
413
- * Tailwind linting via `eslint-plugin-better-tailwindcss`.
414
- * @param options - Tailwind configuration options
415
- * @returns Promise resolving to Tailwind ESLint config items
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.
416
462
  */
417
463
  async function tailwind(options) {
418
464
  const resolved = (0, defu.defu)(options, tailwindDefaults);
@@ -440,9 +486,10 @@ async function tailwind(options) {
440
486
  //#region src/configs/typescript.ts
441
487
  const typescriptDefaults = { files: [tsGlob] };
442
488
  /**
443
- * Typescript linting via `typescript-eslint`.
444
- * @param options - TypeScript configuration options
445
- * @returns Array of TypeScript ESLint config items
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.
446
493
  */
447
494
  async function typescript(options) {
448
495
  const resolved = (0, defu.defu)(options, typescriptDefaults);
@@ -477,6 +524,12 @@ const jsoncDefaults = { files: [
477
524
  jsoncGlob,
478
525
  jsonGlob
479
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
+ */
480
533
  async function jsonc(options) {
481
534
  const resolved = (0, defu.defu)(options, jsoncDefaults);
482
535
  return [
@@ -754,11 +807,61 @@ async function jsonc(options) {
754
807
  ];
755
808
  }
756
809
  //#endregion
810
+ //#region src/configs/jsdoc.ts
811
+ const jsdocDefaults = { files: [
812
+ jsGlob,
813
+ tsGlob,
814
+ vueGlob
815
+ ] };
816
+ /**
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.
821
+ */
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
+ };
829
+ return [{
830
+ name: "favorodera/jsdoc/setup",
831
+ plugins: { jsdoc: jsdocPlugin }
832
+ }, {
833
+ name: "favorodera/tailwind/rules",
834
+ files: resolved.files,
835
+ 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",
854
+ ...resolved.overrides
855
+ }
856
+ }];
857
+ }
858
+ //#endregion
757
859
  //#region src/factory.ts
758
860
  /**
759
- * Factory to create a flat ESLint config
760
- * @param options - Configuration options for the ESLint config
761
- * @returns Flat ESLint config composer
861
+ * Factory to create a flat ESLint config.
862
+ * It builds an ESLint config by sequentially adding sub-configs based on the provided options.
863
+ * @param options Configuration options for enabling/disabling or configuring specific rule sets.
864
+ * @returns A flat config composer instance that can be exported directly or further modified.
762
865
  */
763
866
  function factory(options = {}) {
764
867
  const configs = [];
@@ -771,7 +874,8 @@ function factory(options = {}) {
771
874
  imports,
772
875
  markdown,
773
876
  javascript,
774
- jsonc
877
+ jsonc,
878
+ jsdoc
775
879
  };
776
880
  for (const [key, configFunction] of Object.entries(configFunctions)) {
777
881
  const configOption = options[key];