ScriptTransformer.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. function _crypto() {
  7. const data = _interopRequireDefault(require('crypto'));
  8. _crypto = function _crypto() {
  9. return data;
  10. };
  11. return data;
  12. }
  13. function _path() {
  14. const data = _interopRequireDefault(require('path'));
  15. _path = function _path() {
  16. return data;
  17. };
  18. return data;
  19. }
  20. function _vm() {
  21. const data = _interopRequireDefault(require('vm'));
  22. _vm = function _vm() {
  23. return data;
  24. };
  25. return data;
  26. }
  27. function _jestUtil() {
  28. const data = require('jest-util');
  29. _jestUtil = function _jestUtil() {
  30. return data;
  31. };
  32. return data;
  33. }
  34. function _gracefulFs() {
  35. const data = _interopRequireDefault(require('graceful-fs'));
  36. _gracefulFs = function _gracefulFs() {
  37. return data;
  38. };
  39. return data;
  40. }
  41. function _core() {
  42. const data = require('@babel/core');
  43. _core = function _core() {
  44. return data;
  45. };
  46. return data;
  47. }
  48. function _babelPluginIstanbul() {
  49. const data = _interopRequireDefault(require('babel-plugin-istanbul'));
  50. _babelPluginIstanbul = function _babelPluginIstanbul() {
  51. return data;
  52. };
  53. return data;
  54. }
  55. function _convertSourceMap() {
  56. const data = _interopRequireDefault(require('convert-source-map'));
  57. _convertSourceMap = function _convertSourceMap() {
  58. return data;
  59. };
  60. return data;
  61. }
  62. function _jestHasteMap() {
  63. const data = _interopRequireDefault(require('jest-haste-map'));
  64. _jestHasteMap = function _jestHasteMap() {
  65. return data;
  66. };
  67. return data;
  68. }
  69. function _fastJsonStableStringify() {
  70. const data = _interopRequireDefault(require('fast-json-stable-stringify'));
  71. _fastJsonStableStringify = function _fastJsonStableStringify() {
  72. return data;
  73. };
  74. return data;
  75. }
  76. function _slash() {
  77. const data = _interopRequireDefault(require('slash'));
  78. _slash = function _slash() {
  79. return data;
  80. };
  81. return data;
  82. }
  83. function _writeFileAtomic() {
  84. const data = _interopRequireDefault(require('write-file-atomic'));
  85. _writeFileAtomic = function _writeFileAtomic() {
  86. return data;
  87. };
  88. return data;
  89. }
  90. function _realpathNative() {
  91. const data = require('realpath-native');
  92. _realpathNative = function _realpathNative() {
  93. return data;
  94. };
  95. return data;
  96. }
  97. function _pirates() {
  98. const data = require('pirates');
  99. _pirates = function _pirates() {
  100. return data;
  101. };
  102. return data;
  103. }
  104. var _shouldInstrument = _interopRequireDefault(require('./shouldInstrument'));
  105. var _enhanceUnexpectedTokenMessage = _interopRequireDefault(
  106. require('./enhanceUnexpectedTokenMessage')
  107. );
  108. function _interopRequireDefault(obj) {
  109. return obj && obj.__esModule ? obj : {default: obj};
  110. }
  111. function _defineProperty(obj, key, value) {
  112. if (key in obj) {
  113. Object.defineProperty(obj, key, {
  114. value: value,
  115. enumerable: true,
  116. configurable: true,
  117. writable: true
  118. });
  119. } else {
  120. obj[key] = value;
  121. }
  122. return obj;
  123. }
  124. function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  125. try {
  126. var info = gen[key](arg);
  127. var value = info.value;
  128. } catch (error) {
  129. reject(error);
  130. return;
  131. }
  132. if (info.done) {
  133. resolve(value);
  134. } else {
  135. Promise.resolve(value).then(_next, _throw);
  136. }
  137. }
  138. function _asyncToGenerator(fn) {
  139. return function() {
  140. var self = this,
  141. args = arguments;
  142. return new Promise(function(resolve, reject) {
  143. var gen = fn.apply(self, args);
  144. function _next(value) {
  145. asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'next', value);
  146. }
  147. function _throw(err) {
  148. asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
  149. }
  150. _next(undefined);
  151. });
  152. };
  153. }
  154. // Use `require` to avoid TS rootDir
  155. const _require = require('../package.json'),
  156. VERSION = _require.version; // This data structure is used to avoid recalculating some data every time that
  157. // we need to transform a file. Since ScriptTransformer is instantiated for each
  158. // file we need to keep this object in the local scope of this module.
  159. const projectCaches = new WeakMap(); // To reset the cache for specific changesets (rather than package version).
  160. const CACHE_VERSION = '1';
  161. function waitForPromiseWithCleanup(_x, _x2) {
  162. return _waitForPromiseWithCleanup.apply(this, arguments);
  163. }
  164. function _waitForPromiseWithCleanup() {
  165. _waitForPromiseWithCleanup = _asyncToGenerator(function*(promise, cleanup) {
  166. try {
  167. yield promise;
  168. } finally {
  169. cleanup();
  170. }
  171. });
  172. return _waitForPromiseWithCleanup.apply(this, arguments);
  173. }
  174. class ScriptTransformer {
  175. constructor(config) {
  176. _defineProperty(this, '_cache', void 0);
  177. _defineProperty(this, '_config', void 0);
  178. _defineProperty(this, '_transformCache', void 0);
  179. _defineProperty(this, '_transformConfigCache', void 0);
  180. this._config = config;
  181. this._transformCache = new Map();
  182. this._transformConfigCache = new Map();
  183. let projectCache = projectCaches.get(config);
  184. if (!projectCache) {
  185. projectCache = {
  186. configString: (0, _fastJsonStableStringify().default)(this._config),
  187. ignorePatternsRegExp: calcIgnorePatternRegExp(this._config),
  188. transformRegExp: calcTransformRegExp(this._config),
  189. transformedFiles: new Map()
  190. };
  191. projectCaches.set(config, projectCache);
  192. }
  193. this._cache = projectCache;
  194. }
  195. _getCacheKey(fileData, filename, instrument) {
  196. const configString = this._cache.configString;
  197. const transformer = this._getTransformer(filename);
  198. if (transformer && typeof transformer.getCacheKey === 'function') {
  199. return _crypto()
  200. .default.createHash('md5')
  201. .update(
  202. transformer.getCacheKey(fileData, filename, configString, {
  203. config: this._config,
  204. instrument,
  205. rootDir: this._config.rootDir
  206. })
  207. )
  208. .update(CACHE_VERSION)
  209. .digest('hex');
  210. } else {
  211. return _crypto()
  212. .default.createHash('md5')
  213. .update(fileData)
  214. .update(configString)
  215. .update(instrument ? 'instrument' : '')
  216. .update(filename)
  217. .update(CACHE_VERSION)
  218. .digest('hex');
  219. }
  220. }
  221. _getFileCachePath(filename, content, instrument) {
  222. const baseCacheDir = _jestHasteMap().default.getCacheFilePath(
  223. this._config.cacheDirectory,
  224. 'jest-transform-cache-' + this._config.name,
  225. VERSION
  226. );
  227. const cacheKey = this._getCacheKey(content, filename, instrument); // Create sub folders based on the cacheKey to avoid creating one
  228. // directory with many files.
  229. const cacheDir = _path().default.join(
  230. baseCacheDir,
  231. cacheKey[0] + cacheKey[1]
  232. );
  233. const cacheFilenamePrefix = _path()
  234. .default.basename(filename, _path().default.extname(filename))
  235. .replace(/\W/g, '');
  236. const cachePath = (0, _slash().default)(
  237. _path().default.join(cacheDir, cacheFilenamePrefix + '_' + cacheKey)
  238. );
  239. (0, _jestUtil().createDirectory)(cacheDir);
  240. return cachePath;
  241. }
  242. _getTransformPath(filename) {
  243. const transformRegExp = this._cache.transformRegExp;
  244. if (!transformRegExp) {
  245. return undefined;
  246. }
  247. for (let i = 0; i < transformRegExp.length; i++) {
  248. if (transformRegExp[i][0].test(filename)) {
  249. const transformPath = transformRegExp[i][1];
  250. this._transformConfigCache.set(transformPath, transformRegExp[i][2]);
  251. return transformPath;
  252. }
  253. }
  254. return undefined;
  255. }
  256. _getTransformer(filename) {
  257. let transform = null;
  258. if (!this._config.transform || !this._config.transform.length) {
  259. return null;
  260. }
  261. const transformPath = this._getTransformPath(filename);
  262. if (transformPath) {
  263. const transformer = this._transformCache.get(transformPath);
  264. if (transformer != null) {
  265. return transformer;
  266. }
  267. transform = require(transformPath);
  268. const transformerConfig = this._transformConfigCache.get(transformPath);
  269. if (typeof transform.createTransformer === 'function') {
  270. transform = transform.createTransformer(transformerConfig);
  271. }
  272. if (typeof transform.process !== 'function') {
  273. throw new TypeError(
  274. 'Jest: a transform must export a `process` function.'
  275. );
  276. }
  277. this._transformCache.set(transformPath, transform);
  278. }
  279. return transform;
  280. }
  281. _instrumentFile(filename, content) {
  282. const result = (0, _core().transformSync)(content, {
  283. auxiliaryCommentBefore: ' istanbul ignore next ',
  284. babelrc: false,
  285. caller: {
  286. name: '@jest/transform',
  287. supportsStaticESM: false
  288. },
  289. configFile: false,
  290. filename,
  291. plugins: [
  292. [
  293. _babelPluginIstanbul().default,
  294. {
  295. compact: false,
  296. // files outside `cwd` will not be instrumented
  297. cwd: this._config.rootDir,
  298. exclude: [],
  299. useInlineSourceMaps: false
  300. }
  301. ]
  302. ]
  303. });
  304. if (result) {
  305. const code = result.code;
  306. if (code) {
  307. return code;
  308. }
  309. }
  310. return content;
  311. }
  312. _getRealPath(filepath) {
  313. try {
  314. return (0, _realpathNative().sync)(filepath) || filepath;
  315. } catch (err) {
  316. return filepath;
  317. }
  318. } // We don't want to expose transformers to the outside - this function is just
  319. // to warm up `this._transformCache`
  320. preloadTransformer(filepath) {
  321. this._getTransformer(filepath);
  322. }
  323. transformSource(filepath, content, instrument) {
  324. const filename = this._getRealPath(filepath);
  325. const transform = this._getTransformer(filename);
  326. const cacheFilePath = this._getFileCachePath(filename, content, instrument);
  327. let sourceMapPath = cacheFilePath + '.map'; // Ignore cache if `config.cache` is set (--no-cache)
  328. let code = this._config.cache ? readCodeCacheFile(cacheFilePath) : null;
  329. const shouldCallTransform = transform && this.shouldTransform(filename); // That means that the transform has a custom instrumentation
  330. // logic and will handle it based on `config.collectCoverage` option
  331. const transformWillInstrument =
  332. shouldCallTransform && transform && transform.canInstrument; // If we handle the coverage instrumentation, we should try to map code
  333. // coverage against original source with any provided source map
  334. const mapCoverage = instrument && !transformWillInstrument;
  335. if (code) {
  336. // This is broken: we return the code, and a path for the source map
  337. // directly from the cache. But, nothing ensures the source map actually
  338. // matches that source code. They could have gotten out-of-sync in case
  339. // two separate processes write concurrently to the same cache files.
  340. return {
  341. code,
  342. mapCoverage,
  343. sourceMapPath
  344. };
  345. }
  346. let transformed = {
  347. code: content,
  348. map: null
  349. };
  350. if (transform && shouldCallTransform) {
  351. const processed = transform.process(content, filename, this._config, {
  352. instrument
  353. });
  354. if (typeof processed === 'string') {
  355. transformed.code = processed;
  356. } else if (processed != null && typeof processed.code === 'string') {
  357. transformed = processed;
  358. } else {
  359. throw new TypeError(
  360. "Jest: a transform's `process` function must return a string, " +
  361. 'or an object with `code` key containing this string.'
  362. );
  363. }
  364. }
  365. if (!transformed.map) {
  366. //Could be a potential freeze here.
  367. //See: https://github.com/facebook/jest/pull/5177#discussion_r158883570
  368. const inlineSourceMap = _convertSourceMap().default.fromSource(
  369. transformed.code
  370. );
  371. if (inlineSourceMap) {
  372. transformed.map = inlineSourceMap.toJSON();
  373. }
  374. }
  375. if (!transformWillInstrument && instrument) {
  376. code = this._instrumentFile(filename, transformed.code);
  377. } else {
  378. code = transformed.code;
  379. }
  380. if (transformed.map) {
  381. const sourceMapContent =
  382. typeof transformed.map === 'string'
  383. ? transformed.map
  384. : JSON.stringify(transformed.map);
  385. writeCacheFile(sourceMapPath, sourceMapContent);
  386. } else {
  387. sourceMapPath = null;
  388. }
  389. writeCodeCacheFile(cacheFilePath, code);
  390. return {
  391. code,
  392. mapCoverage,
  393. sourceMapPath
  394. };
  395. }
  396. _transformAndBuildScript(filename, options, instrument, fileSource) {
  397. const isInternalModule = !!(options && options.isInternalModule);
  398. const isCoreModule = !!(options && options.isCoreModule);
  399. const content = stripShebang(
  400. fileSource || _gracefulFs().default.readFileSync(filename, 'utf8')
  401. );
  402. let wrappedCode;
  403. let sourceMapPath = null;
  404. let mapCoverage = false;
  405. const willTransform =
  406. !isInternalModule &&
  407. !isCoreModule &&
  408. (this.shouldTransform(filename) || instrument);
  409. try {
  410. const extraGlobals = (options && options.extraGlobals) || [];
  411. if (willTransform) {
  412. const transformedSource = this.transformSource(
  413. filename,
  414. content,
  415. instrument
  416. );
  417. wrappedCode = wrap(transformedSource.code, ...extraGlobals);
  418. sourceMapPath = transformedSource.sourceMapPath;
  419. mapCoverage = transformedSource.mapCoverage;
  420. } else {
  421. wrappedCode = wrap(content, ...extraGlobals);
  422. }
  423. return {
  424. mapCoverage,
  425. script: new (_vm()).default.Script(wrappedCode, {
  426. displayErrors: true,
  427. filename: isCoreModule ? 'jest-nodejs-core-' + filename : filename
  428. }),
  429. sourceMapPath
  430. };
  431. } catch (e) {
  432. if (e.codeFrame) {
  433. e.stack = e.message + '\n' + e.codeFrame;
  434. }
  435. if (
  436. e instanceof SyntaxError &&
  437. e.message.includes('Unexpected token') &&
  438. !e.message.includes(' expected')
  439. ) {
  440. throw (0, _enhanceUnexpectedTokenMessage.default)(e);
  441. }
  442. throw e;
  443. }
  444. }
  445. transform(filename, options, fileSource) {
  446. let scriptCacheKey = undefined;
  447. let instrument = false;
  448. if (!options.isCoreModule) {
  449. instrument = (0, _shouldInstrument.default)(
  450. filename,
  451. options,
  452. this._config
  453. );
  454. scriptCacheKey = getScriptCacheKey(filename, instrument);
  455. const result = this._cache.transformedFiles.get(scriptCacheKey);
  456. if (result) {
  457. return result;
  458. }
  459. }
  460. const result = this._transformAndBuildScript(
  461. filename,
  462. options,
  463. instrument,
  464. fileSource
  465. );
  466. if (scriptCacheKey) {
  467. this._cache.transformedFiles.set(scriptCacheKey, result);
  468. }
  469. return result;
  470. }
  471. transformJson(filename, options, fileSource) {
  472. const isInternalModule = options.isInternalModule;
  473. const isCoreModule = options.isCoreModule;
  474. const willTransform =
  475. !isInternalModule && !isCoreModule && this.shouldTransform(filename);
  476. if (willTransform) {
  477. const _this$transformSource = this.transformSource(
  478. filename,
  479. fileSource,
  480. false
  481. ),
  482. transformedJsonSource = _this$transformSource.code;
  483. return transformedJsonSource;
  484. }
  485. return fileSource;
  486. }
  487. requireAndTranspileModule(moduleName, callback) {
  488. // Load the transformer to avoid a cycle where we need to load a
  489. // transformer in order to transform it in the require hooks
  490. this.preloadTransformer(moduleName);
  491. let transforming = false;
  492. const revertHook = (0, _pirates().addHook)(
  493. (code, filename) => {
  494. try {
  495. transforming = true;
  496. return this.transformSource(filename, code, false).code || code;
  497. } finally {
  498. transforming = false;
  499. }
  500. },
  501. {
  502. exts: [_path().default.extname(moduleName)],
  503. ignoreNodeModules: false,
  504. matcher: filename => {
  505. if (transforming) {
  506. // Don't transform any dependency required by the transformer itself
  507. return false;
  508. }
  509. return this.shouldTransform(filename);
  510. }
  511. }
  512. );
  513. const module = require(moduleName);
  514. if (!callback) {
  515. revertHook();
  516. return module;
  517. }
  518. try {
  519. const cbResult = callback(module);
  520. if ((0, _jestUtil().isPromise)(cbResult)) {
  521. return waitForPromiseWithCleanup(cbResult, revertHook).then(
  522. () => module
  523. );
  524. }
  525. } finally {
  526. revertHook();
  527. }
  528. return module;
  529. }
  530. /**
  531. * @deprecated use `this.shouldTransform` instead
  532. */
  533. // @ts-ignore: Unused and private - remove in Jest 25
  534. _shouldTransform(filename) {
  535. return this.shouldTransform(filename);
  536. }
  537. shouldTransform(filename) {
  538. const ignoreRegexp = this._cache.ignorePatternsRegExp;
  539. const isIgnored = ignoreRegexp ? ignoreRegexp.test(filename) : false;
  540. return (
  541. !!this._config.transform && !!this._config.transform.length && !isIgnored
  542. );
  543. }
  544. }
  545. exports.default = ScriptTransformer;
  546. _defineProperty(ScriptTransformer, 'EVAL_RESULT_VARIABLE', void 0);
  547. const removeFile = path => {
  548. try {
  549. _gracefulFs().default.unlinkSync(path);
  550. } catch (e) {}
  551. };
  552. const stripShebang = content => {
  553. // If the file data starts with a shebang remove it. Leaves the empty line
  554. // to keep stack trace line numbers correct.
  555. if (content.startsWith('#!')) {
  556. return content.replace(/^#!.*/, '');
  557. } else {
  558. return content;
  559. }
  560. };
  561. /**
  562. * This is like `writeCacheFile` but with an additional sanity checksum. We
  563. * cannot use the same technique for source maps because we expose source map
  564. * cache file paths directly to callsites, with the expectation they can read
  565. * it right away. This is not a great system, because source map cache file
  566. * could get corrupted, out-of-sync, etc.
  567. */
  568. function writeCodeCacheFile(cachePath, code) {
  569. const checksum = _crypto()
  570. .default.createHash('md5')
  571. .update(code)
  572. .digest('hex');
  573. writeCacheFile(cachePath, checksum + '\n' + code);
  574. }
  575. /**
  576. * Read counterpart of `writeCodeCacheFile`. We verify that the content of the
  577. * file matches the checksum, in case some kind of corruption happened. This
  578. * could happen if an older version of `jest-runtime` writes non-atomically to
  579. * the same cache, for example.
  580. */
  581. function readCodeCacheFile(cachePath) {
  582. const content = readCacheFile(cachePath);
  583. if (content == null) {
  584. return null;
  585. }
  586. const code = content.substr(33);
  587. const checksum = _crypto()
  588. .default.createHash('md5')
  589. .update(code)
  590. .digest('hex');
  591. if (checksum === content.substr(0, 32)) {
  592. return code;
  593. }
  594. return null;
  595. }
  596. /**
  597. * Writing to the cache atomically relies on 'rename' being atomic on most
  598. * file systems. Doing atomic write reduces the risk of corruption by avoiding
  599. * two processes to write to the same file at the same time. It also reduces
  600. * the risk of reading a file that's being overwritten at the same time.
  601. */
  602. const writeCacheFile = (cachePath, fileData) => {
  603. try {
  604. _writeFileAtomic().default.sync(cachePath, fileData, {
  605. encoding: 'utf8'
  606. });
  607. } catch (e) {
  608. if (cacheWriteErrorSafeToIgnore(e, cachePath)) {
  609. return;
  610. }
  611. e.message =
  612. 'jest: failed to cache transform results in: ' +
  613. cachePath +
  614. '\nFailure message: ' +
  615. e.message;
  616. removeFile(cachePath);
  617. throw e;
  618. }
  619. };
  620. /**
  621. * On Windows, renames are not atomic, leading to EPERM exceptions when two
  622. * processes attempt to rename to the same target file at the same time.
  623. * If the target file exists we can be reasonably sure another process has
  624. * legitimately won a cache write race and ignore the error.
  625. */
  626. const cacheWriteErrorSafeToIgnore = (e, cachePath) =>
  627. process.platform === 'win32' &&
  628. e.code === 'EPERM' &&
  629. _gracefulFs().default.existsSync(cachePath);
  630. const readCacheFile = cachePath => {
  631. if (!_gracefulFs().default.existsSync(cachePath)) {
  632. return null;
  633. }
  634. let fileData;
  635. try {
  636. fileData = _gracefulFs().default.readFileSync(cachePath, 'utf8');
  637. } catch (e) {
  638. e.message =
  639. 'jest: failed to read cache file: ' +
  640. cachePath +
  641. '\nFailure message: ' +
  642. e.message;
  643. removeFile(cachePath);
  644. throw e;
  645. }
  646. if (fileData == null) {
  647. // We must have somehow created the file but failed to write to it,
  648. // let's delete it and retry.
  649. removeFile(cachePath);
  650. }
  651. return fileData;
  652. };
  653. const getScriptCacheKey = (filename, instrument) => {
  654. const mtime = _gracefulFs().default.statSync(filename).mtime;
  655. return filename + '_' + mtime.getTime() + (instrument ? '_instrumented' : '');
  656. };
  657. const calcIgnorePatternRegExp = config => {
  658. if (
  659. !config.transformIgnorePatterns ||
  660. config.transformIgnorePatterns.length === 0
  661. ) {
  662. return undefined;
  663. }
  664. return new RegExp(config.transformIgnorePatterns.join('|'));
  665. };
  666. const calcTransformRegExp = config => {
  667. if (!config.transform.length) {
  668. return undefined;
  669. }
  670. const transformRegexp = [];
  671. for (let i = 0; i < config.transform.length; i++) {
  672. transformRegexp.push([
  673. new RegExp(config.transform[i][0]),
  674. config.transform[i][1],
  675. config.transform[i][2]
  676. ]);
  677. }
  678. return transformRegexp;
  679. };
  680. const wrap = (content, ...extras) => {
  681. const globals = new Set([
  682. 'module',
  683. 'exports',
  684. 'require',
  685. '__dirname',
  686. '__filename',
  687. 'global',
  688. 'jest',
  689. ...extras
  690. ]);
  691. return (
  692. '({"' +
  693. ScriptTransformer.EVAL_RESULT_VARIABLE +
  694. `":function(${Array.from(globals).join(',')}){` +
  695. content +
  696. '\n}});'
  697. );
  698. }; // TODO: Can this be added to the static property?
  699. ScriptTransformer.EVAL_RESULT_VARIABLE = 'Object.<anonymous>';