11import * as CompilerDOM from '@vue/compiler-dom' ;
22import { camelize , capitalize } from '@vue/shared' ;
33import type { Code , VueCodeInformation } from '../../types' ;
4+ import { hyphenateTag } from '../../utils/shared' ;
45import { collectVars , createTsAst , endOfLine , newLine , variableNameRegex , wrapWith } from '../common' ;
56import { generateCamelized } from './camelized' ;
67import type { TemplateCodegenContext } from './context' ;
@@ -11,16 +12,15 @@ import { generateElementProps } from './elementProps';
1112import type { TemplateCodegenOptions } from './index' ;
1213import { generateInterpolation } from './interpolation' ;
1314import { generatePropertyAccess } from './propertyAccess' ;
14- import { generateStringLiteralKey } from './stringLiteralKey' ;
1515import { generateTemplateChild } from './templateChild' ;
1616
1717const colonReg = / : / g;
1818
19- export function * generateElement (
19+ export function * generateComponent (
2020 options : TemplateCodegenOptions ,
2121 ctx : TemplateCodegenContext ,
2222 node : CompilerDOM . ElementNode ,
23- currentElement : CompilerDOM . ElementNode | undefined ,
23+ currentComponent : CompilerDOM . ElementNode | undefined ,
2424 componentCtxVar : string | undefined ,
2525) : Generator < Code > {
2626 const startTagOffset = node . loc . start . offset + options . template . content . substring ( node . loc . start . offset ) . indexOf ( node . tag ) ;
@@ -29,8 +29,6 @@ export function* generateElement(
2929 const var_functionalComponent = ctx . getInternalVariable ( ) ;
3030 const var_componentInstance = ctx . getInternalVariable ( ) ;
3131 const var_componentEvents = ctx . getInternalVariable ( ) ;
32- const isIntrinsicElement = node . tagType === CompilerDOM . ElementTypes . ELEMENT
33- || node . tagType === CompilerDOM . ElementTypes . TEMPLATE ;
3432 const isComponentTag = node . tag . toLowerCase ( ) === 'component' ;
3533
3634 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(
6967 } ;
7068 }
7169
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 ) {
8271 yield `const ${ var_originalComponent } = ` ;
8372 yield * generateInterpolation (
8473 options ,
@@ -113,20 +102,15 @@ export function* generateElement(
113102 yield `const ${ var_originalComponent } = {} as any${ endOfLine } ` ;
114103 }
115104
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 } ` ;
124108
125109 if (
126110 ! dynamicTagInfo
127- && ! isIntrinsicElement
128111 && ! isComponentTag
129112 ) {
113+ // hover support
130114 for ( const offset of tagOffsets ) {
131115 yield `({} as { ${ getCanonicalComponentName ( tag ) } : typeof ${ var_originalComponent } }).` ;
132116 yield * generateCanonicalComponentName (
@@ -136,6 +120,45 @@ export function* generateElement(
136120 ) ;
137121 yield endOfLine ;
138122 }
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+ }
139162 }
140163
141164 if ( options . vueCompilerOptions . strictTemplates ) {
@@ -169,13 +192,89 @@ export function* generateElement(
169192 yield `)${ endOfLine } ` ;
170193 }
171194
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+ ) ;
176266 }
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 } ` ;
177277
178- //#region fix #1775
179278 for ( const failedExp of propsFailedExps ) {
180279 yield * generateInterpolation (
181280 options ,
@@ -190,6 +289,23 @@ export function* generateElement(
190289 yield endOfLine ;
191290 }
192291
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 > {
193309 const vScope = props . find ( prop => prop . type === CompilerDOM . NodeTypes . DIRECTIVE && ( prop . name === 'scope' || prop . name === 'data' ) ) ;
194310 let inScope = false ;
195311 let originalConditionsNum = ctx . blockConditions . length ;
@@ -217,31 +333,11 @@ export function* generateElement(
217333 if ( options . shouldGenerateScopedClasses ) {
218334 yield * generateReferencesForScopedCssClasses ( ctx , node ) ;
219335 }
220- if ( componentCtxVar ) {
221- ctx . usedComponentCtxVars . add ( componentCtxVar ) ;
222- yield * generateElementEvents ( options , ctx , node , var_functionalComponent , var_componentInstance , var_componentEvents , ( ) => usedComponentEventsVar = true ) ;
223- }
224336
225337 if ( inScope ) {
226338 yield `}${ newLine } ` ;
227339 ctx . blockConditions . length = originalConditionsNum ;
228340 }
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- }
245341}
246342
247343export function getCanonicalComponentName ( tagText : string ) {
@@ -282,13 +378,13 @@ function* generateComponentSlot(
282378 ctx : TemplateCodegenContext ,
283379 node : CompilerDOM . ElementNode ,
284380 slotDir : CompilerDOM . DirectiveNode ,
285- currentElement : CompilerDOM . ElementNode | undefined ,
381+ currentComponent : CompilerDOM . ElementNode | undefined ,
286382 componentCtxVar : string ,
287383) : Generator < Code > {
288384 yield `{${ newLine } ` ;
289385 ctx . usedComponentCtxVars . add ( componentCtxVar ) ;
290- if ( currentElement ) {
291- ctx . hasSlotElements . add ( currentElement ) ;
386+ if ( currentComponent ) {
387+ ctx . hasSlotElements . add ( currentComponent ) ;
292388 }
293389 const slotBlockVars : string [ ] = [ ] ;
294390 let hasProps = false ;
@@ -363,7 +459,7 @@ function* generateComponentSlot(
363459
364460 let prev : CompilerDOM . TemplateChildNode | undefined ;
365461 for ( const childNode of node . children ) {
366- yield * generateTemplateChild ( options , ctx , childNode , currentElement , prev , componentCtxVar ) ;
462+ yield * generateTemplateChild ( options , ctx , childNode , currentComponent , prev , componentCtxVar ) ;
367463 prev = childNode ;
368464 }
369465
@@ -464,3 +560,11 @@ function* generateReferencesForScopedCssClasses(
464560 }
465561 }
466562}
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