@shayanthenerd/eslint-config 0.14.0 → 0.16.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 (53) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +209 -190
  3. package/dist/configs/astro.mjs +34 -0
  4. package/dist/configs/base.mjs +19 -10
  5. package/dist/configs/css.mjs +2 -2
  6. package/dist/configs/cypress.mjs +2 -2
  7. package/dist/configs/html.mjs +2 -3
  8. package/dist/configs/importX.mjs +8 -4
  9. package/dist/configs/oxlintOverrides.mjs +20 -14
  10. package/dist/configs/perfectionist.mjs +8 -4
  11. package/dist/configs/playwright.mjs +2 -2
  12. package/dist/configs/restrictedExports.mjs +1 -1
  13. package/dist/configs/storybook.mjs +2 -2
  14. package/dist/configs/stylistic.mjs +8 -4
  15. package/dist/configs/tailwind.mjs +14 -14
  16. package/dist/configs/typescript.mjs +8 -4
  17. package/dist/configs/vitest.mjs +2 -2
  18. package/dist/configs/vue.mjs +2 -2
  19. package/dist/configs/vueComponentNames.mjs +1 -1
  20. package/dist/configs/vueServerComponents.mjs +1 -1
  21. package/dist/configs/zod.mjs +8 -4
  22. package/dist/{utils → helpers}/globs.mjs +2 -1
  23. package/dist/{utils → helpers}/ignores/defaultIgnorePatterns.mjs +3 -1
  24. package/dist/{utils → helpers}/ignores/getIgnorePatterns.mjs +1 -1
  25. package/dist/{utils → helpers}/ignores/resolveGitignorePatterns.mjs +1 -1
  26. package/dist/{utils → helpers}/isPackageDetected.mjs +1 -1
  27. package/dist/{utils → helpers}/options/defaultOptions.mjs +15 -7
  28. package/dist/{utils → helpers}/options/enableDetectedConfigs.mjs +2 -3
  29. package/dist/{utils → helpers}/options/mergeWithDefaults.mjs +4 -5
  30. package/dist/{utils → helpers}/vue/getRestrictedVueElements.mjs +1 -1
  31. package/dist/{utils → helpers}/vue/getRestrictedVueInputs.mjs +1 -1
  32. package/dist/index.mjs +6 -4
  33. package/dist/oxlint.config.jsonc +120 -206
  34. package/dist/prettier.config.mjs +1 -1
  35. package/dist/rules/astro.mjs +61 -0
  36. package/dist/rules/css.mjs +1 -1
  37. package/dist/rules/html.mjs +3 -3
  38. package/dist/rules/importX.mjs +1 -1
  39. package/dist/rules/javascript.mjs +1 -2
  40. package/dist/rules/perfectionist.mjs +2 -2
  41. package/dist/rules/stylistic.mjs +10 -7
  42. package/dist/rules/tailwind.mjs +4 -4
  43. package/dist/rules/typescript.mjs +2 -2
  44. package/dist/rules/vue.mjs +6 -6
  45. package/dist/rules/vueAccessibility.mjs +1 -1
  46. package/dist/types/configOptions/base.d.mts +8 -8
  47. package/dist/types/configOptions/nuxt.d.mts +3 -3
  48. package/dist/types/configOptions/stylistic.d.mts +0 -15
  49. package/dist/types/configOptions/test.d.mts +4 -4
  50. package/dist/types/configOptions/vue.d.mts +1 -1
  51. package/dist/types/eslint-schema.d.mts +1031 -237
  52. package/dist/types/index.d.mts +46 -20
  53. package/package.json +142 -124
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Shayan Zamani
3
+ Copyright (c) 2026 Shayan Zamani
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -4,7 +4,7 @@ A modern, flexible ESLint configuration for enforcing best practices and maintai
4
4
 
5
5
  - **Performant**: Powered by [OXLint (OXC Linter)](https://oxc.rs/docs/guide/usage/linter) for rapid linting
6
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, Vue & Nuxt, Tailwind, Storybook, Vitest & Playwright, and more
7
+ - **Comprehensive**: Dependency detection with support for TypeScript, Astro, Vue & Nuxt, Tailwind, Storybook, Vitest & Playwright, and more
8
8
  - **Automatic Formatting**: Fine-grained control over formatting with [ESLint Stylistic](https://eslint.style), eliminating the need for Prettier
9
9
  - **Smart Defaults**: Respects your _.gitignore_ file and provides reasonable, opinionated, yet [highly customizable](#customization) defaults
10
10
  - **Developer-friendly**: Easy to use and well-documented with JSDoc
@@ -32,9 +32,13 @@ A modern, flexible ESLint configuration for enforcing best practices and maintai
32
32
  1. Install the package:
33
33
  ```shell
34
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
35
39
  ```
36
40
 
37
- OXLint and all necessary ESLint plugins and parsers will be installed automatically.
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.
38
42
 
39
43
  2. Create an ESLint config file (_eslint.config.js_) at the root of your project:
40
44
  ```js
@@ -64,7 +68,7 @@ export default eslintConfigNuxt(eslintConfig);
64
68
  > [!NOTE]
65
69
  > The Nuxt config relies on the Vue config, so make sure it's enabled (either automatically or manually).
66
70
 
67
- 3. Create an OXLint config file (_.oxlintrc.json_) in the root of your project:
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:
68
72
  ```jsonc
69
73
  {
70
74
  "$schema": "./node_modules/oxlint/configuration_schema.json", // Optional
@@ -73,14 +77,20 @@ export default eslintConfigNuxt(eslintConfig);
73
77
 
74
78
  /* Customize based on your development environment. */
75
79
  "env": {
76
- "builtin": true,
77
- "es2026": true,
80
+ "worker": false,
78
81
  "commonjs": false,
82
+ "bun": false,
83
+ "deno": false,
79
84
  "node": true,
85
+ "nodeBuiltin": true,
80
86
  "browser": true,
81
- "worker": true,
82
87
  "serviceworker": false,
83
- "webextensions": false
88
+ "sharedWorker": false,
89
+ "webextension": false,
90
+ "audioWorklet": false,
91
+ "vitest": true,
92
+ "vue": true,
93
+ "astro": true
84
94
  },
85
95
 
86
96
  "categories": {
@@ -122,16 +132,20 @@ npm run lint:inspect
122
132
  ```
123
133
 
124
134
  ## Automatic Dependency Detection
125
- By default, this config automatically detects dependencies in your project, and enables the appropriate ESLint configurations. This is powered by [local-pkg](https://github.com/antfu-collective/local-pkg), which scans your _node_modules_ directory instead of _package.json_. <br />
126
- For instance, if you install a package "A" that depends on another package "B", your package manager will install both. Even if "B" isn't listed in your _package.json_ file, it will be present in _node_modules_. Consequently, this config will detect both "A" and "B" and enable the appropriate ESLint configurations for them. <br />
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_.
140
+
127
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.
128
142
 
129
- Unlike other plugins, the configurations for Tailwind aren't automatically enabled upon dependency detection. This is because you must explicitly provide the path to your Tailwind config file or entry point.
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.
130
144
 
131
145
  Stylistic, Perfectionist, ImportX, and core (JavaScript) rules are enabled by default.
132
146
 
133
147
  ## Formatting
134
- This config uses [ESLint Stylistic](https://eslint.style) to format JavaScript and TypeScript files (`?([mc])[jt]s?(x)`) as well as 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:
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:
135
149
 
136
150
  1. Install Prettier:
137
151
  ```shell
@@ -149,7 +163,7 @@ export default {
149
163
  };
150
164
  ```
151
165
 
152
- Or if you prefer using TypeScrpit (_prettier.config.ts_):
166
+ Or if you prefer using TypeScript (_prettier.config.ts_):
153
167
  ```ts
154
168
  import type { Config } from 'prettier';
155
169
 
@@ -161,17 +175,15 @@ export default {
161
175
  } satisfies Config;
162
176
  ```
163
177
 
164
- 3. To prevent conflicts with ESLint, Prettier should be configured to only format files other than JavaScript, TypeScript, HTML, and Vue. Hence, add the following script to your _package.json_ file:
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:
165
179
  ```json
166
180
  {
167
181
  "scripts": {
168
- "format": "prettier --write . '!**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,html,vue}' --cache"
182
+ "format": "prettier --write . '!**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,html,vue,astro}' --cache"
169
183
  }
170
184
  }
171
185
  ```
172
186
 
173
- For IDE setup guidance, refer to [VS Code Integration](#vs-code-integration).
174
-
175
187
  ## VS Code Integration
176
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:
177
189
  ```jsonc
@@ -181,7 +193,7 @@ Install VS Code extensions for [ESLint](https://marketplace.visualstudio.com/ite
181
193
 
182
194
  /* Enforce either tabs or spaces for indentation. */
183
195
  "editor.tabSize": 2,
184
- "editor.insertSpaces": false,
196
+ "editor.insertSpaces": true,
185
197
  "editor.detectIndentation": false,
186
198
 
187
199
  "editor.codeActionsOnSave": {
@@ -201,7 +213,7 @@ Install VS Code extensions for [ESLint](https://marketplace.visualstudio.com/ite
201
213
 
202
214
  /* Format and lint JavaScript, TypeScript, HTML, and Vue files with ESLint, while everything else is formatted with Prettier. */
203
215
  "editor.defaultFormatter": "esbenp.prettier-vscode",
204
- "[javascript][typescript][javascriptreact][typescriptreact][html][vue]": {
216
+ "[javascript][typescript][javascriptreact][typescriptreact][html][vue][astro]": {
205
217
  "editor.defaultFormatter": "dbaeumer.vscode-eslint"
206
218
  },
207
219
  "eslint.validate": [
@@ -212,7 +224,8 @@ Install VS Code extensions for [ESLint](https://marketplace.visualstudio.com/ite
212
224
  "html",
213
225
  "css",
214
226
  "tailwindcss",
215
- "vue"
227
+ "vue",
228
+ "astro"
216
229
  ],
217
230
 
218
231
  /* Adjust these based on the features you're using to silently auto-fix the stylistic rules in your IDE. */
@@ -269,8 +282,7 @@ Since OXLint and ESLint use separate config files, customizations made in your E
269
282
  ```
270
283
 
271
284
  ### ESLint
272
-
273
- `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:
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:
274
286
  ```ts
275
287
  interface Overrides {
276
288
  name: '',
@@ -312,7 +324,7 @@ export default defineConfig(
312
324
 
313
325
  /* ESLint Flat Configs: */
314
326
  {
315
- files: ['**/*.yaml', '**/*.yml'],
327
+ files: ['**/*.yaml', '**/*.yml'],
316
328
  ignores: ['**/*.schema.yaml', '**/*.schema.yml'],
317
329
  extends: [pluginYaml.configs.recommended],
318
330
  },
@@ -322,187 +334,194 @@ export default defineConfig(
322
334
 
323
335
  ## API Reference
324
336
  <details>
325
- <summary>The API reference</summary>
326
- Some types are omitted or aliased for brevity.
327
-
328
- ```ts
329
- interface options {
330
- autoDetectDeps?: boolean | 'verbose',
331
- gitignore?: false | string,
332
- packageDir?: string,
333
- env?: 'bun' | 'node',
334
- tsConfig?: {
335
- rootDir: string,
336
- filename?: string,
337
- },
337
+ <summary>The API reference</summary>
338
+ Some types are omitted or aliased for brevity.
339
+
340
+ ```ts
341
+ interface Options {
342
+ autoDetectDeps?: boolean | 'verbose',
343
+ gitignore?: false | string,
344
+ packageDir?: string,
345
+ env?: 'bun' | 'node',
346
+ tsConfig?: {
347
+ rootDir: string,
348
+ filename?: string,
349
+ },
338
350
 
339
- global?: {
340
- name?: string,
341
- basePath?: string,
342
- ignores?: string[],
343
- globals?: {
344
- node?: boolean,
345
- commonjs?: boolean,
346
- browser?: boolean,
347
- worker?: boolean,
348
- serviceworker?: boolean,
349
- webextension?: boolean,
350
- custom?: {
351
- [key: string]: boolean | 'off' | 'readonly' | 'readable' | 'writable' | 'writeable',
351
+ global?: {
352
+ name?: string,
353
+ basePath?: string,
354
+ ignores?: string[],
355
+ globals?: {
356
+ worker?: boolean,
357
+ commonjs?: boolean,
358
+ bun?: boolean,
359
+ deno?: boolean,
360
+ node?: boolean,
361
+ nodeBuiltin?: boolean,
362
+ browser?: boolean,
363
+ serviceworker?: boolean,
364
+ sharedWorker?: boolean,
365
+ webextension?: boolean,
366
+ audioWorklet?: boolean,
367
+ vitest?: boolean,
368
+ vue?: boolean,
369
+ astro?: boolean,
370
+ custom?: {
371
+ [key: string]: boolean | 'off' | 'readonly' | 'readable' | 'writable' | 'writeable',
372
+ },
373
+ }
374
+ linterOptions?: {
375
+ noInlineConfig?: boolean,
376
+ reportUnusedInlineConfigs?: 'error' | 'off' | 'warn',
377
+ reportUnusedDisableDirectives?: 'error' | 'off' | 'warn',
352
378
  },
353
- }
354
- linterOptions?: {
355
- noInlineConfig?: boolean,
356
- reportUnusedInlineConfigs?: 'error' | 'off' | 'warn',
357
- reportUnusedDisableDirectives?: 'error' | 'off' | 'warn',
379
+ settings?: {
380
+ [name: string]: unknown,
381
+ }
382
+ rules?: Linter.RulesRecord,
358
383
  },
359
- settings?: {
360
- [name: string]: unknown,
361
- }
362
- rules?: Linter.RulesRecord,
363
- },
364
384
 
365
- configs?: {
366
- oxlint?: false | string,
367
- base?: {
368
- maxDepth?: number,
369
- maxNestedCallbacks?: number,
370
- preferNamedExports?: boolean,
371
- functionStyle?: 'declaration' | 'expression',
372
- overrides?: {},
373
- },
374
- stylistic?: boolean | {
375
- semi?: 'always' | 'never',
376
- trailingComma?: 'always' | 'never' | 'always-multiline' | 'only-multiline',
377
- memberDelimiterStyle?: 'semi' | 'comma',
378
- quotes?: 'single' | 'double' | 'backtick',
379
- jsxQuotes?: 'prefer-single' | 'prefer-double',
380
- arrowParens?: 'always' | 'as-needed',
381
- useTabs?: boolean,
382
- indent?: number,
383
- maxConsecutiveEmptyLines?: number,
384
- maxLineLength?: number,
385
- maxAttributesPerLine?: number,
386
- selfCloseVoidHTMLElements?: 'never' | 'always',
387
- overrides?: {},
388
- },
389
- html?: boolean | {
390
- useBaseline?: number | false | 'widely' | 'newly',
391
- idNamingConvention?: 'camelCase' | 'snake_case' | 'PascalCase' | 'kebab-case',
392
- overrides?: {},
393
- },
394
- css?: boolean | {
395
- useBaseline?: number | false | 'widely' | 'newly',
396
- allowedRelativeFontUnits?: ('%' | 'cap' | 'ch' | 'em' | 'ex' | 'ic' | 'lh' | 'rcap' | 'rch' | 'rem' | 'rex' | 'ric' | 'rlh')[],
397
- overrides?: {},
398
- },
399
- tailwind?: false | {
400
- config: string,
401
- entryPoint?: string,
402
- multilineSort?: boolean,
403
- ignoredUnregisteredClasses?: string[],
404
- overrides?: {},
405
- } | {
406
- config?: string,
407
- entryPoint: string,
408
- multilineSort?: boolean,
409
- ignoredUnregisteredClasses?: string[],
410
- overrides?: {},
411
- },
412
- typescript?: boolean | {
413
- allowedDefaultProjects?: string[],
414
- methodSignatureStyle?: 'property' | 'method',
415
- typeDefinitionStyle?: 'interface' | 'type',
416
- overrides?: {},
417
- },
418
- importX?: boolean | {
419
- removeUnusedImports?: boolean,
420
- overrides?: {},
421
- },
422
- perfectionist?: boolean | {
423
- sortType?: 'custom' | 'natural' | 'alphabetical' | 'line-length' | 'unsorted',
424
- overrides?: {},
425
- },
426
- vue?: boolean | {
427
- accessibility?: boolean | {
428
- anchorComponents?: string[],
429
- imageComponents?: string[],
430
- accessibleChildComponents?: string[],
385
+ configs?: {
386
+ oxlint?: false | string,
387
+ base?: {
388
+ maxDepth?: number,
389
+ maxNestedCallbacks?: number,
390
+ preferNamedExports?: boolean,
391
+ functionStyle?: 'declaration' | 'expression',
392
+ overrides?: {},
393
+ },
394
+ 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
+ arrowParens?: 'always' | 'as-needed',
401
+ indent?: number,
402
+ maxConsecutiveEmptyLines?: number,
403
+ maxLineLength?: number,
404
+ maxAttributesPerLine?: number,
405
+ selfCloseVoidHTMLElements?: 'never' | 'always',
406
+ overrides?: {},
431
407
  },
432
- blockOrder?: (
433
- | 'docs'
434
- | 'template'
435
- | 'script[setup]'
436
- | 'style[scoped]'
437
- | 'i18n[locale=en]'
438
- | 'script:not([setup])'
439
- | 'style:not([scoped])'
440
- | 'i18n:not([locale=en])'
441
- )[],
442
- macrosOrder?: (
443
- | 'definePage'
444
- | 'defineModel'
445
- | 'defineProps'
446
- | 'defineEmits'
447
- | 'defineSlots'
448
- | 'defineCustom'
449
- | 'defineExpose'
450
- | 'defineOptions'
451
- )[],
452
- attributesOrder?: RuleOptions<'vue/attributes-order'>['order'],
453
- attributeHyphenation?: 'never' | 'always',
454
- preferVBindSameNameShorthand?: 'never' | 'always',
455
- preferVBindTrueShorthand?: 'never' | 'always',
456
- allowedStyleAttributes?: ['module' | 'plain' | 'scoped', 'module' | 'plain' | 'scoped'],
457
- blockLang?: {
458
- style?: 'css' | 'implicit' | 'scss' | 'postcss',
459
- script?: 'js' | 'ts' | 'jsx' | 'tsx' | 'implicit',
408
+ html?: boolean | {
409
+ useBaseline?: number | false | 'widely' | 'newly',
410
+ idNamingConvention?: 'camelCase' | 'snake_case' | 'PascalCase' | 'kebab-case',
411
+ overrides?: {},
460
412
  },
461
- destructureProps?: 'never' | 'always',
462
- componentNameCaseInTemplate?: 'PascalCase' | 'kebab-case',
463
- vForDelimiterStyle?: 'in' | 'of',
464
- vOnHandlerStyle?: 'inline' | 'inline-function' | ['method', 'inline' | 'inline-function'],
465
- restrictedElements?: (string | {
466
- element: string | string[],
467
- message: string,
468
- })[],
469
- restrictedStaticAttributes?: (string | {
470
- key: string,
471
- value?: string | true,
472
- element: string,
473
- message: string,
474
- })[],
475
- ignoredUndefinedComponents?: string[],
476
- overrides?: {},
477
- },
478
- nuxt?: boolean | {
479
- image?: boolean,
480
- icon?: boolean | {
481
- component?: string,
482
- }
483
- ui?: boolean | {
484
- prefix?: string,
485
- }
486
- },
487
- test?: {
488
- storybook?: boolean | {
413
+ css?: boolean | {
414
+ useBaseline?: number | false | 'widely' | 'newly',
415
+ allowedRelativeFontUnits?: ('%' | 'cap' | 'ch' | 'em' | 'ex' | 'ic' | 'lh' | 'rcap' | 'rch' | 'rem' | 'rex' | 'ric' | 'rlh')[],
489
416
  overrides?: {},
490
417
  },
491
- vitest?: boolean | {
418
+ tailwind?: false | {
419
+ config: string,
420
+ entryPoint?: string,
421
+ multilineSort?: boolean,
422
+ ignoredUnregisteredClasses?: string[],
423
+ overrides?: {},
424
+ } | {
425
+ config?: string,
426
+ entryPoint: string,
427
+ multilineSort?: boolean,
428
+ ignoredUnregisteredClasses?: string[],
429
+ overrides?: {},
430
+ },
431
+ typescript?: boolean | {
432
+ allowedDefaultProjects?: string[],
433
+ methodSignatureStyle?: 'property' | 'method',
434
+ typeDefinitionStyle?: 'interface' | 'type',
492
435
  overrides?: {},
493
436
  },
494
- playwright?: boolean | {
437
+ importX?: boolean | {
438
+ removeUnusedImports?: boolean,
495
439
  overrides?: {},
496
440
  },
497
- cypress?: boolean | {
441
+ perfectionist?: boolean | {
442
+ sortType?: 'custom' | 'natural' | 'alphabetical' | 'line-length' | 'unsorted',
498
443
  overrides?: {},
499
444
  },
500
- testFunction?: 'test' | 'it',
501
- maxNestedDescribe?: number,
445
+ vue?: boolean | {
446
+ accessibility?: boolean | {
447
+ anchorComponents?: string[],
448
+ imageComponents?: string[],
449
+ accessibleChildComponents?: string[],
450
+ },
451
+ blockOrder?: (
452
+ | 'docs'
453
+ | 'template'
454
+ | 'script[setup]'
455
+ | 'style[scoped]'
456
+ | 'i18n[locale=en]'
457
+ | 'script:not([setup])'
458
+ | 'style:not([scoped])'
459
+ | 'i18n:not([locale=en])'
460
+ )[],
461
+ macrosOrder?: (
462
+ | 'definePage'
463
+ | 'defineModel'
464
+ | 'defineProps'
465
+ | 'defineEmits'
466
+ | 'defineSlots'
467
+ | 'defineCustom'
468
+ | 'defineExpose'
469
+ | 'defineOptions'
470
+ )[],
471
+ attributesOrder?: RuleOptions<'vue/attributes-order'>['order'],
472
+ attributeHyphenation?: 'never' | 'always',
473
+ preferVBindSameNameShorthand?: 'never' | 'always',
474
+ 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
+ restrictedElements?: (string | {
485
+ element: string | string[],
486
+ message: string,
487
+ })[],
488
+ restrictedStaticAttributes?: (string | {
489
+ key: string,
490
+ value?: string | true,
491
+ element: string,
492
+ message: string,
493
+ })[],
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
+ }
505
+ },
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,
521
+ },
502
522
  },
503
- },
504
- }
505
- ```
523
+ }
524
+ ```
506
525
  </details>
507
526
 
508
527
  ## Versioning Policy
@@ -521,10 +540,10 @@ You can find a list of all available versions and their changelogs on the [relea
521
540
  - [ ] Develop a starter wizard to automate the setup of OXLint, ESLint, Prettier, and other configurations.
522
541
 
523
542
  ## Contribution Guide
524
- Any form of contribution is always appreciated! Please refer to the [CONTRIBUTING.md](CONTRIBUTING.md) file.
543
+ Any form of contribution is always appreciated! Please chekc out the [CONTRIBUTING.md](CONTRIBUTING.md) file.
525
544
 
526
545
  ## Credits
527
- This project was inspired by the work of [Anthony Fu](https://github.com/antfu), whose generous contributions to the JavaScript and ESLint ecosystem were instrumental in making it possible.
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.
528
547
 
529
548
  ## License
530
549
  [MIT](LICENSE) License © 2025-PRESENT — [Shayan Zamani](https://github.com/ShayanTheNerd)
@@ -0,0 +1,34 @@
1
+ import { globs } from "../helpers/globs.mjs";
2
+ import { isEnabled } from "../utils/isEnabled.mjs";
3
+ import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
4
+ import { getAstroRules } from "../rules/astro.mjs";
5
+ import { mergeConfigs } from "eslint-flat-config-utils";
6
+ import { parser } from "typescript-eslint";
7
+ import eslintPluginAstro from "eslint-plugin-astro";
8
+ import * as eslintParserAstro from "astro-eslint-parser";
9
+
10
+ //#region src/configs/astro.ts
11
+ function getAstroConfig(options) {
12
+ const { astro } = options.configs;
13
+ const { overrides } = isEnabled(astro) ? astro : defaultOptions.configs.astro;
14
+ return mergeConfigs({
15
+ name: "shayanthenerd/astro",
16
+ files: [globs.astro],
17
+ plugins: { astro: eslintPluginAstro },
18
+ languageOptions: {
19
+ globals: {
20
+ Astro: "readonly",
21
+ Fragment: "readonly"
22
+ },
23
+ parser: eslintParserAstro,
24
+ parserOptions: {
25
+ parser,
26
+ extraFileExtensions: [".astro"]
27
+ }
28
+ },
29
+ rules: getAstroRules()
30
+ }, overrides);
31
+ }
32
+
33
+ //#endregion
34
+ export { getAstroConfig };
@@ -1,4 +1,4 @@
1
- import { globs } from "../utils/globs.mjs";
1
+ import { globs } from "../helpers/globs.mjs";
2
2
  import { isEnabled } from "../utils/isEnabled.mjs";
3
3
  import { getJavaScriptRules } from "../rules/javascript.mjs";
4
4
  import { mergeConfigs } from "eslint-flat-config-utils";
@@ -7,10 +7,14 @@ import globals from "globals";
7
7
 
8
8
  //#region src/configs/base.ts
9
9
  function getBaseConfig(options) {
10
- const { configs: { vue, test: { vitest }, base: { overrides } }, global: { globals: { node, worker, browser, commonjs, webextension, serviceworker, custom: userGlobals } } } = options;
10
+ const { env, configs: { vue, astro, base: { overrides } }, global: { globals: { bun, node, deno, vitest, worker, browser, commonjs, nodeBuiltin, audioWorklet, webextension, sharedWorker, serviceworker, vue: vueGlobals, astro: astroGlobals, custom: userGlobals } } } = options;
11
11
  return mergeConfigs({
12
12
  name: "shayanthenerd/base",
13
- files: isEnabled(vue) ? [globs.src, globs.vue] : [globs.src],
13
+ files: [
14
+ globs.src,
15
+ isEnabled(vue) ? globs.vue : "",
16
+ isEnabled(astro) ? globs.astro : ""
17
+ ].filter(Boolean),
14
18
  languageOptions: {
15
19
  parser,
16
20
  parserOptions: {
@@ -23,15 +27,20 @@ function getBaseConfig(options) {
23
27
  globals: {
24
28
  ...globals.builtin,
25
29
  ...globals.es2026,
30
+ ...worker && globals.worker,
26
31
  ...commonjs && globals.commonjs,
32
+ ...bun && env === "bun" && globals.bunBuiltin,
33
+ ...deno && env === "deno" && globals.denoBuiltin,
27
34
  ...node && globals.node,
28
- ...node && globals.nodeBuiltin,
29
- ...browser && globals.browser,
30
- ...worker && globals.worker,
31
- ...serviceworker && globals.serviceworker,
32
- ...webextension && globals.webextensions,
33
- ...isEnabled(vue) && globals.vue,
34
- ...isEnabled(vitest) && globals.vitest,
35
+ ...nodeBuiltin && env === "node" && globals.nodeBuiltin,
36
+ ...browser && env === "browser" && globals.browser,
37
+ ...sharedWorker && env === "browser" && globals.sharedWorker,
38
+ ...serviceworker && env === "browser" && globals.serviceworker,
39
+ ...webextension && env === "browser" && globals.webextensions,
40
+ ...audioWorklet && env === "browser" && globals.audioWorklet,
41
+ ...vitest && globals.vitest,
42
+ ...vueGlobals && isEnabled(vue) && globals.vue,
43
+ ...astroGlobals && isEnabled(astro) && globals.astro,
35
44
  ...userGlobals
36
45
  }
37
46
  },
@@ -1,6 +1,6 @@
1
- import { globs } from "../utils/globs.mjs";
1
+ import { globs } from "../helpers/globs.mjs";
2
2
  import { isEnabled } from "../utils/isEnabled.mjs";
3
- import { defaultOptions } from "../utils/options/defaultOptions.mjs";
3
+ import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
4
4
  import { getCSSRules } from "../rules/css.mjs";
5
5
  import eslintPluginCSS from "@eslint/css";
6
6
  import { mergeConfigs } from "eslint-flat-config-utils";
@@ -1,6 +1,6 @@
1
- import { globs } from "../utils/globs.mjs";
1
+ import { globs } from "../helpers/globs.mjs";
2
2
  import { isEnabled } from "../utils/isEnabled.mjs";
3
- import { defaultOptions } from "../utils/options/defaultOptions.mjs";
3
+ import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
4
4
  import { getCypressRules } from "../rules/cypress.mjs";
5
5
  import { mergeConfigs } from "eslint-flat-config-utils";
6
6
  import eslintPluginCypress from "eslint-plugin-cypress";
@@ -1,6 +1,6 @@
1
- import { globs } from "../utils/globs.mjs";
1
+ import { globs } from "../helpers/globs.mjs";
2
2
  import { isEnabled } from "../utils/isEnabled.mjs";
3
- import { defaultOptions } from "../utils/options/defaultOptions.mjs";
3
+ import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
4
4
  import { getHTMLRules } from "../rules/html.mjs";
5
5
  import { mergeConfigs } from "eslint-flat-config-utils";
6
6
  import eslintPluginHTML from "@html-eslint/eslint-plugin";
@@ -14,7 +14,6 @@ function getHTMLConfig(options) {
14
14
  name: "shayanthenerd/html",
15
15
  files: [globs.html],
16
16
  plugins: { "@html-eslint": eslintPluginHTML },
17
- language: "html/html",
18
17
  languageOptions: { parser: eslintParserHTML },
19
18
  rules: getHTMLRules(options)
20
19
  }, overrides);