33 *
44 * This source code is licensed under the MIT license found in the
55 * LICENSE file in the root directory of this source tree.
6- *
7- * @flow
86 */
97
10- import type { Path , ProjectConfig } from 'types/Config' ;
11- import type {
12- Transformer ,
13- TransformedSource ,
14- TransformResult ,
15- } from 'types/Transform' ;
16- import type { ErrorWithCode } from 'types/Errors' ;
17- import type { Options } from './types' ;
18-
198import crypto from 'crypto' ;
209import path from 'path' ;
2110import vm from 'vm' ;
11+ import { Config , Transform } from '@jest/types' ;
2212import { createDirectory } from 'jest-util' ;
2313import fs from 'graceful-fs' ;
2414import { transformSync as babelTransform } from '@babel/core' ;
15+ // @ts -ignore: should just be `require.resolve`, but the tests mess that up
2516import babelPluginIstanbul from 'babel-plugin-istanbul' ;
2617import convertSourceMap from 'convert-source-map' ;
2718import HasteMap from 'jest-haste-map' ;
2819import stableStringify from 'fast-json-stable-stringify' ;
2920import slash from 'slash' ;
30- import { version as VERSION } from '../package.json' ;
31- import shouldInstrument from './shouldInstrument' ;
3221import writeFileAtomic from 'write-file-atomic' ;
3322import { sync as realpath } from 'realpath-native' ;
23+ import { Options } from './types' ;
24+ import shouldInstrument from './shouldInstrument' ;
3425import enhanceUnexpectedTokenMessage from './enhanceUnexpectedTokenMessage' ;
3526
36- type ProjectCache = { |
37- configString : string ,
38- ignorePatternsRegExp : ?RegExp ,
39- transformedFiles : Map < string , TransformResult> ,
40- | } ;
27+ type ProjectCache = {
28+ configString : string ;
29+ ignorePatternsRegExp : RegExp | null ;
30+ transformedFiles : Map < string , Transform . TransformResult | string > ;
31+ } ;
32+
33+ // Use `require` to avoid TS rootDir
34+ const { version : VERSION } = require ( '../package.json' ) ;
4135
4236// This data structure is used to avoid recalculating some data every time that
4337// we need to transform a file. Since ScriptTransformer is instantiated for each
4438// file we need to keep this object in the local scope of this module.
45- const projectCaches : WeakMap < ProjectConfig , ProjectCache > = new WeakMap ( ) ;
39+ const projectCaches : WeakMap <
40+ Config . ProjectConfig ,
41+ ProjectCache
42+ > = new WeakMap ( ) ;
4643
4744// To reset the cache for specific changesets (rather than package version).
4845const CACHE_VERSION = '1' ;
4946
5047export default class ScriptTransformer {
5148 static EVAL_RESULT_VARIABLE : string ;
52- _cache : ProjectCache ;
53- _config : ProjectConfig ;
54- _transformCache : Map < Path , ? Transformer > ;
49+ private _cache : ProjectCache ;
50+ private _config : Config . ProjectConfig ;
51+ private _transformCache : Map < Config . Path , Transform . Transformer > ;
5552
56- constructor ( config : ProjectConfig ) {
53+ constructor ( config : Config . ProjectConfig ) {
5754 this . _config = config ;
5855 this . _transformCache = new Map ( ) ;
5956
@@ -72,7 +69,11 @@ export default class ScriptTransformer {
7269 this . _cache = projectCache ;
7370 }
7471
75- _getCacheKey ( fileData : string , filename : Path , instrument : boolean ) : string {
72+ private _getCacheKey (
73+ fileData : string ,
74+ filename : Config . Path ,
75+ instrument : boolean ,
76+ ) : string {
7677 const configString = this . _cache . configString ;
7778 const transformer = this . _getTransformer ( filename ) ;
7879
@@ -99,11 +100,12 @@ export default class ScriptTransformer {
99100 }
100101 }
101102
102- _getFileCachePath (
103- filename : Path ,
103+ private _getFileCachePath (
104+ filename : Config . Path ,
104105 content : string ,
105106 instrument : boolean ,
106- ) : Path {
107+ ) : Config . Path {
108+ // @ts -ignore: not properly exported (needs ESM)
107109 const baseCacheDir = HasteMap . getCacheFilePath (
108110 this . _config . cacheDirectory ,
109111 'jest-transform-cache-' + this . _config . name ,
@@ -124,7 +126,7 @@ export default class ScriptTransformer {
124126 return cachePath ;
125127 }
126128
127- _getTransformPath ( filename : Path ) {
129+ private _getTransformPath ( filename : Config . Path ) {
128130 for ( let i = 0 ; i < this . _config . transform . length ; i ++ ) {
129131 if ( new RegExp ( this . _config . transform [ i ] [ 0 ] ) . test ( filename ) ) {
130132 return this . _config . transform [ i ] [ 1 ] ;
@@ -133,8 +135,8 @@ export default class ScriptTransformer {
133135 return null ;
134136 }
135137
136- _getTransformer ( filename : Path ) {
137- let transform : ? Transformer ;
138+ private _getTransformer ( filename : Config . Path ) {
139+ let transform : Transform . Transformer | null = null ;
138140 if ( ! this . _config . transform || ! this . _config . transform . length ) {
139141 return null ;
140142 }
@@ -146,8 +148,7 @@ export default class ScriptTransformer {
146148 return transformer ;
147149 }
148150
149- // $FlowFixMe
150- transform = ( require ( transformPath ) : Transformer ) ;
151+ transform = require ( transformPath ) as Transform . Transformer ;
151152 if ( typeof transform . createTransformer === 'function' ) {
152153 transform = transform . createTransformer ( ) ;
153154 }
@@ -161,10 +162,11 @@ export default class ScriptTransformer {
161162 return transform ;
162163 }
163164
164- _instrumentFile ( filename : Path , content : string ) : string {
165+ private _instrumentFile ( filename : Config . Path , content : string ) : string {
165166 const result = babelTransform ( content , {
166167 auxiliaryCommentBefore : ' istanbul ignore next ' ,
167168 babelrc : false ,
169+ // @ts -ignore: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/33118
168170 caller : {
169171 name : '@jest/transform' ,
170172 supportsStaticESM : false ,
@@ -185,10 +187,18 @@ export default class ScriptTransformer {
185187 ] ,
186188 } ) ;
187189
188- return result ? result . code : content ;
190+ if ( result ) {
191+ const { code} = result ;
192+
193+ if ( code ) {
194+ return code ;
195+ }
196+ }
197+
198+ return content ;
189199 }
190200
191- _getRealPath ( filepath : Path ) : Path {
201+ private _getRealPath ( filepath : Config . Path ) : Config . Path {
192202 try {
193203 return realpath ( filepath ) || filepath ;
194204 } catch ( err ) {
@@ -198,15 +208,15 @@ export default class ScriptTransformer {
198208
199209 // We don't want to expose transformers to the outside - this function is just
200210 // to warm up `this._transformCache`
201- preloadTransformer ( filepath : Path ) : void {
211+ preloadTransformer ( filepath : Config . Path ) : void {
202212 this . _getTransformer ( filepath ) ;
203213 }
204214
205- transformSource ( filepath : Path , content : string , instrument : boolean ) {
215+ transformSource ( filepath : Config . Path , content : string , instrument : boolean ) {
206216 const filename = this . _getRealPath ( filepath ) ;
207217 const transform = this . _getTransformer ( filename ) ;
208218 const cacheFilePath = this . _getFileCachePath ( filename , content , instrument ) ;
209- let sourceMapPath = cacheFilePath + '.map' ;
219+ let sourceMapPath : Config . Path | null = cacheFilePath + '.map' ;
210220 // Ignore cache if `config.cache` is set (--no-cache)
211221 let code = this . _config . cache ? readCodeCacheFile ( cacheFilePath ) : null ;
212222
@@ -233,7 +243,7 @@ export default class ScriptTransformer {
233243 } ;
234244 }
235245
236- let transformed : TransformedSource = {
246+ let transformed : Transform . TransformedSource = {
237247 code : content ,
238248 map : null ,
239249 } ;
@@ -290,20 +300,20 @@ export default class ScriptTransformer {
290300 } ;
291301 }
292302
293- _transformAndBuildScript (
294- filename : Path ,
295- options : ? Options ,
303+ private _transformAndBuildScript (
304+ filename : Config . Path ,
305+ options : Options | null ,
296306 instrument : boolean ,
297307 fileSource ?: string ,
298- ) : TransformResult {
308+ ) : Transform . TransformResult {
299309 const isInternalModule = ! ! ( options && options . isInternalModule ) ;
300310 const isCoreModule = ! ! ( options && options . isCoreModule ) ;
301311 const content = stripShebang (
302312 fileSource || fs . readFileSync ( filename , 'utf8' ) ,
303313 ) ;
304314
305315 let wrappedCode : string ;
306- let sourceMapPath : ? string = null ;
316+ let sourceMapPath : string | null = null ;
307317 let mapCoverage = false ;
308318
309319 const willTransform =
@@ -354,13 +364,13 @@ export default class ScriptTransformer {
354364 }
355365
356366 transform (
357- filename : Path ,
367+ filename : Config . Path ,
358368 options : Options ,
359369 fileSource ?: string ,
360- ) : TransformResult {
370+ ) : Transform . TransformResult | string {
361371 let scriptCacheKey = null ;
362372 let instrument = false ;
363- let result = '' ;
373+ let result : Transform . TransformResult | string | undefined = '' ;
364374
365375 if ( ! options . isCoreModule ) {
366376 instrument = shouldInstrument ( filename , options , this . _config ) ;
@@ -386,7 +396,7 @@ export default class ScriptTransformer {
386396 return result ;
387397 }
388398
389- _shouldTransform ( filename : Path ) : boolean {
399+ private _shouldTransform ( filename : Config . Path ) : boolean {
390400 const ignoreRegexp = this . _cache . ignorePatternsRegExp ;
391401 const isIgnored = ignoreRegexp ? ignoreRegexp . test ( filename ) : false ;
392402
@@ -396,13 +406,13 @@ export default class ScriptTransformer {
396406 }
397407}
398408
399- const removeFile = ( path : Path ) => {
409+ const removeFile = ( path : Config . Path ) => {
400410 try {
401411 fs . unlinkSync ( path ) ;
402412 } catch ( e ) { }
403413} ;
404414
405- const stripShebang = content => {
415+ const stripShebang = ( content : string ) => {
406416 // If the file data starts with a shebang remove it. Leaves the empty line
407417 // to keep stack trace line numbers correct.
408418 if ( content . startsWith ( '#!' ) ) {
@@ -419,7 +429,7 @@ const stripShebang = content => {
419429 * it right away. This is not a great system, because source map cache file
420430 * could get corrupted, out-of-sync, etc.
421431 */
422- function writeCodeCacheFile ( cachePath : Path , code : string ) {
432+ function writeCodeCacheFile ( cachePath : Config . Path , code : string ) {
423433 const checksum = crypto
424434 . createHash ( 'md5' )
425435 . update ( code )
@@ -433,7 +443,7 @@ function writeCodeCacheFile(cachePath: Path, code: string) {
433443 * could happen if an older version of `jest-runtime` writes non-atomically to
434444 * the same cache, for example.
435445 */
436- function readCodeCacheFile ( cachePath : Path ) : ? string {
446+ function readCodeCacheFile ( cachePath : Config . Path ) : string | null {
437447 const content = readCacheFile ( cachePath ) ;
438448 if ( content == null ) {
439449 return null ;
@@ -455,7 +465,7 @@ function readCodeCacheFile(cachePath: Path): ?string {
455465 * two processes to write to the same file at the same time. It also reduces
456466 * the risk of reading a file that's being overwritten at the same time.
457467 */
458- const writeCacheFile = ( cachePath : Path , fileData : string ) => {
468+ const writeCacheFile = ( cachePath : Config . Path , fileData : string ) => {
459469 try {
460470 writeFileAtomic . sync ( cachePath , fileData , { encoding : 'utf8' } ) ;
461471 } catch ( e ) {
@@ -479,12 +489,15 @@ const writeCacheFile = (cachePath: Path, fileData: string) => {
479489 * If the target file exists we can be reasonably sure another process has
480490 * legitimately won a cache write race and ignore the error.
481491 */
482- const cacheWriteErrorSafeToIgnore = ( e : ErrorWithCode , cachePath : Path ) =>
492+ const cacheWriteErrorSafeToIgnore = (
493+ e : Error & { code : string } ,
494+ cachePath : Config . Path ,
495+ ) =>
483496 process . platform === 'win32' &&
484497 e . code === 'EPERM' &&
485498 fs . existsSync ( cachePath ) ;
486499
487- const readCacheFile = ( cachePath : Path ) : ? string => {
500+ const readCacheFile = ( cachePath : Config . Path ) : string | null => {
488501 if ( ! fs . existsSync ( cachePath ) ) {
489502 return null ;
490503 }
@@ -510,12 +523,14 @@ const readCacheFile = (cachePath: Path): ?string => {
510523 return fileData ;
511524} ;
512525
513- const getScriptCacheKey = ( filename , instrument : boolean ) => {
526+ const getScriptCacheKey = ( filename : Config . Path , instrument : boolean ) => {
514527 const mtime = fs . statSync ( filename ) . mtime ;
515528 return filename + '_' + mtime . getTime ( ) + ( instrument ? '_instrumented' : '' ) ;
516529} ;
517530
518- const calcIgnorePatternRegexp = ( config : ProjectConfig ) : ?RegExp => {
531+ const calcIgnorePatternRegexp = (
532+ config : Config . ProjectConfig ,
533+ ) : RegExp | null => {
519534 if (
520535 ! config . transformIgnorePatterns ||
521536 config . transformIgnorePatterns . length === 0
@@ -526,7 +541,7 @@ const calcIgnorePatternRegexp = (config: ProjectConfig): ?RegExp => {
526541 return new RegExp ( config . transformIgnorePatterns . join ( '|' ) ) ;
527542} ;
528543
529- const wrap = ( content , ...extras ) => {
544+ const wrap = ( content : string , ...extras : Array < string > ) => {
530545 const globals = new Set ( [
531546 'module' ,
532547 'exports' ,
0 commit comments