1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', {
- value: true
- });
- exports.createScriptTransformer = createScriptTransformer;
- exports.createTranspilingRequire = createTranspilingRequire;
- function _crypto() {
- const data = require('crypto');
- _crypto = function () {
- return data;
- };
- return data;
- }
- function path() {
- const data = _interopRequireWildcard(require('path'));
- path = function () {
- return data;
- };
- return data;
- }
- function _core() {
- const data = require('@babel/core');
- _core = function () {
- return data;
- };
- return data;
- }
- function _babelPluginIstanbul() {
- const data = _interopRequireDefault(require('babel-plugin-istanbul'));
- _babelPluginIstanbul = function () {
- return data;
- };
- return data;
- }
- function _convertSourceMap() {
- const data = require('convert-source-map');
- _convertSourceMap = function () {
- return data;
- };
- return data;
- }
- function _fastJsonStableStringify() {
- const data = _interopRequireDefault(require('fast-json-stable-stringify'));
- _fastJsonStableStringify = function () {
- return data;
- };
- return data;
- }
- function fs() {
- const data = _interopRequireWildcard(require('graceful-fs'));
- fs = function () {
- return data;
- };
- return data;
- }
- function _pirates() {
- const data = require('pirates');
- _pirates = function () {
- return data;
- };
- return data;
- }
- function _slash() {
- const data = _interopRequireDefault(require('slash'));
- _slash = function () {
- return data;
- };
- return data;
- }
- function _writeFileAtomic() {
- const data = require('write-file-atomic');
- _writeFileAtomic = function () {
- return data;
- };
- return data;
- }
- function _jestHasteMap() {
- const data = _interopRequireDefault(require('jest-haste-map'));
- _jestHasteMap = function () {
- return data;
- };
- return data;
- }
- function _jestUtil() {
- const data = require('jest-util');
- _jestUtil = function () {
- return data;
- };
- return data;
- }
- var _enhanceUnexpectedTokenMessage = _interopRequireDefault(
- require('./enhanceUnexpectedTokenMessage')
- );
- var _runtimeErrorsAndWarnings = require('./runtimeErrorsAndWarnings');
- var _shouldInstrument = _interopRequireDefault(require('./shouldInstrument'));
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {default: obj};
- }
- function _getRequireWildcardCache(nodeInterop) {
- if (typeof WeakMap !== 'function') return null;
- var cacheBabelInterop = new WeakMap();
- var cacheNodeInterop = new WeakMap();
- return (_getRequireWildcardCache = function (nodeInterop) {
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
- })(nodeInterop);
- }
- function _interopRequireWildcard(obj, nodeInterop) {
- if (!nodeInterop && obj && obj.__esModule) {
- return obj;
- }
- if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
- return {default: obj};
- }
- var cache = _getRequireWildcardCache(nodeInterop);
- if (cache && cache.has(obj)) {
- return cache.get(obj);
- }
- var newObj = {};
- var hasPropertyDescriptor =
- Object.defineProperty && Object.getOwnPropertyDescriptor;
- for (var key in obj) {
- if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
- var desc = hasPropertyDescriptor
- ? Object.getOwnPropertyDescriptor(obj, key)
- : null;
- if (desc && (desc.get || desc.set)) {
- Object.defineProperty(newObj, key, desc);
- } else {
- newObj[key] = obj[key];
- }
- }
- }
- newObj.default = obj;
- if (cache) {
- cache.set(obj, newObj);
- }
- return newObj;
- }
- /**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
- // @ts-expect-error: should just be `require.resolve`, but the tests mess that up
- // Use `require` to avoid TS rootDir
- const {version: VERSION} = require('../package.json');
- // This data structure is used to avoid recalculating some data every time that
- // we need to transform a file. Since ScriptTransformer is instantiated for each
- // file we need to keep this object in the local scope of this module.
- const projectCaches = new Map();
- // To reset the cache for specific changesets (rather than package version).
- const CACHE_VERSION = '1';
- async function waitForPromiseWithCleanup(promise, cleanup) {
- try {
- await promise;
- } finally {
- cleanup();
- }
- }
- // type predicate
- function isTransformerFactory(t) {
- return typeof t.createTransformer === 'function';
- }
- class ScriptTransformer {
- _cache;
- _transformCache = new Map();
- _transformsAreLoaded = false;
- constructor(_config, _cacheFS) {
- this._config = _config;
- this._cacheFS = _cacheFS;
- const configString = (0, _fastJsonStableStringify().default)(this._config);
- let projectCache = projectCaches.get(configString);
- if (!projectCache) {
- projectCache = {
- configString,
- ignorePatternsRegExp: calcIgnorePatternRegExp(this._config),
- transformRegExp: calcTransformRegExp(this._config),
- transformedFiles: new Map()
- };
- projectCaches.set(configString, projectCache);
- }
- this._cache = projectCache;
- }
- _buildCacheKeyFromFileInfo(
- fileData,
- filename,
- transformOptions,
- transformerCacheKey
- ) {
- if (transformerCacheKey != null) {
- return (0, _crypto().createHash)('sha1')
- .update(transformerCacheKey)
- .update(CACHE_VERSION)
- .digest('hex')
- .substring(0, 32);
- }
- return (0, _crypto().createHash)('sha1')
- .update(fileData)
- .update(transformOptions.configString)
- .update(transformOptions.instrument ? 'instrument' : '')
- .update(filename)
- .update(CACHE_VERSION)
- .digest('hex')
- .substring(0, 32);
- }
- _buildTransformCacheKey(pattern, filepath) {
- return pattern + filepath;
- }
- _getCacheKey(fileData, filename, options) {
- const configString = this._cache.configString;
- const {transformer, transformerConfig = {}} =
- this._getTransformer(filename) ?? {};
- let transformerCacheKey = undefined;
- const transformOptions = {
- ...options,
- cacheFS: this._cacheFS,
- config: this._config,
- configString,
- transformerConfig
- };
- if (typeof transformer?.getCacheKey === 'function') {
- transformerCacheKey = transformer.getCacheKey(
- fileData,
- filename,
- transformOptions
- );
- }
- return this._buildCacheKeyFromFileInfo(
- fileData,
- filename,
- transformOptions,
- transformerCacheKey
- );
- }
- async _getCacheKeyAsync(fileData, filename, options) {
- const configString = this._cache.configString;
- const {transformer, transformerConfig = {}} =
- this._getTransformer(filename) ?? {};
- let transformerCacheKey = undefined;
- const transformOptions = {
- ...options,
- cacheFS: this._cacheFS,
- config: this._config,
- configString,
- transformerConfig
- };
- if (transformer) {
- const getCacheKey =
- transformer.getCacheKeyAsync ?? transformer.getCacheKey;
- if (typeof getCacheKey === 'function') {
- transformerCacheKey = await getCacheKey(
- fileData,
- filename,
- transformOptions
- );
- }
- }
- return this._buildCacheKeyFromFileInfo(
- fileData,
- filename,
- transformOptions,
- transformerCacheKey
- );
- }
- _createCachedFilename(filename, cacheKey) {
- const HasteMapClass = _jestHasteMap().default.getStatic(this._config);
- const baseCacheDir = HasteMapClass.getCacheFilePath(
- this._config.cacheDirectory,
- `jest-transform-cache-${this._config.id}`,
- VERSION
- );
- // Create sub folders based on the cacheKey to avoid creating one
- // directory with many files.
- const cacheDir = path().join(baseCacheDir, cacheKey[0] + cacheKey[1]);
- const cacheFilenamePrefix = path()
- .basename(filename, path().extname(filename))
- .replace(/\W/g, '');
- return (0, _slash().default)(
- path().join(cacheDir, `${cacheFilenamePrefix}_${cacheKey}`)
- );
- }
- _getFileCachePath(filename, content, options) {
- const cacheKey = this._getCacheKey(content, filename, options);
- return this._createCachedFilename(filename, cacheKey);
- }
- async _getFileCachePathAsync(filename, content, options) {
- const cacheKey = await this._getCacheKeyAsync(content, filename, options);
- return this._createCachedFilename(filename, cacheKey);
- }
- _getTransformPatternAndPath(filename) {
- const transformEntry = this._cache.transformRegExp;
- if (transformEntry == null) {
- return undefined;
- }
- for (let i = 0; i < transformEntry.length; i++) {
- const [transformRegExp, transformPath] = transformEntry[i];
- if (transformRegExp.test(filename)) {
- return [transformRegExp.source, transformPath];
- }
- }
- return undefined;
- }
- _getTransformPath(filename) {
- const transformInfo = this._getTransformPatternAndPath(filename);
- if (!Array.isArray(transformInfo)) {
- return undefined;
- }
- return transformInfo[1];
- }
- async loadTransformers() {
- await Promise.all(
- this._config.transform.map(
- async ([transformPattern, transformPath, transformerConfig], i) => {
- let transformer = await (0, _jestUtil().requireOrImportModule)(
- transformPath
- );
- if (transformer == null) {
- throw new Error(
- (0, _runtimeErrorsAndWarnings.makeInvalidTransformerError)(
- transformPath
- )
- );
- }
- if (isTransformerFactory(transformer)) {
- transformer = await transformer.createTransformer(
- transformerConfig
- );
- }
- if (
- typeof transformer.process !== 'function' &&
- typeof transformer.processAsync !== 'function'
- ) {
- throw new Error(
- (0, _runtimeErrorsAndWarnings.makeInvalidTransformerError)(
- transformPath
- )
- );
- }
- const res = {
- transformer,
- transformerConfig
- };
- const transformCacheKey = this._buildTransformCacheKey(
- this._cache.transformRegExp?.[i]?.[0].source ??
- new RegExp(transformPattern).source,
- transformPath
- );
- this._transformCache.set(transformCacheKey, res);
- }
- )
- );
- this._transformsAreLoaded = true;
- }
- _getTransformer(filename) {
- if (!this._transformsAreLoaded) {
- throw new Error(
- 'Jest: Transformers have not been loaded yet - make sure to run `loadTransformers` and wait for it to complete before starting to transform files'
- );
- }
- if (this._config.transform.length === 0) {
- return null;
- }
- const transformPatternAndPath = this._getTransformPatternAndPath(filename);
- if (!Array.isArray(transformPatternAndPath)) {
- return null;
- }
- const [transformPattern, transformPath] = transformPatternAndPath;
- const transformCacheKey = this._buildTransformCacheKey(
- transformPattern,
- transformPath
- );
- const transformer = this._transformCache.get(transformCacheKey);
- if (transformer !== undefined) {
- return transformer;
- }
- throw new Error(
- `Jest was unable to load the transformer defined for ${filename}. This is a bug in Jest, please open up an issue`
- );
- }
- _instrumentFile(filename, input, canMapToInput, options) {
- const inputCode = typeof input === 'string' ? input : input.code;
- const inputMap = typeof input === 'string' ? null : input.map;
- const result = (0, _core().transformSync)(inputCode, {
- auxiliaryCommentBefore: ' istanbul ignore next ',
- babelrc: false,
- caller: {
- name: '@jest/transform',
- supportsDynamicImport: options.supportsDynamicImport,
- supportsExportNamespaceFrom: options.supportsExportNamespaceFrom,
- supportsStaticESM: options.supportsStaticESM,
- supportsTopLevelAwait: options.supportsTopLevelAwait
- },
- configFile: false,
- filename,
- plugins: [
- [
- _babelPluginIstanbul().default,
- {
- compact: false,
- // files outside `cwd` will not be instrumented
- cwd: this._config.rootDir,
- exclude: [],
- extension: false,
- inputSourceMap: inputMap,
- useInlineSourceMaps: false
- }
- ]
- ],
- sourceMaps: canMapToInput ? 'both' : false
- });
- if (result?.code != null) {
- return result;
- }
- return input;
- }
- _buildTransformResult(
- filename,
- cacheFilePath,
- content,
- transformer,
- shouldCallTransform,
- options,
- processed,
- sourceMapPath
- ) {
- let transformed = {
- code: content,
- map: null
- };
- if (transformer && shouldCallTransform) {
- if (processed != null && typeof processed.code === 'string') {
- transformed = processed;
- } else {
- const transformPath = this._getTransformPath(filename);
- (0, _jestUtil().invariant)(transformPath);
- throw new Error(
- (0, _runtimeErrorsAndWarnings.makeInvalidReturnValueError)(
- transformPath
- )
- );
- }
- }
- if (transformed.map == null || transformed.map === '') {
- try {
- //Could be a potential freeze here.
- //See: https://github.com/jestjs/jest/pull/5177#discussion_r158883570
- const inlineSourceMap = (0, _convertSourceMap().fromSource)(
- transformed.code
- );
- if (inlineSourceMap) {
- transformed.map = inlineSourceMap.toObject();
- }
- } catch {
- const transformPath = this._getTransformPath(filename);
- (0, _jestUtil().invariant)(transformPath);
- console.warn(
- (0, _runtimeErrorsAndWarnings.makeInvalidSourceMapWarning)(
- filename,
- transformPath
- )
- );
- }
- }
- // That means that the transform has a custom instrumentation
- // logic and will handle it based on `config.collectCoverage` option
- const transformWillInstrument =
- shouldCallTransform && transformer && transformer.canInstrument;
- // Apply instrumentation to the code if necessary, keeping the instrumented code and new map
- let map = transformed.map;
- let code;
- if (transformWillInstrument !== true && options.instrument) {
- /**
- * We can map the original source code to the instrumented code ONLY if
- * - the process of transforming the code produced a source map e.g. ts-jest
- * - we did not transform the source code
- *
- * Otherwise we cannot make any statements about how the instrumented code corresponds to the original code,
- * and we should NOT emit any source maps
- *
- */
- const shouldEmitSourceMaps =
- (transformer != null && map != null) || transformer == null;
- const instrumented = this._instrumentFile(
- filename,
- transformed,
- shouldEmitSourceMaps,
- options
- );
- code =
- typeof instrumented === 'string' ? instrumented : instrumented.code;
- map = typeof instrumented === 'string' ? null : instrumented.map;
- } else {
- code = transformed.code;
- }
- if (map != null) {
- const sourceMapContent =
- typeof map === 'string' ? map : JSON.stringify(map);
- (0, _jestUtil().invariant)(
- sourceMapPath,
- 'We should always have default sourceMapPath'
- );
- writeCacheFile(sourceMapPath, sourceMapContent);
- } else {
- sourceMapPath = null;
- }
- writeCodeCacheFile(cacheFilePath, code);
- return {
- code,
- originalCode: content,
- sourceMapPath
- };
- }
- transformSource(filepath, content, options) {
- const filename = (0, _jestUtil().tryRealpath)(filepath);
- const {transformer, transformerConfig = {}} =
- this._getTransformer(filename) ?? {};
- const cacheFilePath = this._getFileCachePath(filename, content, options);
- const sourceMapPath = `${cacheFilePath}.map`;
- // Ignore cache if `config.cache` is set (--no-cache)
- const code = this._config.cache ? readCodeCacheFile(cacheFilePath) : null;
- if (code != null) {
- // This is broken: we return the code, and a path for the source map
- // directly from the cache. But, nothing ensures the source map actually
- // matches that source code. They could have gotten out-of-sync in case
- // two separate processes write concurrently to the same cache files.
- return {
- code,
- originalCode: content,
- sourceMapPath
- };
- }
- let processed = null;
- let shouldCallTransform = false;
- if (transformer && this.shouldTransform(filename)) {
- shouldCallTransform = true;
- assertSyncTransformer(transformer, this._getTransformPath(filename));
- processed = transformer.process(content, filename, {
- ...options,
- cacheFS: this._cacheFS,
- config: this._config,
- configString: this._cache.configString,
- transformerConfig
- });
- }
- (0, _jestUtil().createDirectory)(path().dirname(cacheFilePath));
- return this._buildTransformResult(
- filename,
- cacheFilePath,
- content,
- transformer,
- shouldCallTransform,
- options,
- processed,
- sourceMapPath
- );
- }
- async transformSourceAsync(filepath, content, options) {
- const filename = (0, _jestUtil().tryRealpath)(filepath);
- const {transformer, transformerConfig = {}} =
- this._getTransformer(filename) ?? {};
- const cacheFilePath = await this._getFileCachePathAsync(
- filename,
- content,
- options
- );
- const sourceMapPath = `${cacheFilePath}.map`;
- // Ignore cache if `config.cache` is set (--no-cache)
- const code = this._config.cache ? readCodeCacheFile(cacheFilePath) : null;
- if (code != null) {
- // This is broken: we return the code, and a path for the source map
- // directly from the cache. But, nothing ensures the source map actually
- // matches that source code. They could have gotten out-of-sync in case
- // two separate processes write concurrently to the same cache files.
- return {
- code,
- originalCode: content,
- sourceMapPath
- };
- }
- let processed = null;
- let shouldCallTransform = false;
- if (transformer && this.shouldTransform(filename)) {
- shouldCallTransform = true;
- const process = transformer.processAsync ?? transformer.process;
- // This is probably dead code since `_getTransformerAsync` already asserts this
- (0, _jestUtil().invariant)(
- typeof process === 'function',
- 'A transformer must always export either a `process` or `processAsync`'
- );
- processed = await process(content, filename, {
- ...options,
- cacheFS: this._cacheFS,
- config: this._config,
- configString: this._cache.configString,
- transformerConfig
- });
- }
- (0, _jestUtil().createDirectory)(path().dirname(cacheFilePath));
- return this._buildTransformResult(
- filename,
- cacheFilePath,
- content,
- transformer,
- shouldCallTransform,
- options,
- processed,
- sourceMapPath
- );
- }
- async _transformAndBuildScriptAsync(
- filename,
- options,
- transformOptions,
- fileSource
- ) {
- const {isInternalModule} = options;
- let fileContent = fileSource ?? this._cacheFS.get(filename);
- if (fileContent == null) {
- fileContent = fs().readFileSync(filename, 'utf8');
- this._cacheFS.set(filename, fileContent);
- }
- const content = stripShebang(fileContent);
- let code = content;
- let sourceMapPath = null;
- const willTransform =
- isInternalModule !== true &&
- (transformOptions.instrument || this.shouldTransform(filename));
- try {
- if (willTransform) {
- const transformedSource = await this.transformSourceAsync(
- filename,
- content,
- transformOptions
- );
- code = transformedSource.code;
- sourceMapPath = transformedSource.sourceMapPath;
- }
- return {
- code,
- originalCode: content,
- sourceMapPath
- };
- } catch (e) {
- if (!(e instanceof Error)) {
- throw e;
- }
- throw (0, _enhanceUnexpectedTokenMessage.default)(e);
- }
- }
- _transformAndBuildScript(filename, options, transformOptions, fileSource) {
- const {isInternalModule} = options;
- let fileContent = fileSource ?? this._cacheFS.get(filename);
- if (fileContent == null) {
- fileContent = fs().readFileSync(filename, 'utf8');
- this._cacheFS.set(filename, fileContent);
- }
- const content = stripShebang(fileContent);
- let code = content;
- let sourceMapPath = null;
- const willTransform =
- isInternalModule !== true &&
- (transformOptions.instrument || this.shouldTransform(filename));
- try {
- if (willTransform) {
- const transformedSource = this.transformSource(
- filename,
- content,
- transformOptions
- );
- code = transformedSource.code;
- sourceMapPath = transformedSource.sourceMapPath;
- }
- return {
- code,
- originalCode: content,
- sourceMapPath
- };
- } catch (e) {
- if (!(e instanceof Error)) {
- throw e;
- }
- throw (0, _enhanceUnexpectedTokenMessage.default)(e);
- }
- }
- async transformAsync(filename, options, fileSource) {
- const instrument =
- options.coverageProvider === 'babel' &&
- (0, _shouldInstrument.default)(filename, options, this._config);
- const scriptCacheKey = getScriptCacheKey(filename, instrument);
- let result = this._cache.transformedFiles.get(scriptCacheKey);
- if (result) {
- return result;
- }
- result = await this._transformAndBuildScriptAsync(
- filename,
- options,
- {
- ...options,
- instrument
- },
- fileSource
- );
- if (scriptCacheKey) {
- this._cache.transformedFiles.set(scriptCacheKey, result);
- }
- return result;
- }
- transform(filename, options, fileSource) {
- const instrument =
- options.coverageProvider === 'babel' &&
- (0, _shouldInstrument.default)(filename, options, this._config);
- const scriptCacheKey = getScriptCacheKey(filename, instrument);
- let result = this._cache.transformedFiles.get(scriptCacheKey);
- if (result) {
- return result;
- }
- result = this._transformAndBuildScript(
- filename,
- options,
- {
- ...options,
- instrument
- },
- fileSource
- );
- if (scriptCacheKey) {
- this._cache.transformedFiles.set(scriptCacheKey, result);
- }
- return result;
- }
- transformJson(filename, options, fileSource) {
- const {isInternalModule} = options;
- const willTransform =
- isInternalModule !== true && this.shouldTransform(filename);
- if (willTransform) {
- const {code: transformedJsonSource} = this.transformSource(
- filename,
- fileSource,
- {
- ...options,
- instrument: false
- }
- );
- return transformedJsonSource;
- }
- return fileSource;
- }
- async requireAndTranspileModule(
- moduleName,
- callback,
- options = {
- applyInteropRequireDefault: true,
- instrument: false,
- supportsDynamicImport: false,
- supportsExportNamespaceFrom: false,
- supportsStaticESM: false,
- supportsTopLevelAwait: false
- }
- ) {
- let transforming = false;
- const {applyInteropRequireDefault, ...transformOptions} = options;
- const revertHook = (0, _pirates().addHook)(
- (code, filename) => {
- try {
- transforming = true;
- return (
- this.transformSource(filename, code, transformOptions).code || code
- );
- } finally {
- transforming = false;
- }
- },
- {
- // Exclude `mjs` extension when addHook because pirates don't support hijack es module
- exts: this._config.moduleFileExtensions
- .filter(ext => ext !== 'mjs')
- .map(ext => `.${ext}`),
- ignoreNodeModules: false,
- matcher: filename => {
- if (transforming) {
- // Don't transform any dependency required by the transformer itself
- return false;
- }
- return this.shouldTransform(filename);
- }
- }
- );
- try {
- const module = await (0, _jestUtil().requireOrImportModule)(
- moduleName,
- applyInteropRequireDefault
- );
- if (!callback) {
- revertHook();
- return module;
- }
- const cbResult = callback(module);
- if ((0, _jestUtil().isPromise)(cbResult)) {
- return await waitForPromiseWithCleanup(cbResult, revertHook).then(
- () => module
- );
- }
- return module;
- } finally {
- revertHook();
- }
- }
- shouldTransform(filename) {
- const ignoreRegexp = this._cache.ignorePatternsRegExp;
- const isIgnored = ignoreRegexp ? ignoreRegexp.test(filename) : false;
- return this._config.transform.length !== 0 && !isIgnored;
- }
- }
- // TODO: do we need to define the generics twice?
- async function createTranspilingRequire(config) {
- const transformer = await createScriptTransformer(config);
- return async function requireAndTranspileModule(
- resolverPath,
- applyInteropRequireDefault = false
- ) {
- const transpiledModule = await transformer.requireAndTranspileModule(
- resolverPath,
- // eslint-disable-next-line @typescript-eslint/no-empty-function
- () => {},
- {
- applyInteropRequireDefault,
- instrument: false,
- supportsDynamicImport: false,
- // this might be true, depending on node version.
- supportsExportNamespaceFrom: false,
- supportsStaticESM: false,
- supportsTopLevelAwait: false
- }
- );
- return transpiledModule;
- };
- }
- const removeFile = path => {
- try {
- fs().unlinkSync(path);
- } catch {}
- };
- const stripShebang = content => {
- // If the file data starts with a shebang remove it. Leaves the empty line
- // to keep stack trace line numbers correct.
- if (content.startsWith('#!')) {
- return content.replace(/^#!.*/, '');
- } else {
- return content;
- }
- };
- /**
- * This is like `writeCacheFile` but with an additional sanity checksum. We
- * cannot use the same technique for source maps because we expose source map
- * cache file paths directly to callsites, with the expectation they can read
- * it right away. This is not a great system, because source map cache file
- * could get corrupted, out-of-sync, etc.
- */
- function writeCodeCacheFile(cachePath, code) {
- const checksum = (0, _crypto().createHash)('sha1')
- .update(code)
- .digest('hex')
- .substring(0, 32);
- writeCacheFile(cachePath, `${checksum}\n${code}`);
- }
- /**
- * Read counterpart of `writeCodeCacheFile`. We verify that the content of the
- * file matches the checksum, in case some kind of corruption happened. This
- * could happen if an older version of `jest-runtime` writes non-atomically to
- * the same cache, for example.
- */
- function readCodeCacheFile(cachePath) {
- const content = readCacheFile(cachePath);
- if (content == null) {
- return null;
- }
- const code = content.substring(33);
- const checksum = (0, _crypto().createHash)('sha1')
- .update(code)
- .digest('hex')
- .substring(0, 32);
- if (checksum === content.substring(0, 32)) {
- return code;
- }
- return null;
- }
- /**
- * Writing to the cache atomically relies on 'rename' being atomic on most
- * file systems. Doing atomic write reduces the risk of corruption by avoiding
- * two processes to write to the same file at the same time. It also reduces
- * the risk of reading a file that's being overwritten at the same time.
- */
- const writeCacheFile = (cachePath, fileData) => {
- try {
- (0, _writeFileAtomic().sync)(cachePath, fileData, {
- encoding: 'utf8',
- fsync: false
- });
- } catch (e) {
- if (!(e instanceof Error)) {
- throw e;
- }
- if (cacheWriteErrorSafeToIgnore(e, cachePath)) {
- return;
- }
- e.message = `jest: failed to cache transform results in: ${cachePath}\nFailure message: ${e.message}`;
- removeFile(cachePath);
- throw e;
- }
- };
- /**
- * On Windows, renames are not atomic, leading to EPERM exceptions when two
- * processes attempt to rename to the same target file at the same time.
- * If the target file exists we can be reasonably sure another process has
- * legitimately won a cache write race and ignore the error.
- */
- const cacheWriteErrorSafeToIgnore = (e, cachePath) =>
- process.platform === 'win32' &&
- e.code === 'EPERM' &&
- fs().existsSync(cachePath);
- const readCacheFile = cachePath => {
- if (!fs().existsSync(cachePath)) {
- return null;
- }
- let fileData;
- try {
- fileData = fs().readFileSync(cachePath, 'utf8');
- } catch (e) {
- if (!(e instanceof Error)) {
- throw e;
- }
- // on windows write-file-atomic is not atomic which can
- // result in this error
- if (e.code === 'ENOENT' && process.platform === 'win32') {
- return null;
- }
- e.message = `jest: failed to read cache file: ${cachePath}\nFailure message: ${e.message}`;
- removeFile(cachePath);
- throw e;
- }
- if (fileData == null) {
- // We must have somehow created the file but failed to write to it,
- // let's delete it and retry.
- removeFile(cachePath);
- }
- return fileData;
- };
- const getScriptCacheKey = (filename, instrument) => {
- const mtime = fs().statSync(filename).mtime;
- return `${filename}_${mtime.getTime()}${instrument ? '_instrumented' : ''}`;
- };
- const calcIgnorePatternRegExp = config => {
- if (
- config.transformIgnorePatterns == null ||
- config.transformIgnorePatterns.length === 0
- ) {
- return undefined;
- }
- return new RegExp(config.transformIgnorePatterns.join('|'));
- };
- const calcTransformRegExp = config => {
- if (!config.transform.length) {
- return undefined;
- }
- const transformRegexp = [];
- for (let i = 0; i < config.transform.length; i++) {
- transformRegexp.push([
- new RegExp(config.transform[i][0]),
- config.transform[i][1],
- config.transform[i][2]
- ]);
- }
- return transformRegexp;
- };
- function assertSyncTransformer(transformer, name) {
- (0, _jestUtil().invariant)(name);
- (0, _jestUtil().invariant)(
- typeof transformer.process === 'function',
- (0, _runtimeErrorsAndWarnings.makeInvalidSyncTransformerError)(name)
- );
- }
- async function createScriptTransformer(config, cacheFS = new Map()) {
- const transformer = new ScriptTransformer(config, cacheFS);
- await transformer.loadTransformers();
- return transformer;
- }
|