@@ -167,16 +167,78 @@ export class App {
167167 ) ;
168168
169169 // OXC strip must have been called with the jitTransform output (which
170- // still contains `readonly`) so Rolldown receives valid JS.
170+ // still contains `readonly`) so Rolldown receives valid JS. We also
171+ // pass the jitTransform map as `inMap` so OXC composes the strip map
172+ // with it, keeping debug positions accurate.
171173 const oxcStripCall = mockTransformWithOxc . mock . calls . find (
172174 ( [ , callId ] ) => callId === '/src/app/app.ts' ,
173175 ) ;
174176 expect ( oxcStripCall ) . toBeDefined ( ) ;
175177 expect ( oxcStripCall ! [ 0 ] ) . toContain ( 'readonly' ) ;
176- expect ( oxcStripCall ! [ 2 ] ) . toMatchObject ( { lang : 'ts' } ) ;
178+ expect ( oxcStripCall ! [ 2 ] ) . toMatchObject ( { lang : 'ts' , sourcemap : true } ) ;
179+ expect ( oxcStripCall ! [ 3 ] ) . toBeDefined ( ) ; // inMap from jitTransform
177180 expect ( result . code ) . not . toContain ( 'readonly' ) ;
178181 } ) ;
179182
183+ it ( 'JIT path falls back to esbuild when transformWithOxc is unavailable' , async ( ) => {
184+ // Vite 6-8 compatibility: the same regression coverage as the OXC test
185+ // above, but exercising the esbuild branch the plugin takes when
186+ // `vite.transformWithOxc` is undefined (Vite 6 / pre-Rolldown).
187+ mockTransformWithEsbuild . mockResolvedValue ( {
188+ code : 'export class App { test = ""; }\n' ,
189+ map : { mappings : '' } ,
190+ } ) ;
191+
192+ const viteMod = await import ( 'vite' ) ;
193+ const realOxc = viteMod . transformWithOxc ;
194+ Object . defineProperty ( viteMod , 'transformWithOxc' , {
195+ value : undefined ,
196+ configurable : true ,
197+ } ) ;
198+ try {
199+ const plugin = fastCompilePlugin ( {
200+ tsconfigGetter : ( ) => 'tsconfig.json' ,
201+ workspaceRoot : '/workspace' ,
202+ inlineStylesExtension : 'css' ,
203+ jit : true ,
204+ liveReload : false ,
205+ supportedBrowsers : [ ] ,
206+ isTest : true ,
207+ isAstroIntegration : false ,
208+ } ) ;
209+ const handler = getTransformHandler ( plugin ) ;
210+
211+ const code = `import { Component } from '@angular/core';
212+ @Component({ selector: 'app-root', template: '<div></div>' })
213+ export class App {
214+ readonly test = '';
215+ }
216+ ` ;
217+ const result = await handler . call (
218+ { addWatchFile : ( ) => undefined } ,
219+ code ,
220+ '/src/app/app.ts' ,
221+ ) ;
222+
223+ const esbuildStripCall = mockTransformWithEsbuild . mock . calls . find (
224+ ( [ , callId ] ) => callId === '/src/app/app.ts' ,
225+ ) ;
226+ expect ( esbuildStripCall ) . toBeDefined ( ) ;
227+ expect ( esbuildStripCall ! [ 0 ] ) . toContain ( 'readonly' ) ;
228+ expect ( esbuildStripCall ! [ 2 ] ) . toMatchObject ( {
229+ loader : 'ts' ,
230+ sourcemap : true ,
231+ } ) ;
232+ expect ( esbuildStripCall ! [ 3 ] ) . toBeDefined ( ) ; // inMap from jitTransform
233+ expect ( result . code ) . not . toContain ( 'readonly' ) ;
234+ } finally {
235+ Object . defineProperty ( viteMod , 'transformWithOxc' , {
236+ value : realOxc ,
237+ configurable : true ,
238+ } ) ;
239+ }
240+ } ) ;
241+
180242 it ( 'does not run the bypass strip when the file has @Component' , async ( ) => {
181243 const plugin = buildPlugin ( ) ;
182244 const handler = getTransformHandler ( plugin ) ;
0 commit comments