@@ -205,11 +205,15 @@ export default class ScriptTransformer {
205
205
206
206
private _instrumentFile (
207
207
filename : Config . Path ,
208
- content : string ,
208
+ input : TransformedSource ,
209
209
supportsDynamicImport : boolean ,
210
210
supportsStaticESM : boolean ,
211
- ) : string {
212
- const result = babelTransform ( content , {
211
+ canMapToInput : boolean ,
212
+ ) : TransformedSource {
213
+ const inputCode = typeof input === 'string' ? input : input . code ;
214
+ const inputMap = typeof input === 'string' ? null : input . map ;
215
+
216
+ const result = babelTransform ( inputCode , {
213
217
auxiliaryCommentBefore : ' istanbul ignore next ' ,
214
218
babelrc : false ,
215
219
caller : {
@@ -228,21 +232,19 @@ export default class ScriptTransformer {
228
232
cwd : this . _config . rootDir ,
229
233
exclude : [ ] ,
230
234
extension : false ,
235
+ inputSourceMap : inputMap ,
231
236
useInlineSourceMaps : false ,
232
237
} ,
233
238
] ,
234
239
] ,
240
+ sourceMaps : canMapToInput ? 'both' : false ,
235
241
} ) ;
236
242
237
- if ( result ) {
238
- const { code} = result ;
239
-
240
- if ( code ) {
241
- return code ;
242
- }
243
+ if ( result && result . code ) {
244
+ return result as TransformResult ;
243
245
}
244
246
245
- return content ;
247
+ return input ;
246
248
}
247
249
248
250
private _getRealPath ( filepath : Config . Path ) : Config . Path {
@@ -287,18 +289,14 @@ export default class ScriptTransformer {
287
289
const transformWillInstrument =
288
290
shouldCallTransform && transform && transform . canInstrument ;
289
291
290
- // If we handle the coverage instrumentation, we should try to map code
291
- // coverage against original source with any provided source map
292
- const mapCoverage = instrument && ! transformWillInstrument ;
293
-
294
292
if ( code ) {
295
293
// This is broken: we return the code, and a path for the source map
296
294
// directly from the cache. But, nothing ensures the source map actually
297
295
// matches that source code. They could have gotten out-of-sync in case
298
296
// two separate processes write concurrently to the same cache files.
299
297
return {
300
298
code,
301
- mapCoverage,
299
+ mapCoverage : false ,
302
300
originalCode : content ,
303
301
sourceMapPath,
304
302
} ;
@@ -333,9 +331,8 @@ export default class ScriptTransformer {
333
331
//Could be a potential freeze here.
334
332
//See: https://github.com/facebook/jest/pull/5177#discussion_r158883570
335
333
const inlineSourceMap = sourcemapFromSource ( transformed . code ) ;
336
-
337
334
if ( inlineSourceMap ) {
338
- transformed . map = inlineSourceMap . toJSON ( ) ;
335
+ transformed . map = inlineSourceMap . toObject ( ) ;
339
336
}
340
337
} catch ( e ) {
341
338
const transformPath = this . _getTransformPath ( filename ) ;
@@ -347,22 +344,38 @@ export default class ScriptTransformer {
347
344
}
348
345
}
349
346
347
+ // Apply instrumentation to the code if necessary, keeping the instrumented code and new map
348
+ let map = transformed . map ;
350
349
if ( ! transformWillInstrument && instrument ) {
351
- code = this . _instrumentFile (
350
+ /**
351
+ * We can map the original source code to the instrumented code ONLY if
352
+ * - the process of transforming the code produced a source map e.g. ts-jest
353
+ * - we did not transform the source code
354
+ *
355
+ * Otherwise we cannot make any statements about how the instrumented code corresponds to the original code,
356
+ * and we should NOT emit any source maps
357
+ *
358
+ */
359
+ const shouldEmitSourceMaps = ( ! ! transform && ! ! map ) || ! transform ;
360
+
361
+ const instrumented = this . _instrumentFile (
352
362
filename ,
353
- transformed . code ,
363
+ transformed ,
354
364
supportsDynamicImport ,
355
365
supportsStaticESM ,
366
+ shouldEmitSourceMaps ,
356
367
) ;
368
+
369
+ code =
370
+ typeof instrumented === 'string' ? instrumented : instrumented . code ;
371
+ map = typeof instrumented === 'string' ? null : instrumented . map ;
357
372
} else {
358
373
code = transformed . code ;
359
374
}
360
375
361
- if ( transformed . map ) {
376
+ if ( map ) {
362
377
const sourceMapContent =
363
- typeof transformed . map === 'string'
364
- ? transformed . map
365
- : JSON . stringify ( transformed . map ) ;
378
+ typeof map === 'string' ? map : JSON . stringify ( map ) ;
366
379
writeCacheFile ( sourceMapPath , sourceMapContent ) ;
367
380
} else {
368
381
sourceMapPath = null ;
@@ -372,7 +385,7 @@ export default class ScriptTransformer {
372
385
373
386
return {
374
387
code,
375
- mapCoverage,
388
+ mapCoverage : false ,
376
389
originalCode : content ,
377
390
sourceMapPath,
378
391
} ;
@@ -396,7 +409,6 @@ export default class ScriptTransformer {
396
409
397
410
let code = content ;
398
411
let sourceMapPath : string | null = null ;
399
- let mapCoverage = false ;
400
412
401
413
const willTransform =
402
414
! isInternalModule &&
@@ -415,12 +427,11 @@ export default class ScriptTransformer {
415
427
416
428
code = transformedSource . code ;
417
429
sourceMapPath = transformedSource . sourceMapPath ;
418
- mapCoverage = transformedSource . mapCoverage ;
419
430
}
420
431
421
432
return {
422
433
code,
423
- mapCoverage,
434
+ mapCoverage : false ,
424
435
originalCode : content ,
425
436
sourceMapPath,
426
437
} ;
0 commit comments