diff options
author | Joel Kronqvist <work.joelkronqvist@pm.me> | 2022-03-11 20:46:06 +0200 |
---|---|---|
committer | Joel Kronqvist <work.joelkronqvist@pm.me> | 2022-03-11 20:46:06 +0200 |
commit | 080c5819d87b933816d724a83f3bf4f1686770a7 (patch) | |
tree | 4a2ccc68b27edf7d4cbc586c932cc7542b655e19 /node_modules/jest-haste-map/build/index.js | |
parent | 5ac7049a9d30733165cc212dee308163c2a14644 (diff) | |
parent | d003b82235a9329f912522a2f70aa950dfce4998 (diff) | |
download | LYLLRuoka-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.js | 1266 |
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); +} |