@shayanthenerd/eslint-config 0.28.2 → 0.28.4

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
@@ -213,10 +213,7 @@ For editor integration, to avoid inconsistent diagnostics from the [Tailwind CS
213
213
  ```
214
214
 
215
215
  ### Nuxt
216
- Nuxt support is already included through the Vue integration, so you don’t need to install or configure [@nuxt/eslint][eslint-nuxt] manually. If you need additional rules tailored to Nuxt, refer to the plugin’s documentation for setup instructions.
217
-
218
- > [!TIP]
219
- > `configs.nuxt` only includes options for Nuxt Image, Nuxt UI, and the `<Icon>` component. Vue's rules and `overrides` can be configured via `configs.vue`.
216
+ The required Nuxt configurations and rules are already included, so there's no need to install or configure the [@nuxt/eslint][eslint-nuxt] module.
220
217
 
221
218
  ### Markdown
222
219
  Markdown linting is powered by [@eslint/markdown][plugin-md].
@@ -500,6 +497,7 @@ _.vscode/settings.json_:
500
497
  ui?: boolean | {
501
498
  prefix?: string,
502
499
  },
500
+ overrides?: Overrides,
503
501
  },
504
502
  packageJson?: boolean | {
505
503
  overrides?: Overrides,
@@ -12,7 +12,7 @@ function getBaseConfig(options) {
12
12
  name: "shayanthenerd/base",
13
13
  files: [
14
14
  globs.src,
15
- globs.jsxLike,
15
+ globs.jsxTsx,
16
16
  isEnabled(vue) ? globs.vue : "",
17
17
  isEnabled(astro) ? globs.astro : ""
18
18
  ].filter(isTruthy),
@@ -10,7 +10,7 @@ function getBaselineConfig(options) {
10
10
  name: "shayanthenerd/baseline",
11
11
  files: [
12
12
  globs.src,
13
- globs.jsxLike,
13
+ globs.jsxTsx,
14
14
  isEnabled(vue) ? globs.vue : "",
15
15
  isEnabled(astro) ? globs.astro : ""
16
16
  ].filter(isTruthy),
@@ -13,7 +13,7 @@ function getImportXConfig(options) {
13
13
  name: "shayanthenerd/import-x",
14
14
  files: [
15
15
  globs.src,
16
- globs.jsxLike,
16
+ globs.jsxTsx,
17
17
  isEnabled(vue) ? globs.vue : "",
18
18
  isEnabled(astro) ? globs.astro : ""
19
19
  ].filter(isTruthy),
@@ -10,7 +10,7 @@ function getNextConfig(options) {
10
10
  const { overrides } = isEnabled(next) ? next : defaultOptions.configs.next;
11
11
  return mergeConfigs({
12
12
  name: "shayanthenerd/next",
13
- files: [globs.src, globs.jsxLike],
13
+ files: [globs.src, globs.jsxTsx],
14
14
  plugins: { next: eslintPluginNext },
15
15
  settings: { next: { rootDir: packageDir } },
16
16
  rules: getNextRules()
@@ -15,7 +15,7 @@ function getNodeConfig(options) {
15
15
  name: "shayanthenerd/node",
16
16
  files: [
17
17
  globs.src,
18
- globs.jsxLike,
18
+ globs.jsxTsx,
19
19
  isEnabled(vue) ? globs.vue : "",
20
20
  isEnabled(astro) ? globs.astro : ""
21
21
  ].filter(isTruthy),
@@ -0,0 +1,64 @@
1
+ import { globs } from "../helpers/globs.mjs";
2
+ import { isEnabled } from "../utils/isEnabled.mjs";
3
+ import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
4
+ import { getNuxtRules } from "../rules/nuxt.mjs";
5
+ import { mergeConfigs } from "eslint-flat-config-utils";
6
+ import eslintPluginVue from "eslint-plugin-vue";
7
+ import { parser } from "typescript-eslint";
8
+ import eslintPluginNuxt from "@nuxt/eslint-plugin";
9
+ import eslintPluginNuxtLinkChecker from "nuxt-link-checker/eslint";
10
+ //#region src/configs/nuxt.ts
11
+ const baseVueConfig = eslintPluginVue.configs["flat/base"].find((config) => config.languageOptions?.parser);
12
+ const middlewaresConfig = {
13
+ name: "shayanthenerd/nuxt/middlewares",
14
+ files: [globs.nuxtMiddlewares],
15
+ rules: {
16
+ "consistent-return": "off",
17
+ "@typescript-eslint/consistent-return": "off"
18
+ }
19
+ };
20
+ const componentNamesConfig = {
21
+ name: "shayanthenerd/nuxt/component-names",
22
+ files: [globs.nuxtAppErrorLayoutsPages],
23
+ rules: {
24
+ "vue/match-component-file-name": "off",
25
+ "vue/multi-word-component-names": "off",
26
+ "vue/component-definition-name-casing": "off"
27
+ }
28
+ };
29
+ const serverComponentsConfig = {
30
+ name: "shayanthenerd/nuxt/server-components",
31
+ files: [globs.nuxtServerComponents],
32
+ plugins: { vue: eslintPluginVue },
33
+ rules: { "vue/no-multiple-template-root": "error" }
34
+ };
35
+ function getNuxtConfigs(options) {
36
+ const { nuxt } = options.configs;
37
+ const { overrides } = isEnabled(nuxt) ? nuxt : defaultOptions.configs.nuxt;
38
+ return [
39
+ mergeConfigs({
40
+ name: "shayanthenerd/nuxt",
41
+ files: [globs.vue],
42
+ plugins: {
43
+ "vue": eslintPluginVue,
44
+ "nuxt": eslintPluginNuxt,
45
+ "link-checker": eslintPluginNuxtLinkChecker
46
+ },
47
+ processor: "vue/vue",
48
+ languageOptions: {
49
+ parser: baseVueConfig?.languageOptions?.parser,
50
+ parserOptions: {
51
+ parser,
52
+ extraFileExtensions: [".vue"],
53
+ vueFeatures: { filter: false }
54
+ }
55
+ },
56
+ rules: getNuxtRules()
57
+ }, overrides),
58
+ middlewaresConfig,
59
+ componentNamesConfig,
60
+ serverComponentsConfig
61
+ ];
62
+ }
63
+ //#endregion
64
+ export { getNuxtConfigs };
@@ -13,7 +13,7 @@ function getPerfectionistConfig(options) {
13
13
  name: "shayanthenerd/perfectionist",
14
14
  files: [
15
15
  globs.src,
16
- globs.jsxLike,
16
+ globs.jsxTsx,
17
17
  isEnabled(vue) ? globs.vue : "",
18
18
  isEnabled(astro) ? globs.astro : ""
19
19
  ].filter(isTruthy),
@@ -13,7 +13,7 @@ function getPromiseConfig(options) {
13
13
  name: "shayanthenerd/promise",
14
14
  files: [
15
15
  globs.src,
16
- globs.jsxLike,
16
+ globs.jsxTsx,
17
17
  isEnabled(vue) ? globs.vue : "",
18
18
  isEnabled(astro) ? globs.astro : ""
19
19
  ].filter(isTruthy),
@@ -13,7 +13,7 @@ function getReactConfig(options) {
13
13
  const { overrides, accessibility } = isEnabled(react) ? react : defaultOptions.configs.react;
14
14
  return mergeConfigs({
15
15
  name: "shayanthenerd/react",
16
- files: [globs.src, globs.jsxLike],
16
+ files: [globs.src, globs.jsxTsx],
17
17
  plugins: {
18
18
  "@eslint-react": eslintPluginReact,
19
19
  "@html-eslint/react": eslintPluginHtmlReact,
@@ -13,7 +13,7 @@ function getStylisticConfig(options) {
13
13
  name: "shayanthenerd/stylistic",
14
14
  files: [
15
15
  globs.src,
16
- globs.jsxLike,
16
+ globs.jsxTsx,
17
17
  isEnabled(vue) ? globs.vue : "",
18
18
  isEnabled(astro) ? globs.astro : ""
19
19
  ].filter(isTruthy),
@@ -58,7 +58,7 @@ function getTailwindConfig(options) {
58
58
  name: "shayanthenerd/tailwind",
59
59
  files: [
60
60
  globs.src,
61
- globs.jsxLike,
61
+ globs.jsxTsx,
62
62
  isEnabled(vue) ? globs.vue : "",
63
63
  isEnabled(html) ? globs.html : "",
64
64
  isEnabled(astro) ? globs.astro : ""
@@ -15,7 +15,7 @@ function getTypeScriptConfig(options) {
15
15
  name: "shayanthenerd/typescript",
16
16
  files: [
17
17
  globs.src,
18
- globs.jsxLike,
18
+ globs.jsxTsx,
19
19
  isEnabled(vue) ? globs.vue : "",
20
20
  isEnabled(astro) ? globs.astro : ""
21
21
  ].filter(isTruthy),
@@ -13,7 +13,7 @@ function getUnicornConfig(options) {
13
13
  name: "shayanthenerd/unicorn",
14
14
  files: [
15
15
  globs.src,
16
- globs.jsxLike,
16
+ globs.jsxTsx,
17
17
  isEnabled(vue) ? globs.vue : "",
18
18
  isEnabled(astro) ? globs.astro : ""
19
19
  ].filter(isTruthy),
@@ -10,8 +10,8 @@ import eslintPluginVueAccessibility from "eslint-plugin-vuejs-accessibility";
10
10
  const baseVueConfig = eslintPluginVue.configs["flat/base"].find((config) => config.languageOptions?.parser);
11
11
  function getVueConfig(options) {
12
12
  const { vue } = options.configs;
13
- const isVueAccessibilityEnabled = isEnabled(vue) && isEnabled(vue.accessibility);
14
13
  const { overrides } = isEnabled(vue) ? vue : defaultOptions.configs.vue;
14
+ const isVueAccessibilityEnabled = isEnabled(vue) && isEnabled(vue.accessibility);
15
15
  return mergeConfigs({
16
16
  name: "shayanthenerd/vue",
17
17
  files: [globs.vue],
@@ -14,7 +14,7 @@ function getZodConfig(options) {
14
14
  name: `shayanthenerd/${mini ? "zod-mini" : "zod"}`,
15
15
  files: [
16
16
  globs.src,
17
- globs.jsxLike,
17
+ globs.jsxTsx,
18
18
  isEnabled(vue) ? globs.vue : "",
19
19
  isEnabled(astro) ? globs.astro : ""
20
20
  ].filter(isTruthy),
@@ -1,20 +1,20 @@
1
1
  //#region src/helpers/globs.ts
2
2
  const srcExtensions = "?([mc])[jt]s";
3
- const jsxLikeExtensions = "[jt]sx";
4
- const vueExtensions = `{vue,${srcExtensions},${jsxLikeExtensions}}`;
3
+ const jsxTsxExtensions = "[jt]sx";
4
+ const vueExtensions = `{vue,${srcExtensions},${jsxTsxExtensions}}`;
5
5
  const globs = {
6
6
  src: `**/*.${srcExtensions}`,
7
- jsxLike: `**/*.${jsxLikeExtensions}`,
7
+ jsxTsx: `**/*.${jsxTsxExtensions}`,
8
8
  packageJson: "**/package.json",
9
9
  markdown: "**/*.md",
10
10
  html: "**/*.html",
11
11
  css: "**/*.css",
12
12
  astro: "**/*.astro",
13
13
  vue: `**/*.${vueExtensions}`,
14
- vueMiddlewares: `**/middleware?(s)/**/*.${srcExtensions}`,
15
- vueServerComponents: `**/*.server.${vueExtensions}`,
16
- vueAppErrorLayoutsPages: `**/{{app,error},{layouts,pages}/**/*}.${vueExtensions}`,
17
- storybook: `**/*.(story|stories).{${srcExtensions},${jsxLikeExtensions}}`,
14
+ nuxtAppErrorLayoutsPages: `**/{{app,error},{layouts,pages}/**/*}.${vueExtensions}`,
15
+ nuxtServerComponents: `**/*.server.${vueExtensions}`,
16
+ nuxtMiddlewares: `**/middleware?(s)/**/*.${srcExtensions}`,
17
+ storybook: `**/*.(story|stories).{${srcExtensions},${jsxTsxExtensions}}`,
18
18
  test: `**/{__tests__/*,*.{test,spec,cy,bench?(mark)}.${srcExtensions}`,
19
19
  coverage: "**/coverage/**"
20
20
  };
@@ -14,11 +14,10 @@ const defaultIgnorePatterns = [
14
14
  "**/dist",
15
15
  "**/build",
16
16
  "**/.data",
17
+ "**/public",
17
18
  "**/output",
18
19
  "**/.output",
19
20
  "**/.serverless",
20
- "**/public/build",
21
- "**/public/static",
22
21
  "**/.eslint-config-inspector",
23
22
  "**/tmp",
24
23
  "**/.tmp",
@@ -58,7 +58,8 @@ const defaultOptions = {
58
58
  nuxt: {
59
59
  icon: { component: "Icon" },
60
60
  image: false,
61
- ui: { prefix: "U" }
61
+ ui: { prefix: "U" },
62
+ overrides: {}
62
63
  },
63
64
  packageJson: { overrides: {} },
64
65
  perfectionist: {
package/dist/index.mjs CHANGED
@@ -7,6 +7,7 @@ import { getBaseConfig } from "./configs/base.mjs";
7
7
  import { getHtmlConfig } from "./configs/html.mjs";
8
8
  import { getNextConfig } from "./configs/next.mjs";
9
9
  import { getNodeConfig } from "./configs/node.mjs";
10
+ import { getNuxtConfigs } from "./configs/nuxt.mjs";
10
11
  import { getAstroConfig } from "./configs/astro.mjs";
11
12
  import { getReactConfig } from "./configs/react.mjs";
12
13
  import { getVitestConfig } from "./configs/vitest.mjs";
@@ -23,11 +24,8 @@ import { getPlaywrightConfig } from "./configs/playwright.mjs";
23
24
  import { getTypeScriptConfig } from "./configs/typescript.mjs";
24
25
  import { getPackageJsonConfig } from "./configs/packageJson.mjs";
25
26
  import { getPerfectionistConfig } from "./configs/perfectionist.mjs";
26
- import { getVueMiddlewaresConfig } from "./configs/vueMiddlewares.mjs";
27
27
  import { getIgnorePatterns } from "./helpers/ignores/getIgnorePatterns.mjs";
28
28
  import { mergeWithDefaults } from "./helpers/options/mergeWithDefaults.mjs";
29
- import { getVueComponentNamesConfig } from "./configs/vueComponentNames.mjs";
30
- import { getVueServerComponentsConfig } from "./configs/vueServerComponents.mjs";
31
29
  import { defineConfig as defineConfig$1, globalIgnores } from "eslint/config";
32
30
  //#region src/index.ts
33
31
  /**
@@ -106,9 +104,7 @@ function defineConfig(...args) {
106
104
  isEnabled(react) && getReactConfig(mergedOptions),
107
105
  isEnabled(next) && getNextConfig(mergedOptions),
108
106
  isEnabled(vue) && getVueConfig(mergedOptions),
109
- isEnabled(vue) && getVueMiddlewaresConfig(),
110
- isEnabled(vue) && getVueComponentNamesConfig(),
111
- isEnabled(vue) && isEnabled(nuxt) && getVueServerComponentsConfig(),
107
+ ...isEnabled(nuxt) ? getNuxtConfigs(mergedOptions) : [],
112
108
  isEnabled(storybook) && getStorybookConfig(mergedOptions),
113
109
  isEnabled(vitest) && getVitestConfig(mergedOptions),
114
110
  isEnabled(cypress) && getCypressConfig(mergedOptions),
@@ -0,0 +1,12 @@
1
+ //#region src/rules/nuxt.ts
2
+ const nuxtRules = {
3
+ "link-checker/valid-route": "error",
4
+ "link-checker/valid-sitemap-link": "warn",
5
+ "nuxt/no-page-meta-runtime-values": "error",
6
+ "nuxt/prefer-import-meta": "warn"
7
+ };
8
+ function getNuxtRules() {
9
+ return nuxtRules;
10
+ }
11
+ //#endregion
12
+ export { getNuxtRules };
@@ -59,7 +59,15 @@ const typeConstituentSortOptions = {
59
59
  };
60
60
  const sortArrayIncludesOptions = {
61
61
  customGroups: literalCustomGroups,
62
- groups: sharedTypeLikeGroups
62
+ groups: [
63
+ "boolean-literal",
64
+ "number-literal",
65
+ "bigint-literal",
66
+ "string-literal",
67
+ "template-literal",
68
+ "literal",
69
+ "unknown"
70
+ ]
63
71
  };
64
72
  const sortImportsCustomGroups = [{
65
73
  groupName: "component",
@@ -45,11 +45,12 @@ function getTailwindRules(options) {
45
45
  }],
46
46
  "better-tailwindcss/enforce-consistent-variant-order": "warn",
47
47
  "better-tailwindcss/enforce-logical-properties": ["warn", { ignore: nonLogicalTailwindUtilityPatterns }],
48
- "better-tailwindcss/no-duplicate-classes": "error",
48
+ "better-tailwindcss/no-concatenated-classes": "error",
49
+ "better-tailwindcss/no-conflicting-classes": "error",
49
50
  "better-tailwindcss/no-deprecated-classes": "error",
50
- "better-tailwindcss/no-unnecessary-whitespace": "warn",
51
+ "better-tailwindcss/no-duplicate-classes": "error",
51
52
  "better-tailwindcss/no-unknown-classes": [isTailwindV4 ? "warn" : "off", { ignore: userIgnoredUnknownClasses }],
52
- "better-tailwindcss/no-conflicting-classes": "error"
53
+ "better-tailwindcss/no-unnecessary-whitespace": "warn"
53
54
  };
54
55
  }
55
56
  //#endregion
@@ -55,7 +55,7 @@ function getVueRules(options) {
55
55
  "vuejs-accessibility/role-has-required-aria-props": "error",
56
56
  "vuejs-accessibility/tabindex-no-positive": "error"
57
57
  };
58
- const vueAndNuxtRules = {
58
+ const vueRules = {
59
59
  "@typescript-eslint/no-useless-default-assignment": "off",
60
60
  "vue/jsx-uses-vars": "error",
61
61
  "vue/comment-directive": ["error", { reportUnusedDisableDirectives: true }],
@@ -238,11 +238,7 @@ function getVueRules(options) {
238
238
  multiline: true,
239
239
  consistent: true
240
240
  }],
241
- "vue/object-curly-spacing": [
242
- "warn",
243
- "always",
244
- { emptyObjects: "never" }
245
- ],
241
+ "vue/object-curly-spacing": ["warn", "always"],
246
242
  "vue/object-property-newline": ["warn", { allowAllPropertiesOnSameLine: true }],
247
243
  "vue/object-shorthand": "warn",
248
244
  "vue/operator-linebreak": [
@@ -404,10 +400,10 @@ function getVueRules(options) {
404
400
  "vue/slot-name-casing": "warn",
405
401
  "vue/v-for-delimiter-style": ["warn", vForDelimiterStyle]
406
402
  };
407
- if (isEnabled(stylistic)) vueAndNuxtRules["@stylistic/max-len"] = "off";
403
+ if (isEnabled(stylistic)) vueRules["@stylistic/max-len"] = "off";
408
404
  const isVueAccessibilityEnabled = isEnabled(vue) && isEnabled(vue.accessibility);
409
405
  return {
410
- ...vueAndNuxtRules,
406
+ ...vueRules,
411
407
  ...isVueAccessibilityEnabled && vueAccessibilityRules
412
408
  };
413
409
  }
@@ -1873,6 +1873,7 @@ interface ESLintSchema {
1873
1873
  /**
1874
1874
  * Disallow specified modules when loaded by `import`
1875
1875
  * @see https://typescript-eslint.io/rules/no-restricted-imports
1876
+ * @deprecated
1876
1877
  */
1877
1878
  '@typescript-eslint/no-restricted-imports'?: Linter.RuleEntry<TypescriptEslintNoRestrictedImports>;
1878
1879
  /**
@@ -2626,6 +2627,11 @@ interface ESLintSchema {
2626
2627
  * @see https://github.com/schoero/eslint-plugin-better-tailwindcss/blob/main/docs/rules/enforce-shorthand-classes.md
2627
2628
  */
2628
2629
  'better-tailwindcss/enforce-shorthand-classes'?: Linter.RuleEntry<BetterTailwindcssEnforceShorthandClasses>;
2630
+ /**
2631
+ * Disallow concatenated classes in Tailwind CSS class strings.
2632
+ * @see https://github.com/schoero/eslint-plugin-better-tailwindcss/blob/main/docs/rules/no-concatenated-classes.md
2633
+ */
2634
+ 'better-tailwindcss/no-concatenated-classes'?: Linter.RuleEntry<BetterTailwindcssNoConcatenatedClasses>;
2629
2635
  /**
2630
2636
  * Disallow classes that produce conflicting styles.
2631
2637
  * @see https://github.com/schoero/eslint-plugin-better-tailwindcss/blob/main/docs/rules/no-conflicting-classes.md
@@ -3518,6 +3524,14 @@ interface ESLintSchema {
3518
3524
  * @deprecated
3519
3525
  */
3520
3526
  'lines-between-class-members'?: Linter.RuleEntry<LinesBetweenClassMembers>;
3527
+ /**
3528
+ * Validate that relative URLs match a known vue-router route pattern
3529
+ */
3530
+ 'link-checker/valid-route'?: Linter.RuleEntry<LinkCheckerValidRoute>;
3531
+ /**
3532
+ * Validate that relative URLs exist in the sitemap
3533
+ */
3534
+ 'link-checker/valid-sitemap-link'?: Linter.RuleEntry<LinkCheckerValidSitemapLink>;
3521
3535
  /**
3522
3536
  * Require or disallow logical assignment operator shorthand
3523
3537
  * @see https://eslint.org/docs/latest/rules/logical-assignment-operators
@@ -4849,6 +4863,26 @@ interface ESLintSchema {
4849
4863
  * @deprecated
4850
4864
  */
4851
4865
  'nonblock-statement-body-position'?: Linter.RuleEntry<NonblockStatementBodyPosition>;
4866
+ /**
4867
+ * Disallow setting `test` key in Nuxt config
4868
+ * @see https://eslint.nuxt.com/packages/plugin#nuxtno-nuxt-config-test-key
4869
+ */
4870
+ 'nuxt/no-nuxt-config-test-key'?: Linter.RuleEntry<[]>;
4871
+ /**
4872
+ * Disallow runtime context values inside `definePageMeta` at the eager level, which is extracted into a separate chunk at build time and runs before component setup
4873
+ * @see https://eslint.nuxt.com/packages/plugin#nuxtno-page-meta-runtime-values
4874
+ */
4875
+ 'nuxt/no-page-meta-runtime-values'?: Linter.RuleEntry<[]>;
4876
+ /**
4877
+ * Prefer recommended order of Nuxt config properties
4878
+ * @see https://eslint.nuxt.com/packages/plugin#nuxtnuxt-config-keys-order
4879
+ */
4880
+ 'nuxt/nuxt-config-keys-order'?: Linter.RuleEntry<[]>;
4881
+ /**
4882
+ * Prefer using `import.meta.*` over `process.*`
4883
+ * @see https://eslint.nuxt.com/packages/plugin#nuxtprefer-import-meta
4884
+ */
4885
+ 'nuxt/prefer-import-meta'?: Linter.RuleEntry<[]>;
4852
4886
  /**
4853
4887
  * Enforce consistent line breaks after opening and before closing braces
4854
4888
  * @see https://eslint.org/docs/latest/rules/object-curly-newline
@@ -13502,6 +13536,7 @@ type BetterTailwindcssEnforceConsistentLineWrapping = [] | [{
13502
13536
  printWidth?: number;
13503
13537
  strictness?: ("strict" | "loose");
13504
13538
  tabWidth?: number;
13539
+ vueConvertToBinding?: boolean;
13505
13540
  }];
13506
13541
  // ----- better-tailwindcss/enforce-consistent-variable-syntax -----
13507
13542
  type BetterTailwindcssEnforceConsistentVariableSyntax = [] | [{
@@ -14285,6 +14320,201 @@ type BetterTailwindcssEnforceShorthandClasses = [] | [{
14285
14320
  rootFontSize?: number;
14286
14321
  cwd?: string;
14287
14322
  }];
14323
+ // ----- better-tailwindcss/no-concatenated-classes -----
14324
+ type BetterTailwindcssNoConcatenatedClasses = [] | [{
14325
+ selectors?: ({
14326
+ kind: "attribute";
14327
+ match?: ({
14328
+ type: "strings";
14329
+ } | {
14330
+ path?: string;
14331
+ type: "objectKeys";
14332
+ } | {
14333
+ path?: string;
14334
+ type: "objectValues";
14335
+ } | {
14336
+ match: ({
14337
+ type: "strings";
14338
+ } | {
14339
+ path?: string;
14340
+ type: "objectKeys";
14341
+ } | {
14342
+ path?: string;
14343
+ type: "objectValues";
14344
+ })[];
14345
+ type: "anonymousFunctionReturn";
14346
+ })[];
14347
+ name: string;
14348
+ } | ({
14349
+ callTarget?: ("all" | "first" | "last" | number);
14350
+ kind: "callee";
14351
+ match?: ({
14352
+ type: "strings";
14353
+ } | {
14354
+ path?: string;
14355
+ type: "objectKeys";
14356
+ } | {
14357
+ path?: string;
14358
+ type: "objectValues";
14359
+ } | {
14360
+ match: ({
14361
+ type: "strings";
14362
+ } | {
14363
+ path?: string;
14364
+ type: "objectKeys";
14365
+ } | {
14366
+ path?: string;
14367
+ type: "objectValues";
14368
+ })[];
14369
+ type: "anonymousFunctionReturn";
14370
+ })[];
14371
+ name: string;
14372
+ path?: string;
14373
+ targetArgument?: ("all" | "first" | "last" | number);
14374
+ targetCall?: ("all" | "first" | "last" | number);
14375
+ } | {
14376
+ callTarget?: ("all" | "first" | "last" | number);
14377
+ kind: "callee";
14378
+ match?: ({
14379
+ type: "strings";
14380
+ } | {
14381
+ path?: string;
14382
+ type: "objectKeys";
14383
+ } | {
14384
+ path?: string;
14385
+ type: "objectValues";
14386
+ } | {
14387
+ match: ({
14388
+ type: "strings";
14389
+ } | {
14390
+ path?: string;
14391
+ type: "objectKeys";
14392
+ } | {
14393
+ path?: string;
14394
+ type: "objectValues";
14395
+ })[];
14396
+ type: "anonymousFunctionReturn";
14397
+ })[];
14398
+ name?: string;
14399
+ path: string;
14400
+ targetArgument?: ("all" | "first" | "last" | number);
14401
+ targetCall?: ("all" | "first" | "last" | number);
14402
+ }) | ({
14403
+ kind: "tag";
14404
+ match?: ({
14405
+ type: "strings";
14406
+ } | {
14407
+ path?: string;
14408
+ type: "objectKeys";
14409
+ } | {
14410
+ path?: string;
14411
+ type: "objectValues";
14412
+ } | {
14413
+ match: ({
14414
+ type: "strings";
14415
+ } | {
14416
+ path?: string;
14417
+ type: "objectKeys";
14418
+ } | {
14419
+ path?: string;
14420
+ type: "objectValues";
14421
+ })[];
14422
+ type: "anonymousFunctionReturn";
14423
+ })[];
14424
+ name: string;
14425
+ path?: string;
14426
+ } | {
14427
+ kind: "tag";
14428
+ match?: ({
14429
+ type: "strings";
14430
+ } | {
14431
+ path?: string;
14432
+ type: "objectKeys";
14433
+ } | {
14434
+ path?: string;
14435
+ type: "objectValues";
14436
+ } | {
14437
+ match: ({
14438
+ type: "strings";
14439
+ } | {
14440
+ path?: string;
14441
+ type: "objectKeys";
14442
+ } | {
14443
+ path?: string;
14444
+ type: "objectValues";
14445
+ })[];
14446
+ type: "anonymousFunctionReturn";
14447
+ })[];
14448
+ name?: string;
14449
+ path: string;
14450
+ }) | {
14451
+ kind: "variable";
14452
+ match?: ({
14453
+ type: "strings";
14454
+ } | {
14455
+ path?: string;
14456
+ type: "objectKeys";
14457
+ } | {
14458
+ path?: string;
14459
+ type: "objectValues";
14460
+ } | {
14461
+ match: ({
14462
+ type: "strings";
14463
+ } | {
14464
+ path?: string;
14465
+ type: "objectKeys";
14466
+ } | {
14467
+ path?: string;
14468
+ type: "objectValues";
14469
+ })[];
14470
+ type: "anonymousFunctionReturn";
14471
+ })[];
14472
+ name: string;
14473
+ })[];
14474
+ callees?: ([string, ({
14475
+ match: "strings";
14476
+ } | {
14477
+ match: "objectKeys";
14478
+ pathPattern?: string;
14479
+ } | {
14480
+ match: "objectValues";
14481
+ pathPattern?: string;
14482
+ })[]] | string)[];
14483
+ attributes?: (string | [string, ({
14484
+ match: "strings";
14485
+ } | {
14486
+ match: "objectKeys";
14487
+ pathPattern?: string;
14488
+ } | {
14489
+ match: "objectValues";
14490
+ pathPattern?: string;
14491
+ })[]])[];
14492
+ variables?: ([string, ({
14493
+ match: "strings";
14494
+ } | {
14495
+ match: "objectKeys";
14496
+ pathPattern?: string;
14497
+ } | {
14498
+ match: "objectValues";
14499
+ pathPattern?: string;
14500
+ })[]] | string)[];
14501
+ tags?: ([string, ({
14502
+ match: "strings";
14503
+ } | {
14504
+ match: "objectKeys";
14505
+ pathPattern?: string;
14506
+ } | {
14507
+ match: "objectValues";
14508
+ pathPattern?: string;
14509
+ })[]] | string)[];
14510
+ entryPoint?: string;
14511
+ messageStyle?: ("visual" | "compact" | "raw");
14512
+ tailwindConfig?: string;
14513
+ tsconfig?: string;
14514
+ detectComponentClasses?: boolean;
14515
+ rootFontSize?: number;
14516
+ cwd?: string;
14517
+ }];
14288
14518
  // ----- better-tailwindcss/no-conflicting-classes -----
14289
14519
  type BetterTailwindcssNoConflictingClasses = [] | [{
14290
14520
  selectors?: ({
@@ -16994,6 +17224,16 @@ type LinesBetweenClassMembers = [] | [({
16994
17224
  } | ("always" | "never")), {
16995
17225
  exceptAfterSingleLine?: boolean;
16996
17226
  }];
17227
+ // ----- link-checker/valid-route -----
17228
+ type LinkCheckerValidRoute = [] | [{
17229
+ routesFile?: string;
17230
+ rootDir?: string;
17231
+ }];
17232
+ // ----- link-checker/valid-sitemap-link -----
17233
+ type LinkCheckerValidSitemapLink = [] | [{
17234
+ routesFile?: string;
17235
+ rootDir?: string;
17236
+ }];
16997
17237
  // ----- logical-assignment-operators -----
16998
17238
  type LogicalAssignmentOperators = (([] | ["always"] | ["always", {
16999
17239
  enforceForIfStatements?: boolean;
@@ -22970,6 +23210,7 @@ type VueSortKeys = [] | [("asc" | "desc")] | [("asc" | "desc"), {
22970
23210
  ignoreGrandchildrenOf?: unknown[];
22971
23211
  minKeys?: number;
22972
23212
  natural?: boolean;
23213
+ allowLineSeparatedGroups?: boolean;
22973
23214
  }];
22974
23215
  // ----- vue/space-in-parens -----
22975
23216
  type VueSpaceInParens = [] | [("always" | "never")] | [("always" | "never"), {
@@ -302,11 +302,9 @@ interface Options {
302
302
  */
303
303
  node?: boolean | ConfigWithOverrides<PluginRules<'n'>>;
304
304
  /**
305
- * Whether [Nuxt](https://nuxt.com) is used in the project.
305
+ * Use [@nuxt/eslint-plugin](https://eslint.nuxt.com/packages/plugin) and [nuxt-link-checker (ESLint plugin)](https://nuxtseo.com/docs/link-checker/guides/eslint) to enforce Nuxt best practices and catch broken links.
306
306
  *
307
- * Enforce best practices and the use of Nuxt-specific components over their standard counterparts. For example, `<NuxtLink>` must be used instead of `<a>`, and `<NuxtTime>` instead of `<time>`.
308
- *
309
- * **This configuration requires `configs.vue` to be enabled.**
307
+ * Enforce best practices and the use of Nuxt-specific components over their counterparts. For example, `<NuxtLink>` must be used instead of `<a>`, and `<NuxtTime>` instead of `<time>`.
310
308
  *
311
309
  * @default false // `true` if "nuxt" is detected in the dependencies when `autoDetectDeps` is enabled
312
310
  */
@@ -1,5 +1,8 @@
1
+ import { PluginRules } from "../eslintRules.mjs";
2
+ import { ConfigWithOverrides } from "../index.mjs";
1
3
  //#region src/types/options/nuxt.d.ts
2
- interface NuxtOptions {
4
+ type ConfigRules = PluginRules<'nuxt'> | PluginRules<'link-checker'>;
5
+ interface NuxtOptions extends ConfigWithOverrides<ConfigRules> {
3
6
  /**
4
7
  * Whether [@nuxt/icon](https://nuxt.com/modules/icon) is used in the project.
5
8
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shayanthenerd/eslint-config",
3
- "version": "0.28.2",
3
+ "version": "0.28.4",
4
4
  "description": "A modern, flexible ESLint configuration for enforcing best practices and maintaining a consistent coding style",
5
5
  "keywords": [
6
6
  "eslint",
@@ -49,12 +49,13 @@
49
49
  "{**/*.ts,package.json}": "pnpm lint"
50
50
  },
51
51
  "dependencies": {
52
- "@eslint-react/eslint-plugin": "5.17.1",
52
+ "@eslint-react/eslint-plugin": "5.17.3",
53
53
  "@eslint/css": "1.4.0",
54
54
  "@eslint/markdown": "8.0.3",
55
55
  "@html-eslint/eslint-plugin": "0.64.0",
56
56
  "@html-eslint/eslint-plugin-react": "0.64.0",
57
57
  "@next/eslint-plugin-next": "16.2.10",
58
+ "@nuxt/eslint-plugin": "1.16.0",
58
59
  "@stylistic/eslint-plugin": "5.10.0",
59
60
  "@vitest/eslint-plugin": "1.6.23",
60
61
  "astro-eslint-parser": "3.0.0",
@@ -63,7 +64,7 @@
63
64
  "eslint-import-resolver-typescript": "4.4.5",
64
65
  "eslint-plugin-astro": "3.0.1",
65
66
  "eslint-plugin-baseline-js": "0.7.0",
66
- "eslint-plugin-better-tailwindcss": "4.6.1",
67
+ "eslint-plugin-better-tailwindcss": "4.7.0",
67
68
  "eslint-plugin-cypress": "6.4.3",
68
69
  "eslint-plugin-import-x": "4.17.1",
69
70
  "eslint-plugin-jsx-a11y": "6.10.2",
@@ -72,16 +73,17 @@
72
73
  "eslint-plugin-perfectionist": "5.10.0",
73
74
  "eslint-plugin-playwright": "2.10.5",
74
75
  "eslint-plugin-promise": "7.3.0",
75
- "eslint-plugin-storybook": "10.5.2",
76
+ "eslint-plugin-storybook": "10.5.3",
76
77
  "eslint-plugin-unicorn": "72.0.0",
77
- "eslint-plugin-vue": "10.9.2",
78
+ "eslint-plugin-vue": "10.10.0",
78
79
  "eslint-plugin-vuejs-accessibility": "2.5.0",
79
80
  "eslint-plugin-zod": "4.8.0",
80
81
  "eslint-plugin-zod-mini": "1.5.0",
81
82
  "globals": "17.7.0",
82
83
  "local-pkg": "1.2.1",
84
+ "nuxt-link-checker": "5.1.3",
83
85
  "tailwind-csstree": "0.3.3",
84
- "typescript-eslint": "8.64.0"
86
+ "typescript-eslint": "8.65.0"
85
87
  },
86
88
  "devDependencies": {
87
89
  "@arethetypeswrong/cli": "0.18.5",
@@ -92,12 +94,12 @@
92
94
  "eslint": "10.7.0",
93
95
  "eslint-typegen": "2.3.1",
94
96
  "nano-staged": "1.0.2",
95
- "prettier": "3.9.5",
97
+ "prettier": "3.9.6",
96
98
  "publint": "0.3.21",
97
99
  "serve": "14.2.6",
98
100
  "simple-git-hooks": "2.13.1",
99
101
  "ts-morph": "28.0.0",
100
- "tsdown": "0.22.9",
102
+ "tsdown": "0.22.12",
101
103
  "typescript": "6.0.3",
102
104
  "unplugin-unused": "0.5.7"
103
105
  },
@@ -110,7 +112,7 @@
110
112
  "devEngines": {
111
113
  "packageManager": {
112
114
  "name": "pnpm",
113
- "version": "11.13.1",
115
+ "version": "11.15.1",
114
116
  "onFail": "warn"
115
117
  },
116
118
  "runtime": {
@@ -1,15 +0,0 @@
1
- import { globs } from "../helpers/globs.mjs";
2
- //#region src/configs/vueComponentNames.ts
3
- function getVueComponentNamesConfig() {
4
- return {
5
- name: "shayanthenerd/vue/multi-word-component-names",
6
- files: [globs.vueAppErrorLayoutsPages],
7
- rules: {
8
- "vue/match-component-file-name": "off",
9
- "vue/multi-word-component-names": "off",
10
- "vue/component-definition-name-casing": "off"
11
- }
12
- };
13
- }
14
- //#endregion
15
- export { getVueComponentNamesConfig };
@@ -1,14 +0,0 @@
1
- import { globs } from "../helpers/globs.mjs";
2
- //#region src/configs/vueMiddlewares.ts
3
- function getVueMiddlewaresConfig() {
4
- return {
5
- name: "shayanthenerd/vue/middlewares",
6
- files: [globs.vueMiddlewares],
7
- rules: {
8
- "consistent-return": "off",
9
- "@typescript-eslint/consistent-return": "off"
10
- }
11
- };
12
- }
13
- //#endregion
14
- export { getVueMiddlewaresConfig };
@@ -1,11 +0,0 @@
1
- import { globs } from "../helpers/globs.mjs";
2
- //#region src/configs/vueServerComponents.ts
3
- function getVueServerComponentsConfig() {
4
- return {
5
- name: "shayanthenerd/vue/server-components",
6
- files: [globs.vueServerComponents],
7
- rules: { "vue/no-multiple-template-root": "error" }
8
- };
9
- }
10
- //#endregion
11
- export { getVueServerComponentsConfig };