Repository: vuejs/eslint-plugin-vue
Pull request #1043 (2020-02-02 21:09:52)

feat(RFC0015): add no-deprecated-filter rule
### Add `no-deprecated-filter` rule

**Relates to:**
 #1035 
[RFC0015](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0015-remove-filters.md)

**Scope:**
* `vue/no-deprecated-filter` - This rule reports usage of `filters` syntax removed in Vue.js 3.0.0+

**Clarification needed:**
- [ ] This rule is based on `VFilterSequenceExpression`. As Vue.js 3 is going to drop support for filters, are they any plans to drop support for that node in AST generated by `vue-eslint-parser`?  
It seems like a reasonable move as `{{ 0b0001 | 0b0010 }}` in Vue.js 3 AST should be probably interpreted as `BinaryExpression` 


ota-meshi: Thank you for this PR.

I think people rarely do bitwise operations on templates. So I don't think there is a problem, but if you strictly parse it, you need to work on adding options to "vue-eslint-parser".

Patch:
diff --git a/docs/rules/README.md b/docs/rules/README.md
index d0aed44c..19a26062 100644
--- a/docs/rules/README.md
+++ b/docs/rules/README.md
@@ -160,6 +160,7 @@ For example:
 | [vue/match-component-file-name](./match-component-file-name.md) | require component name property to match its file name |  |
 | [vue/max-len](./max-len.md) | enforce a maximum line length |  |
 | [vue/no-boolean-default](./no-boolean-default.md) | disallow boolean defaults | :wrench: |
+| [vue/no-deprecated-filter](./no-deprecated-filter.md) | disallow using deprecated filters syntax |  |
 | [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: |
 | [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: |
diff --git a/docs/rules/no-deprecated-filter.md b/docs/rules/no-deprecated-filter.md
new file mode 100644
index 00000000..f72a8ee8
--- /dev/null
+++ b/docs/rules/no-deprecated-filter.md
@@ -0,0 +1,50 @@
+---
+pageClass: rule-details
+sidebarDepth: 0
+title: vue/no-deprecated-filter
+description: disallow using deprecated filters syntax
+---
+# vue/no-deprecated-filter
+> disallow using deprecated filters syntax
+
+
+## :book: Rule Details
+
+This rule reports deprecated `filters` syntax (removed in Vue.js v3.0.0+)
+
+<eslint-code-block :rules="{'vue/no-deprecated-filter': ['error']}">
+
+```vue
+<template>
+  <!-- ✓ GOOD -->
+  {{ filter(msg) }}
+  {{ filter(msg, '€') }}
+  {{ filterB(filterA(msg)) }}
+  <div v-bind:id="filter(msg)"></div>
+  <div v-bind:id="filter(msg, '€')"></div>
+  <div v-bind:id="filterB(filterA(msg))"></div>
+
+  <!-- ✗ BAD -->
+  {{ msg | filter }}
+  {{ msg | filter('€') }}
+  {{ msg | filterA | filterB }}
+  <div v-bind:id="msg | filter"></div>
+  <div v-bind:id="msg | filter('€')"></div>
+  <div v-bind:id="msg | filterA | filterB"></div>
+</template>
+```
+
+</eslint-code-block>
+
+### :wrench: Options
+
+Nothing.
+
+## :books: Further Reading
+
+- [Vue RFCs - Remove support for filters.](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0015-remove-filters.md)
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-filter.js)
+- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-filter.js)
diff --git a/lib/index.js b/lib/index.js
index c13af25c..a8ebcd31 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -39,6 +39,7 @@ module.exports = {
     'no-async-in-computed-properties': require('./rules/no-async-in-computed-properties'),
     'no-boolean-default': require('./rules/no-boolean-default'),
     'no-confusing-v-for-v-if': require('./rules/no-confusing-v-for-v-if'),
+    'no-deprecated-filter': require('./rules/no-deprecated-filter'),
     'no-custom-modifiers-on-v-model': require('./rules/no-custom-modifiers-on-v-model'),
     'no-deprecated-scope-attribute': require('./rules/no-deprecated-scope-attribute'),
     'no-deprecated-slot-attribute': require('./rules/no-deprecated-slot-attribute'),
diff --git a/lib/rules/no-deprecated-filter.js b/lib/rules/no-deprecated-filter.js
new file mode 100644
index 00000000..2ec4256e
--- /dev/null
+++ b/lib/rules/no-deprecated-filter.js
@@ -0,0 +1,43 @@
+/**
+ * @author Przemyslaw Falowski (@przemkow)
+ * @fileoverview disallow using deprecated filters syntax
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+const utils = require('../utils')
+
+// ------------------------------------------------------------------------------
+// Rule Definition
+// ------------------------------------------------------------------------------
+
+module.exports = {
+  meta: {
+    type: 'problem',
+    docs: {
+      description: 'disallow using deprecated filters syntax',
+      category: undefined,
+      url: 'https://eslint.vuejs.org/rules/no-deprecated-filter.html'
+    },
+    fixable: null,
+    schema: [],
+    messages: {
+      noDeprecatedFilter: 'Filters are deprecated.'
+    }
+  },
+
+  create: function (context) {
+    return utils.defineTemplateBodyVisitor(context, {
+      'VFilterSequenceExpression' (node) {
+        context.report({
+          node,
+          loc: node.loc,
+          messageId: 'noDeprecatedFilter'
+        })
+      }
+    })
+  }
+}


Test patch:
diff --git a/tests/lib/rules/no-deprecated-filter.js b/tests/lib/rules/no-deprecated-filter.js
new file mode 100644
index 00000000..20957e46
--- /dev/null
+++ b/tests/lib/rules/no-deprecated-filter.js
@@ -0,0 +1,72 @@
+/**
+ * @author Przemyslaw Falowski (@przemkow)
+ * @fileoverview disallow using deprecated filters syntax
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+const rule = require('../../../lib/rules/no-deprecated-filter')
+const RuleTester = require('eslint').RuleTester
+
+// ------------------------------------------------------------------------------
+// Tests
+// ------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({
+  parser: require.resolve('vue-eslint-parser'),
+  parserOptions: { ecmaVersion: 2015 }
+})
+
+ruleTester.run('no-deprecated-filter', rule, {
+  valid: [
+    {
+      filename: 'test.vue',
+      code: '<template>{{ msg }}</template>'
+    },
+    {
+      filename: 'test.vue',
+      code: '<template>{{ method(msg) }}</template>'
+    }
+  ],
+
+  invalid: [
+    {
+      filename: 'test.vue',
+      code: '<template>{{ msg | filter }}</template>',
+      errors: ['Filters are deprecated.']
+    },
+    {
+      filename: 'test.vue',
+      code: '<template>{{ msg | filter(x) }}</template>',
+      errors: ['Filters are deprecated.']
+    },
+    {
+      filename: 'test.vue',
+      code: '<template>{{ msg | filterA | filterB }}</template>',
+      errors: ['Filters are deprecated.']
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div v-for="msg in messages">{{ msg | filter }}</div></template>',
+      errors: ['Filters are deprecated.']
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div v-bind:id="msg | filter"></div></template>',
+      errors: ['Filters are deprecated.']
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div v-bind:id="msg | filter(aaa)"></div></template>',
+      errors: ['Filters are deprecated.']
+    },
+    {
+      filename: 'test.vue',
+      code: '<template><div v-bind:id="msg | filterA | filterB"></div></template>',
+      errors: ['Filters are deprecated.']
+    }
+  ]
+})