UNPKG

jest-haste-map

Version:
1,584 lines (1,447 loc) 99.4 kB
/*! * /** * * 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