Repository: vuejs/eslint-plugin-vue
Pull request #1130 (2020-05-16 00:44:07)

Add `vue/no-deprecated-v-on-native-modifier` rule
refs #1035 


Patch:
diff --git a/docs/rules/README.md b/docs/rules/README.md
index d022dd67..a6f2627e 100644
--- a/docs/rules/README.md
+++ b/docs/rules/README.md
@@ -49,6 +49,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
 | [vue/no-deprecated-slot-attribute](./no-deprecated-slot-attribute.md) | disallow deprecated `slot` attribute (in Vue.js 2.6.0+) | :wrench: |
 | [vue/no-deprecated-slot-scope-attribute](./no-deprecated-slot-scope-attribute.md) | disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+) | :wrench: |
 | [vue/no-deprecated-v-bind-sync](./no-deprecated-v-bind-sync.md) | disallow use of deprecated `.sync` modifier on `v-bind` directive (in Vue.js 3.0.0+) | :wrench: |
+| [vue/no-deprecated-v-on-native-modifier](./no-deprecated-v-on-native-modifier.md) | disallow using deprecated `.native` modifiers (in Vue.js 3.0.0+) |  |
 | [vue/no-deprecated-v-on-number-modifiers](./no-deprecated-v-on-number-modifiers.md) | disallow using deprecated number (keycode) modifiers (in Vue.js 3.0.0+) | :wrench: |
 | [vue/no-deprecated-vue-config-keycodes](./no-deprecated-vue-config-keycodes.md) | disallow using deprecated `Vue.config.keyCodes` (in Vue.js 3.0.0+) |  |
 | [vue/no-dupe-keys](./no-dupe-keys.md) | disallow duplication of field names |  |
diff --git a/docs/rules/no-deprecated-data-object-declaration.md b/docs/rules/no-deprecated-data-object-declaration.md
index 773a50dd..1875ff09 100644
--- a/docs/rules/no-deprecated-data-object-declaration.md
+++ b/docs/rules/no-deprecated-data-object-declaration.md
@@ -75,7 +75,7 @@ Nothing.
 
 ## :books: Further reading
 
-- [RFC: remove data object declaration](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0019-remove-data-object-declaration.md)
+- [Vue RFCs - 0019-remove-data-object-declaration](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0019-remove-data-object-declaration.md)
 
 ## :mag: Implementation
 
diff --git a/docs/rules/no-deprecated-events-api.md b/docs/rules/no-deprecated-events-api.md
index 8f1244a0..11fb96a3 100644
--- a/docs/rules/no-deprecated-events-api.md
+++ b/docs/rules/no-deprecated-events-api.md
@@ -49,7 +49,7 @@ Nothing.
 
 ## :books: Further reading
 
-- [RFC: events api change](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0020-events-api-change.md)
+- [Vue RFCs - 0020-events-api-change](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0020-events-api-change.md)
 
 ## :mag: Implementation
 
diff --git a/docs/rules/no-deprecated-filter.md b/docs/rules/no-deprecated-filter.md
index 787536ba..cba1380f 100644
--- a/docs/rules/no-deprecated-filter.md
+++ b/docs/rules/no-deprecated-filter.md
@@ -43,7 +43,7 @@ Nothing.
 
 ## :books: Further Reading
 
-- [Vue RFCs - Remove support for filters.](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0015-remove-filters.md)
+- [Vue RFCs - 0015-remove-filters](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0015-remove-filters.md)
 
 ## :mag: Implementation
 
diff --git a/docs/rules/no-deprecated-v-bind-sync.md b/docs/rules/no-deprecated-v-bind-sync.md
index 642df95b..75359741 100644
--- a/docs/rules/no-deprecated-v-bind-sync.md
+++ b/docs/rules/no-deprecated-v-bind-sync.md
@@ -45,7 +45,7 @@ Nothing.
 
 ## :books: Further reading
 
-- [RFC: Replace v-bind.sync with v-model argument](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0005-replace-v-bind-sync-with-v-model-argument.md)
+- [Vue RFCs - 0005-replace-v-bind-sync-with-v-model-argument](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0005-replace-v-bind-sync-with-v-model-argument.md)
 
 ## :mag: Implementation
 
diff --git a/docs/rules/no-deprecated-v-on-native-modifier.md b/docs/rules/no-deprecated-v-on-native-modifier.md
new file mode 100644
index 00000000..93620cd7
--- /dev/null
+++ b/docs/rules/no-deprecated-v-on-native-modifier.md
@@ -0,0 +1,49 @@
+---
+pageClass: rule-details
+sidebarDepth: 0
+title: vue/no-deprecated-v-on-native-modifier
+description: disallow using deprecated `.native` modifiers (in Vue.js 3.0.0+)
+---
+# vue/no-deprecated-v-on-native-modifier
+> disallow using deprecated `.native` modifiers (in Vue.js 3.0.0+)
+
+- :gear: This rule is included in all of `"plugin:vue/vue3-essential"`, `"plugin:vue/vue3-strongly-recommended"` and `"plugin:vue/vue3-recommended"`.
+
+## :book: Rule Details
+
+This rule reports use of deprecated `.native` modifier on `v-on` directive (in Vue.js 3.0.0+)
+
+<eslint-code-block :rules="{'vue/no-deprecated-v-on-native-modifier': ['error']}">
+
+```vue
+<template>
+  <!-- ✓ GOOD -->
+  <CoolInput v-on:keydown.enter="onKeydownEnter" />
+  <CoolInput @keydown.enter="onKeydownEnter" />
+
+  <!-- ✗ BAD -->
+  <CoolInput v-on:keydown.native="onKeydown" />
+  <CoolInput @keydown.enter.native="onKeydownEnter" />
+</template>
+```
+
+</eslint-code-block>
+
+## :wrench: Options
+
+Nothing.
+
+## :couple: Related rules
+
+- [valid-v-on]
+
+[valid-v-on]: valid-v-on.md
+
+## :books: Further reading
+
+- [Vue RFCs - 0031-attr-fallthrough](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0031-attr-fallthrough.md)
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-v-on-native-modifier.js)
+- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-v-on-native-modifier.js)
diff --git a/docs/rules/no-deprecated-v-on-number-modifiers.md b/docs/rules/no-deprecated-v-on-number-modifiers.md
index 5ecba24a..5b720015 100644
--- a/docs/rules/no-deprecated-v-on-number-modifiers.md
+++ b/docs/rules/no-deprecated-v-on-number-modifiers.md
@@ -44,7 +44,7 @@ Nothing.
 
 ## :books: Further reading
 
-- [RFC: drop keycode support](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0014-drop-keycode-support.md)
+- [Vue RFCs - 0014-drop-keycode-support](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0014-drop-keycode-support.md)
 
 ## :mag: Implementation
 
diff --git a/lib/configs/vue3-essential.js b/lib/configs/vue3-essential.js
index 651ff096..93e4996b 100644
--- a/lib/configs/vue3-essential.js
+++ b/lib/configs/vue3-essential.js
@@ -17,6 +17,7 @@ module.exports = {
     'vue/no-deprecated-slot-attribute': 'error',
     'vue/no-deprecated-slot-scope-attribute': 'error',
     'vue/no-deprecated-v-bind-sync': 'error',
+    'vue/no-deprecated-v-on-native-modifier': 'error',
     'vue/no-deprecated-v-on-number-modifiers': 'error',
     'vue/no-deprecated-vue-config-keycodes': 'error',
     'vue/no-dupe-keys': 'error',
diff --git a/lib/index.js b/lib/index.js
index fa2bc434..9faa9163 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -50,6 +50,7 @@ module.exports = {
     'no-deprecated-slot-attribute': require('./rules/no-deprecated-slot-attribute'),
     'no-deprecated-slot-scope-attribute': require('./rules/no-deprecated-slot-scope-attribute'),
     'no-deprecated-v-bind-sync': require('./rules/no-deprecated-v-bind-sync'),
+    'no-deprecated-v-on-native-modifier': require('./rules/no-deprecated-v-on-native-modifier'),
     'no-deprecated-v-on-number-modifiers': require('./rules/no-deprecated-v-on-number-modifiers'),
     'no-deprecated-vue-config-keycodes': require('./rules/no-deprecated-vue-config-keycodes'),
     'no-dupe-keys': require('./rules/no-dupe-keys'),
diff --git a/lib/rules/no-deprecated-v-on-native-modifier.js b/lib/rules/no-deprecated-v-on-native-modifier.js
new file mode 100644
index 00000000..d9375543
--- /dev/null
+++ b/lib/rules/no-deprecated-v-on-native-modifier.js
@@ -0,0 +1,45 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+const utils = require('../utils')
+
+// ------------------------------------------------------------------------------
+// Rule Definition
+// ------------------------------------------------------------------------------
+
+module.exports = {
+  meta: {
+    type: 'problem',
+    docs: {
+      description: 'disallow using deprecated `.native` modifiers (in Vue.js 3.0.0+)',
+      categories: ['vue3-essential'],
+      url: 'https://eslint.vuejs.org/rules/no-deprecated-v-on-native-modifier.html'
+    },
+    fixable: null,
+    schema: [],
+    messages: {
+      deprecated: "'.native' modifier on 'v-on' directive is deprecated."
+    }
+  },
+
+  create (context) {
+    return utils.defineTemplateBodyVisitor(context, {
+      "VAttribute[directive=true][key.name.name='on'] > VDirectiveKey > VIdentifier[name='native']" (node) {
+        const key = node.parent
+        if (!key.modifiers.includes(node)) return
+
+        context.report({
+          node,
+          messageId: 'deprecated'
+        })
+      }
+    })
+  }
+}
diff --git a/lib/rules/no-deprecated-v-on-number-modifiers.js b/lib/rules/no-deprecated-v-on-number-modifiers.js
index 971ffdc0..6e5125e4 100644
--- a/lib/rules/no-deprecated-v-on-number-modifiers.js
+++ b/lib/rules/no-deprecated-v-on-number-modifiers.js
@@ -32,8 +32,8 @@ module.exports = {
 
   create (context) {
     return utils.defineTemplateBodyVisitor(context, {
-      "VAttribute[directive=true][key.name.name='on']" (node) {
-        const modifier = node.key.modifiers.find(mod => Number.isInteger(parseInt(mod.name, 10)))
+      "VAttribute[directive=true][key.name.name='on'] > VDirectiveKey" (node) {
+        const modifier = node.modifiers.find(mod => Number.isInteger(parseInt(mod.name, 10)))
         if (!modifier) return
 
         const keyCodes = parseInt(modifier.name, 10)
@@ -41,8 +41,7 @@ module.exports = {
           keyCodes > 9 || keyCodes < 0
         ) {
           context.report({
-            node,
-            loc: node.loc,
+            node: modifier,
             messageId: 'numberModifierIsDeprecated',
             fix: (fixer) => {
               const key = keyCodeToKey[keyCodes]


Test patch:
diff --git a/tests/lib/rules/no-deprecated-v-on-native-modifier.js b/tests/lib/rules/no-deprecated-v-on-native-modifier.js
new file mode 100644
index 00000000..772a5691
--- /dev/null
+++ b/tests/lib/rules/no-deprecated-v-on-native-modifier.js
@@ -0,0 +1,76 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+const rule = require('../../../lib/rules/no-deprecated-v-on-native-modifier')
+const RuleTester = require('eslint').RuleTester
+
+// ------------------------------------------------------------------------------
+// Tests
+// ------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({
+  parser: require.resolve('vue-eslint-parser'),
+  parserOptions: { ecmaVersion: 2015 }
+})
+
+ruleTester.run('no-deprecated-v-on-native-modifier', rule, {
+
+  valid: [
+    {
+      filename: 'test.vue',
+      code: "<template><input v-on:keyup.enter='fire'></template>"
+    },
+    {
+      filename: 'test.vue',
+      code: "<template><input @keyup.enter='fire'></template>"
+    },
+    {
+      filename: 'test.vue',
+      code: "<template><input v-native:foo.native.foo.bar='fire'></template>"
+    },
+    {
+      filename: 'test.vue',
+      code: "<template><input @native.enter='fire'></template>"
+    },
+    {
+      filename: 'test.vue',
+      code: "<template><input :keydown.native='fire'></template>"
+    }
+  ],
+
+  invalid: [
+    {
+      filename: 'test.vue',
+      code: "<template><input v-on:keyup.native='fore'></template>",
+      errors: [
+        {
+          line: 1,
+          column: 29,
+          messageId: 'deprecated',
+          endLine: 1,
+          endColumn: 35
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: "<template><input v-on:keyup.foo.native.bar='fore'></template>",
+      errors: [
+        {
+          line: 1,
+          column: 33,
+          messageId: 'deprecated',
+          endLine: 1,
+          endColumn: 39
+        }
+      ]
+    }
+  ]
+})
diff --git a/tests/lib/rules/no-deprecated-v-on-number-modifiers.js b/tests/lib/rules/no-deprecated-v-on-number-modifiers.js
index f2e11906..36d4bf00 100644
--- a/tests/lib/rules/no-deprecated-v-on-number-modifiers.js
+++ b/tests/lib/rules/no-deprecated-v-on-number-modifiers.js
@@ -20,7 +20,7 @@ const ruleTester = new RuleTester({
   parserOptions: { ecmaVersion: 2015 }
 })
 
-ruleTester.run('no-deprecated-v-bind-sync', rule, {
+ruleTester.run('no-deprecated-v-on-number-modifiers', rule, {
 
   valid: [
     {