@shayanthenerd/eslint-config 0.17.0 → 0.20.0

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.
Files changed (78) hide show
  1. package/README.md +498 -342
  2. package/dist/configs/astro.mjs +1 -3
  3. package/dist/configs/base.mjs +4 -5
  4. package/dist/configs/css.mjs +1 -3
  5. package/dist/configs/cypress.mjs +1 -3
  6. package/dist/configs/html.mjs +2 -5
  7. package/dist/configs/importX.mjs +6 -11
  8. package/dist/configs/markdown.mjs +24 -0
  9. package/dist/configs/packageJson.mjs +20 -0
  10. package/dist/configs/perfectionist.mjs +3 -4
  11. package/dist/configs/playwright.mjs +1 -3
  12. package/dist/configs/promise.mjs +24 -0
  13. package/dist/configs/restrictedExports.mjs +1 -3
  14. package/dist/configs/storybook.mjs +1 -3
  15. package/dist/configs/stylistic.mjs +3 -4
  16. package/dist/configs/tailwind.mjs +33 -21
  17. package/dist/configs/typescript.mjs +4 -5
  18. package/dist/configs/vitest.mjs +1 -3
  19. package/dist/configs/vue.mjs +5 -10
  20. package/dist/configs/vueComponentNames.mjs +1 -3
  21. package/dist/configs/vueServerComponents.mjs +1 -3
  22. package/dist/configs/zod.mjs +9 -9
  23. package/dist/helpers/globs.mjs +6 -6
  24. package/dist/helpers/ignores/defaultIgnorePatterns.mjs +1 -2
  25. package/dist/helpers/ignores/getIgnorePatterns.mjs +1 -3
  26. package/dist/helpers/ignores/resolveGitignorePatterns.mjs +3 -5
  27. package/dist/helpers/isPackageDetected.mjs +5 -7
  28. package/dist/helpers/options/defaultOptions.mjs +102 -94
  29. package/dist/helpers/options/enableDetectedConfigs.mjs +4 -3
  30. package/dist/helpers/options/mergeWithDefaults.mjs +1 -3
  31. package/dist/helpers/vue/getRestrictedVueElements.mjs +1 -2
  32. package/dist/helpers/vue/getRestrictedVueInputs.mjs +1 -2
  33. package/dist/index.d.mts +34 -7
  34. package/dist/index.mjs +57 -26
  35. package/dist/prettier.config.mjs +21 -23
  36. package/dist/rules/astro.mjs +58 -57
  37. package/dist/rules/css.mjs +1 -3
  38. package/dist/rules/cypress.mjs +14 -14
  39. package/dist/rules/html.mjs +13 -6
  40. package/dist/rules/importX.mjs +2 -8
  41. package/dist/rules/javascript.mjs +49 -37
  42. package/dist/rules/markdown.mjs +52 -0
  43. package/dist/rules/packageJson.mjs +133 -0
  44. package/dist/rules/perfectionist.mjs +1 -3
  45. package/dist/rules/playwright.mjs +4 -3
  46. package/dist/rules/promise.mjs +26 -0
  47. package/dist/rules/storybook.mjs +1 -3
  48. package/dist/rules/stylistic.mjs +5 -6
  49. package/dist/rules/tailwind.mjs +9 -15
  50. package/dist/rules/typescript.mjs +15 -45
  51. package/dist/rules/vitest.mjs +2 -2
  52. package/dist/rules/vue.mjs +25 -14
  53. package/dist/rules/vueAccessibility.mjs +1 -5
  54. package/dist/rules/zod.mjs +54 -16
  55. package/dist/types/eslint-schema.d.mts +5145 -2020
  56. package/dist/types/eslintRules.d.mts +8 -2
  57. package/dist/types/helpers.d.mts +2 -2
  58. package/dist/types/index.d.mts +131 -163
  59. package/dist/types/{configOptions → options}/base.d.mts +20 -23
  60. package/dist/types/{configOptions → options}/css.d.mts +13 -13
  61. package/dist/types/{configOptions → options}/html.d.mts +13 -13
  62. package/dist/types/options/markdown.d.mts +42 -0
  63. package/dist/types/{configOptions → options}/nuxt.d.mts +12 -14
  64. package/dist/types/{configOptions → options}/perfectionist.d.mts +5 -4
  65. package/dist/types/{configOptions → options}/stylistic.d.mts +58 -65
  66. package/dist/types/{configOptions → options}/tailwind.d.mts +29 -19
  67. package/dist/types/{configOptions → options}/test.d.mts +32 -33
  68. package/dist/types/{configOptions → options}/typescript.d.mts +16 -7
  69. package/dist/types/{configOptions → options}/vue.d.mts +92 -106
  70. package/dist/types/{configOptions → options}/vueAccessibility.d.mts +14 -16
  71. package/dist/types/options/zod.d.mts +27 -0
  72. package/dist/utils/isEmptyString.mjs +1 -2
  73. package/dist/utils/isEnabled.mjs +1 -2
  74. package/dist/utils/isTruthy.mjs +6 -0
  75. package/package.json +97 -101
  76. package/dist/configs/oxlintOverrides.mjs +0 -52
  77. package/dist/oxlint.config.jsonc +0 -122
  78. package/dist/types/configOptions/importX.d.mts +0 -15
package/README.md CHANGED
@@ -1,26 +1,21 @@
1
- # @shayanthenerd/eslint-config    [![NPM Version](https://img.shields.io/npm/v/@shayanthenerd/eslint-config?label=&logo=npm&logoColor=EEEEEE&labelColor=545A61&color=545A61&registry_uri=https://registry.npmjs.com/@shayanthenerd/eslint-config&link=https://github.com/ShayanTheNerd/eslint-config)](https://www.npmjs.com/package/@shayanthenerd/eslint-config) [![License MIT](https://img.shields.io/badge/License-MIT-blue.svg?labelColor=545A61&color=545A61)](https://github.com/ShayanTheNerd/eslint-config/blob/main/LICENSE) [![Netlify Status](https://api.netlify.com/api/v1/badges/8ed76fdd-5aa7-446a-89fa-c916f8cce0de/deploy-status)](https://eslint-config.shayan-zamani.me)
1
+ # @shayanthenerd/eslint-config   [![license-badge]][license] [![npm-version-badge]][npmx] [![jsr-version-badge]][jsr]
2
2
 
3
- A modern, flexible ESLint configuration for enforcing best practices and maintaining a consistent coding style.
3
+ ESLint configuration for enforcing best practices and maintaining a consistent coding style. [Explore configurations][online-preview]!
4
4
 
5
- - **Performant**: Powered by [OXLint (OXC Linter)](https://oxc.rs/docs/guide/usage/linter) for rapid linting
6
- - **Flat Config**: Type-safe [ESLint Flat Config](https://eslint.org/docs/latest/use/configure/configuration-files) with `extends` and `overrides` support
7
- - **Comprehensive**: Dependency detection with support for TypeScript, Astro, Vue & Nuxt, Tailwind, Storybook, Vitest & Playwright, and more
8
- - **Automatic Formatting**: Fine-grained control over formatting with [ESLint Stylistic](https://eslint.style), eliminating the need for Prettier
9
- - **Smart Defaults**: Respects your _.gitignore_ file and provides reasonable, opinionated, yet [highly customizable](#customization) defaults
10
- - **Developer-friendly**: Easy to use and well-documented with JSDoc
11
- - **Modern**: Requires Node.js v20.12.0+ and ESLint v9.28.0+ (ESM-only)
12
-
13
- > [!NOTE]
14
- > This configuration is designed with a flexible API for easy customization. However, it remains a **personal config**. While its primary goal is to enforce best practices and maintain code consistency, some rules—particularly stylistic ones—are rather opinionated. <br /> If the available customization and override options still don't meet your requirements, feel free to fork the project and tailor it to your needs.
5
+ - **Flexible**: [Highly-customizable options](#customization) and configurations with sensible defaults.
6
+ - **Smart**: Context-aware linting with [automatic dependency detection](#automatic-dependency-detection) and _.gitignore_ recognition.
7
+ - **Comprehensive**: [Supports popular plugins](#plugin-support) for TypeScript, Astro, Vue & Nuxt, Tailwind, Zod, Vitest, Markdown, and more.
8
+ - **Type-safe**: [Fully-typed and well-documented API](#api-reference) with `overrides` support for every built-in configuration object.
9
+ - **Modern**: Requires ESLint ^10.4.0 and Node.js ^20.19.0 (ESM-only)
15
10
 
16
11
  ## Table of Contents
12
+ - [Plugin Support](#plugin-support)
17
13
  - [Installation and Configuration](#installation-and-configuration)
14
+ - [Customization](#customization)
18
15
  - [Automatic Dependency Detection](#automatic-dependency-detection)
16
+ - [Framework and Tool Integrations](#framework-and-tool-integrations)
17
+ - [IDE Support](#ide-support)
19
18
  - [Formatting](#formatting)
20
- - [VS Code Integration](#vs-code-integration)
21
- - [Customization](#customization)
22
- - [OXLint](#oxlint)
23
- - [ESLint](#eslint)
24
19
  - [API Reference](#api-reference)
25
20
  - [Versioning Policy](#versioning-policy)
26
21
  - [Roadmap to v1.0.0](#roadmap-to-v100)
@@ -28,170 +23,216 @@ A modern, flexible ESLint configuration for enforcing best practices and maintai
28
23
  - [Credits](#credits)
29
24
  - [License](#license)
30
25
 
31
- ## Installation and Configuration
32
- 1. Install the package:
33
- ```shell
34
- npm i -D @shayanthenerd/eslint-config
35
- # or
36
- bun i -d @shayanthenerd/eslint-config
37
- # or
38
- pnpm i -D @shayanthenerd/eslint-config oxlint
39
- ```
26
+ ## Plugin Support
27
+ Legend:
28
+ - ✅ Supported
29
+ - ⌛️ In progress
30
+ - ◻️ Enabled by default
31
+ - Disabled by default
32
+ - 🔎 [Automatically detected](#automatic-dependency-detection) (`autoDetectDeps: true`)
33
+
34
+ | Category | Support | Activation |
35
+ | :----------------------------------------------------------- | :-----: | :----: |
36
+ | **Languages** | | |
37
+ | [JavaScript][eslint] | ✅  | ◻️  |
38
+ | [TypeScript][plugin-ts] | ✅  | 🔎  |
39
+ | [Markdown][plugin-md] | ✅  | ◻️  |
40
+ | [HTML][plugin-html] | ✅  | ⬛  |
41
+ | [CSS][plugin-css] | ✅  | ⬛  |
42
+ | **Formatting** | | |
43
+ | [Stylistic][plugin-stylistic] | ✅  | ◻️  |
44
+ | [Perfectionist][plugin-perfectionist] | ✅  | ◻️  |
45
+ | **Frameworks** | | |
46
+ | [Astro][plugin-astro] ([JSX accessibility][plugin-jsx-a11y]) | ✅  | 🔎  |
47
+ | [React][plugin-react] ([hooks][plugin-react-hooks]) | ⌛️  | N/A |
48
+ | [Next][plugin-next] | ⌛️  | N/A |
49
+ | [Vue & Nuxt][plugin-vue] ([accessibility][plugin-vue-a11y]) | ✅  | 🔎  |
50
+ | [Tailwind][plugin-tailwind] | ✅  | ⬛  |
51
+ | **Testing Tools** | | |
52
+ | [Storybook][plugin-storybook] | ✅  | 🔎  |
53
+ | [Vitest][plugin-vitest] | ✅  | 🔎  |
54
+ | [Cypress][plugin-cypress] | ✅  | 🔎  |
55
+ | [Playwright][plugin-playwright] | ✅  | 🔎  |
56
+ | **Miscellaneous** | | |
57
+ | [_package.json_][plugin-package-json] | ✅  | ◻️  |
58
+ | [promises][plugin-promise] | ✅  | ◻️  |
59
+ | [Imports][plugin-import-x] | ✅  | ◻️  |
60
+ | [Zod][plugin-zod] | ✅  | 🔎  |
61
+ | [Node][plugin-node] | ⌛️  | N/A |
62
+ | [Unicorn][plugin-unicorn] | ⌛️  | N/A |
40
63
 
41
- This will install OXLint along with all the necessary ESLint plugins and parsers. However, if you're using PNPM, you must install `oxlint` separately.
42
-
43
- 2. Create an ESLint config file (_eslint.config.js_) at the root of your project:
44
- ```js
45
- import { defineConfig } from '@shayanthenerd/eslint-config';
64
+ ## Installation and Configuration
65
+ 1. Install the package and ESLint as dev dependencies:
66
+ ```shell
67
+ npm i -D @shayanthenerd/eslint-config eslint
68
+ ```
69
+
70
+ 2. Create an ESLint configuration file (_eslint.config.js_) at the root of your project:
71
+ ```js title="eslint.config.js"
72
+ import { defineConfig } from '@shayanthenerd/eslint-config';
73
+
74
+ export default defineConfig();
75
+ ```
76
+
77
+ Note: TypeScript configuration files (_eslint.config.ts_) are also supported. Node.js versions below v22.18.0 may require [additional setup][eslint-config-ts-setup].
78
+
79
+ 3. Add the following scripts to your _package.json_:
80
+ ```json title="package.json"
81
+ {
82
+ "scripts": {
83
+ "lint:inspect": "npx @eslint/config-inspector",
84
+ "lint": "eslint --fix --cache --cache-location='node_modules/.cache/.eslintcache'"
85
+ }
86
+ }
87
+ ```
46
88
 
47
- export default defineConfig();
48
- ```
89
+ ---
49
90
 
50
- You can also use a TypeScript file (_eslint.config.ts_). Depending on your Node.js version, [additional setup](https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files) may be required.
91
+ After installation:
92
+ - Use `npm run lint` to lint and fix files.
93
+ - Use `npm run lint:inspect` to see a visual breakdown of your configuration.
94
+ - See [IDE Support](#ide-support) for editor integration.
95
+ - See [Customization](#customization) for advanced configuration.
96
+ - See [Formatting](#formatting) for formatting options and Prettier integration.
51
97
 
52
- If you're using Nuxt, install [@nuxt/eslint](https://eslint.nuxt.com) as a dev dependency:
53
- ```shell
54
- npm i -D @nuxt/eslint
55
- ```
98
+ ## Customization
99
+ `defineConfig()` supports both simple and advanced use cases:
100
+ ```js title="eslint.config.js"
101
+ import eslintPluginYaml from 'eslint-plugin-yaml';
102
+ import * as eslintPluginRegexp from 'eslint-plugin-regexp';
56
103
 
57
- Then, update your ESLint config file:
58
- ```js
59
104
  import { defineConfig } from '@shayanthenerd/eslint-config';
60
105
 
61
- import eslintConfigNuxt from './.nuxt/eslint.config.mjs';
62
-
63
- const eslintConfig = defineConfig();
64
-
65
- export default eslintConfigNuxt(eslintConfig);
66
- ```
106
+ // Use the default configuration:
107
+ export default defineConfig();
67
108
 
68
- > [!NOTE]
69
- > The Nuxt config relies on the Vue config, so make sure it's enabled (either automatically or manually).
109
+ // Customize the built-in configurations:
110
+ export default defineConfig({
111
+ autoDetectDeps: false,
112
+ configs: {
113
+ stylistic: false,
114
+ markdown: {
115
+ language: 'commonmark',
116
+ },
117
+ },
118
+ });
70
119
 
71
- 3. If you're not using OXLint, set `configs.oxlint` to `false` in your ESLint config and skip this step. Otherwise, create an OXLint config file (_.oxlintrc.json_) in the root of your project:
72
- ```jsonc
73
- {
74
- "$schema": "./node_modules/oxlint/configuration_schema.json", // Optional
75
-
76
- "extends": ["./node_modules/@shayanthenerd/eslint-config/dist/oxlint.config.jsonc"],
77
-
78
- /* Customize based on your development environment. */
79
- "env": {
80
- "worker": false,
81
- "commonjs": false,
82
- "bun": false,
83
- "deno": false,
84
- "node": true,
85
- "nodeBuiltin": true,
86
- "browser": true,
87
- "serviceworker": false,
88
- "sharedWorker": false,
89
- "webextension": false,
90
- "audioWorklet": false,
91
- "vitest": true,
92
- "vue": true,
93
- "astro": true
120
+ // Use custom configuration objects:
121
+ export default defineConfig([
122
+ {
123
+ files: ['**/*.yaml', '**/*.yml'],
124
+ ignores: ['**/*.schema.yaml', '**/*.schema.yml'],
125
+ extends: [eslintPluginYaml.configs.recommended],
94
126
  },
127
+ eslintPluginRegexp.configs['flat/recommended'],
128
+ ]);
95
129
 
96
- "categories": {
97
- "correctness": "error",
98
- "suspicious": "error",
99
- "restriction": "error",
100
- "pedantic": "error",
101
- "perf": "warn",
102
- "style": "warn",
103
- "nursery": "error"
104
- }
105
- }
130
+ // Customize the built-in configurations and use custom configuration objects:
131
+ export default defineConfig(
132
+ {
133
+ autoDetectDeps: 'verbose',
134
+ configs: {
135
+ typescript: {
136
+ typeDefinitionStyle: 'type',
137
+ overrides: {
138
+ rules: {
139
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
140
+ },
141
+ },
142
+ },
143
+ },
144
+ },
145
+ [
146
+ {
147
+ files: ['**/*.yaml', '**/*.yml'],
148
+ ignores: ['**/*.schema.yaml', '**/*.schema.yml'],
149
+ extends: [eslintPluginYaml.configs.recommended],
150
+ },
151
+ eslintPluginRegexp.configs['flat/recommended'],
152
+ ],
153
+ );
106
154
  ```
107
155
 
108
- Due to [the limitation of OXLint](https://oxc.rs/docs/guide/usage/linter/nested-config#extending-configuration-files), only `rules`, `plugins`, and `overrides` can be extended. Check out [OXLint config reference](https://oxc.rs/docs/guide/usage/linter/config-file-reference) for more details.
156
+ Every built-in configuration accepts an `overrides` option. These values are merged into the generated configuration and take precedence over the defaults.
157
+ ```ts
158
+ import type { ESLint, Linter } from 'eslint';
109
159
 
110
- 4. Add the following scripts to your _package.json_ file:
111
- ```json
112
- {
113
- "scripts": {
114
- "lint:inspect": "npx @eslint/config-inspector",
115
- "lint:oxlint": "oxlint --fix",
116
- "lint:eslint": "eslint --fix --cache --cache-location='node_modules/.cache/.eslintcache'",
117
- "lint": "npm run lint:oxlint && npm run lint:eslint"
118
- }
160
+ interface Overrides {
161
+ name?: string,
162
+ files?: (string | string[])[],
163
+ ignores?: string[],
164
+ plugins?: Record<string, ESLint.Plugin>,
165
+ languageOptions?: Linter.Config['languageOptions'],
166
+ settings?: Record<string, unknown>,
167
+ rules?: ConfigRules, // The available rules in the current configuration object
119
168
  }
120
169
  ```
121
170
 
122
- ---
123
-
124
- That's it! You can now run OXLint and ESLint in your project:
125
- ```shell
126
- npm run lint
127
- ```
128
-
129
- To get a visual breakdown of your configuration, run:
130
- ```shell
131
- npm run lint:inspect
132
- ```
133
-
134
171
  ## Automatic Dependency Detection
135
- This package automatically detects dependencies in your project and enables the corresponding ESLint configurations for them. This is powered by [local-pkg](https://github.com/antfu-collective/local-pkg), which scans your _node_modules_ directory instead of _package.json_. <br />
136
- > [!IMPORTANT]
137
- > This behavior is particularly noticeable with package managers that use a flat _node_modules_ structure, such as **NPM** or **Bun**. <br />
138
- A concrete example is `eslint-plugin-storybook`, which is a dependency of this package. Since the plugin transitively depends on `storybook`, NPM and Bun hoist `storybook` to the root of your _node_modules_. As a result, the ESLint configuration for `storybook` will be automatically enabled, even if you haven't explicitly installed it. <br />
139
- Using a package manager with strict dependency resolution, such as **PNPM**, prevents this issue by hiding transitive dependencies from the root of your _node_modules_.
172
+ [local-pkg][local-pkg] is used to detect installed dependencies and automatically enable the relevant integrations. Package managers that hoist transitive dependencies (such as NPM and Bun) may sometimes cause an integration to get enabled unexpectedly. This is because **_local-pkg_ scans _node_modules_ instead of _package.json_.**
140
173
 
141
- To opt out of this behavior, you can either set `autoDetectDeps: false` in the options object or explicitly disable any unwanted configurations that were automatically enabled.
174
+ PNPM's strict dependency resolution avoids this issue.
142
175
 
143
- Unlike other plugins, the configuration for Tailwind isn't automatically enabled upon dependency detection, because you must explicitly provide the path to your Tailwind entry point (config file), or the ESLint configuration won't work as expected.
176
+ > [!NOTE]
177
+ > For example, `eslint-plugin-storybook` depends on `storybook`, which is hoisted by NPM and Bun. As a result, the integration for `storybook` will be enabled automatically, even if you haven't explicitly installed it.
144
178
 
145
- Stylistic, Perfectionist, ImportX, and core (JavaScript) rules are enabled by default.
179
+ To opt out of this behavior, either [globally disable automatic dependency detection](#customization) or manually disable the unwanted integrations that were enabled automatically.
146
180
 
147
- ## Formatting
148
- This config uses [ESLint Stylistic](https://eslint.style) to format JavaScript and TypeScript files (`?([mc])[jt]s?(x)`) as well as Astro (similar to JSX/TSX) and the `<script>` blocks in Vue components. HTML and the `<template>` blocks in Vue components are formatted with [html-eslint](https://html-eslint.org) and [eslint-plugin-vue](https://eslint.vuejs.org), respectively. For other files such as CSS, JSON, and Markdown, you'll need Prettier. To make this easier, a customizable [shared Prettier configuration](https://prettier.io/docs/sharing-configurations) is provided. Here's how to set it up:
181
+ ## Framework and Tool Integrations
182
+ ### Tailwind
183
+ The Tailwind integration isn't automatically enabled because ESLint needs to know where to locate your Tailwind configuration.
184
+ ```js title="eslint.config.js"
185
+ import { defineConfig } from '@shayanthenerd/eslint-config';
149
186
 
150
- 1. Install Prettier:
151
- ```shell
152
- npm i -D prettier
187
+ export default defineConfig({
188
+ configs: {
189
+ tailwind: {
190
+ /* Either option is sufficient, but both can be provided. */
191
+ config: './tailwind.config.js',
192
+ entryPoint: './app/assets/styles/app.css',
193
+ },
194
+ },
195
+ });
153
196
  ```
154
197
 
155
- 2. Create a Prettier config file in the root of your project (_prettier.config.js_):
156
- ```js
157
- import prettierConfig from '@shayanthenerd/eslint-config/prettier';
158
-
159
- /** @type {import('prettier').Config} */
160
- export default {
161
- ...prettierConfig,
162
- semi: false, // Override `semi` from the shared config
163
- };
198
+ For editor integration, to avoid inconsistent diagnostics and auto-fixes from the [Tailwind CSS IntelliSense VS Code extension][extension-tailwind], add the following settings to _.vscode/settings.json_:
199
+ ```json title=".vscode/settings.json"
200
+ {
201
+ "tailwindCSS.lint.cssConflict": "ignore",
202
+ "tailwindCSS.lint.recommendedVariantOrder": "ignore",
203
+ "tailwindCSS.lint.suggestCanonicalClasses": "ignore",
204
+
205
+ "eslint.rules.customizations": [
206
+ { "rule": "better-tailwindcss/*", "severity": "off", "fixable": true },
207
+ { "rule": "better-tailwindcss/no-restricted-classes", "severity": "warn", "fixable": true },
208
+ { "rule": "better-tailwindcss/no-conflicting-classes", "severity": "error", "fixable": false },
209
+ { "rule": "better-tailwindcss/no-unknown-classes", "severity": "warn", "fixable": false }
210
+ ]
211
+ }
164
212
  ```
165
213
 
166
- Or if you prefer using TypeScript (_prettier.config.ts_):
167
- ```ts
168
- import type { Config } from 'prettier';
214
+ ### Nuxt
215
+ Nuxt support is already included through the Vue integration, so you don’t need to install or configure [@nuxt/eslint][eslint-nuxt] manually. If you need additional rules tailored to Nuxt, refer to the plugin’s documentation for setup instructions.
169
216
 
170
- import prettierConfig from '@shayanthenerd/eslint-config/prettier';
217
+ > [!TIP]
218
+ > `configs.nuxt` only includes options for Nuxt Image, Nuxt UI, and the `<Icon>` component. Vue's rules and `overrides` can be configured via `configs.vue`.
171
219
 
172
- export default {
173
- ...prettierConfig,
174
- semi: true, // Override `semi` from the shared config
175
- } satisfies Config;
176
- ```
220
+ ### Markdown
221
+ Markdown linting is powered by [@eslint/markdown][plugin-md].
177
222
 
178
- 3. To prevent conflicts with ESLint, Prettier should be configured to only format files other than JavaScript, TypeScript, Astro, HTML, and Vue. Hence, add the following script to your _package.json_ file:
179
- ```json
180
- {
181
- "scripts": {
182
- "format": "prettier --write . '!**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,html,vue,astro}' --cache"
183
- }
184
- }
185
- ```
223
+ By default, the plugin uses GitHub Flavored Markdown (GFM). You can [switch to CommonMark](#customization) if you prefer, but rules related to tables, label references, and other GFM syntax will be disabled because CommonMark doesn't support them.
186
224
 
187
- ## VS Code Integration
188
- Install VS Code extensions for [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint), [OXLint](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode), and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode). Then, add the following in the _.vscode/settings.json_ file of your project:
189
- ```jsonc
225
+ > [!NOTE]
226
+ > Fenced code blocks inside Markdown files are not linted by @eslint/markdown.
227
+
228
+ ## IDE Support
229
+ Install the VS Code extensions for [ESLint][extension-eslint] and [Prettier][extension-prettier]. Then add the following in _.vscode/settings.json_:
230
+ ```jsonc title=".vscode/settings.json"
190
231
  {
191
232
  /* Enforce Unix-like line endings (LF). */
192
233
  "files.eol": "\n",
193
234
 
194
- /* Enforce either tabs or spaces for indentation. */
235
+ /* Enforce 2 spaces for indentation. */
195
236
  "editor.tabSize": 2,
196
237
  "editor.insertSpaces": true,
197
238
  "editor.detectIndentation": false,
@@ -202,35 +243,27 @@ Install VS Code extensions for [ESLint](https://marketplace.visualstudio.com/ite
202
243
  "source.organizeImports": "never",
203
244
  "source.removeUnusedImports": "never",
204
245
 
205
- /* Apply OXLint and ESLint automatic fixes on file save. */
206
- "source.fixAll.oxc": "explicit",
246
+ /* Apply ESLint fixes when saving files. */
207
247
  "source.fixAll.eslint": "explicit"
208
248
  },
209
- "oxc.lint.run": "onSave",
210
- "eslint.run": "onSave",
211
- "editor.formatOnSave": true,
212
- "eslint.format.enable": true,
213
249
 
214
- /* Format and lint JavaScript, TypeScript, HTML, and Vue files with ESLint, while everything else is formatted with Prettier. */
215
- "editor.defaultFormatter": "esbenp.prettier-vscode",
216
- "[javascript][typescript][javascriptreact][typescriptreact][html][vue][astro]": {
217
- "editor.defaultFormatter": "dbaeumer.vscode-eslint"
218
- },
250
+ "eslint.run": "onSave",
251
+ "eslint.format.enable": true,
219
252
  "eslint.validate": [
220
253
  "javascript",
221
254
  "typescript",
222
255
  "javascriptreact",
223
256
  "typescriptreact",
257
+ "json",
258
+ "markdown",
224
259
  "html",
225
260
  "css",
226
261
  "tailwindcss",
227
- "vue",
228
- "astro"
262
+ "astro",
263
+ "vue"
229
264
  ],
230
265
 
231
- /* Adjust these based on the features you're using to silently auto-fix the stylistic rules in your IDE. */
232
- "tailwindCSS.lint.cssConflict": "ignore", // Only if you're using the Tailwind config
233
- "tailwindCSS.lint.recommendedVariantOrder": "ignore", // Only if you're using the Tailwind config
266
+ /* Adjust these based on the features you're using to silently auto-fix the stylistic rules. */
234
267
  "eslint.rules.customizations": [
235
268
  { "rule": "*styl*", "severity": "off", "fixable": true },
236
269
  { "rule": "*sort*", "severity": "off", "fixable": true },
@@ -241,214 +274,313 @@ Install VS Code extensions for [ESLint](https://marketplace.visualstudio.com/ite
241
274
  { "rule": "*order-*", "severity": "off", "fixable": true },
242
275
  { "rule": "*newline*", "severity": "off", "fixable": true },
243
276
  { "rule": "*attribute*", "severity": "off", "fixable": true },
277
+ { "rule": "package-json/order-properties", "severity": "off", "fixable": true },
244
278
  { "rule": "vue/max-len", "severity": "off", "fixable": true },
245
279
  { "rule": "vue/comma-dangle", "severity": "off", "fixable": true },
246
- { "rule": "vue/space-in-parens", "severity": "off", "fixable": true },
247
- { "rule": "better-tailwindcss/*", "severity": "off", "fixable": true },
248
- { "rule": "better-tailwindcss/no-restricted-classes", "severity": "error", "fixable": true },
249
- { "rule": "better-tailwindcss/no-conflicting-classes", "severity": "error", "fixable": false },
250
- { "rule": "better-tailwindcss/no-unregistered-classes", "severity": "error", "fixable": false }
280
+ { "rule": "vue/space-in-parens", "severity": "off", "fixable": true }
251
281
  ]
252
282
  }
253
283
  ```
254
284
 
255
- ## Customization
256
- ### OXLint
257
- Since OXLint and ESLint use separate config files, customizations made in your ESLint config will not apply to OXLint. However, you can still customize OXLint rules in your _.oxlintrc.json_ file. Here's an example:
258
- ```jsonc
259
- {
260
- /* Base configuration */
285
+ > [!TIP]
286
+ > These settings match the default behavior of this configuration. If you've customized any formatting or stylistic rules, update the corresponding editor settings to keep them consistent.
261
287
 
262
- "rules": {
263
- /* Globally override rules. */
264
- "oxlint/no-named-as-default-member": "warn"
265
- },
288
+ ## Formatting
289
+ This configuration uses [ESLint Stylistic][plugin-stylistic] to format:
290
+ - JavaScript and TypeScript (_js_, _cjs_, _mjs_, _jsx_, _ts_, _cts_, _mts_, _tsx_),
291
+ - Astro (similar to _jsx_/_tsx_), and
292
+ - Vue's `<script>` blocks.
266
293
 
267
- "overrides": [
268
- /* Override rules for specific files. */
269
- {
270
- "files": ["app/**/*.tsx"],
271
- "ignores": ["app/app.tsx"],
272
- "rules": {
273
- "oxlint/max-depth": ["error", { "max": 5 }],
274
- "oxlint/explicit-function-return-type": "off"
275
- }
276
- }
277
- ],
294
+ HTML and Vue's `<template>` blocks are formatted with [@html-eslint/eslint-plugin][plugin-html] and [eslint-plugin-vue][plugin-vue], respectively.
278
295
 
279
- /* OXLint respects the ignore patterns defined in `.gitignore` and `.eslintignore` files by default. */
280
- "ignorePatterns": ["**/*.min.*"]
296
+ For file types not handled by ESLint Stylistic—such as CSS, JSON, Yaml, and Markdown—you can use Prettier. To simplify the setup, this package also provides a customizable [shared Prettier configuration][prettier-shared-config].
297
+
298
+ 1. Install Prettier as a dev dependency:
299
+ ```shell
300
+ npm i -D prettier
301
+ ```
302
+
303
+ 2. Create a Prettier config file in the root of your project (_prettier.config.js_):
304
+ ```js title="prettier.config.js"
305
+ import prettierConfig from '@shayanthenerd/eslint-config/prettier';
306
+
307
+ /** @type {import('prettier').Config} */
308
+ export default {
309
+ ...prettierConfig,
310
+ semi: false, // Override `semi` from the shared config
311
+ };
312
+ ```
313
+
314
+ Or if you prefer using TypeScript (_prettier.config.ts_):
315
+ ```ts title="prettier.config.ts"
316
+ import type { Config } from 'prettier';
317
+
318
+ import prettierConfig from '@shayanthenerd/eslint-config/prettier';
319
+
320
+ export default {
321
+ ...prettierConfig,
322
+ semi: true, // Override `semi` from the shared config
323
+ } satisfies Config;
324
+ ```
325
+
326
+ ### Using ESLint Stylistic with Prettier
327
+ In this setup, Prettier formats everything that ESLint Stylistic doesn't. To prevent overlaps and potential race conditions, Prettier should only target files that ESLint Stylistic doesn't format.
328
+
329
+ _package.json_:
330
+ ```json title="package.json"
331
+ {
332
+ "scripts": {
333
+ "format": "prettier --write . '!**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,html,vue,astro}' --cache"
334
+ }
281
335
  }
282
336
  ```
283
-
284
- ### ESLint
285
- `defineConfig` takes the `options` object as the first argument. `options` is thoroughly documented with JSDoc and provides many options for rule customizations. In addition, each config object in `options.configs` accepts an `overrides` option:
286
- ```ts
287
- interface Overrides {
288
- name: '',
289
- files: [],
290
- ignores: [],
291
- plugins: {},
292
- settings: {},
293
- languageOptions: {
294
- parser: {},
295
- globals: {},
337
+ _.vscode/settings.json_:
338
+ ```json title=".vscode/settings.json"
339
+ {
340
+ "editor.formatOnSave": true,
341
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
342
+ "[javascript][typescript][javascriptreact][typescriptreact][html][vue][astro][{**/package.json}]": {
343
+ "editor.defaultFormatter": "dbaeumer.vscode-eslint"
296
344
  },
297
- rules: {},
298
345
  }
299
346
  ```
300
347
 
301
- `overrides` is merged with the default config, taking precedence over its properties. However, there is no guarantee that the resulting configuration works correctly — it depends on the options you provide.
302
-
303
- `defineConfig` also accepts any number of custom ESLint Flat Configs (_eslint.config.js_):
304
- ```js
305
- import eslintPluginYaml from 'eslint-plugin-yaml';
306
- import * as eslintPluginRegexp from 'eslint-plugin-regexp';
307
- import { defineConfig } from '@shayanthenerd/eslint-config';
308
-
309
- export default defineConfig(
310
- /* The options object: */
311
- {
312
- env: 'bun',
313
- configs: {
314
- typescript: {
315
- typeDefinitionStyle: 'type',
316
- overrides: {
317
- rules: {
318
- '@typescript-eslint/no-unsafe-type-assertion': 'off',
319
- },
320
- },
321
- },
322
- },
323
- },
348
+ ### Using Prettier Alone
349
+ If you prefer to use Prettier as the only formatter, [disable the stylistic configuration](#customization) and let Prettier handle all formatting. Note that **this approach provides less granular control over the formatting options**.
324
350
 
325
- /* ESLint Flat Configs: */
326
- {
327
- files: ['**/*.yaml', '**/*.yml'],
328
- ignores: ['**/*.schema.yaml', '**/*.schema.yml'],
329
- extends: [pluginYaml.configs.recommended],
330
- },
331
- regexpPlugin.configs['flat/recommended'],
332
- );
351
+ _package.json_:
352
+ ```json title="package.json"
353
+ {
354
+ "scripts": {
355
+ "format": "prettier --write . --cache"
356
+ }
357
+ }
333
358
  ```
359
+ _.vscode/settings.json_:
360
+ ```json title=".vscode/settings.json"
361
+ {
362
+ "eslint.format.enable": false,
363
+ "editor.formatOnSave": true,
364
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
365
+ "editor.codeActionsOnSave": {
366
+ "source.fixAll.eslint": "never"
367
+ }
368
+ }
369
+ ```
370
+
371
+ When using this approach:
372
+ - Avoid running `lint` and `format` scripts on the same files simultaneously.
373
+ - Use either ESLint fixes or Prettier formatting when saving files, but not both.
334
374
 
335
375
  ## API Reference
336
376
  <details>
337
- <summary>The API reference</summary>
338
- Some types are omitted or aliased for brevity.
377
+ <summary>
378
+ <!-- eslint-disable-next-line markdown/no-html -->
379
+ The API reference of the <code>options</code> object passed to <code>defineConfig</code>
380
+ </summary><br />
339
381
 
382
+ <small>Some types are omitted or aliased for brevity.</small>
383
+
384
+ <!-- START_AUTO-GENERATED_API_REFERENCE -->
340
385
  ```ts
386
+ import type { ESLint, Linter } from 'eslint';
387
+
388
+ type VueAttributeCategory =
389
+ | 'SLOT'
390
+ | 'EVENTS'
391
+ | 'GLOBAL'
392
+ | 'UNIQUE'
393
+ | 'CONTENT'
394
+ | 'DEFINITION'
395
+ | 'OTHER_ATTR'
396
+ | 'ATTR_STATIC'
397
+ | 'ATTR_DYNAMIC'
398
+ | 'CONDITIONALS'
399
+ | 'LIST_RENDERING'
400
+ | 'TWO_WAY_BINDING'
401
+ | 'OTHER_DIRECTIVES'
402
+ | 'RENDER_MODIFIERS'
403
+ | 'ATTR_SHORTHAND_BOOL';
404
+
405
+ interface Overrides {
406
+ name?: string,
407
+ files?: (string | string[])[],
408
+ ignores?: string[],
409
+ plugins?: Record<string, ESLint.Plugin>,
410
+ languageOptions?: Linter.Config['languageOptions'],
411
+ settings?: Record<string, unknown>,
412
+ rules?: ConfigRules, // The available rules in the current configuration object
413
+ }
414
+
341
415
  interface Options {
342
416
  autoDetectDeps?: boolean | 'verbose',
417
+ env?: 'browser' | 'bun' | 'deno' | 'node',
343
418
  gitignore?: false | string,
344
419
  packageDir?: string,
345
- env?: 'bun' | 'node',
346
- tsConfig?: {
347
- rootDir: string,
420
+ tsConfig?: false | {
348
421
  filename?: string,
422
+ rootDir: string,
349
423
  },
350
424
 
351
- global?: {
352
- name?: string,
425
+ project?: {
353
426
  basePath?: string,
354
- ignores?: string[],
355
427
  globals?: {
356
- worker?: boolean,
357
- commonjs?: boolean,
428
+ astro?: boolean,
429
+ audioWorklet?: boolean,
430
+ browser?: boolean,
358
431
  bun?: boolean,
432
+ commonjs?: boolean,
359
433
  deno?: boolean,
360
434
  node?: boolean,
361
435
  nodeBuiltin?: boolean,
362
- browser?: boolean,
363
436
  serviceworker?: boolean,
364
437
  sharedWorker?: boolean,
365
- webextension?: boolean,
366
- audioWorklet?: boolean,
367
438
  vitest?: boolean,
368
439
  vue?: boolean,
369
- astro?: boolean,
370
- custom?: {
371
- [key: string]: boolean | 'off' | 'readonly' | 'readable' | 'writable' | 'writeable',
372
- },
373
- }
440
+ webextension?: boolean,
441
+ worker?: boolean,
442
+ custom?: Record<string, 'off' | boolean | 'readable' | 'readonly' | 'writable' | 'writeable'>,
443
+ },
444
+ ignores?: string[],
374
445
  linterOptions?: {
375
446
  noInlineConfig?: boolean,
376
- reportUnusedInlineConfigs?: 'error' | 'off' | 'warn',
377
- reportUnusedDisableDirectives?: 'error' | 'off' | 'warn',
447
+ reportUnusedDisableDirectives?: 'off' | 'warn' | 'error',
448
+ reportUnusedInlineConfigs?: 'off' | 'warn' | 'error',
378
449
  },
379
- settings?: {
380
- [name: string]: unknown,
381
- }
450
+ name?: string,
382
451
  rules?: Linter.RulesRecord,
452
+ settings?: Record<string, unknown>,
383
453
  },
384
454
 
385
455
  configs?: {
386
- oxlint?: false | string,
456
+ astro?: boolean | {
457
+ overrides?: Overrides,
458
+ },
387
459
  base?: {
460
+ functionStyle?: 'expression' | 'declaration',
388
461
  maxDepth?: number,
389
462
  maxNestedCallbacks?: number,
390
463
  preferNamedExports?: boolean,
391
- functionStyle?: 'declaration' | 'expression',
392
- overrides?: {},
464
+ overrides?: Overrides,
465
+ },
466
+ css?: boolean | {
467
+ allowedRelativeFontUnits?: (
468
+ | '%'
469
+ | 'ch'
470
+ | 'em'
471
+ | 'ex'
472
+ | 'ic'
473
+ | 'lh'
474
+ | 'cap'
475
+ | 'rch'
476
+ | 'rem'
477
+ | 'rex'
478
+ | 'ric'
479
+ | 'rlh'
480
+ | 'rcap'
481
+ )[],
482
+ useBaseline?: false | number | 'newly' | 'widely',
483
+ overrides?: Overrides,
484
+ },
485
+ html?: boolean | {
486
+ idNamingConvention?: 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case',
487
+ useBaseline?: false | number | 'newly' | 'widely',
488
+ overrides?: Overrides,
489
+ },
490
+ importX?: boolean | {
491
+ overrides?: Overrides,
492
+ },
493
+ markdown?: boolean | {
494
+ allowedHtmlTags?: string[],
495
+ frontmatter?: false | 'json' | 'toml' | 'yaml',
496
+ language?: 'gfm' | 'commonmark',
497
+ overrides?: Overrides,
498
+ },
499
+ nuxt?: boolean | {
500
+ icon?: boolean | {
501
+ component?: string,
502
+ },
503
+ image?: boolean,
504
+ ui?: boolean | {
505
+ prefix?: string,
506
+ },
507
+ },
508
+ packageJson?: boolean | {
509
+ overrides?: Overrides,
510
+ },
511
+ perfectionist?: boolean | {
512
+ sortType?: 'custom' | 'natural' | 'unsorted' | 'line-length' | 'alphabetical' | 'subgroup-order',
513
+ overrides?: Overrides,
514
+ },
515
+ promise?: boolean | {
516
+ overrides?: Overrides,
393
517
  },
394
518
  stylistic?: boolean | {
395
- semi?: 'always' | 'never',
396
- trailingComma?: 'always' | 'never' | 'always-multiline' | 'only-multiline',
397
- memberDelimiterStyle?: 'semi' | 'comma',
398
- quotes?: 'single' | 'double' | 'backtick',
399
- jsxQuotes?: 'prefer-single' | 'prefer-double',
400
519
  arrowParens?: 'always' | 'as-needed',
401
520
  indent?: number,
521
+ jsxQuotes?: 'prefer-double' | 'prefer-single',
522
+ maxAttributesPerLine?: number,
402
523
  maxConsecutiveEmptyLines?: number,
403
524
  maxLineLength?: number,
404
- maxAttributesPerLine?: number,
525
+ memberDelimiterStyle?: 'semi' | 'comma',
526
+ quotes?: 'double' | 'single' | 'backtick',
405
527
  selfCloseVoidHTMLElements?: 'never' | 'always',
406
- overrides?: {},
407
- },
408
- html?: boolean | {
409
- useBaseline?: number | false | 'widely' | 'newly',
410
- idNamingConvention?: 'camelCase' | 'snake_case' | 'PascalCase' | 'kebab-case',
411
- overrides?: {},
412
- },
413
- css?: boolean | {
414
- useBaseline?: number | false | 'widely' | 'newly',
415
- allowedRelativeFontUnits?: ('%' | 'cap' | 'ch' | 'em' | 'ex' | 'ic' | 'lh' | 'rcap' | 'rch' | 'rem' | 'rex' | 'ric' | 'rlh')[],
416
- overrides?: {},
528
+ semi?: 'never' | 'always',
529
+ trailingComma?: 'never' | 'always' | 'only-multiline' | 'always-multiline',
530
+ overrides?: Overrides,
417
531
  },
418
532
  tailwind?: false | {
419
533
  config: string,
534
+ cwd?: string,
420
535
  entryPoint?: string,
536
+ ignoredUnknownClasses?: string[],
421
537
  multilineSort?: boolean,
422
- ignoredUnregisteredClasses?: string[],
423
- overrides?: {},
538
+ overrides?: Overrides,
424
539
  } | {
425
540
  config?: string,
541
+ cwd?: string,
426
542
  entryPoint: string,
543
+ ignoredUnknownClasses?: string[],
427
544
  multilineSort?: boolean,
428
- ignoredUnregisteredClasses?: string[],
429
- overrides?: {},
545
+ overrides?: Overrides,
546
+ },
547
+ test?: {
548
+ maxNestedDescribe?: number,
549
+ testFunction?: 'it' | 'test',
550
+ cypress?: boolean | {
551
+ overrides?: Overrides,
552
+ },
553
+ playwright?: boolean | {
554
+ overrides?: Overrides,
555
+ },
556
+ storybook?: boolean | {
557
+ overrides?: Overrides,
558
+ },
559
+ vitest?: boolean | {
560
+ overrides?: Overrides,
561
+ },
430
562
  },
431
563
  typescript?: boolean | {
432
564
  allowedDefaultProjects?: string[],
433
- methodSignatureStyle?: 'property' | 'method',
434
- typeDefinitionStyle?: 'interface' | 'type',
435
- overrides?: {},
436
- },
437
- importX?: boolean | {
565
+ methodSignatureStyle?: 'method' | 'property',
438
566
  removeUnusedImports?: boolean,
439
- overrides?: {},
440
- },
441
- perfectionist?: boolean | {
442
- sortType?: 'custom' | 'natural' | 'alphabetical' | 'line-length' | 'unsorted',
443
- overrides?: {},
567
+ typeDefinitionStyle?: 'type' | 'interface',
568
+ overrides?: Overrides,
444
569
  },
445
570
  vue?: boolean | {
446
571
  accessibility?: boolean | {
572
+ accessibleChildComponents?: string[],
447
573
  anchorComponents?: string[],
448
574
  imageComponents?: string[],
449
- accessibleChildComponents?: string[],
450
575
  },
451
- blockOrder?: (
576
+ allowedStyleAttributes?: ['plain' | 'module' | 'scoped', 'plain' | 'module' | 'scoped'],
577
+ attributeHyphenation?: 'never' | 'always',
578
+ attributesOrder?: (VueAttributeCategory | VueAttributeCategory[])[],
579
+ blockLang?: {
580
+ script?: 'js' | 'ts' | 'jsx' | 'tsx' | 'implicit',
581
+ style?: 'css' | 'scss' | 'postcss' | 'implicit',
582
+ },
583
+ blocksOrder?: (
452
584
  | 'docs'
453
585
  | 'template'
454
586
  | 'script[setup]'
@@ -458,92 +590,116 @@ export default defineConfig(
458
590
  | 'style:not([scoped])'
459
591
  | 'i18n:not([locale=en])'
460
592
  )[],
593
+ componentNameCaseInTemplate?: 'kebab-case' | 'PascalCase',
594
+ destructureProps?: 'never' | 'always' | 'only-when-assigned',
595
+ ignoredUndefinedComponents?: string[],
461
596
  macrosOrder?: (
462
597
  | 'definePage'
598
+ | 'defineEmits'
463
599
  | 'defineModel'
464
600
  | 'defineProps'
465
- | 'defineEmits'
466
601
  | 'defineSlots'
467
602
  | 'defineCustom'
468
603
  | 'defineExpose'
469
604
  | 'defineOptions'
470
605
  )[],
471
- attributesOrder?: RuleOptions<'vue/attributes-order'>['order'],
472
- attributeHyphenation?: 'never' | 'always',
473
606
  preferVBindSameNameShorthand?: 'never' | 'always',
474
607
  preferVBindTrueShorthand?: 'never' | 'always',
475
- allowedStyleAttributes?: ['module' | 'plain' | 'scoped', 'module' | 'plain' | 'scoped'],
476
- blockLang?: {
477
- style?: 'css' | 'implicit' | 'scss' | 'postcss',
478
- script?: 'js' | 'ts' | 'jsx' | 'tsx' | 'implicit',
479
- },
480
- destructureProps?: 'never' | 'always',
481
- componentNameCaseInTemplate?: 'PascalCase' | 'kebab-case',
482
- vForDelimiterStyle?: 'in' | 'of',
483
- vOnHandlerStyle?: 'inline' | 'inline-function' | ['method', 'inline' | 'inline-function'],
484
608
  restrictedElements?: (string | {
485
609
  element: string | string[],
486
610
  message: string,
487
611
  })[],
488
612
  restrictedStaticAttributes?: (string | {
489
- key: string,
490
- value?: string | true,
491
613
  element: string,
614
+ key: string,
492
615
  message: string,
616
+ value: true | string,
493
617
  })[],
494
- ignoredUndefinedComponents?: string[],
495
- overrides?: {},
496
- },
497
- nuxt?: boolean | {
498
- image?: boolean,
499
- icon?: boolean | {
500
- component?: string,
501
- }
502
- ui?: boolean | {
503
- prefix?: string,
504
- }
618
+ vForDelimiterStyle?: 'in' | 'of',
619
+ overrides?: Overrides,
505
620
  },
506
- test?: {
507
- storybook?: boolean | {
508
- overrides?: {},
509
- },
510
- vitest?: boolean | {
511
- overrides?: {},
512
- },
513
- playwright?: boolean | {
514
- overrides?: {},
515
- },
516
- cypress?: boolean | {
517
- overrides?: {},
518
- },
519
- testFunction?: 'test' | 'it',
520
- maxNestedDescribe?: number,
621
+ zod?: boolean | {
622
+ mini?: boolean,
623
+ overrides?: Overrides,
521
624
  },
522
625
  },
523
626
  }
524
627
  ```
628
+ <!-- END_AUTO-GENERATED_API_REFERENCE -->
525
629
  </details>
526
630
 
527
631
  ## Versioning Policy
528
- This project adheres to [The Semantic Versioning Standard](https://semver.org). However, to facilitate rapid development and fast iteration, the following changes are considered non-breaking:
529
- - Upgrades to dependency versions
632
+ This project adheres to [The Semantic Versioning Standard][semver]. However, to facilitate rapid development and fast iteration, **the following changes are considered non-breaking**:
633
+ - Updates to dependency versions
530
634
  - Modifications to rule options
531
635
  - Enabling or disabling rules and plugins
532
636
 
533
637
  Under this policy, minor updates may introduce new linting errors, which could break your project's build pipeline. To prevent this, it's recommended to use an exact version. Alternatively, you can use a tilde (`~`) version range in your _package.json_ file (e.g., `"@shayanthenerd/eslint-config": "~1.2.3"`), which will restrict updates to patches only, ensuring your project's build pipeline remains stable.
534
638
 
535
- You can find a list of all available versions and their changelogs on the [releases page](https://github.com/ShayanTheNerd/eslint-config/releases).
639
+ You can find a list of all available versions and their changelogs on the [releases page][releases].
536
640
 
537
641
  ## Roadmap to v1.0.0
538
- - [ ] Integrate additional ESLint plugins such as [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn), [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n), [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc), etc.
539
- - [ ] Add support for other frameworks and file types, including Astro, React, Next.js, MDX, Markdown, JSON, etc.
540
- - [ ] Develop a starter wizard to automate the setup of OXLint, ESLint, Prettier, and other configurations.
642
+ - [ ] Add integration for ESLint plugins such as [eslint-plugin-n][plugin-node], [eslint-plugin-unicorn][plugin-unicorn], and more.
643
+ - [ ] Add support for other React, Next, Astro, and Markdown.
644
+ - [ ] Develop an interactive starter wizard to quickly scaffold the configurations for ESLint, Prettier, etc.
541
645
 
542
646
  ## Contribution Guide
543
- Any form of contribution is always appreciated! Please chekc out the [CONTRIBUTING.md](CONTRIBUTING.md) file.
647
+ Contributions of all kinds are welcome. Please check out the [CONTRIBUTING.md][contributing] file.
544
648
 
545
649
  ## Credits
546
- This project was inspired by the work of [Anthony Fu](https://github.com/antfu), whose generous contributions to the JavaScript and the ESLint ecosystem were instrumental in making it possible.
650
+ This project was inspired by the work of [Anthony Fu][antfu], whose generous contributions to the JavaScript and the ESLint ecosystem were instrumental in making it possible.
547
651
 
548
652
  ## License
549
- [MIT](LICENSE) License © 2025-PRESENT — [Shayan Zamani](https://github.com/ShayanTheNerd)
653
+ [MIT][license] License © 2025-PRESENT — [Shayan Zamani][ShayanTheNerd]
654
+
655
+ <!-- Badges -->
656
+ [jsr]: https://jsr.io/badges/@shayanthenerd/eslint-config
657
+ [jsr-version-badge]: https://jsr.io/badges/@shayanthenerd/eslint-config?logoColor=FEFEFE&labelColor=3B82F6&color=3B82F6
658
+ [license]: ./LICENSE
659
+ [license-badge]: https://img.shields.io/badge/License-MIT-blue.svg?logoColor=FEFEFE&labelColor=3B82F6&color=3B82F6
660
+ [npm-version-badge]: https://img.shields.io/npm/v/@shayanthenerd/eslint-config?label=&logo=npm&logoColor=FEFEFE&labelColor=3B82F6&color=3B82F6
661
+ [npmx]: https://www.npmjs.com/package/@shayanthenerd/eslint-config
662
+
663
+ <!-- Editor Extensions -->
664
+ [extension-eslint]: https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
665
+ [extension-prettier]: https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
666
+ [extension-tailwind]: https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss
667
+
668
+ <!-- ESLint Plugins -->
669
+ [plugin-astro]: https://ota-meshi.github.io/eslint-plugin-astro
670
+ [plugin-css]: https://github.com/eslint/css
671
+ [plugin-cypress]: https://github.com/cypress-io/eslint-plugin-cypress
672
+ [plugin-html]: https://html-eslint.org
673
+ [plugin-import-x]: https://github.com/un-ts/eslint-plugin-import-x
674
+ [plugin-jsx-a11y]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y
675
+ [plugin-md]: https://github.com/eslint/markdown
676
+ [plugin-next]: https://nextjs.org/docs/app/api-reference/config/eslint#eslint-plugin
677
+ [plugin-node]: https://github.com/eslint-community/eslint-plugin-n
678
+ [plugin-package-json]: https://github.com/JoshuaKGoldberg/eslint-plugin-package-json
679
+ [plugin-perfectionist]: https://perfectionist.dev
680
+ [plugin-playwright]: https://github.com/mskelton/eslint-plugin-playwright
681
+ [plugin-promise]: https://github.com/eslint-community/eslint-plugin-promise
682
+ [plugin-react]: https://eslint-react.xyz
683
+ [plugin-react-hooks]: https://react.dev/reference/eslint-plugin-react-hooks
684
+ [plugin-storybook]: https://storybook.js.org/docs/configure/integration/eslint-plugin
685
+ [plugin-stylistic]: https://eslint.style
686
+ [plugin-tailwind]: https://github.com/schoero/eslint-plugin-better-tailwindcss
687
+ [plugin-ts]: https://typescript-eslint.io
688
+ [plugin-unicorn]: https://github.com/sindresorhus/eslint-plugin-unicorn
689
+ [plugin-vitest]: https://github.com/vitest-dev/eslint-plugin-vitest
690
+ [plugin-vue]: https://eslint.vuejs.org
691
+ [plugin-vue-a11y]: https://vue-a11y.github.io/eslint-plugin-vuejs-accessibility
692
+ [plugin-zod]: https://github.com/marcalexiei/eslint-zod
693
+
694
+ <!-- References -->
695
+ [antfu]: https://github.com/antfu
696
+ [contributing]: ./.github/CONTRIBUTING.md
697
+ [eslint]: https://eslint.org
698
+ [online-preview]: https://eslintconfig.netlify.app
699
+ [eslint-config-ts-setup]: https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files
700
+ [eslint-nuxt]: https://eslint.nuxt.com
701
+ [local-pkg]: https://github.com/antfu-collective/local-pkg
702
+ [prettier-shared-config]: https://prettier.io/docs/sharing-configurations
703
+ [releases]: https://github.com/ShayanTheNerd/eslint-config/releases
704
+ [semver]: https://semver.org
705
+ [ShayanTheNerd]: https://github.com/ShayanTheNerd