Repository: vuejs/eslint-plugin-vue
Pull request #2793 (2025-07-13 15:24:55)

test(no-deprecated-slot-attribute): make tests more strict
Continuation of https://github.com/vuejs/eslint-plugin-vue/pull/2773#discussion_r2176359714

- https://github.com/vuejs/eslint-plugin-vue/pull/2773#discussion_r2176359714

> It might be helpful to include more detailed error information, such as `line`, `column`, `endLine`, and `endColumn`...

---

This PR converts all error assertions for `no-deprecated-slot-attribute` to include both error message and full location checks.

---

Is this kind of PR appreciated? If not, we can close it. If yes, I will create one for each rule one at a time.


Patch:
diff --git a/.changeset/eight-camels-refuse.md b/.changeset/eight-camels-refuse.md
new file mode 100644
index 00000000..527b123e
--- /dev/null
+++ b/.changeset/eight-camels-refuse.md
@@ -0,0 +1,5 @@
+---
+"eslint-plugin-vue": patch
+---
+
+Resolved TypeScript compatibility issues introduced by eslint-typegen
diff --git a/.changeset/true-pumas-open.md b/.changeset/true-pumas-open.md
new file mode 100644
index 00000000..7a49b0f2
--- /dev/null
+++ b/.changeset/true-pumas-open.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-vue': minor
+---
+
+Added new [`vue/no-negated-condition`](https://eslint.vuejs.org/rules/no-negated-condition.html) rule
diff --git a/docs/rules/index.md b/docs/rules/index.md
index 6423ef36..34462fba 100644
--- a/docs/rules/index.md
+++ b/docs/rules/index.md
@@ -327,6 +327,7 @@ The following rules extend the rules provided by ESLint itself and apply them to
 | [vue/no-implicit-coercion] | Disallow shorthand type conversions in `<template>` | :wrench::bulb: | :hammer: |
 | [vue/no-irregular-whitespace] | disallow irregular whitespace in `.vue` files |  | :warning: |
 | [vue/no-loss-of-precision] | Disallow literal numbers that lose precision in `<template>` |  | :warning: |
+| [vue/no-negated-condition] | Disallow negated conditions in `<template>` |  | :hammer: |
 | [vue/no-restricted-syntax] | Disallow specified syntax in `<template>` |  | :hammer: |
 | [vue/no-sparse-arrays] | Disallow sparse arrays in `<template>` |  | :warning: |
 | [vue/no-useless-concat] | Disallow unnecessary concatenation of literals or template literals in `<template>` |  | :hammer: |
@@ -482,6 +483,7 @@ The following rules extend the rules provided by ESLint itself and apply them to
 [vue/no-multiple-slot-args]: ./no-multiple-slot-args.md
 [vue/no-multiple-template-root]: ./no-multiple-template-root.md
 [vue/no-mutating-props]: ./no-mutating-props.md
+[vue/no-negated-condition]: ./no-negated-condition.md
 [vue/no-parsing-error]: ./no-parsing-error.md
 [vue/no-potential-component-option-typo]: ./no-potential-component-option-typo.md
 [vue/no-ref-as-operand]: ./no-ref-as-operand.md
diff --git a/docs/rules/no-negated-condition.md b/docs/rules/no-negated-condition.md
new file mode 100644
index 00000000..e389172a
--- /dev/null
+++ b/docs/rules/no-negated-condition.md
@@ -0,0 +1,33 @@
+---
+pageClass: rule-details
+sidebarDepth: 0
+title: vue/no-negated-condition
+description: Disallow negated conditions in `<template>`
+---
+
+# vue/no-negated-condition
+
+> Disallow negated conditions in `<template>`
+
+- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> _**This rule has not been released yet.**_ </badge>
+
+## :book: Rule Details
+
+This rule is the same rule as core [no-negated-condition] rule but it applies to the expressions in `<template>`.
+
+## :couple: Related Rules
+
+- [unicorn/no-negated-condition](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-negated-condition.md)
+
+## :books: Further Reading
+
+- [no-negated-condition]
+
+[no-negated-condition]: https://eslint.org/docs/rules/no-negated-condition
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-negated-condition.js)
+- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-negated-condition.js)
+
+<sup>Taken with ❤️ [from ESLint core](https://eslint.org/docs/latest/rules/no-negated-condition)</sup>
diff --git a/lib/index.js b/lib/index.js
index e511536f..bfc35b11 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -141,6 +141,7 @@ const plugin = {
     'no-multiple-slot-args': require('./rules/no-multiple-slot-args'),
     'no-multiple-template-root': require('./rules/no-multiple-template-root'),
     'no-mutating-props': require('./rules/no-mutating-props'),
+    'no-negated-condition': require('./rules/no-negated-condition'),
     'no-parsing-error': require('./rules/no-parsing-error'),
     'no-potential-component-option-typo': require('./rules/no-potential-component-option-typo'),
     'no-ref-as-operand': require('./rules/no-ref-as-operand'),
diff --git a/lib/rules/no-negated-condition.js b/lib/rules/no-negated-condition.js
new file mode 100644
index 00000000..22a9a6fc
--- /dev/null
+++ b/lib/rules/no-negated-condition.js
@@ -0,0 +1,12 @@
+/**
+ * @author Wayne Zhang
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const { wrapCoreRule } = require('../utils')
+
+// eslint-disable-next-line internal/no-invalid-meta
+module.exports = wrapCoreRule('no-negated-condition', {
+  applyDocument: true
+})
diff --git a/tools/generate-typegen.mjs b/tools/generate-typegen.mjs
index 5bcb325a..1f3b4a12 100644
--- a/tools/generate-typegen.mjs
+++ b/tools/generate-typegen.mjs
@@ -2,8 +2,13 @@ import fs from 'node:fs/promises'
 import { pluginsToRulesDTS } from 'eslint-typegen/core'
 import plugin from '../lib/index.js'
 
-const dts = await pluginsToRulesDTS({
-  vue: plugin
-})
+const dts = await pluginsToRulesDTS(
+  {
+    vue: plugin
+  },
+  {
+    includeAugmentation: false
+  }
+)
 
 await fs.writeFile('lib/eslint-typegen.d.ts', dts)


Test patch:
diff --git a/tests/lib/rules/no-deprecated-slot-attribute.js b/tests/lib/rules/no-deprecated-slot-attribute.js
index b072deb2..01b8f31d 100644
--- a/tests/lib/rules/no-deprecated-slot-attribute.js
+++ b/tests/lib/rules/no-deprecated-slot-attribute.js
@@ -110,7 +110,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
         }
       ]
     },
@@ -130,7 +133,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
         }
       ]
     },
@@ -150,7 +156,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
         }
       ]
     },
@@ -170,7 +179,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
         }
       ]
     },
@@ -190,7 +202,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
         }
       ]
     },
@@ -209,23 +224,38 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
         },
         {
           message: '`slot` attributes are deprecated.',
-          line: 5
+          line: 5,
+          column: 21,
+          endLine: 5,
+          endColumn: 25
         },
         {
           message: '`slot` attributes are deprecated.',
-          line: 6
+          line: 6,
+          column: 21,
+          endLine: 6,
+          endColumn: 25
         },
         {
           message: '`slot` attributes are deprecated.',
-          line: 7
+          line: 7,
+          column: 21,
+          endLine: 7,
+          endColumn: 25
         },
         {
           message: '`slot` attributes are deprecated.',
-          line: 8
+          line: 8,
+          column: 21,
+          endLine: 8,
+          endColumn: 25
         }
       ]
     },
@@ -245,7 +275,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 32
         }
       ]
     },
@@ -260,7 +293,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 26
         }
       ]
     },
@@ -280,7 +316,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 26
         }
       ]
     },
@@ -295,7 +334,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 26
         }
       ]
     },
@@ -310,7 +352,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 26
         }
       ]
     },
@@ -325,7 +370,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 26
         }
       ]
     },
@@ -340,7 +388,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 26
         }
       ]
     },
@@ -360,7 +411,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 26
         }
       ]
     },
@@ -380,7 +434,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 14,
+          endLine: 4,
+          endColumn: 18
         }
       ]
     },
@@ -400,7 +457,10 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 14,
+          endLine: 4,
+          endColumn: 19
         }
       ]
     },
@@ -421,7 +481,15 @@ tester.run('no-deprecated-slot-attribute', rule, {
           </template>
         </MyComponent>
       </template>`,
-      errors: ['`slot` attributes are deprecated.']
+      errors: [
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
+        }
+      ]
     },
     {
       code: `
@@ -440,7 +508,15 @@ tester.run('no-deprecated-slot-attribute', rule, {
           </template>
         </MyComponent>
       </template>`,
-      errors: ['`slot` attributes are deprecated.']
+      errors: [
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
+        }
+      ]
     },
     {
       code: `
@@ -459,7 +535,15 @@ tester.run('no-deprecated-slot-attribute', rule, {
           </template>
         </MyComponent>
       </template>`,
-      errors: ['`slot` attributes are deprecated.']
+      errors: [
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
+        }
+      ]
     },
     {
       // https://github.com/vuejs/eslint-plugin-vue/issues/1499
@@ -494,11 +578,17 @@ tester.run('no-deprecated-slot-attribute', rule, {
       errors: [
         {
           message: '`slot` attributes are deprecated.',
-          line: 4
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
         },
         {
           message: '`slot` attributes are deprecated.',
-          line: 9
+          line: 9,
+          column: 23,
+          endLine: 9,
+          endColumn: 27
         }
       ]
     },
@@ -526,8 +616,20 @@ tester.run('no-deprecated-slot-attribute', rule, {
         </my-component>
       </template>`,
       errors: [
-        '`slot` attributes are deprecated.',
-        '`slot` attributes are deprecated.'
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 37,
+          endLine: 4,
+          endColumn: 41
+        },
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 7,
+          column: 37,
+          endLine: 7,
+          endColumn: 42
+        }
       ]
     },
     {
@@ -544,8 +646,20 @@ tester.run('no-deprecated-slot-attribute', rule, {
       </template>`,
       output: null,
       errors: [
-        '`slot` attributes are deprecated.',
-        '`slot` attributes are deprecated.'
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 25
+        },
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 7,
+          column: 21,
+          endLine: 7,
+          endColumn: 25
+        }
       ]
     },
     {
@@ -590,8 +704,20 @@ tester.run('no-deprecated-slot-attribute', rule, {
       </template>`,
       output: null,
       errors: [
-        '`slot` attributes are deprecated.',
-        '`slot` attributes are deprecated.'
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 37,
+          endLine: 4,
+          endColumn: 42
+        },
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 7,
+          column: 37,
+          endLine: 7,
+          endColumn: 42
+        }
       ]
     },
     {
@@ -618,8 +744,20 @@ tester.run('no-deprecated-slot-attribute', rule, {
         </my-component>
       </template>`,
       errors: [
-        '`slot` attributes are deprecated.',
-        '`slot` attributes are deprecated.'
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 37,
+          endLine: 4,
+          endColumn: 42
+        },
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 7,
+          column: 37,
+          endLine: 7,
+          endColumn: 42
+        }
       ]
     },
     {
@@ -646,8 +784,20 @@ tester.run('no-deprecated-slot-attribute', rule, {
         </my-component>
       </template>`,
       errors: [
-        '`slot` attributes are deprecated.',
-        '`slot` attributes are deprecated.'
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 41,
+          endLine: 4,
+          endColumn: 46
+        },
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 7,
+          column: 37,
+          endLine: 7,
+          endColumn: 42
+        }
       ]
     },
     {
@@ -678,7 +828,15 @@ tester.run('no-deprecated-slot-attribute', rule, {
           ignore: ['one']
         }
       ],
-      errors: ['`slot` attributes are deprecated.']
+      errors: [
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 7,
+          column: 16,
+          endLine: 7,
+          endColumn: 20
+        }
+      ]
     },
     {
       code: `
@@ -863,7 +1021,15 @@ tester.run('no-deprecated-slot-attribute', rule, {
 </template>
         </my-component>
       </template>`,
-      errors: ['`slot` attributes are deprecated.']
+      errors: [
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 6,
+          column: 13,
+          endLine: 6,
+          endColumn: 18
+        }
+      ]
     },
     {
       code: `
@@ -876,7 +1042,15 @@ tester.run('no-deprecated-slot-attribute', rule, {
         </component>
       </template>`,
       output: null,
-      errors: ['`slot` attributes are deprecated.']
+      errors: [
+        {
+          message: '`slot` attributes are deprecated.',
+          line: 4,
+          column: 16,
+          endLine: 4,
+          endColumn: 20
+        }
+      ]
     }
   ]
 })
diff --git a/tests/lib/rules/no-negated-condition.js b/tests/lib/rules/no-negated-condition.js
new file mode 100644
index 00000000..4a4d5e4c
--- /dev/null
+++ b/tests/lib/rules/no-negated-condition.js
@@ -0,0 +1,166 @@
+/**
+ * @author Wayne Zhang
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const RuleTester = require('../../eslint-compat').RuleTester
+const rule = require('../../../lib/rules/no-negated-condition')
+
+const tester = new RuleTester({
+  languageOptions: {
+    parser: require('vue-eslint-parser'),
+    ecmaVersion: 2020,
+    sourceType: 'module'
+  }
+})
+
+tester.run('no-negated-condition', rule, {
+  valid: [
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :class="foo ? 'baz' : 'bar'" />
+      </template>
+      `
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :style="{ color: isActive ? 'red' : 'blue' }" />
+      </template>
+      `
+    }
+  ],
+  invalid: [
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :class="!foo ? 'bar' : 'baz'" />
+      </template>
+      `,
+      errors: [
+        {
+          message: 'Unexpected negated condition.',
+          line: 3,
+          column: 22,
+          endLine: 3,
+          endColumn: 42
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :style="{
+          'display': !isVisible ? 'none' : 'block',
+          'color': 'red'
+        }" />
+      </template>
+      `,
+      errors: [
+        {
+          message: 'Unexpected negated condition.',
+          line: 4,
+          column: 22,
+          endLine: 4,
+          endColumn: 51
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :class="{
+          'hidden': !foo ? true : false,
+          'visible': bar
+        }" />
+      </template>
+      `,
+      errors: [
+        {
+          message: 'Unexpected negated condition.',
+          line: 4,
+          column: 21,
+          endLine: 4,
+          endColumn: 40
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :disabled="!enabled ? true : false" />
+      </template>
+      `,
+      errors: [
+        {
+          message: 'Unexpected negated condition.',
+          line: 3,
+          column: 25,
+          endLine: 3,
+          endColumn: 48
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :class="a !== b ? 'different' : 'same'" />
+      </template>
+      `,
+      errors: [
+        {
+          message: 'Unexpected negated condition.',
+          line: 3,
+          column: 22,
+          endLine: 3,
+          endColumn: 52
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :class="a != b ? 'not-equal' : 'equal'" />
+      </template>
+      `,
+      errors: [
+        {
+          message: 'Unexpected negated condition.',
+          line: 3,
+          column: 22,
+          endLine: 3,
+          endColumn: 52
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <template>
+        <div :style="{
+          opacity: !(x && y) ? 0 : 1
+        }" />
+      </template>
+      `,
+      errors: [
+        {
+          message: 'Unexpected negated condition.',
+          line: 4,
+          column: 20,
+          endLine: 4,
+          endColumn: 37
+        }
+      ]
+    }
+  ]
+})