1
1
import * as CompilerDOM from '@vue/compiler-dom' ;
2
2
import { camelize , capitalize } from '@vue/shared' ;
3
3
import type { Code , VueCodeInformation } from '../../types' ;
4
+ import { hyphenateTag } from '../../utils/shared' ;
4
5
import { collectVars , createTsAst , endOfLine , newLine , variableNameRegex , wrapWith } from '../common' ;
5
6
import { generateCamelized } from './camelized' ;
6
7
import type { TemplateCodegenContext } from './context' ;
@@ -11,16 +12,15 @@ import { generateElementProps } from './elementProps';
11
12
import type { TemplateCodegenOptions } from './index' ;
12
13
import { generateInterpolation } from './interpolation' ;
13
14
import { generatePropertyAccess } from './propertyAccess' ;
14
- import { generateStringLiteralKey } from './stringLiteralKey' ;
15
15
import { generateTemplateChild } from './templateChild' ;
16
16
17
17
const colonReg = / : / g;
18
18
19
- export function * generateElement (
19
+ export function * generateComponent (
20
20
options : TemplateCodegenOptions ,
21
21
ctx : TemplateCodegenContext ,
22
22
node : CompilerDOM . ElementNode ,
23
- currentElement : CompilerDOM . ElementNode | undefined ,
23
+ currentComponent : CompilerDOM . ElementNode | undefined ,
24
24
componentCtxVar : string | undefined ,
25
25
) : Generator < Code > {
26
26
const startTagOffset = node . loc . start . offset + options . template . content . substring ( node . loc . start . offset ) . indexOf ( node . tag ) ;
@@ -29,8 +29,6 @@ export function* generateElement(
29
29
const var_functionalComponent = ctx . getInternalVariable ( ) ;
30
30
const var_componentInstance = ctx . getInternalVariable ( ) ;
31
31
const var_componentEvents = ctx . getInternalVariable ( ) ;
32
- const isIntrinsicElement = node . tagType === CompilerDOM . ElementTypes . ELEMENT
33
- || node . tagType === CompilerDOM . ElementTypes . TEMPLATE ;
34
32
const isComponentTag = node . tag . toLowerCase ( ) === 'component' ;
35
33
36
34
let endTagOffset = ! node . isSelfClosing && options . template . lang === 'html' ? node . loc . start . offset + node . loc . source . lastIndexOf ( node . tag ) : undefined ;
@@ -69,16 +67,7 @@ export function* generateElement(
69
67
} ;
70
68
}
71
69
72
- if ( isIntrinsicElement ) {
73
- yield `const ${ var_originalComponent } = __VLS_intrinsicElements[` ;
74
- yield * generateStringLiteralKey (
75
- tag ,
76
- startTagOffset ,
77
- ctx . codeFeatures . verification ,
78
- ) ;
79
- yield `]${ endOfLine } ` ;
80
- }
81
- else if ( dynamicTagInfo ) {
70
+ if ( dynamicTagInfo ) {
82
71
yield `const ${ var_originalComponent } = ` ;
83
72
yield * generateInterpolation (
84
73
options ,
@@ -113,20 +102,15 @@ export function* generateElement(
113
102
yield `const ${ var_originalComponent } = {} as any${ endOfLine } ` ;
114
103
}
115
104
116
- if ( isIntrinsicElement ) {
117
- yield `const ${ var_functionalComponent } = __VLS_elementAsFunctionalComponent(${ var_originalComponent } )${ endOfLine } ` ;
118
- }
119
- else {
120
- yield `const ${ var_functionalComponent } = __VLS_asFunctionalComponent(${ var_originalComponent } , new ${ var_originalComponent } ({` ;
121
- yield * generateElementProps ( options , ctx , node , props , false ) ;
122
- yield `}))${ endOfLine } ` ;
123
- }
105
+ yield `const ${ var_functionalComponent } = __VLS_asFunctionalComponent(${ var_originalComponent } , new ${ var_originalComponent } ({` ;
106
+ yield * generateElementProps ( options , ctx , node , props , false ) ;
107
+ yield `}))${ endOfLine } ` ;
124
108
125
109
if (
126
110
! dynamicTagInfo
127
- && ! isIntrinsicElement
128
111
&& ! isComponentTag
129
112
) {
113
+ // hover support
130
114
for ( const offset of tagOffsets ) {
131
115
yield `({} as { ${ getCanonicalComponentName ( tag ) } : typeof ${ var_originalComponent } }).` ;
132
116
yield * generateCanonicalComponentName (
@@ -136,6 +120,45 @@ export function* generateElement(
136
120
) ;
137
121
yield endOfLine ;
138
122
}
123
+ const camelizedTag = camelize ( node . tag ) ;
124
+ if ( variableNameRegex . test ( camelizedTag ) ) {
125
+ // renaming / find references support
126
+ for ( const tagOffset of tagOffsets ) {
127
+ for ( const shouldCapitalize of ( node . tag [ 0 ] === node . tag [ 0 ] . toUpperCase ( ) ? [ false ] : [ true , false ] ) ) {
128
+ const expectName = shouldCapitalize ? capitalize ( camelizedTag ) : camelizedTag ;
129
+ yield `__VLS_components.` ;
130
+ yield * generateCamelized (
131
+ shouldCapitalize ? capitalize ( node . tag ) : node . tag ,
132
+ tagOffset ,
133
+ {
134
+ navigation : {
135
+ resolveRenameNewName : node . tag !== expectName ? camelizeComponentName : undefined ,
136
+ resolveRenameEditText : getTagRenameApply ( node . tag ) ,
137
+ } ,
138
+ } as VueCodeInformation ,
139
+ ) ;
140
+ yield `;` ;
141
+ }
142
+ }
143
+ yield `${ newLine } ` ;
144
+ // auto import support
145
+ yield `// @ts-ignore${ newLine } ` ; // #2304
146
+ yield `[` ;
147
+ for ( const tagOffset of tagOffsets ) {
148
+ yield * generateCamelized (
149
+ capitalize ( node . tag ) ,
150
+ tagOffset ,
151
+ {
152
+ completion : {
153
+ isAdditional : true ,
154
+ onlyImport : true ,
155
+ } ,
156
+ } as VueCodeInformation ,
157
+ ) ;
158
+ yield `,` ;
159
+ }
160
+ yield `]${ endOfLine } ` ;
161
+ }
139
162
}
140
163
141
164
if ( options . vueCompilerOptions . strictTemplates ) {
@@ -169,13 +192,89 @@ export function* generateElement(
169
192
yield `)${ endOfLine } ` ;
170
193
}
171
194
172
- if ( node . tagType !== CompilerDOM . ElementTypes . TEMPLATE ) {
173
- defineComponentCtxVar = ctx . getInternalVariable ( ) ;
174
- componentCtxVar = defineComponentCtxVar ;
175
- currentElement = node ;
195
+ defineComponentCtxVar = ctx . getInternalVariable ( ) ;
196
+ componentCtxVar = defineComponentCtxVar ;
197
+ currentComponent = node ;
198
+
199
+ for ( const failedExp of propsFailedExps ) {
200
+ yield * generateInterpolation (
201
+ options ,
202
+ ctx ,
203
+ failedExp . loc . source ,
204
+ failedExp . loc ,
205
+ failedExp . loc . start . offset ,
206
+ ctx . codeFeatures . all ,
207
+ '(' ,
208
+ ')' ,
209
+ ) ;
210
+ yield endOfLine ;
211
+ }
212
+
213
+ yield * generateVScope ( options , ctx , node , props ) ;
214
+
215
+ if ( componentCtxVar ) {
216
+ ctx . usedComponentCtxVars . add ( componentCtxVar ) ;
217
+ yield * generateElementEvents ( options , ctx , node , var_functionalComponent , var_componentInstance , var_componentEvents , ( ) => usedComponentEventsVar = true ) ;
218
+ }
219
+
220
+ const slotDir = node . props . find ( p => p . type === CompilerDOM . NodeTypes . DIRECTIVE && p . name === 'slot' ) as CompilerDOM . DirectiveNode ;
221
+ if ( slotDir && componentCtxVar ) {
222
+ yield * generateComponentSlot ( options , ctx , node , slotDir , currentComponent , componentCtxVar ) ;
223
+ }
224
+ else {
225
+ yield * generateElementChildren ( options , ctx , node , currentComponent , componentCtxVar ) ;
226
+ }
227
+
228
+ if ( defineComponentCtxVar && ctx . usedComponentCtxVars . has ( defineComponentCtxVar ) ) {
229
+ yield `const ${ componentCtxVar } = __VLS_pickFunctionalComponentCtx(${ var_originalComponent } , ${ var_componentInstance } )!${ endOfLine } ` ;
230
+ }
231
+ if ( usedComponentEventsVar ) {
232
+ yield `let ${ var_componentEvents } !: __VLS_NormalizeEmits<typeof ${ componentCtxVar } .emit>${ endOfLine } ` ;
233
+ }
234
+ }
235
+
236
+ export function * generateElement (
237
+ options : TemplateCodegenOptions ,
238
+ ctx : TemplateCodegenContext ,
239
+ node : CompilerDOM . ElementNode ,
240
+ currentComponent : CompilerDOM . ElementNode | undefined ,
241
+ componentCtxVar : string | undefined ,
242
+ ) : Generator < Code > {
243
+ const startTagOffset = node . loc . start . offset + options . template . content . substring ( node . loc . start . offset ) . indexOf ( node . tag ) ;
244
+ const endTagOffset = ! node . isSelfClosing && options . template . lang === 'html'
245
+ ? node . loc . start . offset + node . loc . source . lastIndexOf ( node . tag )
246
+ : undefined ;
247
+ const propsFailedExps : CompilerDOM . SimpleExpressionNode [ ] = [ ] ;
248
+
249
+ yield `__VLS_elementAsFunction(__VLS_intrinsicElements` ;
250
+ yield * generatePropertyAccess (
251
+ options ,
252
+ ctx ,
253
+ node . tag ,
254
+ startTagOffset ,
255
+ ctx . codeFeatures . withoutHighlightAndCompletion ,
256
+ ) ;
257
+ if ( endTagOffset !== undefined ) {
258
+ yield `, __VLS_intrinsicElements` ;
259
+ yield * generatePropertyAccess (
260
+ options ,
261
+ ctx ,
262
+ node . tag ,
263
+ endTagOffset ,
264
+ ctx . codeFeatures . withoutHighlightAndCompletion ,
265
+ ) ;
176
266
}
267
+ yield `)(` ;
268
+ yield * wrapWith (
269
+ startTagOffset ,
270
+ startTagOffset + node . tag . length ,
271
+ ctx . codeFeatures . verification ,
272
+ `{` ,
273
+ ...generateElementProps ( options , ctx , node , node . props , true , propsFailedExps ) ,
274
+ `}` ,
275
+ ) ;
276
+ yield `)${ endOfLine } ` ;
177
277
178
- //#region fix #1775
179
278
for ( const failedExp of propsFailedExps ) {
180
279
yield * generateInterpolation (
181
280
options ,
@@ -190,6 +289,23 @@ export function* generateElement(
190
289
yield endOfLine ;
191
290
}
192
291
292
+ yield * generateVScope ( options , ctx , node , node . props ) ;
293
+
294
+ const slotDir = node . props . find ( p => p . type === CompilerDOM . NodeTypes . DIRECTIVE && p . name === 'slot' ) as CompilerDOM . DirectiveNode ;
295
+ if ( slotDir && componentCtxVar ) {
296
+ yield * generateComponentSlot ( options , ctx , node , slotDir , currentComponent , componentCtxVar ) ;
297
+ }
298
+ else {
299
+ yield * generateElementChildren ( options , ctx , node , currentComponent , componentCtxVar ) ;
300
+ }
301
+ }
302
+
303
+ function * generateVScope (
304
+ options : TemplateCodegenOptions ,
305
+ ctx : TemplateCodegenContext ,
306
+ node : CompilerDOM . ElementNode ,
307
+ props : ( CompilerDOM . AttributeNode | CompilerDOM . DirectiveNode ) [ ] ,
308
+ ) : Generator < Code > {
193
309
const vScope = props . find ( prop => prop . type === CompilerDOM . NodeTypes . DIRECTIVE && ( prop . name === 'scope' || prop . name === 'data' ) ) ;
194
310
let inScope = false ;
195
311
let originalConditionsNum = ctx . blockConditions . length ;
@@ -217,31 +333,11 @@ export function* generateElement(
217
333
if ( options . shouldGenerateScopedClasses ) {
218
334
yield * generateReferencesForScopedCssClasses ( ctx , node ) ;
219
335
}
220
- if ( componentCtxVar ) {
221
- ctx . usedComponentCtxVars . add ( componentCtxVar ) ;
222
- yield * generateElementEvents ( options , ctx , node , var_functionalComponent , var_componentInstance , var_componentEvents , ( ) => usedComponentEventsVar = true ) ;
223
- }
224
336
225
337
if ( inScope ) {
226
338
yield `}${ newLine } ` ;
227
339
ctx . blockConditions . length = originalConditionsNum ;
228
340
}
229
- //#endregion
230
-
231
- const slotDir = node . props . find ( p => p . type === CompilerDOM . NodeTypes . DIRECTIVE && p . name === 'slot' ) as CompilerDOM . DirectiveNode ;
232
- if ( slotDir && componentCtxVar ) {
233
- yield * generateComponentSlot ( options , ctx , node , slotDir , currentElement , componentCtxVar ) ;
234
- }
235
- else {
236
- yield * generateElementChildren ( options , ctx , node , currentElement , componentCtxVar ) ;
237
- }
238
-
239
- if ( defineComponentCtxVar && ctx . usedComponentCtxVars . has ( defineComponentCtxVar ) ) {
240
- yield `const ${ componentCtxVar } = __VLS_pickFunctionalComponentCtx(${ var_originalComponent } , ${ var_componentInstance } )!${ endOfLine } ` ;
241
- }
242
- if ( usedComponentEventsVar ) {
243
- yield `let ${ var_componentEvents } !: __VLS_NormalizeEmits<typeof ${ componentCtxVar } .emit>${ endOfLine } ` ;
244
- }
245
341
}
246
342
247
343
export function getCanonicalComponentName ( tagText : string ) {
@@ -282,13 +378,13 @@ function* generateComponentSlot(
282
378
ctx : TemplateCodegenContext ,
283
379
node : CompilerDOM . ElementNode ,
284
380
slotDir : CompilerDOM . DirectiveNode ,
285
- currentElement : CompilerDOM . ElementNode | undefined ,
381
+ currentComponent : CompilerDOM . ElementNode | undefined ,
286
382
componentCtxVar : string ,
287
383
) : Generator < Code > {
288
384
yield `{${ newLine } ` ;
289
385
ctx . usedComponentCtxVars . add ( componentCtxVar ) ;
290
- if ( currentElement ) {
291
- ctx . hasSlotElements . add ( currentElement ) ;
386
+ if ( currentComponent ) {
387
+ ctx . hasSlotElements . add ( currentComponent ) ;
292
388
}
293
389
const slotBlockVars : string [ ] = [ ] ;
294
390
let hasProps = false ;
@@ -363,7 +459,7 @@ function* generateComponentSlot(
363
459
364
460
let prev : CompilerDOM . TemplateChildNode | undefined ;
365
461
for ( const childNode of node . children ) {
366
- yield * generateTemplateChild ( options , ctx , childNode , currentElement , prev , componentCtxVar ) ;
462
+ yield * generateTemplateChild ( options , ctx , childNode , currentComponent , prev , componentCtxVar ) ;
367
463
prev = childNode ;
368
464
}
369
465
@@ -464,3 +560,11 @@ function* generateReferencesForScopedCssClasses(
464
560
}
465
561
}
466
562
}
563
+
564
+ function camelizeComponentName ( newName : string ) {
565
+ return camelize ( '-' + newName ) ;
566
+ }
567
+
568
+ function getTagRenameApply ( oldName : string ) {
569
+ return oldName === hyphenateTag ( oldName ) ? hyphenateTag : undefined ;
570
+ }
0 commit comments