123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', {
- value: true
- });
- exports.createTranspilingRequire = createTranspilingRequire;
- exports.default = void 0;
- 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 _shouldInstrument = _interopRequireDefault(require('./shouldInstrument'));
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {default: obj};
- }
- function _getRequireWildcardCache() {
- if (typeof WeakMap !== 'function') return null;
- var cache = new WeakMap();
- _getRequireWildcardCache = function () {
- return cache;
- };
- return cache;
- }
- function _interopRequireWildcard(obj) {
- if (obj && obj.__esModule) {
- return obj;
- }
- if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
- return {default: obj};
- }
- var cache = _getRequireWildcardCache();
- if (cache && cache.has(obj)) {
- return cache.get(obj);
- }
- var newObj = {};
- var hasPropertyDescriptor =
- Object.defineProperty && Object.getOwnPropertyDescriptor;
- for (var key in obj) {
- if (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;
- }
- function _defineProperty(obj, key, value) {
- if (key in obj) {
- Object.defineProperty(obj, key, {
- value: value,
- enumerable: true,
- configurable: true,
- writable: true
- });
- } else {
- obj[key] = value;
- }
- return obj;
- }
- // 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();
- }
- }
- class ScriptTransformer {
- constructor(config) {
- _defineProperty(this, '_cache', void 0);
- _defineProperty(this, '_config', void 0);
- _defineProperty(this, '_transformCache', void 0);
- _defineProperty(this, '_transformConfigCache', void 0);
- this._config = config;
- this._transformCache = new Map();
- this._transformConfigCache = new Map();
- 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;
- }
- _getCacheKey(
- fileData,
- filename,
- instrument,
- supportsDynamicImport,
- supportsStaticESM
- ) {
- const configString = this._cache.configString;
- const transformer = this._getTransformer(filename);
- if (transformer && typeof transformer.getCacheKey === 'function') {
- return (0, _crypto().createHash)('md5')
- .update(
- transformer.getCacheKey(fileData, filename, configString, {
- config: this._config,
- instrument,
- rootDir: this._config.rootDir,
- supportsDynamicImport,
- supportsStaticESM
- })
- )
- .update(CACHE_VERSION)
- .digest('hex');
- } else {
- return (0, _crypto().createHash)('md5')
- .update(fileData)
- .update(configString)
- .update(instrument ? 'instrument' : '')
- .update(filename)
- .update(CACHE_VERSION)
- .digest('hex');
- }
- }
- _getFileCachePath(
- filename,
- content,
- instrument,
- supportsDynamicImport,
- supportsStaticESM
- ) {
- const baseCacheDir = _jestHasteMap().default.getCacheFilePath(
- this._config.cacheDirectory,
- 'jest-transform-cache-' + this._config.name,
- VERSION
- );
- const cacheKey = this._getCacheKey(
- content,
- filename,
- instrument,
- supportsDynamicImport,
- supportsStaticESM
- ); // 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, '');
- const cachePath = (0, _slash().default)(
- path().join(cacheDir, cacheFilenamePrefix + '_' + cacheKey)
- );
- (0, _jestUtil().createDirectory)(cacheDir);
- return cachePath;
- }
- _getTransformPath(filename) {
- const transformRegExp = this._cache.transformRegExp;
- if (!transformRegExp) {
- return undefined;
- }
- for (let i = 0; i < transformRegExp.length; i++) {
- if (transformRegExp[i][0].test(filename)) {
- const transformPath = transformRegExp[i][1];
- this._transformConfigCache.set(transformPath, transformRegExp[i][2]);
- return transformPath;
- }
- }
- return undefined;
- }
- _getTransformer(filename) {
- if (!this._config.transform || !this._config.transform.length) {
- return null;
- }
- const transformPath = this._getTransformPath(filename);
- if (!transformPath) {
- return null;
- }
- const transformer = this._transformCache.get(transformPath);
- if (transformer) {
- return transformer;
- }
- let transform = require(transformPath);
- if (!transform) {
- throw new TypeError('Jest: a transform must export something.');
- }
- const transformerConfig = this._transformConfigCache.get(transformPath);
- if (typeof transform.createTransformer === 'function') {
- transform = transform.createTransformer(transformerConfig);
- }
- if (typeof transform.process !== 'function') {
- throw new TypeError(
- 'Jest: a transform must export a `process` function.'
- );
- }
- this._transformCache.set(transformPath, transform);
- return transform;
- }
- _instrumentFile(
- filename,
- input,
- supportsDynamicImport,
- supportsStaticESM,
- canMapToInput
- ) {
- 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,
- supportsStaticESM
- },
- 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 && result.code) {
- return result;
- }
- return input;
- } // We don't want to expose transformers to the outside - this function is just
- // to warm up `this._transformCache`
- preloadTransformer(filepath) {
- this._getTransformer(filepath);
- } // TODO: replace third argument with TransformOptions in Jest 26
- transformSource(
- filepath,
- content,
- instrument,
- supportsDynamicImport = false,
- supportsStaticESM = false
- ) {
- const filename = (0, _jestUtil().tryRealpath)(filepath);
- const transform = this._getTransformer(filename);
- const cacheFilePath = this._getFileCachePath(
- filename,
- content,
- instrument,
- supportsDynamicImport,
- supportsStaticESM
- );
- let sourceMapPath = cacheFilePath + '.map'; // Ignore cache if `config.cache` is set (--no-cache)
- let code = this._config.cache ? readCodeCacheFile(cacheFilePath) : null;
- const shouldCallTransform = transform && this.shouldTransform(filename); // That means that the transform has a custom instrumentation
- // logic and will handle it based on `config.collectCoverage` option
- const transformWillInstrument =
- shouldCallTransform && transform && transform.canInstrument;
- if (code) {
- // 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 transformed = {
- code: content,
- map: null
- };
- if (transform && shouldCallTransform) {
- const processed = transform.process(content, filename, this._config, {
- instrument,
- supportsDynamicImport,
- supportsStaticESM
- });
- if (typeof processed === 'string') {
- transformed.code = processed;
- } else if (processed != null && typeof processed.code === 'string') {
- transformed = processed;
- } else {
- throw new TypeError(
- "Jest: a transform's `process` function must return a string, " +
- 'or an object with `code` key containing this string.'
- );
- }
- }
- if (!transformed.map) {
- try {
- //Could be a potential freeze here.
- //See: https://github.com/facebook/jest/pull/5177#discussion_r158883570
- const inlineSourceMap = (0, _convertSourceMap().fromSource)(
- transformed.code
- );
- if (inlineSourceMap) {
- transformed.map = inlineSourceMap.toObject();
- }
- } catch {
- const transformPath = this._getTransformPath(filename);
- console.warn(
- `jest-transform: The source map produced for the file ${filename} ` +
- `by ${transformPath} was invalid. Proceeding without source ` +
- 'mapping for that file.'
- );
- }
- } // Apply instrumentation to the code if necessary, keeping the instrumented code and new map
- let map = transformed.map;
- if (!transformWillInstrument && 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 =
- (transform != null && map != null) || transform == null;
- const instrumented = this._instrumentFile(
- filename,
- transformed,
- supportsDynamicImport,
- supportsStaticESM,
- shouldEmitSourceMaps
- );
- code =
- typeof instrumented === 'string' ? instrumented : instrumented.code;
- map = typeof instrumented === 'string' ? null : instrumented.map;
- } else {
- code = transformed.code;
- }
- if (map) {
- const sourceMapContent =
- typeof map === 'string' ? map : JSON.stringify(map);
- writeCacheFile(sourceMapPath, sourceMapContent);
- } else {
- sourceMapPath = null;
- }
- writeCodeCacheFile(cacheFilePath, code);
- return {
- code,
- originalCode: content,
- sourceMapPath
- };
- }
- _transformAndBuildScript(filename, options, instrument, fileSource) {
- const {
- isCoreModule,
- isInternalModule,
- supportsDynamicImport,
- supportsStaticESM
- } = options;
- const content = stripShebang(
- fileSource || fs().readFileSync(filename, 'utf8')
- );
- let code = content;
- let sourceMapPath = null;
- const willTransform =
- !isInternalModule &&
- !isCoreModule &&
- (this.shouldTransform(filename) || instrument);
- try {
- if (willTransform) {
- const transformedSource = this.transformSource(
- filename,
- content,
- instrument,
- supportsDynamicImport,
- supportsStaticESM
- );
- code = transformedSource.code;
- sourceMapPath = transformedSource.sourceMapPath;
- }
- return {
- code,
- originalCode: content,
- sourceMapPath
- };
- } catch (e) {
- throw (0, _enhanceUnexpectedTokenMessage.default)(e);
- }
- }
- transform(filename, options, fileSource) {
- let scriptCacheKey = undefined;
- let instrument = false;
- if (!options.isCoreModule) {
- instrument =
- options.coverageProvider === 'babel' &&
- (0, _shouldInstrument.default)(filename, options, this._config);
- scriptCacheKey = getScriptCacheKey(filename, instrument);
- const result = this._cache.transformedFiles.get(scriptCacheKey);
- if (result) {
- return result;
- }
- }
- const result = this._transformAndBuildScript(
- filename,
- options,
- instrument,
- fileSource
- );
- if (scriptCacheKey) {
- this._cache.transformedFiles.set(scriptCacheKey, result);
- }
- return result;
- }
- transformJson(filename, options, fileSource) {
- const {
- isCoreModule,
- isInternalModule,
- supportsDynamicImport,
- supportsStaticESM
- } = options;
- const willTransform =
- !isInternalModule && !isCoreModule && this.shouldTransform(filename);
- if (willTransform) {
- const {code: transformedJsonSource} = this.transformSource(
- filename,
- fileSource,
- false,
- supportsDynamicImport,
- supportsStaticESM
- );
- return transformedJsonSource;
- }
- return fileSource;
- }
- requireAndTranspileModule(moduleName, callback) {
- // Load the transformer to avoid a cycle where we need to load a
- // transformer in order to transform it in the require hooks
- this.preloadTransformer(moduleName);
- let transforming = false;
- const revertHook = (0, _pirates().addHook)(
- (code, filename) => {
- try {
- transforming = true;
- return (
- // we might wanna do `supportsDynamicImport` at some point
- this.transformSource(filename, code, false, false, false).code ||
- code
- );
- } finally {
- transforming = false;
- }
- },
- {
- exts: this._config.moduleFileExtensions.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);
- }
- }
- );
- const module = require(moduleName);
- if (!callback) {
- revertHook();
- return module;
- }
- try {
- const cbResult = callback(module);
- if ((0, _jestUtil().isPromise)(cbResult)) {
- return waitForPromiseWithCleanup(cbResult, revertHook).then(
- () => module
- );
- }
- } finally {
- revertHook();
- }
- return module;
- }
- /**
- * @deprecated use `this.shouldTransform` instead
- */
- // @ts-expect-error: Unused and private - remove in Jest 25
- _shouldTransform(filename) {
- return this.shouldTransform(filename);
- }
- shouldTransform(filename) {
- const ignoreRegexp = this._cache.ignorePatternsRegExp;
- const isIgnored = ignoreRegexp ? ignoreRegexp.test(filename) : false;
- return (
- !!this._config.transform && !!this._config.transform.length && !isIgnored
- );
- }
- } // TODO: do we need to define the generics twice?
- exports.default = ScriptTransformer;
- function createTranspilingRequire(config) {
- const transformer = new ScriptTransformer(config);
- return function requireAndTranspileModule(
- resolverPath,
- applyInteropRequireDefault = false
- ) {
- const transpiledModule = transformer.requireAndTranspileModule(
- resolverPath
- );
- return applyInteropRequireDefault
- ? (0, _jestUtil().interopRequireDefault)(transpiledModule).default
- : 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)('md5').update(code).digest('hex');
- 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.substr(33);
- const checksum = (0, _crypto().createHash)('md5').update(code).digest('hex');
- if (checksum === content.substr(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 (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) {
- 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 ||
- 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;
- };
|