/
githubmirror
/
jest
Обзор
Документация
Войти
/
githubmirror
/
jest
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/jest-runtime/src/internals/Resolution.ts
234 строки
7 KB
Simen Bekkhus
chore(runtime): final pass for splitting up god class (#16088)
03 май 2026, 15:58
Не верифицирован
03 май 2026, 15:58
f768319
Код
Авторство
О чём код?
/** * 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. */ import * as path from 'node:path'; import * as fs from 'graceful-fs'; import Resolver from 'jest-resolve'; export const isWasm = (modulePath: string): boolean => modulePath.endsWith('.wasm'); export class Resolution { private readonly resolver: Resolver; private readonly cjsConditions: ReadonlyArray<string>; private readonly esmConditions: ReadonlyArray<string>; private readonly extensionsToTreatAsEsm: ReadonlyArray<string>; private readonly cjsCache = new Map<string, string>(); private readonly esmCache = new Map<string, string>(); private readonly manualMockCache = new Map<string, string | null>(); constructor( resolver: Resolver, envExportConditions: ReadonlyArray<string>, extensionsToTreatAsEsm: ReadonlyArray<string>, ) { this.resolver = resolver; this.cjsConditions = [ ...new Set(['require', 'node', 'default', ...envExportConditions]), ]; this.esmConditions = [ ...new Set(['import', 'default', ...envExportConditions]), ]; this.extensionsToTreatAsEsm = extensionsToTreatAsEsm; } shouldLoadAsEsm(modulePath: string): boolean { return ( isWasm(modulePath) || Resolver.unstable_shouldLoadAsEsm( modulePath, this.extensionsToTreatAsEsm as Array<string>, ) ); } resolveCjs(from: string, to: string | undefined): string { if (!to) return from; return this.resolveCached(from, to, this.cjsCache, this.cjsConditions); } resolveEsm(from: string, to: string | undefined): string { if (!to) return from; return this.resolveCached(from, to, this.esmCache, this.esmConditions); } resolveEsmAsync(from: string, to: string | undefined): Promise<string> { if (!to) return Promise.resolve(from); return this.resolver.resolveModuleAsync(from, to, { conditions: this.esmConditions, }); } getCjsModuleId( virtualMocks: Map<string, boolean>, from: string, moduleName?: string, ): string { return this.resolver.getModuleID(virtualMocks, from, moduleName, { conditions: this.cjsConditions, }); } getEsmModuleId( virtualMocks: Map<string, boolean>, from: string, moduleName?: string, ): string { return this.resolver.getModuleID(virtualMocks, from, moduleName, { conditions: this.esmConditions, }); } getEsmModuleIdAsync( virtualMocks: Map<string, boolean>, from: string, moduleName?: string, ): Promise<string> { return this.resolver.getModuleIDAsync(virtualMocks, from, moduleName, { conditions: this.esmConditions, }); } getCjsMockModule(from: string, moduleName: string): string | null { return this.resolver.getMockModule(from, moduleName, { conditions: this.cjsConditions, }); } getEsmMockModule(from: string, moduleName: string): string | null { return this.resolver.getMockModule(from, moduleName, { conditions: this.esmConditions, }); } getEsmMockModuleAsync( from: string, moduleName: string, ): Promise<string | null> { return this.resolver.getMockModuleAsync(from, moduleName, { conditions: this.esmConditions, }); } // Resolves the manual mock module path from a (potentially aliased) module // name. Covers three shapes: // // A. Core module specifier i.e. ['fs', 'node:fs']: // Normalize then check for a root manual mock '<rootDir>/__mocks__/'. // // B. Node module specifier i.e. ['jest', 'react']: // Look for root manual mock. // // C. Relative/Absolute path: // If the actual module file has a __mocks__ dir sitting immediately next // to it, look to see if there is a manual mock for this file. // // subDir1/my_module.js // subDir1/__mocks__/my_module.js // subDir2/my_module.js // subDir2/__mocks__/my_module.js // // Where some other module does a relative require into each of the // respective subDir{1,2} directories and expects a manual mock // corresponding to that particular my_module.js file. findManualMock(from: string, moduleName: string): string | null { // Normalize core specifiers (`node:fs` → `fs`) before building the cache // key so the two forms share an entry instead of populating two. const canonicalName = this.isCoreModule(moduleName) ? this.normalizeCoreModuleSpecifier(moduleName) : moduleName; const cacheKey = `${from}\0${canonicalName}`; let result = this.manualMockCache.get(cacheKey); if (result === undefined) { result = this.computeManualMock(from, canonicalName); this.manualMockCache.set(cacheKey, result); } return result; } private computeManualMock(from: string, moduleName: string): string | null { if (this.isCoreModule(moduleName)) { return this.getCjsMockModule(from, moduleName); } const rootMock = this.getCjsMockModule(from, moduleName); if (rootMock) return rootMock; const modulePath = this.resolveCjs(from, moduleName); const sibling = path.join( path.dirname(modulePath), '__mocks__', path.basename(modulePath), ); return fs.existsSync(sibling) ? sibling : null; } resolveCjsStub(from: string, moduleName: string): string | null { return this.resolver.resolveStubModuleName(from, moduleName, { conditions: this.cjsConditions, }); } getModulePaths(from: string): Array<string> { return this.resolver.getModulePaths(from); } getGlobalPaths(moduleName?: string): Array<string> { return this.resolver.getGlobalPaths(moduleName); } isCoreModule(name: string): boolean { return this.resolver.isCoreModule(name); } normalizeCoreModuleSpecifier(name: string): string { return this.resolver.normalizeCoreModuleSpecifier(name); } getModule(name: string): string | null { return this.resolver.getModule(name); } getModulePath(from: string, moduleName: string): string { return this.resolver.getModulePath(from, moduleName); } canResolveSync(): boolean { return this.resolver.canResolveSync(); } resolveCjsFromDirIfExists( dir: string, name: string, paths?: Array<string>, ): string | null { return this.resolver.resolveModuleFromDirIfExists(dir, name, { conditions: this.cjsConditions, paths, }); } clear(): void { this.cjsCache.clear(); this.esmCache.clear(); this.manualMockCache.clear(); } private resolveCached( from: string, to: string, cache: Map<string, string>, conditions: ReadonlyArray<string>, ): string { const key = `${from}\0${to}`; const cached = cache.get(key); if (cached !== undefined) return cached; const resolved = this.resolver.resolveModule(from, to, {conditions}); cache.set(key, resolved); return resolved; } }