1
1
import { isValidHTMLNesting } from '../html-nesting'
2
2
import {
3
3
type AttributeNode ,
4
+ type ComponentNode ,
4
5
type ElementNode ,
5
6
ElementTypes ,
6
7
ErrorCodes ,
7
8
NodeTypes ,
9
+ type PlainElementNode ,
8
10
type SimpleExpressionNode ,
9
11
createCompilerError ,
10
12
createSimpleExpression ,
13
+ isStaticArgOf ,
11
14
} from '@vue/compiler-dom'
12
15
import {
13
16
camelize ,
@@ -33,6 +36,7 @@ import {
33
36
type VaporDirectiveNode ,
34
37
} from '../ir'
35
38
import { EMPTY_EXPRESSION } from './utils'
39
+ import { findProp } from '../utils'
36
40
37
41
export const isReservedProp : ( key : string ) => boolean = /*#__PURE__*/ makeMap (
38
42
// the leading comma is intentional so empty string "" is also included
@@ -51,46 +55,56 @@ export const transformElement: NodeTransform = (node, context) => {
51
55
)
52
56
return
53
57
54
- const { tag , tagType } = node
55
- const isComponent = tagType === ElementTypes . COMPONENT
58
+ const isComponent = node . tagType === ElementTypes . COMPONENT
59
+ const isDynamicComponent = isComponentTag ( node . tag )
56
60
const propsResult = buildProps (
57
61
node ,
58
62
context as TransformContext < ElementNode > ,
59
63
isComponent ,
64
+ isDynamicComponent ,
60
65
)
61
66
62
67
; ( isComponent ? transformComponentElement : transformNativeElement ) (
63
- tag ,
68
+ node as any ,
64
69
propsResult ,
65
70
context as TransformContext < ElementNode > ,
71
+ isDynamicComponent ,
66
72
)
67
73
}
68
74
}
69
75
70
76
function transformComponentElement (
71
- tag : string ,
77
+ node : ComponentNode ,
72
78
propsResult : PropsResult ,
73
79
context : TransformContext ,
80
+ isDynamicComponent : boolean ,
74
81
) {
75
- let asset = true
82
+ const dynamicComponent = isDynamicComponent
83
+ ? resolveDynamicComponent ( node )
84
+ : undefined
76
85
77
- const fromSetup = resolveSetupReference ( tag , context )
78
- if ( fromSetup ) {
79
- tag = fromSetup
80
- asset = false
81
- }
86
+ let { tag } = node
87
+ let asset = true
82
88
83
- const dotIndex = tag . indexOf ( '.' )
84
- if ( dotIndex > 0 ) {
85
- const ns = resolveSetupReference ( tag . slice ( 0 , dotIndex ) , context )
86
- if ( ns ) {
87
- tag = ns + tag . slice ( dotIndex )
89
+ if ( ! dynamicComponent ) {
90
+ const fromSetup = resolveSetupReference ( tag , context )
91
+ if ( fromSetup ) {
92
+ tag = fromSetup
88
93
asset = false
89
94
}
90
- }
91
95
92
- if ( asset ) {
93
- context . component . add ( tag )
96
+ const dotIndex = tag . indexOf ( '.' )
97
+ if ( dotIndex > 0 ) {
98
+ const ns = resolveSetupReference ( tag . slice ( 0 , dotIndex ) , context )
99
+ if ( ns ) {
100
+ tag = ns + tag . slice ( dotIndex )
101
+ asset = false
102
+ }
103
+ }
104
+
105
+ if ( asset ) {
106
+ context . component . add ( tag )
107
+ }
94
108
}
95
109
96
110
context . dynamic . flags |= DynamicFlag . NON_TEMPLATE | DynamicFlag . INSERT
@@ -106,10 +120,28 @@ function transformComponentElement(
106
120
root,
107
121
slots : [ ...context . slots ] ,
108
122
once : context . inVOnce ,
123
+ dynamic : dynamicComponent ,
109
124
} )
110
125
context . slots = [ ]
111
126
}
112
127
128
+ function resolveDynamicComponent ( node : ComponentNode ) {
129
+ const isProp = findProp ( node , 'is' , false , true /* allow empty */ )
130
+ if ( ! isProp ) return
131
+
132
+ if ( isProp . type === NodeTypes . ATTRIBUTE ) {
133
+ return isProp . value && createSimpleExpression ( isProp . value . content , true )
134
+ } else {
135
+ return (
136
+ isProp . exp ||
137
+ // #10469 handle :is shorthand
138
+ extend ( createSimpleExpression ( `is` , false , isProp . arg ! . loc ) , {
139
+ ast : null ,
140
+ } )
141
+ )
142
+ }
143
+ }
144
+
113
145
function resolveSetupReference ( name : string , context : TransformContext ) {
114
146
const bindings = context . options . bindingMetadata
115
147
if ( ! bindings || bindings . __isScriptSetup === false ) {
@@ -128,10 +160,11 @@ function resolveSetupReference(name: string, context: TransformContext) {
128
160
}
129
161
130
162
function transformNativeElement (
131
- tag : string ,
163
+ node : PlainElementNode ,
132
164
propsResult : PropsResult ,
133
165
context : TransformContext < ElementNode > ,
134
166
) {
167
+ const { tag } = node
135
168
const { scopeId } = context . options
136
169
137
170
let template = ''
@@ -189,6 +222,7 @@ export function buildProps(
189
222
node : ElementNode ,
190
223
context : TransformContext < ElementNode > ,
191
224
isComponent : boolean ,
225
+ isDynamicComponent : boolean ,
192
226
) : PropsResult {
193
227
const props = node . props as ( VaporDirectiveNode | AttributeNode ) [ ]
194
228
if ( props . length === 0 ) return [ false , [ ] ]
@@ -252,6 +286,18 @@ export function buildProps(
252
286
}
253
287
}
254
288
289
+ // exclude `is` prop for <component>
290
+ if (
291
+ ( isDynamicComponent &&
292
+ prop . type === NodeTypes . ATTRIBUTE &&
293
+ prop . name === 'is' ) ||
294
+ ( prop . type === NodeTypes . DIRECTIVE &&
295
+ prop . name === 'bind' &&
296
+ isStaticArgOf ( prop . arg , 'is' ) )
297
+ ) {
298
+ continue
299
+ }
300
+
255
301
const result = transformProp ( prop , node , context )
256
302
if ( result ) {
257
303
dynamicExpr . push ( result . key , result . value )
@@ -362,3 +408,7 @@ function mergePropValues(existing: IRProp, incoming: IRProp) {
362
408
const newValues = incoming . values
363
409
existing . values . push ( ...newValues )
364
410
}
411
+
412
+ function isComponentTag ( tag : string ) {
413
+ return tag === 'component' || tag === 'Component'
414
+ }
0 commit comments