@shayanthenerd/eslint-config 0.5.0 → 0.6.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.
@@ -13,6 +13,7 @@ function getHTMLConfig(options) {
13
13
  name: "shayanthenerd/html",
14
14
  files: [globs.html],
15
15
  extends: [eslintPluginHTML.configs["flat/recommended"]],
16
+ language: "html/html",
16
17
  rules: getHTMLRules(options)
17
18
  };
18
19
  return mergeConfigs(htmlConfig, overrides);
@@ -3,6 +3,7 @@ import { isEnabled } from "../utils/isEnabled.js";
3
3
  import { defaultOptions } from "../utils/options/defaultOptions.js";
4
4
  import { getTypeScriptRules } from "../rules/typescript.js";
5
5
  import typescriptESLint from "typescript-eslint";
6
+ import path from "node:path";
6
7
  import { mergeConfigs } from "eslint-flat-config-utils";
7
8
 
8
9
  //#region src/configs/typescript.ts
@@ -15,10 +16,11 @@ function getTypeScriptConfig(options) {
15
16
  files: [globs.ts, vue ? globs.vue : ""],
16
17
  extends: [typescriptESLint.configs.strictTypeChecked, typescriptESLint.configs.stylisticTypeChecked],
17
18
  languageOptions: { parserOptions: {
18
- tsconfigRootDir: tsConfig ? tsConfig.rootDir : void 0,
19
+ warnOnUnsupportedTypeScriptVersion: false,
20
+ tsconfigRootDir: tsConfig ? path.resolve(tsConfig.rootDir) : void 0,
19
21
  projectService: {
20
- allowDefaultProject: allowedDefaultProjects,
21
- defaultProject: tsConfig ? tsConfig.filename : void 0
22
+ defaultProject: tsConfig ? tsConfig.filename : void 0,
23
+ allowDefaultProject: allowedDefaultProjects
22
24
  }
23
25
  } },
24
26
  rules: getTypeScriptRules(options)
@@ -4,8 +4,7 @@ import { globs } from "../utils/globs.js";
4
4
  function getVueComponentNamesConfig() {
5
5
  const vueComponentNamesConfig = {
6
6
  name: "shayanthenerd/vue/multi-word-component-names",
7
- files: [globs.vueComponentNames],
8
- ignores: [globs.vueComponentNamesIgnore],
7
+ files: [globs.vueAppErrorLayoutsPages],
9
8
  rules: {
10
9
  "vue/match-component-file-name": "off",
11
10
  "vue/multi-word-component-names": "off",
@@ -0,0 +1,14 @@
1
+ import { globs } from "../utils/globs.js";
2
+
3
+ //#region src/configs/vueServerComponents.ts
4
+ function getVueServerComponentsConfig() {
5
+ const vueServerComponentsConfig = {
6
+ name: "shayanthenerd/vue/server-components",
7
+ files: [globs.vueServerComponents],
8
+ rules: { "vue/no-multiple-template-root": "error" }
9
+ };
10
+ return vueServerComponentsConfig;
11
+ }
12
+
13
+ //#endregion
14
+ export { getVueServerComponentsConfig };
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import { getOXLintOverridesConfig } from "./configs/oxlintOverrides.js";
18
18
  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
- import { getNuxtMultiRootTemplateConfig } from "./configs/nuxtMultiRootTemplate.js";
21
+ import { getVueServerComponentsConfig } from "./configs/vueServerComponents.js";
22
22
  import { globalIgnores } from "eslint/config";
23
23
  import eslintPluginOXLint from "eslint-plugin-oxlint";
24
24
  import { config } from "typescript-eslint";
@@ -46,7 +46,7 @@ function defineConfig(options = {}, ...configs) {
46
46
  linterOptions,
47
47
  settings,
48
48
  rules
49
- }, 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) ? getNuxtMultiRootTemplateConfig() : {}, isEnabled(storybook) ? getStorybookConfig(mergedOptions) : {}, isEnabled(vitest) ? getVitestConfig(mergedOptions) : {}, isEnabled(playwright) ? getPlaywrightConfig(mergedOptions) : {}, isEnabled(cypress) ? getCypressConfig(mergedOptions) : {}, ...oxlint ? eslintPluginOXLint.buildFromOxlintConfigFile(oxlintConfigPath) : [], oxlint ? getOXLintOverridesConfig(mergedOptions) : {}, ...configs);
49
+ }, 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
50
  return eslintConfig;
51
51
  }
52
52
 
@@ -81,11 +81,13 @@
81
81
  "import/no-anonymous-default-export": "off",
82
82
 
83
83
  /*** Unicorn ***/
84
+ "unicorn/no-null": "off",
84
85
  "unicorn/filename-case": "off",
85
86
  "unicorn/prefer-set-has": "off",
86
87
  "unicorn/no-array-reduce": "off",
87
88
  "unicorn/prefer-string-raw": "off",
88
89
  "unicorn/no-array-for-each": "off",
90
+ "unicorn/prefer-global-this": "off",
89
91
  "unicorn/no-useless-undefined": "off",
90
92
  "unicorn/prefer-prototype-methods": "off",
91
93
  "unicorn/no-await-expression-member": "off",
@@ -95,6 +97,11 @@
95
97
  "jest/prefer-lowercase-title": "warn",
96
98
  "jest/require-top-level-describe": "off",
97
99
 
100
+ /*** JSDoc ***/
101
+ "jsdoc/require-param": "off",
102
+ "jsdoc/require-returns": "off",
103
+ "jsdoc/require-property": "off",
104
+
98
105
  /*** Customizable Overrides ***/
99
106
  /* These rules are customizable in the ESLint config, but OXLint doesn't respect them. */
100
107
  "eslint/max-depth": "off",
@@ -11,6 +11,7 @@ function getHTMLRules(options) {
11
11
  "@html-eslint/no-target-blank": "error",
12
12
  "@html-eslint/no-duplicate-class": "warn",
13
13
  "@html-eslint/require-button-type": "error",
14
+ "@html-eslint/no-ineffective-attrs": "error",
14
15
  "@html-eslint/no-script-style-type": "error",
15
16
  "@html-eslint/require-meta-charset": "error",
16
17
  "@html-eslint/quotes": [
@@ -37,7 +37,6 @@ function getJavaScriptRules(options) {
37
37
  "no-void": "error",
38
38
  "no-proto": "warn",
39
39
  "no-empty": "warn",
40
- "camelcase": "warn",
41
40
  "no-caller": "error",
42
41
  "no-eq-null": "warn",
43
42
  "complexity": "warn",
@@ -90,7 +89,6 @@ function getJavaScriptRules(options) {
90
89
  "prefer-destructuring": "warn",
91
90
  "no-implicit-coercion": "error",
92
91
  "no-array-constructor": "error",
93
- "no-underscore-dangle": "error",
94
92
  "prefer-object-spread": "error",
95
93
  "radix": ["error", "as-needed"],
96
94
  "curly": ["warn", "multi-line"],
@@ -121,6 +119,11 @@ function getJavaScriptRules(options) {
121
119
  "prefer-promise-reject-errors": ["error", { allowEmptyReject: true }],
122
120
  "prefer-regex-literals": ["error", { disallowRedundantWrapping: true }],
123
121
  "no-extra-boolean-cast": ["error", { enforceForInnerExpressions: true }],
122
+ "camelcase": ["warn", {
123
+ properties: "never",
124
+ ignoreImports: true,
125
+ ignoreDestructuring: true
126
+ }],
124
127
  "no-console": ["warn", { allow: [
125
128
  "info",
126
129
  "warn",
@@ -10,6 +10,7 @@ function getTailwindRules(options) {
10
10
  const tailwindRules = {
11
11
  "@stylistic/max-len": "off",
12
12
  "css/no-duplicate-imports": "off",
13
+ "vue/first-attribute-linebreak": "off",
13
14
  "better-tailwindcss/no-duplicate-classes": "error",
14
15
  "better-tailwindcss/no-deprecated-classes": "error",
15
16
  "better-tailwindcss/no-conflicting-classes": "error",
package/dist/rules/vue.js CHANGED
@@ -10,7 +10,7 @@ function getVueRules(options) {
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
11
  const nuxtImage = isEnabled(nuxt) ? nuxt.image : void 0;
12
12
  const nuxtUI = isEnabled(nuxt) ? nuxt.ui : void 0;
13
- const nuxtUIPrefix = isEnabled(nuxt) && isEnabled(nuxt.ui) ? nuxt.ui.prefix : void 0;
13
+ const nuxtUIPrefix = isEnabled(nuxt) && isEnabled(nuxt.ui) ? nuxt.ui.prefix : defaultOptions.configs.nuxt.ui.prefix;
14
14
  const isScriptLangTS = blockLang.script === "ts";
15
15
  const isStyleLangImplicit = blockLang.style === "implicit";
16
16
  const vueRules = {
@@ -18,7 +18,9 @@ function getVueRules(options) {
18
18
  "no-useless-assignment": "off",
19
19
  "import-x/default": "off",
20
20
  "import-x/no-unresolved": "off",
21
+ "vue/no-multiple-template-root": "off",
21
22
  "vue/comment-directive": ["error", { reportUnusedDisableDirectives: true }],
23
+ "vue/require-default-prop": "off",
22
24
  "vue/html-closing-bracket-newline": "warn",
23
25
  "vue/singleline-html-element-content-newline": "off",
24
26
  "vue/html-indent": ["warn", useTabs ? "tab" : indent],
@@ -57,6 +59,7 @@ function getVueRules(options) {
57
59
  "vue/custom-event-name-casing": "warn",
58
60
  "vue/no-use-v-else-with-v-for": "error",
59
61
  "vue/no-empty-component-block": "error",
62
+ "vue/no-negated-v-if-condition": "warn",
60
63
  "vue/no-import-compiler-macros": "error",
61
64
  "vue/require-typed-object-prop": "error",
62
65
  "vue/require-macro-variable-name": "warn",
@@ -130,18 +133,28 @@ function getVueRules(options) {
130
133
  "RouterLink",
131
134
  "NuxtLink"
132
135
  ] : "",
133
- message: nuxtUI && nuxtUIPrefix ? `Use <${nuxtUIPrefix}Link>.` : void 0
136
+ message: nuxtUI ? `Use \`<${nuxtUIPrefix}Link>\`.` : void 0
134
137
  },
135
138
  {
136
139
  element: ["a", nuxt ? "RouterLink" : ""],
137
- message: `Use <${nuxt ? "NuxtLink" : "RouterLink"}>.`
140
+ message: `Use \`<${nuxt ? "NuxtLink" : "RouterLink"}>\`.`
138
141
  },
139
- ...nuxtUI && nuxtUIPrefix ? getRestrictedVueElements(nuxtUIPrefix) : [],
142
+ ...nuxtUI ? getRestrictedVueElements(nuxtUIPrefix) : [],
140
143
  ...userRestrictedElements
141
144
  ],
142
145
  "vue/no-restricted-static-attribute": [
143
146
  "error",
144
- ...nuxtUI && nuxtUIPrefix ? getRestrictedVueInputs(nuxtUIPrefix) : [],
147
+ ...nuxtUI ? getRestrictedVueInputs(nuxtUIPrefix) : [],
148
+ nuxtUI ? {
149
+ key: "href",
150
+ element: `${nuxtUIPrefix}Link`,
151
+ message: "Use `v-bind:to=\"\"`."
152
+ } : { key: "" },
153
+ nuxtUI ? {
154
+ key: "href",
155
+ element: `${nuxtUIPrefix}Button`,
156
+ message: "Use `v-bind:to=\"\"`."
157
+ } : { key: " " },
145
158
  ...userRestrictedStaticAttributes
146
159
  ],
147
160
  "vue/no-undef-components": ["error", { ignorePatterns: [
@@ -162,7 +175,7 @@ function getVueRules(options) {
162
175
  "warn",
163
176
  componentNameCaseInTemplate,
164
177
  {
165
- ignores: ["*.*"],
178
+ ignores: ["/^\\w+(\\.\\w+)+$/"],
166
179
  registeredComponentsOnly: false
167
180
  }
168
181
  ]
@@ -176,8 +176,6 @@ interface VueOptions extends ConfigWithOverrides {
176
176
  *
177
177
  * When NuxtUI or NuxtImage are enabled, certain HTML elements (e.g., `<img>`, `<a>`, `<form>`, `<input>`) are disallowed in favor of their alternative components.
178
178
  *
179
- * New items extend the defaults, they don't override it.
180
- *
181
179
  * @default []
182
180
  *
183
181
  * @see [vue/no-restricted-html-elements](https://eslint.vuejs.org/rules/no-restricted-html-elements)
@@ -6,6 +6,8 @@ interface VueAccessibilityOptions {
6
6
  /**
7
7
  * Names of components that render an `<a>` element.
8
8
  *
9
+ * New items extend the defaults, they don't override it.
10
+ *
9
11
  * @default ['RouterLink', 'NuxtLink', 'ULink']
10
12
  *
11
13
  * @see [vuejs-accessibility/anchor-has-content: `components` option](https://vue-a11y.github.io/eslint-plugin-vuejs-accessibility/rules/anchor-has-content#%F0%9F%94%A7-options)
@@ -15,6 +17,8 @@ interface VueAccessibilityOptions {
15
17
  /**
16
18
  * Names of components that render an `<img>` element.
17
19
  *
20
+ * New items extend the defaults, they don't override it.
21
+ *
18
22
  * @default ['NuxtImg']
19
23
  *
20
24
  * @see [vuejs-accessibility/alt-text: `img` option](https://vue-a11y.github.io/eslint-plugin-vuejs-accessibility/rules/alt-text#%F0%9F%94%A7-options)
@@ -24,7 +28,9 @@ interface VueAccessibilityOptions {
24
28
  /**
25
29
  * Names of components that should be considered accessible child elements.
26
30
  *
27
- * @default ['img', 'picture', 'NuxtImg', 'NuxtPicture']
31
+ * New items extend the defaults, they don't override it.
32
+ *
33
+ * @default ['img', 'picture', 'NuxtImg', 'NuxtPicture', 'UBadge']
28
34
  *
29
35
  * @see [vuejs-accessibility/anchor-has-content: `accessibleChildren` option](https://vue-a11y.github.io/eslint-plugin-vuejs-accessibility/rules/anchor-has-content#%F0%9F%94%A7-options)
30
36
  */
@@ -43,7 +43,7 @@ declare module 'eslint-flat-config-utils' {
43
43
  'shayanthenerd/vue__vuejs-accessibility:setup:with-files-rules-and-parser'?: true;
44
44
  'shayanthenerd/vue'?: true;
45
45
  'shayanthenerd/vue/multi-word-component-names'?: true;
46
- 'shayanthenerd/nuxt/allow-multiple-template-root'?: true;
46
+ 'shayanthenerd/vue/server-components'?: true;
47
47
  'shayanthenerd/storybook__storybook:recommended:setup'?: true;
48
48
  'shayanthenerd/storybook__storybook:recommended:stories-rules'?: true;
49
49
  'shayanthenerd/storybook__storybook:recommended:main-rules'?: true;
@@ -72,7 +72,7 @@ interface ESLintSchema {
72
72
  */
73
73
  '@html-eslint/element-newline'?: Linter.RuleEntry<HtmlEslintElementNewline>;
74
74
  /**
75
- * Enforce consistent naming id attributes
75
+ * Enforce consistent naming of id attributes
76
76
  * @see https://html-eslint.org/docs/rules/id-naming-convention
77
77
  */
78
78
  '@html-eslint/id-naming-convention'?: Linter.RuleEntry<HtmlEslintIdNamingConvention>;
@@ -81,27 +81,27 @@ interface ESLintSchema {
81
81
  */
82
82
  '@html-eslint/indent'?: Linter.RuleEntry<HtmlEslintIndent>;
83
83
  /**
84
- * Enforce to use lowercase for tag and attribute names.
84
+ * Enforce use of lowercase for tag and attribute names.
85
85
  * @see https://html-eslint.org/docs/rules/lowercase
86
86
  */
87
87
  '@html-eslint/lowercase'?: Linter.RuleEntry<[]>;
88
88
  /**
89
- * Enforce element maximum depth
89
+ * Enforce maximum element depth
90
90
  * @see https://html-eslint.org/docs/rules/max-element-depth
91
91
  */
92
92
  '@html-eslint/max-element-depth'?: Linter.RuleEntry<HtmlEslintMaxElementDepth>;
93
93
  /**
94
- * Disallow to use of abstract roles
94
+ * Disallow use of abstract roles
95
95
  * @see https://html-eslint.org/docs/rules/no-abstract-roles
96
96
  */
97
97
  '@html-eslint/no-abstract-roles'?: Linter.RuleEntry<[]>;
98
98
  /**
99
- * Disallow to use of accesskey attribute
99
+ * Disallow use of accesskey attribute
100
100
  * @see https://html-eslint.org/docs/rules/no-accesskey-attrs
101
101
  */
102
102
  '@html-eslint/no-accesskey-attrs'?: Linter.RuleEntry<[]>;
103
103
  /**
104
- * Disallow to use aria-hidden attributes on the `body` element.
104
+ * Disallow use of aria-hidden attributes on the `body` element.
105
105
  * @see https://html-eslint.org/docs/rules/no-aria-hidden-body
106
106
  */
107
107
  '@html-eslint/no-aria-hidden-body'?: Linter.RuleEntry<[]>;
@@ -111,17 +111,17 @@ interface ESLintSchema {
111
111
  */
112
112
  '@html-eslint/no-aria-hidden-on-focusable'?: Linter.RuleEntry<[]>;
113
113
  /**
114
- * Disallow to use duplicate attributes
114
+ * Disallow duplicate attributes
115
115
  * @see https://html-eslint.org/docs/rules/no-duplicate-attrs
116
116
  */
117
117
  '@html-eslint/no-duplicate-attrs'?: Linter.RuleEntry<[]>;
118
118
  /**
119
- * Disallow to use duplicate class
119
+ * Disallow duplicate class names
120
120
  * @see https://html-eslint.org/docs/rules/no-duplicate-class
121
121
  */
122
122
  '@html-eslint/no-duplicate-class'?: Linter.RuleEntry<[]>;
123
123
  /**
124
- * Disallow to use duplicate id
124
+ * Disallow duplicate id attributes
125
125
  * @see https://html-eslint.org/docs/rules/no-duplicate-id
126
126
  */
127
127
  '@html-eslint/no-duplicate-id'?: Linter.RuleEntry<[]>;
@@ -136,7 +136,7 @@ interface ESLintSchema {
136
136
  */
137
137
  '@html-eslint/no-empty-headings'?: Linter.RuleEntry<[]>;
138
138
  /**
139
- * Disallow an extra spacing around attributes
139
+ * Disallow extra spacing around attributes
140
140
  * @see https://html-eslint.org/docs/rules/no-extra-spacing-attrs
141
141
  */
142
142
  '@html-eslint/no-extra-spacing-attrs'?: Linter.RuleEntry<HtmlEslintNoExtraSpacingAttrs>;
@@ -150,6 +150,10 @@ interface ESLintSchema {
150
150
  * @see https://html-eslint.org/docs/rules/no-heading-inside-button
151
151
  */
152
152
  '@html-eslint/no-heading-inside-button'?: Linter.RuleEntry<[]>;
153
+ /**
154
+ * Disallow HTML attributes that have no effect in their context
155
+ */
156
+ '@html-eslint/no-ineffective-attrs'?: Linter.RuleEntry<[]>;
153
157
  /**
154
158
  * Disallow using inline style
155
159
  * @see https://html-eslint.org/docs/rules/no-inline-styles
@@ -186,7 +190,7 @@ interface ESLintSchema {
186
190
  */
187
191
  '@html-eslint/no-non-scalable-viewport'?: Linter.RuleEntry<[]>;
188
192
  /**
189
- * Disallow to use obsolete elements in HTML5
193
+ * Disallow use of obsolete elements in HTML5
190
194
  * @see https://html-eslint.org/docs/rules/no-obsolete-tags
191
195
  */
192
196
  '@html-eslint/no-obsolete-tags'?: Linter.RuleEntry<[]>;
@@ -241,7 +245,7 @@ interface ESLintSchema {
241
245
  */
242
246
  '@html-eslint/require-attrs'?: Linter.RuleEntry<HtmlEslintRequireAttrs>;
243
247
  /**
244
- * Require use of button element with a valid type attribute.
248
+ * Require use of the button element with a valid type attribute.
245
249
  * @see https://html-eslint.org/docs/rules/require-button-type
246
250
  */
247
251
  '@html-eslint/require-button-type'?: Linter.RuleEntry<[]>;
@@ -251,7 +255,7 @@ interface ESLintSchema {
251
255
  */
252
256
  '@html-eslint/require-closing-tags'?: Linter.RuleEntry<HtmlEslintRequireClosingTags>;
253
257
  /**
254
- * Require `<!DOCTYPE HTML>` in html,
258
+ * Require `<!DOCTYPE HTML>` in HTML
255
259
  * @see https://html-eslint.org/docs/rules/require-doctype
256
260
  */
257
261
  '@html-eslint/require-doctype'?: Linter.RuleEntry<[]>;
@@ -271,7 +275,7 @@ interface ESLintSchema {
271
275
  */
272
276
  '@html-eslint/require-frame-title'?: Linter.RuleEntry<[]>;
273
277
  /**
274
- * Require `alt` attribute at `<img>` tag
278
+ * Require `alt` attribute on `<img>` tag
275
279
  * @see https://html-eslint.org/docs/rules/require-img-alt
276
280
  */
277
281
  '@html-eslint/require-img-alt'?: Linter.RuleEntry<HtmlEslintRequireImgAlt>;
@@ -281,17 +285,17 @@ interface ESLintSchema {
281
285
  */
282
286
  '@html-eslint/require-input-label'?: Linter.RuleEntry<[]>;
283
287
  /**
284
- * Require `lang` attribute at `<html>` tag
288
+ * Require `lang` attribute on `<html>` tag
285
289
  * @see https://html-eslint.org/docs/rules/require-lang
286
290
  */
287
291
  '@html-eslint/require-lang'?: Linter.RuleEntry<[]>;
288
292
  /**
289
- * Enforce `<li>` to be in `<ul>`, `<ol>` or `<menu>`.
293
+ * Enforce `<li>` to be in `<ul>`, `<ol>` or `<menu>`.
290
294
  * @see https://html-eslint.org/docs/rules/require-li-container
291
295
  */
292
296
  '@html-eslint/require-li-container'?: Linter.RuleEntry<[]>;
293
297
  /**
294
- * Enforce to use `<meta charset="...">` in `<head>`
298
+ * Enforce use of `<meta charset="...">` in `<head>`
295
299
  * @see https://html-eslint.org/docs/rules/require-meta-charset
296
300
  */
297
301
  '@html-eslint/require-meta-charset'?: Linter.RuleEntry<[]>;
@@ -301,22 +305,22 @@ interface ESLintSchema {
301
305
  */
302
306
  '@html-eslint/require-meta-description'?: Linter.RuleEntry<[]>;
303
307
  /**
304
- * Enforce to use `<meta name="viewport">` in `<head>`
308
+ * Enforce use of `<meta name="viewport">` in `<head>`
305
309
  * @see https://html-eslint.org/docs/rules/require-meta-viewport
306
310
  */
307
311
  '@html-eslint/require-meta-viewport'?: Linter.RuleEntry<[]>;
308
312
  /**
309
- * Enforce to use specified meta tags for open graph protocol.
313
+ * Enforce use of specified meta tags for open graph protocol.
310
314
  * @see https://html-eslint.org/docs/rules/require-open-graph-protocol
311
315
  */
312
316
  '@html-eslint/require-open-graph-protocol'?: Linter.RuleEntry<HtmlEslintRequireOpenGraphProtocol>;
313
317
  /**
314
- * Require `<title><title/>` in the `<head><head/>`
318
+ * Require `<title>` in the `<head>`
315
319
  * @see https://html-eslint.org/docs/rules/require-title
316
320
  */
317
321
  '@html-eslint/require-title'?: Linter.RuleEntry<[]>;
318
322
  /**
319
- * Enforce attributes alphabetical sorting
323
+ * Enforce priority and alphabetical sorting of attributes
320
324
  * @see https://html-eslint.org/docs/rules/sort-attrs
321
325
  */
322
326
  '@html-eslint/sort-attrs'?: Linter.RuleEntry<HtmlEslintSortAttrs>;
@@ -4741,6 +4745,16 @@ interface ESLintSchema {
4741
4745
  * @see https://eslint.vuejs.org/rules/no-mutating-props.html
4742
4746
  */
4743
4747
  'vue/no-mutating-props'?: Linter.RuleEntry<VueNoMutatingProps>;
4748
+ /**
4749
+ * Disallow negated conditions in `<template>`
4750
+ * @see https://eslint.vuejs.org/rules/no-negated-condition.html
4751
+ */
4752
+ 'vue/no-negated-condition'?: Linter.RuleEntry<[]>;
4753
+ /**
4754
+ * disallow negated conditions in v-if/v-else
4755
+ * @see https://eslint.vuejs.org/rules/no-negated-v-if-condition.html
4756
+ */
4757
+ 'vue/no-negated-v-if-condition'?: Linter.RuleEntry<[]>;
4744
4758
  /**
4745
4759
  * disallow parsing errors in `<template>`
4746
4760
  * @see https://eslint.vuejs.org/rules/no-parsing-error.html
@@ -5616,6 +5630,7 @@ type HtmlEslintRequireAttrs = {
5616
5630
  tag: string;
5617
5631
  attr: string;
5618
5632
  value?: string;
5633
+ message?: string;
5619
5634
  }[];
5620
5635
  // ----- @html-eslint/require-closing-tags -----
5621
5636
  type HtmlEslintRequireClosingTags = [] | [{
@@ -5635,7 +5650,9 @@ type HtmlEslintRequireImgAlt = [] | [{
5635
5650
  type HtmlEslintRequireOpenGraphProtocol = [] | [string[]];
5636
5651
  // ----- @html-eslint/sort-attrs -----
5637
5652
  type HtmlEslintSortAttrs = [] | [{
5638
- priority?: string[];
5653
+ priority?: (string | {
5654
+ pattern: string;
5655
+ })[];
5639
5656
  }];
5640
5657
  // ----- @html-eslint/use-baseline -----
5641
5658
  type HtmlEslintUseBaseline = [] | [{
@@ -9602,10 +9619,17 @@ type NoRestrictedExports = [] | [({
9602
9619
  };
9603
9620
  })];
9604
9621
  // ----- no-restricted-globals -----
9605
- type NoRestrictedGlobals = (string | {
9622
+ type NoRestrictedGlobals = ((string | {
9606
9623
  name: string;
9607
9624
  message?: string;
9608
- })[];
9625
+ })[] | [] | [{
9626
+ globals: (string | {
9627
+ name: string;
9628
+ message?: string;
9629
+ })[];
9630
+ checkGlobalObject?: boolean;
9631
+ globalObjects?: string[];
9632
+ }]);
9609
9633
  // ----- no-restricted-imports -----
9610
9634
  type NoRestrictedImports = ((string | {
9611
9635
  name: string;
@@ -9833,6 +9857,8 @@ type OneVar = [] | [(("always" | "never" | "consecutive") | {
9833
9857
  var?: ("always" | "never" | "consecutive");
9834
9858
  let?: ("always" | "never" | "consecutive");
9835
9859
  const?: ("always" | "never" | "consecutive");
9860
+ using?: ("always" | "never" | "consecutive");
9861
+ awaitUsing?: ("always" | "never" | "consecutive");
9836
9862
  } | {
9837
9863
  initialized?: ("always" | "never" | "consecutive");
9838
9864
  uninitialized?: ("always" | "never" | "consecutive");
@@ -11643,11 +11669,9 @@ type PlaywrightValidExpect = [] | [{
11643
11669
  type PlaywrightValidTestTags = [] | [{
11644
11670
  allowedTags?: (string | {
11645
11671
  source?: string;
11646
- [k: string]: unknown | undefined;
11647
11672
  })[];
11648
11673
  disallowedTags?: (string | {
11649
11674
  source?: string;
11650
- [k: string]: unknown | undefined;
11651
11675
  })[];
11652
11676
  }];
11653
11677
  // ----- playwright/valid-title -----
@@ -12712,6 +12736,7 @@ type VueNoDeprecatedRouterLinkTagProp = [] | [{
12712
12736
  // ----- vue/no-deprecated-slot-attribute -----
12713
12737
  type VueNoDeprecatedSlotAttribute = [] | [{
12714
12738
  ignore?: string[];
12739
+ ignoreParents?: string[];
12715
12740
  }];
12716
12741
  // ----- vue/no-dupe-keys -----
12717
12742
  type VueNoDupeKeys = [] | [{
@@ -18,9 +18,8 @@ const globs = {
18
18
  src: `**/*.${srcExtensions}`,
19
19
  restrictedExports: `**/{${restrictedExportsFolders.join(",")}}/**/*.${srcExtensions}`,
20
20
  vue: `**/*.${vueExtensions}`,
21
- vueMultiRootTemplate: `**/pages/**/(_|-)components/**/*.${vueExtensions}`,
22
- vueComponentNames: `**/{{app,error},{layouts,pages}/**/*}.${vueExtensions}`,
23
- vueComponentNamesIgnore: `**/{layouts,pages}/**/(_|-)components/**/*.${vueExtensions}`,
21
+ vueServerComponents: `**/*.server.${vueExtensions}`,
22
+ vueAppErrorLayoutsPages: `**/{{app,error},{layouts,pages}/**/*}.${vueExtensions}`,
24
23
  storybook: `**/*.(story|stories).${srcExtensions}`,
25
24
  test: `**/{__tests__/*,*.{test,spec,cy,bench?(mark)}.${srcExtensions}`
26
25
  };
@@ -13,6 +13,7 @@ function isPackageDetected(packageName, options = defaultOptions) {
13
13
  if (!autoDetectDeps) return false;
14
14
  const isPackageInstalled = isPackageExists(packageName, { paths: [path.resolve(packageDir)] });
15
15
  if (isPackageInstalled) detectedPackages.push(packageName);
16
+ detectedPackages.sort();
16
17
  return isPackageInstalled;
17
18
  }
18
19
 
@@ -92,7 +92,8 @@ const defaultOptions = {
92
92
  "img",
93
93
  "picture",
94
94
  "NuxtImg",
95
- "NuxtPicture"
95
+ "NuxtPicture",
96
+ "UBadge"
96
97
  ]
97
98
  },
98
99
  blocksOrder: [
@@ -122,8 +123,8 @@ const defaultOptions = {
122
123
  "LIST_RENDERING",
123
124
  "UNIQUE",
124
125
  "GLOBAL",
125
- "TWO_WAY_BINDING",
126
126
  "SLOT",
127
+ "TWO_WAY_BINDING",
127
128
  "CONTENT",
128
129
  "OTHER_DIRECTIVES",
129
130
  "EVENTS",
@@ -5,6 +5,17 @@ import { createDefu } from "defu";
5
5
 
6
6
  //#region src/utils/options/mergeWithDefaults.ts
7
7
  const mergeOptions = createDefu((object, key, value) => {
8
+ const stringKey = key.toString();
9
+ const uniqueArrayOptions = [
10
+ "allowedRelativeFontUnits",
11
+ "macrosOrder",
12
+ "blocksOrder",
13
+ "attributesOrder"
14
+ ];
15
+ if (uniqueArrayOptions.includes(stringKey)) {
16
+ object[key] = value;
17
+ return true;
18
+ }
8
19
  const isValueTrue = value === true;
9
20
  const isDefaultValueFalse = object[key] === false;
10
21
  const isValueEmptyString = isEmptyString(value);
@@ -18,7 +18,7 @@ function getRestrictedVueElements(prefix) {
18
18
  const restrictedElements = [];
19
19
  for (const [element, component] of alternativeComponentPairs) restrictedElements.push({
20
20
  element,
21
- message: `Use <${prefix}${component}>.`
21
+ message: `Use \`<${prefix}${component}>\`.`
22
22
  });
23
23
  return restrictedElements;
24
24
  }
@@ -14,7 +14,7 @@ function getRestrictedVueInputs(prefix) {
14
14
  element: "input",
15
15
  key: "type",
16
16
  value: input,
17
- message: `Use <${prefix}${component}>.`
17
+ message: `Use \`<${prefix}${component}>\`.`
18
18
  });
19
19
  return restrictedInputs;
20
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shayanthenerd/eslint-config",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "license": "MIT",
5
5
  "description": "A modern, flexible ESLint configuration for enforcing best practices and maintaining a consistent coding style",
6
6
  "keywords": [
@@ -52,11 +52,11 @@
52
52
  "#configs/*": "./src/configs/*"
53
53
  },
54
54
  "type": "module",
55
- "packageManager": "bun@1.2.19",
55
+ "packageManager": "bun@1.2.21",
56
56
  "scripts": {
57
- "prepare": "bun set:gitmessage && bunx simple-git-hooks && bun generate:types",
57
+ "prepare": "bun git:gitmessage && bunx simple-git-hooks && bun generate:types",
58
58
  "prepublishOnly": "bun build:package",
59
- "set:gitmessage": "git config --local commit.template \".gitmessage\"",
59
+ "git:gitmessage": "git config --local commit.template \".gitmessage\"",
60
60
  "inspect": "bunx @eslint/config-inspector",
61
61
  "build:package": "tsdown --no-report",
62
62
  "build:inspector": "bunx @eslint/config-inspector build --config=./scripts/defaultESLintConfigReference.ts",
@@ -75,48 +75,48 @@
75
75
  "pre-commit": "./node_modules/.bin/nano-staged"
76
76
  },
77
77
  "nano-staged": {
78
- "**/*.{json,jsonc,yaml,yml,lock}": "prettier --write --ignore-unknown --cache",
79
- "**/*.{js,ts}": [
80
- "oxlint --fix",
81
- "eslint --fix --cache --cache-location=./node_modules/.cache/.eslintcache"
82
- ]
78
+ "**/*.{js,ts}": "bun lint",
79
+ "**/*.{json,jsonc,yaml,yml,lock}": "bun format"
83
80
  },
84
81
  "dependencies": {
85
- "@eslint/compat": "1.3.1",
82
+ "@eslint/compat": "1.3.2",
86
83
  "@eslint/css": "0.10.0",
87
- "@eslint/js": "9.32.0",
88
- "@html-eslint/eslint-plugin": "0.43.1",
89
- "@stylistic/eslint-plugin": "5.2.2",
84
+ "@eslint/js": "9.34.0",
85
+ "@html-eslint/eslint-plugin": "0.46.1",
86
+ "@stylistic/eslint-plugin": "5.2.3",
90
87
  "@vitest/eslint-plugin": "1.3.4",
91
88
  "defu": "6.1.4",
92
- "eslint": "9.32.0",
89
+ "eslint": "9.34.0",
93
90
  "eslint-flat-config-utils": "2.1.1",
94
91
  "eslint-import-resolver-typescript": "4.4.4",
95
- "eslint-plugin-better-tailwindcss": "3.7.2",
96
- "eslint-plugin-cypress": "5.1.0",
92
+ "eslint-plugin-better-tailwindcss": "3.7.5",
93
+ "eslint-plugin-cypress": "5.1.1",
97
94
  "eslint-plugin-import-x": "4.16.1",
98
- "eslint-plugin-oxlint": "1.9.0",
95
+ "eslint-plugin-oxlint": "1.13.0",
99
96
  "eslint-plugin-perfectionist": "4.15.0",
100
- "eslint-plugin-playwright": "2.2.1",
101
- "eslint-plugin-storybook": "9.0.18",
102
- "eslint-plugin-unused-imports": "4.1.4",
103
- "eslint-plugin-vue": "10.3.0",
97
+ "eslint-plugin-playwright": "2.2.2",
98
+ "eslint-plugin-storybook": "9.1.3",
99
+ "eslint-plugin-unused-imports": "4.2.0",
100
+ "eslint-plugin-vue": "10.4.0",
104
101
  "eslint-plugin-vuejs-accessibility": "2.4.1",
105
102
  "globals": "16.3.0",
106
- "local-pkg": "1.1.1",
107
- "oxlint": "1.9.0",
108
- "tailwind-csstree": "0.1.2",
109
- "typescript-eslint": "8.38.0"
103
+ "local-pkg": "1.1.2",
104
+ "oxlint": "1.13.0",
105
+ "tailwind-csstree": "0.1.3",
106
+ "typescript-eslint": "8.41.0"
110
107
  },
111
108
  "devDependencies": {
112
- "@types/node": "24.1.0",
109
+ "@types/node": "24.3.0",
113
110
  "eslint-typegen": "2.3.0",
114
- "lint-staged": "16.1.2",
115
111
  "nano-staged": "0.8.0",
116
112
  "prettier": "3.6.2",
117
113
  "publint": "0.3.12",
118
- "tsdown": "0.13.0",
119
- "typescript": "5.8.3",
120
- "unplugin-unused": "0.5.1"
121
- }
114
+ "tsdown": "0.14.2",
115
+ "typescript": "5.9.2",
116
+ "unplugin-unused": "0.5.2"
117
+ },
118
+ "trustedDependencies": [
119
+ "esbuild",
120
+ "unrs-resolver"
121
+ ]
122
122
  }
@@ -1,14 +0,0 @@
1
- import { globs } from "../utils/globs.js";
2
-
3
- //#region src/configs/nuxtMultiRootTemplate.ts
4
- function getNuxtMultiRootTemplateConfig() {
5
- const nuxtMultiRootTemplateConfig = {
6
- name: "shayanthenerd/nuxt/allow-multiple-template-root",
7
- files: [globs.vueMultiRootTemplate],
8
- rules: { "vue/no-multiple-template-root": "off" }
9
- };
10
- return nuxtMultiRootTemplateConfig;
11
- }
12
-
13
- //#endregion
14
- export { getNuxtMultiRootTemplateConfig };