@shayanthenerd/eslint-config 0.13.1 → 0.15.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 +192 -183
  3. package/dist/configs/base.mjs +13 -9
  4. package/dist/configs/css.mjs +2 -2
  5. package/dist/configs/cypress.mjs +2 -2
  6. package/dist/configs/html.mjs +2 -2
  7. package/dist/configs/importX.mjs +2 -2
  8. package/dist/configs/oxlintOverrides.mjs +16 -11
  9. package/dist/configs/perfectionist.mjs +2 -2
  10. package/dist/configs/playwright.mjs +2 -2
  11. package/dist/configs/restrictedExports.mjs +1 -1
  12. package/dist/configs/storybook.mjs +2 -2
  13. package/dist/configs/stylistic.mjs +2 -2
  14. package/dist/configs/tailwind.mjs +4 -4
  15. package/dist/configs/typescript.mjs +2 -2
  16. package/dist/configs/vitest.mjs +2 -2
  17. package/dist/configs/vue.mjs +2 -2
  18. package/dist/configs/vueComponentNames.mjs +1 -1
  19. package/dist/configs/vueServerComponents.mjs +1 -1
  20. package/dist/configs/zod.mjs +21 -0
  21. package/dist/{utils → helpers}/globs.mjs +1 -1
  22. package/dist/{utils → helpers}/ignores/defaultIgnorePatterns.mjs +1 -1
  23. package/dist/{utils → helpers}/ignores/getIgnorePatterns.mjs +1 -1
  24. package/dist/{utils → helpers}/ignores/resolveGitignorePatterns.mjs +1 -1
  25. package/dist/{utils → helpers}/isPackageDetected.mjs +5 -3
  26. package/dist/{utils → helpers}/options/defaultOptions.mjs +14 -7
  27. package/dist/{utils → helpers}/options/enableDetectedConfigs.mjs +2 -3
  28. package/dist/{utils → helpers}/options/mergeWithDefaults.mjs +4 -5
  29. package/dist/{utils → helpers}/vue/getRestrictedVueElements.mjs +1 -1
  30. package/dist/{utils → helpers}/vue/getRestrictedVueInputs.mjs +1 -1
  31. package/dist/index.mjs +6 -4
  32. package/dist/oxlint.config.jsonc +209 -201
  33. package/dist/prettier.config.mjs +1 -1
  34. package/dist/rules/css.mjs +1 -1
  35. package/dist/rules/html.mjs +3 -3
  36. package/dist/rules/importX.mjs +1 -1
  37. package/dist/rules/javascript.mjs +1 -2
  38. package/dist/rules/perfectionist.mjs +2 -2
  39. package/dist/rules/stylistic.mjs +22 -10
  40. package/dist/rules/tailwind.mjs +4 -4
  41. package/dist/rules/typescript.mjs +6 -3
  42. package/dist/rules/vitest.mjs +4 -0
  43. package/dist/rules/vue.mjs +6 -6
  44. package/dist/rules/vueAccessibility.mjs +1 -1
  45. package/dist/rules/zod.mjs +20 -0
  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 +769 -270
  52. package/dist/types/index.d.mts +43 -19
  53. package/package.json +139 -123
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
@@ -35,6 +35,13 @@ npm i -D @shayanthenerd/eslint-config
35
35
  ```
36
36
 
37
37
  OXLint and all necessary ESLint plugins and parsers will be installed automatically.
38
+ > [!important]
39
+ > If you're using PNPM without `shamefullyHoist: true`, make sure to install `eslint` and `oxlint` separately with `pnpm i -D eslint oxlint`, or hoist them in _pnpm-workspace.yaml_:
40
+ > ```yaml
41
+ > publicHoistPattern:
42
+ > - eslint
43
+ > - oxlint
44
+ > ```
38
45
 
39
46
  2. Create an ESLint config file (_eslint.config.js_) at the root of your project:
40
47
  ```js
@@ -64,7 +71,7 @@ export default eslintConfigNuxt(eslintConfig);
64
71
  > [!NOTE]
65
72
  > The Nuxt config relies on the Vue config, so make sure it's enabled (either automatically or manually).
66
73
 
67
- 3. Create an OXLint config file (_.oxlintrc.json_) in the root of your project:
74
+ 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
75
  ```jsonc
69
76
  {
70
77
  "$schema": "./node_modules/oxlint/configuration_schema.json", // Optional
@@ -122,11 +129,15 @@ npm run lint:inspect
122
129
  ```
123
130
 
124
131
  ## 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 />
132
+ 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 />
133
+ > [!IMPORTANT]
134
+ > This behavior is particularly noticeable with package managers that use a flat _node_modules_ structure, such as **NPM** or **Bun**. <br />
135
+ 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 />
136
+ 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_.
137
+
127
138
  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
139
 
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.
140
+ 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
141
 
131
142
  Stylistic, Perfectionist, ImportX, and core (JavaScript) rules are enabled by default.
132
143
 
@@ -149,7 +160,7 @@ export default {
149
160
  };
150
161
  ```
151
162
 
152
- Or if you prefer using TypeScrpit (_prettier.config.ts_):
163
+ Or if you prefer using TypeScript (_prettier.config.ts_):
153
164
  ```ts
154
165
  import type { Config } from 'prettier';
155
166
 
@@ -170,7 +181,7 @@ export default {
170
181
  }
171
182
  ```
172
183
 
173
- For IDE setup guidance, refer to [VS Code Integration](#vs-code-integration).
184
+ For IDE setup guidance, see [VS Code Integration](#vs-code-integration).
174
185
 
175
186
  ## VS Code Integration
176
187
  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:
@@ -181,7 +192,7 @@ Install VS Code extensions for [ESLint](https://marketplace.visualstudio.com/ite
181
192
 
182
193
  /* Enforce either tabs or spaces for indentation. */
183
194
  "editor.tabSize": 2,
184
- "editor.insertSpaces": false,
195
+ "editor.insertSpaces": true,
185
196
  "editor.detectIndentation": false,
186
197
 
187
198
  "editor.codeActionsOnSave": {
@@ -194,9 +205,10 @@ Install VS Code extensions for [ESLint](https://marketplace.visualstudio.com/ite
194
205
  "source.fixAll.oxc": "explicit",
195
206
  "source.fixAll.eslint": "explicit"
196
207
  },
197
- "eslint.run": "onSave",
198
- "oxc.lint.run": "onSave",
208
+ "oxc.lint.run": "onSave",
209
+ "eslint.run": "onSave",
199
210
  "editor.formatOnSave": true,
211
+ "eslint.format.enable": true,
200
212
 
201
213
  /* Format and lint JavaScript, TypeScript, HTML, and Vue files with ESLint, while everything else is formatted with Prettier. */
202
214
  "editor.defaultFormatter": "esbenp.prettier-vscode",
@@ -268,8 +280,7 @@ Since OXLint and ESLint use separate config files, customizations made in your E
268
280
  ```
269
281
 
270
282
  ### ESLint
271
-
272
- `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:
283
+ `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:
273
284
  ```ts
274
285
  interface Overrides {
275
286
  name: '',
@@ -311,7 +322,7 @@ export default defineConfig(
311
322
 
312
323
  /* ESLint Flat Configs: */
313
324
  {
314
- files: ['**/*.yaml', '**/*.yml'],
325
+ files: ['**/*.yaml', '**/*.yml'],
315
326
  ignores: ['**/*.schema.yaml', '**/*.schema.yml'],
316
327
  extends: [pluginYaml.configs.recommended],
317
328
  },
@@ -321,187 +332,186 @@ export default defineConfig(
321
332
 
322
333
  ## API Reference
323
334
  <details>
324
- <summary>The API reference</summary>
325
- Some types are omitted or aliased for brevity.
326
-
327
- ```ts
328
- interface options {
329
- autoDetectDeps?: boolean | 'verbose',
330
- gitignore?: false | string,
331
- packageDir?: string,
332
- env?: 'bun' | 'node',
333
- tsConfig?: {
334
- rootDir: string,
335
- filename?: string,
336
- },
335
+ <summary>The API reference</summary>
336
+ Some types are omitted or aliased for brevity.
337
+
338
+ ```ts
339
+ interface Options {
340
+ autoDetectDeps?: boolean | 'verbose',
341
+ gitignore?: false | string,
342
+ packageDir?: string,
343
+ env?: 'bun' | 'node',
344
+ tsConfig?: {
345
+ rootDir: string,
346
+ filename?: string,
347
+ },
337
348
 
338
- global?: {
339
- name?: string,
340
- basePath?: string,
341
- ignores?: string[],
342
- globals?: {
343
- node?: boolean,
344
- commonjs?: boolean,
345
- browser?: boolean,
346
- worker?: boolean,
347
- serviceworker?: boolean,
348
- webextension?: boolean,
349
- custom?: {
350
- [key: string]: boolean | 'off' | 'readonly' | 'readable' | 'writable' | 'writeable',
349
+ global?: {
350
+ name?: string,
351
+ basePath?: string,
352
+ ignores?: string[],
353
+ globals?: {
354
+ node?: boolean,
355
+ commonjs?: boolean,
356
+ browser?: boolean,
357
+ worker?: boolean,
358
+ serviceworker?: boolean,
359
+ webextension?: boolean,
360
+ custom?: {
361
+ [key: string]: boolean | 'off' | 'readonly' | 'readable' | 'writable' | 'writeable',
362
+ },
363
+ }
364
+ linterOptions?: {
365
+ noInlineConfig?: boolean,
366
+ reportUnusedInlineConfigs?: 'error' | 'off' | 'warn',
367
+ reportUnusedDisableDirectives?: 'error' | 'off' | 'warn',
351
368
  },
352
- }
353
- linterOptions?: {
354
- noInlineConfig?: boolean,
355
- reportUnusedInlineConfigs?: 'error' | 'off' | 'warn',
356
- reportUnusedDisableDirectives?: 'error' | 'off' | 'warn',
369
+ settings?: {
370
+ [name: string]: unknown,
371
+ }
372
+ rules?: Linter.RulesRecord,
357
373
  },
358
- settings?: {
359
- [name: string]: unknown,
360
- }
361
- rules?: Linter.RulesRecord,
362
- },
363
374
 
364
- configs?: {
365
- oxlint?: false | string,
366
- base?: {
367
- maxDepth?: number,
368
- maxNestedCallbacks?: number,
369
- preferNamedExports?: boolean,
370
- functionStyle?: 'declaration' | 'expression',
371
- overrides?: {},
372
- },
373
- stylistic?: boolean | {
374
- semi?: 'always' | 'never',
375
- trailingComma?: 'always' | 'never' | 'always-multiline' | 'only-multiline',
376
- memberDelimiterStyle?: 'semi' | 'comma',
377
- quotes?: 'single' | 'double' | 'backtick',
378
- jsxQuotes?: 'prefer-single' | 'prefer-double',
379
- arrowParens?: 'always' | 'as-needed',
380
- useTabs?: boolean,
381
- indent?: number,
382
- maxConsecutiveEmptyLines?: number,
383
- maxLineLength?: number,
384
- maxAttributesPerLine?: number,
385
- selfCloseVoidHTMLElements?: 'never' | 'always',
386
- overrides?: {},
387
- },
388
- html?: boolean | {
389
- useBaseline?: number | false | 'widely' | 'newly',
390
- idNamingConvention?: 'camelCase' | 'snake_case' | 'PascalCase' | 'kebab-case',
391
- overrides?: {},
392
- },
393
- css?: boolean | {
394
- useBaseline?: number | false | 'widely' | 'newly',
395
- allowedRelativeFontUnits?: ('%' | 'cap' | 'ch' | 'em' | 'ex' | 'ic' | 'lh' | 'rcap' | 'rch' | 'rem' | 'rex' | 'ric' | 'rlh')[],
396
- overrides?: {},
397
- },
398
- tailwind?: false | {
399
- config: string,
400
- entryPoint?: string,
401
- multilineSort?: boolean,
402
- ignoredUnregisteredClasses?: string[],
403
- overrides?: {},
404
- } | {
405
- config?: string,
406
- entryPoint: string,
407
- multilineSort?: boolean,
408
- ignoredUnregisteredClasses?: string[],
409
- overrides?: {},
410
- },
411
- typescript?: boolean | {
412
- allowedDefaultProjects?: string[],
413
- methodSignatureStyle?: 'property' | 'method',
414
- typeDefinitionStyle?: 'interface' | 'type',
415
- overrides?: {},
416
- },
417
- importX?: boolean | {
418
- removeUnusedImports?: boolean,
419
- overrides?: {},
420
- },
421
- perfectionist?: boolean | {
422
- sortType?: 'custom' | 'natural' | 'alphabetical' | 'line-length' | 'unsorted',
423
- overrides?: {},
424
- },
425
- vue?: boolean | {
426
- accessibility?: boolean | {
427
- anchorComponents?: string[],
428
- imageComponents?: string[],
429
- accessibleChildComponents?: string[],
375
+ configs?: {
376
+ oxlint?: false | string,
377
+ base?: {
378
+ maxDepth?: number,
379
+ maxNestedCallbacks?: number,
380
+ preferNamedExports?: boolean,
381
+ functionStyle?: 'declaration' | 'expression',
382
+ overrides?: {},
430
383
  },
431
- blockOrder?: (
432
- | 'docs'
433
- | 'template'
434
- | 'script[setup]'
435
- | 'style[scoped]'
436
- | 'i18n[locale=en]'
437
- | 'script:not([setup])'
438
- | 'style:not([scoped])'
439
- | 'i18n:not([locale=en])'
440
- )[],
441
- macrosOrder?: (
442
- | 'definePage'
443
- | 'defineModel'
444
- | 'defineProps'
445
- | 'defineEmits'
446
- | 'defineSlots'
447
- | 'defineCustom'
448
- | 'defineExpose'
449
- | 'defineOptions'
450
- )[],
451
- attributesOrder?: RuleOptions<'vue/attributes-order'>['order'],
452
- attributeHyphenation?: 'never' | 'always',
453
- preferVBindSameNameShorthand?: 'never' | 'always',
454
- preferVBindTrueShorthand?: 'never' | 'always',
455
- allowedStyleAttributes?: ['module' | 'plain' | 'scoped', 'module' | 'plain' | 'scoped'],
456
- blockLang?: {
457
- style?: 'css' | 'implicit' | 'scss' | 'postcss',
458
- script?: 'js' | 'ts' | 'jsx' | 'tsx' | 'implicit',
384
+ stylistic?: boolean | {
385
+ semi?: 'always' | 'never',
386
+ trailingComma?: 'always' | 'never' | 'always-multiline' | 'only-multiline',
387
+ memberDelimiterStyle?: 'semi' | 'comma',
388
+ quotes?: 'single' | 'double' | 'backtick',
389
+ jsxQuotes?: 'prefer-single' | 'prefer-double',
390
+ arrowParens?: 'always' | 'as-needed',
391
+ indent?: number,
392
+ maxConsecutiveEmptyLines?: number,
393
+ maxLineLength?: number,
394
+ maxAttributesPerLine?: number,
395
+ selfCloseVoidHTMLElements?: 'never' | 'always',
396
+ overrides?: {},
459
397
  },
460
- destructureProps?: 'never' | 'always',
461
- componentNameCaseInTemplate?: 'PascalCase' | 'kebab-case',
462
- vForDelimiterStyle?: 'in' | 'of',
463
- vOnHandlerStyle?: 'inline' | 'inline-function' | ['method', 'inline' | 'inline-function'],
464
- restrictedElements?: (string | {
465
- element: string | string[],
466
- message: string,
467
- })[],
468
- restrictedStaticAttributes?: (string | {
469
- key: string,
470
- value?: string | true,
471
- element: string,
472
- message: string,
473
- })[],
474
- ignoredUndefinedComponents?: string[],
475
- overrides?: {},
476
- },
477
- nuxt?: boolean | {
478
- image?: boolean,
479
- icon?: boolean | {
480
- component?: string,
481
- }
482
- ui?: boolean | {
483
- prefix?: string,
484
- }
485
- },
486
- test?: {
487
- storybook?: boolean | {
398
+ html?: boolean | {
399
+ useBaseline?: number | false | 'widely' | 'newly',
400
+ idNamingConvention?: 'camelCase' | 'snake_case' | 'PascalCase' | 'kebab-case',
488
401
  overrides?: {},
489
402
  },
490
- vitest?: boolean | {
403
+ css?: boolean | {
404
+ useBaseline?: number | false | 'widely' | 'newly',
405
+ allowedRelativeFontUnits?: ('%' | 'cap' | 'ch' | 'em' | 'ex' | 'ic' | 'lh' | 'rcap' | 'rch' | 'rem' | 'rex' | 'ric' | 'rlh')[],
406
+ overrides?: {},
407
+ },
408
+ tailwind?: false | {
409
+ config: string,
410
+ entryPoint?: string,
411
+ multilineSort?: boolean,
412
+ ignoredUnregisteredClasses?: string[],
413
+ overrides?: {},
414
+ } | {
415
+ config?: string,
416
+ entryPoint: string,
417
+ multilineSort?: boolean,
418
+ ignoredUnregisteredClasses?: string[],
491
419
  overrides?: {},
492
420
  },
493
- playwright?: boolean | {
421
+ typescript?: boolean | {
422
+ allowedDefaultProjects?: string[],
423
+ methodSignatureStyle?: 'property' | 'method',
424
+ typeDefinitionStyle?: 'interface' | 'type',
494
425
  overrides?: {},
495
426
  },
496
- cypress?: boolean | {
427
+ importX?: boolean | {
428
+ removeUnusedImports?: boolean,
429
+ overrides?: {},
430
+ },
431
+ perfectionist?: boolean | {
432
+ sortType?: 'custom' | 'natural' | 'alphabetical' | 'line-length' | 'unsorted',
433
+ overrides?: {},
434
+ },
435
+ vue?: boolean | {
436
+ accessibility?: boolean | {
437
+ anchorComponents?: string[],
438
+ imageComponents?: string[],
439
+ accessibleChildComponents?: string[],
440
+ },
441
+ blockOrder?: (
442
+ | 'docs'
443
+ | 'template'
444
+ | 'script[setup]'
445
+ | 'style[scoped]'
446
+ | 'i18n[locale=en]'
447
+ | 'script:not([setup])'
448
+ | 'style:not([scoped])'
449
+ | 'i18n:not([locale=en])'
450
+ )[],
451
+ macrosOrder?: (
452
+ | 'definePage'
453
+ | 'defineModel'
454
+ | 'defineProps'
455
+ | 'defineEmits'
456
+ | 'defineSlots'
457
+ | 'defineCustom'
458
+ | 'defineExpose'
459
+ | 'defineOptions'
460
+ )[],
461
+ attributesOrder?: RuleOptions<'vue/attributes-order'>['order'],
462
+ attributeHyphenation?: 'never' | 'always',
463
+ preferVBindSameNameShorthand?: 'never' | 'always',
464
+ preferVBindTrueShorthand?: 'never' | 'always',
465
+ allowedStyleAttributes?: ['module' | 'plain' | 'scoped', 'module' | 'plain' | 'scoped'],
466
+ blockLang?: {
467
+ style?: 'css' | 'implicit' | 'scss' | 'postcss',
468
+ script?: 'js' | 'ts' | 'jsx' | 'tsx' | 'implicit',
469
+ },
470
+ destructureProps?: 'never' | 'always',
471
+ componentNameCaseInTemplate?: 'PascalCase' | 'kebab-case',
472
+ vForDelimiterStyle?: 'in' | 'of',
473
+ vOnHandlerStyle?: 'inline' | 'inline-function' | ['method', 'inline' | 'inline-function'],
474
+ restrictedElements?: (string | {
475
+ element: string | string[],
476
+ message: string,
477
+ })[],
478
+ restrictedStaticAttributes?: (string | {
479
+ key: string,
480
+ value?: string | true,
481
+ element: string,
482
+ message: string,
483
+ })[],
484
+ ignoredUndefinedComponents?: string[],
497
485
  overrides?: {},
498
486
  },
499
- testFunction?: 'test' | 'it',
500
- maxNestedDescribe?: number,
487
+ nuxt?: boolean | {
488
+ image?: boolean,
489
+ icon?: boolean | {
490
+ component?: string,
491
+ }
492
+ ui?: boolean | {
493
+ prefix?: string,
494
+ }
495
+ },
496
+ test?: {
497
+ storybook?: boolean | {
498
+ overrides?: {},
499
+ },
500
+ vitest?: boolean | {
501
+ overrides?: {},
502
+ },
503
+ playwright?: boolean | {
504
+ overrides?: {},
505
+ },
506
+ cypress?: boolean | {
507
+ overrides?: {},
508
+ },
509
+ testFunction?: 'test' | 'it',
510
+ maxNestedDescribe?: number,
511
+ },
501
512
  },
502
- },
503
- }
504
- ```
513
+ }
514
+ ```
505
515
  </details>
506
516
 
507
517
  ## Versioning Policy
@@ -515,16 +525,15 @@ Under this policy, minor updates may introduce new linting errors, which could b
515
525
  You can find a list of all available versions and their changelogs on the [releases page](https://github.com/ShayanTheNerd/eslint-config/releases).
516
526
 
517
527
  ## Roadmap to v1.0.0
518
- - [ ] 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), and [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc).
519
- - [ ] Add support for other frameworks and file types, including Astro, React, Next.js, MDX, Markdown, and JSON.
520
- - [ ] Reduce bundle size by dynamically (programmatically) installing dependencies as needed.
528
+ - [ ] 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.
529
+ - [ ] Add support for other frameworks and file types, including Astro, React, Next.js, MDX, Markdown, JSON, etc.
521
530
  - [ ] Develop a starter wizard to automate the setup of OXLint, ESLint, Prettier, and other configurations.
522
531
 
523
532
  ## Contribution Guide
524
- Any form of contribution is always appreciated! Please refer to the [CONTRIBUTING.md](CONTRIBUTING.md) file.
533
+ Any form of contribution is always appreciated! Please chekc out the [CONTRIBUTING.md](CONTRIBUTING.md) file.
525
534
 
526
535
  ## 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.
536
+ 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
537
 
529
538
  ## License
530
539
  [MIT](LICENSE) License © 2025-PRESENT — [Shayan Zamani](https://github.com/ShayanTheNerd)
@@ -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,7 +7,7 @@ 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, base: { overrides } }, global: { globals: { bun, node, deno, vitest, worker, browser, commonjs, nodeBuiltin, audioWorklet, webextension, sharedWorker, serviceworker, vue: vueGlobals, custom: userGlobals } } } = options;
11
11
  return mergeConfigs({
12
12
  name: "shayanthenerd/base",
13
13
  files: isEnabled(vue) ? [globs.src, globs.vue] : [globs.src],
@@ -23,15 +23,19 @@ function getBaseConfig(options) {
23
23
  globals: {
24
24
  ...globals.builtin,
25
25
  ...globals.es2026,
26
+ ...worker && globals.worker,
26
27
  ...commonjs && globals.commonjs,
28
+ ...bun && env === "bun" && globals.bunBuiltin,
29
+ ...deno && env === "deno" && globals.denoBuiltin,
27
30
  ...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,
31
+ ...nodeBuiltin && env === "node" && globals.nodeBuiltin,
32
+ ...browser && env === "browser" && globals.browser,
33
+ ...sharedWorker && env === "browser" && globals.sharedWorker,
34
+ ...serviceworker && env === "browser" && globals.serviceworker,
35
+ ...webextension && env === "browser" && globals.webextensions,
36
+ ...audioWorklet && env === "browser" && globals.audioWorklet,
37
+ ...vitest && globals.vitest,
38
+ ...vueGlobals && isEnabled(vue) && globals.vue,
35
39
  ...userGlobals
36
40
  }
37
41
  },
@@ -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";
@@ -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 { getImportXRules } from "../rules/importX.mjs";
5
5
  import { mergeConfigs } from "eslint-flat-config-utils";
6
6
  import eslintPluginImportX from "eslint-plugin-import-x";
@@ -1,21 +1,26 @@
1
- import { globs } from "../utils/globs.mjs";
1
+ import { globs } from "../helpers/globs.mjs";
2
2
  import { isEnabled } from "../utils/isEnabled.mjs";
3
- import { getJavaScriptRules } from "../rules/javascript.mjs";
4
- import { getVitestRules } from "../rules/vitest.mjs";
5
- import { getPlaywrightRules } from "../rules/playwright.mjs";
6
- import { getTypeScriptRules } from "../rules/typescript.mjs";
3
+ import { getVueConfig } from "./vue.mjs";
4
+ import { getBaseConfig } from "./base.mjs";
5
+ import { getVitestConfig } from "./vitest.mjs";
6
+ import { getPlaywrightConfig } from "./playwright.mjs";
7
+ import { getTypeScriptConfig } from "./typescript.mjs";
7
8
  import typescriptESLint from "typescript-eslint";
8
9
  import eslintPluginVitest from "@vitest/eslint-plugin";
9
10
  import eslintPluginImportX from "eslint-plugin-import-x";
10
11
  import eslintPluginPlaywright from "eslint-plugin-playwright";
11
12
 
12
13
  //#region src/configs/oxlintOverrides.ts
14
+ /**
15
+ * Prevent OXLint from overriding rules that are customizable via the configuration options.
16
+ */
13
17
  function getOXLintOverridesConfig(options) {
14
18
  const { vue, importX, typescript, test: { vitest, playwright } } = options.configs;
15
- const vitestRules = getVitestRules(options);
16
- const javascriptRules = getJavaScriptRules(options);
17
- const typescriptRules = getTypeScriptRules(options);
18
- const playwrightRules = getPlaywrightRules(options);
19
+ const vueRules = getVueConfig(options).rules;
20
+ const vitestRules = getVitestConfig(options).rules;
21
+ const javascriptRules = getBaseConfig(options).rules;
22
+ const typescriptRules = getTypeScriptConfig(options).rules;
23
+ const playwrightRules = getPlaywrightConfig(options).rules;
19
24
  return {
20
25
  name: "shayanthenerd/oxlint/overrides",
21
26
  files: [
@@ -33,11 +38,11 @@ function getOXLintOverridesConfig(options) {
33
38
  "max-depth": javascriptRules["max-depth"],
34
39
  "func-style": javascriptRules["func-style"],
35
40
  "max-nested-callbacks": javascriptRules["max-nested-callbacks"],
36
- "@typescript-eslint/explicit-module-boundary-types": typescriptRules["@typescript-eslint/explicit-module-boundary-types"],
37
41
  "@typescript-eslint/consistent-type-definitions": isEnabled(typescript) ? typescriptRules["@typescript-eslint/consistent-type-definitions"] : "off",
38
42
  "playwright/max-nested-describe": isEnabled(playwright) ? playwrightRules["playwright/max-nested-describe"] : "off",
39
43
  "vitest/consistent-test-it": isEnabled(vitest) ? vitestRules["vitest/consistent-test-it"] : "off",
40
- "vitest/max-nested-describe": isEnabled(vitest) ? vitestRules["vitest/max-nested-describe"] : "off"
44
+ "vitest/max-nested-describe": isEnabled(vitest) ? vitestRules["vitest/max-nested-describe"] : "off",
45
+ "vue/define-props-destructuring": isEnabled(vue) ? vueRules["vue/define-props-destructuring"] : "off"
41
46
  }
42
47
  };
43
48
  }
@@ -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 { getPerfectionistRules } from "../rules/perfectionist.mjs";
5
5
  import { mergeConfigs } from "eslint-flat-config-utils";
6
6
  import eslintPluginPerfectionist from "eslint-plugin-perfectionist";
@@ -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 { getPlaywrightRules } from "../rules/playwright.mjs";
5
5
  import { mergeConfigs } from "eslint-flat-config-utils";
6
6
  import eslintPluginPlaywright from "eslint-plugin-playwright";
@@ -1,4 +1,4 @@
1
- import { globs } from "../utils/globs.mjs";
1
+ import { globs } from "../helpers/globs.mjs";
2
2
 
3
3
  //#region src/configs/restrictedExports.ts
4
4
  function getRestrictedExports() {
@@ -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 { getStorybookRules } from "../rules/storybook.mjs";
5
5
  import { mergeConfigs } from "eslint-flat-config-utils";
6
6
  import eslintPluginStorybook from "eslint-plugin-storybook";