Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e9d20fd

Browse files
Add support for is="vue:" (Vue 3.1) (#1509)
* Add support `is="vue:"` (Vue 3.1) * update * update
1 parent 021fe2b commit e9d20fd

11 files changed

+209
-13
lines changed

‎docs/rules/no-unsupported-features.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ This rule reports unsupported Vue.js syntax on the specified version.
2929
- `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.
3030
- `ignores` ... You can use this `ignores` option to ignore the given features.
3131
The `"ignores"` option accepts an array of the following strings.
32+
- Vue.js 3.1.0+
33+
- `"is-attribute-with-vue-prefix"` ... [`is` attribute with `vue:` prefix](https://v3.vuejs.org/api/special-attributes.html#is)
3234
- Vue.js 3.0.0+
3335
- `"v-model-argument"` ... [argument on `v-model`][Vue RFCs - 0005-replace-v-bind-sync-with-v-model-argument]
3436
- `"v-model-custom-modifiers"` ... [custom modifiers on `v-model`][Vue RFCs - 0011-v-model-api-change]

‎lib/rules/no-deprecated-html-element-is.js‎

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,34 @@ module.exports = {
3131
},
3232
/** @param {RuleContext} context */
3333
create(context) {
34+
/** @param {VElement} node */
35+
function isValidElement(node) {
36+
return (
37+
!utils.isHtmlWellKnownElementName(node.rawName) &&
38+
!utils.isSvgWellKnownElementName(node.rawName)
39+
)
40+
}
3441
return utils.defineTemplateBodyVisitor(context, {
35-
/** @param {VDirective | VAttribute} node */
36-
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='is'], VAttribute[directive=false][key.name='is']"(
42+
/** @param {VDirective} node */
43+
"VAttribute[directive=true][key.name.name='bind'][key.argument.name='is']"(
3744
node
3845
) {
39-
const element = node.parent.parent
40-
if (
41-
!utils.isHtmlWellKnownElementName(element.rawName) &&
42-
!utils.isSvgWellKnownElementName(element.rawName)
43-
) {
46+
if (isValidElement(node.parent.parent)) {
47+
return
48+
}
49+
context.report({
50+
node,
51+
loc: node.loc,
52+
messageId: 'unexpected'
53+
})
54+
},
55+
/** @param {VAttribute} node */
56+
"VAttribute[directive=false][key.name='is']"(node) {
57+
if (isValidElement(node.parent.parent)) {
58+
return
59+
}
60+
if (node.value && node.value.value.startsWith('vue:')) {
61+
// Usage on native elements 3.1+
4462
return
4563
}
4664
context.report({

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,14 @@ module.exports = {
119119
/** @param {VAttribute} node */
120120
"VAttribute[directive=false][key.name='is']"(node) {
121121
if (
122-
!node.value || // `<component is />`
123-
utils.isHtmlWellKnownElementName(node.value.value)
122+
!node.value // `<component is />`
124123
)
125124
return
126-
usedComponentNodes.push({ node, name: node.value.value })
125+
const value = node.value.value.startsWith('vue:') // Usage on native elements 3.1+
126+
? node.value.value.slice(4)
127+
: node.value.value
128+
if (utils.isHtmlWellKnownElementName(value)) return
129+
usedComponentNodes.push({ node, name: value })
127130
},
128131
/** @param {VElement} node */
129132
"VElement[name='template'][parent.type='VDocumentFragment']:exit"() {

‎lib/rules/no-unsupported-features.js‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const FEATURES = {
2525
// Vue.js 3.0.0+
2626
'v-model-argument': require('./syntaxes/v-model-argument'),
2727
'v-model-custom-modifiers': require('./syntaxes/v-model-custom-modifiers'),
28-
'v-is': require('./syntaxes/v-is')
28+
'v-is': require('./syntaxes/v-is'),
29+
// Vue.js 3.1.0+
30+
'is-attribute-with-vue-prefix': require('./syntaxes/is-attribute-with-vue-prefix')
2931
}
3032

3133
const SYNTAX_NAMES = /** @type {(keyof FEATURES)[]} */ (Object.keys(FEATURES))
@@ -97,7 +99,9 @@ module.exports = {
9799
'Argument on `v-model` is not supported until Vue.js "3.0.0".',
98100
forbiddenVModelCustomModifiers:
99101
'Custom modifiers on `v-model` are not supported until Vue.js "3.0.0".',
100-
forbiddenVIs: '`v-is` are not supported until Vue.js "3.0.0".'
102+
forbiddenVIs: '`v-is` are not supported until Vue.js "3.0.0".',
103+
forbiddenIsAttributeWithVuePrefix:
104+
'`is="vue:"` are not supported until Vue.js "3.1.0".'
101105
}
102106
},
103107
/** @param {RuleContext} context */

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ module.exports = {
8888
if (!node.value) {
8989
return
9090
}
91-
usedComponents.add(node.value.value)
91+
const value = node.value.value.startsWith('vue:') // Usage on native elements 3.1+
92+
? node.value.value.slice(4)
93+
: node.value.value
94+
usedComponents.add(value)
9295
},
9396
/** @param {VElement} node */
9497
"VElement[name='template']"(node) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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.1.0',
8+
/** @param {RuleContext} context @returns {TemplateListener} */
9+
createTemplateBodyVisitor(context) {
10+
return {
11+
/** @param {VAttribute} node */
12+
"VAttribute[directive=false][key.name='is']"(node) {
13+
if (!node.value) {
14+
return
15+
}
16+
if (node.value.value.startsWith('vue:')) {
17+
context.report({
18+
node: node.value,
19+
messageId: 'forbiddenIsAttributeWithVuePrefix'
20+
})
21+
}
22+
}
23+
}
24+
}
25+
}

‎lib/rules/syntaxes/v-is.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
'use strict'
66
module.exports = {
7+
deprecated: '3.1.0',
78
supported: '>=3.0.0',
89
/** @param {RuleContext} context @returns {TemplateListener} */
910
createTemplateBodyVisitor(context) {

‎tests/lib/rules/no-deprecated-html-element-is.js‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ ruleTester.run('no-deprecated-html-element-is', rule, {
3737
{
3838
filename: 'test.vue',
3939
code: '<template><component :is="\'foo\'" /></template>'
40+
},
41+
42+
// is="vue:xxx"
43+
{
44+
filename: 'test.vue',
45+
code: '<template><div is="vue:foo" /></template>'
4046
}
4147
],
4248

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,19 @@ tester.run('no-unregistered-components', rule, {
446446
</script>
447447
`
448448
},
449+
{
450+
filename: 'test.vue',
451+
code: `
452+
<template>
453+
<component is="vue:CustomComponent" />
454+
</template>
455+
<script>
456+
export default {
457+
name: 'CustomComponent'
458+
}
459+
</script>
460+
`
461+
},
449462
{
450463
filename: 'test.vue',
451464
code: `
@@ -706,6 +719,48 @@ tester.run('no-unregistered-components', rule, {
706719
line: 3
707720
}
708721
]
722+
},
723+
{
724+
filename: 'test.vue',
725+
code: `
726+
<template>
727+
<div is="vue:foo" />
728+
</template>
729+
<script>
730+
export default {
731+
components: {
732+
bar
733+
}
734+
}
735+
</script>
736+
`,
737+
errors: [
738+
{
739+
message: 'The "foo" component has been used but not registered.',
740+
line: 3
741+
}
742+
]
743+
},
744+
{
745+
filename: 'test.vue',
746+
code: `
747+
<template>
748+
<div v-is="'foo'" />
749+
</template>
750+
<script>
751+
export default {
752+
components: {
753+
bar
754+
}
755+
}
756+
</script>
757+
`,
758+
errors: [
759+
{
760+
message: 'The "foo" component has been used but not registered.',
761+
line: 3
762+
}
763+
]
709764
}
710765
]
711766
})
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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(
12+
'is-attribute-with-vue-prefix',
13+
'^3.1.0'
14+
)
15+
const tester = new RuleTester({
16+
parser: require.resolve('vue-eslint-parser'),
17+
parserOptions: {
18+
ecmaVersion: 2019
19+
}
20+
})
21+
22+
tester.run('no-unsupported-features/is-attribute-with-vue-prefix', rule, {
23+
valid: [
24+
{
25+
code: `
26+
<template>
27+
<div is="vue:foo" />
28+
</template>`,
29+
options: buildOptions()
30+
},
31+
{
32+
code: `
33+
<template>
34+
<div is="foo" />
35+
</template>`,
36+
options: buildOptions({ version: '^2.5.0' })
37+
},
38+
{
39+
code: `
40+
<template>
41+
<div is="vue:foo" />
42+
</template>`,
43+
options: buildOptions({
44+
version: '^2.5.0',
45+
ignores: ['is-attribute-with-vue-prefix']
46+
})
47+
}
48+
],
49+
invalid: [
50+
{
51+
code: `
52+
<template>
53+
<div is="vue:foo" />
54+
</template>`,
55+
options: buildOptions({ version: '^3.0.0' }),
56+
errors: [
57+
{
58+
message: '`is="vue:"` are not supported until Vue.js "3.1.0".',
59+
line: 3
60+
}
61+
]
62+
}
63+
]
64+
})

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /