overtake 1.3.2 → 1.4.0

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.
@@ -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 { 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 : 'undefined');\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 globals = Object.create(null);\nfor (const k of Object.getOwnPropertyNames(globalThis)) {\n globals[k] = (globalThis as any)[k];\n}\nconst context = createContext(globals);\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","globals","Object","create","k","getOwnPropertyNames","globalThis","context","createContext","imports","Map","createSyntheticModule","moduleExports","exportNames","identifier","mod","SyntheticModule","name","setExport","isCjsModule","target","endsWith","toRequireTarget","loadModule","cached","get","required","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":"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"}
1
+ {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule } 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 : 'undefined');\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 try {\n return requireFrom.resolve(specifier);\n } catch {\n return specifier;\n }\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 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 },\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 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","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":"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"}
package/build/worker.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { workerData } from 'node:worker_threads';
2
- import { SourceTextModule, SyntheticModule, createContext } from 'node:vm';
2
+ import { SourceTextModule, SyntheticModule } from 'node:vm';
3
3
  import { createRequire } from 'node:module';
4
4
  import { isAbsolute } from 'node:path';
5
5
  import { fileURLToPath, pathToFileURL } from 'node:url';
@@ -19,7 +19,11 @@ const resolveSpecifier = (specifier)=>{
19
19
  if (isAbsolute(specifier)) {
20
20
  return pathToFileURL(specifier).href;
21
21
  }
22
- return requireFrom.resolve(specifier);
22
+ try {
23
+ return requireFrom.resolve(specifier);
24
+ } catch {
25
+ return specifier;
26
+ }
23
27
  };
24
28
  const source = `
25
29
  export const setup = ${serialize(setupCode)};
@@ -28,11 +32,6 @@ export const pre = ${serialize(preCode)};
28
32
  export const run = ${serialize(runCode)};
29
33
  export const post = ${serialize(postCode)};
30
34
  `;
31
- const globals = Object.create(null);
32
- for (const k of Object.getOwnPropertyNames(globalThis)){
33
- globals[k] = globalThis[k];
34
- }
35
- const context = createContext(globals);
36
35
  const imports = new Map();
37
36
  const createSyntheticModule = (moduleExports, exportNames, identifier)=>{
38
37
  const mod = new SyntheticModule(exportNames, ()=>{
@@ -44,8 +43,7 @@ const createSyntheticModule = (moduleExports, exportNames, identifier)=>{
44
43
  mod.setExport(name, moduleExports[name]);
45
44
  }
46
45
  }, {
47
- identifier,
48
- context
46
+ identifier
49
47
  });
50
48
  return mod;
51
49
  };
@@ -79,7 +77,6 @@ const loadDynamicModule = async (target)=>{
79
77
  };
80
78
  const mod = new SourceTextModule(source, {
81
79
  identifier: resolvedBenchmarkUrl,
82
- context,
83
80
  initializeImportMeta (meta) {
84
81
  meta.url = resolvedBenchmarkUrl;
85
82
  },
@@ -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 { 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 : 'undefined');\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 globals = Object.create(null);\nfor (const k of Object.getOwnPropertyNames(globalThis)) {\n globals[k] = (globalThis as any)[k];\n}\nconst context = createContext(globals);\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","globals","Object","create","k","getOwnPropertyNames","globalThis","context","imports","Map","createSyntheticModule","moduleExports","exportNames","identifier","mod","name","setExport","isCjsModule","target","endsWith","toRequireTarget","loadModule","cached","get","required","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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"}
1
+ {"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule } 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 : 'undefined');\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 try {\n return requireFrom.resolve(specifier);\n } catch {\n return specifier;\n }\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 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 },\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 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","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","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.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "NodeJS performance benchmark",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
@@ -0,0 +1,134 @@
1
+ import { assertNoClosure } from '../utils.js';
2
+
3
+ describe('assertNoClosure', () => {
4
+ describe('allows functions without closures', () => {
5
+ test('arrow with params only', () => {
6
+ expect(() => assertNoClosure('(x) => x * 2', 'run')).not.toThrow();
7
+ });
8
+
9
+ test('arrow with local variables', () => {
10
+ expect(() => assertNoClosure('(ctx, input) => { const y = ctx.value + input; return y; }', 'run')).not.toThrow();
11
+ });
12
+
13
+ test('function expression', () => {
14
+ expect(() => assertNoClosure('function(x) { return x + 1; }', 'run')).not.toThrow();
15
+ });
16
+
17
+ test('named function expression', () => {
18
+ expect(() => assertNoClosure('function run(x) { return x + 1; }', 'run')).not.toThrow();
19
+ });
20
+
21
+ test('async arrow', () => {
22
+ expect(() => assertNoClosure('async (ctx) => { const r = await fetch("url"); return r; }', 'run')).not.toThrow();
23
+ });
24
+
25
+ test('destructured params', () => {
26
+ expect(() => assertNoClosure('({a, b: c}, [d, ...e]) => a + c + d + e.length', 'run')).not.toThrow();
27
+ });
28
+
29
+ test('nested function declaration', () => {
30
+ expect(() => assertNoClosure('(arr) => { function helper(x) { return x * 2; } return arr.map(helper); }', 'run')).not.toThrow();
31
+ });
32
+
33
+ test('for-of loop variable', () => {
34
+ expect(() => assertNoClosure('(arr) => { let sum = 0; for (const x of arr) sum += x; return sum; }', 'run')).not.toThrow();
35
+ });
36
+
37
+ test('member access on params', () => {
38
+ expect(() => assertNoClosure('(ctx) => ctx.data.map(x => x.value)', 'run')).not.toThrow();
39
+ });
40
+
41
+ test('globals like console, Buffer, Math, Array', () => {
42
+ expect(() => assertNoClosure('(ctx) => { console.log(Math.max(...ctx)); return Buffer.from(Array.of(1)); }', 'run')).not.toThrow();
43
+ });
44
+
45
+ test('try-catch with error binding', () => {
46
+ expect(() => assertNoClosure('(ctx) => { try { return ctx(); } catch (e) { return e; } }', 'run')).not.toThrow();
47
+ });
48
+
49
+ test('class expression', () => {
50
+ expect(() => assertNoClosure('() => { class Foo { bar() { return 1; } } return new Foo(); }', 'run')).not.toThrow();
51
+ });
52
+
53
+ test('label statements', () => {
54
+ expect(() => assertNoClosure('() => { outer: for (let i = 0; i < 10; i++) { break outer; } }', 'run')).not.toThrow();
55
+ });
56
+ });
57
+
58
+ describe('detects closures', () => {
59
+ test('single closed-over variable', () => {
60
+ expect(() => assertNoClosure('(x) => x + closedOver', 'run')).toThrow(/closedOver/);
61
+ });
62
+
63
+ test('multiple closed-over variables', () => {
64
+ expect(() => {
65
+ assertNoClosure('(ctx) => sharedData.filter(x => x > threshold)', 'run');
66
+ }).toThrow(/sharedData/);
67
+ });
68
+
69
+ test('closed-over function call', () => {
70
+ expect(() => assertNoClosure('(ctx) => helper(ctx)', 'run')).toThrow(/helper/);
71
+ });
72
+
73
+ test('closed-over array', () => {
74
+ expect(() => assertNoClosure('() => myArray.map(x => x * 2)', 'run')).toThrow(/myArray/);
75
+ });
76
+
77
+ test('computed member access with outer variable', () => {
78
+ expect(() => assertNoClosure('(obj) => obj[key]', 'run')).toThrow(/key/);
79
+ });
80
+
81
+ test('variable used as argument', () => {
82
+ expect(() => assertNoClosure('() => JSON.stringify(config)', 'run')).toThrow(/config/);
83
+ });
84
+
85
+ test('variable in template literal', () => {
86
+ expect(() => assertNoClosure('() => `${prefix}-value`', 'run')).toThrow(/prefix/);
87
+ });
88
+ });
89
+
90
+ describe('error message', () => {
91
+ test('includes the function name', () => {
92
+ expect(() => assertNoClosure('() => x', 'setup')).toThrow(/"setup"/);
93
+ expect(() => assertNoClosure('() => x', 'run')).toThrow(/"run"/);
94
+ expect(() => assertNoClosure('() => x', 'teardown')).toThrow(/"teardown"/);
95
+ });
96
+
97
+ test('lists all closed-over variables', () => {
98
+ try {
99
+ assertNoClosure('() => a + b + c', 'run');
100
+ expect.unreachable('should have thrown');
101
+ } catch (e) {
102
+ expect(e.message).toMatch(/\ba\b/);
103
+ expect(e.message).toMatch(/\bb\b/);
104
+ expect(e.message).toMatch(/\bc\b/);
105
+ }
106
+ });
107
+
108
+ test('explains the problem and suggests fix', () => {
109
+ try {
110
+ assertNoClosure('() => x', 'run');
111
+ expect.unreachable('should have thrown');
112
+ } catch (e) {
113
+ expect(e.message).toContain('.toString()');
114
+ expect(e.message).toContain('worker');
115
+ expect(e.message).toContain('setup');
116
+ expect(e.message).toContain('data');
117
+ }
118
+ });
119
+ });
120
+
121
+ describe('edge cases', () => {
122
+ test('silently passes on unparseable code', () => {
123
+ expect(() => assertNoClosure('not valid js {{{', 'run')).not.toThrow();
124
+ });
125
+
126
+ test('empty arrow function', () => {
127
+ expect(() => assertNoClosure('() => {}', 'run')).not.toThrow();
128
+ });
129
+
130
+ test('undefined return', () => {
131
+ expect(() => assertNoClosure('() => undefined', 'run')).not.toThrow();
132
+ });
133
+ });
134
+ });
package/src/executor.ts CHANGED
@@ -3,7 +3,7 @@ import { once } from 'node:events';
3
3
  import { queue } from 'async';
4
4
  import { pathToFileURL } from 'node:url';
5
5
  import { createReport, Report } from './reporter.js';
6
- import { cmp } from './utils.js';
6
+ import { cmp, assertNoClosure } from './utils.js';
7
7
  import {
8
8
  ExecutorRunOptions,
9
9
  ReportOptions,
@@ -21,6 +21,7 @@ export type ExecutorReport<R extends ReportTypeList> = Record<R[number], Report>
21
21
  count: number;
22
22
  heapUsedKB: number;
23
23
  dceWarning: boolean;
24
+ error?: string;
24
25
  };
25
26
 
26
27
  export interface ExecutorOptions<R extends ReportTypeList> extends BenchmarkOptions, ReportOptions<R> {
@@ -44,6 +45,12 @@ export const createExecutor = <TContext, TInput, R extends ReportTypeList>(optio
44
45
  const runCode = run.toString()!;
45
46
  const postCode = post?.toString();
46
47
 
48
+ if (setupCode) assertNoClosure(setupCode, 'setup');
49
+ if (teardownCode) assertNoClosure(teardownCode, 'teardown');
50
+ if (preCode) assertNoClosure(preCode, 'pre');
51
+ assertNoClosure(runCode, 'run');
52
+ if (postCode) assertNoClosure(postCode, 'post');
53
+
47
54
  const controlSAB = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * CONTROL_SLOTS);
48
55
  const durationsSAB = new SharedArrayBuffer(BigUint64Array.BYTES_PER_ELEMENT * maxCycles);
49
56
 
@@ -83,17 +90,18 @@ export const createExecutor = <TContext, TInput, R extends ReportTypeList>(optio
83
90
  const WORKER_TIMEOUT_MS = 300_000;
84
91
  const exitPromise = once(worker, 'exit');
85
92
  const timeoutId = setTimeout(() => worker.terminate(), WORKER_TIMEOUT_MS);
93
+ let workerError: string | undefined;
86
94
  try {
87
95
  const [exitCode] = await exitPromise;
88
96
  clearTimeout(timeoutId);
89
97
  if (progressIntervalId) clearInterval(progressIntervalId);
90
98
  if (exitCode !== 0) {
91
- throw new Error(`worker exited with code ${exitCode}`);
99
+ workerError = `worker exited with code ${exitCode}`;
92
100
  }
93
101
  } catch (err) {
94
102
  clearTimeout(timeoutId);
95
103
  if (progressIntervalId) clearInterval(progressIntervalId);
96
- throw err;
104
+ workerError = err instanceof Error ? err.message : String(err);
97
105
  }
98
106
 
99
107
  const count = control[Control.INDEX];
@@ -118,13 +126,10 @@ export const createExecutor = <TContext, TInput, R extends ReportTypeList>(optio
118
126
  ['count', count],
119
127
  ['heapUsedKB', heapUsedKB],
120
128
  ['dceWarning', dceWarning],
129
+ ['error', workerError],
121
130
  ]);
122
131
  return Object.fromEntries(report);
123
132
  }, workers);
124
133
 
125
- executor.error((err) => {
126
- console.error(err);
127
- });
128
-
129
134
  return executor;
130
135
  };
package/src/index.ts CHANGED
@@ -7,7 +7,7 @@ declare global {
7
7
  const benchmark: typeof Benchmark.create;
8
8
  }
9
9
 
10
- export const DEFAULT_WORKERS = cpus().length;
10
+ export const DEFAULT_WORKERS = Math.max(1, Math.ceil(cpus().length / 4));
11
11
 
12
12
  export const AsyncFunction = (async () => {}).constructor;
13
13
  const BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');
@@ -240,7 +240,11 @@ export const printSimpleReports = <R extends ReportTypeList>(reports: TargetRepo
240
240
  for (const { measure, feeds } of report.measures) {
241
241
  console.group('\n', report.target, measure);
242
242
  for (const { feed, data } of feeds) {
243
- const { count, heapUsedKB, dceWarning, ...metrics } = data as Record<string, unknown>;
243
+ const { count, heapUsedKB, dceWarning, error: benchError, ...metrics } = data as Record<string, unknown>;
244
+ if (benchError) {
245
+ console.log(feed, `\x1b[31m[error: ${benchError}]\x1b[0m`);
246
+ continue;
247
+ }
244
248
  const output = Object.entries(metrics)
245
249
  .map(([key, report]) => `${key}: ${(report as { toString(): string }).toString()}`)
246
250
  .join('; ');
@@ -261,7 +265,12 @@ export const printTableReports = <R extends ReportTypeList>(reports: TargetRepor
261
265
  console.log('\n', report.target, measure);
262
266
  const table: Record<string, unknown> = {};
263
267
  for (const { feed, data } of feeds) {
264
- table[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));
268
+ const { error: benchError } = data as Record<string, unknown>;
269
+ if (benchError) {
270
+ table[feed] = { error: benchError };
271
+ } else {
272
+ table[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));
273
+ }
265
274
  }
266
275
  console.table(table);
267
276
  }
@@ -274,7 +283,12 @@ export const printJSONReports = <R extends ReportTypeList>(reports: TargetReport
274
283
  for (const { measure, feeds } of report.measures) {
275
284
  const row = {} as Record<string, Record<string, string>>;
276
285
  for (const { feed, data } of feeds) {
277
- row[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));
286
+ const { error: benchError } = data as Record<string, unknown>;
287
+ if (benchError) {
288
+ row[feed] = { error: String(benchError) };
289
+ } else {
290
+ row[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));
291
+ }
278
292
  }
279
293
  output[`${report.target} ${measure}`] = row;
280
294
  }
@@ -288,7 +302,14 @@ export const printMarkdownReports = <R extends ReportTypeList>(reports: TargetRe
288
302
  console.log(`\n## ${report.target} - ${measure}\n`);
289
303
  if (feeds.length === 0) continue;
290
304
 
291
- const keys = Object.keys(feeds[0].data).filter((k) => k !== 'count');
305
+ const firstValid = feeds.find((f) => !(f.data as Record<string, unknown>).error);
306
+ if (!firstValid) {
307
+ for (const { feed, data } of feeds) {
308
+ console.log(`| ${feed} | error: ${(data as Record<string, unknown>).error} |`);
309
+ }
310
+ continue;
311
+ }
312
+ const keys = Object.keys(firstValid.data).filter((k) => k !== 'count' && k !== 'error');
292
313
  const header = ['Feed', ...keys].join(' | ');
293
314
  const separator = ['---', ...keys.map(() => '---')].join(' | ');
294
315
 
@@ -296,6 +317,10 @@ export const printMarkdownReports = <R extends ReportTypeList>(reports: TargetRe
296
317
  console.log(`| ${separator} |`);
297
318
 
298
319
  for (const { feed, data } of feeds) {
320
+ if ((data as Record<string, unknown>).error) {
321
+ console.log(`| ${feed} | error: ${(data as Record<string, unknown>).error} |`);
322
+ continue;
323
+ }
299
324
  const values = keys.map((k) => (data as Record<string, { toString(): string }>)[k]?.toString() ?? '-');
300
325
  console.log(`| ${[feed, ...values].join(' | ')} |`);
301
326
  }
@@ -309,18 +334,26 @@ export const printHistogramReports = <R extends ReportTypeList>(reports: TargetR
309
334
  console.log(`\n${report.target} - ${measure}\n`);
310
335
 
311
336
  const opsKey = 'ops';
312
- const values = feeds.map((f) => ({
313
- feed: f.feed,
314
- value: (f.data as Record<string, { valueOf(): number }>)[opsKey]?.valueOf() ?? 0,
315
- }));
337
+ const values = feeds.map((f) => {
338
+ const { error: benchError } = f.data as Record<string, unknown>;
339
+ return {
340
+ feed: f.feed,
341
+ value: benchError ? 0 : ((f.data as Record<string, { valueOf(): number }>)[opsKey]?.valueOf() ?? 0),
342
+ error: benchError as string | undefined,
343
+ };
344
+ });
316
345
 
317
346
  const maxValue = Math.max(...values.map((v) => v.value));
318
347
  const maxLabelLen = Math.max(...values.map((v) => v.feed.length));
319
348
 
320
- for (const { feed, value } of values) {
349
+ for (const { feed, value, error } of values) {
350
+ const label = feed.padEnd(maxLabelLen);
351
+ if (error) {
352
+ console.log(` ${label} | \x1b[31m[error: ${error}]\x1b[0m`);
353
+ continue;
354
+ }
321
355
  const barLen = maxValue > 0 ? Math.round((value / maxValue) * width) : 0;
322
356
  const bar = '\u2588'.repeat(barLen);
323
- const label = feed.padEnd(maxLabelLen);
324
357
  const formatted = value.toLocaleString('en-US', { maximumFractionDigits: 2 });
325
358
  console.log(` ${label} | ${bar} ${formatted} ops/s`);
326
359
  }
@@ -339,6 +372,7 @@ export const reportsToBaseline = <R extends ReportTypeList>(reports: TargetRepor
339
372
  for (const report of reports) {
340
373
  for (const { measure, feeds } of report.measures) {
341
374
  for (const { feed, data } of feeds) {
375
+ if ((data as Record<string, unknown>).error) continue;
342
376
  const key = `${report.target}/${measure}/${feed}`;
343
377
  results[key] = {};
344
378
  for (const [metric, value] of Object.entries(data)) {
@@ -367,6 +401,11 @@ export const printComparisonReports = <R extends ReportTypeList>(reports: Target
367
401
 
368
402
  console.log(` ${feed}:`);
369
403
 
404
+ if ((data as Record<string, unknown>).error) {
405
+ console.log(` \x1b[31m[error: ${(data as Record<string, unknown>).error}]\x1b[0m`);
406
+ continue;
407
+ }
408
+
370
409
  for (const [metric, value] of Object.entries(data)) {
371
410
  if (metric === 'count') continue;
372
411
  const current = (value as { valueOf(): number }).valueOf();