@shayanthenerd/eslint-config 0.26.1 → 0.26.3

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
@@ -6,7 +6,7 @@ ESLint configuration for enforcing best practices and maintaining a consistent c
6
6
  - **Smart**: Context-aware linting with [automatic dependency detection](#automatic-dependency-detection) and _.gitignore_ recognition.
7
7
  - **Comprehensive**: [Supports useful plugins](#plugin-support) for TypeScript, React & Next, Vue & Nuxt, Astro, Tailwind, and more.
8
8
  - **Type-safe**: [Fully-typed and well-documented API](#api-reference) with `overrides` support for built-in configuration objects.
9
- - **Modern**: Requires ESLint ^10.4.0 and Node.js ^20.19.0 (ESM-only)
9
+ - **Modern**: Requires ESLint ^10.6.0 and Node.js ^20.19.0 (ESM-only)
10
10
 
11
11
  ## Table of Contents
12
12
  - [Plugin Support](#plugin-support)
@@ -25,40 +25,40 @@ ESLint configuration for enforcing best practices and maintaining a consistent c
25
25
 
26
26
  ## Plugin Support
27
27
  Legend:
28
- - ✅ Enabled by default
29
- - Disabled by default
30
- - 🔎 [Automatically detected](#automatic-dependency-detection)
28
+ - ✅ — **Enabled** by default
29
+ - ⚙️ **Opt-in** (requires manual configuration)
30
+ - 🔍 [**Automatically detected**](#automatic-dependency-detection) (based on project dependencies)
31
31
 
32
32
  | Category | Activation |
33
33
  | :---------------------------------------------------------------------------------------------------- | :--------: |
34
34
  | **Languages** | |
35
35
  | [JavaScript][eslint] | ✅  |
36
- | [TypeScript][plugin-ts] | 🔎  |
36
+ | [TypeScript][plugin-ts] | 🔍  |
37
37
  | [Markdown][plugin-md] | ✅  |
38
- | [HTML][plugin-html] |   |
39
- | [CSS][plugin-css] |   |
38
+ | [HTML][plugin-html] | ⚙️  |
39
+ | [CSS][plugin-css] | ⚙️  |
40
40
  | **Formatting** | |
41
41
  | [Stylistic][plugin-stylistic] | ✅  |
42
42
  | [Perfectionist][plugin-perfectionist] | ✅  |
43
43
  | **Frameworks & Libraries** | |
44
- | [Astro][plugin-astro] ([jsx-accessibility][plugin-jsx-a11y]) | 🔎  |
45
- | [React][plugin-react] ([jsx-accessibility][plugin-jsx-a11y], [@html-eslint/react][plugin-html-react]) | 🔎  |
46
- | [Next][plugin-next] | 🔎  |
47
- | [Vue & Nuxt][plugin-vue] ([vue-accessibility][plugin-vue-a11y]) | 🔎  |
48
- | [Tailwind][plugin-tailwind] |   |
49
- | [Zod & Zod Mini][plugin-zod] | 🔎  |
44
+ | [Astro][plugin-astro] ([jsx-accessibility][plugin-jsx-a11y]) | 🔍  |
45
+ | [React][plugin-react] ([jsx-accessibility][plugin-jsx-a11y], [@html-eslint/react][plugin-html-react]) | 🔍  |
46
+ | [Next][plugin-next] | 🔍  |
47
+ | [Vue & Nuxt][plugin-vue] ([vue-accessibility][plugin-vue-a11y]) | 🔍  |
48
+ | [Tailwind][plugin-tailwind] | ⚙️  |
49
+ | [Zod & Zod Mini][plugin-zod] | 🔍  |
50
50
  | **Testing Tools** | |
51
- | [Storybook][plugin-storybook] | 🔎  |
52
- | [Vitest][plugin-vitest] | 🔎  |
53
- | [Cypress][plugin-cypress] | 🔎  |
54
- | [Playwright][plugin-playwright] | 🔎  |
51
+ | [Storybook][plugin-storybook] | 🔍  |
52
+ | [Vitest][plugin-vitest] | 🔍  |
53
+ | [Cypress][plugin-cypress] | 🔍  |
54
+ | [Playwright][plugin-playwright] | 🔍  |
55
55
  | **Miscellaneous** | |
56
56
  | [_package.json_][plugin-package-json] | ✅  |
57
57
  | [Node][plugin-n] | ✅  |
58
58
  | [Promises][plugin-promise] | ✅  |
59
59
  | [Imports][plugin-import-x] | ✅  |
60
60
  | [Unicorn][plugin-unicorn] | ✅  |
61
- | [Baseline][plugin-baseline] | 🔎  |
61
+ | [Baseline][plugin-baseline] | 🔍  |
62
62
 
63
63
  ## Installation and Configuration
64
64
  1. Install the package and ESLint as dev dependencies:
@@ -230,7 +230,15 @@ By default, the plugin uses GitHub Flavored Markdown (GFM). You can [switch to C
230
230
  Some rules depend on the specified Node.js version. Visit the documentation for [version-resolution options and project-specific configurations](https://github.com/eslint-community/eslint-plugin-n#configured-nodejs-version-range).
231
231
 
232
232
  ## IDE Support
233
- Install the VS Code extensions for [ESLint][extension-eslint] and [Prettier][extension-prettier]. Then add the following in _.vscode/settings.json_:
233
+ Install the VS Code extensions for [ESLint][extension-eslint] and [Prettier][extension-prettier].
234
+ > [!TIP]
235
+ > In case you're using PNPM without `shamefullyHoist: true`, add the following to your _pnpm-workspace.yaml_ and run `pnpm install --yes` so ESLint's VS Code extension works as expected:
236
+ > ```yaml title="pnpm-workspace.yaml"
237
+ > publicHoistPattern:
238
+ > - '*eslint*'
239
+ > ```
240
+
241
+ You can also add the following to your _.vscode/settings.json_:
234
242
  ```jsonc title=".vscode/settings.json"
235
243
  {
236
244
  /* Enforce Unix-like line endings (LF). */
@@ -286,9 +294,6 @@ Install the VS Code extensions for [ESLint][extension-eslint] and [Prettier][ext
286
294
  }
287
295
  ```
288
296
 
289
- > [!TIP]
290
- > These settings match the default behavior of this configuration. If you've customized any formatting or stylistic rules, update the corresponding editor settings to keep them consistent.
291
-
292
297
  ## Formatting
293
298
  This configuration uses [ESLint Stylistic][plugin-stylistic] to format:
294
299
  - JavaScript and TypeScript (_js_, _cjs_, _mjs_, _jsx_, _ts_, _cts_, _mts_, _tsx_),
@@ -16,11 +16,9 @@ function getReactConfig(options) {
16
16
  files: [globs.src],
17
17
  plugins: {
18
18
  "@eslint-react": eslintPluginReact,
19
+ "@html-eslint/react": eslintPluginHtmlReact,
19
20
  ...isEnabled(unicorn) && { unicorn: eslintPluginUnicorn },
20
- ...isEnabled(accessibility) && {
21
- "jsx-a11y": eslintPluginJsxA11y,
22
- "@html-eslint/react": eslintPluginHtmlReact
23
- }
21
+ ...isEnabled(accessibility) && { "jsx-a11y": eslintPluginJsxA11y }
24
22
  },
25
23
  rules: getReactRules(options)
26
24
  }, overrides);
@@ -2,7 +2,6 @@ import { globs } from "../helpers/globs.mjs";
2
2
  import { isEnabled } from "../utils/isEnabled.mjs";
3
3
  import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
4
4
  import { getVueRules } from "../rules/vue.mjs";
5
- import { getVueAccessibilityRules } from "../rules/vueAccessibility.mjs";
6
5
  import { mergeConfigs } from "eslint-flat-config-utils";
7
6
  import eslintPluginVue from "eslint-plugin-vue";
8
7
  import { parser } from "typescript-eslint";
@@ -30,10 +29,7 @@ function getVueConfig(options) {
30
29
  vueFeatures: { filter: false }
31
30
  }
32
31
  },
33
- rules: {
34
- ...getVueRules(options),
35
- ...isVueAccessibilityEnabled && getVueAccessibilityRules(options)
36
- }
32
+ rules: getVueRules(options)
37
33
  }, overrides);
38
34
  }
39
35
  //#endregion
@@ -4,10 +4,11 @@ import { styleText } from "node:util";
4
4
  import { isPackageExists } from "local-pkg";
5
5
  //#region src/helpers/isPackageDetected.ts
6
6
  const detectedPackages = [];
7
- function logDetectedPackages() {
8
- if (detectedPackages.length > 0) {
9
- detectedPackages.sort();
10
- console.info(`${styleText("green", "✔")} ESLint integrations enabled via dependency detection:`, detectedPackages.map((packageName) => styleText("blue", packageName)).join(", "));
7
+ function logDetectedPackages(disabledConfigs) {
8
+ const nonDisabledDetectedPackages = detectedPackages.filter((packageName) => !disabledConfigs[packageName]);
9
+ if (nonDisabledDetectedPackages.length > 0) {
10
+ nonDisabledDetectedPackages.sort();
11
+ console.info(`${styleText("green", "✔")} ESLint integrations enabled via dependency detection:`, nonDisabledDetectedPackages.map((packageName) => styleText("blue", packageName)).join(", "));
11
12
  }
12
13
  }
13
14
  function isPackageDetected(packageName, options) {
@@ -1,7 +1,24 @@
1
+ import { isEnabled } from "../../utils/isEnabled.mjs";
1
2
  import { isPackageDetected, logDetectedPackages } from "../isPackageDetected.mjs";
2
3
  //#region src/helpers/options/enableDetectedConfigs.ts
3
4
  function enableDetectedConfigs(options) {
4
- const autoDetectedDeps = {
5
+ const explicitlyDisabledConfigs = {
6
+ "typescript": options.configs?.typescript === false,
7
+ "zod": options.configs?.zod === false,
8
+ "astro": options.configs?.astro === false,
9
+ "react": options.configs?.react === false,
10
+ "next": options.configs?.next === false,
11
+ "vue": options.configs?.vue === false,
12
+ "nuxt": options.configs?.nuxt === false,
13
+ "@nuxt/ui": isEnabled(options.configs?.nuxt) && options.configs?.nuxt?.ui === false,
14
+ "@nuxt/icon": isEnabled(options.configs?.nuxt) && options.configs?.nuxt?.icon === false,
15
+ "@nuxt/image": isEnabled(options.configs?.nuxt) && options.configs?.nuxt?.image === false,
16
+ "vitest": options.configs?.test?.vitest === false,
17
+ "cypress": options.configs?.test?.cypress === false,
18
+ "storybook": options.configs?.test?.storybook === false,
19
+ "@playwright/test": options.configs?.test?.playwright === false
20
+ };
21
+ const autoDetectedPackages = {
5
22
  typescript: isPackageDetected("typescript", options),
6
23
  zod: isPackageDetected("zod", options),
7
24
  astro: isPackageDetected("astro", options),
@@ -30,17 +47,17 @@ function enableDetectedConfigs(options) {
30
47
  options.configs.stylistic ??= true;
31
48
  options.configs.perfectionist ??= true;
32
49
  options.configs.useBaseline ??= options.env === "browser";
33
- options.configs.typescript ??= autoDetectedDeps.typescript;
34
- options.configs.zod ??= autoDetectedDeps.zod;
35
- options.configs.astro ??= autoDetectedDeps.astro;
36
- options.configs.vue ??= autoDetectedDeps.vue;
37
- options.configs.nuxt ??= autoDetectedDeps.nuxt;
38
- options.configs.react ??= autoDetectedDeps.react;
39
- options.configs.next ??= autoDetectedDeps.next;
40
- options.configs.test.vitest ??= autoDetectedDeps.vitest;
41
- options.configs.test.cypress ??= autoDetectedDeps.cypress;
42
- options.configs.test.storybook ??= autoDetectedDeps.storybook;
43
- options.configs.test.playwright ??= autoDetectedDeps.playwright;
50
+ options.configs.typescript ??= autoDetectedPackages.typescript;
51
+ options.configs.zod ??= autoDetectedPackages.zod;
52
+ options.configs.astro ??= autoDetectedPackages.astro;
53
+ options.configs.vue ??= autoDetectedPackages.vue;
54
+ options.configs.nuxt ??= autoDetectedPackages.nuxt;
55
+ options.configs.react ??= autoDetectedPackages.react;
56
+ options.configs.next ??= autoDetectedPackages.next;
57
+ options.configs.test.vitest ??= autoDetectedPackages.vitest;
58
+ options.configs.test.cypress ??= autoDetectedPackages.cypress;
59
+ options.configs.test.storybook ??= autoDetectedPackages.storybook;
60
+ options.configs.test.playwright ??= autoDetectedPackages.playwright;
44
61
  options.tsConfig ??= options.configs.typescript ? {
45
62
  rootDir: ".",
46
63
  filename: "tsconfig.json"
@@ -51,11 +68,11 @@ function enableDetectedConfigs(options) {
51
68
  }
52
69
  if (options.configs.nuxt) {
53
70
  if (options.configs.nuxt === true) options.configs.nuxt = {};
54
- options.configs.nuxt.ui ??= autoDetectedDeps.nuxtUI;
55
- options.configs.nuxt.icon ??= autoDetectedDeps.nuxtIcon;
56
- options.configs.nuxt.image ??= autoDetectedDeps.nuxtImage;
71
+ options.configs.nuxt.ui ??= autoDetectedPackages.nuxtUI;
72
+ options.configs.nuxt.icon ??= autoDetectedPackages.nuxtIcon;
73
+ options.configs.nuxt.image ??= autoDetectedPackages.nuxtImage;
57
74
  }
58
- if (options.autoDetectDeps === "verbose") logDetectedPackages();
75
+ if (options.autoDetectDeps === "verbose") logDetectedPackages(explicitlyDisabledConfigs);
59
76
  return options;
60
77
  }
61
78
  //#endregion
@@ -12,6 +12,7 @@ function getHtmlRules(options) {
12
12
  "@html-eslint/no-duplicate-id": "error",
13
13
  "@html-eslint/no-duplicate-in-head": "error",
14
14
  "@html-eslint/no-ineffective-attrs": "warn",
15
+ "@html-eslint/no-inline-styles": ["warn", { allowExpressions: true }],
15
16
  "@html-eslint/no-invalid-attr-value": "error",
16
17
  "@html-eslint/no-invalid-entity": "error",
17
18
  "@html-eslint/no-nested-interactive": "error",
@@ -16,7 +16,7 @@ function getJavaScriptRules(options) {
16
16
  "no-compare-neg-zero": "error",
17
17
  "no-cond-assign": "error",
18
18
  "no-const-assign": isTypeScriptEnabled ? "off" : "error",
19
- "no-constant-binary-expression": "error",
19
+ "no-constant-binary-expression": ["error", { checkRelationalComparisons: true }],
20
20
  "no-constant-condition": "error",
21
21
  "no-constructor-return": "error",
22
22
  "no-control-regex": "error",
@@ -15,7 +15,7 @@ function getNodeRules(options) {
15
15
  "n/no-unpublished-import": "error",
16
16
  "n/no-unsupported-features/es-builtins": "error",
17
17
  "n/no-unsupported-features/es-syntax": "error",
18
- "n/no-unsupported-features/node-builtins": "error",
18
+ "n/no-unsupported-features/node-builtins": ["error", { allowExperimental: true }],
19
19
  "n/prefer-global/buffer": "warn",
20
20
  "n/prefer-global/console": "warn",
21
21
  "n/prefer-global/crypto": "warn",
@@ -64,9 +64,28 @@ const packageJsonRules = {
64
64
  ] }],
65
65
  "package-json/scripts-name-casing": "warn",
66
66
  "package-json/sort-collections": ["warn", [
67
+ {
68
+ key: "author",
69
+ order: [
70
+ "name",
71
+ "email",
72
+ "url"
73
+ ]
74
+ },
75
+ {
76
+ key: "bugs",
77
+ order: ["email", "url"]
78
+ },
67
79
  "config",
68
80
  "dependencies",
81
+ "devEngines",
69
82
  "devDependencies",
83
+ "directories",
84
+ {
85
+ key: "dist",
86
+ order: ["shasum", "tarball"]
87
+ },
88
+ "engines",
70
89
  "exports",
71
90
  "husky",
72
91
  "husky.hooks",
@@ -76,6 +95,15 @@ const packageJsonRules = {
76
95
  "overrides",
77
96
  "peerDependencies",
78
97
  "peerDependenciesMeta",
98
+ {
99
+ key: "repository",
100
+ order: [
101
+ "type",
102
+ "url",
103
+ "directory"
104
+ ]
105
+ },
106
+ "release",
79
107
  "simple-git-hooks"
80
108
  ]],
81
109
  "package-json/specify-peers-locally": "warn",
@@ -16,7 +16,48 @@ const commonCallees = [
16
16
  function getReactRules(options) {
17
17
  const { react, unicorn, tailwind, useBaseline } = options.configs;
18
18
  const { imageComponents: userImageComponents, anchorComponents: userAnchorComponents, headingComponents: userHeadingComponents } = isEnabled(react) && isEnabled(react.accessibility) ? react.accessibility : defaultOptions.configs.react.accessibility;
19
- const reactRules = {
19
+ const jsxA11yRules = {
20
+ "jsx-a11y/alt-text": ["error", { img: userImageComponents }],
21
+ "jsx-a11y/anchor-ambiguous-text": "warn",
22
+ "jsx-a11y/anchor-has-content": ["error", { components: userAnchorComponents }],
23
+ "jsx-a11y/anchor-is-valid": ["error", {
24
+ specialLink: ["to"],
25
+ components: userAnchorComponents
26
+ }],
27
+ "jsx-a11y/aria-activedescendant-has-tabindex": "error",
28
+ "jsx-a11y/aria-props": "error",
29
+ "jsx-a11y/aria-proptypes": "error",
30
+ "jsx-a11y/aria-role": "error",
31
+ "jsx-a11y/aria-unsupported-elements": "error",
32
+ "jsx-a11y/autocomplete-valid": "error",
33
+ "jsx-a11y/click-events-have-key-events": "error",
34
+ "jsx-a11y/control-has-associated-label": "error",
35
+ "jsx-a11y/heading-has-content": ["error", { components: userHeadingComponents }],
36
+ "jsx-a11y/html-has-lang": "error",
37
+ "jsx-a11y/iframe-has-title": "error",
38
+ "jsx-a11y/img-redundant-alt": ["error", { components: userImageComponents }],
39
+ "jsx-a11y/interactive-supports-focus": "error",
40
+ "jsx-a11y/label-has-associated-control": "error",
41
+ "jsx-a11y/lang": "error",
42
+ "jsx-a11y/media-has-caption": "error",
43
+ "jsx-a11y/mouse-events-have-key-events": "error",
44
+ "jsx-a11y/no-access-key": "warn",
45
+ "jsx-a11y/no-aria-hidden-on-focusable": "error",
46
+ "jsx-a11y/no-autofocus": "warn",
47
+ "jsx-a11y/no-distracting-elements": "warn",
48
+ "jsx-a11y/no-interactive-element-to-noninteractive-role": "error",
49
+ "jsx-a11y/no-noninteractive-element-interactions": "error",
50
+ "jsx-a11y/no-noninteractive-element-to-interactive-role": "error",
51
+ "jsx-a11y/no-noninteractive-tabindex": "error",
52
+ "jsx-a11y/no-redundant-roles": "warn",
53
+ "jsx-a11y/no-static-element-interactions": "warn",
54
+ "jsx-a11y/prefer-tag-over-role": "warn",
55
+ "jsx-a11y/role-has-required-aria-props": "warn",
56
+ "jsx-a11y/role-supports-aria-props": "warn",
57
+ "jsx-a11y/scope": "error",
58
+ "jsx-a11y/tabindex-no-positive": "error"
59
+ };
60
+ const reactAndHtmlReactRules = {
20
61
  /*** @eslint/react ***/
21
62
  "@eslint-react/error-boundaries": "error",
22
63
  "@eslint-react/exhaustive-deps": "error",
@@ -103,46 +144,6 @@ function getReactRules(options) {
103
144
  "@eslint-react/naming-convention-context-name": "warn",
104
145
  "@eslint-react/naming-convention-id-name": "warn",
105
146
  "@eslint-react/naming-convention-ref-name": "warn",
106
- /*** jsx-a11y ***/
107
- "jsx-a11y/alt-text": ["error", { img: userImageComponents }],
108
- "jsx-a11y/anchor-ambiguous-text": "warn",
109
- "jsx-a11y/anchor-has-content": ["error", { components: userAnchorComponents }],
110
- "jsx-a11y/anchor-is-valid": ["error", {
111
- specialLink: ["to"],
112
- components: userAnchorComponents
113
- }],
114
- "jsx-a11y/aria-activedescendant-has-tabindex": "error",
115
- "jsx-a11y/aria-props": "error",
116
- "jsx-a11y/aria-proptypes": "error",
117
- "jsx-a11y/aria-role": "error",
118
- "jsx-a11y/aria-unsupported-elements": "error",
119
- "jsx-a11y/autocomplete-valid": "error",
120
- "jsx-a11y/click-events-have-key-events": "error",
121
- "jsx-a11y/control-has-associated-label": "error",
122
- "jsx-a11y/heading-has-content": ["error", { components: userHeadingComponents }],
123
- "jsx-a11y/html-has-lang": "error",
124
- "jsx-a11y/iframe-has-title": "error",
125
- "jsx-a11y/img-redundant-alt": ["error", { components: userImageComponents }],
126
- "jsx-a11y/interactive-supports-focus": "error",
127
- "jsx-a11y/label-has-associated-control": "error",
128
- "jsx-a11y/lang": "error",
129
- "jsx-a11y/media-has-caption": "error",
130
- "jsx-a11y/mouse-events-have-key-events": "error",
131
- "jsx-a11y/no-access-key": "warn",
132
- "jsx-a11y/no-aria-hidden-on-focusable": "error",
133
- "jsx-a11y/no-autofocus": "warn",
134
- "jsx-a11y/no-distracting-elements": "warn",
135
- "jsx-a11y/no-interactive-element-to-noninteractive-role": "error",
136
- "jsx-a11y/no-noninteractive-element-interactions": "error",
137
- "jsx-a11y/no-noninteractive-element-to-interactive-role": "error",
138
- "jsx-a11y/no-noninteractive-tabindex": "error",
139
- "jsx-a11y/no-redundant-roles": "warn",
140
- "jsx-a11y/no-static-element-interactions": "warn",
141
- "jsx-a11y/prefer-tag-over-role": "warn",
142
- "jsx-a11y/role-has-required-aria-props": "warn",
143
- "jsx-a11y/role-supports-aria-props": "warn",
144
- "jsx-a11y/scope": "error",
145
- "jsx-a11y/tabindex-no-positive": "error",
146
147
  /*** @html-eslint/react ***/
147
148
  "@html-eslint/react/no-invalid-attr-value": "error",
148
149
  "@html-eslint/react/use-baseline": isEnabled(useBaseline) ? ["warn", { available: useBaseline.baseline }] : "off",
@@ -152,9 +153,13 @@ function getReactRules(options) {
152
153
  "@html-eslint/react/classname-spacing": ["warn", { callees: commonCallees }],
153
154
  "@html-eslint/react/no-duplicate-classname": ["warn", { callees: commonCallees }]
154
155
  };
155
- if (isEnabled(tailwind)) reactRules["better-tailwindcss/no-duplicate-classes"] = "off";
156
- if (isEnabled(unicorn)) reactRules["unicorn/no-invalid-file-input-accept"] = "error";
157
- return reactRules;
156
+ if (isEnabled(tailwind)) reactAndHtmlReactRules["better-tailwindcss/no-duplicate-classes"] = "off";
157
+ if (isEnabled(unicorn)) reactAndHtmlReactRules["unicorn/no-invalid-file-input-accept"] = "error";
158
+ const isReactAccessibilityEnabled = isEnabled(react) && isEnabled(react.accessibility);
159
+ return {
160
+ ...reactAndHtmlReactRules,
161
+ ...isReactAccessibilityEnabled && jsxA11yRules
162
+ };
158
163
  }
159
164
  //#endregion
160
165
  export { getReactRules };
@@ -14,6 +14,7 @@ const unicornRules = {
14
14
  "unicorn/consistent-json-file-read": "error",
15
15
  "unicorn/consistent-optional-chaining": "warn",
16
16
  "unicorn/consistent-template-literal-escape": "warn",
17
+ "unicorn/consistent-tuple-labels": "warn",
17
18
  "unicorn/custom-error-definition": "error",
18
19
  "unicorn/dom-node-dataset": "warn",
19
20
  "unicorn/empty-brace-spaces": "warn",
@@ -32,6 +33,7 @@ const unicornRules = {
32
33
  "unicorn/no-array-from-fill": "warn",
33
34
  "unicorn/no-array-method-this-argument": "warn",
34
35
  "unicorn/no-array-sort-for-min-max": "warn",
36
+ "unicorn/no-async-promise-finally": "warn",
35
37
  "unicorn/no-await-expression-member": "warn",
36
38
  "unicorn/no-await-in-promise-methods": "error",
37
39
  "unicorn/no-blob-to-file": "warn",
@@ -59,7 +61,9 @@ const unicornRules = {
59
61
  "unicorn/no-invalid-character-comparison": "error",
60
62
  "unicorn/no-invalid-fetch-options": "error",
61
63
  "unicorn/no-invalid-remove-event-listener": "error",
64
+ "unicorn/no-invalid-well-known-symbol-methods": "error",
62
65
  "unicorn/no-late-current-target-access": "warn",
66
+ "unicorn/no-late-event-control": "error",
63
67
  "unicorn/no-lonely-if": "warn",
64
68
  "unicorn/no-loop-iterable-mutation": "warn",
65
69
  "unicorn/no-magic-array-flat-depth": "warn",
@@ -75,6 +79,7 @@ const unicornRules = {
75
79
  "unicorn/no-object-methods-with-collections": "warn",
76
80
  "unicorn/no-optional-chaining-on-undeclared-variable": "error",
77
81
  "unicorn/no-redundant-comparison": "warn",
82
+ "unicorn/no-return-array-push": "warn",
78
83
  "unicorn/no-selector-as-dom-name": "error",
79
84
  "unicorn/no-single-promise-in-promise-methods": "warn",
80
85
  "unicorn/no-static-only-class": "warn",
@@ -87,6 +92,7 @@ const unicornRules = {
87
92
  "unicorn/no-unnecessary-array-flat-depth": "warn",
88
93
  "unicorn/no-unnecessary-array-splice-count": "warn",
89
94
  "unicorn/no-unnecessary-boolean-comparison": "warn",
95
+ "unicorn/no-unnecessary-fetch-options": "warn",
90
96
  "unicorn/no-unnecessary-global-this": "warn",
91
97
  "unicorn/no-unnecessary-nested-ternary": "warn",
92
98
  "unicorn/no-unnecessary-polyfills": "warn",
@@ -97,6 +103,7 @@ const unicornRules = {
97
103
  "unicorn/no-unreadable-iife": "warn",
98
104
  "unicorn/no-unreadable-new-expression": "warn",
99
105
  "unicorn/no-unsafe-buffer-conversion": "warn",
106
+ "unicorn/no-unsafe-promise-all-settled-values": "error",
100
107
  "unicorn/no-unsafe-property-key": "error",
101
108
  "unicorn/no-unused-array-method-return": "warn",
102
109
  "unicorn/no-unused-properties": "warn",
@@ -122,8 +129,11 @@ const unicornRules = {
122
129
  "unicorn/no-zero-fractions": "warn",
123
130
  "unicorn/number-literal-case": "warn",
124
131
  "unicorn/numeric-separators-style": "warn",
132
+ "unicorn/prefer-abort-signal-any": "warn",
133
+ "unicorn/prefer-abort-signal-timeout": "warn",
125
134
  "unicorn/prefer-add-event-listener": "warn",
126
135
  "unicorn/prefer-add-event-listener-options": "warn",
136
+ "unicorn/prefer-aggregate-error": "warn",
127
137
  "unicorn/prefer-array-flat": "warn",
128
138
  "unicorn/prefer-array-flat-map": "warn",
129
139
  "unicorn/prefer-array-from-async": "warn",
@@ -136,6 +146,7 @@ const unicornRules = {
136
146
  "unicorn/prefer-at": "warn",
137
147
  "unicorn/prefer-bigint-literals": "warn",
138
148
  "unicorn/prefer-blob-reading-methods": "warn",
149
+ "unicorn/prefer-block-statement-over-iife": "warn",
139
150
  "unicorn/prefer-boolean-return": "warn",
140
151
  "unicorn/prefer-class-fields": "warn",
141
152
  "unicorn/prefer-classlist-toggle": "warn",
@@ -147,12 +158,15 @@ const unicornRules = {
147
158
  "unicorn/prefer-dom-node-append": "warn",
148
159
  "unicorn/prefer-dom-node-html-methods": "warn",
149
160
  "unicorn/prefer-dom-node-remove": "warn",
161
+ "unicorn/prefer-dom-node-replace-children": "warn",
150
162
  "unicorn/prefer-dom-node-text-content": "warn",
163
+ "unicorn/prefer-error-is-error": "error",
151
164
  "unicorn/prefer-event-target": "warn",
152
165
  "unicorn/prefer-export-from": ["warn", { checkUsedVariables: false }],
153
166
  "unicorn/prefer-flat-math-min-max": "warn",
154
167
  "unicorn/prefer-get-or-insert-computed": "warn",
155
168
  "unicorn/prefer-global-number-constants": "warn",
169
+ "unicorn/prefer-group-by": "warn",
156
170
  "unicorn/prefer-has-check": "warn",
157
171
  "unicorn/prefer-hoisting-branch-code": "warn",
158
172
  "unicorn/prefer-https": "warn",
@@ -161,6 +175,7 @@ const unicornRules = {
161
175
  "unicorn/prefer-includes": "warn",
162
176
  "unicorn/prefer-iterable-in-constructor": "warn",
163
177
  "unicorn/prefer-iterator-concat": "warn",
178
+ "unicorn/prefer-iterator-helpers": "warn",
164
179
  "unicorn/prefer-iterator-to-array": "warn",
165
180
  "unicorn/prefer-iterator-to-array-at-end": "warn",
166
181
  "unicorn/prefer-keyboard-event-key": "error",
@@ -184,9 +199,11 @@ const unicornRules = {
184
199
  "unicorn/prefer-object-destructuring-defaults": "warn",
185
200
  "unicorn/prefer-object-from-entries": "warn",
186
201
  "unicorn/prefer-object-iterable-methods": "warn",
202
+ "unicorn/prefer-observer-apis": "warn",
187
203
  "unicorn/prefer-optional-catch-binding": "warn",
188
204
  "unicorn/prefer-path2d": "warn",
189
205
  "unicorn/prefer-private-class-fields": "warn",
206
+ "unicorn/prefer-promise-try": "warn",
190
207
  "unicorn/prefer-promise-with-resolvers": "warn",
191
208
  "unicorn/prefer-queue-microtask": "warn",
192
209
  "unicorn/prefer-reflect-apply": "warn",
@@ -194,9 +211,11 @@ const unicornRules = {
194
211
  "unicorn/prefer-regexp-test": "warn",
195
212
  "unicorn/prefer-response-static-json": "warn",
196
213
  "unicorn/prefer-scoped-selector": "warn",
214
+ "unicorn/prefer-set-methods": "warn",
197
215
  "unicorn/prefer-set-size": "warn",
198
216
  "unicorn/prefer-simple-condition-first": "warn",
199
217
  "unicorn/prefer-simple-sort-comparator": "warn",
218
+ "unicorn/prefer-simplified-conditions": "warn",
200
219
  "unicorn/prefer-single-array-predicate": "warn",
201
220
  "unicorn/prefer-single-call": "warn",
202
221
  "unicorn/prefer-single-object-destructuring": "warn",
@@ -212,12 +231,14 @@ const unicornRules = {
212
231
  "unicorn/prefer-string-trim-start-end": "warn",
213
232
  "unicorn/prefer-structured-clone": "warn",
214
233
  "unicorn/prefer-temporal": "warn",
234
+ "unicorn/prefer-toggle-attribute": "warn",
215
235
  "unicorn/prefer-top-level-await": "warn",
216
236
  "unicorn/prefer-type-error": "warn",
217
237
  "unicorn/prefer-uint8array-base64": "warn",
218
238
  "unicorn/prefer-unary-minus": "warn",
219
239
  "unicorn/prefer-url-can-parse": "warn",
220
240
  "unicorn/prefer-url-href": "warn",
241
+ "unicorn/prefer-url-search-parameters": "warn",
221
242
  "unicorn/prefer-while-loop-condition": "warn",
222
243
  "unicorn/relative-url-style": "warn",
223
244
  "unicorn/require-array-join-separator": "warn",
@@ -8,6 +8,7 @@ function getVueRules(options) {
8
8
  const { typescript, stylistic, vue, nuxt } = options.configs;
9
9
  const { indent, trailingComma, maxLineLength, maxAttributesPerLine, maxConsecutiveEmptyLines, selfCloseVoidHtmlElements } = isEnabled(stylistic) ? stylistic : defaultOptions.configs.stylistic;
10
10
  const { blockLang, blocksOrder, macrosOrder, attributesOrder, destructureProps, vForDelimiterStyle, attributeHyphenation, allowedStyleAttributes, preferVBindTrueShorthand, componentNameCaseInTemplate, preferVBindSameNameShorthand, restrictedElements: userRestrictedElements, ignoredUndefinedComponents: userIgnoredUndefinedComponents, restrictedStaticAttributes: userRestrictedStaticAttributes } = isEnabled(vue) ? vue : defaultOptions.configs.vue;
11
+ const { imageComponents: userImageComponents, anchorComponents: userAnchorComponents, accessibleChildComponents: userAccessibleChildComponents } = isEnabled(vue) && isEnabled(vue.accessibility) ? vue.accessibility : defaultOptions.configs.vue.accessibility;
11
12
  const isNuxtEnabled = isEnabled(nuxt);
12
13
  const isNuxtImageEnabled = isNuxtEnabled ? nuxt.image : void 0;
13
14
  const isNuxtUIEnabled = isNuxtEnabled ? nuxt.ui : void 0;
@@ -18,8 +19,43 @@ function getVueRules(options) {
18
19
  const restrictedVueInputs = isNuxtUIEnabled ? getRestrictedVueInputs(nuxtUIPrefix) : [];
19
20
  const isScriptLangTS = blockLang.script === "ts";
20
21
  const isStyleLangImplicit = blockLang.style === "implicit";
21
- return {
22
- "@stylistic/max-len": "off",
22
+ const vueAccessibilityRules = {
23
+ "vuejs-accessibility/alt-text": ["error", { img: userImageComponents }],
24
+ "vuejs-accessibility/anchor-has-content": ["error", {
25
+ components: userAnchorComponents,
26
+ accessibleChildren: userAccessibleChildComponents
27
+ }],
28
+ "vuejs-accessibility/aria-props": "error",
29
+ "vuejs-accessibility/aria-role": "error",
30
+ "vuejs-accessibility/aria-unsupported-elements": "error",
31
+ "vuejs-accessibility/form-control-has-label": ["error", { labelComponents: isNuxtUIEnabled ? [`${nuxtUIPrefix}FormField`] : void 0 }],
32
+ "vuejs-accessibility/heading-has-content": "error",
33
+ "vuejs-accessibility/iframe-has-title": "error",
34
+ "vuejs-accessibility/interactive-supports-focus": "error",
35
+ "vuejs-accessibility/label-has-for": ["error", {
36
+ allowChildren: true,
37
+ required: { some: ["nesting", "id"] },
38
+ controlComponents: [
39
+ "input",
40
+ "output",
41
+ "meter",
42
+ "select",
43
+ "textarea",
44
+ "progress"
45
+ ]
46
+ }],
47
+ "vuejs-accessibility/media-has-caption": "error",
48
+ "vuejs-accessibility/no-access-key": "warn",
49
+ "vuejs-accessibility/no-aria-hidden-on-focusable": "error",
50
+ "vuejs-accessibility/no-autofocus": "warn",
51
+ "vuejs-accessibility/no-distracting-elements": "warn",
52
+ "vuejs-accessibility/no-redundant-roles": "warn",
53
+ "vuejs-accessibility/no-role-presentation-on-focusable": "error",
54
+ "vuejs-accessibility/no-static-element-interactions": "error",
55
+ "vuejs-accessibility/role-has-required-aria-props": "error",
56
+ "vuejs-accessibility/tabindex-no-positive": "error"
57
+ };
58
+ const vueAndNuxtRules = {
23
59
  "vue/jsx-uses-vars": "error",
24
60
  "vue/comment-directive": ["error", { reportUnusedDisableDirectives: true }],
25
61
  "vue/multi-word-component-names": "error",
@@ -330,7 +366,7 @@ function getVueRules(options) {
330
366
  isNuxtUIEnabled && `^${nuxtUIPrefix}`,
331
367
  ...userIgnoredUndefinedComponents
332
368
  ].filter(isTruthy) }],
333
- "vue/no-undef-directives": nuxt ? "off" : "error",
369
+ "vue/no-undef-directives": isNuxtEnabled ? "off" : "error",
334
370
  "vue/no-unused-emit-declarations": "error",
335
371
  "vue/no-unused-properties": ["error", {
336
372
  groups: [
@@ -367,6 +403,12 @@ function getVueRules(options) {
367
403
  "vue/slot-name-casing": "warn",
368
404
  "vue/v-for-delimiter-style": ["warn", vForDelimiterStyle]
369
405
  };
406
+ if (isEnabled(stylistic)) vueAndNuxtRules["@stylistic/max-len"] = "off";
407
+ const isVueAccessibilityEnabled = isEnabled(vue) && isEnabled(vue.accessibility);
408
+ return {
409
+ ...vueAndNuxtRules,
410
+ ...isVueAccessibilityEnabled && vueAccessibilityRules
411
+ };
370
412
  }
371
413
  //#endregion
372
414
  export { getVueRules };