overtake 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/worker.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { workerData } from 'node:worker_threads';
2
2
  import { SourceTextModule, SyntheticModule, createContext } from 'node:vm';
3
3
  import { createRequire } from 'node:module';
4
- import { fileURLToPath } from 'node:url';
4
+ import { isAbsolute } from 'node:path';
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
5
6
  import { benchmark } from './runner.js';
6
7
  import { WorkerOptions } from './types.js';
7
8
 
8
9
  const {
9
- baseUrl,
10
+ benchmarkUrl,
10
11
  setupCode,
11
12
  teardownCode,
12
13
  preCode,
@@ -24,20 +25,23 @@ const {
24
25
  controlSAB,
25
26
  }: WorkerOptions = workerData;
26
27
 
27
- const serialize = (code?: string) => (code ? code : '() => {}');
28
+ const serialize = (code?: string) => (code ? code : 'undefined');
28
29
 
29
- const isCjs = typeof require !== 'undefined';
30
+ const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;
31
+ const benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;
32
+ const requireFrom = createRequire(fileURLToPath(new URL('benchmark.js', benchmarkDirUrl)));
30
33
 
31
- const resolveSpecifier = (specifier: string, parent: string) => {
32
- if (!isCjs) {
33
- try {
34
- return import.meta.resolve(specifier, parent);
35
- } catch {
36
- // fall through to CommonJS resolution
37
- }
34
+ const resolveSpecifier = (specifier: string) => {
35
+ if (specifier.startsWith('file:')) {
36
+ return specifier;
37
+ }
38
+ if (specifier.startsWith('./') || specifier.startsWith('../')) {
39
+ return new URL(specifier, benchmarkDirUrl).href;
40
+ }
41
+ if (isAbsolute(specifier)) {
42
+ return pathToFileURL(specifier).href;
38
43
  }
39
- const resolveFrom = createRequire(fileURLToPath(parent));
40
- return resolveFrom.resolve(specifier);
44
+ return requireFrom.resolve(specifier);
41
45
  };
42
46
 
43
47
  const source = `
@@ -50,38 +54,71 @@ export const post = ${serialize(postCode)};
50
54
 
51
55
  const context = createContext({ console, Buffer });
52
56
  const imports = new Map<string, SyntheticModule>();
53
- const mod = new SourceTextModule(source, {
54
- identifier: baseUrl,
55
- context,
56
- initializeImportMeta(meta) {
57
- meta.url = baseUrl;
58
- },
59
- importModuleDynamically(specifier, referencingModule) {
60
- const base = referencingModule.identifier ?? baseUrl;
61
- const resolved = resolveSpecifier(specifier, base);
62
- return import(resolved);
63
- },
64
- });
65
57
 
66
- await mod.link(async (specifier, referencingModule) => {
67
- const base = referencingModule.identifier ?? baseUrl;
68
- const target = resolveSpecifier(specifier, base);
58
+ const createSyntheticModule = (moduleExports: unknown, exportNames: string[], identifier: string) => {
59
+ const mod = new SyntheticModule(
60
+ exportNames,
61
+ () => {
62
+ for (const name of exportNames) {
63
+ if (name === 'default') {
64
+ mod.setExport(name, moduleExports);
65
+ continue;
66
+ }
67
+ mod.setExport(name, (moduleExports as Record<string, unknown>)[name]);
68
+ }
69
+ },
70
+ { identifier, context },
71
+ );
72
+ return mod;
73
+ };
74
+
75
+ const isCjsModule = (target: string) => target.endsWith('.cjs') || target.endsWith('.cts');
76
+
77
+ const toRequireTarget = (target: string) => (target.startsWith('file:') ? fileURLToPath(target) : target);
78
+
79
+ const loadModule = async (target: string) => {
69
80
  const cached = imports.get(target);
70
81
  if (cached) return cached;
71
82
 
83
+ if (isCjsModule(target)) {
84
+ const required = requireFrom(toRequireTarget(target));
85
+ const exportNames = required && (typeof required === 'object' || typeof required === 'function') ? Object.keys(required) : [];
86
+ if (!exportNames.includes('default')) {
87
+ exportNames.push('default');
88
+ }
89
+ const mod = createSyntheticModule(required, exportNames, target);
90
+ imports.set(target, mod);
91
+ return mod;
92
+ }
93
+
72
94
  const importedModule = await import(target);
73
95
  const exportNames = Object.keys(importedModule);
74
- const imported = new SyntheticModule(
75
- exportNames,
76
- () => {
77
- exportNames.forEach((key) => imported.setExport(key, importedModule[key]));
78
- },
79
- { identifier: target, context: referencingModule.context },
80
- );
81
- imports.set(target, imported);
82
- return imported;
96
+ const mod = createSyntheticModule(importedModule, exportNames, target);
97
+ imports.set(target, mod);
98
+ return mod;
99
+ };
100
+
101
+ const loadDynamicModule = async (target: string) => {
102
+ const mod = await loadModule(target);
103
+ if (mod.status !== 'evaluated') {
104
+ await mod.evaluate();
105
+ }
106
+ return mod;
107
+ };
108
+ const mod = new SourceTextModule(source, {
109
+ identifier: resolvedBenchmarkUrl,
110
+ context,
111
+ initializeImportMeta(meta) {
112
+ meta.url = resolvedBenchmarkUrl;
113
+ },
114
+ importModuleDynamically(specifier) {
115
+ const resolved = resolveSpecifier(specifier);
116
+ return loadDynamicModule(resolved);
117
+ },
83
118
  });
84
119
 
120
+ await mod.link(async (specifier) => loadModule(resolveSpecifier(specifier)));
121
+
85
122
  await mod.evaluate();
86
123
  const { setup, teardown, pre, run, post } = mod.namespace as any;
87
124
 
@@ -90,7 +127,6 @@ if (!run) {
90
127
  }
91
128
 
92
129
  process.exitCode = await benchmark({
93
- baseUrl,
94
130
  setup,
95
131
  teardown,
96
132
  pre,