jest-haste-map
Version:
`jest-haste-map` is a module used by Jest, a popular JavaScript testing framework, to create a fast lookup of files in a project. It helps Jest efficiently locate and track changes in files during testing, making it particularly useful for large projects
3,680 lines • 131 kB
JavaScript
/*!
* /**
* * 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.
* * /
*/
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/HasteFS.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
var _constants = _interopRequireDefault(__webpack_require__("./src/constants.ts"));
var fastPath = _interopRequireWildcard(__webpack_require__("./src/lib/fast_path.ts"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* 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.
*/
class HasteFS {
_rootDir;
_files;
constructor({
rootDir,
files
}) {
this._rootDir = rootDir;
this._files = files;
}
getModuleName(file) {
const fileMetadata = this._getFileData(file);
return fileMetadata && fileMetadata[_constants.default.ID] || null;
}
getSize(file) {
const fileMetadata = this._getFileData(file);
return fileMetadata && fileMetadata[_constants.default.SIZE] || null;
}
getDependencies(file) {
const fileMetadata = this._getFileData(file);
if (fileMetadata) {
return fileMetadata[_constants.default.DEPENDENCIES] ? fileMetadata[_constants.default.DEPENDENCIES].split(_constants.default.DEPENDENCY_DELIM) : [];
} else {
return null;
}
}
getSha1(file) {
const fileMetadata = this._getFileData(file);
return fileMetadata && fileMetadata[_constants.default.SHA1] || null;
}
exists(file) {
return this._getFileData(file) != null;
}
getAllFiles() {
return [...this.getAbsoluteFileIterator()];
}
getFileIterator() {
return this._files.keys();
}
*getAbsoluteFileIterator() {
for (const file of this.getFileIterator()) {
yield fastPath.resolve(this._rootDir, file);
}
}
matchFiles(pattern) {
if (!(pattern instanceof RegExp)) {
pattern = new RegExp(pattern);
}
const files = [];
for (const file of this.getAbsoluteFileIterator()) {
if (pattern.test(file)) {
files.push(file);
}
}
return files;
}
matchFilesWithGlob(globs, root) {
const files = new Set();
const matcher = (0, _jestUtil().globsToMatcher)(globs);
for (const file of this.getAbsoluteFileIterator()) {
const filePath = root ? fastPath.relative(root, file) : file;
if (matcher((0, _jestUtil().replacePathSepForGlob)(filePath))) {
files.add(file);
}
}
return files;
}
_getFileData(file) {
const relativePath = fastPath.relative(this._rootDir, file);
return this._files.get(relativePath);
}
}
exports["default"] = HasteFS;
/***/ },
/***/ "./src/ModuleMap.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
var _constants = _interopRequireDefault(__webpack_require__("./src/constants.ts"));
var fastPath = _interopRequireWildcard(__webpack_require__("./src/lib/fast_path.ts"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* 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.
*/
const EMPTY_OBJ = {};
const EMPTY_MAP = new Map();
class ModuleMap {
static DuplicateHasteCandidatesError;
_raw;
json;
static mapToArrayRecursive(map) {
let arr = [...map];
if (arr[0] && arr[0][1] instanceof Map) {
arr = arr.map(el => [el[0], this.mapToArrayRecursive(el[1])]);
}
return arr;
}
static mapFromArrayRecursive(arr) {
if (arr[0] && Array.isArray(arr[0][1])) {
arr = arr.map(el => [el[0], this.mapFromArrayRecursive(el[1])]);
}
return new Map(arr);
}
constructor(raw) {
this._raw = raw;
}
getModule(name, platform, supportsNativePlatform, type) {
if (type == null) {
type = _constants.default.MODULE;
}
const module = this._getModuleMetadata(name, platform, !!supportsNativePlatform);
if (module && module[_constants.default.TYPE] === type) {
const modulePath = module[_constants.default.PATH];
return modulePath && fastPath.resolve(this._raw.rootDir, modulePath);
}
return null;
}
getPackage(name, platform, _supportsNativePlatform) {
return this.getModule(name, platform, null, _constants.default.PACKAGE);
}
getMockModule(name) {
const mockPath = this._raw.mocks.get(name) || this._raw.mocks.get(`${name}/index`);
return mockPath && fastPath.resolve(this._raw.rootDir, mockPath);
}
getRawModuleMap() {
return {
duplicates: this._raw.duplicates,
map: this._raw.map,
mocks: this._raw.mocks,
rootDir: this._raw.rootDir
};
}
toJSON() {
if (!this.json) {
this.json = {
duplicates: ModuleMap.mapToArrayRecursive(this._raw.duplicates),
map: [...this._raw.map],
mocks: [...this._raw.mocks],
rootDir: this._raw.rootDir
};
}
return this.json;
}
static fromJSON(serializableModuleMap) {
return new ModuleMap({
duplicates: ModuleMap.mapFromArrayRecursive(serializableModuleMap.duplicates),
map: new Map(serializableModuleMap.map),
mocks: new Map(serializableModuleMap.mocks),
rootDir: serializableModuleMap.rootDir
});
}
/**
* When looking up a module's data, we walk through each eligible platform for
* the query. For each platform, we want to check if there are known
* duplicates for that name+platform pair. The duplication logic normally
* removes elements from the `map` object, but we want to check upfront to be
* extra sure. If metadata exists both in the `duplicates` object and the
* `map`, this would be a bug.
*/
_getModuleMetadata(name, platform, supportsNativePlatform) {
const map = this._raw.map.get(name) || EMPTY_OBJ;
const dupMap = this._raw.duplicates.get(name) || EMPTY_MAP;
if (platform != null) {
this._assertNoDuplicates(name, platform, supportsNativePlatform, dupMap.get(platform));
if (map[platform] != null) {
return map[platform];
}
}
if (supportsNativePlatform) {
this._assertNoDuplicates(name, _constants.default.NATIVE_PLATFORM, supportsNativePlatform, dupMap.get(_constants.default.NATIVE_PLATFORM));
if (map[_constants.default.NATIVE_PLATFORM]) {
return map[_constants.default.NATIVE_PLATFORM];
}
}
this._assertNoDuplicates(name, _constants.default.GENERIC_PLATFORM, supportsNativePlatform, dupMap.get(_constants.default.GENERIC_PLATFORM));
if (map[_constants.default.GENERIC_PLATFORM]) {
return map[_constants.default.GENERIC_PLATFORM];
}
return null;
}
_assertNoDuplicates(name, platform, supportsNativePlatform, relativePathSet) {
if (relativePathSet == null) {
return;
}
// Force flow refinement
const previousSet = relativePathSet;
const duplicates = new Map();
for (const [relativePath, type] of previousSet) {
const duplicatePath = fastPath.resolve(this._raw.rootDir, relativePath);
duplicates.set(duplicatePath, type);
}
throw new DuplicateHasteCandidatesError(name, platform, supportsNativePlatform, duplicates);
}
static create(rootDir) {
return new ModuleMap({
duplicates: new Map(),
map: new Map(),
mocks: new Map(),
rootDir
});
}
}
exports["default"] = ModuleMap;
class DuplicateHasteCandidatesError extends Error {
hasteName;
platform;
supportsNativePlatform;
duplicatesSet;
constructor(name, platform, supportsNativePlatform, duplicatesSet) {
const platformMessage = getPlatformMessage(platform);
super(`The name \`${name}\` was looked up in the Haste module map. It ` + 'cannot be resolved, because there exists several different ' + 'files, or packages, that provide a module for ' + `that particular name and platform. ${platformMessage} You must ` + `delete or exclude files until there remains only one of these:\n\n${[...duplicatesSet].map(([dupFilePath, dupFileType]) => ` * \`${dupFilePath}\` (${getTypeMessage(dupFileType)})\n`).sort().join('')}`);
this.hasteName = name;
this.platform = platform;
this.supportsNativePlatform = supportsNativePlatform;
this.duplicatesSet = duplicatesSet;
}
}
function getPlatformMessage(platform) {
if (platform === _constants.default.GENERIC_PLATFORM) {
return 'The platform is generic (no extension).';
}
return `The platform extension is \`${platform}\`.`;
}
function getTypeMessage(type) {
switch (type) {
case _constants.default.MODULE:
return 'module';
case _constants.default.PACKAGE:
return 'package';
}
return 'unknown';
}
ModuleMap.DuplicateHasteCandidatesError = DuplicateHasteCandidatesError;
/***/ },
/***/ "./src/blacklist.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
/**
* 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.
*/
// This list is compiled after the MDN list of the most common MIME types (see
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/
// Complete_list_of_MIME_types).
//
// Only MIME types starting with "image/", "video/", "audio/" and "font/" are
// reflected in the list. Adding "application/" is too risky since some text
// file formats (like ".js" and ".json") have an "application/" MIME type.
//
// Feel free to add any extensions that cannot be a Haste module.
const extensions = new Set([
// JSONs are never haste modules, except for "package.json", which is handled.
'.json',
// Image extensions.
'.bmp', '.gif', '.ico', '.jpeg', '.jpg', '.png', '.svg', '.tiff', '.tif', '.webp',
// Video extensions.
'.avi', '.mp4', '.mpeg', '.mpg', '.ogv', '.webm', '.3gp', '.3g2',
// Audio extensions.
'.aac', '.midi', '.mid', '.mp3', '.oga', '.wav', '.3gp', '.3g2',
// Font extensions.
'.eot', '.otf', '.ttf', '.woff', '.woff2']);
var _default = exports["default"] = extensions;
/***/ },
/***/ "./src/constants.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
/**
* 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.
*/
/*
* This file exports a set of constants that are used for Jest's haste map
* serialization. On very large repositories, the haste map cache becomes very
* large to the point where it is the largest overhead in starting up Jest.
*
* This constant key map allows to keep the map smaller without having to build
* a custom serialization library.
*/
/* eslint-disable sort-keys */
const constants = {
/* dependency serialization */
DEPENDENCY_DELIM: '\0',
/* file map attributes */
ID: 0,
MTIME: 1,
SIZE: 2,
VISITED: 3,
DEPENDENCIES: 4,
SHA1: 5,
/* module map attributes */
PATH: 0,
TYPE: 1,
/* module types */
MODULE: 0,
PACKAGE: 1,
/* platforms */
GENERIC_PLATFORM: 'g',
NATIVE_PLATFORM: 'native'
};
/* eslint-enable */
var _default = exports["default"] = constants;
/***/ },
/***/ "./src/crawlers/index.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.crawl = crawl;
var _node = __webpack_require__("./src/crawlers/node.ts");
var _watchman = __webpack_require__("./src/crawlers/watchman.ts");
/**
* 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.
*/
async function crawl(crawlerOptions, useWatchman) {
const crawlFn = useWatchman ? _watchman.watchmanCrawl : _node.nodeCrawl;
const retry = retryError => {
if (crawlFn === _watchman.watchmanCrawl) {
crawlerOptions.console.warn('jest-haste-map: Watchman crawl failed. Retrying once with node ' + 'crawler.\n' + " Usually this happens when watchman isn't running. Create an " + "empty `.watchmanconfig` file in your project's root folder or " + 'initialize a git or hg repository in your project.\n' + ` ${retryError}`);
return (0, _node.nodeCrawl)(crawlerOptions).catch(error => {
throw new Error('Crawler retry failed:\n' + ` Original error: ${retryError.message}\n` + ` Retry error: ${error.message}\n`);
});
}
throw retryError;
};
try {
return await crawlFn(crawlerOptions);
} catch (error) {
return retry(error);
}
}
/***/ },
/***/ "./src/crawlers/node.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.nodeCrawl = nodeCrawl;
function _nodeChild_process() {
const data = require("node:child_process");
_nodeChild_process = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require("graceful-fs"));
fs = function () {
return data;
};
return data;
}
var _constants = _interopRequireDefault(__webpack_require__("./src/constants.ts"));
var fastPath = _interopRequireWildcard(__webpack_require__("./src/lib/fast_path.ts"));
var _walk = __webpack_require__("./src/lib/walk.ts");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
async function hasNativeFindSupport(forceNodeFilesystemAPI) {
if (forceNodeFilesystemAPI) {
return false;
}
try {
return await new Promise(resolve => {
// Check the find binary supports the non-POSIX -iname parameter wrapped in parens.
const args = ['.', '-type', 'f', '(', '-iname', '*.ts', '-o', '-iname', '*.js', ')'];
const child = (0, _nodeChild_process().spawn)('find', args, {
cwd: __dirname
});
child.on('error', () => {
resolve(false);
});
child.on('exit', code => {
resolve(code === 0);
});
});
} catch {
return false;
}
}
function find(roots, extensions, ignore, enableSymlinks, callback) {
const extSet = new Set(extensions);
const result = [];
const statCache = new Map();
let remaining = roots.length;
if (remaining === 0) {
callback(result);
return;
}
for (const root of roots) {
(0, _walk.walk)({
enableSymlinks,
exclude: ignore,
onEntry: (kind, filePath, stats) => {
if (kind === 'file' && extSet.has(path().extname(filePath).slice(1))) {
result.push([filePath, stats.mtime.getTime(), stats.size]);
}
},
root,
statCache
}, () => {
remaining--;
if (remaining === 0) {
callback(result);
}
});
}
}
function findNative(roots, extensions, ignore, enableSymlinks, callback) {
const args = [...roots];
if (enableSymlinks) {
args.push('(', '-type', 'f', '-o', '-type', 'l', ')');
} else {
args.push('-type', 'f');
}
if (extensions.length > 0) {
args.push('(');
}
for (const [index, ext] of extensions.entries()) {
if (index) {
args.push('-o');
}
args.push('-iname', `*.${ext}`);
}
if (extensions.length > 0) {
args.push(')');
}
const child = (0, _nodeChild_process().spawn)('find', args);
if (child.stdout === null) {
throw new Error('stdout is null - this should never happen. Please open up an issue at https://github.com/jestjs/jest');
}
child.stdout.setEncoding('utf8');
const chunks = [];
child.stdout.on('data', data => chunks.push(data));
child.stdout.on('close', () => {
const lines = chunks.join('').trim().split('\n').filter(x => x && !ignore(x));
const result = [];
let count = lines.length;
if (count) {
for (const path of lines) {
fs().stat(path, (err, stat) => {
// Filter out symlinks that describe directories
if (!err && stat && !stat.isDirectory()) {
result.push([path, stat.mtime.getTime(), stat.size]);
}
if (--count === 0) {
callback(result);
}
});
}
} else {
callback([]);
}
});
}
async function nodeCrawl(options) {
const {
data,
enableSymlinks,
extensions,
forceNodeFilesystemAPI,
ignore,
rootDir,
roots
} = options;
const useNativeFind = await hasNativeFindSupport(forceNodeFilesystemAPI);
return new Promise(resolve => {
const callback = list => {
const files = new Map();
const removedFiles = new Map(data.files);
for (const fileData of list) {
const [filePath, mtime, size] = fileData;
const relativeFilePath = fastPath.relative(rootDir, filePath);
const existingFile = data.files.get(relativeFilePath);
if (existingFile && existingFile[_constants.default.MTIME] === mtime) {
files.set(relativeFilePath, existingFile);
} else {
// See ../constants.js; SHA-1 will always be null and fulfilled later.
files.set(relativeFilePath, ['', mtime, size, 0, '', null]);
}
removedFiles.delete(relativeFilePath);
}
data.files = files;
resolve({
hasteMap: data,
removedFiles
});
};
if (useNativeFind) {
// TODO: consider making forceNodeFilesystemAPI the default. find(1) does
// not receive the ignore predicate, so it traverses ignored directories
// (e.g. node_modules, .git) in full and discards results afterward.
// find() via fdir prunes those subtrees at readdir time. For a typical
// project where node_modules dwarfs source files, the wasted traversal
// likely outweighs find(1)'s native speed advantage.
findNative(roots, extensions, ignore, enableSymlinks, callback);
} else {
find(roots, extensions, ignore, enableSymlinks, callback);
}
});
}
/***/ },
/***/ "./src/crawlers/watchman.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.watchmanCrawl = watchmanCrawl;
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function watchman() {
const data = _interopRequireWildcard(require("fb-watchman"));
watchman = function () {
return data;
};
return data;
}
var _constants = _interopRequireDefault(__webpack_require__("./src/constants.ts"));
var fastPath = _interopRequireWildcard(__webpack_require__("./src/lib/fast_path.ts"));
var _normalizePathSep = _interopRequireDefault(__webpack_require__("./src/lib/normalizePathSep.ts"));
var _watchmanSockname = __webpack_require__("./src/lib/watchmanSockname.ts");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const watchmanURL = 'https://facebook.github.io/watchman/docs/troubleshooting';
function watchmanError(error) {
error.message = `Watchman error: ${error.message.trim()}. Make sure watchman ` + `is running for this project. See ${watchmanURL}.`;
return error;
}
/**
* Wrap watchman capabilityCheck method as a promise.
*
* @param client watchman client
* @param caps capabilities to verify
* @returns a promise resolving to a list of verified capabilities
*/
async function capabilityCheck(client, caps) {
return new Promise((resolve, reject) => {
client.capabilityCheck(
// @ts-expect-error: incorrectly typed
caps, (error, response) => {
if (error) {
reject(error);
} else {
resolve(response);
}
});
});
}
async function watchmanCrawl(options) {
const fields = ['name', 'exists', 'mtime_ms', 'size'];
const {
console,
data,
extensions,
ignore,
rootDir,
roots
} = options;
const defaultWatchExpression = ['allof', ['type', 'f']];
const clocks = data.clocks;
const client = new (watchman().Client)();
// fb-watchman reports connection and daemon-startup failures as a client
// `error` event rather than through a command callback. Without a listener
// already attached, the first such failure is an unhandled `error` that
// takes the process down instead of letting the caller retry with the node
// crawler, so subscribe before issuing any command.
let clientError;
client.on('error', error => clientError = watchmanError(error));
if (options.watchmanSockname !== undefined) {
(0, _watchmanSockname.connectClientToSockname)(client, options.watchmanSockname);
}
const cmd = (...args) => new Promise((resolve, reject) =>
// @ts-expect-error: client is typed strictly, but incomplete
client.command(args, (error, result) => error ? reject(watchmanError(error)) : resolve(result)));
async function getWatchmanRoots(roots) {
const watchmanRoots = new Map();
await Promise.all(roots.map(async root => {
const response = await cmd('watch-project', root);
const existing = watchmanRoots.get(response.watch);
// A root can only be filtered if it was never seen with a
// relative_path before.
const canBeFiltered = !existing || existing.length > 0;
if (canBeFiltered) {
if (response.relative_path) {
watchmanRoots.set(response.watch, [...(existing || []), response.relative_path]);
} else {
// Make the filter directories an empty array to signal that this
// root was already seen and needs to be watched for all files or
// directories.
watchmanRoots.set(response.watch, []);
}
}
}));
return watchmanRoots;
}
async function queryWatchmanForDirs(rootProjectDirMappings) {
const results = new Map();
let isFresh = false;
await Promise.all([...rootProjectDirMappings].map(async ([root, directoryFilters]) => {
const expression = [...defaultWatchExpression];
const glob = [];
if (directoryFilters.length > 0) {
expression.push(['anyof', ...directoryFilters.map(dir => ['dirname', dir])]);
for (const directory of directoryFilters) {
for (const extension of extensions) {
glob.push(`${directory}/**/*.${extension}`);
}
}
} else {
for (const extension of extensions) {
glob.push(`**/*.${extension}`);
}
}
// Jest is only going to store one type of clock; a string that
// represents a local clock. However, the Watchman crawler supports
// a second type of clock that can be written by automation outside of
// Jest, called an "scm query", which fetches changed files based on
// source control mergebases. The reason this is necessary is because
// local clocks are not portable across systems, but scm queries are.
// By using scm queries, we can create the haste map on a different
// system and import it, transforming the clock into a local clock.
const since = clocks.get(fastPath.relative(rootDir, root));
const query = since === undefined ?
// Without a clock, enumerate everything matching the globs
{
expression,
fields,
glob,
glob_includedotfiles: true
} :
// With a clock available, ask only for the delta since then
{
expression,
fields,
since
};
const response = await cmd('query', root, query);
if ('warning' in response) {
console.warn('watchman warning:', response.warning);
}
// When a source-control query is used, we ignore the "is fresh"
// response from Watchman because it will be true despite the query
// being incremental.
const isSourceControlQuery = typeof since !== 'string' && since?.scm?.['mergebase-with'] !== undefined;
if (!isSourceControlQuery) {
isFresh = isFresh || response.is_fresh_instance;
}
results.set(root, response);
}));
return {
isFresh,
results
};
}
let files = data.files;
let removedFiles = new Map();
const changedFiles = new Map();
let results;
let isFresh = false;
try {
// https://facebook.github.io/watchman/docs/capabilities.html
// Check adds about ~28ms
const capabilities = await capabilityCheck(client, {
// If a required capability is missing then an error will be thrown,
// we don't need this assertion, so using optional instead.
optional: ['suffix-set']
});
if (capabilities?.capabilities['suffix-set']) {
// If available, use the optimized `suffix-set` operation:
// https://facebook.github.io/watchman/docs/expr/suffix.html#suffix-set
defaultWatchExpression.push(['suffix', extensions]);
} else {
// Otherwise use the older and less optimal suffix tuple array
defaultWatchExpression.push(['anyof', ...extensions.map(extension => ['suffix', extension])]);
}
if (options.computeSha1) {
const {
capabilities: listedCapabilities
} = await cmd('list-capabilities');
if (listedCapabilities.includes('field-content.sha1hex')) {
fields.push('content.sha1hex');
}
}
const watchmanRoots = await getWatchmanRoots(roots);
const watchmanFileResults = await queryWatchmanForDirs(watchmanRoots);
// Reset the file map if watchman was restarted and sends us a list of
// files.
if (watchmanFileResults.isFresh) {
files = new Map();
removedFiles = new Map(data.files);
isFresh = true;
}
results = watchmanFileResults.results;
} finally {
client.end();
}
if (clientError) {
throw clientError;
}
for (const [watchRoot, response] of results) {
const fsRoot = (0, _normalizePathSep.default)(watchRoot);
const relativeFsRoot = fastPath.relative(rootDir, fsRoot);
clocks.set(relativeFsRoot,
// Ensure we persist only the local clock.
typeof response.clock === 'string' ? response.clock : response.clock.clock);
for (const fileData of response.files) {
const filePath = fsRoot + path().sep + (0, _normalizePathSep.default)(fileData.name);
const relativeFilePath = fastPath.relative(rootDir, filePath);
const existingFileData = data.files.get(relativeFilePath);
// If watchman is fresh, the removed files map starts with all files
// and we remove them as we verify they still exist.
if (isFresh && existingFileData && fileData.exists) {
removedFiles.delete(relativeFilePath);
}
if (!fileData.exists) {
// No need to act on files that do not exist and were not tracked.
if (existingFileData) {
files.delete(relativeFilePath);
// If watchman is not fresh, we will know what specific files were
// deleted since we last ran and can track only those files.
if (!isFresh) {
removedFiles.set(relativeFilePath, existingFileData);
}
}
} else if (!ignore(filePath)) {
const mtime = typeof fileData.mtime_ms === 'number' ? fileData.mtime_ms : fileData.mtime_ms.toNumber();
const size = fileData.size;
let sha1hex = fileData['content.sha1hex'];
if (typeof sha1hex !== 'string' || sha1hex.length !== 40) {
sha1hex = undefined;
}
let nextData;
if (existingFileData && existingFileData[_constants.default.MTIME] === mtime) {
nextData = existingFileData;
} else if (existingFileData && sha1hex && existingFileData[_constants.default.SHA1] === sha1hex) {
nextData = [existingFileData[0], mtime, existingFileData[2], existingFileData[3], existingFileData[4], existingFileData[5]];
} else {
// See ../constants.ts
nextData = ['', mtime, size, 0, '', sha1hex ?? null];
}
files.set(relativeFilePath, nextData);
changedFiles.set(relativeFilePath, nextData);
}
}
}
data.files = files;
return {
changedFiles: isFresh ? undefined : changedFiles,
hasteMap: data,
removedFiles
};
}
/***/ },
/***/ "./src/getMockName.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const MOCKS_PATTERN = `${path().sep}__mocks__${path().sep}`;
const getMockName = filePath => {
const mockPath = filePath.split(MOCKS_PATTERN)[1];
return mockPath.slice(0, mockPath.lastIndexOf(path().extname(mockPath))).replaceAll('\\', '/');
};
var _default = exports["default"] = getMockName;
/***/ },
/***/ "./src/lib/CacheManager.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.CacheManager = void 0;
function _nodeV() {
const data = require("node:v8");
_nodeV = function () {
return data;
};
return data;
}
function _gracefulFs() {
const data = require("graceful-fs");
_gracefulFs = function () {
return data;
};
return data;
}
var _util = __webpack_require__("./src/lib/util.ts");
/**
* 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.
*/
class CacheManager {
_cachePath;
constructor(cachePath) {
this._cachePath = cachePath;
}
get path() {
return this._cachePath;
}
read() {
let hasteMap;
try {
hasteMap = (0, _nodeV().deserialize)((0, _gracefulFs().readFileSync)(this._cachePath));
} catch {
return (0, _util.createEmptyMap)();
}
// A cache written before `mockDuplicates` existed has no record of which
// files claim which mock name. Defaulting it to empty would read as "no
// duplicates anywhere" and leave watch mode unable to recover one, so treat
// it as a miss and let the crawl derive the claims again.
if (hasteMap.mockDuplicates == null) {
return (0, _util.createEmptyMap)();
}
return hasteMap;
}
persist(hasteMap) {
(0, _gracefulFs().writeFileSync)(this._cachePath, (0, _nodeV().serialize)(hasteMap));
}
}
exports.CacheManager = CacheManager;
/***/ },
/***/ "./src/lib/FileProcessor.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.FileProcessor = exports.DuplicateError = void 0;
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
var _constants = _interopRequireDefault(__webpack_require__("./src/constants.ts"));
var _getMockName = _interopRequireDefault(__webpack_require__("./src/getMockName.ts"));
var fastPath = _interopRequireWildcard(__webpack_require__("./src/lib/fast_path.ts"));
var _getPlatformExtension = _interopRequireDefault(__webpack_require__("./src/lib/getPlatformExtension.ts"));
var _isIgnorableFileError = __webpack_require__("./src/lib/isIgnorableFileError.ts");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const NODE_MODULES = `${path().sep}node_modules${path().sep}`;
const PACKAGE_JSON = `${path().sep}package.json`;
class DuplicateError extends Error {
mockPath1;
mockPath2;
constructor(mockPath1, mockPath2) {
super('Duplicated files or mocks. Please check the console for more info');
this.mockPath1 = mockPath1;
this.mockPath2 = mockPath2;
}
}
exports.DuplicateError = DuplicateError;
class FileProcessor {
_console;
_options;
_workerPool;
constructor(options, console, workerPool) {
this._console = console;
this._options = options;
this._workerPool = workerPool;
}
processFile(hasteMap, map, mocks, filePath, workerOptions) {
const rootDir = this._options.rootDir;
const setModule = (id, module) => {
let moduleMap = map.get(id);
if (!moduleMap) {
moduleMap = Object.create(null);
map.set(id, moduleMap);
}
const platform = (0, _getPlatformExtension.default)(module[_constants.default.PATH], this._options.platforms) || _constants.default.GENERIC_PLATFORM;
const existingModule = moduleMap[platform];
if (existingModule && existingModule[_constants.default.PATH] !== module[_constants.default.PATH]) {
const method = this._options.throwOnModuleCollision ? 'error' : 'warn';
this._console[method]([`jest-haste-map: Haste module naming collision: ${id}`, ' The following files share their name; please adjust your hasteImpl:', ` * <rootDir>${path().sep}${existingModule[_constants.default.PATH]}`, ` * <rootDir>${path().sep}${module[_constants.default.PATH]}`, ''].join('\n'));
if (this._options.throwOnModuleCollision) {
throw new DuplicateError(existingModule[_constants.default.PATH], module[_constants.default.PATH]);
}
// We do NOT want consumers to use a module that is ambiguous.
delete moduleMap[platform];
if (Object.keys(moduleMap).length === 0) {
map.delete(id);
}
let dupsByPlatform = hasteMap.duplicates.get(id);
if (dupsByPlatform == null) {
dupsByPlatform = new Map();
hasteMap.duplicates.set(id, dupsByPlatform);
}
const dups = new Map([[module[_constants.default.PATH], module[_constants.default.TYPE]], [existingModule[_constants.default.PATH], existingModule[_constants.default.TYPE]]]);
dupsByPlatform.set(platform, dups);
return;
}
const dupsByPlatform = hasteMap.duplicates.get(id);
if (dupsByPlatform != null) {
const dups = dupsByPlatform.get(platform);
if (dups != null) {
dups.set(module[_constants.default.PATH], module[_constants.default.TYPE]);
}
return;
}
moduleMap[platform] = module;
};
const relativeFilePath = fastPath.relative(rootDir, filePath);
const fileMetadata = hasteMap.files.get(relativeFilePath);
if (!fileMetadata) {
throw new Error('jest-haste-map: File to process was not found in the haste map.');
}
const moduleMetadata = hasteMap.map.get(fileMetadata[_constants.default.ID]);
const computeSha1 = this._options.computeSha1 && !fileMetadata[_constants.default.SHA1];
const workerReply = metadata => {
// `1` for truthy values instead of `true` to save cache space.
fileMetadata[_constants.default.VISITED] = 1;
const metadataId = metadata.id;
const metadataModule = metadata.module;
if (metadataId && metadataModule) {
fileMetadata[_constants.default.ID] = metadataId;
setModule(metadataId, metadataModule);
}
fileMetadata[_constants.default.DEPENDENCIES] = metadata.dependencies ? metadata.dependencies.join(_constants.default.DEPENDENCY_DELIM) : '';
if (computeSha1) {
fileMetadata[_constants.default.SHA1] = metadata.sha1;
}
};
const workerError = error => {
if (typeof error !== 'object' || !error.message || !error.stack) {
error = new Error(error);
error.stack = ''; // Remove stack for stack-less errors.
}
// `EACCES` is not in `isIgnorableFileError`: an unreadable file is fatal
// to a watcher, but here it only means this one file cannot be indexed.
if (error.code !== 'EACCES' && !(0, _isIgnorableFileError.isIgnorableFileError)(error)) {
throw error;
}
// If a file cannot be read we remove it from the file list and
// ignore the failure silently.
hasteMap.files.delete(relativeFilePath);
};
// If we retain all files in the virtual HasteFS representation, we avoid
// reading them if they aren't important (node_modules).
if (this._options.retainAllFiles && filePath.includes(NODE_MODULES)) {
if (computeSha1) {
return this._getWorker(workerOptions).getSha1({
computeDependencies: this._options.computeDependencies,
computeSha1,
dependencyExtractor: this._options.dependencyExtractor,
filePath,
hasteImplModulePath: this._options.hasteImplModulePath,
rootDir
}).then(workerReply, workerError);
}
return null;
}
if (this._options.mocksPattern && this._options.mocksPattern.test(filePath)) {
const mockPath = (0, _getMockName.default)(filePath);
const existingMockPath = mocks.get(mockPath);
if (existingMockPath) {
const secondMockPath = fastPath.relative(rootDir, filePath);
if (existingMockPath !== secondMockPath) {
const method = this._options.throwOnModuleCollision ? 'error' : 'warn';
this._console[method]([`jest-haste-map: duplicate manual mock found: ${mockPath}`, ' The following files share their name; please delete one of them:', ` * <rootDir>${path().sep}${existingMockPath}`, ` * <rootDir>${path().sep}${secondMockPath}`, ''].join('\n'));
if (this._options.throwOnModuleCollision) {
throw new DuplicateError(existingMockPath, secondMockPath);
}
let duplicates = hasteMap.mockDuplicates.get(mockPath);
if (duplicates == null) {
duplicates = new Set();
hasteMap.mockDuplicates.set(mockPath, duplicates);
}
duplicates.add(existingMockPath).add(secondMockPath);
}
}
mocks.set(mockPath, relativeFilePath);
}
if (fileMetadata[_constants.default.VISITED]) {
if (!fileMetadata[_constants.default.ID]) {
return null;
}
const moduleId = fileMetadata[_constants.default.ID];
const platform = (0, _getPlatformExtension.default)(filePath, this._options.platforms) || _constants.default.GENERIC_PLATFORM;
if (moduleMetadata != null) {
const module = moduleMetadata[platform];
if (module == null) {
return null;
}
let modulesByPlatform = map.get(moduleId);
if (!modulesByPlatform) {
modulesByPlatform = Object.create(null);
map.set(moduleId, modulesByPlatform);
}
modulesByPlatform[platform] = module;
return null;
}
// A haste name involved in a collision has no `map` entry — it was
// deleted when the collision was recorded — but `duplicates` survives a
// rebuild and already lists this file, so its metadata is up to date and
// re-extracting it would change nothing.
if (hasteMap.duplicates.get(moduleId)?.get(platform)?.has(relativeFilePath)) {
return null;
}
}
return this._getWorker(workerOptions).worker({
computeDependencies: this._options.computeDependencies,
computeSha1,
dependencyExtractor: this._options.dependencyExtractor,
filePath,
hasteImplModulePath: this._options.hasteImplModulePath,
rootDir
}).then(workerReply, workerError);
}
buildHasteMap(data, recoverDuplicates) {
const {
removedFiles,
changedFiles,
hasteMap
} = data;
// If any files were removed or we did not track what files changed, process
// every file looking for changes. Otherwise, process only changed files.
let map;
let mocks;
let filesToProcess;
if (changedFiles === undefined || removedFiles.size > 0) {
map = new Map();
mocks = new Map();
// Re-derived along with `mocks` below; keeping the old entries would let a
// file deleted while Jest was not running be promoted back later.
hasteMap.mockDuplicates = new Map();
filesToProcess = hasteMap.files;
} else {
map = hasteMap.map;
mocks = hasteMap.mocks;
filesToProcess = changedFiles;
}
for (const [relativeFilePath, fileMetadata] of removedFiles) {
recoverDuplicates(hasteMap, relativeFilePath, fileMetadata[_constants.default.ID]);
}
const promises = [];
try {
for (const relativeFilePath of filesToProcess.keys()) {
if (this._options.skipPackageJson && relativeFilePath.endsWith(PACKAGE_JSON)) {
continue;
}
// SHA-1, if requested, should already be present thanks to the crawler.
const filePath = fastPath.resolve(this._options.rootDir, relativeFilePath);
const promise = this.processFile(hasteMap, map, mocks, filePath);
if (promise) {
promises.push(promise);
}
}
} catch (error) {
// `processFile` throws synchronously on a duplicate manual mock when
// `throwOnModuleCollision` is set, which would otherwise escape before
// the settlement handlers below can shut the worker farm down.
this._workerPool.end();
throw error;
}
return Promise.all(promises).then(() => {
this._workerPool.end();
hasteMap.map = map;
hasteMap.mocks = mocks;
return hasteMap;
}, error => {
this._workerPool.end();
throw error;
});
}
_getWorker(options) {
return this._workerPool.get(options?.forceInBand);
}
}
exports.FileProcessor = FileProcessor;
/***/ },
/***/ "./src/lib/WorkerPool.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.WorkerPool = void 0;
function _jestWorker() {
const data = require("jest-worker");
_jestWorker = function () {
return data;
};
return data;
}
var _worker = __webpack_require__("./src/worker.ts");
/**
* 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.
*/
const inBandWorker = {
getSha1: _worker.getSha1,
worker: _worker.worker
};
class WorkerPool {
_options;
_farm = null;
constructor(options) {
this._options = options;
}
get(forceInBand) {
if (forceInBand || this._options.maxWorkers <= 1) {
return inBandWorker;
}
if (!this._farm) {
this._farm = new (_jestWorker().Worker)(this._options.workerPath, {
enableWorkerThreads: this._options.workerThreads,
exposedMethods: ['getSha1', 'worker'],
forkOptions: {
serialization: 'json'
},
maxRetries: 3,
numWorkers: this._options.maxWorkers
});
}
return this._farm;
}
end() {
this._farm?.end();
this._farm = null;
}
}
exports.WorkerPool = WorkerPool;
/***/ },
/***/ "./src/lib/buildIgnoreMatcher.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.buildIgnoreMatcher = buildIgnoreMatcher;
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const NODE_MODULES = `${path().sep}node_modules${path().sep}`;
function buildIgnoreMatcher(ignorePattern, retainAllFiles) {
return filePath => {
const ignoreMatched = ignorePattern instanceof RegExp ? ignorePattern.test(filePath) : ignorePattern && ignorePattern(filePath);
return Boolean(ignoreMatched) || !retainAllFiles && filePath.includes(NODE_MODULES);
};
}
/***/ },
/***/ "./src/lib/dependencyExtractor.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.extractor = void 0;
/**
* 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.
*/
const NOT_A_DOT = '(?<!\\.\\s*)';
const CAPTURE_STRING_LITERAL = pos => `([\`'"])([^'"\`]*?)(?:\\${pos})`;
const WORD_SEPARATOR = '\\b';
const LEFT_PARENTHESIS = '\\(';
const RIGHT_PARENTHESIS = '\\)';
const WHITESPACE = '\\s*';
const OPTIONAL_COMMA = '(:?,\\s*)?';
function createRegExp(parts, flags) {
return new RegExp(parts.join(''), flags);
}
function alternatives(...parts) {
return `(?:${parts.join('|')})`;
}
function functionCallStart(...names) {
return [NOT_A_DOT, WORD_SEPARATOR, alternatives(...names), WHITESPACE, LEFT_PARENTHESIS, WHITESPACE];
}
const BLOCK_COMMENT_RE = /\/\*[^]*?\*\//g;
const LINE_COMMENT_RE = /\/\/.*/g;
const REQUIRE_OR_DYNAMIC_IMPORT_RE = createRegExp([...functionCallStart('require', 'import'), CAPTURE_STRING_LITERAL(1), WHITESPACE, OPTIONAL_COMMA, RIGHT_PARENTHESIS], 'g');
const IMPORT_OR_EXPORT_RE = createRegExp(['\\b(?:import|export)\\s+(?!type(?:of)?\\s+)(?:[^\'"]+\\s+from\\s+)?', CAPTURE_STRING_LITERAL(1)], 'g');
const JEST_EXTENSIONS_RE = createRegExp([...functionCallStart('jest\\s*\\.\\s*(?:requireActual|requireMock|createMockFromModule)'), CAPTURE_STRING_LITERAL(1), WHITESPACE, OPTIONAL_COMMA, RIGHT_PARENTHESIS], 'g');
const extractor = exports.extractor = {
extract(code) {
const dependencies = new Set();
const addDependency = (match, _, dep) => {
dependencies.add(dep);
return match;
};
code.replaceAll(BLOCK_COMMENT_RE, '').replaceAll(LINE_COMMENT_RE, '').replace(IMPORT_OR_EXPORT_RE, addDependency).replace(REQUIRE_OR_DYNAMIC_IMPORT_RE, addDependency).replace(JEST_EXTENSIONS_RE, addDependency);
return dependencies;
}
};
/***/ },
/***/ "./src/lib/fast_path.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.relative = relative;
exports.resolve = resolve;
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
// rootDir and filename must be absolute paths (resolved)
function relative(rootDir, filename) {
return filename.startsWith(rootDir + path().sep) ? filename.slice(rootDir.length + 1) : path().relative(rootDir, filename);
}
const INDIRECTION_FRAGMENT = `..${path().sep}`;
// rootDir must be an absolute path and relativeFilename must be simple
// (e.g.: foo/bar or ../foo/bar, but never ./foo or foo/../bar)
function resolve(rootDir, relativeFilename) {
return relativeFilename.startsWith(INDIRECTION_FRAGMENT) ? path().resolve(rootDir, relativeFilename) : rootDir + path().sep + relativeFilename;
}
/***/ },
/***/ "./src/lib/getPlatformExtension.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = getPlatformExtension;
/**
* 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.
*/
const SUPPORTED_PLATFORM_EXTS = new Set(['android', 'ios', 'native', 'web']);
// Extract platform extension: index.ios.js -> ios
function getPlatformExtension(file, platforms) {
const last = file.lastIndexOf('.');
const secondToLast = file.lastIndexOf('.', last - 1);
if (secondToLast === -1) {
return null;
}
const platform = file.slice(secondToLast + 1, last);
// If an overriding platform array is passed, check that first
if (platforms && platforms.includes(platform)) {
return platform;
}
return SUPPORTED_PLATFORM_EXTS.has(platform) ? platform : null;
}
/***/ },
/***/ "./src/lib/isIgnorableFileError.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.isIgnorableFileError = isIgnorableFileError;
function os() {
const data = _interopRequireWildcard(require("node:os"));
os = function () {
return data;
};
return data;
}
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const platform = os().platform();
/**
* A file can vanish between the moment it is observed and the moment it is
* read, which is `ENOENT`. On Windows an outside process holding the file open
* -- `git maintenance` touching `.git/index.lock` or `.git/objects`, for
* instance -- surfaces as `EPERM` instead. Neither means anything is wrong with
* the watcher or the crawl, so neither should abort it.
*/
function isIgnorableFileError(error) {
return error.code === 'ENOENT' || error.code === 'EPERM' && platform === 'win32';
}
/***/ },
/***/ "./src/lib/normalizePathSep.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
let normalizePathSep;
if (path().sep === '/') {
normalizePathSep = filePath => filePath;
} else {
normalizePathSep = filePath => filePath.replaceAll('/', path().sep);
}
var _default = exports["default"] = normalizePathSep;
/***/ },
/***/ "./src/lib/util.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.copy = copy;
exports.copyMap = copyMap;
exports.createEmptyMap = createEmptyMap;
/**
* 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.
*/
function copy(object) {
return Object.assign(Object.create(null), object);
}
function copyMap(input) {
return new Map(input);
}
function createEmptyMap() {
return {
clocks: new Map(),
duplicates: new Map(),
files: new Map(),
map: new Map(),
mockDuplicates: new Map(),
mocks: new Map()
};
}
/***/ },
/***/ "./src/lib/walk.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.walk = walk;
function os() {
const data = _interopRequireWildcard(require("node:os"));
os = function () {
return data;
};
return data;
}
function _fdir() {
const data = require("fdir");
_fdir = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require("graceful-fs"));
fs = function () {
return data;
};
return data;
}
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const DEFAULT_CONCURRENCY = Math.max(os().availableParallelism() * 4, 32);
// fdir returns directory paths with a trailing separator; strip it.
const TRAILING_SEP_RE = /[/\\]+$/;
// `includeDirs` and the `dir` entry kind have no caller yet: they are for
// symlinked directories, where following a link means walking its target.
function walk(options, done) {
const {
concurrency = DEFAULT_CONCURRENCY,
enableSymlinks = false,
exclude,
onEntry,
onError,
root,
statCache,
...fdirOpts
} = options;
// Wrap exclude to strip fdir's trailing path separator before delegating.
const normalizedExclude = exclude ? p => exclude(p.replace(TRAILING_SEP_RE, '')) : undefined;
const builder = new (_fdir().fdir)({
...fdirOpts,
// Used for directory pruning (prevents fdir from recursing into subtrees).
// fdir calls exclude(dirName, dirPath) — dirName is the basename and dirPath
// is the full path, so dirName is unused (it's a subset of dirPath).
exclude: normalizedExclude ? (_dirName, dirPath) => normalizedExclude(dirPath) : undefined,
excludeSymlinks: !enableSymlinks,
// Also used as an output filter so ignored paths never enter the stat pool.
// Applies to both file and dir entries (dirs also have a trailing sep, hence
// the shared normalizedExclude that strips it). fdir includes entries where
// the filter returns true, so we negate: include when NOT excluded.
filters: normalizedExclude ? [path => !normalizedExclude(path)] : [],
fs: fs(),
includeBasePath: true,
// resolveSymlinks: false — `fdir`'s resolveSymlinks calls realpath and emits
// the resolved path, losing the original symlink path. haste-map must track
// files under the path Jest uses to require them (the symlink path), so we
// keep the original path and use fs.stat to follow the symlink for stats.
resolveSymlinks: false,
// Unreadable directories are skipped and the walk continues with partial
// results.
suppressErrors: true
});
const statFn = enableSymlinks ? fs().stat : fs().lstat;
builder.crawl(root).withCallback((crawlErr, rawPaths) => {
// suppressErrors: true means crawlErr is always null, but keep the guard
// as a safety net in case fdir's default changes.
/* c8 ignore next 4 */
if (crawlErr != null) {
done(crawlErr);
return;
}
// Two-phase design (readdir-all via fdir, then stat-all here): fdir does not
// stat during the crawl. Pipelining lstat with readdir would not improve
// throughput on large repos anyway — both share libuv's thread pool, which
// the concurrent readdir calls already saturate.
let index = 0;
let inflight = 0;
// Prevent done() being called twice: once from the last stat callback and
// once from the post-while guard when concurrency > remaining paths.
let finished = false;
function pump() {
while (inflight < concurrency && index < rawPaths.length) {
const filePath = rawPaths[index++].replace(TRAILING_SEP_RE, '');
const cached = statCache?.get(filePath);
if (cached != null) {
onEntry(cached.isDirectory() ? 'dir' : 'file', filePath, cached);
continue;
}
inflight++;
statFn(filePath, (err, stats) => {
inflight--;
if (err) {
onError?.(err);
} else {
statCache?.set(filePath, stats);
onEntry(stats.isDirectory() ? 'dir' : 'file', filePath, stats);
}
if (index < rawPaths.length) {
pump();
} else if (inflight === 0 && !finished) {
finished = true;
done(null);
}
});
}
if (inflight === 0 && !finished) {
finished = true;
done(null);
}
}
pump();
});
}
/***/ },
/***/ "./src/lib/watchmanSockname.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.connectClientToSockname = connectClientToSockname;
exports.getWatchmanAvailability = getWatchmanAvailability;
function _nodeChild_process() {
const data = require("node:child_process");
_nodeChild_process = function () {
return data;
};
return data;
}
function net() {
const data = _interopRequireWildcard(require("node:net"));
net = function () {
return data;
};
return data;
}
function os() {
const data = _interopRequireWildcard(require("node:os"));
os = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function _nodeUtil() {
const data = require("node:util");
_nodeUtil = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require("graceful-fs"));
fs = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const NOT_INSTALLED = {
installed: false,
sockname: undefined
};
// Installed, but `get-sockname` failed. Attempting the crawl lets fb-watchman
// surface the failure through the existing warn-and-fall-back path.
const BROKEN = {
installed: true,
sockname: undefined
};
// Codes `child_process` reports when the binary itself could not be started.
// Anything else, including a non-zero exit, means watchman is there but not
// answering, which is the `BROKEN` case.
const SPAWN_FAILURE_CODES = new Set(['EACCES', 'ENOENT', 'ENOTDIR', 'EPERM']);
// Connecting to a live local socket takes well under a millisecond, but a
// socket whose listener is stopped or whose backlog is full accepts neither
// outcome, and there is no default timeout. Without a bound the probe would
// hang startup before a single test runs.
const CONNECT_PROBE_TIMEOUT = 1000;
let availabilityPromise;
/**
* Resolved once per process, not once per `cacheDirectory`: the socket path is
* a property of the machine and the user, not of any one project. With
* per-project cache directories the first caller therefore decides where the
* entry is written, and later callers reuse the resolved value.
*/
function getWatchmanAvailability(cacheDirectory) {
availabilityPromise ??= resolveAvailability(cacheDirectory);
return availabilityPromise;
}
async function resolveAvailability(cacheDirectory) {
const socknameFromEnv = process.env.WATCHMAN_SOCK;
if (socknameFromEnv) {
return {
installed: true,
sockname: socknameFromEnv
};
}
const cacheFilePath = socknameCacheFilePath(cacheDirectory);
const cachedSockname = readCachedSockname(cacheFilePath);
if (cachedSockname !== undefined && (await canConnect(cachedSockname))) {
return {
installed: true,
sockname: cachedSockname
};
}
const availability = await runGetSockname();
if (availability.sockname === undefined) {
if (cachedSockname !== undefined) {
removeCachedSockname(cacheFilePath);
}
} else {
writeCachedSockname(cacheFilePath, availability.sockname);
}
return availability;
}
async function runGetSockname() {
let stdout;
try {
({
stdout
} = await (0, _nodeUtil().promisify)(_nodeChild_process().execFile)('watchman', ['--no-pretty', 'get-sockname']));
} catch (error) {
if ((0, _jestUtil().isError)(error) && isSpawnFailure(error)) {
return NOT_INSTALLED;
}
return BROKEN;
}
try {
const response = JSON.parse(stdout);
if (typeof response.sockname === 'string' && response.error == null) {
return {
installed: true,
sockname: response.sockname
};
}
} catch {}
return BROKEN;
}
/**
* fb-watchman has no option for passing a known socket path; the only way to
* skip its `get-sockname` child process is the `WATCHMAN_SOCK` environment
* variable, which `Client.connect` reads synchronously. Set it just for that
* synchronous window so no mutation is observable afterwards.
*/
function connectClientToSockname(client, sockname) {
const previousSockname = process.env.WATCHMAN_SOCK;
process.env.WATCHMAN_SOCK = sockname;
try {
client.connect();
} finally {
if (previousSockname === undefined) {
delete process.env.WATCHMAN_SOCK;
} else {
process.env.WATCHMAN_SOCK = previousSockname;
}
}
}
function isSpawnFailure(error) {
const {
code
} = error;
return code !== undefined && SPAWN_FAILURE_CODES.has(code);
}
function currentUserKey() {
const uid = process.getuid?.();
if (uid !== undefined) {
return String(uid);
}
try {
// Windows has no uid. `userInfo` throws when the account has no entry to
// look up, which a container running as an unmapped user can produce.
return os().userInfo().username.replaceAll(/\W/g, '-');
} catch {
return 'default';
}
}
function socknameCacheFilePath(cacheDirectory) {
// The socket path is per-user, so two users sharing a cache directory need
// separate entries. The name stays predictable, which means a local user can
// pre-create it as a symlink and redirect the read and the write - the same
// exposure every other file in this directory already has, since the cache
// is written with plain `readFileSync`/`writeFileSync` too. Hardening one
// file in isolation would not buy anything; it needs `CacheManager` as well.
return path().join(cacheDirectory, `haste-map-watchman-sockname-${currentUserKey()}`);
}
function readCachedSockname(cacheFilePath) {
let sockname;
try {
sockname = fs().readFileSync(cacheFilePath, 'utf8').trim();
} catch {
return undefined;
}
return sockname.length > 0 ? sockname : undefined;
}
function writeCachedSockname(cacheFilePath, sockname) {
try {
fs().writeFileSync(cacheFilePath, sockname);
} catch {
// The cache is best-effort; a failed write only costs the next run a
// `get-sockname` spawn.
}
}
function removeCachedSockname(cacheFilePath) {
try {
fs().rmSync(cacheFilePath, {
force: true
});
} catch {
// `force` only ignores a missing file, so a read-only cache directory
// still throws. Availability is resolved before the crawl starts, outside
// the node-crawler fallback, so letting this escape would fail the run
// over a cache entry.
}
}
function canConnect(sockname) {
return new Promise(resolve => {
const socket = net().createConnection(sockname, () => {
socket.destroy();
resolve(true);
});
socket.setTimeout(CONNECT_PROBE_TIMEOUT, () => {
socket.destroy();
resolve(false);
});
socket.once('error', () => {
socket.destroy();
resolve(false);
});
});
}
/***/ },
/***/ "./src/watchers/ChangeQueue.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.ChangeQueue = void 0;
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
var _HasteFS = _interopRequireDefault(__webpack_require__("./src/HasteFS.ts"));
var _ModuleMap = _interopRequireDefault(__webpack_require__("./src/ModuleMap.ts"));
var _constants = _interopRequireDefault(__webpack_require__("./src/constants.ts"));
var _getMockName = _interopRequireDefault(__webpack_require__("./src/getMockName.ts"));
var fastPath = _interopRequireWildcard(__webpack_require__("./src/lib/fast_path.ts"));
var _getPlatformExtension = _interopRequireDefault(__webpack_require__("./src/lib/getPlatformExtension.ts"));
var _normalizePathSep = _interopRequireDefault(__webpack_require__("./src/lib/normalizePathSep.ts"));
var _util = __webpack_require__("./src/lib/util.ts");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const CHANGE_INTERVAL = 30;
class ChangeQueue {
_callbacks;
_extensions;
_changeInterval;
_changeQueue = Promise.resolve();
_eventsQueue = [];
_pendingEventKeys = new Set();
_hasteMap;
// We only need to copy the entire haste map once per "frame".
_mustCopy = true;
constructor(hasteMap, extensions, callbacks) {
this._hasteMap = hasteMap;
this._extensions = new Set(extensions.map(extension => `.${extension}`));
this._callbacks = callbacks;
}
start() {
this._changeInterval = setInterval(() => this._emitChange(), CHANGE_INTERVAL);
}
stop() {
if (this._changeInterval) {
clearInterval(this._changeInterval);
}
}
onChange(type, filePath, root, stat) {
const {
ignore,
rootDir
} = this._callbacks;
filePath = path().join(root, (0, _normalizePathSep.default)(filePath));
if (stat && stat.isDirectory() || ignore(filePath) || !this._extensions.has(path().extname(filePath))) {
return;
}
const relativeFilePath = fastPath.relative(rootDir, filePath);
const fileMetadata = this._hasteMap.files.get(relativeFilePath);
// The file has been accessed, not modified.
if (type === 'change' && fileMetadata && stat && fileMetadata[_constants.default.MTIME] === stat.mtime.getTime()) {
return;
}
this._changeQueue = this._changeQueue.then(() => {
const dedupKey = `${type}:${filePath}:${stat ? stat.mtime.getTime() : ''}`;
if (this._pendingEventKeys.has(dedupKey)) {
return null;
}
if (this._mustCopy) {
this._mustCopy = false;
this._hasteMap = {
clocks: new Map(this._hasteMap.clocks),
duplicates: new Map(this._hasteMap.duplicates),
files: new Map(this._hasteMap.files),
map: new Map(this._hasteMap.map),
mockDuplicates: new Map(this._hasteMap.mockDuplicates),
mocks: new Map(this._hasteMap.mocks)
};
}
const add = () => {
this._pendingEventKeys.add(dedupKey);
this._eventsQueue.push({
filePath,
stat,
type
});
return null;
};
const currentMetadata = this._hasteMap.files.get(relativeFilePath);
// If it's not an addition, delete the file and all its metadata.
if (currentMetadata != null) {
const moduleName = currentMetadata[_constants.default.ID];
const platform = (0, _getPlatformExtension.default)(filePath, this._callbacks.platforms) || _constants.default.GENERIC_PLATFORM;
this._hasteMap.files.delete(relativeFilePath);
let moduleMap = this._hasteMap.map.get(moduleName);
if (moduleMap != null) {
// We are forced to copy the object because jest-haste-map
// exposes the map as an immutable entity.
moduleMap = (0, _util.copy)(moduleMap);
delete moduleMap[platform];
if (Object.keys(moduleMap).length === 0) {
this._hasteMap.map.delete(moduleName);
} else {
this._hasteMap.map.set(moduleName, moduleMap);
}
}
if (this._callbacks.mocksPattern && this._callbacks.mocksPattern.test(filePath)) {
this._removeMock((0, _getMockName.default)(filePath), relativeFilePath);
}
this._callbacks.recoverDuplicates(this._hasteMap, relativeFilePath, moduleName);
}
// If the file was added or changed, parse it and update the haste map.
if (type === 'add' || type === 'change') {
(0, _jestUtil().invariant)(stat, 'since the file exists or changed, it should have stats');
const newMetadata = ['', stat.mtime.getTime(), stat.size, 0, '', null];
this._hasteMap.files.set(relativeFilePath, newMetadata);
const promise = this._callbacks.processFile(this._hasteMap, filePath);
this._callbacks.cleanup();
if (promise) {
return promise.then(add);
} else {
// If a file in node_modules has changed, emit an event regardless.
add();
}
} else {
add();
}
return null;
}).catch(error => {
this._callbacks.onError(error);
});
}
// A mock name can be claimed by several files. Dropping the name outright
// when one of them goes loses the others until they change or Jest restarts.
_removeMock(mockName, relativeFilePath) {
const claimants = this._hasteMap.mockDuplicates.get(mockName);
if (claimants != null) {
// Copied because the previous frame's ChangeEvent still holds the old set.
const remaining = new Set(claimants);
remaining.delete(relativeFilePath);
if (remaining.size === 0) {
this._hasteMap.mockDuplicates.delete(mockName);
} else {
this._hasteMap.mockDuplicates.set(mockName, remaining);
}
}
if (this._hasteMap.mocks.get(mockName) !== relativeFilePath) {
// Another file owns the name, so there is nothing to replace.
return;
}
// Claimants are recorded in the order they were processed and the last one
// wins, so search from the end to land on the same file a rebuild would.
// `files` has already had this path deleted, so a survivor found here is one
// the haste map still tracks.
const survivor = [...(this._hasteMap.mockDuplicates.get(mockName) ?? [])].reverse().find(candidate => this._hasteMap.files.has(candidate));
if (survivor == null) {
this._hasteMap.mocks.delete(mockName);
} else {
this._hasteMap.mocks.set(mockName, survivor);
}
}
_emitChange() {
if (this._eventsQueue.length > 0) {
this._mustCopy = true;
this._pendingEventKeys.clear();
const {
emit,
rootDir
} = this._callbacks;
const changeEvent = {
eventsQueue: this._eventsQueue,
hasteFS: new _HasteFS.default({
files: this._hasteMap.files,
rootDir
}),
moduleMap: new _ModuleMap.default({
duplicates: this._hasteMap.duplicates,
map: this._hasteMap.map,
mocks: this._hasteMap.mocks,
rootDir
})
};
emit(changeEvent);
this._eventsQueue = [];
}
}
}
exports.ChangeQueue = ChangeQueue;
/***/ },
/***/ "./src/watchers/ParcelWatcher.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.ParcelWatcher = void 0;
function _nodeEvents() {
const data = require("node:events");
_nodeEvents = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function _anymatch() {
const data = _interopRequireDefault(require("anymatch"));
_anymatch = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require("graceful-fs"));
fs = function () {
return data;
};
return data;
}
var _isIgnorableFileError = __webpack_require__("./src/lib/isIgnorableFileError.ts");
var _common = __webpack_require__("./src/watchers/common.ts");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
// WatcherDriver always instantiates WatchmanWatcher directly when useWatchman
// is true, so the 'watchman' branch below is unreachable through normal Jest
// operation. It exists so ParcelWatcher can be used standalone (e.g. in tests
// or custom tooling) with watchman as the parcel backend.
function pickBackend(useWatchman) {
if (useWatchman) {
return 'watchman';
}
switch (process.platform) {
case 'darwin':
return 'fs-events';
case 'linux':
return 'inotify';
case 'win32':
return 'windows';
default:
// Jest only supports the three platforms above. Elsewhere, omit the
// option so parcel's own default resolution picks the best compiled
// backend
return undefined;
}
}
// Both forms are needed: the bare glob prunes the directory itself from
// parcel's initial scan, while the `/**` variant filters per-event paths —
// fs-events delivers paths inside the directory that only match the latter.
const VCS_IGNORE_GLOBS = ['**/.git', '**/.git/**', '**/.hg', '**/.hg/**', '**/.sl', '**/.sl/**'];
const MAX_RESUBSCRIBE_ATTEMPTS = 3;
// Give transient conditions (fd exhaustion, inotify limits) a moment to
// clear instead of burning every attempt within milliseconds.
const RESUBSCRIBE_RETRY_DELAY = 1000;
class ParcelWatcher extends _nodeEvents().EventEmitter {
root;
_console;
_dot;
_glob;
_doIgnore;
_backend;
_parcelIgnore;
_subscription = null;
_closed = false;
constructor(root, opts) {
super();
this.root = path().resolve(root);
this._console = opts.console;
this._dot = opts.dot;
this._glob = opts.glob;
// Fallback for patterns parcel's native matcher can't take: flagged
// regexes, and sources std::regex rejects or matches differently.
this._doIgnore = opts.ignored ? (0, _anymatch().default)(opts.ignored) : () => false;
this._backend = pickBackend(opts.useWatchman);
// Parcel matches the pattern against the path relative to the watched
// root, same as isFileIncluded does — but flags are unsupported. The VCS
// globs are always appended: the path parcel matches has no leading
// separator, so HasteMap's separator-anchored VCS alternation
// (`/\.git/|…`) never matches the root's own `.git` directory.
this._parcelIgnore = opts.ignored instanceof RegExp && opts.ignored.flags === '' ? [opts.ignored, ...VCS_IGNORE_GLOBS] : VCS_IGNORE_GLOBS;
setImmediate(() => this._start());
}
_parcelOpts() {
return {
backend: this._backend,
ignore: this._parcelIgnore
};
}
// close() ends with removeAllListeners(), and an 'error' emit without a
// listener throws. Async work started before close() can still fail after
// it (a hung subscribe finally rejecting, an in-flight lstat) — swallow
// those instead of crashing the process.
_emitError(error) {
if (this._closed) {
return;
}
this.emit('error', error);
}
// Parcel compiles the regex source with C++ std::regex, which rejects some
// JS-valid constructs (lookbehind, named groups, \p{…}) at subscribe time.
// There is no way to validate against std::regex from JS ahead of time, so
// rejection is the signal: drop the regex (per-event filtering still happens
// through _doIgnore) and retry with the VCS globs alone.
async _subscribe() {
// Watch mode is the only consumer of the native binding — loading it with
// the module would take down every jest run on platforms without a
// prebuild. The build's lazy commonjs transform already defers top-level
// imports, but that guarantee lives in build config; keep it in the code.
const {
subscribe
} = require('@parcel/watcher');
try {
return await subscribe(this.root, this._handleEvents, this._parcelOpts());
} catch (error) {
const rejectedPattern = this._parcelIgnore.find(pattern => pattern instanceof RegExp);
if (rejectedPattern == null) {
throw error;
}
// The retry can also swallow failures unrelated to the regex, silently
// costing the native-level ignore for the session — make it diagnosable.
this._console.warn(`jest-haste-map: subscribing with the ignore pattern ${rejectedPattern} failed (${error}); ignored paths will still be watched and filtered in JS`);
this._parcelIgnore = VCS_IGNORE_GLOBS;
return subscribe(this.root, this._handleEvents, this._parcelOpts());
}
}
async _resubscribe(cause) {
// Events occurring while the watcher is down are lost — they surface on
// the next restart, when the startup crawl picks up the mtime changes.
this._console.warn(`jest-haste-map: watch error (${cause}); re-subscribing. Changes made in the meantime are not detected until the next restart`);
this._subscription?.unsubscribe().catch(() => undefined);
this._subscription = null;
let lastError = cause;
for (let attempt = 0; attempt < MAX_RESUBSCRIBE_ATTEMPTS; attempt++) {
if (attempt > 0) {
await new Promise(resolve => {
setTimeout(resolve, RESUBSCRIBE_RETRY_DELAY).unref();
});
if (this._closed) {
return;
}
}
try {
const subscription = await this._subscribe();
if (this._closed) {
await subscription.unsubscribe();
return;
}
this._subscription = subscription;
return;
} catch (error) {
lastError = error;
}
}
this._emitError(lastError);
}
async _start() {
try {
const subscription = await this._subscribe();
// WatcherDriver may time out and call close() while subscribe() was in
// flight. Unsubscribe immediately rather than leaking the subscription.
if (this._closed) {
await subscription.unsubscribe();
return;
}
this._subscription = subscription;
this.emit('ready');
} catch (error) {
this._emitError(error);
}
}
_handleEvents = (err, events) => {
if (this._closed) {
return;
}
if (err) {
// Parcel tears the subscription down before reporting a watcher error
// (Backend::handleWatcherError unwatches it and Watcher::notifyError
// clears its callbacks), so no further events can arrive on it —
// recover by subscribing anew, like WatchmanWatcher re-inits on a
// lost connection.
void this._resubscribe(err);
return;
}
for (const event of events) {
const absPath = event.path;
const relPath = path().relative(this.root, absPath);
if (!(0, _common.isFileIncluded)(this._glob, this._dot, this._doIgnore, relPath)) {
continue;
}
if (event.type === 'delete') {
this.emit(_common.DELETE_EVENT, relPath, this.root);
this.emit(_common.ALL_EVENT, _common.DELETE_EVENT, relPath, this.root);
} else {
const type = event.type === 'create' ? _common.ADD_EVENT : _common.CHANGE_EVENT;
fs().lstat(absPath, (error, stat) => {
if (error) {
if (!(0, _isIgnorableFileError.isIgnorableFileError)(error)) {
this._emitError(error);
}
return;
}
this.emit(type, relPath, this.root, stat);
this.emit(_common.ALL_EVENT, type, relPath, this.root, stat);
});
}
}
};
async close() {
this._closed = true;
await this._subscription?.unsubscribe();
this._subscription = null;
this.removeAllListeners();
}
}
exports.ParcelWatcher = ParcelWatcher;
/***/ },
/***/ "./src/watchers/common.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.DELETE_EVENT = exports.CHANGE_EVENT = exports.ALL_EVENT = exports.ADD_EVENT = void 0;
exports.isFileIncluded = isFileIncluded;
function _picomatch() {
const data = _interopRequireDefault(require("picomatch"));
_picomatch = function () {
return data;
};
return data;
}
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* 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.
*/
const CHANGE_EVENT = exports.CHANGE_EVENT = 'change';
const DELETE_EVENT = exports.DELETE_EVENT = 'delete';
const ADD_EVENT = exports.ADD_EVENT = 'add';
const ALL_EVENT = exports.ALL_EVENT = 'all';
const matcherCache = new Map();
function getMatcher(glob, dot) {
const key = `${dot}:${glob}`;
let matcher = matcherCache.get(key);
if (matcher == null) {
matcher = (0, _picomatch().default)(glob, {
dot
});
matcherCache.set(key, matcher);
}
return matcher;
}
function isFileIncluded(globs, dot, doIgnore, relativePath) {
if (doIgnore(relativePath)) {
return false;
}
return globs.length > 0 ? globs.some(glob => getMatcher(glob, dot)(relativePath)) : dot || getMatcher('**/*', false)(relativePath);
}
/***/ },
/***/ "./src/watchers/index.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.WatcherDriver = void 0;
exports.shouldUseWatchman = shouldUseWatchman;
var _watchmanSockname = __webpack_require__("./src/lib/watchmanSockname.ts");
var _ParcelWatcher = __webpack_require__("./src/watchers/ParcelWatcher.ts");
var _WatchmanWatcher = _interopRequireDefault(__webpack_require__("./src/watchers/WatchmanWatcher.js"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* 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: not converted to TypeScript - it's a fork: https://github.com/jestjs/jest/pull/5387
const WatchmanWatcher = _WatchmanWatcher.default;
async function shouldUseWatchman(useWatchmanOption, cacheDirectory) {
if (!useWatchmanOption) {
return false;
}
const availability = await (0, _watchmanSockname.getWatchmanAvailability)(cacheDirectory);
return availability.installed;
}
const MAX_WAIT_TIME = 240_000;
class WatcherDriver {
_console;
_extensions;
_ignorePattern;
_onError;
_roots;
_useWatchman;
_watchers = [];
constructor(opts) {
this._console = opts.console;
this._extensions = opts.extensions;
this._ignorePattern = opts.ignorePattern;
this._onError = opts.onError;
this._roots = opts.roots;
this._useWatchman = opts.useWatchman;
}
async start(onChange) {
const Backend = this._useWatchman ? WatchmanWatcher : _ParcelWatcher.ParcelWatcher;
const results = await Promise.allSettled(this._roots.map(root => this._createWatcher(Backend, root, onChange)));
const fulfilled = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const rejected = results.filter(r => r.status === 'rejected').map(r => r.reason);
if (rejected.length > 0) {
await Promise.allSettled(fulfilled.map(w => w.close()));
throw new AggregateError(rejected, 'Failed to start watch mode.');
}
this._watchers = fulfilled;
}
async close() {
await Promise.all(this._watchers.map(watcher => watcher.close()));
this._watchers = [];
}
_createWatcher(Backend, root, onChange) {
const watcher = new Backend(root, {
console: this._console,
dot: true,
glob: this._extensions.map(ext => `**/*.${ext}`),
ignored: this._ignorePattern,
useWatchman: this._useWatchman
});
return new Promise((resolve, reject) => {
const onReady = () => {
clearTimeout(rejectTimeout);
watcher.off('error', onStartupError);
// Post-startup errors are non-fatal: the watcher stays subscribed,
// and an unhandled 'error' emit would crash the process.
watcher.on('error', error => this._onError(error));
watcher.on('all', onChange);
resolve(watcher);
};
const onStartupError = startupError => {
clearTimeout(rejectTimeout);
watcher.off('ready', onReady);
watcher.close().catch(() => undefined);
reject(startupError);
};
const rejectTimeout = setTimeout(() => {
watcher.off('ready', onReady);
watcher.off('error', onStartupError);
watcher.close().catch(() => undefined);
reject(new Error('Failed to start watch mode.'));
}, MAX_WAIT_TIME);
watcher.once('ready', onReady);
watcher.once('error', onStartupError);
});
}
}
exports.WatcherDriver = WatcherDriver;
/***/ },
/***/ "./src/worker.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.getSha1 = getSha1;
exports.worker = worker;
function _nodeCrypto() {
const data = require("node:crypto");
_nodeCrypto = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require("graceful-fs"));
fs = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
var _blacklist = _interopRequireDefault(__webpack_require__("./src/blacklist.ts"));
var _constants = _interopRequireDefault(__webpack_require__("./src/constants.ts"));
var _dependencyExtractor = __webpack_require__("./src/lib/dependencyExtractor.ts");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
const PACKAGE_JSON = `${path().sep}package.json`;
function sha1hex(content) {
return (0, _nodeCrypto().createHash)('sha1').update(content).digest('hex');
}
async function worker(data) {
const hasteImpl = data.hasteImplModulePath ? require(data.hasteImplModulePath) : null;
let content;
let dependencies;
let id;
let module;
let sha1;
const {
computeDependencies,
computeSha1,
rootDir,
filePath
} = data;
const getContent = () => {
if (content === undefined) {
content = fs().readFileSync(filePath, 'utf8');
}
return content;
};
if (filePath.endsWith(PACKAGE_JSON)) {
// Process a package.json that is returned as a PACKAGE type with its name.
try {
const fileData = JSON.parse(getContent());
if (fileData.name) {
const relativeFilePath = path().relative(rootDir, filePath);
id = fileData.name;
module = [relativeFilePath, _constants.default.PACKAGE];
}
} catch (error) {
throw new Error(`Cannot parse ${filePath} as JSON: ${error.message}`, {
cause: error
});
}
} else if (!_blacklist.default.has(filePath.slice(filePath.lastIndexOf('.')))) {
// Process a random file that is returned as a MODULE.
if (hasteImpl) {
id = hasteImpl.getHasteName(filePath);
}
if (computeDependencies) {
const content = getContent();
const extractor = data.dependencyExtractor ? await (0, _jestUtil().requireOrImportModule)(data.dependencyExtractor, false) : _dependencyExtractor.extractor;
dependencies = [...extractor.extract(content, filePath, _dependencyExtractor.extractor.extract)];
}
if (id) {
const relativeFilePath = path().relative(rootDir, filePath);
module = [relativeFilePath, _constants.default.MODULE];
}
}
// If a SHA-1 is requested on update, compute it.
if (computeSha1) {
sha1 = sha1hex(content || fs().readFileSync(filePath));
}
return {
dependencies,
id,
module,
sha1
};
}
async function getSha1(data) {
const sha1 = data.computeSha1 ? sha1hex(fs().readFileSync(data.filePath)) : null;
return {
dependencies: undefined,
id: undefined,
module: undefined,
sha1
};
}
/***/ },
/***/ "./src/watchers/WatchmanWatcher.js"
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
"default": () => (/* binding */ WatchmanWatcher)
});
;// external "node:assert"
const external_node_assert_namespaceObject = require("node:assert");
;// external "node:events"
const external_node_events_namespaceObject = require("node:events");
;// external "node:path"
const external_node_path_namespaceObject = require("node:path");
;// external "anymatch"
const external_anymatch_namespaceObject = require("anymatch");
var external_anymatch_default = /*#__PURE__*/__webpack_require__.n(external_anymatch_namespaceObject);
;// external "fb-watchman"
const external_fb_watchman_namespaceObject = require("fb-watchman");
var external_fb_watchman_default = /*#__PURE__*/__webpack_require__.n(external_fb_watchman_namespaceObject);
;// external "graceful-fs"
const external_graceful_fs_namespaceObject = require("graceful-fs");
var external_graceful_fs_default = /*#__PURE__*/__webpack_require__.n(external_graceful_fs_namespaceObject);
// EXTERNAL MODULE: ./src/lib/isIgnorableFileError.ts
var isIgnorableFileError = __webpack_require__("./src/lib/isIgnorableFileError.ts");
// EXTERNAL MODULE: ./src/watchers/common.ts
var common = __webpack_require__("./src/watchers/common.ts");
;// ./src/watchers/WatchmanWatcher.js
/**
* 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.
*/
const CHANGE_EVENT = common.CHANGE_EVENT;
const DELETE_EVENT = common.DELETE_EVENT;
const ADD_EVENT = common.ADD_EVENT;
const ALL_EVENT = common.ALL_EVENT;
const SUB_NAME = 'jest-haste-map';
// Dedupe repeated "Recrawled this watch N times" warnings from watchman.
const RECRAWL_WARNINGS = [];
const RECRAWL_REGEXP =
/Recrawled this watch (\d+) times, most recently because:\n([^:]+)/;
function isRecrawlWarningDupe(warningMessage) {
if (typeof warningMessage !== 'string') {
return false;
}
const match = warningMessage.match(RECRAWL_REGEXP);
if (!match) {
return false;
}
const count = Number(match[1]);
const root = match[2];
const existing = RECRAWL_WARNINGS.find(w => w.root === root);
if (existing) {
if (existing.count >= count) {
return true;
}
existing.count = count;
return false;
}
RECRAWL_WARNINGS.push({count, root});
return false;
}
/**
* Watches `dir`.
*
* @class WatchmanWatcher
* @param String dir
* @param {Object} opts
* @public
*/
function WatchmanWatcher(dir, opts) {
this.globs = opts.glob;
this.dot = opts.dot;
this.hasIgnore = Boolean(opts.ignored);
this.doIgnore = opts.ignored ? external_anymatch_default()(opts.ignored) : () => false;
this.root = external_node_path_namespaceObject.resolve(dir);
this._console = opts.console || globalThis.console;
this._closed = false;
this.init();
}
Object.setPrototypeOf(WatchmanWatcher.prototype, external_node_events_namespaceObject.EventEmitter.prototype);
/**
* Run the watchman `watch` command on the root and subscribe to changes.
*
* @private
*/
WatchmanWatcher.prototype.init = function () {
if (this.client) {
this.client.removeAllListeners();
}
const self = this;
this.client = new (external_fb_watchman_default()).Client();
this.client.on('error', error => {
self.emit('error', error);
});
this.client.on('subscription', this.handleChangeEvent.bind(this));
this.client.on('end', () => {
if (self._closed) {
return;
}
self._console.warn(
'[jest-haste-map] Warning: Lost connection to watchman, reconnecting..',
);
self.init();
});
this.watchProjectInfo = null;
function getWatchRoot() {
return self.watchProjectInfo ? self.watchProjectInfo.root : self.root;
}
function onCapability(error, resp) {
if (handleError(self, error)) {
// The Watchman watcher is unusable on this system, we cannot continue
return;
}
handleWarning(self, resp);
self.capabilities = resp.capabilities;
if (self.capabilities.relative_root) {
self.client.command(['watch-project', getWatchRoot()], onWatchProject);
} else {
self.client.command(['watch', getWatchRoot()], onWatch);
}
}
function onWatchProject(error, resp) {
if (handleError(self, error)) {
return;
}
handleWarning(self, resp);
self.watchProjectInfo = {
relativePath: resp.relative_path ?? '',
root: resp.watch,
};
self.client.command(['clock', getWatchRoot()], onClock);
}
function onWatch(error, resp) {
if (handleError(self, error)) {
return;
}
handleWarning(self, resp);
self.client.command(['clock', getWatchRoot()], onClock);
}
function onClock(error, resp) {
if (handleError(self, error)) {
return;
}
handleWarning(self, resp);
const options = {
fields: ['name', 'exists', 'new'],
since: resp.clock,
};
// If the server has the wildmatch capability available it supports
// the recursive **/*.foo style match and we can offload our globs
// to the watchman server. This saves both on data size to be
// communicated back to us and compute for evaluating the globs
// in our node process.
if (self.capabilities.wildmatch) {
if (self.globs.length === 0) {
if (!self.dot) {
// Make sure we honor the dot option if even we're not using globs.
options.expression = [
'match',
'**',
'wholename',
{
includedotfiles: false,
},
];
}
} else {
options.expression = ['anyof'];
for (const glob of self.globs) {
options.expression.push([
'match',
glob,
'wholename',
{
includedotfiles: self.dot,
},
]);
}
}
}
if (self.capabilities.relative_root) {
options.relative_root = self.watchProjectInfo.relativePath;
}
self.client.command(
['subscribe', getWatchRoot(), SUB_NAME, options],
onSubscribe,
);
}
function onSubscribe(error, resp) {
if (handleError(self, error)) {
return;
}
handleWarning(self, resp);
self.emit('ready');
}
self.client.capabilityCheck(
{
optional: ['wildmatch', 'relative_root'],
},
onCapability,
);
};
/**
* Handles a change event coming from the subscription.
*
* @param {Object} resp
* @private
*/
WatchmanWatcher.prototype.handleChangeEvent = function (resp) {
external_node_assert_namespaceObject.strict.equal(resp.subscription, SUB_NAME, 'Invalid subscription event.');
if (resp.is_fresh_instance) {
this.emit('fresh_instance');
}
if (Array.isArray(resp.files)) {
for (const file of resp.files) this.handleFileChange(file);
}
};
/**
* Handles a single change event record.
*
* @param {Object} changeDescriptor
* @private
*/
WatchmanWatcher.prototype.handleFileChange = function (changeDescriptor) {
const self = this;
let absPath;
let relativePath;
if (this.capabilities.relative_root) {
relativePath = changeDescriptor.name;
absPath = external_node_path_namespaceObject.join(
this.watchProjectInfo.root,
this.watchProjectInfo.relativePath,
relativePath,
);
} else {
absPath = external_node_path_namespaceObject.join(this.root, changeDescriptor.name);
relativePath = changeDescriptor.name;
}
if (
!(self.capabilities.wildmatch && !this.hasIgnore) &&
!common.isFileIncluded(this.globs, this.dot, this.doIgnore, relativePath)
) {
return;
}
if (changeDescriptor.exists) {
external_graceful_fs_default().lstat(absPath, (error, stat) => {
// Files can disappear or temporarily become unreadable between the
// Watchman event and the lstat call, so ignore that stale event.
if (error && (0,isIgnorableFileError.isIgnorableFileError)(error)) {
return;
}
if (handleError(self, error)) {
return;
}
const eventType = changeDescriptor.new ? ADD_EVENT : CHANGE_EVENT;
// Change event on dirs are mostly useless.
if (!(eventType === CHANGE_EVENT && stat.isDirectory())) {
self.emitEvent(eventType, relativePath, self.root, stat);
}
});
} else {
self.emitEvent(DELETE_EVENT, relativePath, self.root);
}
};
/**
* Dispatches the event.
*
* @param {string} eventType
* @param {string} filepath
* @param {string} root
* @param {fs.Stat} stat
* @private
*/
WatchmanWatcher.prototype.emitEvent = function (
eventType,
filepath,
root,
stat,
) {
// An `lstat` started before close() can still complete after it. Delivering
// that event would feed the already-stopped ChangeQueue.
if (this._closed) {
return;
}
this.emit(eventType, filepath, root, stat);
this.emit(ALL_EVENT, eventType, filepath, root, stat);
};
/**
* Closes the watcher.
*
*/
WatchmanWatcher.prototype.close = function () {
this._closed = true;
this.client.removeAllListeners();
this.client.end();
return Promise.resolve();
};
/**
* Handles an error and returns true if exists.
*
* @param {WatchmanWatcher} self
* @param {Error} error
* @private
*/
function handleError(self, error) {
if (error == null) {
return false;
} else {
if (!self._closed) {
self.emit('error', error);
}
return true;
}
}
/**
* Handles a warning in the watchman resp object.
*
* @param {WatchmanWatcher} self
* @param {object} resp
* @private
*/
function handleWarning(self, resp) {
if ('warning' in resp) {
if (isRecrawlWarningDupe(resp.warning)) {
return true;
}
self._console.warn(resp.warning);
return true;
} else {
return false;
}
}
/***/ },
/***/ "./package.json"
(module) {
module.exports = {"version":"30.5.0"};
/***/ }
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ const __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ const cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ const module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ const getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter/value functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ if(Array.isArray(definition)) {
/******/ var i = 0;
/******/ while(i < definition.length) {
/******/ var key = definition[i++];
/******/ var binding = definition[i++];
/******/ if(!__webpack_require__.o(exports, key)) {
/******/ if(binding === 0) {
/******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
/******/ } else {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
/******/ }
/******/ } else if(binding === 0) { i++; }
/******/ }
/******/ } else {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
let __webpack_exports__ = {};
// This entry needs to be wrapped in an IIFE because it uses a non-standard name for the exports (exports).
(() => {
let exports = __webpack_exports__;
Object.defineProperty(exports, "__esModule", ({
value: true
}));
Object.defineProperty(exports, "DuplicateError", ({
enumerable: true,
get: function () {
return _FileProcessor.DuplicateError;
}
}));
exports["default"] = exports.ModuleMap = void 0;
function _nodeCrypto() {
const data = require("node:crypto");
_nodeCrypto = function () {
return data;
};
return data;
}
function _nodeEvents() {
const data = require("node:events");
_nodeEvents = function () {
return data;
};
return data;
}
function _nodeOs() {
const data = require("node:os");
_nodeOs = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("node:path"));
path = function () {
return data;
};
return data;
}
function _jestRegexUtil() {
const data = require("jest-regex-util");
_jestRegexUtil = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
var _HasteFS = _interopRequireDefault(__webpack_require__("./src/HasteFS.ts"));
var _ModuleMap = _interopRequireDefault(__webpack_require__("./src/ModuleMap.ts"));
var _constants = _interopRequireDefault(__webpack_require__("./src/constants.ts"));
var _crawlers = __webpack_require__("./src/crawlers/index.ts");
var _CacheManager = __webpack_require__("./src/lib/CacheManager.ts");
var _FileProcessor = __webpack_require__("./src/lib/FileProcessor.ts");
var _WorkerPool = __webpack_require__("./src/lib/WorkerPool.ts");
var _buildIgnoreMatcher = __webpack_require__("./src/lib/buildIgnoreMatcher.ts");
var fastPath = _interopRequireWildcard(__webpack_require__("./src/lib/fast_path.ts"));
var _getPlatformExtension = _interopRequireDefault(__webpack_require__("./src/lib/getPlatformExtension.ts"));
var _util = __webpack_require__("./src/lib/util.ts");
var _watchmanSockname = __webpack_require__("./src/lib/watchmanSockname.ts");
var _watchers = __webpack_require__("./src/watchers/index.ts");
var _ChangeQueue = __webpack_require__("./src/watchers/ChangeQueue.ts");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
* 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.
*/
// TypeScript doesn't like us importing from outside `rootDir`, but it doesn't
// understand `require`.
const {
version: VERSION
} = __webpack_require__("./package.json");
const ModuleMap = exports.ModuleMap = _ModuleMap.default;
const VCS_DIRECTORIES = ['.git', '.hg', '.sl'].map(vcs => (0, _jestRegexUtil().escapePathForRegex)(path().sep + vcs + path().sep)).join('|');
/**
* HasteMap is a JavaScript implementation of Facebook's haste module system.
*
* This implementation is inspired by https://github.com/facebook/node-haste
* and was built with for high-performance in large code repositories with
* hundreds of thousands of files. This implementation is scalable and provides
* predictable performance.
*
* Because the haste map creation and synchronization is critical to startup
* performance and most tasks are blocked by I/O this class makes heavy use of
* synchronous operations. It uses worker processes for parallelizing file
* access and metadata extraction.
*
* The data structures created by `jest-haste-map` can be used directly from the
* cache without further processing. The metadata objects in the `files` and
* `map` objects contain cross-references: a metadata object from one can look
* up the corresponding metadata object in the other map. Note that in most
* projects, the number of files will be greater than the number of haste
* modules one module can refer to many files based on platform extensions.
*
* type HasteMap = {
* clocks: WatchmanClocks,
* files: {[filepath: string]: FileMetaData},
* map: {[id: string]: ModuleMapItem},
* mocks: {[id: string]: string},
* }
*
* // Watchman clocks are used for query synchronization and file system deltas.
* type WatchmanClocks = {[filepath: string]: string};
*
* type FileMetaData = {
* id: ?string, // used to look up module metadata objects in `map`.
* mtime: number, // check for outdated files.
* size: number, // size of the file in bytes.
* visited: boolean, // whether the file has been parsed or not.
* dependencies: Array<string>, // all relative dependencies of this file.
* sha1: ?string, // SHA-1 of the file, if requested via options.
* };
*
* // Modules can be targeted to a specific platform based on the file name.
* // Example: platform.ios.js and Platform.android.js will both map to the same
* // `Platform` module. The platform should be specified during resolution.
* type ModuleMapItem = {[platform: string]: ModuleMetaData};
*
* //
* type ModuleMetaData = {
* path: string, // the path to look up the file object in `files`.
* type: string, // the module type (either `package` or `module`).
* };
*
* Note that the data structures described above are conceptual only. The actual
* implementation uses arrays and constant keys for metadata storage. Instead of
* `{id: 'flatMap', mtime: 3421, size: 42, visited: true, dependencies: []}` the real
* representation is similar to `['flatMap', 3421, 42, 1, []]` to save storage space
* and reduce parse and write time of a big JSON blob.
*
* The HasteMap is created as follows:
* 1. read data from the cache or create an empty structure.
*
* 2. crawl the file system.
* * empty cache: crawl the entire file system.
* * cache available:
* * if watchman is available: get file system delta changes.
* * if watchman is unavailable: crawl the entire file system.
* * build metadata objects for every file. This builds the `files` part of
* the `HasteMap`.
*
* 3. parse and extract metadata from changed files.
* * this is done in parallel over worker processes to improve performance.
* * the worst case is to parse all files.
* * the best case is no file system access and retrieving all data from
* the cache.
* * the average case is a small number of changed files.
*
* 4. serialize the new `HasteMap` in a cache file.
* Worker processes can directly access the cache through `HasteMap.read()`.
*
*/
class HasteMap extends _nodeEvents().EventEmitter {
_buildPromise = null;
_cacheManager;
_changeQueue;
_fileProcessor;
_ignoreFn = () => false;
_console;
_options;
_watcherDriver;
_workerPool;
static getStatic(config) {
if (config.haste.hasteMapModulePath) {
return require(config.haste.hasteMapModulePath);
}
return HasteMap;
}
static async create(options) {
if (options.hasteMapModulePath) {
const CustomHasteMap = require(options.hasteMapModulePath);
return new CustomHasteMap(options);
}
const hasteMap = new HasteMap(options);
await hasteMap.setupCachePath(options);
return hasteMap;
}
constructor(options) {
super();
this._options = {
cacheDirectory: options.cacheDirectory || (0, _nodeOs().tmpdir)(),
computeDependencies: options.computeDependencies ?? true,
computeSha1: options.computeSha1 || false,
dependencyExtractor: options.dependencyExtractor || null,
enableSymlinks: options.enableSymlinks ?? false,
extensions: options.extensions,
forceNodeFilesystemAPI: options.forceNodeFilesystemAPI ?? false,
hasteImplModulePath: options.hasteImplModulePath,
id: options.id,
maxWorkers: options.maxWorkers,
mocksPattern: options.mocksPattern ? new RegExp(options.mocksPattern) : null,
platforms: options.platforms,
resetCache: options.resetCache,
retainAllFiles: options.retainAllFiles,
rootDir: options.rootDir,
roots: [...new Set(options.roots)],
skipPackageJson: !!options.skipPackageJson,
throwOnModuleCollision: !!options.throwOnModuleCollision,
useWatchman: options.useWatchman ?? true,
watch: !!options.watch,
workerThreads: options.workerThreads
};
this._console = options.console || globalThis.console;
if (options.ignorePattern) {
if (options.ignorePattern instanceof RegExp) {
this._options.ignorePattern = new RegExp(`${options.ignorePattern.source}|${VCS_DIRECTORIES}`, options.ignorePattern.flags);
} else {
throw new TypeError('jest-haste-map: the `ignorePattern` option must be a RegExp');
}
} else {
this._options.ignorePattern = new RegExp(VCS_DIRECTORIES);
}
if (this._options.enableSymlinks && this._options.useWatchman) {
throw new Error('jest-haste-map: enableSymlinks config option was set, but ' + 'is incompatible with watchman.\n' + 'Set either `enableSymlinks` to false or `useWatchman` to false.');
}
this._ignoreFn = (0, _buildIgnoreMatcher.buildIgnoreMatcher)(this._options.ignorePattern, this._options.retainAllFiles);
this._workerPool = new _WorkerPool.WorkerPool({
maxWorkers: this._options.maxWorkers,
workerPath: require.resolve('./worker'),
workerThreads: this._options.workerThreads
});
this._fileProcessor = new _FileProcessor.FileProcessor({
computeDependencies: this._options.computeDependencies,
computeSha1: this._options.computeSha1,
dependencyExtractor: this._options.dependencyExtractor,
hasteImplModulePath: this._options.hasteImplModulePath,
mocksPattern: this._options.mocksPattern,
platforms: this._options.platforms,
retainAllFiles: this._options.retainAllFiles,
rootDir: this._options.rootDir,
skipPackageJson: this._options.skipPackageJson,
throwOnModuleCollision: this._options.throwOnModuleCollision
}, this._console, this._workerPool);
}
async setupCachePath(options) {
const rootDirHash = (0, _nodeCrypto().createHash)('sha1').update(options.rootDir).digest('hex').slice(0, 32);
let hasteImplHash = '';
let dependencyExtractorHash = '';
if (options.hasteImplModulePath) {
const hasteImpl = require(options.hasteImplModulePath);
if (hasteImpl.getCacheKey) {
hasteImplHash = String(hasteImpl.getCacheKey());
}
}
if (options.dependencyExtractor) {
const dependencyExtractor = await (0, _jestUtil().requireOrImportModule)(options.dependencyExtractor, false);
if (dependencyExtractor.getCacheKey) {
dependencyExtractorHash = String(dependencyExtractor.getCacheKey());
}
}
const cachePath = HasteMap.getCacheFilePath(this._options.cacheDirectory, `haste-map-${this._options.id}-${rootDirHash}`, VERSION, this._options.id, this._options.roots.map(root => fastPath.relative(options.rootDir, root)).join(':'), this._options.extensions.join(':'), this._options.platforms.join(':'), this._options.computeSha1.toString(), options.mocksPattern || '', (options.ignorePattern || '').toString(), hasteImplHash, dependencyExtractorHash, this._options.computeDependencies.toString());
this._cacheManager = new _CacheManager.CacheManager(cachePath);
}
static getCacheFilePath(tmpdir, id, ...extra) {
// NUL-delimited so that adjacent fields cannot run together and let two
// different option sets hash to the same cache file.
const hash = (0, _nodeCrypto().createHash)('sha1').update(extra.join('\0'));
return path().join(tmpdir, `${id.replaceAll(/\W/g, '-')}-${hash.digest('hex').slice(0, 32)}`);
}
static getModuleMapFromJSON(json) {
return _ModuleMap.default.fromJSON(json);
}
getCacheFilePath() {
return this._cacheManager.path;
}
build() {
if (!this._buildPromise) {
this._buildPromise = (async () => {
const data = await this._buildFileMap();
// Persist when we don't know if files changed (changedFiles undefined)
// or when we know a file was changed or deleted.
let hasteMap;
if (data.changedFiles === undefined || data.changedFiles.size > 0 || data.removedFiles.size > 0) {
hasteMap = await this._buildHasteMap(data);
this._persist(hasteMap);
} else {
hasteMap = data.hasteMap;
}
const rootDir = this._options.rootDir;
const hasteFS = new _HasteFS.default({
files: hasteMap.files,
rootDir
});
const moduleMap = new _ModuleMap.default({
duplicates: hasteMap.duplicates,
map: hasteMap.map,
mocks: hasteMap.mocks,
rootDir
});
const __hasteMapForTest = false || null;
await this._watch(hasteMap);
return {
__hasteMapForTest,
hasteFS,
moduleMap
};
})();
}
return this._buildPromise;
}
/**
* 1. read data from the cache or create an empty structure.
*/
read() {
return this._cacheManager.read();
}
readModuleMap() {
const data = this.read();
return new _ModuleMap.default({
duplicates: data.duplicates,
map: data.map,
mocks: data.mocks,
rootDir: this._options.rootDir
});
}
/**
* 2. crawl the file system.
*/
async _buildFileMap() {
const hasteMap = this._options.resetCache ? this._createEmptyMap() : this._cacheManager.read();
return this._crawl(hasteMap);
}
/**
* 3. parse and extract metadata from changed files.
*/
_processFile(hasteMap, filePath) {
return this._fileProcessor.processFile(hasteMap, hasteMap.map, hasteMap.mocks, filePath, {
forceInBand: true
});
}
_buildHasteMap(data) {
return this._fileProcessor.buildHasteMap(data, (map, relPath, name) => this._recoverDuplicates(map, relPath, name));
}
/**
* 4. serialize the new `HasteMap` in a cache file.
*/
_persist(hasteMap) {
this._cacheManager.persist(hasteMap);
}
async _crawl(hasteMap) {
const options = this._options;
const watchmanAvailability = options.useWatchman ? await (0, _watchmanSockname.getWatchmanAvailability)(options.cacheDirectory) : undefined;
return (0, _crawlers.crawl)({
computeSha1: options.computeSha1,
console: this._console,
data: hasteMap,
enableSymlinks: options.enableSymlinks,
extensions: options.extensions,
forceNodeFilesystemAPI: options.forceNodeFilesystemAPI,
ignore: this._ignore.bind(this),
rootDir: options.rootDir,
roots: options.roots,
watchmanSockname: watchmanAvailability?.sockname
}, watchmanAvailability?.installed ?? false);
}
/**
* Watch mode
*/
async _watch(hasteMap) {
if (!this._options.watch) {
return;
}
// In watch mode, we'll only warn about module collisions and we'll retain
// all files, even changes to node_modules.
this._options.throwOnModuleCollision = false;
this._options.retainAllFiles = true;
this._ignoreFn = (0, _buildIgnoreMatcher.buildIgnoreMatcher)(this._options.ignorePattern, true);
this._fileProcessor = new _FileProcessor.FileProcessor({
computeDependencies: this._options.computeDependencies,
computeSha1: this._options.computeSha1,
dependencyExtractor: this._options.dependencyExtractor,
hasteImplModulePath: this._options.hasteImplModulePath,
mocksPattern: this._options.mocksPattern,
platforms: this._options.platforms,
retainAllFiles: true,
rootDir: this._options.rootDir,
skipPackageJson: this._options.skipPackageJson,
throwOnModuleCollision: false
}, this._console, this._workerPool);
this._watcherDriver = new _watchers.WatcherDriver({
console: this._console,
extensions: this._options.extensions,
ignorePattern: this._options.ignorePattern,
onError: error => this._console.error(`jest-haste-map: watch error:\n ${error.stack}\n`),
roots: this._options.roots,
useWatchman: await (0, _watchers.shouldUseWatchman)(this._options.useWatchman, this._options.cacheDirectory)
});
this._changeQueue = new _ChangeQueue.ChangeQueue(hasteMap, this._options.extensions, {
cleanup: () => this._workerPool.end(),
emit: event => this.emit('change', event),
ignore: filePath => this._ignore(filePath),
mocksPattern: this._options.mocksPattern,
onError: error => this._console.error(`jest-haste-map: watch error:\n ${error.stack}\n`),
platforms: this._options.platforms,
processFile: (map, filePath) => this._processFile(map, filePath),
recoverDuplicates: (map, relPath, name) => this._recoverDuplicates(map, relPath, name),
rootDir: this._options.rootDir
});
this._changeQueue.start();
try {
await this._watcherDriver.start((type, filePath, root, stat) => this._changeQueue.onChange(type, filePath, root, stat));
} catch (error) {
this._changeQueue.stop();
throw error;
}
}
/**
* This function should be called when the file under `filePath` is removed
* or changed. When that happens, we want to figure out if that file was
* part of a group of files that had the same ID. If it was, we want to
* remove it from the group. Furthermore, if there is only one file
* remaining in the group, then we want to restore that single file as the
* correct resolution for its ID, and cleanup the duplicates index.
*/
_recoverDuplicates(hasteMap, relativeFilePath, moduleName) {
let dupsByPlatform = hasteMap.duplicates.get(moduleName);
if (dupsByPlatform == null) {
return;
}
const platform = (0, _getPlatformExtension.default)(relativeFilePath, this._options.platforms) || _constants.default.GENERIC_PLATFORM;
let dups = dupsByPlatform.get(platform);
if (dups == null) {
return;
}
dupsByPlatform = (0, _util.copyMap)(dupsByPlatform);
hasteMap.duplicates.set(moduleName, dupsByPlatform);
dups = (0, _util.copyMap)(dups);
dupsByPlatform.set(platform, dups);
dups.delete(relativeFilePath);
if (dups.size !== 1) {
return;
}
const uniqueModule = dups.entries().next().value;
if (!uniqueModule) {
return;
}
let dedupMap = hasteMap.map.get(moduleName);
if (!dedupMap) {
dedupMap = Object.create(null);
hasteMap.map.set(moduleName, dedupMap);
}
dedupMap[platform] = uniqueModule;
dupsByPlatform.delete(platform);
if (dupsByPlatform.size === 0) {
hasteMap.duplicates.delete(moduleName);
}
}
async end() {
this._changeQueue?.stop();
await this._watcherDriver?.close();
}
/**
* Helpers
*/
_ignore(filePath) {
return this._ignoreFn(filePath);
}
_createEmptyMap() {
return (0, _util.createEmptyMap)();
}
static H = _constants.default;
}
// Export the smallest API surface required by Jest
const JestHasteMap = HasteMap;
var _default = exports["default"] = JestHasteMap;
})();
module.exports = __webpack_exports__;
/******/ })()
;