aboutsummaryrefslogtreecommitdiff
path: root/node_modules/jest-haste-map/build/index.js
diff options
context:
space:
mode:
authorJoel Kronqvist <work.joelkronqvist@pm.me>2022-03-11 20:46:06 +0200
committerJoel Kronqvist <work.joelkronqvist@pm.me>2022-03-11 20:46:06 +0200
commit080c5819d87b933816d724a83f3bf4f1686770a7 (patch)
tree4a2ccc68b27edf7d4cbc586c932cc7542b655e19 /node_modules/jest-haste-map/build/index.js
parent5ac7049a9d30733165cc212dee308163c2a14644 (diff)
parentd003b82235a9329f912522a2f70aa950dfce4998 (diff)
downloadLYLLRuoka-080c5819d87b933816d724a83f3bf4f1686770a7.tar.gz
LYLLRuoka-080c5819d87b933816d724a83f3bf4f1686770a7.zip
Merge branch 'master' of https://github.com/JoelHMikael/FoodJS
Updating remote changes
Diffstat (limited to 'node_modules/jest-haste-map/build/index.js')
-rw-r--r--node_modules/jest-haste-map/build/index.js1266
1 files changed, 1266 insertions, 0 deletions
diff --git a/node_modules/jest-haste-map/build/index.js b/node_modules/jest-haste-map/build/index.js
new file mode 100644
index 0000000..30a60a2
--- /dev/null
+++ b/node_modules/jest-haste-map/build/index.js
@@ -0,0 +1,1266 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.DuplicateError = void 0;
+Object.defineProperty(exports, 'ModuleMap', {
+ enumerable: true,
+ get: function () {
+ return _ModuleMap.default;
+ }
+});
+exports.default = void 0;
+
+function _child_process() {
+ const data = require('child_process');
+
+ _child_process = function () {
+ return data;
+ };
+
+ return data;
+}
+
+function _crypto() {
+ const data = require('crypto');
+
+ _crypto = function () {
+ return data;
+ };
+
+ return data;
+}
+
+function _events() {
+ const data = require('events');
+
+ _events = function () {
+ return data;
+ };
+
+ return data;
+}
+
+function _os() {
+ const data = require('os');
+
+ _os = function () {
+ return data;
+ };
+
+ return data;
+}
+
+function path() {
+ const data = _interopRequireWildcard(require('path'));
+
+ path = function () {
+ return data;
+ };
+
+ return data;
+}
+
+function _jestRegexUtil() {
+ const data = require('jest-regex-util');
+
+ _jestRegexUtil = function () {
+ return data;
+ };
+
+ return data;
+}
+
+function _jestSerializer() {
+ const data = _interopRequireDefault(require('jest-serializer'));
+
+ _jestSerializer = function () {
+ return data;
+ };
+
+ return data;
+}
+
+function _jestWorker() {
+ const data = require('jest-worker');
+
+ _jestWorker = function () {
+ return data;
+ };
+
+ return data;
+}
+
+var _HasteFS = _interopRequireDefault(require('./HasteFS'));
+
+var _ModuleMap = _interopRequireDefault(require('./ModuleMap'));
+
+var _constants = _interopRequireDefault(require('./constants'));
+
+var _node = _interopRequireDefault(require('./crawlers/node'));
+
+var _watchman = _interopRequireDefault(require('./crawlers/watchman'));
+
+var _getMockName = _interopRequireDefault(require('./getMockName'));
+
+var fastPath = _interopRequireWildcard(require('./lib/fast_path'));
+
+var _getPlatformExtension = _interopRequireDefault(
+ require('./lib/getPlatformExtension')
+);
+
+var _normalizePathSep = _interopRequireDefault(
+ require('./lib/normalizePathSep')
+);
+
+var _FSEventsWatcher = _interopRequireDefault(
+ require('./watchers/FSEventsWatcher')
+);
+
+var _NodeWatcher = _interopRequireDefault(require('./watchers/NodeWatcher'));
+
+var _WatchmanWatcher = _interopRequireDefault(
+ require('./watchers/WatchmanWatcher')
+);
+
+var _worker = require('./worker');
+
+function _interopRequireDefault(obj) {
+ return obj && obj.__esModule ? obj : {default: obj};
+}
+
+function _getRequireWildcardCache(nodeInterop) {
+ if (typeof WeakMap !== 'function') return null;
+ var cacheBabelInterop = new WeakMap();
+ var cacheNodeInterop = new WeakMap();
+ return (_getRequireWildcardCache = function (nodeInterop) {
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
+ })(nodeInterop);
+}
+
+function _interopRequireWildcard(obj, nodeInterop) {
+ if (!nodeInterop && obj && obj.__esModule) {
+ return obj;
+ }
+ if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
+ return {default: obj};
+ }
+ var cache = _getRequireWildcardCache(nodeInterop);
+ if (cache && cache.has(obj)) {
+ return cache.get(obj);
+ }
+ var newObj = {};
+ var hasPropertyDescriptor =
+ Object.defineProperty && Object.getOwnPropertyDescriptor;
+ for (var key in obj) {
+ if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
+ var desc = hasPropertyDescriptor
+ ? Object.getOwnPropertyDescriptor(obj, key)
+ : null;
+ if (desc && (desc.get || desc.set)) {
+ Object.defineProperty(newObj, key, desc);
+ } else {
+ newObj[key] = obj[key];
+ }
+ }
+ }
+ newObj.default = obj;
+ if (cache) {
+ cache.set(obj, newObj);
+ }
+ return newObj;
+}
+
+function _defineProperty(obj, key, value) {
+ if (key in obj) {
+ Object.defineProperty(obj, key, {
+ value: value,
+ enumerable: true,
+ configurable: true,
+ writable: true
+ });
+ } else {
+ obj[key] = value;
+ }
+ return obj;
+}
+
+// TypeScript doesn't like us importing from outside `rootDir`, but it doesn't
+// understand `require`.
+const {version: VERSION} = require('../package.json');
+
+const CHANGE_INTERVAL = 30;
+const MAX_WAIT_TIME = 240000;
+const NODE_MODULES = path().sep + 'node_modules' + path().sep;
+const PACKAGE_JSON = path().sep + 'package.json';
+const VCS_DIRECTORIES = ['.git', '.hg']
+ .map(vcs =>
+ (0, _jestRegexUtil().escapePathForRegex)(path().sep + vcs + path().sep)
+ )
+ .join('|');
+
+const canUseWatchman = (() => {
+ try {
+ (0, _child_process().execSync)('watchman --version', {
+ stdio: ['ignore']
+ });
+ return true;
+ } catch {}
+
+ return false;
+})();
+
+function invariant(condition, message) {
+ if (!condition) {
+ throw new Error(message);
+ }
+}
+/**
+ * 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 _events().EventEmitter {
+ static getStatic(config) {
+ if (config.haste.hasteMapModulePath) {
+ return require(config.haste.hasteMapModulePath);
+ }
+
+ return HasteMap;
+ }
+
+ static create(options) {
+ if (options.hasteMapModulePath) {
+ const CustomHasteMap = require(options.hasteMapModulePath);
+
+ return new CustomHasteMap(options);
+ }
+
+ return new HasteMap(options);
+ }
+
+ constructor(options) {
+ super();
+
+ _defineProperty(this, '_buildPromise', void 0);
+
+ _defineProperty(this, '_cachePath', void 0);
+
+ _defineProperty(this, '_changeInterval', void 0);
+
+ _defineProperty(this, '_console', void 0);
+
+ _defineProperty(this, '_options', void 0);
+
+ _defineProperty(this, '_watchers', void 0);
+
+ _defineProperty(this, '_worker', void 0);
+
+ this._options = {
+ cacheDirectory: options.cacheDirectory || (0, _os().tmpdir)(),
+ computeDependencies:
+ options.computeDependencies === undefined
+ ? true
+ : options.computeDependencies,
+ computeSha1: options.computeSha1 || false,
+ dependencyExtractor: options.dependencyExtractor || null,
+ enableSymlinks: options.enableSymlinks || false,
+ extensions: options.extensions,
+ forceNodeFilesystemAPI: !!options.forceNodeFilesystemAPI,
+ hasteImplModulePath: options.hasteImplModulePath,
+ maxWorkers: options.maxWorkers,
+ mocksPattern: options.mocksPattern
+ ? new RegExp(options.mocksPattern)
+ : null,
+ name: options.name,
+ platforms: options.platforms,
+ resetCache: options.resetCache,
+ retainAllFiles: options.retainAllFiles,
+ rootDir: options.rootDir,
+ roots: Array.from(new Set(options.roots)),
+ skipPackageJson: !!options.skipPackageJson,
+ throwOnModuleCollision: !!options.throwOnModuleCollision,
+ useWatchman: options.useWatchman == null ? true : options.useWatchman,
+ watch: !!options.watch
+ };
+ this._console = options.console || global.console;
+
+ if (options.ignorePattern) {
+ if (options.ignorePattern instanceof RegExp) {
+ this._options.ignorePattern = new RegExp(
+ options.ignorePattern.source.concat('|' + VCS_DIRECTORIES),
+ options.ignorePattern.flags
+ );
+ } else {
+ throw new Error(
+ '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.'
+ );
+ }
+
+ const rootDirHash = (0, _crypto().createHash)('md5')
+ .update(options.rootDir)
+ .digest('hex');
+ let hasteImplHash = '';
+ let dependencyExtractorHash = '';
+
+ if (options.hasteImplModulePath) {
+ const hasteImpl = require(options.hasteImplModulePath);
+
+ if (hasteImpl.getCacheKey) {
+ hasteImplHash = String(hasteImpl.getCacheKey());
+ }
+ }
+
+ if (options.dependencyExtractor) {
+ const dependencyExtractor = require(options.dependencyExtractor);
+
+ if (dependencyExtractor.getCacheKey) {
+ dependencyExtractorHash = String(dependencyExtractor.getCacheKey());
+ }
+ }
+
+ this._cachePath = HasteMap.getCacheFilePath(
+ this._options.cacheDirectory,
+ `haste-map-${this._options.name}-${rootDirHash}`,
+ VERSION,
+ this._options.name,
+ 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._buildPromise = null;
+ this._watchers = [];
+ this._worker = null;
+ }
+
+ static getCacheFilePath(tmpdir, name, ...extra) {
+ const hash = (0, _crypto().createHash)('md5').update(extra.join(''));
+ return path().join(
+ tmpdir,
+ name.replace(/\W/g, '-') + '-' + hash.digest('hex')
+ );
+ }
+
+ static getModuleMapFromJSON(json) {
+ return _ModuleMap.default.fromJSON(json);
+ }
+
+ getCacheFilePath() {
+ return this._cachePath;
+ }
+
+ 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 =
+ (process.env.NODE_ENV === 'test' && hasteMap) || null;
+
+ await this._watch(hasteMap);
+ return {
+ __hasteMapForTest,
+ hasteFS,
+ moduleMap
+ };
+ })();
+ }
+
+ return this._buildPromise;
+ }
+ /**
+ * 1. read data from the cache or create an empty structure.
+ */
+
+ read() {
+ let hasteMap;
+
+ try {
+ hasteMap = _jestSerializer().default.readFileSync(this._cachePath);
+ } catch {
+ hasteMap = this._createEmptyMap();
+ }
+
+ return hasteMap;
+ }
+
+ 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() {
+ let hasteMap;
+
+ try {
+ const read = this._options.resetCache ? this._createEmptyMap : this.read;
+ hasteMap = await read.call(this);
+ } catch {
+ hasteMap = this._createEmptyMap();
+ }
+
+ return this._crawl(hasteMap);
+ }
+ /**
+ * 3. parse and extract metadata from changed files.
+ */
+
+ _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 === 1) {
+ 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]; // Callback called when the response from the worker is successful.
+
+ 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;
+ }
+ }; // Callback called when the response from the worker is an error.
+
+ const workerError = error => {
+ if (typeof error !== 'object' || !error.message || !error.stack) {
+ error = new Error(error);
+ error.stack = ''; // Remove stack for stack-less errors.
+ }
+
+ if (!['ENOENT', 'EACCES'].includes(error.code)) {
+ 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);
+ }
+ }
+ }
+
+ mocks.set(mockPath, relativeFilePath);
+ }
+
+ if (fileMetadata[_constants.default.VISITED]) {
+ if (!fileMetadata[_constants.default.ID]) {
+ return null;
+ }
+
+ if (moduleMetadata != null) {
+ const platform =
+ (0, _getPlatformExtension.default)(
+ filePath,
+ this._options.platforms
+ ) || _constants.default.GENERIC_PLATFORM;
+
+ const module = moduleMetadata[platform];
+
+ if (module == null) {
+ return null;
+ }
+
+ const moduleId = fileMetadata[_constants.default.ID];
+ let modulesByPlatform = map.get(moduleId);
+
+ if (!modulesByPlatform) {
+ modulesByPlatform = Object.create(null);
+ map.set(moduleId, modulesByPlatform);
+ }
+
+ modulesByPlatform[platform] = module;
+ 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) {
+ 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) {
+ map = new Map();
+ mocks = new Map();
+ filesToProcess = hasteMap.files;
+ } else {
+ map = hasteMap.map;
+ mocks = hasteMap.mocks;
+ filesToProcess = changedFiles;
+ }
+
+ for (const [relativeFilePath, fileMetadata] of removedFiles) {
+ this._recoverDuplicates(
+ hasteMap,
+ relativeFilePath,
+ fileMetadata[_constants.default.ID]
+ );
+ }
+
+ const promises = [];
+
+ 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);
+ }
+ }
+
+ return Promise.all(promises).then(
+ () => {
+ this._cleanup();
+
+ hasteMap.map = map;
+ hasteMap.mocks = mocks;
+ return hasteMap;
+ },
+ error => {
+ this._cleanup();
+
+ throw error;
+ }
+ );
+ }
+
+ _cleanup() {
+ const worker = this._worker; // @ts-expect-error
+
+ if (worker && typeof worker.end === 'function') {
+ // @ts-expect-error
+ worker.end();
+ }
+
+ this._worker = null;
+ }
+ /**
+ * 4. serialize the new `HasteMap` in a cache file.
+ */
+
+ _persist(hasteMap) {
+ _jestSerializer().default.writeFileSync(this._cachePath, hasteMap);
+ }
+ /**
+ * Creates workers or parses files and extracts metadata in-process.
+ */
+
+ _getWorker(options) {
+ if (!this._worker) {
+ if ((options && options.forceInBand) || this._options.maxWorkers <= 1) {
+ this._worker = {
+ getSha1: _worker.getSha1,
+ worker: _worker.worker
+ };
+ } else {
+ // @ts-expect-error: assignment of a worker with custom properties.
+ this._worker = new (_jestWorker().Worker)(require.resolve('./worker'), {
+ exposedMethods: ['getSha1', 'worker'],
+ maxRetries: 3,
+ numWorkers: this._options.maxWorkers
+ });
+ }
+ }
+
+ return this._worker;
+ }
+
+ _crawl(hasteMap) {
+ const options = this._options;
+
+ const ignore = this._ignore.bind(this);
+
+ const crawl =
+ canUseWatchman && this._options.useWatchman
+ ? _watchman.default
+ : _node.default;
+ const crawlerOptions = {
+ computeSha1: options.computeSha1,
+ data: hasteMap,
+ enableSymlinks: options.enableSymlinks,
+ extensions: options.extensions,
+ forceNodeFilesystemAPI: options.forceNodeFilesystemAPI,
+ ignore,
+ rootDir: options.rootDir,
+ roots: options.roots
+ };
+
+ const retry = error => {
+ if (crawl === _watchman.default) {
+ this._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' +
+ ' ' +
+ error
+ );
+
+ return (0, _node.default)(crawlerOptions).catch(e => {
+ throw new Error(
+ 'Crawler retry failed:\n' +
+ ` Original error: ${error.message}\n` +
+ ` Retry error: ${e.message}\n`
+ );
+ });
+ }
+
+ throw error;
+ };
+
+ try {
+ return crawl(crawlerOptions).catch(retry);
+ } catch (error) {
+ return retry(error);
+ }
+ }
+ /**
+ * Watch mode
+ */
+
+ _watch(hasteMap) {
+ if (!this._options.watch) {
+ return Promise.resolve();
+ } // 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; // WatchmanWatcher > FSEventsWatcher > sane.NodeWatcher
+
+ const Watcher =
+ canUseWatchman && this._options.useWatchman
+ ? _WatchmanWatcher.default
+ : _FSEventsWatcher.default.isSupported()
+ ? _FSEventsWatcher.default
+ : _NodeWatcher.default;
+ const extensions = this._options.extensions;
+ const ignorePattern = this._options.ignorePattern;
+ const rootDir = this._options.rootDir;
+ let changeQueue = Promise.resolve();
+ let eventsQueue = []; // We only need to copy the entire haste map once on every "frame".
+
+ let mustCopy = true;
+
+ const createWatcher = root => {
+ const watcher = new Watcher(root, {
+ dot: true,
+ glob: extensions.map(extension => '**/*.' + extension),
+ ignored: ignorePattern
+ });
+ return new Promise((resolve, reject) => {
+ const rejectTimeout = setTimeout(
+ () => reject(new Error('Failed to start watch mode.')),
+ MAX_WAIT_TIME
+ );
+ watcher.once('ready', () => {
+ clearTimeout(rejectTimeout);
+ watcher.on('all', onChange);
+ resolve(watcher);
+ });
+ });
+ };
+
+ const emitChange = () => {
+ if (eventsQueue.length) {
+ mustCopy = true;
+ const changeEvent = {
+ eventsQueue,
+ hasteFS: new _HasteFS.default({
+ files: hasteMap.files,
+ rootDir
+ }),
+ moduleMap: new _ModuleMap.default({
+ duplicates: hasteMap.duplicates,
+ map: hasteMap.map,
+ mocks: hasteMap.mocks,
+ rootDir
+ })
+ };
+ this.emit('change', changeEvent);
+ eventsQueue = [];
+ }
+ };
+
+ const onChange = (type, filePath, root, stat) => {
+ filePath = path().join(root, (0, _normalizePathSep.default)(filePath));
+
+ if (
+ (stat && stat.isDirectory()) ||
+ this._ignore(filePath) ||
+ !extensions.some(extension => filePath.endsWith(extension))
+ ) {
+ return;
+ }
+
+ const relativeFilePath = fastPath.relative(rootDir, filePath);
+ const fileMetadata = hasteMap.files.get(relativeFilePath); // The file has been accessed, not modified
+
+ if (
+ type === 'change' &&
+ fileMetadata &&
+ stat &&
+ fileMetadata[_constants.default.MTIME] === stat.mtime.getTime()
+ ) {
+ return;
+ }
+
+ changeQueue = changeQueue
+ .then(() => {
+ // If we get duplicate events for the same file, ignore them.
+ if (
+ eventsQueue.find(
+ event =>
+ event.type === type &&
+ event.filePath === filePath &&
+ ((!event.stat && !stat) ||
+ (!!event.stat &&
+ !!stat &&
+ event.stat.mtime.getTime() === stat.mtime.getTime()))
+ )
+ ) {
+ return null;
+ }
+
+ if (mustCopy) {
+ mustCopy = false;
+ hasteMap = {
+ clocks: new Map(hasteMap.clocks),
+ duplicates: new Map(hasteMap.duplicates),
+ files: new Map(hasteMap.files),
+ map: new Map(hasteMap.map),
+ mocks: new Map(hasteMap.mocks)
+ };
+ }
+
+ const add = () => {
+ eventsQueue.push({
+ filePath,
+ stat,
+ type
+ });
+ return null;
+ };
+
+ const fileMetadata = hasteMap.files.get(relativeFilePath); // If it's not an addition, delete the file and all its metadata
+
+ if (fileMetadata != null) {
+ const moduleName = fileMetadata[_constants.default.ID];
+
+ const platform =
+ (0, _getPlatformExtension.default)(
+ filePath,
+ this._options.platforms
+ ) || _constants.default.GENERIC_PLATFORM;
+
+ hasteMap.files.delete(relativeFilePath);
+ let moduleMap = 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 = copy(moduleMap);
+ delete moduleMap[platform];
+
+ if (Object.keys(moduleMap).length === 0) {
+ hasteMap.map.delete(moduleName);
+ } else {
+ hasteMap.map.set(moduleName, moduleMap);
+ }
+ }
+
+ if (
+ this._options.mocksPattern &&
+ this._options.mocksPattern.test(filePath)
+ ) {
+ const mockName = (0, _getMockName.default)(filePath);
+ hasteMap.mocks.delete(mockName);
+ }
+
+ this._recoverDuplicates(hasteMap, relativeFilePath, moduleName);
+ } // If the file was added or changed,
+ // parse it and update the haste map.
+
+ if (type === 'add' || type === 'change') {
+ invariant(
+ stat,
+ 'since the file exists or changed, it should have stats'
+ );
+ const fileMetadata = [
+ '',
+ stat.mtime.getTime(),
+ stat.size,
+ 0,
+ '',
+ null
+ ];
+ hasteMap.files.set(relativeFilePath, fileMetadata);
+
+ const promise = this._processFile(
+ hasteMap,
+ hasteMap.map,
+ hasteMap.mocks,
+ filePath,
+ {
+ forceInBand: true
+ }
+ ); // Cleanup
+
+ this._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._console.error(
+ `jest-haste-map: watch error:\n ${error.stack}\n`
+ );
+ });
+ };
+
+ this._changeInterval = setInterval(emitChange, CHANGE_INTERVAL);
+ return Promise.all(this._options.roots.map(createWatcher)).then(
+ watchers => {
+ this._watchers = watchers;
+ }
+ );
+ }
+ /**
+ * 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 = copyMap(dupsByPlatform);
+ hasteMap.duplicates.set(moduleName, dupsByPlatform);
+ dups = 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 == null) {
+ 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() {
+ if (this._changeInterval) {
+ clearInterval(this._changeInterval);
+ }
+
+ if (!this._watchers.length) {
+ return;
+ }
+
+ await Promise.all(this._watchers.map(watcher => watcher.close()));
+ this._watchers = [];
+ }
+ /**
+ * Helpers
+ */
+
+ _ignore(filePath) {
+ const ignorePattern = this._options.ignorePattern;
+ const ignoreMatched =
+ ignorePattern instanceof RegExp
+ ? ignorePattern.test(filePath)
+ : ignorePattern && ignorePattern(filePath);
+ return (
+ ignoreMatched ||
+ (!this._options.retainAllFiles && filePath.includes(NODE_MODULES))
+ );
+ }
+
+ _createEmptyMap() {
+ return {
+ clocks: new Map(),
+ duplicates: new Map(),
+ files: new Map(),
+ map: new Map(),
+ mocks: new Map()
+ };
+ }
+}
+
+exports.default = HasteMap;
+
+_defineProperty(HasteMap, 'H', _constants.default);
+
+class DuplicateError extends Error {
+ constructor(mockPath1, mockPath2) {
+ super('Duplicated files or mocks. Please check the console for more info');
+
+ _defineProperty(this, 'mockPath1', void 0);
+
+ _defineProperty(this, 'mockPath2', void 0);
+
+ this.mockPath1 = mockPath1;
+ this.mockPath2 = mockPath2;
+ }
+}
+
+exports.DuplicateError = DuplicateError;
+
+function copy(object) {
+ return Object.assign(Object.create(null), object);
+}
+
+function copyMap(input) {
+ return new Map(input);
+}