overtake 1.1.1 → 1.1.2

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/build/worker.cjs CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  const _nodeworker_threads = require("node:worker_threads");
6
6
  const _nodevm = require("node:vm");
7
7
  const _nodemodule = require("node:module");
8
+ const _nodepath = require("node:path");
8
9
  const _nodeurl = require("node:url");
9
10
  const _runnercjs = require("./runner.cjs");
10
11
  function _getRequireWildcardCache(nodeInterop) {
@@ -48,17 +49,22 @@ function _interop_require_wildcard(obj, nodeInterop) {
48
49
  }
49
50
  return newObj;
50
51
  }
51
- const { baseUrl, setupCode, teardownCode, preCode, runCode, postCode, data, warmupCycles, minCycles, absThreshold, relThreshold, gcObserver = true, durationsSAB, controlSAB } = _nodeworker_threads.workerData;
52
+ const { benchmarkUrl, setupCode, teardownCode, preCode, runCode, postCode, data, warmupCycles, minCycles, absThreshold, relThreshold, gcObserver = true, durationsSAB, controlSAB } = _nodeworker_threads.workerData;
52
53
  const serialize = (code)=>code ? code : '() => {}';
53
- const isCjs = typeof require !== 'undefined';
54
- const resolveSpecifier = (specifier, parent)=>{
55
- if (!isCjs) {
56
- try {
57
- return require.resolve(specifier, parent);
58
- } catch {}
54
+ const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : (0, _nodeurl.pathToFileURL)(process.cwd()).href;
55
+ const benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;
56
+ const requireFrom = (0, _nodemodule.createRequire)((0, _nodeurl.fileURLToPath)(new URL('benchmark.js', benchmarkDirUrl)));
57
+ const resolveSpecifier = (specifier)=>{
58
+ if (specifier.startsWith('file:')) {
59
+ return specifier;
59
60
  }
60
- const resolveFrom = (0, _nodemodule.createRequire)((0, _nodeurl.fileURLToPath)(parent));
61
- return resolveFrom.resolve(specifier);
61
+ if (specifier.startsWith('./') || specifier.startsWith('../')) {
62
+ return new URL(specifier, benchmarkDirUrl).href;
63
+ }
64
+ if ((0, _nodepath.isAbsolute)(specifier)) {
65
+ return (0, _nodeurl.pathToFileURL)(specifier).href;
66
+ }
67
+ return requireFrom.resolve(specifier);
62
68
  };
63
69
  const source = `
64
70
  export const setup = ${serialize(setupCode)};
@@ -72,41 +78,67 @@ const context = (0, _nodevm.createContext)({
72
78
  Buffer
73
79
  });
74
80
  const imports = new Map();
81
+ const createSyntheticModule = (moduleExports, exportNames, identifier)=>{
82
+ const mod = new _nodevm.SyntheticModule(exportNames, ()=>{
83
+ for (const name of exportNames){
84
+ if (name === 'default') {
85
+ mod.setExport(name, moduleExports);
86
+ continue;
87
+ }
88
+ mod.setExport(name, moduleExports[name]);
89
+ }
90
+ }, {
91
+ identifier,
92
+ context
93
+ });
94
+ return mod;
95
+ };
96
+ const isCjsModule = (target)=>target.endsWith('.cjs') || target.endsWith('.cts');
97
+ const toRequireTarget = (target)=>target.startsWith('file:') ? (0, _nodeurl.fileURLToPath)(target) : target;
98
+ const loadModule = async (target)=>{
99
+ const cached = imports.get(target);
100
+ if (cached) return cached;
101
+ if (isCjsModule(target)) {
102
+ const required = requireFrom(toRequireTarget(target));
103
+ const exportNames = required && (typeof required === 'object' || typeof required === 'function') ? Object.keys(required) : [];
104
+ if (!exportNames.includes('default')) {
105
+ exportNames.push('default');
106
+ }
107
+ const mod = createSyntheticModule(required, exportNames, target);
108
+ imports.set(target, mod);
109
+ return mod;
110
+ }
111
+ const importedModule = await Promise.resolve(target).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
112
+ const exportNames = Object.keys(importedModule);
113
+ const mod = createSyntheticModule(importedModule, exportNames, target);
114
+ imports.set(target, mod);
115
+ return mod;
116
+ };
117
+ const loadDynamicModule = async (target)=>{
118
+ const mod = await loadModule(target);
119
+ if (mod.status !== 'evaluated') {
120
+ await mod.evaluate();
121
+ }
122
+ return mod;
123
+ };
75
124
  const mod = new _nodevm.SourceTextModule(source, {
76
- identifier: baseUrl,
125
+ identifier: resolvedBenchmarkUrl,
77
126
  context,
78
127
  initializeImportMeta (meta) {
79
- meta.url = baseUrl;
128
+ meta.url = resolvedBenchmarkUrl;
80
129
  },
81
- importModuleDynamically (specifier, referencingModule) {
82
- const base = referencingModule.identifier ?? baseUrl;
83
- const resolved = resolveSpecifier(specifier, base);
84
- return Promise.resolve(resolved).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
130
+ importModuleDynamically (specifier) {
131
+ const resolved = resolveSpecifier(specifier);
132
+ return loadDynamicModule(resolved);
85
133
  }
86
134
  });
87
- await mod.link(async (specifier, referencingModule)=>{
88
- const base = referencingModule.identifier ?? baseUrl;
89
- const target = resolveSpecifier(specifier, base);
90
- const cached = imports.get(target);
91
- if (cached) return cached;
92
- const importedModule = await Promise.resolve(target).then((p)=>/*#__PURE__*/ _interop_require_wildcard(require(p)));
93
- const exportNames = Object.keys(importedModule);
94
- const imported = new _nodevm.SyntheticModule(exportNames, ()=>{
95
- exportNames.forEach((key)=>imported.setExport(key, importedModule[key]));
96
- }, {
97
- identifier: target,
98
- context: referencingModule.context
99
- });
100
- imports.set(target, imported);
101
- return imported;
102
- });
135
+ await mod.link(async (specifier)=>loadModule(resolveSpecifier(specifier)));
103
136
  await mod.evaluate();
104
137
  const { setup, teardown, pre, run, post } = mod.namespace;
105
138
  if (!run) {
106
139
  throw new Error('Benchmark run function is required');
107
140
  }
108
141
  process.exitCode = await (0, _runnercjs.benchmark)({
109
- baseUrl,
110
142
  setup,
111
143
  teardown,
112
144
  pre,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule, createContext } from 'node:vm';\nimport { createRequire } from 'node:module';\nimport { fileURLToPath } from 'node:url';\nimport { benchmark } from './runner.js';\nimport { WorkerOptions } from './types.js';\n\nconst {\n baseUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = true,\n\n durationsSAB,\n controlSAB,\n}: WorkerOptions = workerData;\n\nconst serialize = (code?: string) => (code ? code : '() => {}');\n\nconst isCjs = typeof require !== 'undefined';\n\nconst resolveSpecifier = (specifier: string, parent: string) => {\n if (!isCjs) {\n try {\n return import.meta.resolve(specifier, parent);\n } catch {\n // fall through to CommonJS resolution\n }\n }\n const resolveFrom = createRequire(fileURLToPath(parent));\n return resolveFrom.resolve(specifier);\n};\n\nconst source = `\nexport const setup = ${serialize(setupCode)};\nexport const teardown = ${serialize(teardownCode)};\nexport const pre = ${serialize(preCode)};\nexport const run = ${serialize(runCode)};\nexport const post = ${serialize(postCode)};\n `;\n\nconst context = createContext({ console, Buffer });\nconst imports = new Map<string, SyntheticModule>();\nconst mod = new SourceTextModule(source, {\n identifier: baseUrl,\n context,\n initializeImportMeta(meta) {\n meta.url = baseUrl;\n },\n importModuleDynamically(specifier, referencingModule) {\n const base = referencingModule.identifier ?? baseUrl;\n const resolved = resolveSpecifier(specifier, base);\n return import(resolved);\n },\n});\n\nawait mod.link(async (specifier, referencingModule) => {\n const base = referencingModule.identifier ?? baseUrl;\n const target = resolveSpecifier(specifier, base);\n const cached = imports.get(target);\n if (cached) return cached;\n\n const importedModule = await import(target);\n const exportNames = Object.keys(importedModule);\n const imported = new SyntheticModule(\n exportNames,\n () => {\n exportNames.forEach((key) => imported.setExport(key, importedModule[key]));\n },\n { identifier: target, context: referencingModule.context },\n );\n imports.set(target, imported);\n return imported;\n});\n\nawait mod.evaluate();\nconst { setup, teardown, pre, run, post } = mod.namespace as any;\n\nif (!run) {\n throw new Error('Benchmark run function is required');\n}\n\nprocess.exitCode = await benchmark({\n baseUrl,\n setup,\n teardown,\n pre,\n run,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n\n durationsSAB,\n controlSAB,\n});\n"],"names":["baseUrl","setupCode","teardownCode","preCode","runCode","postCode","data","warmupCycles","minCycles","absThreshold","relThreshold","gcObserver","durationsSAB","controlSAB","workerData","serialize","code","isCjs","require","resolveSpecifier","specifier","parent","resolve","resolveFrom","createRequire","fileURLToPath","source","context","createContext","console","Buffer","imports","Map","mod","SourceTextModule","identifier","initializeImportMeta","meta","url","importModuleDynamically","referencingModule","base","resolved","link","target","cached","get","importedModule","exportNames","Object","keys","imported","SyntheticModule","forEach","key","setExport","set","evaluate","setup","teardown","pre","run","post","namespace","Error","process","exitCode","benchmark"],"mappings":";;;;oCAA2B;wBACsC;4BACnC;yBACA;2BACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG1B,MAAM,EACJA,OAAO,EACPC,SAAS,EACTC,YAAY,EACZC,OAAO,EACPC,OAAO,EACPC,QAAQ,EACRC,IAAI,EAEJC,YAAY,EACZC,SAAS,EACTC,YAAY,EACZC,YAAY,EACZC,aAAa,IAAI,EAEjBC,YAAY,EACZC,UAAU,EACX,GAAkBC,8BAAU;AAE7B,MAAMC,YAAY,CAACC,OAAmBA,OAAOA,OAAO;AAEpD,MAAMC,QAAQ,OAAOC,YAAY;AAEjC,MAAMC,mBAAmB,CAACC,WAAmBC;IAC3C,IAAI,CAACJ,OAAO;QACV,IAAI;YACF,OAAO,QAAYK,OAAO,CAACF,WAAWC;QACxC,EAAE,OAAM,CAER;IACF;IACA,MAAME,cAAcC,IAAAA,yBAAa,EAACC,IAAAA,sBAAa,EAACJ;IAChD,OAAOE,YAAYD,OAAO,CAACF;AAC7B;AAEA,MAAMM,SAAS,CAAC;qBACK,EAAEX,UAAUd,WAAW;wBACpB,EAAEc,UAAUb,cAAc;mBAC/B,EAAEa,UAAUZ,SAAS;mBACrB,EAAEY,UAAUX,SAAS;oBACpB,EAAEW,UAAUV,UAAU;EACxC,CAAC;AAEH,MAAMsB,UAAUC,IAAAA,qBAAa,EAAC;IAAEC;IAASC;AAAO;AAChD,MAAMC,UAAU,IAAIC;AACpB,MAAMC,MAAM,IAAIC,wBAAgB,CAACR,QAAQ;IACvCS,YAAYnC;IACZ2B;IACAS,sBAAqBC,IAAI;QACvBA,KAAKC,GAAG,GAAGtC;IACb;IACAuC,yBAAwBnB,SAAS,EAAEoB,iBAAiB;QAClD,MAAMC,OAAOD,kBAAkBL,UAAU,IAAInC;QAC7C,MAAM0C,WAAWvB,iBAAiBC,WAAWqB;QAC7C,OAAO,gBAAOC,4DAAP;IACT;AACF;AAEA,MAAMT,IAAIU,IAAI,CAAC,OAAOvB,WAAWoB;IAC/B,MAAMC,OAAOD,kBAAkBL,UAAU,IAAInC;IAC7C,MAAM4C,SAASzB,iBAAiBC,WAAWqB;IAC3C,MAAMI,SAASd,QAAQe,GAAG,CAACF;IAC3B,IAAIC,QAAQ,OAAOA;IAEnB,MAAME,iBAAiB,MAAM,gBAAOH,0DAAP;IAC7B,MAAMI,cAAcC,OAAOC,IAAI,CAACH;IAChC,MAAMI,WAAW,IAAIC,uBAAe,CAClCJ,aACA;QACEA,YAAYK,OAAO,CAAC,CAACC,MAAQH,SAASI,SAAS,CAACD,KAAKP,cAAc,CAACO,IAAI;IAC1E,GACA;QAAEnB,YAAYS;QAAQjB,SAASa,kBAAkBb,OAAO;IAAC;IAE3DI,QAAQyB,GAAG,CAACZ,QAAQO;IACpB,OAAOA;AACT;AAEA,MAAMlB,IAAIwB,QAAQ;AAClB,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,GAAG,EAAEC,IAAI,EAAE,GAAG7B,IAAI8B,SAAS;AAEzD,IAAI,CAACF,KAAK;IACR,MAAM,IAAIG,MAAM;AAClB;AAEAC,QAAQC,QAAQ,GAAG,MAAMC,IAAAA,oBAAS,EAAC;IACjCnE;IACA0D;IACAC;IACAC;IACAC;IACAC;IACAxD;IAEAC;IACAC;IACAC;IACAC;IACAC;IAEAC;IACAC;AACF"}
1
+ {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule, createContext } from 'node:vm';\nimport { createRequire } from 'node:module';\nimport { isAbsolute } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { benchmark } from './runner.js';\nimport { WorkerOptions } from './types.js';\n\nconst {\n benchmarkUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = true,\n\n durationsSAB,\n controlSAB,\n}: WorkerOptions = workerData;\n\nconst serialize = (code?: string) => (code ? code : '() => {}');\n\nconst resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;\nconst benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;\nconst requireFrom = createRequire(fileURLToPath(new URL('benchmark.js', benchmarkDirUrl)));\n\nconst resolveSpecifier = (specifier: string) => {\n if (specifier.startsWith('file:')) {\n return specifier;\n }\n if (specifier.startsWith('./') || specifier.startsWith('../')) {\n return new URL(specifier, benchmarkDirUrl).href;\n }\n if (isAbsolute(specifier)) {\n return pathToFileURL(specifier).href;\n }\n return requireFrom.resolve(specifier);\n};\n\nconst source = `\nexport const setup = ${serialize(setupCode)};\nexport const teardown = ${serialize(teardownCode)};\nexport const pre = ${serialize(preCode)};\nexport const run = ${serialize(runCode)};\nexport const post = ${serialize(postCode)};\n `;\n\nconst context = createContext({ console, Buffer });\nconst imports = new Map<string, SyntheticModule>();\n\nconst createSyntheticModule = (moduleExports: unknown, exportNames: string[], identifier: string) => {\n const mod = new SyntheticModule(\n exportNames,\n () => {\n for (const name of exportNames) {\n if (name === 'default') {\n mod.setExport(name, moduleExports);\n continue;\n }\n mod.setExport(name, (moduleExports as Record<string, unknown>)[name]);\n }\n },\n { identifier, context },\n );\n return mod;\n};\n\nconst isCjsModule = (target: string) => target.endsWith('.cjs') || target.endsWith('.cts');\n\nconst toRequireTarget = (target: string) => (target.startsWith('file:') ? fileURLToPath(target) : target);\n\nconst loadModule = async (target: string) => {\n const cached = imports.get(target);\n if (cached) return cached;\n\n if (isCjsModule(target)) {\n const required = requireFrom(toRequireTarget(target));\n const exportNames = required && (typeof required === 'object' || typeof required === 'function') ? Object.keys(required) : [];\n if (!exportNames.includes('default')) {\n exportNames.push('default');\n }\n const mod = createSyntheticModule(required, exportNames, target);\n imports.set(target, mod);\n return mod;\n }\n\n const importedModule = await import(target);\n const exportNames = Object.keys(importedModule);\n const mod = createSyntheticModule(importedModule, exportNames, target);\n imports.set(target, mod);\n return mod;\n};\n\nconst loadDynamicModule = async (target: string) => {\n const mod = await loadModule(target);\n if (mod.status !== 'evaluated') {\n await mod.evaluate();\n }\n return mod;\n};\nconst mod = new SourceTextModule(source, {\n identifier: resolvedBenchmarkUrl,\n context,\n initializeImportMeta(meta) {\n meta.url = resolvedBenchmarkUrl;\n },\n importModuleDynamically(specifier) {\n const resolved = resolveSpecifier(specifier);\n return loadDynamicModule(resolved);\n },\n});\n\nawait mod.link(async (specifier) => loadModule(resolveSpecifier(specifier)));\n\nawait mod.evaluate();\nconst { setup, teardown, pre, run, post } = mod.namespace as any;\n\nif (!run) {\n throw new Error('Benchmark run function is required');\n}\n\nprocess.exitCode = await benchmark({\n setup,\n teardown,\n pre,\n run,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n\n durationsSAB,\n controlSAB,\n});\n"],"names":["benchmarkUrl","setupCode","teardownCode","preCode","runCode","postCode","data","warmupCycles","minCycles","absThreshold","relThreshold","gcObserver","durationsSAB","controlSAB","workerData","serialize","code","resolvedBenchmarkUrl","pathToFileURL","process","cwd","href","benchmarkDirUrl","URL","requireFrom","createRequire","fileURLToPath","resolveSpecifier","specifier","startsWith","isAbsolute","resolve","source","context","createContext","console","Buffer","imports","Map","createSyntheticModule","moduleExports","exportNames","identifier","mod","SyntheticModule","name","setExport","isCjsModule","target","endsWith","toRequireTarget","loadModule","cached","get","required","Object","keys","includes","push","set","importedModule","loadDynamicModule","status","evaluate","SourceTextModule","initializeImportMeta","meta","url","importModuleDynamically","resolved","link","setup","teardown","pre","run","post","namespace","Error","exitCode","benchmark"],"mappings":";;;;oCAA2B;wBACsC;4BACnC;0BACH;yBACkB;2BACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG1B,MAAM,EACJA,YAAY,EACZC,SAAS,EACTC,YAAY,EACZC,OAAO,EACPC,OAAO,EACPC,QAAQ,EACRC,IAAI,EAEJC,YAAY,EACZC,SAAS,EACTC,YAAY,EACZC,YAAY,EACZC,aAAa,IAAI,EAEjBC,YAAY,EACZC,UAAU,EACX,GAAkBC,8BAAU;AAE7B,MAAMC,YAAY,CAACC,OAAmBA,OAAOA,OAAO;AAEpD,MAAMC,uBAAuB,OAAOjB,iBAAiB,WAAWA,eAAekB,IAAAA,sBAAa,EAACC,QAAQC,GAAG,IAAIC,IAAI;AAChH,MAAMC,kBAAkB,IAAIC,IAAI,KAAKN,sBAAsBI,IAAI;AAC/D,MAAMG,cAAcC,IAAAA,yBAAa,EAACC,IAAAA,sBAAa,EAAC,IAAIH,IAAI,gBAAgBD;AAExE,MAAMK,mBAAmB,CAACC;IACxB,IAAIA,UAAUC,UAAU,CAAC,UAAU;QACjC,OAAOD;IACT;IACA,IAAIA,UAAUC,UAAU,CAAC,SAASD,UAAUC,UAAU,CAAC,QAAQ;QAC7D,OAAO,IAAIN,IAAIK,WAAWN,iBAAiBD,IAAI;IACjD;IACA,IAAIS,IAAAA,oBAAU,EAACF,YAAY;QACzB,OAAOV,IAAAA,sBAAa,EAACU,WAAWP,IAAI;IACtC;IACA,OAAOG,YAAYO,OAAO,CAACH;AAC7B;AAEA,MAAMI,SAAS,CAAC;qBACK,EAAEjB,UAAUd,WAAW;wBACpB,EAAEc,UAAUb,cAAc;mBAC/B,EAAEa,UAAUZ,SAAS;mBACrB,EAAEY,UAAUX,SAAS;oBACpB,EAAEW,UAAUV,UAAU;EACxC,CAAC;AAEH,MAAM4B,UAAUC,IAAAA,qBAAa,EAAC;IAAEC;IAASC;AAAO;AAChD,MAAMC,UAAU,IAAIC;AAEpB,MAAMC,wBAAwB,CAACC,eAAwBC,aAAuBC;IAC5E,MAAMC,MAAM,IAAIC,uBAAe,CAC7BH,aACA;QACE,KAAK,MAAMI,QAAQJ,YAAa;YAC9B,IAAII,SAAS,WAAW;gBACtBF,IAAIG,SAAS,CAACD,MAAML;gBACpB;YACF;YACAG,IAAIG,SAAS,CAACD,MAAM,AAACL,aAAyC,CAACK,KAAK;QACtE;IACF,GACA;QAAEH;QAAYT;IAAQ;IAExB,OAAOU;AACT;AAEA,MAAMI,cAAc,CAACC,SAAmBA,OAAOC,QAAQ,CAAC,WAAWD,OAAOC,QAAQ,CAAC;AAEnF,MAAMC,kBAAkB,CAACF,SAAoBA,OAAOnB,UAAU,CAAC,WAAWH,IAAAA,sBAAa,EAACsB,UAAUA;AAElG,MAAMG,aAAa,OAAOH;IACxB,MAAMI,SAASf,QAAQgB,GAAG,CAACL;IAC3B,IAAII,QAAQ,OAAOA;IAEnB,IAAIL,YAAYC,SAAS;QACvB,MAAMM,WAAW9B,YAAY0B,gBAAgBF;QAC7C,MAAMP,cAAca,YAAa,CAAA,OAAOA,aAAa,YAAY,OAAOA,aAAa,UAAS,IAAKC,OAAOC,IAAI,CAACF,YAAY,EAAE;QAC7H,IAAI,CAACb,YAAYgB,QAAQ,CAAC,YAAY;YACpChB,YAAYiB,IAAI,CAAC;QACnB;QACA,MAAMf,MAAMJ,sBAAsBe,UAAUb,aAAaO;QACzDX,QAAQsB,GAAG,CAACX,QAAQL;QACpB,OAAOA;IACT;IAEA,MAAMiB,iBAAiB,MAAM,gBAAOZ,0DAAP;IAC7B,MAAMP,cAAcc,OAAOC,IAAI,CAACI;IAChC,MAAMjB,MAAMJ,sBAAsBqB,gBAAgBnB,aAAaO;IAC/DX,QAAQsB,GAAG,CAACX,QAAQL;IACpB,OAAOA;AACT;AAEA,MAAMkB,oBAAoB,OAAOb;IAC/B,MAAML,MAAM,MAAMQ,WAAWH;IAC7B,IAAIL,IAAImB,MAAM,KAAK,aAAa;QAC9B,MAAMnB,IAAIoB,QAAQ;IACpB;IACA,OAAOpB;AACT;AACA,MAAMA,MAAM,IAAIqB,wBAAgB,CAAChC,QAAQ;IACvCU,YAAYzB;IACZgB;IACAgC,sBAAqBC,IAAI;QACvBA,KAAKC,GAAG,GAAGlD;IACb;IACAmD,yBAAwBxC,SAAS;QAC/B,MAAMyC,WAAW1C,iBAAiBC;QAClC,OAAOiC,kBAAkBQ;IAC3B;AACF;AAEA,MAAM1B,IAAI2B,IAAI,CAAC,OAAO1C,YAAcuB,WAAWxB,iBAAiBC;AAEhE,MAAMe,IAAIoB,QAAQ;AAClB,MAAM,EAAEQ,KAAK,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,GAAG,EAAEC,IAAI,EAAE,GAAGhC,IAAIiC,SAAS;AAEzD,IAAI,CAACF,KAAK;IACR,MAAM,IAAIG,MAAM;AAClB;AAEA1D,QAAQ2D,QAAQ,GAAG,MAAMC,IAAAA,oBAAS,EAAC;IACjCR;IACAC;IACAC;IACAC;IACAC;IACArE;IAEAC;IACAC;IACAC;IACAC;IACAC;IAEAC;IACAC;AACF"}
package/build/worker.js CHANGED
@@ -1,19 +1,25 @@
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
- const { baseUrl, setupCode, teardownCode, preCode, runCode, postCode, data, warmupCycles, minCycles, absThreshold, relThreshold, gcObserver = true, durationsSAB, controlSAB } = workerData;
7
+ const { benchmarkUrl, setupCode, teardownCode, preCode, runCode, postCode, data, warmupCycles, minCycles, absThreshold, relThreshold, gcObserver = true, durationsSAB, controlSAB } = workerData;
7
8
  const serialize = (code)=>code ? code : '() => {}';
8
- const isCjs = typeof require !== 'undefined';
9
- const resolveSpecifier = (specifier, parent)=>{
10
- if (!isCjs) {
11
- try {
12
- return import.meta.resolve(specifier, parent);
13
- } catch {}
9
+ const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;
10
+ const benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;
11
+ const requireFrom = createRequire(fileURLToPath(new URL('benchmark.js', benchmarkDirUrl)));
12
+ const resolveSpecifier = (specifier)=>{
13
+ if (specifier.startsWith('file:')) {
14
+ return specifier;
14
15
  }
15
- const resolveFrom = createRequire(fileURLToPath(parent));
16
- return resolveFrom.resolve(specifier);
16
+ if (specifier.startsWith('./') || specifier.startsWith('../')) {
17
+ return new URL(specifier, benchmarkDirUrl).href;
18
+ }
19
+ if (isAbsolute(specifier)) {
20
+ return pathToFileURL(specifier).href;
21
+ }
22
+ return requireFrom.resolve(specifier);
17
23
  };
18
24
  const source = `
19
25
  export const setup = ${serialize(setupCode)};
@@ -27,41 +33,67 @@ const context = createContext({
27
33
  Buffer
28
34
  });
29
35
  const imports = new Map();
36
+ const createSyntheticModule = (moduleExports, exportNames, identifier)=>{
37
+ const mod = new SyntheticModule(exportNames, ()=>{
38
+ for (const name of exportNames){
39
+ if (name === 'default') {
40
+ mod.setExport(name, moduleExports);
41
+ continue;
42
+ }
43
+ mod.setExport(name, moduleExports[name]);
44
+ }
45
+ }, {
46
+ identifier,
47
+ context
48
+ });
49
+ return mod;
50
+ };
51
+ const isCjsModule = (target)=>target.endsWith('.cjs') || target.endsWith('.cts');
52
+ const toRequireTarget = (target)=>target.startsWith('file:') ? fileURLToPath(target) : target;
53
+ const loadModule = async (target)=>{
54
+ const cached = imports.get(target);
55
+ if (cached) return cached;
56
+ if (isCjsModule(target)) {
57
+ const required = requireFrom(toRequireTarget(target));
58
+ const exportNames = required && (typeof required === 'object' || typeof required === 'function') ? Object.keys(required) : [];
59
+ if (!exportNames.includes('default')) {
60
+ exportNames.push('default');
61
+ }
62
+ const mod = createSyntheticModule(required, exportNames, target);
63
+ imports.set(target, mod);
64
+ return mod;
65
+ }
66
+ const importedModule = await import(target);
67
+ const exportNames = Object.keys(importedModule);
68
+ const mod = createSyntheticModule(importedModule, exportNames, target);
69
+ imports.set(target, mod);
70
+ return mod;
71
+ };
72
+ const loadDynamicModule = async (target)=>{
73
+ const mod = await loadModule(target);
74
+ if (mod.status !== 'evaluated') {
75
+ await mod.evaluate();
76
+ }
77
+ return mod;
78
+ };
30
79
  const mod = new SourceTextModule(source, {
31
- identifier: baseUrl,
80
+ identifier: resolvedBenchmarkUrl,
32
81
  context,
33
82
  initializeImportMeta (meta) {
34
- meta.url = baseUrl;
83
+ meta.url = resolvedBenchmarkUrl;
35
84
  },
36
- importModuleDynamically (specifier, referencingModule) {
37
- const base = referencingModule.identifier ?? baseUrl;
38
- const resolved = resolveSpecifier(specifier, base);
39
- return import(resolved);
85
+ importModuleDynamically (specifier) {
86
+ const resolved = resolveSpecifier(specifier);
87
+ return loadDynamicModule(resolved);
40
88
  }
41
89
  });
42
- await mod.link(async (specifier, referencingModule)=>{
43
- const base = referencingModule.identifier ?? baseUrl;
44
- const target = resolveSpecifier(specifier, base);
45
- const cached = imports.get(target);
46
- if (cached) return cached;
47
- const importedModule = await import(target);
48
- const exportNames = Object.keys(importedModule);
49
- const imported = new SyntheticModule(exportNames, ()=>{
50
- exportNames.forEach((key)=>imported.setExport(key, importedModule[key]));
51
- }, {
52
- identifier: target,
53
- context: referencingModule.context
54
- });
55
- imports.set(target, imported);
56
- return imported;
57
- });
90
+ await mod.link(async (specifier)=>loadModule(resolveSpecifier(specifier)));
58
91
  await mod.evaluate();
59
92
  const { setup, teardown, pre, run, post } = mod.namespace;
60
93
  if (!run) {
61
94
  throw new Error('Benchmark run function is required');
62
95
  }
63
96
  process.exitCode = await benchmark({
64
- baseUrl,
65
97
  setup,
66
98
  teardown,
67
99
  pre,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule, createContext } from 'node:vm';\nimport { createRequire } from 'node:module';\nimport { fileURLToPath } from 'node:url';\nimport { benchmark } from './runner.js';\nimport { WorkerOptions } from './types.js';\n\nconst {\n baseUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = true,\n\n durationsSAB,\n controlSAB,\n}: WorkerOptions = workerData;\n\nconst serialize = (code?: string) => (code ? code : '() => {}');\n\nconst isCjs = typeof require !== 'undefined';\n\nconst resolveSpecifier = (specifier: string, parent: string) => {\n if (!isCjs) {\n try {\n return import.meta.resolve(specifier, parent);\n } catch {\n // fall through to CommonJS resolution\n }\n }\n const resolveFrom = createRequire(fileURLToPath(parent));\n return resolveFrom.resolve(specifier);\n};\n\nconst source = `\nexport const setup = ${serialize(setupCode)};\nexport const teardown = ${serialize(teardownCode)};\nexport const pre = ${serialize(preCode)};\nexport const run = ${serialize(runCode)};\nexport const post = ${serialize(postCode)};\n `;\n\nconst context = createContext({ console, Buffer });\nconst imports = new Map<string, SyntheticModule>();\nconst mod = new SourceTextModule(source, {\n identifier: baseUrl,\n context,\n initializeImportMeta(meta) {\n meta.url = baseUrl;\n },\n importModuleDynamically(specifier, referencingModule) {\n const base = referencingModule.identifier ?? baseUrl;\n const resolved = resolveSpecifier(specifier, base);\n return import(resolved);\n },\n});\n\nawait mod.link(async (specifier, referencingModule) => {\n const base = referencingModule.identifier ?? baseUrl;\n const target = resolveSpecifier(specifier, base);\n const cached = imports.get(target);\n if (cached) return cached;\n\n const importedModule = await import(target);\n const exportNames = Object.keys(importedModule);\n const imported = new SyntheticModule(\n exportNames,\n () => {\n exportNames.forEach((key) => imported.setExport(key, importedModule[key]));\n },\n { identifier: target, context: referencingModule.context },\n );\n imports.set(target, imported);\n return imported;\n});\n\nawait mod.evaluate();\nconst { setup, teardown, pre, run, post } = mod.namespace as any;\n\nif (!run) {\n throw new Error('Benchmark run function is required');\n}\n\nprocess.exitCode = await benchmark({\n baseUrl,\n setup,\n teardown,\n pre,\n run,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n\n durationsSAB,\n controlSAB,\n});\n"],"names":["workerData","SourceTextModule","SyntheticModule","createContext","createRequire","fileURLToPath","benchmark","baseUrl","setupCode","teardownCode","preCode","runCode","postCode","data","warmupCycles","minCycles","absThreshold","relThreshold","gcObserver","durationsSAB","controlSAB","serialize","code","isCjs","require","resolveSpecifier","specifier","parent","resolve","resolveFrom","source","context","console","Buffer","imports","Map","mod","identifier","initializeImportMeta","meta","url","importModuleDynamically","referencingModule","base","resolved","link","target","cached","get","importedModule","exportNames","Object","keys","imported","forEach","key","setExport","set","evaluate","setup","teardown","pre","run","post","namespace","Error","process","exitCode"],"mappings":"AAAA,SAASA,UAAU,QAAQ,sBAAsB;AACjD,SAASC,gBAAgB,EAAEC,eAAe,EAAEC,aAAa,QAAQ,UAAU;AAC3E,SAASC,aAAa,QAAQ,cAAc;AAC5C,SAASC,aAAa,QAAQ,WAAW;AACzC,SAASC,SAAS,QAAQ,cAAc;AAGxC,MAAM,EACJC,OAAO,EACPC,SAAS,EACTC,YAAY,EACZC,OAAO,EACPC,OAAO,EACPC,QAAQ,EACRC,IAAI,EAEJC,YAAY,EACZC,SAAS,EACTC,YAAY,EACZC,YAAY,EACZC,aAAa,IAAI,EAEjBC,YAAY,EACZC,UAAU,EACX,GAAkBpB;AAEnB,MAAMqB,YAAY,CAACC,OAAmBA,OAAOA,OAAO;AAEpD,MAAMC,QAAQ,OAAOC,YAAY;AAEjC,MAAMC,mBAAmB,CAACC,WAAmBC;IAC3C,IAAI,CAACJ,OAAO;QACV,IAAI;YACF,OAAO,YAAYK,OAAO,CAACF,WAAWC;QACxC,EAAE,OAAM,CAER;IACF;IACA,MAAME,cAAczB,cAAcC,cAAcsB;IAChD,OAAOE,YAAYD,OAAO,CAACF;AAC7B;AAEA,MAAMI,SAAS,CAAC;qBACK,EAAET,UAAUb,WAAW;wBACpB,EAAEa,UAAUZ,cAAc;mBAC/B,EAAEY,UAAUX,SAAS;mBACrB,EAAEW,UAAUV,SAAS;oBACpB,EAAEU,UAAUT,UAAU;EACxC,CAAC;AAEH,MAAMmB,UAAU5B,cAAc;IAAE6B;IAASC;AAAO;AAChD,MAAMC,UAAU,IAAIC;AACpB,MAAMC,MAAM,IAAInC,iBAAiB6B,QAAQ;IACvCO,YAAY9B;IACZwB;IACAO,sBAAqBC,IAAI;QACvBA,KAAKC,GAAG,GAAGjC;IACb;IACAkC,yBAAwBf,SAAS,EAAEgB,iBAAiB;QAClD,MAAMC,OAAOD,kBAAkBL,UAAU,IAAI9B;QAC7C,MAAMqC,WAAWnB,iBAAiBC,WAAWiB;QAC7C,OAAO,MAAM,CAACC;IAChB;AACF;AAEA,MAAMR,IAAIS,IAAI,CAAC,OAAOnB,WAAWgB;IAC/B,MAAMC,OAAOD,kBAAkBL,UAAU,IAAI9B;IAC7C,MAAMuC,SAASrB,iBAAiBC,WAAWiB;IAC3C,MAAMI,SAASb,QAAQc,GAAG,CAACF;IAC3B,IAAIC,QAAQ,OAAOA;IAEnB,MAAME,iBAAiB,MAAM,MAAM,CAACH;IACpC,MAAMI,cAAcC,OAAOC,IAAI,CAACH;IAChC,MAAMI,WAAW,IAAInD,gBACnBgD,aACA;QACEA,YAAYI,OAAO,CAAC,CAACC,MAAQF,SAASG,SAAS,CAACD,KAAKN,cAAc,CAACM,IAAI;IAC1E,GACA;QAAElB,YAAYS;QAAQf,SAASW,kBAAkBX,OAAO;IAAC;IAE3DG,QAAQuB,GAAG,CAACX,QAAQO;IACpB,OAAOA;AACT;AAEA,MAAMjB,IAAIsB,QAAQ;AAClB,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,GAAG,EAAEC,IAAI,EAAE,GAAG3B,IAAI4B,SAAS;AAEzD,IAAI,CAACF,KAAK;IACR,MAAM,IAAIG,MAAM;AAClB;AAEAC,QAAQC,QAAQ,GAAG,MAAM7D,UAAU;IACjCC;IACAoD;IACAC;IACAC;IACAC;IACAC;IACAlD;IAEAC;IACAC;IACAC;IACAC;IACAC;IAEAC;IACAC;AACF"}
1
+ {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule, createContext } from 'node:vm';\nimport { createRequire } from 'node:module';\nimport { isAbsolute } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { benchmark } from './runner.js';\nimport { WorkerOptions } from './types.js';\n\nconst {\n benchmarkUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = true,\n\n durationsSAB,\n controlSAB,\n}: WorkerOptions = workerData;\n\nconst serialize = (code?: string) => (code ? code : '() => {}');\n\nconst resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;\nconst benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;\nconst requireFrom = createRequire(fileURLToPath(new URL('benchmark.js', benchmarkDirUrl)));\n\nconst resolveSpecifier = (specifier: string) => {\n if (specifier.startsWith('file:')) {\n return specifier;\n }\n if (specifier.startsWith('./') || specifier.startsWith('../')) {\n return new URL(specifier, benchmarkDirUrl).href;\n }\n if (isAbsolute(specifier)) {\n return pathToFileURL(specifier).href;\n }\n return requireFrom.resolve(specifier);\n};\n\nconst source = `\nexport const setup = ${serialize(setupCode)};\nexport const teardown = ${serialize(teardownCode)};\nexport const pre = ${serialize(preCode)};\nexport const run = ${serialize(runCode)};\nexport const post = ${serialize(postCode)};\n `;\n\nconst context = createContext({ console, Buffer });\nconst imports = new Map<string, SyntheticModule>();\n\nconst createSyntheticModule = (moduleExports: unknown, exportNames: string[], identifier: string) => {\n const mod = new SyntheticModule(\n exportNames,\n () => {\n for (const name of exportNames) {\n if (name === 'default') {\n mod.setExport(name, moduleExports);\n continue;\n }\n mod.setExport(name, (moduleExports as Record<string, unknown>)[name]);\n }\n },\n { identifier, context },\n );\n return mod;\n};\n\nconst isCjsModule = (target: string) => target.endsWith('.cjs') || target.endsWith('.cts');\n\nconst toRequireTarget = (target: string) => (target.startsWith('file:') ? fileURLToPath(target) : target);\n\nconst loadModule = async (target: string) => {\n const cached = imports.get(target);\n if (cached) return cached;\n\n if (isCjsModule(target)) {\n const required = requireFrom(toRequireTarget(target));\n const exportNames = required && (typeof required === 'object' || typeof required === 'function') ? Object.keys(required) : [];\n if (!exportNames.includes('default')) {\n exportNames.push('default');\n }\n const mod = createSyntheticModule(required, exportNames, target);\n imports.set(target, mod);\n return mod;\n }\n\n const importedModule = await import(target);\n const exportNames = Object.keys(importedModule);\n const mod = createSyntheticModule(importedModule, exportNames, target);\n imports.set(target, mod);\n return mod;\n};\n\nconst loadDynamicModule = async (target: string) => {\n const mod = await loadModule(target);\n if (mod.status !== 'evaluated') {\n await mod.evaluate();\n }\n return mod;\n};\nconst mod = new SourceTextModule(source, {\n identifier: resolvedBenchmarkUrl,\n context,\n initializeImportMeta(meta) {\n meta.url = resolvedBenchmarkUrl;\n },\n importModuleDynamically(specifier) {\n const resolved = resolveSpecifier(specifier);\n return loadDynamicModule(resolved);\n },\n});\n\nawait mod.link(async (specifier) => loadModule(resolveSpecifier(specifier)));\n\nawait mod.evaluate();\nconst { setup, teardown, pre, run, post } = mod.namespace as any;\n\nif (!run) {\n throw new Error('Benchmark run function is required');\n}\n\nprocess.exitCode = await benchmark({\n setup,\n teardown,\n pre,\n run,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n\n durationsSAB,\n controlSAB,\n});\n"],"names":["workerData","SourceTextModule","SyntheticModule","createContext","createRequire","isAbsolute","fileURLToPath","pathToFileURL","benchmark","benchmarkUrl","setupCode","teardownCode","preCode","runCode","postCode","data","warmupCycles","minCycles","absThreshold","relThreshold","gcObserver","durationsSAB","controlSAB","serialize","code","resolvedBenchmarkUrl","process","cwd","href","benchmarkDirUrl","URL","requireFrom","resolveSpecifier","specifier","startsWith","resolve","source","context","console","Buffer","imports","Map","createSyntheticModule","moduleExports","exportNames","identifier","mod","name","setExport","isCjsModule","target","endsWith","toRequireTarget","loadModule","cached","get","required","Object","keys","includes","push","set","importedModule","loadDynamicModule","status","evaluate","initializeImportMeta","meta","url","importModuleDynamically","resolved","link","setup","teardown","pre","run","post","namespace","Error","exitCode"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overtake",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "NodeJS performance benchmark",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
@@ -47,15 +47,15 @@
47
47
  "@types/jest": "^30.0.0",
48
48
  "@types/node": "^25.0.3",
49
49
  "husky": "^9.1.7",
50
- "inop": "^0.8.3",
50
+ "inop": "^0.8.10",
51
51
  "jest": "^30.2.0",
52
- "overtake": "^1.1.0",
52
+ "overtake": "^1.1.1",
53
53
  "prettier": "^3.7.4",
54
54
  "pretty-quick": "^4.2.2",
55
55
  "typescript": "^5.9.3"
56
56
  },
57
57
  "dependencies": {
58
- "@swc/core": "^1.15.7",
58
+ "@swc/core": "^1.15.8",
59
59
  "async": "^3.2.6",
60
60
  "commander": "^14.0.2",
61
61
  "glob": "^13.0.0"
package/src/cli.ts CHANGED
@@ -10,6 +10,7 @@ import { REPORT_TYPES } from './types.js';
10
10
 
11
11
  const require = createRequire(import.meta.url);
12
12
  const { name, description, version } = require('../package.json');
13
+ const BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');
13
14
 
14
15
  const commander = new Command();
15
16
 
@@ -97,8 +98,8 @@ commander
97
98
  if (instance) {
98
99
  const reports = await instance.execute({
99
100
  ...executeOptions,
100
- baseUrl: identifier,
101
- });
101
+ [BENCHMARK_URL]: identifier,
102
+ } as typeof executeOptions);
102
103
  switch (executeOptions.format) {
103
104
  case 'json':
104
105
  {
package/src/executor.ts CHANGED
@@ -9,23 +9,18 @@ import { RunOptions, ReportOptions, WorkerOptions, BenchmarkOptions, Control, Re
9
9
  export type ExecutorReport<R extends ReportTypeList> = Record<R[number], Report> & { count: number };
10
10
 
11
11
  export interface ExecutorOptions<R extends ReportTypeList> extends BenchmarkOptions, ReportOptions<R> {
12
- baseUrl?: string;
13
12
  workers?: number;
14
13
  maxCycles?: number;
15
14
  }
16
15
 
17
- export const createExecutor = <TContext, TInput, R extends ReportTypeList>({
18
- baseUrl = pathToFileURL(process.cwd()).href,
19
- workers,
20
- warmupCycles,
21
- maxCycles,
22
- minCycles,
23
- absThreshold,
24
- relThreshold,
25
- gcObserver = true,
26
- reportTypes,
27
- }: Required<ExecutorOptions<R>>) => {
28
- const executor = queue<RunOptions<TContext, TInput>>(async ({ baseUrl: runBaseUrl = baseUrl, setup, teardown, pre, run, post, data }) => {
16
+ const BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');
17
+
18
+ export const createExecutor = <TContext, TInput, R extends ReportTypeList>(options: Required<ExecutorOptions<R>>) => {
19
+ const { workers, warmupCycles, maxCycles, minCycles, absThreshold, relThreshold, gcObserver = true, reportTypes } = options;
20
+ const benchmarkUrl = (options as Record<symbol, unknown>)[BENCHMARK_URL];
21
+ const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;
22
+
23
+ const executor = queue<RunOptions<TContext, TInput>>(async ({ setup, teardown, pre, run, post, data }) => {
29
24
  const setupCode = setup?.toString();
30
25
  const teardownCode = teardown?.toString();
31
26
  const preCode = pre?.toString();
@@ -37,7 +32,7 @@ export const createExecutor = <TContext, TInput, R extends ReportTypeList>({
37
32
 
38
33
  const workerFile = new URL('./worker.js', import.meta.url);
39
34
  const workerData: WorkerOptions = {
40
- baseUrl: runBaseUrl,
35
+ benchmarkUrl: resolvedBenchmarkUrl,
41
36
  setupCode,
42
37
  teardownCode,
43
38
  preCode,
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { cpus } from 'node:os';
2
- import { pathToFileURL } from 'node:url';
3
2
  import { createExecutor, ExecutorOptions, ExecutorReport } from './executor.js';
4
3
  import { MaybePromise, StepFn, SetupFn, TeardownFn, FeedFn, ReportType, ReportTypeList, DEFAULT_CYCLES } from './types.js';
5
4
 
@@ -10,6 +9,7 @@ declare global {
10
9
  export const DEFAULT_WORKERS = cpus().length;
11
10
 
12
11
  export const AsyncFunction = (async () => {}).constructor;
12
+ const BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');
13
13
 
14
14
  export interface TargetReport<R extends ReportTypeList> {
15
15
  target: string;
@@ -135,29 +135,24 @@ export class Benchmark<TInput> {
135
135
  return new Target<TContext, TInput>(target);
136
136
  }
137
137
 
138
- async execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>({
139
- workers = DEFAULT_WORKERS,
140
- warmupCycles = 20,
141
- maxCycles = DEFAULT_CYCLES,
142
- minCycles = 50,
143
- absThreshold = 1_000,
144
- relThreshold = 0.02,
145
- gcObserver = true,
146
- reportTypes = DEFAULT_REPORT_TYPES as unknown as R,
147
- baseUrl,
148
- }: ExecutorOptions<R>): Promise<TargetReport<R>[]> {
138
+ async execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>(options: ExecutorOptions<R>): Promise<TargetReport<R>[]> {
139
+ const {
140
+ workers = DEFAULT_WORKERS,
141
+ warmupCycles = 20,
142
+ maxCycles = DEFAULT_CYCLES,
143
+ minCycles = 50,
144
+ absThreshold = 1_000,
145
+ relThreshold = 0.02,
146
+ gcObserver = true,
147
+ reportTypes = DEFAULT_REPORT_TYPES as unknown as R,
148
+ } = options;
149
149
  if (this.#executed) {
150
150
  throw new Error("Benchmark is executed and can't be reused");
151
151
  }
152
152
  this.#executed = true;
153
-
154
- const resolvedBaseUrl = baseUrl ?? pathToFileURL(process.cwd()).href;
155
- if (!baseUrl) {
156
- console.warn("Overtake: baseUrl not provided; defaulting to process.cwd(). Pass the benchmark's import.meta.url so relative imports resolve correctly.");
157
- }
153
+ const benchmarkUrl = (options as unknown as Record<symbol, unknown>)[BENCHMARK_URL];
158
154
 
159
155
  const executor = createExecutor<unknown, TInput, R>({
160
- baseUrl: resolvedBaseUrl,
161
156
  workers,
162
157
  warmupCycles,
163
158
  maxCycles,
@@ -166,7 +161,8 @@ export class Benchmark<TInput> {
166
161
  relThreshold,
167
162
  gcObserver,
168
163
  reportTypes,
169
- });
164
+ [BENCHMARK_URL]: benchmarkUrl,
165
+ } as Required<ExecutorOptions<R>>);
170
166
 
171
167
  const reports: TargetReport<R>[] = [];
172
168
  for (const target of this.#targets) {
@@ -177,7 +173,6 @@ export class Benchmark<TInput> {
177
173
  const data = await feed.fn?.();
178
174
  executor
179
175
  .push<ExecutorReport<R>>({
180
- baseUrl: resolvedBaseUrl,
181
176
  setup: target.setup,
182
177
  teardown: target.teardown,
183
178
  pre: measure.pre,
package/src/types.ts CHANGED
@@ -34,11 +34,9 @@ export interface BenchmarkOptions {
34
34
  absThreshold?: number; // ns
35
35
  relThreshold?: number; // %
36
36
  gcObserver?: boolean;
37
- baseUrl?: string;
38
37
  }
39
38
 
40
39
  export interface RunOptions<TContext, TInput> {
41
- baseUrl?: string;
42
40
  setup?: SetupFn<TContext>;
43
41
  teardown?: TeardownFn<TContext>;
44
42
  pre?: StepFn<TContext, TInput>;
@@ -48,7 +46,7 @@ export interface RunOptions<TContext, TInput> {
48
46
  }
49
47
 
50
48
  export interface WorkerOptions extends Required<BenchmarkOptions> {
51
- baseUrl: string;
49
+ benchmarkUrl?: string;
52
50
  setupCode?: string;
53
51
  teardownCode?: string;
54
52
  preCode?: string;