Skip to content

Commit 1678cd9

Browse files
authored
chore: use Maps throughout jest-runtime (#10968)
1 parent ec820c3 commit 1678cd9

File tree

10 files changed

+69
-92
lines changed

10 files changed

+69
-92
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
- `[jest-resolve]` [**BREAKING**] Migrate to ESM ([#10688](https://github.com/facebook/jest/pull/10688))
6363
- `[jest-resolve-dependencies]` [**BREAKING**] Migrate to ESM ([#10876](https://github.com/facebook/jest/pull/10876))
6464
- `[jest-mock]` [**BREAKING**] Migrate to ESM ([#10887](https://github.com/facebook/jest/pull/10887))
65+
- `[jest-resolve, jest-runtime]` [**BREAKING**] Use `Map`s instead of objects for all cached resources ([#10968](https://github.com/facebook/jest/pull/10968))
6566
- `[jest-runner]` [**BREAKING**] Migrate to ESM ([#10900](https://github.com/facebook/jest/pull/10900))
6667
- `[jest-runtime]` [**BREAKING**] Remove deprecated and unnused `getSourceMapInfo` from Runtime ([#9969](https://github.com/facebook/jest/pull/9969))
6768
- `[jest-util]` No longer checking `enumerable` when adding `process.domain` ([#10862](https://github.com/facebook/jest/pull/10862))

packages/jest-repl/src/cli/runtime-cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export async function run(
9191
config,
9292
environment,
9393
hasteMap.resolver,
94-
undefined,
94+
new Map(),
9595
undefined,
9696
filePath,
9797
);

packages/jest-resolve/src/index.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ type FindNodeModuleConfig = {
3131
throwIfNotFound?: boolean;
3232
};
3333

34-
// TODO: replace with a Map in Jest 27
35-
type BooleanObject = Record<string, boolean>;
36-
3734
export type ResolveModuleConfig = {
3835
skipNodeResolution?: boolean;
3936
paths?: Array<Config.Path>;
@@ -314,7 +311,7 @@ class Resolver {
314311
}
315312

316313
getModuleID(
317-
virtualMocks: BooleanObject,
314+
virtualMocks: Map<string, boolean>,
318315
from: Config.Path,
319316
_moduleName?: string,
320317
): string {
@@ -346,7 +343,7 @@ class Resolver {
346343
}
347344

348345
private _getAbsolutePath(
349-
virtualMocks: BooleanObject,
346+
virtualMocks: Map<string, boolean>,
350347
from: Config.Path,
351348
moduleName: string,
352349
): Config.Path | null {
@@ -368,12 +365,12 @@ class Resolver {
368365
}
369366

370367
private _getVirtualMockPath(
371-
virtualMocks: BooleanObject,
368+
virtualMocks: Map<string, boolean>,
372369
from: Config.Path,
373370
moduleName: string,
374371
): Config.Path {
375372
const virtualMockPath = this.getModulePath(from, moduleName);
376-
return virtualMocks[virtualMockPath]
373+
return virtualMocks.get(virtualMockPath)
377374
? virtualMockPath
378375
: moduleName
379376
? this.resolveModule(from, moduleName)

packages/jest-runner/src/runTest.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ async function runTestInternal(
146146
? new LeakDetector(environment)
147147
: null;
148148

149-
const cacheFS = {[path]: testSource};
149+
const cacheFS = new Map([[path, testSource]]);
150150
setGlobal(environment.global, 'console', testConsole);
151151

152152
const runtime = new Runtime(
@@ -182,8 +182,7 @@ async function runTestInternal(
182182
environment: 'node',
183183
handleUncaughtExceptions: false,
184184
retrieveSourceMap: source => {
185-
const sourceMaps = runtime.getSourceMaps();
186-
const sourceMapSource = sourceMaps && sourceMaps[source];
185+
const sourceMapSource = runtime.getSourceMaps()?.get(source);
187186

188187
if (sourceMapSource) {
189188
try {

packages/jest-runtime/src/__mocks__/createRuntime.js

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,14 @@ const setupModuleNameMapper = (config, rootDir) => {
3535
};
3636

3737
const setupTransform = (config, rootDir) => {
38-
if (config && config.transform) {
38+
if (config?.transform) {
3939
const transform = config.transform;
4040
return Object.keys(transform).map(regex => [
4141
regex,
4242
path.resolve(rootDir, transform[regex]),
4343
]);
4444
}
45-
return [
46-
[
47-
'^.+\\.[jt]sx?$',
48-
path.resolve(
49-
__dirname,
50-
'..',
51-
'..',
52-
'..',
53-
'babel-jest',
54-
'build',
55-
'index.js',
56-
),
57-
],
58-
];
45+
return [['^.+\\.[jt]sx?$', require.resolve('babel-jest')]];
5946
};
6047

6148
module.exports = async function createRuntime(filename, config) {
@@ -67,32 +54,29 @@ module.exports = async function createRuntime(filename, config) {
6754
const moduleNameMapper = setupModuleNameMapper(config, rootDir);
6855
const transform = setupTransform(config, rootDir);
6956

70-
config = makeProjectConfig(
71-
{
72-
cacheDirectory: getCacheDirectory(),
73-
cwd: path.resolve(__dirname, '..', '..', '..', '..'),
74-
haste: {
75-
hasteImplModulePath: path.resolve(
76-
__dirname,
77-
'..',
78-
'..',
79-
'..',
80-
'jest-haste-map',
81-
'src',
82-
'__tests__',
83-
'haste_impl.js',
84-
),
85-
},
86-
moduleDirectories: ['node_modules'],
87-
moduleFileExtensions: ['js', 'json', 'jsx', 'ts', 'tsx', 'node'],
88-
name: 'Runtime-' + filename.replace(/\W/, '-') + '.tests',
89-
rootDir,
90-
...config,
91-
moduleNameMapper,
92-
transform,
57+
config = makeProjectConfig({
58+
cacheDirectory: getCacheDirectory(),
59+
cwd: path.resolve(__dirname, '..', '..', '..', '..'),
60+
haste: {
61+
hasteImplModulePath: path.resolve(
62+
__dirname,
63+
'..',
64+
'..',
65+
'..',
66+
'jest-haste-map',
67+
'src',
68+
'__tests__',
69+
'haste_impl.js',
70+
),
9371
},
94-
{},
95-
);
72+
moduleDirectories: ['node_modules'],
73+
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],
74+
name: 'Runtime-' + filename.replace(/\W/, '-') + '.tests',
75+
rootDir,
76+
...config,
77+
moduleNameMapper,
78+
transform,
79+
});
9680

9781
if (!config.roots.length) {
9882
config.roots = [config.rootDir];
@@ -110,7 +94,7 @@ module.exports = async function createRuntime(filename, config) {
11094
config,
11195
environment,
11296
Runtime.createResolver(config, hasteMap.moduleMap),
113-
undefined,
97+
new Map(),
11498
undefined,
11599
filename,
116100
);

packages/jest-runtime/src/__tests__/__snapshots__/runtime_require_module_no_ext.test.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ exports[`Runtime requireModule with no extension throws error pointing out file
66
However, Jest was able to find:
77
'./RegularModuleWithWrongExt.txt'
88
9-
You might want to include a file extension in your import, or update your 'moduleFileExtensions', which is currently ['js', 'json', 'jsx', 'ts', 'tsx', 'node'].
9+
You might want to include a file extension in your import, or update your 'moduleFileExtensions', which is currently ['js', 'jsx', 'ts', 'tsx', 'json', 'node'].
1010
1111
See https://jestjs.io/docs/en/configuration#modulefileextensions-arraystring"
1212
`;

packages/jest-runtime/src/index.ts

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,6 @@ type ResolveOptions = Parameters<typeof require.resolve>[1] & {
102102
[JEST_RESOLVE_OUTSIDE_VM_OPTION]?: true;
103103
};
104104

105-
type StringMap = Map<string, string>;
106-
type BooleanMap = Map<string, boolean>;
107-
108-
const fromEntries: typeof Object.fromEntries =
109-
Object.fromEntries ??
110-
function fromEntries<T>(iterable: Iterable<[string, T]>) {
111-
return [...iterable].reduce<Record<string, T>>((obj, [key, val]) => {
112-
obj[key] = val;
113-
return obj;
114-
}, {});
115-
};
116-
117105
const testTimeoutSymbol = Symbol.for('TEST_TIMEOUT_SYMBOL');
118106
const retryTimesSymbol = Symbol.for('RETRY_TIMES');
119107

@@ -154,12 +142,12 @@ const supportsTopLevelAwait =
154142
})();
155143

156144
export default class Runtime {
157-
private readonly _cacheFS: StringMap;
145+
private readonly _cacheFS: Map<string, string>;
158146
private readonly _config: Config.ProjectConfig;
159147
private readonly _coverageOptions: ShouldInstrumentOptions;
160148
private _currentlyExecutingModulePath: string;
161149
private readonly _environment: JestEnvironment;
162-
private readonly _explicitShouldMock: BooleanMap;
150+
private readonly _explicitShouldMock: Map<string, boolean>;
163151
private _fakeTimersImplementation:
164152
| LegacyFakeTimers<unknown>
165153
| ModernFakeTimers
@@ -181,16 +169,19 @@ export default class Runtime {
181169
private readonly _testPath: Config.Path | undefined;
182170
private readonly _resolver: Resolver;
183171
private _shouldAutoMock: boolean;
184-
private readonly _shouldMockModuleCache: BooleanMap;
185-
private readonly _shouldUnmockTransitiveDependenciesCache: BooleanMap;
186-
private readonly _sourceMapRegistry: StringMap;
172+
private readonly _shouldMockModuleCache: Map<string, boolean>;
173+
private readonly _shouldUnmockTransitiveDependenciesCache: Map<
174+
string,
175+
boolean
176+
>;
177+
private readonly _sourceMapRegistry: Map<string, string>;
187178
private readonly _scriptTransformer: ScriptTransformer;
188179
private readonly _fileTransforms: Map<string, RuntimeTransformResult>;
189180
private _v8CoverageInstrumenter: CoverageInstrumenter | undefined;
190181
private _v8CoverageResult: V8Coverage | undefined;
191-
private readonly _transitiveShouldMock: BooleanMap;
182+
private readonly _transitiveShouldMock: Map<string, boolean>;
192183
private _unmockList: RegExp | undefined;
193-
private readonly _virtualMocks: BooleanMap;
184+
private readonly _virtualMocks: Map<string, boolean>;
194185
private _moduleImplementation?: typeof nativeModule.Module;
195186
private readonly jestObjectCaches: Map<string, Jest>;
196187
private jestGlobals?: JestGlobals;
@@ -199,12 +190,12 @@ export default class Runtime {
199190
config: Config.ProjectConfig,
200191
environment: JestEnvironment,
201192
resolver: Resolver,
202-
cacheFS: Record<string, string> = {},
193+
cacheFS: Map<string, string>,
203194
coverageOptions?: ShouldInstrumentOptions,
204195
// TODO: Make mandatory in Jest 27
205196
testPath?: Config.Path,
206197
) {
207-
this._cacheFS = new Map(Object.entries(cacheFS));
198+
this._cacheFS = cacheFS;
208199
this._config = config;
209200
this._coverageOptions = coverageOptions || {
210201
changedFiles: undefined,
@@ -222,8 +213,11 @@ export default class Runtime {
222213
this._mainModule = null;
223214
this._mockFactories = new Map();
224215
this._mockRegistry = new Map();
225-
// during setup, this cannot be null (and it's fine to explode if it is)
226-
this._moduleMocker = this._environment.moduleMocker!;
216+
invariant(
217+
this._environment.moduleMocker,
218+
'`moduleMocker` must be set on an environment when created',
219+
);
220+
this._moduleMocker = this._environment.moduleMocker;
227221
this._isolatedModuleRegistry = null;
228222
this._isolatedMockRegistry = null;
229223
this._moduleRegistry = new Map();
@@ -256,10 +250,12 @@ export default class Runtime {
256250
}
257251

258252
if (config.automock) {
259-
const virtualMocks = fromEntries(this._virtualMocks);
260253
config.setupFiles.forEach(filePath => {
261-
if (filePath && filePath.includes(NODE_MODULES)) {
262-
const moduleID = this._resolver.getModuleID(virtualMocks, filePath);
254+
if (filePath.includes(NODE_MODULES)) {
255+
const moduleID = this._resolver.getModuleID(
256+
this._virtualMocks,
257+
filePath,
258+
);
263259
this._transitiveShouldMock.set(moduleID, false);
264260
}
265261
});
@@ -575,7 +571,7 @@ export default class Runtime {
575571
isRequireActual?: boolean | null,
576572
): T {
577573
const moduleID = this._resolver.getModuleID(
578-
fromEntries(this._virtualMocks),
574+
this._virtualMocks,
579575
from,
580576
moduleName,
581577
);
@@ -670,7 +666,7 @@ export default class Runtime {
670666

671667
requireMock<T = unknown>(from: Config.Path, moduleName: string): T {
672668
const moduleID = this._resolver.getModuleID(
673-
fromEntries(this._virtualMocks),
669+
this._virtualMocks,
674670
from,
675671
moduleName,
676672
);
@@ -922,7 +918,7 @@ export default class Runtime {
922918
}
923919

924920
getSourceMaps(): SourceMapRegistry {
925-
return fromEntries(this._sourceMapRegistry);
921+
return this._sourceMapRegistry;
926922
}
927923

928924
setMock(
@@ -937,7 +933,7 @@ export default class Runtime {
937933
this._virtualMocks.set(mockPath, true);
938934
}
939935
const moduleID = this._resolver.getModuleID(
940-
fromEntries(this._virtualMocks),
936+
this._virtualMocks,
941937
from,
942938
moduleName,
943939
);
@@ -1365,7 +1361,7 @@ export default class Runtime {
13651361
private _shouldMock(from: Config.Path, moduleName: string): boolean {
13661362
const explicitShouldMock = this._explicitShouldMock;
13671363
const moduleID = this._resolver.getModuleID(
1368-
fromEntries(this._virtualMocks),
1364+
this._virtualMocks,
13691365
from,
13701366
moduleName,
13711367
);
@@ -1408,7 +1404,7 @@ export default class Runtime {
14081404

14091405
// transitive unmocking for package managers that store flat packages (npm3)
14101406
const currentModuleID = this._resolver.getModuleID(
1411-
fromEntries(this._virtualMocks),
1407+
this._virtualMocks,
14121408
from,
14131409
);
14141410
if (
@@ -1493,7 +1489,7 @@ export default class Runtime {
14931489
};
14941490
const unmock = (moduleName: string) => {
14951491
const moduleID = this._resolver.getModuleID(
1496-
fromEntries(this._virtualMocks),
1492+
this._virtualMocks,
14971493
from,
14981494
moduleName,
14991495
);
@@ -1502,7 +1498,7 @@ export default class Runtime {
15021498
};
15031499
const deepUnmock = (moduleName: string) => {
15041500
const moduleID = this._resolver.getModuleID(
1505-
fromEntries(this._virtualMocks),
1501+
this._virtualMocks,
15061502
from,
15071503
moduleName,
15081504
);
@@ -1516,7 +1512,7 @@ export default class Runtime {
15161512
}
15171513

15181514
const moduleID = this._resolver.getModuleID(
1519-
fromEntries(this._virtualMocks),
1515+
this._virtualMocks,
15201516
from,
15211517
moduleName,
15221518
);

packages/jest-source-map/src/__tests__/getCallsite.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('getCallsite', () => {
3131
throw new Error('Mock error');
3232
});
3333

34-
const site = getCallsite(0, {[__filename]: 'mockedSourceMapFile'});
34+
const site = getCallsite(0, new Map([[__filename, 'mockedSourceMapFile']]));
3535

3636
expect(site.getFileName()).toEqual(__filename);
3737
expect(site.getColumnNumber()).toEqual(expect.any(Number));
@@ -59,7 +59,7 @@ describe('getCallsite', () => {
5959
}
6060
};
6161

62-
const site = getCallsite(0, {[__filename]: 'mockedSourceMapFile'});
62+
const site = getCallsite(0, new Map([[__filename, 'mockedSourceMapFile']]));
6363

6464
expect(site.getFileName()).toEqual(__filename);
6565
expect(site.getColumnNumber()).toEqual(sourceMapColumn);

packages/jest-source-map/src/getCallsite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export default (
5252
): callsites.CallSite => {
5353
const levelAfterThisCall = level + 1;
5454
const stack = callsites()[levelAfterThisCall];
55-
const sourceMapFileName = sourceMaps && sourceMaps[stack.getFileName() || ''];
55+
const sourceMapFileName = sourceMaps?.get(stack.getFileName() || '');
5656

5757
if (sourceMapFileName) {
5858
try {

packages/jest-source-map/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
export type SourceMapRegistry = Record<string, string>;
8+
export type SourceMapRegistry = Map<string, string>;

0 commit comments

Comments
 (0)