@shayanthenerd/eslint-config 0.7.0 → 0.8.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 (37) hide show
  1. package/README.md +3 -0
  2. package/dist/configs/base.js +1 -1
  3. package/dist/configs/oxlintOverrides.js +1 -2
  4. package/dist/configs/restrictedExports.js +1 -2
  5. package/dist/configs/typescript.js +2 -2
  6. package/dist/configs/vue.js +1 -1
  7. package/dist/configs/vueComponentNames.js +1 -2
  8. package/dist/configs/vueServerComponents.js +1 -2
  9. package/dist/index.js +2 -4
  10. package/dist/oxlint.config.jsonc +7 -1
  11. package/dist/prettier.config.js +1 -1
  12. package/dist/rules/css.js +1 -2
  13. package/dist/rules/cypress.js +1 -2
  14. package/dist/rules/html.js +1 -2
  15. package/dist/rules/importX.js +1 -2
  16. package/dist/rules/javascript.js +3 -2
  17. package/dist/rules/perfectionist.js +3 -3
  18. package/dist/rules/playwright.js +1 -2
  19. package/dist/rules/storybook.js +1 -2
  20. package/dist/rules/stylistic.js +1 -2
  21. package/dist/rules/tailwind.js +1 -2
  22. package/dist/rules/typescript.js +2 -2
  23. package/dist/rules/vitest.js +1 -2
  24. package/dist/rules/vue.js +14 -10
  25. package/dist/rules/vueAccessibility.js +17 -3
  26. package/dist/types/configOptions/nuxt.d.ts +27 -1
  27. package/dist/types/configOptions/typescript.d.ts +3 -1
  28. package/dist/types/eslint-schema.d.ts +143 -39
  29. package/dist/utils/globs.js +10 -11
  30. package/dist/utils/ignores/getIgnorePatterns.js +1 -2
  31. package/dist/utils/ignores/resolveGitignorePatterns.js +1 -2
  32. package/dist/utils/options/defaultOptions.js +1 -0
  33. package/dist/utils/options/enableDetectedConfigs.js +1 -0
  34. package/dist/utils/options/mergeWithDefaults.js +4 -8
  35. package/dist/utils/vue/getRestrictedVueElements.js +2 -3
  36. package/dist/utils/vue/getRestrictedVueInputs.js +2 -3
  37. package/package.json +41 -42
package/README.md CHANGED
@@ -460,6 +460,9 @@ interface options {
460
460
  },
461
461
  nuxt?: boolean | {
462
462
  image?: boolean,
463
+ icon?: boolean | {
464
+ component?: string,
465
+ }
463
466
  ui?: boolean | {
464
467
  prefix?: string,
465
468
  }
@@ -1,7 +1,7 @@
1
1
  import { globs } from "../utils/globs.js";
2
2
  import { getJavaScriptRules } from "../rules/javascript.js";
3
- import typescriptESLint from "typescript-eslint";
4
3
  import { mergeConfigs } from "eslint-flat-config-utils";
4
+ import typescriptESLint from "typescript-eslint";
5
5
  import globals from "globals";
6
6
  import javascriptESLint from "@eslint/js";
7
7
 
@@ -16,7 +16,7 @@ function getOXLintOverridesConfig(options) {
16
16
  const javascriptRules = getJavaScriptRules(options);
17
17
  const typescriptRules = getTypeScriptRules(options);
18
18
  const playwrightRules = getPlaywrightRules(options);
19
- const oxlintOverridesConfig = {
19
+ return {
20
20
  name: "shayanthenerd/oxlint/overrides",
21
21
  files: [
22
22
  globs.src,
@@ -40,7 +40,6 @@ function getOXLintOverridesConfig(options) {
40
40
  "vitest/max-nested-describe": isEnabled(vitest) ? vitestRules["vitest/max-nested-describe"] : "off"
41
41
  }
42
42
  };
43
- return oxlintOverridesConfig;
44
43
  }
45
44
 
46
45
  //#endregion
@@ -2,7 +2,7 @@ import { globs } from "../utils/globs.js";
2
2
 
3
3
  //#region src/configs/restrictedExports.ts
4
4
  function getRestrictedExports() {
5
- const restrictedExportsConfig = {
5
+ return {
6
6
  name: "shayanthenerd/restricted-exports",
7
7
  files: [globs.restrictedExports],
8
8
  rules: { "no-restricted-exports": ["error", { restrictDefaultExports: {
@@ -12,7 +12,6 @@ function getRestrictedExports() {
12
12
  namespaceFrom: true
13
13
  } }] }
14
14
  };
15
- return restrictedExportsConfig;
16
15
  }
17
16
 
18
17
  //#endregion
@@ -2,9 +2,9 @@ import { globs } from "../utils/globs.js";
2
2
  import { isEnabled } from "../utils/isEnabled.js";
3
3
  import { defaultOptions } from "../utils/options/defaultOptions.js";
4
4
  import { getTypeScriptRules } from "../rules/typescript.js";
5
- import typescriptESLint from "typescript-eslint";
6
5
  import path from "node:path";
7
6
  import { mergeConfigs } from "eslint-flat-config-utils";
7
+ import typescriptESLint from "typescript-eslint";
8
8
 
9
9
  //#region src/configs/typescript.ts
10
10
  function getTypeScriptConfig(options) {
@@ -20,7 +20,7 @@ function getTypeScriptConfig(options) {
20
20
  tsconfigRootDir: tsConfig ? path.resolve(tsConfig.rootDir) : void 0,
21
21
  projectService: {
22
22
  defaultProject: tsConfig ? tsConfig.filename : void 0,
23
- allowDefaultProject: allowedDefaultProjects
23
+ allowDefaultProject: ["{prettier,eslint}.config.?([mc])ts", ...allowedDefaultProjects]
24
24
  }
25
25
  } },
26
26
  rules: getTypeScriptRules(options)
@@ -3,9 +3,9 @@ import { isEnabled } from "../utils/isEnabled.js";
3
3
  import { defaultOptions } from "../utils/options/defaultOptions.js";
4
4
  import { getVueRules } from "../rules/vue.js";
5
5
  import { getVueAccessibilityRules } from "../rules/vueAccessibility.js";
6
- import typescriptESLint from "typescript-eslint";
7
6
  import { mergeConfigs } from "eslint-flat-config-utils";
8
7
  import eslintPluginVue from "eslint-plugin-vue";
8
+ import typescriptESLint from "typescript-eslint";
9
9
  import eslintPluginVueAccessibility from "eslint-plugin-vuejs-accessibility";
10
10
 
11
11
  //#region src/configs/vue.ts
@@ -2,7 +2,7 @@ import { globs } from "../utils/globs.js";
2
2
 
3
3
  //#region src/configs/vueComponentNames.ts
4
4
  function getVueComponentNamesConfig() {
5
- const vueComponentNamesConfig = {
5
+ return {
6
6
  name: "shayanthenerd/vue/multi-word-component-names",
7
7
  files: [globs.vueAppErrorLayoutsPages],
8
8
  rules: {
@@ -11,7 +11,6 @@ function getVueComponentNamesConfig() {
11
11
  "vue/component-definition-name-casing": "off"
12
12
  }
13
13
  };
14
- return vueComponentNamesConfig;
15
14
  }
16
15
 
17
16
  //#endregion
@@ -2,12 +2,11 @@ import { globs } from "../utils/globs.js";
2
2
 
3
3
  //#region src/configs/vueServerComponents.ts
4
4
  function getVueServerComponentsConfig() {
5
- const vueServerComponentsConfig = {
5
+ return {
6
6
  name: "shayanthenerd/vue/server-components",
7
7
  files: [globs.vueServerComponents],
8
8
  rules: { "vue/no-multiple-template-root": "error" }
9
9
  };
10
- return vueServerComponentsConfig;
11
10
  }
12
11
 
13
12
  //#endregion
package/dist/index.js CHANGED
@@ -19,9 +19,8 @@ import { getIgnorePatterns } from "./utils/ignores/getIgnorePatterns.js";
19
19
  import { mergeWithDefaults } from "./utils/options/mergeWithDefaults.js";
20
20
  import { getVueComponentNamesConfig } from "./configs/vueComponentNames.js";
21
21
  import { getVueServerComponentsConfig } from "./configs/vueServerComponents.js";
22
- import { globalIgnores } from "eslint/config";
23
22
  import eslintPluginOXLint from "eslint-plugin-oxlint";
24
- import { config } from "typescript-eslint";
23
+ import { defineConfig as defineConfig$1, globalIgnores } from "eslint/config";
25
24
  import path from "node:path";
26
25
 
27
26
  //#region src/index.ts
@@ -41,13 +40,12 @@ function defineConfig(options = {}, ...configs) {
41
40
  patterns: ignores
42
41
  });
43
42
  const oxlintConfigPath = path.resolve(oxlint || defaultOptions.configs.oxlint);
44
- const eslintConfig = config({
43
+ return defineConfig$1({
45
44
  name: "shayanthenerd/global",
46
45
  linterOptions,
47
46
  settings,
48
47
  rules
49
48
  }, globalIgnores(ignorePatterns, "shayanthenerd/ignores"), getBaseConfig(mergedOptions), preferNamedExports ? getRestrictedExports() : {}, isEnabled(importX) ? getImportXConfig(mergedOptions) : {}, isEnabled(stylistic) ? getStylisticConfig(mergedOptions) : {}, isEnabled(perfectionist) ? getPerfectionistConfig(mergedOptions) : {}, isEnabled(typescript) ? getTypeScriptConfig(mergedOptions) : {}, isEnabled(html) ? getHTMLConfig(mergedOptions) : {}, isEnabled(css) ? getCSSConfig(mergedOptions) : {}, isEnabled(tailwind) ? getTailwindConfig(mergedOptions) : {}, isEnabled(vue) ? getVueConfig(mergedOptions) : {}, isEnabled(vue) ? getVueComponentNamesConfig() : {}, isEnabled(vue) && isEnabled(nuxt) ? getVueServerComponentsConfig() : {}, isEnabled(storybook) ? getStorybookConfig(mergedOptions) : {}, isEnabled(vitest) ? getVitestConfig(mergedOptions) : {}, isEnabled(playwright) ? getPlaywrightConfig(mergedOptions) : {}, isEnabled(cypress) ? getCypressConfig(mergedOptions) : {}, ...oxlint ? eslintPluginOXLint.buildFromOxlintConfigFile(oxlintConfigPath) : [], oxlint ? getOXLintOverridesConfig(mergedOptions) : {}, ...configs);
50
- return eslintConfig;
51
49
  }
52
50
 
53
51
  //#endregion
@@ -75,6 +75,7 @@
75
75
  "import/unambiguous": "off",
76
76
  "import/no-namespace": "off",
77
77
  "import/exports-last": "off",
78
+ "import/no-named-export": "off",
78
79
  "import/max-dependencies": "off",
79
80
  "import/no-default-export": "off",
80
81
  "import/prefer-default-export": "off",
@@ -103,6 +104,10 @@
103
104
  "jsdoc/require-returns": "off",
104
105
  "jsdoc/require-property": "off",
105
106
 
107
+ /*** Vue ***/
108
+ "vue/max-props": "off",
109
+ "vue/no-required-prop-with-default": "off",
110
+
106
111
  /*** Customizable Overrides ***/
107
112
  /* These rules are customizable in the ESLint config, but OXLint doesn't respect them. */
108
113
  "eslint/max-depth": "off",
@@ -110,7 +115,8 @@
110
115
  "eslint/max-nested-callbacks": "off",
111
116
  "typescript/consistent-type-definitions": "off",
112
117
  "vitest/consistent-test-it": "off",
113
- "jest/max-nested-describe": "off"
118
+ "jest/max-nested-describe": "off",
119
+ "vue/define-props-destructuring": "off"
114
120
  },
115
121
 
116
122
  "overrides": [
@@ -25,7 +25,7 @@ const prettierConfig = {
25
25
  experimentalTernaries: false,
26
26
  experimentalOperatorPosition: "end",
27
27
  overrides: [{
28
- files: ["*.jsonc", "bun.lock"],
28
+ files: ["*.jsonc"],
29
29
  options: { parser: "json" }
30
30
  }, {
31
31
  files: "*.svg",
package/dist/rules/css.js CHANGED
@@ -49,7 +49,7 @@ const allowedPhysicalProperties = [
49
49
  function getCSSRules(options) {
50
50
  const { css } = options.configs;
51
51
  const { useBaseline, allowedRelativeFontUnits } = isEnabled(css) ? css : defaultOptions.configs.css;
52
- const cssRules = {
52
+ return {
53
53
  "css/no-invalid-properties": ["error", { allowUnknownVariables: true }],
54
54
  "css/relative-font-units": ["warn", { allowUnits: allowedRelativeFontUnits }],
55
55
  "css/use-baseline": useBaseline ? ["warn", { available: useBaseline }] : "off",
@@ -58,7 +58,6 @@ function getCSSRules(options) {
58
58
  allowProperties: allowedPhysicalProperties
59
59
  }]
60
60
  };
61
- return cssRules;
62
61
  }
63
62
 
64
63
  //#endregion
@@ -1,6 +1,6 @@
1
1
  //#region src/rules/cypress.ts
2
2
  function getCypressRules() {
3
- const cypressRules = {
3
+ return {
4
4
  "cypress/no-force": "error",
5
5
  "cypress/no-pause": "error",
6
6
  "cypress/no-xpath": "error",
@@ -8,7 +8,6 @@ function getCypressRules() {
8
8
  "cypress/no-chained-get": "error",
9
9
  "cypress/assertion-before-screenshot": "error"
10
10
  };
11
- return cypressRules;
12
11
  }
13
12
 
14
13
  //#endregion
@@ -6,7 +6,7 @@ function getHTMLRules(options) {
6
6
  const { html, stylistic } = options.configs;
7
7
  const { useBaseline, idNamingConvention } = isEnabled(html) ? html : defaultOptions.configs.html;
8
8
  const { indent, useTabs, maxAttributesPerLine, maxConsecutiveEmptyLines, selfCloseVoidHTMLElements } = isEnabled(stylistic) ? stylistic : defaultOptions.configs.stylistic;
9
- const htmlRules = {
9
+ return {
10
10
  "better-tailwindcss/no-duplicate-classes": "off",
11
11
  "@html-eslint/no-target-blank": "error",
12
12
  "@html-eslint/no-duplicate-class": "warn",
@@ -47,7 +47,6 @@ function getHTMLRules(options) {
47
47
  enforceBeforeSelfClose: true
48
48
  }]
49
49
  };
50
- return htmlRules;
51
50
  }
52
51
 
53
52
  //#endregion
@@ -6,7 +6,7 @@ import path from "node:path";
6
6
  function getImportXRules(options) {
7
7
  const { packageDir, configs: { importX, typescript } } = options;
8
8
  const { removeUnusedImports } = isEnabled(importX) ? importX : defaultOptions.configs.importX;
9
- const importXRules = {
9
+ return {
10
10
  "unused-imports/no-unused-imports": removeUnusedImports ? "warn" : "off",
11
11
  "import-x/no-amd": "error",
12
12
  "import-x/no-commonjs": "error",
@@ -38,7 +38,6 @@ function getImportXRules(options) {
38
38
  packageDir: path.resolve(packageDir)
39
39
  }]
40
40
  };
41
- return importXRules;
42
41
  }
43
42
 
44
43
  //#endregion
@@ -1,7 +1,7 @@
1
1
  //#region src/rules/javascript.ts
2
2
  function getJavaScriptRules(options) {
3
3
  const { maxDepth, functionStyle, maxNestedCallbacks, preferNamedExports } = options.configs.base;
4
- const javascriptRules = {
4
+ return {
5
5
  "no-self-compare": "warn",
6
6
  "no-await-in-loop": "error",
7
7
  "no-unassigned-vars": "error",
@@ -78,6 +78,7 @@ function getJavaScriptRules(options) {
78
78
  "init-declarations": "error",
79
79
  "consistent-return": "error",
80
80
  "no-useless-concat": "error",
81
+ "no-param-reassign": "error",
81
82
  "no-useless-rename": "error",
82
83
  "default-param-last": "warn",
83
84
  "symbol-description": "warn",
@@ -93,6 +94,7 @@ function getJavaScriptRules(options) {
93
94
  "radix": ["error", "as-needed"],
94
95
  "curly": ["warn", "multi-line"],
95
96
  "max-depth": ["warn", maxDepth],
97
+ "preserve-caught-error": "warn",
96
98
  "no-object-constructor": "error",
97
99
  "prefer-object-has-own": "error",
98
100
  "no-useless-constructor": "error",
@@ -159,7 +161,6 @@ function getJavaScriptRules(options) {
159
161
  allowTaggedTemplates: true
160
162
  }]
161
163
  };
162
- return javascriptRules;
163
164
  }
164
165
 
165
166
  //#endregion
@@ -6,7 +6,7 @@ function getPerfectionistRules(options) {
6
6
  const { env, tsConfig, configs: { stylistic, perfectionist } } = options;
7
7
  const { maxLineLength } = isEnabled(stylistic) ? stylistic : defaultOptions.configs.stylistic;
8
8
  const { sortType } = isEnabled(perfectionist) ? perfectionist : defaultOptions.configs.perfectionist;
9
- const perfectionistRules = {
9
+ return {
10
10
  "perfectionist/sort-maps": "warn",
11
11
  "perfectionist/sort-exports": "warn",
12
12
  "perfectionist/sort-union-types": "warn",
@@ -28,7 +28,8 @@ function getPerfectionistRules(options) {
28
28
  maxLineLength,
29
29
  customGroups: [{
30
30
  groupName: "vue-sfc",
31
- elementNamePattern: ["\\.(vue|[jt]sx)$"]
31
+ elementNamePattern: ["\\.(vue|[jt]sx)$"],
32
+ modifiers: ["value"]
32
33
  }, {
33
34
  groupName: "image",
34
35
  elementNamePattern: ["\\.(ico|svg|gif|png|jpe?g|webp|avif|heic)$"]
@@ -66,7 +67,6 @@ function getPerfectionistRules(options) {
66
67
  ]
67
68
  }]
68
69
  };
69
- return perfectionistRules;
70
70
  }
71
71
 
72
72
  //#endregion
@@ -1,7 +1,7 @@
1
1
  //#region src/rules/playwright.ts
2
2
  function getPlaywrightRules(options) {
3
3
  const { maxNestedDescribe } = options.configs.test;
4
- const playwrightRules = {
4
+ return {
5
5
  "playwright/max-expects": "off",
6
6
  "playwright/prefer-to-be": "warn",
7
7
  "playwright/no-get-by-title": "error",
@@ -20,7 +20,6 @@ function getPlaywrightRules(options) {
20
20
  "playwright/max-nested-describe": ["warn", { max: maxNestedDescribe }],
21
21
  "playwright/prefer-lowercase-title": ["warn", { ignoreTopLevelDescribe: true }]
22
22
  };
23
- return playwrightRules;
24
23
  }
25
24
 
26
25
  //#endregion
@@ -2,13 +2,12 @@ import path from "node:path";
2
2
 
3
3
  //#region src/rules/storybook.ts
4
4
  function getStorybookRules(options) {
5
- const storybookRules = {
5
+ return {
6
6
  "storybook/csf-component": "error",
7
7
  "storybook/no-stories-of": "error",
8
8
  "storybook/meta-satisfies-type": "warn",
9
9
  "storybook/no-uninstalled-addons": ["error", { packageJsonLocation: path.resolve(options.packageDir, "package.json") }]
10
10
  };
11
- return storybookRules;
12
11
  }
13
12
 
14
13
  //#endregion
@@ -5,7 +5,7 @@ import { defaultOptions } from "../utils/options/defaultOptions.js";
5
5
  function getStylisticRules(options) {
6
6
  const { stylistic } = options.configs;
7
7
  const { semi, quotes, indent, useTabs, jsxQuotes, arrowParens, trailingComma, maxLineLength, memberDelimiterStyle, maxConsecutiveEmptyLines } = isEnabled(stylistic) ? stylistic : defaultOptions.configs.stylistic;
8
- const stylisticRules = {
8
+ return {
9
9
  "@stylistic/wrap-regex": "warn",
10
10
  "@stylistic/semi-style": "warn",
11
11
  "@stylistic/semi": ["warn", semi],
@@ -153,7 +153,6 @@ function getStylisticRules(options) {
153
153
  }
154
154
  ]
155
155
  };
156
- return stylisticRules;
157
156
  }
158
157
 
159
158
  //#endregion
@@ -7,7 +7,7 @@ function getTailwindRules(options) {
7
7
  const { multilineSort, ignoredUnregisteredClasses: userIgnoredUnregisteredClasses } = isEnabled(tailwind) ? tailwind : defaultOptions.configs.tailwind;
8
8
  const { indent, useTabs, maxLineLength } = isEnabled(stylistic) ? stylistic : defaultOptions.configs.stylistic;
9
9
  const isTailwindV4 = isEnabled(tailwind) && tailwind.entryPoint;
10
- const tailwindRules = {
10
+ return {
11
11
  "@stylistic/max-len": "off",
12
12
  "better-tailwindcss/no-duplicate-classes": "error",
13
13
  "better-tailwindcss/no-deprecated-classes": "error",
@@ -27,7 +27,6 @@ function getTailwindRules(options) {
27
27
  indent: useTabs ? "tab" : indent
28
28
  }]
29
29
  };
30
- return tailwindRules;
31
30
  }
32
31
 
33
32
  //#endregion
@@ -5,12 +5,13 @@ import { defaultOptions } from "../utils/options/defaultOptions.js";
5
5
  function getTypeScriptRules(options) {
6
6
  const { typescript } = options.configs;
7
7
  const { typeDefinitionStyle, methodSignatureStyle } = isEnabled(typescript) ? typescript : defaultOptions.configs.typescript;
8
- const tsRules = {
8
+ return {
9
9
  "no-loop-func": "off",
10
10
  "no-unused-vars": "off",
11
11
  "default-param-last": "off",
12
12
  "prefer-destructuring": "off",
13
13
  "@typescript-eslint/no-loop-func": "error",
14
+ "@typescript-eslint/unbound-method": "off",
14
15
  "@typescript-eslint/default-param-last": "warn",
15
16
  "@typescript-eslint/no-unsafe-assignment": "warn",
16
17
  "@typescript-eslint/prefer-destructuring": "warn",
@@ -56,7 +57,6 @@ function getTypeScriptRules(options) {
56
57
  }
57
58
  ]
58
59
  };
59
- return tsRules;
60
60
  }
61
61
 
62
62
  //#endregion
@@ -1,7 +1,7 @@
1
1
  //#region src/rules/vitest.ts
2
2
  function getVitestRules(options) {
3
3
  const { testFunction, maxNestedDescribe } = options.configs.test;
4
- const vitestRules = {
4
+ return {
5
5
  "vitest/prefer-todo": "warn",
6
6
  "vitest/prefer-to-be": "warn",
7
7
  "vitest/require-hook": "error",
@@ -39,7 +39,6 @@ function getVitestRules(options) {
39
39
  withinDescribe: testFunction
40
40
  }]
41
41
  };
42
- return vitestRules;
43
42
  }
44
43
 
45
44
  //#endregion
package/dist/rules/vue.js CHANGED
@@ -11,15 +11,18 @@ function getVueRules(options) {
11
11
  const nuxtImage = isEnabled(nuxt) ? nuxt.image : void 0;
12
12
  const nuxtUI = isEnabled(nuxt) ? nuxt.ui : void 0;
13
13
  const nuxtUIPrefix = isEnabled(nuxt) && isEnabled(nuxt.ui) ? nuxt.ui.prefix : defaultOptions.configs.nuxt.ui.prefix;
14
+ const nuxtIcon = isEnabled(nuxt) ? nuxt.icon : void 0;
15
+ const nuxtIconComponent = isEnabled(nuxt) && isEnabled(nuxt.icon) ? nuxt.icon.component : defaultOptions.configs.nuxt.icon.component;
14
16
  const isScriptLangTS = blockLang.script === "ts";
15
17
  const isStyleLangImplicit = blockLang.style === "implicit";
16
- const vueRules = {
18
+ return {
17
19
  "no-undef": "off",
18
20
  "no-useless-assignment": "off",
19
21
  "import-x/default": "off",
20
22
  "import-x/no-unresolved": "off",
21
23
  "vue/no-multiple-template-root": "off",
22
24
  "vue/comment-directive": ["error", { reportUnusedDisableDirectives: true }],
25
+ "vue/no-async-in-computed-properties": ["error", { ignoredObjectNames: ["z"] }],
23
26
  "vue/require-default-prop": "off",
24
27
  "vue/html-closing-bracket-newline": "warn",
25
28
  "vue/singleline-html-element-content-newline": "off",
@@ -41,7 +44,11 @@ function getVueRules(options) {
41
44
  void: selfCloseVoidHTMLElements
42
45
  } }],
43
46
  "vue/max-attributes-per-line": ["warn", { singleline: { max: maxAttributesPerLine } }],
44
- "vue/attributes-order": ["warn", { order: attributesOrder }],
47
+ "vue/attributes-order": ["warn", {
48
+ alphabetical: true,
49
+ sortLineLength: true,
50
+ order: attributesOrder
51
+ }],
45
52
  "vue/camelcase": "warn",
46
53
  "vue/no-root-v-if": "warn",
47
54
  "vue/require-expose": "error",
@@ -122,10 +129,6 @@ function getVueRules(options) {
122
129
  element: nuxtImage ? "img" : "",
123
130
  message: "Use `<NuxtImg>`."
124
131
  },
125
- {
126
- element: nuxtImage ? "picture" : "",
127
- message: "Use `<NuxtPicture>`."
128
- },
129
132
  {
130
133
  element: nuxtUI ? [
131
134
  "a",
@@ -157,10 +160,12 @@ function getVueRules(options) {
157
160
  ...userRestrictedStaticAttributes
158
161
  ],
159
162
  "vue/no-undef-components": ["error", { ignorePatterns: [
160
- "^(Nuxt|U)",
161
- "^(Icon|Html|Head|Title|Base|Meta|Link|Style|Body|NoScript)$",
163
+ nuxt ? "^Nuxt" : void 0,
164
+ nuxt ? "^(Html|Head|Title|Base|Meta|Link|Style|Body|NoScript|ClientOnly|DevOnly)$" : void 0,
165
+ nuxtIcon ? `^${nuxtIconComponent}$` : void 0,
166
+ nuxtUI ? `^${nuxtUIPrefix}` : void 0,
162
167
  ...userIgnoredUndefinedComponents
163
- ] }],
168
+ ].filter(Boolean) }],
164
169
  "vue/match-component-file-name": ["error", {
165
170
  shouldMatchCase: true,
166
171
  extensions: [
@@ -179,7 +184,6 @@ function getVueRules(options) {
179
184
  }
180
185
  ]
181
186
  };
182
- return vueRules;
183
187
  }
184
188
 
185
189
  //#endregion
@@ -3,9 +3,11 @@ import { defaultOptions } from "../utils/options/defaultOptions.js";
3
3
 
4
4
  //#region src/rules/vueAccessibility.ts
5
5
  function getVueAccessibilityRules(options) {
6
- const { vue } = options.configs;
6
+ const { vue, nuxt } = options.configs;
7
7
  const { imageComponents: userImageComponents, anchorComponents: userAnchorComponents, accessibleChildComponents: userAccessibleChildComponents } = isEnabled(vue) && isEnabled(vue.accessibility) ? vue.accessibility : defaultOptions.configs.vue.accessibility;
8
- const vueA11yRules = {
8
+ const nuxtUI = isEnabled(nuxt) ? nuxt.ui : void 0;
9
+ const nuxtUIPrefix = isEnabled(nuxt) && isEnabled(nuxt.ui) ? nuxt.ui.prefix : defaultOptions.configs.nuxt.ui.prefix;
10
+ return {
9
11
  "vuejs-accessibility/click-events-have-key-events": "off",
10
12
  "vuejs-accessibility/mouse-events-have-key-events": "off",
11
13
  "vuejs-accessibility/no-aria-hidden-on-focusable": "error",
@@ -14,9 +16,21 @@ function getVueAccessibilityRules(options) {
14
16
  "vuejs-accessibility/anchor-has-content": ["error", {
15
17
  components: userAnchorComponents,
16
18
  accessibleChildren: userAccessibleChildComponents
19
+ }],
20
+ "vuejs-accessibility/form-control-has-label": ["error", { labelComponents: nuxtUI ? [`${nuxtUIPrefix}FormField`] : void 0 }],
21
+ "vuejs-accessibility/label-has-for": ["error", {
22
+ allowChildren: true,
23
+ required: { some: ["nesting", "id"] },
24
+ controlComponents: [
25
+ "input",
26
+ "output",
27
+ "meter",
28
+ "select",
29
+ "textarea",
30
+ "progress"
31
+ ]
17
32
  }]
18
33
  };
19
- return vueA11yRules;
20
34
  }
21
35
 
22
36
  //#endregion
@@ -3,7 +3,7 @@ interface NuxtOptions {
3
3
  /**
4
4
  * Whether [NuxtImage](https://image.nuxt.com) is used in the project.
5
5
  *
6
- * Enforce the use of `<NuxtImg>` instead of `<img>`, and `<NuxtPicture>` instead of `<picture>`.
6
+ * Enforce the use of `<NuxtImg>` instead of `<img>`.
7
7
  *
8
8
  * @default false // `true` if "@nuxt/image" is detected in the package.json file when `autoDetectDeps` is enabled
9
9
  *
@@ -11,6 +11,32 @@ interface NuxtOptions {
11
11
  */
12
12
  image?: boolean;
13
13
 
14
+ /**
15
+ * Whether [@nuxt/icon](https://nuxt.com/modules/icon) is used in the project.
16
+ *
17
+ * Allows ESLint to recognize the icon component.
18
+ *
19
+ * @default false // `true` if "@nuxt/icon" is detected in the package.json file when `autoDetectDeps` is enabled
20
+ *
21
+ * @see [vue/no-undef-components](https://eslint.vuejs.org/rules/no-undef-components)
22
+ */
23
+ icon?: boolean | {
24
+ /**
25
+ * The name of the icon component.
26
+ *
27
+ * This is used by
28
+ * [vue/no-undef-components](https://eslint.vuejs.org/rules/no-undef-components)
29
+ * to detect the icon component.
30
+ *
31
+ * It will fall back to the default value if set to an empty string (`''`).
32
+ *
33
+ * @default 'Icon'
34
+ *
35
+ * @see [@nuxt/icon Options: Vue Component](https://github.com/nuxt/icon#vue-component)
36
+ */
37
+ component?: string;
38
+ };
39
+
14
40
  /**
15
41
  * Whether [NuxtUI](https://ui.nuxt.com) is used in the project.
16
42
  *
@@ -8,7 +8,9 @@ interface TypeScriptOptions extends ConfigWithOverrides {
8
8
  *
9
9
  * The matched files may not also be included in their nearest _tsconfig.json_ file.
10
10
  *
11
- * @default []
11
+ * New items extend the defaults, they don't override it.
12
+ *
13
+ * @default ['{prettier,eslint}.config.?([mc])ts']
12
14
  *
13
15
  * @see [@typescript-eslint: `allowDefaultProject` option](https://typescript-eslint.io/packages/parser#allowdefaultproject)
14
16
  */