Skip to content

Commit e1c87a1

Browse files
authored
Change the rules to support "v-is". (#1254)
* Change the rules to support "v-is". - Change the `vue/attributes-order` rule to handle `v-is` as `DEFINITION` category. - Change the `vue/no-unregistered-components` rule to handle `v-is` like `:is`. - Change the `vue/no-unused-components` rule to handle `v-is` like `:is`. * Add `"v-is"` to the syntax checked by the `vue/no-unsupported-features` rule.
1 parent f626498 commit e1c87a1

12 files changed

+138
-6
lines changed

docs/rules/attributes-order.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ description: enforce order of attributes
1515
This rule aims to enforce ordering of component attributes. The default order is specified in the [Vue styleguide](https://v3.vuejs.org/style-guide/#element-attribute-order-recommended) and is:
1616

1717
- `DEFINITION`
18-
e.g. 'is'
18+
e.g. 'is', 'v-is'
1919
- `LIST_RENDERING`
2020
e.g. 'v-for item in items'
2121
- `CONDITIONALS`

docs/rules/no-unsupported-features.md

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ The `"ignores"` option accepts an array of the following strings.
3030
- Vue.js 3.0.0+
3131
- `"v-model-argument"` ... [argument on `v-model`][Vue RFCs - 0005-replace-v-bind-sync-with-v-model-argument]
3232
- `"v-model-custom-modifiers"` ... [custom modifiers on `v-model`][Vue RFCs - 0011-v-model-api-change]
33+
- `"v-id"` ... [v-is](https://v3.vuejs.org/api/directives.html#v-is) directive.
3334
- Vue.js 2.6.0+
3435
- `"dynamic-directive-arguments"` ... [dynamic directive arguments](https://v3.vuejs.org/guide/template-syntax.html#dynamic-arguments).
3536
- `"v-slot"` ... [v-slot](https://v3.vuejs.org/api/directives.html#v-slot) directive.
@@ -90,6 +91,7 @@ The `"ignores"` option accepts an array of the following strings.
9091

9192
## :books: Further Reading
9293

94+
- [API - v-is](https://v3.vuejs.org/api/directives.html#v-is)
9395
- [Guide - Dynamic Arguments](https://v3.vuejs.org/guide/template-syntax.html#dynamic-arguments)
9496
- [API - v-slot](https://v3.vuejs.org/api/directives.html#v-slot)
9597
- [API (for v2) - slot-scope](https://vuejs.org/v2/api/#slot-scope-deprecated)

lib/rules/attributes-order.js

+2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ function getAttributeType(attribute, sourceCode) {
8484
return ATTRS.CONTENT
8585
} else if (name === 'slot') {
8686
return ATTRS.UNIQUE
87+
} else if (name === 'is') {
88+
return ATTRS.DEFINITION
8789
} else {
8890
return ATTRS.OTHER_DIRECTIVES
8991
}

lib/rules/no-unregistered-components.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ module.exports = {
9595
usedComponentNodes.push({ node, name: node.rawName })
9696
},
9797
/** @param {VDirective} node */
98-
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='is']"(
98+
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='is'], VAttribute[directive=true][key.name.name='is']"(
9999
node
100100
) {
101101
if (

lib/rules/no-unsupported-features.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ const FEATURES = {
2424
'v-bind-prop-modifier-shorthand': require('./syntaxes/v-bind-prop-modifier-shorthand'),
2525
// Vue.js 3.0.0+
2626
'v-model-argument': require('./syntaxes/v-model-argument'),
27-
'v-model-custom-modifiers': require('./syntaxes/v-model-custom-modifiers')
27+
'v-model-custom-modifiers': require('./syntaxes/v-model-custom-modifiers'),
28+
'v-is': require('./syntaxes/v-is')
2829
}
2930

3031
const cache = new Map()
@@ -93,7 +94,8 @@ module.exports = {
9394
forbiddenVModelArgument:
9495
'Argument on `v-model` is not supported until Vue.js "3.0.0".',
9596
forbiddenVModelCustomModifiers:
96-
'Custom modifiers on `v-model` are not supported until Vue.js "3.0.0".'
97+
'Custom modifiers on `v-model` are not supported until Vue.js "3.0.0".',
98+
forbiddenVIs: '`v-is` are not supported until Vue.js "3.0.0".'
9799
}
98100
},
99101
/** @param {RuleContext} context */

lib/rules/no-unused-components.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ module.exports = {
6767
usedComponents.add(node.rawName)
6868
},
6969
/** @param {VDirective} node */
70-
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='is']"(
70+
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='is'], VAttribute[directive=true][key.name.name='is']"(
7171
node
7272
) {
7373
if (

lib/rules/syntaxes/v-is.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @author Yosuke Ota
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
module.exports = {
7+
supported: '3.0.0',
8+
/** @param {RuleContext} context @returns {TemplateListener} */
9+
createTemplateBodyVisitor(context) {
10+
/**
11+
* Reports `v-is` node
12+
* @param {VDirective} vSlotAttr node of `v-is`
13+
* @returns {void}
14+
*/
15+
function reportVSlot(vSlotAttr) {
16+
context.report({
17+
node: vSlotAttr.key,
18+
messageId: 'forbiddenVIs'
19+
})
20+
}
21+
22+
return {
23+
"VAttribute[directive=true][key.name.name='is']": reportVSlot
24+
}
25+
}
26+
}

lib/utils/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,8 @@ module.exports = {
578578
(this.isHtmlElementNode(node) &&
579579
!this.isHtmlWellKnownElementName(node.rawName)) ||
580580
this.hasAttribute(node, 'is') ||
581-
this.hasDirective(node, 'bind', 'is')
581+
this.hasDirective(node, 'bind', 'is') ||
582+
this.hasDirective(node, 'is')
582583
)
583584
},
584585

tests/lib/rules/attributes-order.js

+11
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,17 @@ tester.run('attributes-order', rule, {
932932
message: 'Attribute "v-foo.a" should go before "v-foo.b".'
933933
}
934934
]
935+
},
936+
937+
{
938+
filename: 'test.vue',
939+
code: '<template><div v-cloak v-is="foo"></div></template>',
940+
output: '<template><div v-is="foo" v-cloak></div></template>',
941+
errors: [
942+
{
943+
message: 'Attribute "v-is" should go before "v-cloak".'
944+
}
945+
]
935946
}
936947
]
937948
})

tests/lib/rules/no-unregistered-components.js

+15
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,21 @@ tester.run('no-unregistered-components', rule, {
378378
<Component is />
379379
</template>
380380
`
381+
},
382+
{
383+
filename: 'test.vue',
384+
code: `
385+
<template>
386+
<div v-is="'CustomComponent'" />
387+
</template>
388+
<script>
389+
export default {
390+
components: {
391+
CustomComponent
392+
}
393+
}
394+
</script>
395+
`
381396
}
382397
],
383398
invalid: [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* @author Yosuke Ota
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const RuleTester = require('eslint').RuleTester
8+
const rule = require('../../../../lib/rules/no-unsupported-features')
9+
const utils = require('./utils')
10+
11+
const buildOptions = utils.optionsBuilder('v-is', '^2.6.0')
12+
const tester = new RuleTester({
13+
parser: require.resolve('vue-eslint-parser'),
14+
parserOptions: {
15+
ecmaVersion: 2019
16+
}
17+
})
18+
19+
tester.run('no-unsupported-features/v-is', rule, {
20+
valid: [
21+
{
22+
code: `
23+
<template>
24+
<div v-is="foo" />
25+
</template>`,
26+
options: buildOptions({ version: '^3.0.0' })
27+
},
28+
{
29+
code: `
30+
<template>
31+
<div :is="foo" />
32+
</template>`,
33+
options: buildOptions()
34+
},
35+
{
36+
code: `
37+
<template>
38+
<div v-is="foo" />
39+
</template>`,
40+
options: buildOptions({ version: '^2.5.0', ignores: ['v-is'] })
41+
}
42+
],
43+
invalid: [
44+
{
45+
code: `
46+
<template>
47+
<div v-is="foo" />
48+
</template>`,
49+
options: buildOptions(),
50+
errors: [
51+
{
52+
message: '`v-is` are not supported until Vue.js "3.0.0".',
53+
line: 3
54+
}
55+
]
56+
}
57+
]
58+
})

tests/lib/rules/no-unused-components.js

+15
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,21 @@ tester.run('no-unused-components', rule, {
471471
}
472472
}
473473
</script>`
474+
},
475+
{
476+
filename: 'test.vue',
477+
code: `
478+
<template>
479+
<div v-is="'CustomComponent'" />
480+
</template>
481+
<script>
482+
export default {
483+
components: {
484+
CustomComponent
485+
}
486+
}
487+
</script>
488+
`
474489
}
475490
],
476491
invalid: [

0 commit comments

Comments
 (0)