@shayanthenerd/eslint-config 0.32.0 → 0.33.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.
package/README.md CHANGED
@@ -25,40 +25,40 @@ ESLint configuration for enforcing best practices and maintaining a consistent c
25
25
  ## Plugin Support
26
26
  Legend:
27
27
  - ✅ — **Enabled** by default
28
+ - 🔍 — [**Automatically detected**](#automatic-dependency-detection)
28
29
  - ⚙️ — **Opt-in** (requires manual configuration)
29
- - 🔍 — [**Automatically detected**](#automatic-dependency-detection) (based on project dependencies)
30
-
31
- | Category | Activation |
32
- | :---------------------------------------------------------------------------------------------------- | :--------: |
33
- | **Languages** | |
34
- | [JavaScript][eslint] | ✅  |
35
- | [TypeScript][plugin-ts] | 🔍  |
36
- | [Markdown][plugin-md] | ✅  |
37
- | [HTML][plugin-html] | ⚙️  |
38
- | [CSS][plugin-css] | ⚙️  |
39
- | **Formatting** | |
40
- | [Stylistic][plugin-stylistic] | ✅  |
41
- | [Perfectionist][plugin-perfectionist] | ✅  |
42
- | **Frameworks & Libraries** | |
43
- | [Astro][plugin-astro] ([jsx-accessibility][plugin-jsx-a11y]) | 🔍  |
44
- | [React][plugin-react] ([jsx-accessibility][plugin-jsx-a11y], [@html-eslint/react][plugin-html-react]) | 🔍  |
45
- | [Next][plugin-next] | 🔍  |
46
- | [TanStack Start][plugin-tanstack-start], [TanStack Query][plugin-tanstack-query], [TanStack Router][plugin-tanstack-router] | 🔍  |
47
- | [Vue & Nuxt][plugin-vue] ([vue-accessibility][plugin-vue-a11y]) | 🔍  |
48
- | [Tailwind][plugin-tailwind] | ⚙️  |
49
- | [Zod & Zod Mini][plugin-zod] | 🔍  |
50
- | **Testing Tools** | |
51
- | [Storybook][plugin-storybook] | 🔍  |
52
- | [Vitest][plugin-vitest] | 🔍  |
53
- | [Cypress][plugin-cypress] | 🔍  |
54
- | [Playwright][plugin-playwright] | 🔍  |
55
- | **Miscellaneous** | |
56
- | [_package.json_][plugin-package-json] | ✅  |
57
- | [Node][plugin-n] | ✅  |
58
- | [Promises][plugin-promise] | ✅  |
59
- | [Imports][plugin-import-x] | ✅  |
60
- | [Unicorn][plugin-unicorn] | ✅  |
61
- | [Baseline][plugin-baseline] ([css/use-baseline], [@html-eslint/use-baseline], [@html-eslint/react/use-baseline]) | 🔍  |
30
+
31
+ | Category | Activation |
32
+ | :------------------------------------------------------------------------------------------------------ | :--------: |
33
+ | **Languages** | |
34
+ | [JavaScript][eslint] | ✅  |
35
+ | [TypeScript][plugin-ts] | 🔍  |
36
+ | [Markdown][plugin-md] | ✅  |
37
+ | [HTML][plugin-html] | ⚙️  |
38
+ | [CSS][plugin-css] | ⚙️  |
39
+ | **Formatting** | |
40
+ | [Stylistic][plugin-stylistic] | ✅  |
41
+ | [Perfectionist][plugin-perfectionist] | ✅  |
42
+ | **Frameworks & Libraries** | |
43
+ | [Astro][plugin-astro] ([jsx-accessibility][plugin-jsx-a11y-x]) | 🔍  |
44
+ | [React][plugin-react] ([jsx-accessibility][plugin-jsx-a11y-x], [@html-eslint/react][plugin-html-react]) | 🔍  |
45
+ | [Next][plugin-next] | 🔍  |
46
+ | [TanStack Start][plugin-tanstack-start], [TanStack Query][plugin-tanstack-query], [TanStack Router][plugin-tanstack-router] | 🔍  |
47
+ | [Vue & Nuxt][plugin-vue] ([vue-accessibility][plugin-vue-a11y]) | 🔍  |
48
+ | [Tailwind][plugin-tailwind] | ⚙️  |
49
+ | [Zod & Zod Mini][plugin-zod] | 🔍  |
50
+ | **Testing Tools** | |
51
+ | [Storybook][plugin-storybook] | 🔍  |
52
+ | [Vitest][plugin-vitest] | 🔍  |
53
+ | [Cypress][plugin-cypress] | 🔍  |
54
+ | [Playwright][plugin-playwright] | 🔍  |
55
+ | **Miscellaneous** | |
56
+ | [_package.json_][plugin-package-json] | ✅  |
57
+ | [Node][plugin-n] | ✅  |
58
+ | [Promises][plugin-promise] | ✅  |
59
+ | [Imports][plugin-import-x] | ✅  |
60
+ | [Unicorn][plugin-unicorn] | ✅  |
61
+ | [Baseline][plugin-baseline] ([css/use-baseline], [@html-eslint/use-baseline], [@html-eslint/react/use-baseline]) | 🔍  |
62
62
 
63
63
  ## Installation and Configuration
64
64
  1. Install the package and ESLint as dev dependencies:
@@ -81,7 +81,7 @@ Legend:
81
81
  "scripts": {
82
82
  "lint": "eslint --max-warnings=0 --cache --cache-location='node_modules/.cache/.eslintcache'",
83
83
  "lint:fix": "eslint --fix --max-warnings=0 --cache --cache-location='node_modules/.cache/.eslintcache'",
84
- "lint:inspect": "npx @eslint/config-inspector"
84
+ "lint:inspect": "pnpx @eslint/config-inspector"
85
85
  }
86
86
  }
87
87
  ```
@@ -214,8 +214,27 @@ For editor integration, to reduce noise and avoid inconsistent diagnostics from
214
214
  }
215
215
  ```
216
216
 
217
+ ### Astro
218
+ The accessibility rules in [eslint-plugin-astro][plugin-astro] require [eslint-plugin-jsx-a11y-x][plugin-jsx-a11y-x] as a peer dependency. Install it with:
219
+ ```shell
220
+ pnpm add -D eslint-plugin-jsx-a11y-x
221
+ ```
222
+ When both `astro` and `eslint-plugin-jsx-a11y-x` are detected as dependencies, `configs.astro.accessibility` is set to `true` automatically. To disable the accessibility rules, set `configs.astro.accessibility` to `false`.
223
+
224
+ ### Vue
225
+ [ESLint Stylistic][plugin-stylistic] and [eslint-plugin-vue][plugin-vue] don't format `<style>` blocks inside Vue SFCs. On the other hand, [Prettier][prettier] cannot be limited to just `<style>` blocks, and formats the whole file, including `<script>` and `<template>` blocks, which could conflict with ESLint. To work around this, you may use Tailwind, format styles manually, keep styles in separate `.css` files, or use Prettier and resolve any resulting conflicts.
226
+
227
+ Read more about the formatting options and Prettier integration in the [Formatting](#formatting) section.
228
+
217
229
  ### Nuxt
218
- The required Nuxt configurations and rules are already included, so there's no need to install or configure the [@nuxt/eslint][eslint-nuxt] module.
230
+ The required Nuxt configurations and rules are already included, so there's no need to use the [@nuxt/eslint][eslint-nuxt] module.
231
+
232
+ ### React/Next
233
+ The required Next configurations and rules, including for core web vitals, are already provided, so there's no need to use [eslint-config-next][eslint-next]. Similarly, the React integration also provides React-specific configurations and rules for accessibility and React Hooks.
234
+
235
+ ### TanStack Start
236
+ > [!NOTE]
237
+ > The rules in [@tanstack/eslint-plugin-start][plugin-tanstack-start] require type information, and will be disabled automatically if the TypeScript integration is not enabled.
219
238
 
220
239
  ### Markdown
221
240
  Markdown linting is powered by [@eslint/markdown][plugin-md].
@@ -344,7 +363,7 @@ For file types that ESLint Stylistic does not handle—such as CSS, JSON, YAML,
344
363
  ```json title="package.json"
345
364
  {
346
365
  "scripts": {
347
- "format": "prettier --write . '!**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,html,vue,astro}' --cache"
366
+ "format": "prettier --write . '!pnpm-lock.yaml' '!**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx,html,vue,astro}' --cache"
348
367
  }
349
368
  }
350
369
  ```
@@ -427,7 +446,7 @@ For file types that ESLint Stylistic does not handle—such as CSS, JSON, YAML,
427
446
  ```json title="package.json"
428
447
  {
429
448
  "scripts": {
430
- "format": "prettier --write . --cache",
449
+ "format": "prettier --write . '!pnpm-lock.yaml' --cache",
431
450
  }
432
451
  }
433
452
  ```
@@ -517,6 +536,7 @@ For file types that ESLint Stylistic does not handle—such as CSS, JSON, YAML,
517
536
 
518
537
  configs?: {
519
538
  astro?: boolean | {
539
+ accessibility?: boolean,
520
540
  overrides?: Overrides,
521
541
  },
522
542
  baseline?: boolean | {
@@ -537,6 +557,7 @@ For file types that ESLint Stylistic does not handle—such as CSS, JSON, YAML,
537
557
  overrides?: Overrides,
538
558
  },
539
559
  css?: boolean | {
560
+ allowedUnknownPseudoSelectors?: string[],
540
561
  overrides?: Overrides,
541
562
  },
542
563
  html?: boolean | {
@@ -574,6 +595,8 @@ For file types that ESLint Stylistic does not handle—such as CSS, JSON, YAML,
574
595
  overrides?: Overrides,
575
596
  },
576
597
  packageJson?: boolean | {
598
+ allowedDistTags?: string[],
599
+ allowedDistTagsFor?: ('dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies')[],
577
600
  overrides?: Overrides,
578
601
  },
579
602
  perfectionist?: boolean | {
@@ -763,7 +786,7 @@ This project was inspired by the work of [Anthony Fu][antfu], whose generous con
763
786
  [plugin-html]: https://html-eslint.org
764
787
  [plugin-html-react]: https://html-eslint.org/docs/react/getting-started
765
788
  [plugin-import-x]: https://github.com/un-ts/eslint-plugin-import-x
766
- [plugin-jsx-a11y]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y
789
+ [plugin-jsx-a11y-x]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y-x
767
790
  [plugin-md]: https://github.com/eslint/markdown
768
791
  [plugin-n]: https://github.com/eslint-community/eslint-plugin-n
769
792
  [plugin-next]: https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next
@@ -796,6 +819,7 @@ This project was inspired by the work of [Anthony Fu][antfu], whose generous con
796
819
  [eslint]: https://eslint.org
797
820
  [online-preview]: https://eslintconfig.netlify.app
798
821
  [eslint-config-ts-setup]: https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files
822
+ [eslint-next]: https://nextjs.org/docs/app/api-reference/config/eslint
799
823
  [eslint-nuxt]: https://eslint.nuxt.com
800
824
  [local-pkg]: https://github.com/antfu-collective/local-pkg
801
825
  [prettier]: https://prettier.io
@@ -6,9 +6,10 @@ import * as eslintParserAstro from "astro-eslint-parser";
6
6
  import { mergeConfigs } from "eslint-flat-config-utils";
7
7
  import eslintPluginAstro from "eslint-plugin-astro";
8
8
  import { parser } from "typescript-eslint";
9
+ import path from "node:path";
9
10
  //#region src/configs/astro.ts
10
11
  function getAstroConfig(options) {
11
- const { astro } = options.configs;
12
+ const { tsConfig, configs: { astro } } = options;
12
13
  const { overrides } = isEnabled(astro) ? astro : defaultOptions.configs.astro;
13
14
  const astroConfig = {
14
15
  name: "shayanthenerd/astro",
@@ -22,6 +23,9 @@ function getAstroConfig(options) {
22
23
  parser: eslintParserAstro,
23
24
  parserOptions: {
24
25
  parser,
26
+ projectService: false,
27
+ project: tsConfig ? path.resolve(tsConfig.rootDir, tsConfig.filename) : void 0,
28
+ tsconfigRootDir: tsConfig ? path.resolve(tsConfig.rootDir) : void 0,
25
29
  extraFileExtensions: [".astro"]
26
30
  }
27
31
  },
@@ -13,7 +13,7 @@ function getPackageJsonConfig(options) {
13
13
  files: [globs.packageJson],
14
14
  plugins: { "package-json": eslintPluginPackageJson },
15
15
  languageOptions: { parser: eslintPluginPackageJson.configs.recommended.languageOptions.parser },
16
- rules: getPackageJsonRules()
16
+ rules: getPackageJsonRules(options)
17
17
  };
18
18
  return mergeConfigs(packageJsonConfig, overrides);
19
19
  }
@@ -4,7 +4,7 @@ import { isEnabled } from "../utils/isEnabled.mjs";
4
4
  import { getReactRules } from "../rules/react.mjs";
5
5
  import { mergeConfigs } from "eslint-flat-config-utils";
6
6
  import eslintPluginUnicorn from "eslint-plugin-unicorn";
7
- import eslintPluginJsxA11y from "eslint-plugin-jsx-a11y";
7
+ import eslintPluginJsxA11yX from "eslint-plugin-jsx-a11y-x";
8
8
  import eslintPluginReact from "@eslint-react/eslint-plugin";
9
9
  import eslintPluginHtmlReact from "@html-eslint/eslint-plugin-react";
10
10
  //#region src/configs/react.ts
@@ -18,7 +18,7 @@ function getReactConfig(options) {
18
18
  "@eslint-react": eslintPluginReact,
19
19
  "@html-eslint/react": eslintPluginHtmlReact,
20
20
  ...isEnabled(unicorn) && { unicorn: eslintPluginUnicorn },
21
- ...isEnabled(accessibility) && { "jsx-a11y": eslintPluginJsxA11y }
21
+ ...isEnabled(accessibility) && { "jsx-a11y-x": eslintPluginJsxA11yX }
22
22
  },
23
23
  rules: getReactRules(options)
24
24
  };
@@ -14,6 +14,11 @@ const astroAttributes = {
14
14
  name: "^class:list$",
15
15
  match: [{ type: MatcherType.String }, { type: MatcherType.ObjectKey }]
16
16
  };
17
+ const reactAttributes = {
18
+ kind: SelectorKind.Attribute,
19
+ name: "^(?:className|.*Class)$",
20
+ match: [{ type: MatcherType.String }, { type: MatcherType.ObjectKey }]
21
+ };
17
22
  const vueAttributes = {
18
23
  kind: SelectorKind.Attribute,
19
24
  name: "^(?:v-bind:)?(exactActiveClass|activeClass|inactiveClass|active-class|inactive-class)$",
@@ -43,13 +48,14 @@ const nuxtUiAppConfigUiFields = {
43
48
  }]
44
49
  };
45
50
  function getTailwindConfig(options) {
46
- const { tsConfig, configs: { vue, nuxt, html, astro, tailwind } } = options;
51
+ const { tsConfig, configs: { vue, nuxt, html, astro, react, tailwind } } = options;
47
52
  const { cwd, config, overrides, entryPoint } = isEnabled(tailwind) ? tailwind : defaultOptions.configs.tailwind;
48
53
  const tsconfigPath = tsConfig ? path.resolve(tsConfig.rootDir, tsConfig.filename) : void 0;
49
54
  const isNuxtUiEnabled = isEnabled(nuxt) && isEnabled(nuxt.ui);
50
55
  const selectors = [
51
56
  ...getDefaultSelectors(),
52
57
  isEnabled(astro) ? astroAttributes : void 0,
58
+ isEnabled(react) ? reactAttributes : void 0,
53
59
  isEnabled(vue) ? vueAttributes : void 0,
54
60
  isNuxtUiEnabled ? nuxtUiAttributes : void 0,
55
61
  isNuxtUiEnabled ? nuxtUiAppConfigUiFields : void 0
@@ -8,26 +8,24 @@ import { parser, plugin } from "typescript-eslint";
8
8
  import path from "node:path";
9
9
  //#region src/configs/typescript.ts
10
10
  function getTypescriptConfig(options) {
11
- const { tsConfig, configs: { vue, astro, typescript } } = options;
12
- const { allowedDefaultProjects } = isEnabled(typescript) ? typescript : defaultOptions.configs.typescript;
11
+ const { tsConfig, configs: { vue, typescript } } = options;
12
+ const { allowedDefaultProjects: userAllowedDefaultProjects } = isEnabled(typescript) ? typescript : defaultOptions.configs.typescript;
13
13
  const { overrides } = isEnabled(typescript) ? typescript : defaultOptions.configs.typescript;
14
14
  const typescriptConfig = {
15
15
  name: "shayanthenerd/typescript",
16
16
  files: [
17
17
  globs.src,
18
18
  globs.jsxTsx,
19
- isEnabled(vue) ? globs.vue : "",
20
- isEnabled(astro) ? globs.astro : ""
19
+ isEnabled(vue) ? globs.vue : ""
21
20
  ].filter(isTruthy),
22
21
  plugins: { "@typescript-eslint": plugin },
23
22
  languageOptions: {
24
23
  parser,
25
24
  parserOptions: {
26
- warnOnUnsupportedTypeScriptVersion: false,
27
25
  tsconfigRootDir: tsConfig ? path.resolve(tsConfig.rootDir) : void 0,
28
26
  projectService: {
29
27
  defaultProject: tsConfig ? tsConfig.filename : void 0,
30
- allowDefaultProject: ["{prettier,eslint}.config.?([mc])ts", ...allowedDefaultProjects]
28
+ allowDefaultProject: userAllowedDefaultProjects
31
29
  }
32
30
  }
33
31
  },
@@ -1,9 +1,7 @@
1
1
  //#region src/helpers/ignores/defaultIgnorePatterns.ts
2
2
  const defaultIgnorePatterns = [
3
- "**/*.min.*",
4
3
  "**/jspm_packages",
5
4
  "**/pnpm-lock.yaml",
6
- "**/bower_components",
7
5
  "**/package-lock.json",
8
6
  "**/typegen.d.ts",
9
7
  "**/next-env.d.ts",
@@ -18,6 +16,7 @@ const defaultIgnorePatterns = [
18
16
  "**/public",
19
17
  "**/output",
20
18
  "**/.output",
19
+ "**/*.min.*",
21
20
  "**/.serverless",
22
21
  "**/.eslint-config-inspector",
23
22
  "**/tmp",
@@ -29,22 +28,18 @@ const defaultIgnorePatterns = [
29
28
  "**/.cache",
30
29
  "**/deno_dir",
31
30
  "**/.parcel-cache",
32
- "**/*.lerna_backup",
33
31
  "**/.postcss-cache",
34
32
  "**/.vitepress/cache",
35
33
  "**/vite.config.*.timestamp-*",
36
34
  "**/.nx",
37
35
  "**/.vite",
38
- "**/.yarn",
39
36
  "**/.nuxt",
40
37
  "**/.next",
41
38
  "**/.astro",
42
39
  "**/.vitest",
43
40
  "**/.vercel",
44
- "**/.svelte-kit",
45
41
  "**/.vite-inspect",
46
42
  "**/coverage",
47
- "**/_fixtures",
48
43
  "**/.nyc_output",
49
44
  "**/__snapshots__",
50
45
  "**/.idea",
@@ -34,7 +34,10 @@ const defaultOptions = {
34
34
  settings: {}
35
35
  },
36
36
  configs: {
37
- astro: { overrides: {} },
37
+ astro: {
38
+ accessibility: false,
39
+ overrides: {}
40
+ },
38
41
  baseline: {
39
42
  baseline: "widely",
40
43
  css: {
@@ -52,7 +55,10 @@ const defaultOptions = {
52
55
  },
53
56
  overrides: {}
54
57
  },
55
- css: { overrides: {} },
58
+ css: {
59
+ allowedUnknownPseudoSelectors: [],
60
+ overrides: {}
61
+ },
56
62
  html: {
57
63
  idNamingConvention: "snake_case",
58
64
  overrides: {}
@@ -77,7 +83,11 @@ const defaultOptions = {
77
83
  ui: { prefix: "U" },
78
84
  overrides: {}
79
85
  },
80
- packageJson: { overrides: {} },
86
+ packageJson: {
87
+ allowedDistTags: [],
88
+ allowedDistTagsFor: [],
89
+ overrides: {}
90
+ },
81
91
  perfectionist: {
82
92
  sortType: "line-length",
83
93
  overrides: {}
@@ -7,8 +7,12 @@ function enableDetectedConfigs(options) {
7
7
  "typescript": options.configs?.typescript === false,
8
8
  "zod": options.configs?.zod === false,
9
9
  "astro": options.configs?.astro === false,
10
+ "eslint-plugin-jsx-a11y-x": isEnabled(options.configs?.astro) && options.configs?.astro?.accessibility === false,
10
11
  "react": options.configs?.react === false,
11
12
  "next": options.configs?.next === false,
13
+ "@tanstack/react-router": isEnabled(options.configs?.tanstack) && options.configs?.tanstack?.router === false,
14
+ "@tanstack/react-start": isEnabled(options.configs?.tanstack) && options.configs?.tanstack?.start === false,
15
+ "@tanstack/react-query": isEnabled(options.configs?.tanstack) && options.configs?.tanstack?.query === false,
12
16
  "vue": options.configs?.vue === false,
13
17
  "nuxt": options.configs?.nuxt === false,
14
18
  "@nuxt/ui": isEnabled(options.configs?.nuxt) && options.configs?.nuxt?.ui === false,
@@ -23,6 +27,7 @@ function enableDetectedConfigs(options) {
23
27
  typescript: isPackageDetected("typescript", options),
24
28
  zod: isPackageDetected("zod", options),
25
29
  astro: isPackageDetected("astro", options),
30
+ eslintPluginJsxA11yX: isPackageDetected("eslint-plugin-jsx-a11y-x", options),
26
31
  react: isPackageDetected("react", options),
27
32
  next: isPackageDetected("next", options),
28
33
  tanstackStart: isPackageDetected("@tanstack/react-start", options),
@@ -38,6 +43,8 @@ function enableDetectedConfigs(options) {
38
43
  storybook: isPackageDetected("storybook", options),
39
44
  playwright: isPackageDetected("@playwright/test", options)
40
45
  };
46
+ options.autoDetectDeps ??= defaultOptions.autoDetectDeps;
47
+ options.env ??= defaultOptions.env;
41
48
  options.configs ??= {};
42
49
  options.configs.test ??= {};
43
50
  options.configs.node ??= true;
@@ -50,7 +57,7 @@ function enableDetectedConfigs(options) {
50
57
  options.configs.importX ??= true;
51
58
  options.configs.stylistic ??= true;
52
59
  options.configs.perfectionist ??= true;
53
- options.configs.baseline ??= options.env === "browser";
60
+ options.configs.baseline ??= options.autoDetectDeps && options.env === "browser";
54
61
  options.configs.typescript ??= autoDetectedPackages.typescript;
55
62
  options.configs.zod ??= autoDetectedPackages.zod;
56
63
  options.configs.astro ??= autoDetectedPackages.astro;
@@ -80,18 +87,22 @@ function enableDetectedConfigs(options) {
80
87
  options.configs.vue = options.configs.vue === true ? {} : options.configs.vue;
81
88
  options.configs.vue.blockLang = { script: "ts" };
82
89
  }
83
- if (options.configs.tanstack) {
84
- if (options.configs.tanstack === true) options.configs.tanstack = {};
85
- options.configs.tanstack.start ??= autoDetectedPackages.tanstackStart;
86
- options.configs.tanstack.query ??= autoDetectedPackages.tanstackQuery;
87
- options.configs.tanstack.router ??= autoDetectedPackages.tanstackRouter;
88
- }
89
90
  if (options.configs.nuxt) {
90
91
  if (options.configs.nuxt === true) options.configs.nuxt = {};
91
92
  options.configs.nuxt.ui ??= autoDetectedPackages.nuxtUI;
92
93
  options.configs.nuxt.icon ??= autoDetectedPackages.nuxtIcon;
93
94
  options.configs.nuxt.image ??= autoDetectedPackages.nuxtImage;
94
95
  }
96
+ if (options.configs.astro) {
97
+ options.configs.astro = options.configs.astro === true ? {} : options.configs.astro;
98
+ options.configs.astro.accessibility ??= autoDetectedPackages.eslintPluginJsxA11yX;
99
+ }
100
+ if (options.configs.tanstack) {
101
+ if (options.configs.tanstack === true) options.configs.tanstack = {};
102
+ options.configs.tanstack.start ??= autoDetectedPackages.tanstackStart;
103
+ options.configs.tanstack.query ??= autoDetectedPackages.tanstackQuery;
104
+ options.configs.tanstack.router ??= autoDetectedPackages.tanstackRouter;
105
+ }
95
106
  if (options.autoDetectDeps === "verbose") logDetectedPackages(explicitlyDisabledConfigs);
96
107
  return options;
97
108
  }
package/dist/index.d.mts CHANGED
@@ -35,6 +35,7 @@ import { Linter } from "eslint";
35
35
  * ],
36
36
  * );
37
37
  */
38
+ declare function defineConfig(): Linter.Config[];
38
39
  declare function defineConfig(options: Options): Linter.Config[];
39
40
  declare function defineConfig(configs: Linter.Config[]): Linter.Config[];
40
41
  declare function defineConfig(options: Options, configs: Linter.Config[]): Linter.Config[];
@@ -1,60 +1,67 @@
1
+ import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
1
2
  import { isEnabled } from "../utils/isEnabled.mjs";
2
3
  //#region src/rules/astro.ts
3
- const astroRules = {
4
- "astro/missing-client-only-directive-value": "error",
5
- "astro/no-conflict-set-directives": "error",
6
- "astro/no-deprecated-astro-canonicalurl": "error",
7
- "astro/no-deprecated-astro-fetchcontent": "error",
8
- "astro/no-deprecated-astro-resolve": "error",
9
- "astro/no-deprecated-getentrybyslug": "error",
10
- "astro/no-exports-from-components": "error",
11
- "astro/no-prerender-export-outside-pages": "error",
12
- "astro/no-unused-define-vars-in-style": "warn",
13
- "astro/no-set-html-directive": "warn",
14
- "astro/no-unsafe-inline-scripts": "warn",
15
- "astro/no-set-text-directive": "warn",
16
- "astro/no-unused-css-selector": "warn",
17
- "astro/prefer-class-list-directive": "warn",
18
- "astro/prefer-split-class-list": "warn",
19
- "astro/jsx-a11y/alt-text": "error",
20
- "astro/jsx-a11y/anchor-ambiguous-text": "warn",
21
- "astro/jsx-a11y/anchor-has-content": "warn",
22
- "astro/jsx-a11y/anchor-is-valid": "error",
23
- "astro/jsx-a11y/aria-activedescendant-has-tabindex": "warn",
24
- "astro/jsx-a11y/aria-props": "error",
25
- "astro/jsx-a11y/aria-proptypes": "error",
26
- "astro/jsx-a11y/aria-role": "warn",
27
- "astro/jsx-a11y/aria-unsupported-elements": "error",
28
- "astro/jsx-a11y/autocomplete-valid": "error",
29
- "astro/jsx-a11y/click-events-have-key-events": "warn",
30
- "astro/jsx-a11y/control-has-associated-label": "warn",
31
- "astro/jsx-a11y/heading-has-content": "warn",
32
- "astro/jsx-a11y/html-has-lang": "error",
33
- "astro/jsx-a11y/iframe-has-title": "warn",
34
- "astro/jsx-a11y/img-redundant-alt": "warn",
35
- "astro/jsx-a11y/interactive-supports-focus": "warn",
36
- "astro/jsx-a11y/label-has-associated-control": "warn",
37
- "astro/jsx-a11y/lang": "error",
38
- "astro/jsx-a11y/media-has-caption": "warn",
39
- "astro/jsx-a11y/mouse-events-have-key-events": "warn",
40
- "astro/jsx-a11y/no-access-key": "warn",
41
- "astro/jsx-a11y/no-aria-hidden-on-focusable": "error",
42
- "astro/jsx-a11y/no-autofocus": "warn",
43
- "astro/jsx-a11y/no-distracting-elements": "warn",
44
- "astro/jsx-a11y/no-interactive-element-to-noninteractive-role": "warn",
45
- "astro/jsx-a11y/no-noninteractive-element-interactions": "warn",
46
- "astro/jsx-a11y/no-noninteractive-element-to-interactive-role": "warn",
47
- "astro/jsx-a11y/no-noninteractive-tabindex": "warn",
48
- "astro/jsx-a11y/no-redundant-roles": "warn",
49
- "astro/jsx-a11y/no-static-element-interactions": "warn",
50
- "astro/jsx-a11y/prefer-tag-over-role": "warn",
51
- "astro/jsx-a11y/role-has-required-aria-props": "warn",
52
- "astro/jsx-a11y/role-supports-aria-props": "warn",
53
- "astro/jsx-a11y/scope": "error",
54
- "astro/jsx-a11y/tabindex-no-positive": "warn"
55
- };
56
4
  function getAstroRules(options) {
57
- const { importX, stylistic } = options.configs;
5
+ const { astro, importX, stylistic } = options.configs;
6
+ const { semi } = isEnabled(stylistic) ? stylistic : defaultOptions.configs.stylistic;
7
+ const { accessibility } = isEnabled(astro) ? astro : defaultOptions.configs.astro;
8
+ const astroRules = {
9
+ "astro/missing-client-only-directive-value": "error",
10
+ "astro/no-conflict-set-directives": "error",
11
+ "astro/no-deprecated-astro-canonicalurl": "error",
12
+ "astro/no-deprecated-astro-fetchcontent": "error",
13
+ "astro/no-deprecated-astro-resolve": "error",
14
+ "astro/no-deprecated-getentrybyslug": "error",
15
+ "astro/no-exports-from-components": "error",
16
+ "astro/no-prerender-export-outside-pages": "error",
17
+ "astro/no-unused-define-vars-in-style": "warn",
18
+ "astro/no-set-html-directive": "warn",
19
+ "astro/no-unsafe-inline-scripts": "warn",
20
+ "astro/no-set-text-directive": "warn",
21
+ "astro/no-unused-css-selector": "warn",
22
+ "astro/prefer-class-list-directive": "warn",
23
+ "astro/prefer-split-class-list": "warn",
24
+ "astro/semi": ["warn", semi]
25
+ };
26
+ const astroJsxA11yRules = {
27
+ "astro/jsx-a11y/alt-text": "error",
28
+ "astro/jsx-a11y/anchor-ambiguous-text": "warn",
29
+ "astro/jsx-a11y/anchor-has-content": "warn",
30
+ "astro/jsx-a11y/anchor-is-valid": "error",
31
+ "astro/jsx-a11y/aria-activedescendant-has-tabindex": "warn",
32
+ "astro/jsx-a11y/aria-props": "error",
33
+ "astro/jsx-a11y/aria-proptypes": "error",
34
+ "astro/jsx-a11y/aria-role": "warn",
35
+ "astro/jsx-a11y/aria-unsupported-elements": "error",
36
+ "astro/jsx-a11y/autocomplete-valid": "error",
37
+ "astro/jsx-a11y/click-events-have-key-events": "warn",
38
+ "astro/jsx-a11y/control-has-associated-label": "warn",
39
+ "astro/jsx-a11y/heading-has-content": "warn",
40
+ "astro/jsx-a11y/html-has-lang": "error",
41
+ "astro/jsx-a11y/iframe-has-title": "warn",
42
+ "astro/jsx-a11y/img-redundant-alt": "warn",
43
+ "astro/jsx-a11y/interactive-supports-focus": "warn",
44
+ "astro/jsx-a11y/label-has-associated-control": "warn",
45
+ "astro/jsx-a11y/lang": "error",
46
+ "astro/jsx-a11y/media-has-caption": "warn",
47
+ "astro/jsx-a11y/mouse-events-have-key-events": "warn",
48
+ "astro/jsx-a11y/no-access-key": "warn",
49
+ "astro/jsx-a11y/no-aria-hidden-on-focusable": "error",
50
+ "astro/jsx-a11y/no-autofocus": "warn",
51
+ "astro/jsx-a11y/no-distracting-elements": "warn",
52
+ "astro/jsx-a11y/no-interactive-element-to-noninteractive-role": "warn",
53
+ "astro/jsx-a11y/no-noninteractive-element-interactions": "warn",
54
+ "astro/jsx-a11y/no-noninteractive-element-to-interactive-role": "warn",
55
+ "astro/jsx-a11y/no-noninteractive-tabindex": "warn",
56
+ "astro/jsx-a11y/no-redundant-roles": "warn",
57
+ "astro/jsx-a11y/no-static-element-interactions": "warn",
58
+ "astro/jsx-a11y/prefer-tag-over-role": "warn",
59
+ "astro/jsx-a11y/role-has-required-aria-props": "warn",
60
+ "astro/jsx-a11y/role-supports-aria-props": "warn",
61
+ "astro/jsx-a11y/scope": "error",
62
+ "astro/jsx-a11y/tabindex-no-positive": "warn"
63
+ };
64
+ if (isEnabled(accessibility)) Object.assign(astroRules, astroJsxA11yRules);
58
65
  if (isEnabled(importX)) astroRules["import-x/exports-last"] = "off";
59
66
  if (isEnabled(stylistic)) astroRules["@stylistic/jsx-one-expression-per-line"] = "off";
60
67
  return astroRules;
@@ -14,7 +14,7 @@ function getBaselineRules(options) {
14
14
  baseline,
15
15
  includeWebApis: { preset: "auto" },
16
16
  includeJsBuiltins: { preset: "auto" },
17
- ignoreFeatures: userIgnoredFeatures,
17
+ ignoreFeatures: ["async-clipboard", ...userIgnoredFeatures],
18
18
  ignoreNodeTypes: userIgnoredNodeTypes
19
19
  }]
20
20
  };
@@ -1,5 +1,6 @@
1
1
  import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
2
2
  import { isEnabled } from "../utils/isEnabled.mjs";
3
+ import { isTruthy } from "../utils/isTruthy.mjs";
3
4
  //#region src/rules/css.ts
4
5
  const allowedPhysicalUnits = [
5
6
  "cqh",
@@ -46,7 +47,8 @@ const allowedPhysicalProperties = [
46
47
  "contain-intrinsic-height"
47
48
  ];
48
49
  function getCssRules(options) {
49
- const { unicorn, tailwind, baseline } = options.configs;
50
+ const { css, vue, unicorn, tailwind, baseline } = options.configs;
51
+ const { allowedUnknownPseudoSelectors: userAllowedUnknownPseudoSelectors } = isEnabled(css) ? css : defaultOptions.configs.css;
50
52
  const { allowedAtRules: userAllowedAtRules, allowedFunctions: userAllowedFunctions, allowedMediaConditions: userAllowedMediaConditions, allowedProperties: userAllowedProperties, allowedPropertyValues: userAllowedPropertyValues, allowedSelectors: userAllowedSelectors, allowedUnits: userAllowedUnits } = isEnabled(baseline) ? baseline.css : defaultOptions.configs.baseline.css;
51
53
  const cssRules = {
52
54
  "css/font-family-fallbacks": "warn",
@@ -82,15 +84,41 @@ function getCssRules(options) {
82
84
  allowFunctions: userAllowedFunctions,
83
85
  allowMediaConditions: userAllowedMediaConditions,
84
86
  allowProperties: userAllowedProperties,
85
- allowPropertyValues: userAllowedPropertyValues,
86
- allowSelectors: userAllowedSelectors,
87
+ allowPropertyValues: {
88
+ "background-clip": ["text"],
89
+ ...userAllowedPropertyValues
90
+ },
91
+ allowSelectors: ["selection", ...userAllowedSelectors],
87
92
  allowUnits: userAllowedUnits
88
93
  }] : "off"
89
94
  };
90
- if (isEnabled(unicorn)) {
91
- cssRules["unicorn/no-shorthand-property-overrides"] = "warn";
92
- cssRules["unicorn/prefer-explicit-viewport-units"] = "warn";
93
- }
95
+ const unicornRules = {
96
+ "unicorn/no-deprecated-css-features": "error",
97
+ "unicorn/no-duplicate-css-selectors": "warn",
98
+ "unicorn/no-duplicate-font-family-names": "error",
99
+ "unicorn/no-invalid-media-features": "error",
100
+ "unicorn/no-nesting-with-mixed-specificity": "warn",
101
+ "unicorn/no-redundant-nested-style-rules": "warn",
102
+ "unicorn/no-shorthand-property-overrides": "warn",
103
+ "unicorn/no-unknown-css-annotations": "error",
104
+ "unicorn/no-unknown-pseudo-selectors": ["error", { allow: [
105
+ "::-ms-reveal",
106
+ ":-webkit-autofill",
107
+ "::-webkit-inner-spin-button",
108
+ "::-webkit-search-cancel-button",
109
+ "::-webkit-search-results-button",
110
+ ...isEnabled(vue) ? [
111
+ ":deep",
112
+ ":global",
113
+ ":slotted"
114
+ ] : [],
115
+ ...userAllowedUnknownPseudoSelectors
116
+ ].filter(isTruthy) }],
117
+ "unicorn/no-unscoped-css-nesting-selector": isEnabled(tailwind) ? ["error", { scopingRootAtRules: ["utility", "custom-variant"] }] : "error",
118
+ "unicorn/prefer-explicit-viewport-units": "warn",
119
+ "unicorn/prefer-media-feature-range-syntax": "warn"
120
+ };
121
+ if (isEnabled(unicorn)) Object.assign(cssRules, unicornRules);
94
122
  return cssRules;
95
123
  }
96
124
  //#endregion