jest-haste-map
Version:
1,584 lines (1,447 loc) • 99.4 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[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/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/node.ts"
(__unused_webpack_module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.nodeCrawl = nodeCrawl;
function _child_process() {
const data = require("child_process");
_child_process = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("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"));
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, _child_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 result = [];
let activeCalls = 0;
function search(directory) {
activeCalls++;
fs().readdir(directory, {
withFileTypes: true
}, (err, entries) => {
activeCalls--;
if (err) {
if (activeCalls === 0) {
callback(result);
}
return;
}
for (const entry of entries) {
const file = path().join(directory, entry.name);
if (ignore(file)) {
continue;
}
if (entry.isSymbolicLink()) {
continue;
}
if (entry.isDirectory()) {
search(file);
continue;
}
activeCalls++;
const stat = enableSymlinks ? fs().stat : fs().lstat;
stat(file, (err, stat) => {
activeCalls--;
// This logic is unnecessary for node > v10.10, but leaving it in
// since we need it for backwards-compatibility still.
if (!err && stat && !stat.isSymbolicLink()) {
if (stat.isDirectory()) {
search(file);
} else {
const ext = path().extname(file).slice(1);
if (extensions.includes(ext)) {
result.push([file, stat.mtime.getTime(), stat.size]);
}
}
}
if (activeCalls === 0) {
callback(result);
}
});
}
if (activeCalls === 0) {
callback(result);
}
});
}
if (roots.length > 0) {
for (const root of roots) search(root);
} else {
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, _child_process().spawn)('find', args);
let stdout = '';
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');
child.stdout.on('data', data => stdout += data);
child.stdout.on('close', () => {
const lines = stdout.trim().split('\n').filter(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,
extensions,
forceNodeFilesystemAPI,
ignore,
rootDir,
enableSymlinks,
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) {
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("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"));
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 {
data,
extensions,
ignore,
rootDir,
roots
} = options;
const defaultWatchExpression = ['allof', ['type', 'f']];
const clocks = data.clocks;
const client = new (watchman().Client)();
// 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])]);
}
let clientError;
client.on('error', error => clientError = watchmanError(error));
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)));
if (options.computeSha1) {
const {
capabilities
} = await cmd('list-capabilities');
if (capabilities.includes('field-content.sha1hex')) {
fields.push('content.sha1hex');
}
}
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 ?
// Use the `since` generator if we have a clock available
{
expression,
fields,
glob,
glob_includedotfiles: true
} :
// Otherwise use the `glob` filter
{
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 {
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("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/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("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/isWatchmanInstalled.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = isWatchmanInstalled;
function _child_process() {
const data = require("child_process");
_child_process = function () {
return data;
};
return data;
}
function _util() {
const data = require("util");
_util = function () {
return data;
};
return data;
}
/**
* 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 isWatchmanInstalled() {
try {
await (0, _util().promisify)(_child_process().execFile)('watchman', ['--version']);
return true;
} catch {
return false;
}
}
/***/ },
/***/ "./src/lib/normalizePathSep.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports["default"] = void 0;
function path() {
const data = _interopRequireWildcard(require("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/watchers/FSEventsWatcher.ts"
(__unused_webpack_module, exports) {
Object.defineProperty(exports, "__esModule", ({
value: true
}));
exports.FSEventsWatcher = void 0;
function _events() {
const data = require("events");
_events = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("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;
}
function _walker() {
const data = _interopRequireDefault(require("walker"));
_walker = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require("jest-util");
_jestUtil = function () {
return data;
};
return data;
}
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.
*
*/
// @ts-expect-error -- no types
// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error, @typescript-eslint/ban-ts-comment
// @ts-ignore: this is for CI which runs linux and might not have this
let fsevents = null;
try {
fsevents = require('fsevents');
} catch {
// Optional dependency, only supported on Darwin.
}
const CHANGE_EVENT = 'change';
const DELETE_EVENT = 'delete';
const ADD_EVENT = 'add';
const ALL_EVENT = 'all';
/**
* Export `FSEventsWatcher` class.
* Watches `dir`.
*/
class FSEventsWatcher extends _events().EventEmitter {
root;
ignored;
glob;
dot;
hasIgnore;
doIgnore;
fsEventsWatchStopper;
_tracked;
static isSupported() {
return fsevents !== null;
}
static normalizeProxy(callback) {
return (filepath, stats) => callback(path().normalize(filepath), stats);
}
static recReaddir(dir, dirCallback, fileCallback, endCallback, errorCallback, ignored) {
(0, _walker().default)(dir).filterDir(currentDir => !ignored || !(0, _anymatch().default)(ignored, currentDir)).on('dir', FSEventsWatcher.normalizeProxy(dirCallback)).on('file', FSEventsWatcher.normalizeProxy(fileCallback)).on('error', errorCallback).on('end', () => {
endCallback();
});
}
constructor(dir, opts) {
if (!fsevents) {
throw new Error('`fsevents` unavailable (this watcher can only be used on Darwin)');
}
super();
this.dot = opts.dot || false;
this.ignored = opts.ignored;
this.glob = Array.isArray(opts.glob) ? opts.glob : [opts.glob];
this.hasIgnore = Boolean(opts.ignored) && !(Array.isArray(opts) && opts.length > 0);
this.doIgnore = opts.ignored ? (0, _anymatch().default)(opts.ignored) : () => false;
this.root = path().resolve(dir);
this.fsEventsWatchStopper = fsevents.watch(this.root, this.handleEvent.bind(this));
this._tracked = new Set();
FSEventsWatcher.recReaddir(this.root, filepath => {
this._tracked.add(filepath);
}, filepath => {
this._tracked.add(filepath);
}, this.emit.bind(this, 'ready'), this.emit.bind(this, 'error'), this.ignored);
}
/**
* End watching.
*/
async close(callback) {
await this.fsEventsWatchStopper();
this.removeAllListeners();
if (typeof callback === 'function') {
process.nextTick(() => callback());
}
}
isFileIncluded(relativePath) {
if (this.doIgnore(relativePath)) {
return false;
}
return this.glob.length > 0 ? (0, _jestUtil().globsToMatcher)(this.glob, {
dot: this.dot
})(relativePath) : this.dot || (0, _jestUtil().globsToMatcher)(['**/*'])(relativePath);
}
handleEvent(filepath) {
const relativePath = path().relative(this.root, filepath);
if (!this.isFileIncluded(relativePath)) {
return;
}
fs().lstat(filepath, (error, stat) => {
if (error && error.code !== 'ENOENT') {
this.emit('error', error);
return;
}
if (error) {
// Ignore files that aren't tracked and don't exist.
if (!this._tracked.has(filepath)) {
return;
}
this._emit(DELETE_EVENT, relativePath);
this._tracked.delete(filepath);
return;
}
if (this._tracked.has(filepath)) {
this._emit(CHANGE_EVENT, relativePath, stat);
} else {
this._tracked.add(filepath);
this._emit(ADD_EVENT, relativePath, stat);
}
});
}
/**
* Emit events.
*/
_emit(type, file, stat) {
this.emit(type, file, this.root, stat);
this.emit(ALL_EVENT, type, file, this.root, stat);
}
}
exports.FSEventsWatcher = FSEventsWatcher;
/***/ },
/***/ "./src/watchers/NodeWatcher.js"
(module, __unused_webpack_exports, __webpack_require__) {
// vendored from https://github.com/amasad/sane/blob/64ff3a870c42e84f744086884bf55a4f9c22d376/src/node_watcher.js
const EventEmitter = (__webpack_require__("events").EventEmitter);
const fs = require('fs');
const platform = (__webpack_require__("os").platform)();
const path = require('path');
const common = __webpack_require__("./src/watchers/common.js");
/**
* Constants
*/
const DEFAULT_DELAY = common.DEFAULT_DELAY;
const CHANGE_EVENT = common.CHANGE_EVENT;
const DELETE_EVENT = common.DELETE_EVENT;
const ADD_EVENT = common.ADD_EVENT;
const ALL_EVENT = common.ALL_EVENT;
/**
* Export `NodeWatcher` class.
* Watches `dir`.
*
* @class NodeWatcher
* @param {String} dir
* @param {Object} opts
* @public
*/
module.exports = class NodeWatcher extends EventEmitter {
constructor(dir, opts) {
super();
common.assignOptions(this, opts);
this.watched = Object.create(null);
this.changeTimers = Object.create(null);
this.dirRegistry = Object.create(null);
this.root = path.resolve(dir);
this.watchdir = this.watchdir.bind(this);
this.register = this.register.bind(this);
this.checkedEmitError = this.checkedEmitError.bind(this);
this.watchdir(this.root);
common.recReaddir(
this.root,
this.watchdir,
this.register,
this.emit.bind(this, 'ready'),
this.checkedEmitError,
this.ignored,
);
}
/**
* Register files that matches our globs to know what to type of event to
* emit in the future.
*
* Registry looks like the following:
*
* dirRegister => Map {
* dirpath => Map {
* filename => true
* }
* }
*
* @param {string} filepath
* @return {boolean} whether or not we have registered the file.
* @private
*/
register(filepath) {
const relativePath = path.relative(this.root, filepath);
if (
!common.isFileIncluded(this.globs, this.dot, this.doIgnore, relativePath)
) {
return false;
}
const dir = path.dirname(filepath);
if (!this.dirRegistry[dir]) {
this.dirRegistry[dir] = Object.create(null);
}
const filename = path.basename(filepath);
this.dirRegistry[dir][filename] = true;
return true;
}
/**
* Removes a file from the registry.
*
* @param {string} filepath
* @private
*/
unregister(filepath) {
const dir = path.dirname(filepath);
if (this.dirRegistry[dir]) {
const filename = path.basename(filepath);
delete this.dirRegistry[dir][filename];
}
}
/**
* Removes a dir from the registry.
*
* @param {string} dirpath
* @private
*/
unregisterDir(dirpath) {
if (this.dirRegistry[dirpath]) {
delete this.dirRegistry[dirpath];
}
}
/**
* Checks if a file or directory exists in the registry.
*
* @param {string} fullpath
* @return {boolean}
* @private
*/
registered(fullpath) {
const dir = path.dirname(fullpath);
return (
this.dirRegistry[fullpath] ||
(this.dirRegistry[dir] && this.dirRegistry[dir][path.basename(fullpath)])
);
}
/**
* Emit "error" event if it's not an ignorable event
*
* @param error
* @private
*/
checkedEmitError(error) {
if (!isIgnorableFileError(error)) {
this.emit('error', error);
}
}
/**
* Watch a directory.
*
* @param {string} dir
* @private
*/
watchdir(dir) {
if (this.watched[dir]) {
return;
}
const watcher = fs.watch(
dir,
{persistent: true},
this.normalizeChange.bind(this, dir),
);
this.watched[dir] = watcher;
watcher.on('error', this.checkedEmitError);
if (this.root !== dir) {
this.register(dir);
}
}
/**
* Stop watching a directory.
*
* @param {string} dir
* @private
*/
stopWatching(dir) {
if (this.watched[dir]) {
this.watched[dir].close();
delete this.watched[dir];
}
}
/**
* End watching.
*
* @public
*/
close() {
for (const key of Object.keys(this.watched)) this.stopWatching(key);
this.removeAllListeners();
return Promise.resolve();
}
/**
* On some platforms, as pointed out on the fs docs (most likely just win32)
* the file argument might be missing from the fs event. Try to detect what
* change by detecting if something was deleted or the most recent file change.
*
* @param {string} dir
* @param {string} event
* @param {string} file
* @public
*/
detectChangedFile(dir, event, callback) {
if (!this.dirRegistry[dir]) {
return;
}
let found = false;
let closest = {mtime: 0};
let c = 0;
// eslint-disable-next-line unicorn/no-array-for-each
Object.keys(this.dirRegistry[dir]).forEach((file, i, arr) => {
fs.lstat(path.join(dir, file), (error, stat) => {
if (found) {
return;
}
if (error) {
if (isIgnorableFileError(error)) {
found = true;
callback(file);
} else {
this.emit('error', error);
}
} else {
if (stat.mtime > closest.mtime) {
stat.file = file;
closest = stat;
}
if (arr.length === ++c) {
callback(closest.file);
}
}
});
});
}
/**
* Normalize fs events and pass it on to be processed.
*
* @param {string} dir
* @param {string} event
* @param {string} file
* @public
*/
normalizeChange(dir, event, file) {
if (file) {
this.processChange(dir, event, path.normalize(file));
} else {
this.detectChangedFile(dir, event, actualFile => {
if (actualFile) {
this.processChange(dir, event, actualFile);
}
});
}
}
/**
* Process changes.
*
* @param {string} dir
* @param {string} event
* @param {string} file
* @public
*/
processChange(dir, event, file) {
const fullPath = path.join(dir, file);
const relativePath = path.join(path.relative(this.root, dir), file);
fs.lstat(fullPath, (error, stat) => {
if (error && error.code !== 'ENOENT') {
this.emit('error', error);
} else if (!error && stat.isDirectory()) {
// win32 emits usless change events on dirs.
if (event !== 'change') {
this.watchdir(fullPath);
if (
common.isFileIncluded(
this.globs,
this.dot,
this.doIgnore,
relativePath,
)
) {
this.emitEvent(ADD_EVENT, relativePath, stat);
}
}
} else {
const registered = this.registered(fullPath);
if (error && error.code === 'ENOENT') {
this.unregister(fullPath);
this.stopWatching(fullPath);
this.unregisterDir(fullPath);
if (registered) {
this.emitEvent(DELETE_EVENT, relativePath);
}
} else if (registered) {
this.emitEvent(CHANGE_EVENT, relativePath, stat);
} else {
if (this.register(fullPath)) {
this.emitEvent(ADD_EVENT, relativePath, stat);
}
}
}
});
}
/**
* Triggers a 'change' event after debounding it to take care of duplicate
* events on os x.
*
* @private
*/
emitEvent(type, file, stat) {
const key = `${type}-${file}`;
const addKey = `${ADD_EVENT}-${file}`;
if (type === CHANGE_EVENT && this.changeTimers[addKey]) {
// Ignore the change event that is immediately fired after an add event.
// (This happens on Linux).
return;
}
clearTimeout(this.changeTimers[key]);
this.changeTimers[key] = setTimeout(() => {
delete this.changeTimers[key];
if (type === ADD_EVENT && stat.isDirectory()) {
// Recursively emit add events and watch for sub-files/folders
common.recReaddir(
path.resolve(this.root, file),
function emitAddDir(dir, stats) {
this.watchdir(dir);
this.rawEmitEvent(ADD_EVENT, path.relative(this.root, dir), stats);
}.bind(this),
function emitAddFile(file, stats) {
this.register(file);
this.rawEmitEvent(ADD_EVENT, path.relative(this.root, file), stats);
}.bind(this),
function endCallback() {},
this.checkedEmitError,
this.ignored,
);
} else {
this.rawEmitEvent(type, file, stat);
}
}, DEFAULT_DELAY);
}
/**
* Actually emit the events
*/
rawEmitEvent(type, file, stat) {
this.emit(type, file, this.root, stat);
this.emit(ALL_EVENT, type, file, this.root, stat);
}
};
/**
* Determine if a given FS error can be ignored
*
* @private
*/
function isIgnorableFileError(error) {
return (
error.code === 'ENOENT' ||
// Workaround Windows node issue #4337.
(error.code === 'EPERM' && platform === 'win32')
);
}
/***/ },
/***/ "./src/watchers/RecrawlWarning.js"
(module) {
// vendored from https://github.com/amasad/sane/blob/64ff3a870c42e84f744086884bf55a4f9c22d376/src/utils/recrawl-warning-dedupe.js
class RecrawlWarning {
constructor(root, count) {
this.root = root;
this.count = count;
}
static findByRoot(root) {
for (let i = 0; i < this.RECRAWL_WARNINGS.length; i++) {
const warning = this.RECRAWL_WARNINGS[i];
if (warning.root === root) {
return warning;
}
}
return und