Skip to content

Commit

Permalink
Update vue/no-unsupported-features rule to support Vue 3.2 syntaxes. (
Browse files Browse the repository at this point in the history
  • Loading branch information
ota-meshi committed Aug 10, 2021
1 parent a1a5122 commit 6a49210
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 18 deletions.
7 changes: 5 additions & 2 deletions docs/rules/no-unsupported-features.md
Expand Up @@ -29,6 +29,10 @@ This rule reports unsupported Vue.js syntax on the specified version.
- `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 3.2.0+
- `"v-memo"` ... [v-memo](https://v3.vuejs.org/api/directives.html#v-memo) directive.
- `"v-bind-prop-modifier-shorthand"` ... `v-bind` with `.prop` modifier shorthand.
- `"v-bind-attr-modifier"` ... `.attr` modifier on `v-bind` directive.
- Vue.js 3.1.0+
- `"is-attribute-with-vue-prefix"` ... [`is` attribute with `vue:` prefix](https://v3.vuejs.org/api/special-attributes.html#is)
- Vue.js 3.0.0+
Expand All @@ -42,8 +46,6 @@ The `"ignores"` option accepts an array of the following strings.
- `"v-slot"` ... [v-slot](https://v3.vuejs.org/api/directives.html#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` with `.prop` modifier shorthand.

### `{"version": "^2.6.0"}`

Expand Down Expand Up @@ -97,6 +99,7 @@ The `"ignores"` option accepts an array of the following strings.

## :books: Further Reading

- [API - v-memo](https://v3.vuejs.org/api/directives.html#v-memo)
- [API - v-is](https://v3.vuejs.org/api/directives.html#v-is)
- [API - v-is (Old)](https://github.com/vuejs/docs-next/blob/008613756c3d781128d96b64a2d27f7598f8f548/src/api/directives.md#v-is)
- [Guide - Dynamic Arguments](https://v3.vuejs.org/guide/template-syntax.html#dynamic-arguments)
Expand Down
19 changes: 12 additions & 7 deletions lib/rules/no-unsupported-features.js
Expand Up @@ -20,16 +20,18 @@ const FEATURES = {
// 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'),
// Vue.js 3.0.0+
'v-model-argument': require('./syntaxes/v-model-argument'),
'v-model-custom-modifiers': require('./syntaxes/v-model-custom-modifiers'),
'v-is': require('./syntaxes/v-is'),
'script-setup': require('./syntaxes/script-setup'),
'style-css-vars-injection': require('./syntaxes/style-css-vars-injection'),
// Vue.js 3.1.0+
'is-attribute-with-vue-prefix': require('./syntaxes/is-attribute-with-vue-prefix')
'is-attribute-with-vue-prefix': require('./syntaxes/is-attribute-with-vue-prefix'),
// Vue.js 3.2.0+
'v-memo': require('./syntaxes/v-memo'),
'v-bind-prop-modifier-shorthand': require('./syntaxes/v-bind-prop-modifier-shorthand'),
'v-bind-attr-modifier': require('./syntaxes/v-bind-attr-modifier')
}

const SYNTAX_NAMES = /** @type {(keyof FEATURES)[]} */ (Object.keys(FEATURES))
Expand Down Expand Up @@ -93,9 +95,6 @@ module.exports = {
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".',
// Vue.js 3.0.0+
forbiddenVModelArgument:
'Argument on `v-model` is not supported until Vue.js "3.0.0".',
Expand All @@ -108,7 +107,13 @@ module.exports = {
'SFC CSS variable injection is not supported until Vue.js "3.0.3".',
// Vue.js 3.1.0+
forbiddenIsAttributeWithVuePrefix:
'`is="vue:"` are not supported until Vue.js "3.1.0".'
'`is="vue:"` are not supported until Vue.js "3.1.0".',
// Vue.js 3.2.0+
forbiddenVMemo: '`v-memo` are not supported until Vue.js "3.2.0".',
forbiddenVBindPropModifierShorthand:
'`.prop` shorthand are not supported until Vue.js "3.2.0".',
forbiddenVBindAttrModifier:
'`.attr` modifiers on `v-bind` are not supported until Vue.js "3.2.0".'
}
},
/** @param {RuleContext} context */
Expand Down
32 changes: 32 additions & 0 deletions lib/rules/syntaxes/v-bind-attr-modifier.js
@@ -0,0 +1,32 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'

module.exports = {
supported: '>=3.2.0',
/** @param {RuleContext} context @returns {TemplateListener} */
createTemplateBodyVisitor(context) {
/**
* Reports `v-bind.attr` node
* @param { VIdentifier } mod node of `v-bind.attr`
* @returns {void}
*/
function report(mod) {
context.report({
node: mod,
messageId: 'forbiddenVBindAttrModifier'
})
}

return {
"VAttribute[directive=true][key.name.name='bind']"(node) {
const attrMod = node.key.modifiers.find((m) => m.name === 'attr')
if (attrMod) {
report(attrMod)
}
}
}
}
}
2 changes: 1 addition & 1 deletion lib/rules/syntaxes/v-bind-prop-modifier-shorthand.js
Expand Up @@ -5,7 +5,7 @@
'use strict'

module.exports = {
supported: '>=2.6.0-beta.1 <=2.6.0-beta.3',
supported: '>=3.2.0 || >=2.6.0-beta.1 <=2.6.0-beta.3',
/** @param {RuleContext} context @returns {TemplateListener} */
createTemplateBodyVisitor(context) {
/**
Expand Down
8 changes: 4 additions & 4 deletions lib/rules/syntaxes/v-is.js
Expand Up @@ -10,18 +10,18 @@ module.exports = {
createTemplateBodyVisitor(context) {
/**
* Reports `v-is` node
* @param {VDirective} vSlotAttr node of `v-is`
* @param {VDirective} vIsAttr node of `v-is`
* @returns {void}
*/
function reportVSlot(vSlotAttr) {
function reportVIs(vIsAttr) {
context.report({
node: vSlotAttr.key,
node: vIsAttr.key,
messageId: 'forbiddenVIs'
})
}

return {
"VAttribute[directive=true][key.name.name='is']": reportVSlot
"VAttribute[directive=true][key.name.name='is']": reportVIs
}
}
}
26 changes: 26 additions & 0 deletions lib/rules/syntaxes/v-memo.js
@@ -0,0 +1,26 @@
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
'use strict'
module.exports = {
supported: '>=3.2.0',
/** @param {RuleContext} context @returns {TemplateListener} */
createTemplateBodyVisitor(context) {
/**
* Reports `v-is` node
* @param {VDirective} vMemoAttr node of `v-is`
* @returns {void}
*/
function reportVMemo(vMemoAttr) {
context.report({
node: vMemoAttr.key,
messageId: 'forbiddenVMemo'
})
}

return {
"VAttribute[directive=true][key.name.name='memo']": reportVMemo
}
}
}
62 changes: 62 additions & 0 deletions tests/lib/rules/no-unsupported-features/v-bind-attr-modifier.js
@@ -0,0 +1,62 @@
/**
* @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-attr-modifier', '^3.1.0')
const tester = new RuleTester({
parser: require.resolve('vue-eslint-parser'),
parserOptions: {
ecmaVersion: 2019
}
})

tester.run('no-unsupported-features/v-bind-attr-modifier', rule, {
valid: [
{
code: `
<template>
<div :foo.attr="foo" />
</template>`,
options: buildOptions({ version: '^3.2.0' })
},
{
code: `
<template>
<div v-bind:attr="foo" />
</template>`,
options: buildOptions()
},
{
code: `
<template>
<div :foo.attr="foo" />
</template>`,
options: buildOptions({
version: '^2.5.0',
ignores: ['v-bind-attr-modifier']
})
}
],
invalid: [
{
code: `
<template>
<div :foo.attr="foo" />
</template>`,
options: buildOptions(),
errors: [
{
message:
'`.attr` modifiers on `v-bind` are not supported until Vue.js "3.2.0".',
line: 3
}
]
}
]
})
Expand Up @@ -28,6 +28,13 @@ tester.run('no-unsupported-features/v-bind-prop-modifier-shorthand', rule, {
</template>`,
options: buildOptions({ version: '2.6.0-beta.1' })
},
{
code: `
<template>
<a .href="'/xxx'" />
</template>`,
options: buildOptions({ version: '3.2.0' })
},
{
code: `
<template>
Expand Down Expand Up @@ -63,8 +70,7 @@ tester.run('no-unsupported-features/v-bind-prop-modifier-shorthand', rule, {
</template>`,
errors: [
{
message:
'`.prop` shorthand are not supported except Vue.js ">=2.6.0-beta.1 <=2.6.0-beta.3".',
message: '`.prop` shorthand are not supported until Vue.js "3.2.0".',
line: 3
}
]
Expand All @@ -81,8 +87,24 @@ tester.run('no-unsupported-features/v-bind-prop-modifier-shorthand', rule, {
</template>`,
errors: [
{
message:
'`.prop` shorthand are not supported except Vue.js ">=2.6.0-beta.1 <=2.6.0-beta.3".',
message: '`.prop` shorthand are not supported until Vue.js "3.2.0".',
line: 3
}
]
},
{
code: `
<template>
<a .href="'/xxx'" />
</template>`,
options: buildOptions({ version: '3.1.0' }),
output: `
<template>
<a :href.prop="'/xxx'" />
</template>`,
errors: [
{
message: '`.prop` shorthand are not supported until Vue.js "3.2.0".',
line: 3
}
]
Expand Down
58 changes: 58 additions & 0 deletions tests/lib/rules/no-unsupported-features/v-memo.js
@@ -0,0 +1,58 @@
/**
* @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-memo', '^3.1.0')
const tester = new RuleTester({
parser: require.resolve('vue-eslint-parser'),
parserOptions: {
ecmaVersion: 2019
}
})

tester.run('no-unsupported-features/v-memo', rule, {
valid: [
{
code: `
<template>
<div v-memo="foo" />
</template>`,
options: buildOptions({ version: '^3.2.0' })
},
{
code: `
<template>
<div :memo="foo" />
</template>`,
options: buildOptions()
},
{
code: `
<template>
<div v-memo="foo" />
</template>`,
options: buildOptions({ version: '^2.5.0', ignores: ['v-memo'] })
}
],
invalid: [
{
code: `
<template>
<div v-memo="foo" />
</template>`,
options: buildOptions(),
errors: [
{
message: '`v-memo` are not supported until Vue.js "3.2.0".',
line: 3
}
]
}
]
})

0 comments on commit 6a49210

Please sign in to comment.