@@ -133,38 +133,27 @@ export async function transpileVueTemplate(content: string, root: RootNode, offs
133
133
const s = new MagicString ( content )
134
134
135
135
handleNode ( root , ( ...items ) => expressions . push ( ...items ) )
136
- await Promise . all (
137
- expressions . map ( async ( item ) => {
138
- if ( item . src . trim ( ) === '' ) {
139
- item . replacement = item . src
140
- return
141
- }
142
-
143
- try {
144
- item . replacement = await transformJsSnippet ( item . src , transform )
145
-
146
- const surrounding = getSurrounding (
147
- content ,
148
- item . loc . start . offset - offset ,
149
- item . loc . end . offset - offset ,
150
- )
151
- if ( surrounding ) {
152
- const replace = surrounding . code === `"` ? `'` : `"`
153
- item . replacement = replaceQuote (
154
- item . replacement ,
155
- surrounding . code ,
156
- replace ,
157
- )
158
- }
159
- }
160
- catch {
161
- item . replacement = item . src
162
- }
163
- } ) ,
164
- )
136
+ const transformMap = await transformJsSnippets ( expressions . map ( e => e . src ) , transform )
137
+ for ( const item of expressions ) {
138
+ item . replacement = transformMap . get ( item . src ) ?? item . src
139
+
140
+ const surrounding = getSurrounding (
141
+ content ,
142
+ item . loc . start . offset - offset ,
143
+ item . loc . end . offset - offset ,
144
+ )
145
+ if ( surrounding ) {
146
+ const replace = surrounding . code === `"` ? `'` : `"`
147
+ item . replacement = replaceQuote (
148
+ item . replacement ,
149
+ surrounding . code ,
150
+ replace ,
151
+ )
152
+ }
153
+ }
165
154
166
155
for ( const item of expressions ) {
167
- if ( item . replacement ) {
156
+ if ( item . replacement && item . replacement !== item . src ) {
168
157
s . overwrite (
169
158
item . loc . start . offset - offset ,
170
159
item . loc . end . offset - offset ,
@@ -216,27 +205,37 @@ function getSurrounding(code: string, start: number, end: number) {
216
205
: undefined
217
206
}
218
207
219
- async function transformJsSnippet ( code : string , transform : ( code : string ) => Promise < string > ) : Promise < string > {
220
- // `{ key: val } as any` in `<div :style="{ key: val } as any" />` is a valid js snippet,
221
- // but it can't be transformed.
222
- // We can wrap it with `()` to make it a valid js file
208
+ async function transformJsSnippets ( codes : string [ ] , transform : ( code : string ) => Promise < string > ) : Promise < Map < string , string > > {
209
+ const keyMap = new Map < string , string > ( )
210
+ const resMap = new Map < string , string > ( )
223
211
224
- let res = await transform ( `(${ code } )` )
212
+ for ( const code of codes ) {
213
+ keyMap . set ( `wrapper_${ keyMap . size } ` , code )
214
+ }
225
215
226
- res = res . trim ( )
216
+ // transform all snippets in a single file
217
+ const batchInput = Array . from ( keyMap . entries ( ) ) . map ( ( [ wrapperName , raw ] ) => `${ wrapperName } (${ raw } );` ) . join ( '\n' )
227
218
228
- // result will be wrapped in `{content};\n`, we need to remove it
229
- if ( res . endsWith ( ';' ) ) {
230
- res = res . slice ( 0 , - 1 )
231
- }
219
+ try {
220
+ const batchOutput = await transform ( batchInput )
232
221
233
- // Check if the code was a v-slot destructuring expression like "{ active, ...slotProps }"
234
- // These should not be wrapped in parentheses as Vue template syntax doesn't support it
235
- const isObject = / ^ \s * \{ . * \} \s * $ / . test ( code )
236
- if ( isObject ) {
237
- // Remove the parentheses
238
- res = res . match ( / ^ \( ( . * ) \) $ / ) ?. [ 1 ] ?? res
239
- }
222
+ const lines = batchOutput . split ( '\n' )
223
+ const wrapperRegex = / ^ ( w r a p p e r _ \d + ) \( ( . * ) \) ; $ /
224
+ for ( const line of lines ) {
225
+ const [ _ , wrapperName , res ] = line . match ( wrapperRegex ) ?? [ ]
226
+ if ( ! wrapperName || ! res ) {
227
+ continue
228
+ }
240
229
241
- return res
230
+ const raw = keyMap . get ( wrapperName )
231
+ if ( raw ) {
232
+ resMap . set ( raw , res )
233
+ }
234
+ }
235
+
236
+ return resMap
237
+ }
238
+ catch ( error ) {
239
+ throw new Error ( '[vue-sfc-transform] Error parsing TypeScript expression in template' , { cause : error } )
240
+ }
242
241
}
0 commit comments