diff --git a/docs/rules/README.md b/docs/rules/README.md
index addfcb28c..cbef00777 100644
--- a/docs/rules/README.md
+++ b/docs/rules/README.md
@@ -159,6 +159,7 @@ For example:
| [vue/no-empty-pattern](./no-empty-pattern.md) | disallow empty destructuring patterns | |
| [vue/no-reserved-component-names](./no-reserved-component-names.md) | disallow the use of reserved names in component definitions | |
| [vue/no-restricted-syntax](./no-restricted-syntax.md) | disallow specified syntax | |
+| [vue/no-unsupported-features](./no-unsupported-features.md) | disallow unsupported Vue.js syntax on the specified version | :wrench: |
| [vue/object-curly-spacing](./object-curly-spacing.md) | enforce consistent spacing inside braces | :wrench: |
| [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | |
| [vue/require-name-property](./require-name-property.md) | require a name property in Vue components | |
diff --git a/docs/rules/no-unsupported-features.md b/docs/rules/no-unsupported-features.md
new file mode 100644
index 000000000..5bb39148f
--- /dev/null
+++ b/docs/rules/no-unsupported-features.md
@@ -0,0 +1,82 @@
+---
+pageClass: rule-details
+sidebarDepth: 0
+title: vue/no-unsupported-features
+description: disallow unsupported Vue.js syntax on the specified version
+---
+# vue/no-unsupported-features
+> disallow unsupported Vue.js syntax on the specified version
+
+- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.
+
+## :book: Rule Details
+
+This rule reports unsupported Vue.js syntax on the specified version.
+
+## :wrench: Options
+
+```json
+{
+ "vue/no-unsupported-features": ["error", {
+ "version": "^2.6.0",
+ "ignores": []
+ }]
+}
+```
+
+- `version` ... The `version` option accepts [the valid version range of `node-semver`](https://github.com/npm/node-semver#range-grammar). Set the version of Vue.js you are using. This option is required.
+- `ignores` ... You can use this `ignores` option to ignore the given features.
+The `"ignores"` option accepts an array of the following strings.
+ - Vue.js 2.6.0+
+ - `"dynamic-directive-arguments"` ... [dynamic directive arguments](https://vuejs.org/v2/guide/syntax.html#Dynamic-Arguments).
+ - `"v-slot"` ... [v-slot](https://vuejs.org/v2/api/#v-slot) directive.
+ - Vue.js 2.5.0+
+ - `"slot-scope-attribute"` ... [slot-scope](https://vuejs.org/v2/api/#slot-scope-deprecated) attributes.
+ - Vue.js `">=2.6.0-beta.1 <=2.6.0-beta.3"` or 2.6 custom build
+ - `"v-bind-prop-modifier-shorthand"` ... [v-bind](https://vuejs.org/v2/api/#v-bind) with `.prop` modifier shorthand.
+
+### `{"version": "^2.5.0"}`
+
+
+
+```vue
+
+
+
+
+
+ {{ props.title }}
+
+
+
+
+
+
+
+
+
+ {{ props.title }}
+
+
+ {{ props.title }}
+
+
+
+```
+
+
+
+## :books: Further reading
+
+- [Guide - Dynamic Arguments](https://vuejs.org/v2/guide/syntax.html#Dynamic-Arguments)
+- [API - v-slot](https://vuejs.org/v2/api/#v-slot)
+- [API - slot-scope](https://vuejs.org/v2/api/#slot-scope-deprecated)
+- [Vue RFCs - 0001-new-slot-syntax](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md)
+- [Vue RFCs - 0002-slot-syntax-shorthand](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0002-slot-syntax-shorthand.md)
+- [Vue RFCs - 0003-dynamic-directive-arguments](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0003-dynamic-directive-arguments.md)
+- [Vue RFCs - v-bind .prop shorthand proposal](https://github.com/vuejs/rfcs/pull/18)
+
+## :mag: Implementation
+
+- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-unsupported-features.js)
+- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-unsupported-features.js)
diff --git a/lib/index.js b/lib/index.js
index 3fc0f2c92..5fa52ddd5 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -54,6 +54,7 @@ module.exports = {
'no-template-key': require('./rules/no-template-key'),
'no-template-shadow': require('./rules/no-template-shadow'),
'no-textarea-mustache': require('./rules/no-textarea-mustache'),
+ 'no-unsupported-features': require('./rules/no-unsupported-features'),
'no-unused-components': require('./rules/no-unused-components'),
'no-unused-vars': require('./rules/no-unused-vars'),
'no-use-v-if-with-v-for': require('./rules/no-use-v-if-with-v-for'),
diff --git a/lib/rules/no-unsupported-features.js b/lib/rules/no-unsupported-features.js
new file mode 100644
index 000000000..c4c361b3a
--- /dev/null
+++ b/lib/rules/no-unsupported-features.js
@@ -0,0 +1,143 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const { Range } = require('semver')
+const utils = require('../utils')
+
+const FEATURES = {
+ // Vue.js 2.5.0+
+ 'slot-scope-attribute': require('./syntaxes/slot-scope-attribute'),
+ // Vue.js 2.6.0+
+ 'dynamic-directive-arguments': require('./syntaxes/dynamic-directive-arguments'),
+ 'v-slot': require('./syntaxes/v-slot'),
+
+ // >=2.6.0-beta.1 <=2.6.0-beta.3
+ 'v-bind-prop-modifier-shorthand': require('./syntaxes/v-bind-prop-modifier-shorthand')
+}
+
+const cache = new Map()
+/**
+ * Get the `semver.Range` object of a given range text.
+ * @param {string} x The text expression for a semver range.
+ * @returns {Range|null} The range object of a given range text.
+ * It's null if the `x` is not a valid range text.
+ */
+function getSemverRange (x) {
+ const s = String(x)
+ let ret = cache.get(s) || null
+
+ if (!ret) {
+ try {
+ ret = new Range(s)
+ } catch (_error) {
+ // Ignore parsing error.
+ }
+ cache.set(s, ret)
+ }
+
+ return ret
+}
+
+/**
+ * Merge two visitors.
+ * @param {Visitor} x The visitor which is assigned.
+ * @param {Visitor} y The visitor which is assigning.
+ * @returns {Visitor} `x`.
+ */
+function merge (x, y) {
+ for (const key of Object.keys(y)) {
+ if (typeof x[key] === 'function') {
+ if (x[key]._handlers == null) {
+ const fs = [x[key], y[key]]
+ x[key] = node => fs.forEach(h => h(node))
+ x[key]._handlers = fs
+ } else {
+ x[key]._handlers.push(y[key])
+ }
+ } else {
+ x[key] = y[key]
+ }
+ }
+ return x
+}
+
+module.exports = {
+ meta: {
+ type: 'suggestion',
+ docs: {
+ description: 'disallow unsupported Vue.js syntax on the specified version',
+ category: undefined,
+ url: 'https://eslint.vuejs.org/rules/no-unsupported-features.html'
+ },
+ fixable: 'code',
+ schema: [
+ {
+ type: 'object',
+ properties: {
+ version: {
+ type: 'string'
+ },
+ ignores: {
+ type: 'array',
+ items: {
+ enum: Object.keys(FEATURES)
+ },
+ uniqueItems: true
+ }
+ },
+ additionalProperties: false
+ }
+ ],
+ messages: {
+ // Vue.js 2.5.0+
+ forbiddenSlotScopeAttribute: '`slot-scope` are not supported until Vue.js "2.5.0".',
+ // Vue.js 2.6.0+
+ forbiddenDynamicDirectiveArguments: 'Dynamic arguments are not supported until Vue.js "2.6.0".',
+ forbiddenVSlot: '`v-slot` are not supported until Vue.js "2.6.0".',
+
+ // >=2.6.0-beta.1 <=2.6.0-beta.3
+ forbiddenVBindPropModifierShorthand: '`.prop` shorthand are not supported except Vue.js ">=2.6.0-beta.1 <=2.6.0-beta.3".'
+ }
+ },
+ create (context) {
+ const { version, ignores } = Object.assign(
+ {
+ version: null,
+ ignores: []
+ },
+ context.options[0] || {}
+ )
+ if (!version) {
+ // version is not set.
+ return {}
+ }
+ const versionRange = getSemverRange(version)
+
+ /**
+ * Check whether a given case object is full-supported on the configured node version.
+ * @param {{supported:string}} aCase The case object to check.
+ * @returns {boolean} `true` if it's supporting.
+ */
+ function isNotSupportingVersion (aCase) {
+ if (typeof aCase.supported === 'function') {
+ return !aCase.supported(versionRange)
+ }
+ return versionRange.intersects(getSemverRange(`<${aCase.supported}`))
+ }
+ const templateBodyVisitor = Object.keys(FEATURES)
+ .filter(syntaxName => !ignores.includes(syntaxName))
+ .filter(syntaxName => isNotSupportingVersion(FEATURES[syntaxName]))
+ .reduce((result, syntaxName) => {
+ const visitor = FEATURES[syntaxName].createTemplateBodyVisitor(context)
+ if (visitor) {
+ merge(result, visitor)
+ }
+ return result
+ }, {})
+
+ return utils.defineTemplateBodyVisitor(context, templateBodyVisitor)
+ }
+}
diff --git a/lib/rules/syntaxes/dynamic-directive-arguments.js b/lib/rules/syntaxes/dynamic-directive-arguments.js
new file mode 100644
index 000000000..4c5a5a7f1
--- /dev/null
+++ b/lib/rules/syntaxes/dynamic-directive-arguments.js
@@ -0,0 +1,25 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+module.exports = {
+ supported: '2.6.0',
+ createTemplateBodyVisitor (context) {
+ /**
+ * Reports dynamic argument node
+ * @param {VExpressionContainer} dinamicArgument node of dynamic argument
+ * @returns {void}
+ */
+ function reportDynamicArgument (dinamicArgument) {
+ context.report({
+ node: dinamicArgument,
+ messageId: 'forbiddenDynamicDirectiveArguments'
+ })
+ }
+
+ return {
+ 'VAttribute[directive=true] > VDirectiveKey > VExpressionContainer': reportDynamicArgument
+ }
+ }
+}
diff --git a/lib/rules/syntaxes/v-bind-prop-modifier-shorthand.js b/lib/rules/syntaxes/v-bind-prop-modifier-shorthand.js
new file mode 100644
index 000000000..db5076cf2
--- /dev/null
+++ b/lib/rules/syntaxes/v-bind-prop-modifier-shorthand.js
@@ -0,0 +1,33 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+const { Range } = require('semver')
+const unsupported = new Range('<=2.5 || >=2.6.0')
+
+module.exports = {
+ // >=2.6.0-beta.1 <=2.6.0-beta.3
+ supported: (versionRange) => {
+ return !versionRange.intersects(unsupported)
+ },
+ createTemplateBodyVisitor (context) {
+ /**
+ * Reports `.prop` shorthand node
+ * @param {VDirectiveKey} bindPropKey node of `.prop` shorthand
+ * @returns {void}
+ */
+ function reportPropModifierShorthand (bindPropKey) {
+ context.report({
+ node: bindPropKey,
+ messageId: 'forbiddenVBindPropModifierShorthand',
+ // fix to use `:x.prop` (downgrade)
+ fix: fixer => fixer.replaceText(bindPropKey, `:${bindPropKey.argument.rawName}.prop`)
+ })
+ }
+
+ return {
+ "VAttribute[directive=true] > VDirectiveKey[name.name='bind'][name.rawName='.']": reportPropModifierShorthand
+ }
+ }
+}
diff --git a/lib/rules/syntaxes/v-slot.js b/lib/rules/syntaxes/v-slot.js
new file mode 100644
index 000000000..17b1018a1
--- /dev/null
+++ b/lib/rules/syntaxes/v-slot.js
@@ -0,0 +1,83 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+module.exports = {
+ supported: '2.6.0',
+ createTemplateBodyVisitor (context) {
+ const sourceCode = context.getSourceCode()
+
+ /**
+ * Checks whether the given node can convert to the `slot`.
+ * @param {VAttribute} vSlotAttr node of `v-slot`
+ * @returns {boolean} `true` if the given node can convert to the `slot`
+ */
+ function canConvertToSlot (vSlotAttr) {
+ if (vSlotAttr.parent.parent.name !== 'template') {
+ return false
+ }
+ return true
+ }
+ /**
+ * Convert to `slot` and `slot-scope`.
+ * @param {object} fixer fixer
+ * @param {VAttribute} vSlotAttr node of `v-slot`
+ * @returns {*} fix data
+ */
+ function fixVSlotToSlot (fixer, vSlotAttr) {
+ const key = vSlotAttr.key
+ if (key.modifiers.length) {
+ // unknown modifiers
+ return null
+ }
+
+ const attrs = []
+ const argument = key.argument
+ if (argument) {
+ if (argument.type === 'VIdentifier') {
+ const name = argument.rawName
+ attrs.push(`slot="${name}"`)
+ } else if (argument.type === 'VExpressionContainer' && argument.expression) {
+ const expression = sourceCode.getText(argument.expression)
+ attrs.push(`:slot="${expression}"`)
+ } else {
+ // unknown or syntax error
+ return null
+ }
+ }
+ const scopedValueNode = vSlotAttr.value
+ if (scopedValueNode) {
+ attrs.push(
+ `slot-scope=${sourceCode.getText(scopedValueNode)}`
+ )
+ }
+ if (!attrs.length) {
+ attrs.push('slot') // useless
+ }
+ return fixer.replaceText(vSlotAttr, attrs.join(' '))
+ }
+ /**
+ * Reports `v-slot` node
+ * @param {VAttribute} vSlotAttr node of `v-slot`
+ * @returns {void}
+ */
+ function reportVSlot (vSlotAttr) {
+ context.report({
+ node: vSlotAttr.key,
+ messageId: 'forbiddenVSlot',
+ // fix to use `slot` (downgrade)
+ fix: fixer => {
+ if (!canConvertToSlot(vSlotAttr)) {
+ return null
+ }
+ return fixVSlotToSlot(fixer, vSlotAttr)
+ }
+ })
+ }
+
+ return {
+ "VAttribute[directive=true][key.name.name='slot']": reportVSlot
+ }
+ }
+}
diff --git a/tests/lib/rules/no-unsupported-features.js b/tests/lib/rules/no-unsupported-features.js
new file mode 100644
index 000000000..ced993c05
--- /dev/null
+++ b/tests/lib/rules/no-unsupported-features.js
@@ -0,0 +1,72 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+/**
+ * See to testcases in `./no-unsupported-features` directory for testcases of each features.
+ */
+'use strict'
+
+const RuleTester = require('eslint').RuleTester
+const rule = require('../../../lib/rules/no-unsupported-features')
+
+const tester = new RuleTester({
+ parser: 'vue-eslint-parser',
+ parserOptions: {
+ ecmaVersion: 2019
+ }
+})
+
+tester.run('no-unsupported-features', rule, {
+ valid: [
+ {
+ code: `
+
+
+
+
+
+
+ `,
+ options: [{ version: '^2.6.0' }]
+ }
+ ],
+ invalid: [
+ {
+ code: `
+
+
+
+
+
+
+ `,
+ options: [{ version: '^2.5.0' }],
+ output: `
+
+
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ },
+ {
+ message: 'Dynamic arguments are not supported until Vue.js "2.6.0".',
+ line: 6
+ }
+ ]
+ }
+ ]
+})
+
diff --git a/tests/lib/rules/no-unsupported-features/dynamic-directive-arguments.js b/tests/lib/rules/no-unsupported-features/dynamic-directive-arguments.js
new file mode 100644
index 000000000..46c0725d5
--- /dev/null
+++ b/tests/lib/rules/no-unsupported-features/dynamic-directive-arguments.js
@@ -0,0 +1,86 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const RuleTester = require('eslint').RuleTester
+const rule = require('../../../../lib/rules/no-unsupported-features')
+const utils = require('./utils')
+
+const buildOptions = utils.optionsBuilder('dynamic-directive-arguments', '^2.5.0')
+const tester = new RuleTester({
+ parser: 'vue-eslint-parser',
+ parserOptions: {
+ ecmaVersion: 2019
+ }
+})
+
+tester.run('no-unsupported-features/dynamic-directive-arguments', rule, {
+ valid: [
+ {
+ code: `
+
+
+ `,
+ options: buildOptions({ version: '^2.6.0' })
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions({ version: '^2.6.0' })
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions()
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions()
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions({ version: '2.6.0-beta.2' })
+ }
+ ],
+ invalid: [
+ {
+ code: `
+
+
+ `,
+ options: buildOptions(),
+ errors: [
+ {
+ message: 'Dynamic arguments are not supported until Vue.js "2.6.0".',
+ line: 3
+ }
+ ]
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions(),
+ errors: [
+ {
+ message: 'Dynamic arguments are not supported until Vue.js "2.6.0".',
+ line: 3
+ }
+ ]
+ }
+ ]
+})
+
diff --git a/tests/lib/rules/no-unsupported-features/slot-scope-attribute.js b/tests/lib/rules/no-unsupported-features/slot-scope-attribute.js
new file mode 100644
index 000000000..675eea30c
--- /dev/null
+++ b/tests/lib/rules/no-unsupported-features/slot-scope-attribute.js
@@ -0,0 +1,92 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const RuleTester = require('eslint').RuleTester
+const rule = require('../../../../lib/rules/no-unsupported-features')
+const utils = require('./utils')
+
+const buildOptions = utils.optionsBuilder('slot-scope-attribute', '^2.4.0')
+const tester = new RuleTester({
+ parser: 'vue-eslint-parser',
+ parserOptions: {
+ ecmaVersion: 2019
+ }
+})
+
+tester.run('no-unsupported-features/slot-scope-attribute', rule, {
+ valid: [
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions({ version: '^2.5.0' })
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions()
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions()
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions({ version: '^2.4.0', ignores: ['slot-scope-attribute'] })
+ }
+ ],
+ invalid: [
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: null,
+ errors: [
+ {
+ message: '`slot-scope` are not supported until Vue.js "2.5.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: null,
+ errors: [
+ {
+ message: '`slot-scope` are not supported until Vue.js "2.5.0".',
+ line: 4
+ }
+ ]
+ }
+ ]
+})
diff --git a/tests/lib/rules/no-unsupported-features/utils.js b/tests/lib/rules/no-unsupported-features/utils.js
new file mode 100644
index 000000000..9c94f062c
--- /dev/null
+++ b/tests/lib/rules/no-unsupported-features/utils.js
@@ -0,0 +1,38 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const rule = require('../../../../lib/rules/no-unsupported-features')
+
+const SYNTAXES = rule.meta.schema[0].properties.ignores.items.enum
+
+module.exports = {
+ SYNTAXES,
+ /**
+ * Define the options builder to exclude anything other than the given syntax.
+ * @param {string} targetSyntax syntax for given
+ * @param {string} defaultVersion default Vue.js version
+ * @returns {function} the options builder
+ */
+ optionsBuilder (targetSyntax, defaultVersion) {
+ const baseIgnores = SYNTAXES.filter(s => s !== targetSyntax)
+ return (option) => {
+ const ignores = [...baseIgnores]
+ let version = defaultVersion
+ if (!option) {
+ option = {}
+ }
+ if (option.ignores) {
+ ignores.push(...option.ignores)
+ }
+ if (option.version) {
+ version = option.version
+ }
+ option.ignores = ignores
+ option.version = version
+ return [option]
+ }
+ }
+}
diff --git a/tests/lib/rules/no-unsupported-features/v-bind-prop-modifier-shorthand.js b/tests/lib/rules/no-unsupported-features/v-bind-prop-modifier-shorthand.js
new file mode 100644
index 000000000..0dace1ac7
--- /dev/null
+++ b/tests/lib/rules/no-unsupported-features/v-bind-prop-modifier-shorthand.js
@@ -0,0 +1,87 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const RuleTester = require('eslint').RuleTester
+const rule = require('../../../../lib/rules/no-unsupported-features')
+const utils = require('./utils')
+
+const buildOptions = utils.optionsBuilder('v-bind-prop-modifier-shorthand', '^2.6.0')
+const tester = new RuleTester({
+ parser: 'vue-eslint-parser',
+ parserOptions: {
+ ecmaVersion: 2019
+ }
+})
+
+tester.run('no-unsupported-features/v-bind-prop-modifier-shorthand', rule, {
+ valid: [
+ {
+ code: `
+
+
+ `,
+ options: buildOptions({ version: '2.6.0-beta.1' })
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions({ version: '2.6.0-beta.2' })
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions({ version: '2.6.0-beta.3' })
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions()
+ }
+ ],
+ invalid: [
+ {
+ code: `
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+ `,
+ errors: [
+ {
+ message: '`.prop` shorthand are not supported except Vue.js ">=2.6.0-beta.1 <=2.6.0-beta.3".',
+ line: 3
+ }
+ ]
+ },
+ {
+ code: `
+
+
+ `,
+ options: buildOptions({ version: '2.5.99' }),
+ output: `
+
+
+ `,
+ errors: [
+ {
+ message: '`.prop` shorthand are not supported except Vue.js ">=2.6.0-beta.1 <=2.6.0-beta.3".',
+ line: 3
+ }
+ ]
+ }
+ ]
+})
+
diff --git a/tests/lib/rules/no-unsupported-features/v-slot.js b/tests/lib/rules/no-unsupported-features/v-slot.js
new file mode 100644
index 000000000..fbde61e60
--- /dev/null
+++ b/tests/lib/rules/no-unsupported-features/v-slot.js
@@ -0,0 +1,342 @@
+/**
+ * @author Yosuke Ota
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+const RuleTester = require('eslint').RuleTester
+const rule = require('../../../../lib/rules/no-unsupported-features')
+const utils = require('./utils')
+
+const buildOptions = utils.optionsBuilder('v-slot', '^2.5.0')
+const tester = new RuleTester({
+ parser: 'vue-eslint-parser',
+ parserOptions: {
+ ecmaVersion: 2019
+ }
+})
+
+tester.run('no-unsupported-features/v-slot', rule, {
+ valid: [
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions({ version: '^2.6.0' })
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions()
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions()
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions({ version: '^2.5.0', ignores: ['v-slot'] })
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions({ version: '>=2.0.0' })
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions({ version: '2.6.0-beta.2' })
+ }
+ ],
+ invalid: [
+
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ // syntax error
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: `
+
+
+
+
+ `,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: null,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+
+ // unknown modifiers
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: null,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 4
+ }
+ ]
+ },
+
+ // cannot fix
+ {
+ code: `
+
+
+
+
+ `,
+ options: buildOptions(),
+ output: null,
+ errors: [
+ {
+ message: '`v-slot` are not supported until Vue.js "2.6.0".',
+ line: 3
+ }
+ ]
+ }
+ ]
+})