Repository: vuejs/eslint-plugin-vue
Pull request #1119 (2020-05-09 11:08:20)

Add `vue/no-deprecated-functional-template` rule
This PR adds `vue/no-deprecated-functional-template` rule that reports deprecated the `functional` template (in Vue.js 3.0.0+)


Patch:
diff --git a/docs/rules/README.md b/docs/rules/README.md
index 24c7edf8..cb46ea8d 100644
--- a/docs/rules/README.md
+++ b/docs/rules/README.md
@@ -42,6 +42,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
 | [vue/no-deprecated-data-object-declaration](./no-deprecated-data-object-declaration.md) | disallow using deprecated object declaration on data (in Vue.js 3.0.0+) | :wrench: |
 | [vue/no-deprecated-events-api](./no-deprecated-events-api.md) | disallow using deprecated events api (in Vue.js 3.0.0+) |  |
 | [vue/no-deprecated-filter](./no-deprecated-filter.md) | disallow using deprecated filters syntax (in Vue.js 3.0.0+) |  |
+| [vue/no-deprecated-functional-template](./no-deprecated-functional-template.md) | disallow using deprecated the `functional` template (in Vue.js 3.0.0+) |  |
 | [vue/no-deprecated-html-element-is](./no-deprecated-html-element-is.md) | disallow using deprecated the `is` attribute on HTML elements (in Vue.js 3.0.0+) |  |
 | [vue/no-deprecated-inline-template](./no-deprecated-inline-template.md) | disallow using deprecated `inline-template` attribute (in Vue.js 3.0.0+) |  |
 | [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: |
diff --git a/docs/rules/no-deprecated-functional-template.md b/docs/rules/no-deprecated-functional-template.md
new file mode 100644
index 00000000..a7e288f7
--- /dev/null
+++ b/docs/rules/no-deprecated-functional-template.md
@@ -0,0 +1,39 @@
+---
+pageClass: rule-details
+sidebarDepth: 0
+title: vue/no-deprecated-functional-template
+description: disallow using deprecated the `functional` template (in Vue.js 3.0.0+)
+---
+# vue/no-deprecated-functional-template
+> disallow using deprecated the `functional` template (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 deprecated the `functional` template (in Vue.js 3.0.0+)
+
+<eslint-code-block :rules="{'vue/no-deprecated-functional-template': ['error']}">
+
+```vue
+<!-- ✗ BAD -->
+<template functional>
+  <!-- ... -->
+</template>
+```
+
+</eslint-code-block>
+
+### :wrench: Options
+
+Nothing.
+
+## :books: Further Reading
+
+- [Vue RFCs - 0007-functional-async-api-change](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0007-functional-async-api-change.md)
+- [Guide - Functional Components](https://vuejs.org/v2/guide/render-function.html#Functional-Components)
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-functional-template.js)
+- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-functional-template.js)
diff --git a/lib/configs/vue3-essential.js b/lib/configs/vue3-essential.js
index 305146f2..b476de9e 100644
--- a/lib/configs/vue3-essential.js
+++ b/lib/configs/vue3-essential.js
@@ -10,6 +10,7 @@ module.exports = {
     'vue/no-deprecated-data-object-declaration': 'error',
     'vue/no-deprecated-events-api': 'error',
     'vue/no-deprecated-filter': 'error',
+    'vue/no-deprecated-functional-template': 'error',
     'vue/no-deprecated-html-element-is': 'error',
     'vue/no-deprecated-inline-template': 'error',
     'vue/no-deprecated-scope-attribute': 'error',
diff --git a/lib/index.js b/lib/index.js
index 43a34626..852782f2 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -43,6 +43,7 @@ module.exports = {
     'no-deprecated-data-object-declaration': require('./rules/no-deprecated-data-object-declaration'),
     'no-deprecated-events-api': require('./rules/no-deprecated-events-api'),
     'no-deprecated-filter': require('./rules/no-deprecated-filter'),
+    'no-deprecated-functional-template': require('./rules/no-deprecated-functional-template'),
     'no-deprecated-html-element-is': require('./rules/no-deprecated-html-element-is'),
     'no-deprecated-inline-template': require('./rules/no-deprecated-inline-template'),
     'no-deprecated-scope-attribute': require('./rules/no-deprecated-scope-attribute'),
diff --git a/lib/rules/no-deprecated-functional-template.js b/lib/rules/no-deprecated-functional-template.js
new file mode 100644
index 00000000..7ab88623
--- /dev/null
+++ b/lib/rules/no-deprecated-functional-template.js
@@ -0,0 +1,51 @@
+/**
+ * @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 the `functional` template (in Vue.js 3.0.0+)',
+      categories: ['vue3-essential'],
+      url: 'https://eslint.vuejs.org/rules/no-deprecated-functional-template.html'
+    },
+    fixable: null,
+    schema: [],
+    messages: {
+      unexpected: 'The `functional` template are deprecated.'
+    }
+  },
+
+  create (context) {
+    return {
+      Program (program) {
+        const element = program.templateBody
+        if (element == null) {
+          return
+        }
+
+        const functional = utils.getAttribute(element, 'functional')
+
+        if (functional) {
+          context.report({
+            node: functional,
+            messageId: 'unexpected'
+          })
+        }
+      }
+    }
+  }
+}


Test patch:
diff --git a/tests/lib/rules/no-deprecated-functional-template.js b/tests/lib/rules/no-deprecated-functional-template.js
new file mode 100644
index 00000000..9b031cf2
--- /dev/null
+++ b/tests/lib/rules/no-deprecated-functional-template.js
@@ -0,0 +1,65 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+const rule = require('../../../lib/rules/no-deprecated-functional-template')
+const RuleTester = require('eslint').RuleTester
+
+// ------------------------------------------------------------------------------
+// Tests
+// ------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({
+  parser: require.resolve('vue-eslint-parser'),
+  parserOptions: { ecmaVersion: 2019 }
+})
+
+ruleTester.run('no-deprecated-functional-template', rule, {
+  valid: [
+    {
+      filename: 'test.vue',
+      code: '<template></template>'
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div /></template>'
+    },
+    {
+      filename: 'test.vue',
+      code: '<template f><div /></template>'
+    }
+  ],
+
+  invalid: [
+    {
+      filename: 'test.vue',
+      code: '<template functional></template>',
+      errors: [
+        {
+          line: 1,
+          column: 11,
+          messageId: 'unexpected',
+          endLine: 1,
+          endColumn: 21
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: '<template functional><div /></template>',
+      errors: [
+        {
+          line: 1,
+          column: 11,
+          messageId: 'unexpected'
+        }
+      ]
+    }
+  ]
+})