From 52f4e2600f5a0ec75c50a3f301c33ff87d1af4f0 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 10:13:38 +0200 Subject: [PATCH 1/9] chore: debug --- package.json | 2 +- src/index.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a212641..9bb8387 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "release": "standard-version -a", "release:github": "github-generate-release", "release:tags": "git push --follow-tags origin HEAD:master", - "test": "c8 ava" + "test": "c8 ava --fail-fast" }, "license": "MIT", "ava": { diff --git a/src/index.js b/src/index.js index 1de16f2..3371b83 100644 --- a/src/index.js +++ b/src/index.js @@ -61,6 +61,9 @@ module.exports = (snippet, { tmpdir, timeout, memory, throwError = true, allow = })() : { isFulfilled: false, value: deserializeError(value), profiling, logging } } catch (error) { + console.log('=========== DEBUG ===========') + console.log('args', JSON.stringify(args)) + console.log(error) if (error.signalCode === 'SIGTRAP') { throw createError({ name: 'MemoryError', From d2312546015d90fc0b0216a9fd646da7fda3122d Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 10:37:12 +0200 Subject: [PATCH 2/9] fix: ensure to wait --- src/template/index.js | 54 ++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/template/index.js b/src/template/index.js index b8764c8..f32ff4a 100644 --- a/src/template/index.js +++ b/src/template/index.js @@ -3,34 +3,36 @@ const SERIALIZE_ERROR = require('./serialize-error') module.exports = snippet => ` - const args = JSON.parse(process.argv[2]) + ;(async () => { + const args = JSON.parse(process.argv[2]) - /* https://github.com/Kikobeats/null-prototype-object */ - const logging = new (/* @__PURE__ */ (() => { let e = function(){}; return e.prototype = Object.create(null), Object.freeze(e.prototype), e })()); + /* https://github.com/Kikobeats/null-prototype-object */ + const logging = new (/* @__PURE__ */ (() => { let e = function(){}; return e.prototype = Object.create(null), Object.freeze(e.prototype), e })()); - for (const method of ['log', 'info', 'debug', 'warn', 'error']) { - console[method] = function (...args) { - logging[method] === undefined ? logging[method] = [args] : logging[method].push(args) + for (const method of ['log', 'info', 'debug', 'warn', 'error']) { + console[method] = function (...args) { + logging[method] === undefined ? logging[method] = [args] : logging[method].push(args) + } } - } - ;(async (send) => { - process.stdout.write = function () {} - let value - let isFulfilled + ;await (async (send) => { + process.stdout.write = function () {} + let value + let isFulfilled - try { - value = await (${snippet.toString()})(...args) - isFulfilled = true - } catch (error) { - value = ${SERIALIZE_ERROR}(error) - isFulfilled = false - } finally { - send(JSON.stringify({ - isFulfilled, - logging, - value, - profiling: { memory: process.memoryUsage().rss } - })) - } - })(process.stdout.write.bind(process.stdout))` + try { + value = await (${snippet.toString()})(...args) + isFulfilled = true + } catch (error) { + value = ${SERIALIZE_ERROR}(error) + isFulfilled = false + } finally { + send(JSON.stringify({ + isFulfilled, + logging, + value, + profiling: { memory: process.memoryUsage().rss } + })) + } + })(process.stdout.write.bind(process.stdout)) + })()` From f51ad55811dcb4b1d160cf8899e7ffa6448871cb Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 10:43:41 +0200 Subject: [PATCH 3/9] chore: remove debug logs --- package.json | 2 +- src/index.js | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index 9bb8387..a212641 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "release": "standard-version -a", "release:github": "github-generate-release", "release:tags": "git push --follow-tags origin HEAD:master", - "test": "c8 ava --fail-fast" + "test": "c8 ava" }, "license": "MIT", "ava": { diff --git a/src/index.js b/src/index.js index 3371b83..1de16f2 100644 --- a/src/index.js +++ b/src/index.js @@ -61,9 +61,6 @@ module.exports = (snippet, { tmpdir, timeout, memory, throwError = true, allow = })() : { isFulfilled: false, value: deserializeError(value), profiling, logging } } catch (error) { - console.log('=========== DEBUG ===========') - console.log('args', JSON.stringify(args)) - console.log(error) if (error.signalCode === 'SIGTRAP') { throw createError({ name: 'MemoryError', From 6d70d2dc818fb4f057ec12521bf9286fec4ed33f Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 11:05:56 +0200 Subject: [PATCH 4/9] fix: minify by default --- src/compile/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile/build.js b/src/compile/build.js index 7db8c8d..f65ac88 100644 --- a/src/compile/build.js +++ b/src/compile/build.js @@ -3,7 +3,7 @@ const esbuild = require('esbuild') const MINIFY = (() => { - return process.env.ISOLATED_FUNCTIONS_MINIFY !== 'false' + return process.env.ISOLATED_FUNCTIONS_MINIFY === 'false' ? {} : { minifyWhitespace: true, From 3caf1c1b51a33bed7339755d48711222444b6c21 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 11:06:18 +0200 Subject: [PATCH 5/9] perf: avoid transformation if no dependencies --- src/compile/index.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/compile/index.js b/src/compile/index.js index 965749f..188cafd 100644 --- a/src/compile/index.js +++ b/src/compile/index.js @@ -4,10 +4,10 @@ const fs = require('fs/promises') const path = require('path') const transformDependencies = require('./transform-dependencies') -const detectDependencies = require('./detect-dependencies') const installDependencies = require('./install-dependencies') -const generateTemplate = require('../template') +const detectDependencies = require('./detect-dependencies') const { duration } = require('../debug') +const template = require('../template') const build = require('./build') const tmpdirDefault = async () => { @@ -18,21 +18,21 @@ const tmpdirDefault = async () => { } module.exports = async (snippet, tmpdir = tmpdirDefault) => { - const compiledTemplate = generateTemplate(snippet) - const dependencies = detectDependencies(compiledTemplate) - let content = transformDependencies(compiledTemplate) - let cleanupPromise + let content = template(snippet) + const { cwd, cleanup } = await duration('tmpdir', tmpdir) + const dependencies = detectDependencies(content) if (dependencies.length) { - const { cwd, cleanup } = await duration('tmpdir', tmpdir) + content = transformDependencies(content) await duration('npm:install', () => installDependencies({ dependencies, cwd }), { dependencies }) - const result = await duration('esbuild', () => build({ content, cwd })) - content = result.outputFiles[0].text - cleanupPromise = duration('tmpDir:cleanup', cleanup) } + const result = await duration('esbuild', () => build({ content, cwd })) + content = result.outputFiles[0].text + const cleanupPromise = duration('tmpDir:cleanup', cleanup) + return { content, cleanupPromise } } From 524612194aed0d0cd14919b13858f94eb9fff307 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 11:06:24 +0200 Subject: [PATCH 6/9] docs: explain --- src/compile/transform-dependencies.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/compile/transform-dependencies.js b/src/compile/transform-dependencies.js index 3ff1e6a..b1f3a74 100644 --- a/src/compile/transform-dependencies.js +++ b/src/compile/transform-dependencies.js @@ -3,6 +3,24 @@ const walk = require('acorn-walk') const acorn = require('acorn') +/** + * Transforms dependency module names by removing version specifiers. + * + * Parses JavaScript code and walks through the AST to find all require() calls + * and import declarations. Extracts module names from strings that include + * version information (e.g., 'is-emoji@1.0.0' becomes 'is-emoji'). + * + * Handles both: + * - Scoped packages: '@scope/package@1.0.0' → '@scope/package' + * - Regular packages: 'package@1.0.0' → 'package' + * + * This transformation is necessary because the dependency strings include + * version specifiers for installation tracking, but require/import statements + * should only reference the base module name. + * + * @param {string} code - JavaScript code containing require() or import statements + * @returns {string} Transformed code with version specifiers removed from dependencies + */ module.exports = code => { const ast = acorn.parse(code, { ecmaVersion: 2023, sourceType: 'module' }) From 318a4bfeee31412f30c8cf95baf65b64dd8a626a Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 11:10:23 +0200 Subject: [PATCH 7/9] chore: debug --- src/index.js | 8 +++++ src/template/index.js | 71 +++++++++++++++++++++++++++---------------- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/index.js b/src/index.js index 1de16f2..86bf20f 100644 --- a/src/index.js +++ b/src/index.js @@ -32,6 +32,7 @@ module.exports = (snippet, { tmpdir, timeout, memory, throwError = true, allow = const fn = async (...args) => { let duration + let _stdout try { const { content, cleanupPromise } = await compilePromise @@ -46,6 +47,7 @@ module.exports = (snippet, { tmpdir, timeout, memory, throwError = true, allow = }) Readable.from(content).pipe(subprocess.stdin) const [{ stdout }] = await Promise.all([subprocess, cleanupPromise]) + _stdout = stdout const { isFulfilled, value, profiling, logging } = JSON.parse(stdout) profiling.duration = duration() debug('node', { @@ -61,6 +63,12 @@ module.exports = (snippet, { tmpdir, timeout, memory, throwError = true, allow = })() : { isFulfilled: false, value: deserializeError(value), profiling, logging } } catch (error) { + console.log('=========== DEBUG ===========') + console.log('error', error) + console.log('args', JSON.stringify(args)) + console.log('_stdout', JSON.stringify(_stdout)) + + console.log('=========== DEBUG ===========') if (error.signalCode === 'SIGTRAP') { throw createError({ name: 'MemoryError', diff --git a/src/template/index.js b/src/template/index.js index f32ff4a..2724cad 100644 --- a/src/template/index.js +++ b/src/template/index.js @@ -4,35 +4,52 @@ const SERIALIZE_ERROR = require('./serialize-error') module.exports = snippet => ` ;(async () => { - const args = JSON.parse(process.argv[2]) + try { + const args = JSON.parse(process.argv[2]) - /* https://github.com/Kikobeats/null-prototype-object */ - const logging = new (/* @__PURE__ */ (() => { let e = function(){}; return e.prototype = Object.create(null), Object.freeze(e.prototype), e })()); + /* https://github.com/Kikobeats/null-prototype-object */ + const logging = new (/* @__PURE__ */ (() => { let e = function(){}; return e.prototype = Object.create(null), Object.freeze(e.prototype), e })()); - for (const method of ['log', 'info', 'debug', 'warn', 'error']) { - console[method] = function (...args) { - logging[method] === undefined ? logging[method] = [args] : logging[method].push(args) + for (const method of ['log', 'info', 'debug', 'warn', 'error']) { + console[method] = function (...args) { + logging[method] === undefined ? logging[method] = [args] : logging[method].push(args) + } } - } - ;await (async (send) => { - process.stdout.write = function () {} - let value - let isFulfilled + ;await (async (send) => { + process.stdout.write = function () {} + let value + let isFulfilled - try { - value = await (${snippet.toString()})(...args) - isFulfilled = true - } catch (error) { - value = ${SERIALIZE_ERROR}(error) - isFulfilled = false - } finally { - send(JSON.stringify({ - isFulfilled, - logging, - value, - profiling: { memory: process.memoryUsage().rss } - })) - } - })(process.stdout.write.bind(process.stdout)) - })()` + try { + value = await (${snippet.toString()})(...args) + isFulfilled = true + } catch (error) { + value = ${SERIALIZE_ERROR}(error) + isFulfilled = false + } finally { + send(JSON.stringify({ + isFulfilled, + logging, + value, + profiling: { memory: process.memoryUsage().rss } + })) + } + })(process.stdout.write.bind(process.stdout)) + } catch (error) { + process.stdout.write(JSON.stringify({ + isFulfilled: false, + logging: {}, + value: ${SERIALIZE_ERROR}(error), + profiling: { memory: process.memoryUsage().rss } + })) + } + })().catch(err => { + process.stdout.write(JSON.stringify({ + isFulfilled: false, + logging: {}, + value: ${SERIALIZE_ERROR}(err), + profiling: { memory: process.memoryUsage().rss } + })) + process.exitCode = 1 + })` From 8b106b7ece811baa1c1bc5dce88abf2f4751a754 Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 11:41:43 +0200 Subject: [PATCH 8/9] refactor: minimal template --- src/template/index.js | 68 +++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 45 deletions(-) diff --git a/src/template/index.js b/src/template/index.js index 2724cad..99d52ac 100644 --- a/src/template/index.js +++ b/src/template/index.js @@ -2,54 +2,32 @@ const SERIALIZE_ERROR = require('./serialize-error') -module.exports = snippet => ` - ;(async () => { - try { - const args = JSON.parse(process.argv[2]) +module.exports = snippet => `;(send => { + process.stdout.write = function () {} + const respond = (isFulfilled, value, logs = {}) => send(JSON.stringify({isFulfilled, logging: logs, value, profiling: {memory: process.memoryUsage().rss}})) - /* https://github.com/Kikobeats/null-prototype-object */ - const logging = new (/* @__PURE__ */ (() => { let e = function(){}; return e.prototype = Object.create(null), Object.freeze(e.prototype), e })()); + return Promise.resolve().then(async () => { + const args = JSON.parse(process.argv[2]) - for (const method of ['log', 'info', 'debug', 'warn', 'error']) { - console[method] = function (...args) { - logging[method] === undefined ? logging[method] = [args] : logging[method].push(args) - } + /* https://github.com/Kikobeats/null-prototype-object */ + const logging = new (/* @__PURE__ */ (() => { let e = function(){}; return e.prototype = Object.create(null), Object.freeze(e.prototype), e })()); + for (const method of ['log', 'info', 'debug', 'warn', 'error']) { + console[method] = function (...args) { + logging[method] === undefined ? logging[method] = [args] : logging[method].push(args) } + } - ;await (async (send) => { - process.stdout.write = function () {} - let value - let isFulfilled - - try { - value = await (${snippet.toString()})(...args) - isFulfilled = true - } catch (error) { - value = ${SERIALIZE_ERROR}(error) - isFulfilled = false - } finally { - send(JSON.stringify({ - isFulfilled, - logging, - value, - profiling: { memory: process.memoryUsage().rss } - })) - } - })(process.stdout.write.bind(process.stdout)) + let value + let isFulfilled + try { + value = await (${snippet.toString()})(...args) + isFulfilled = true } catch (error) { - process.stdout.write(JSON.stringify({ - isFulfilled: false, - logging: {}, - value: ${SERIALIZE_ERROR}(error), - profiling: { memory: process.memoryUsage().rss } - })) + value = ${SERIALIZE_ERROR}(error) + isFulfilled = false + } finally { + respond(isFulfilled, value, logging) } - })().catch(err => { - process.stdout.write(JSON.stringify({ - isFulfilled: false, - logging: {}, - value: ${SERIALIZE_ERROR}(err), - profiling: { memory: process.memoryUsage().rss } - })) - process.exitCode = 1 - })` + }) + .catch(e => respond(false, ${SERIALIZE_ERROR}(e))) +})(process.stdout.write.bind(process.stdout))` From 47ec310744306617a752a0a1fee5d6e0d4357f2b Mon Sep 17 00:00:00 2001 From: Kiko Beats Date: Tue, 21 Oct 2025 11:43:31 +0200 Subject: [PATCH 9/9] chore: remove debug --- src/index.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/index.js b/src/index.js index 86bf20f..1de16f2 100644 --- a/src/index.js +++ b/src/index.js @@ -32,7 +32,6 @@ module.exports = (snippet, { tmpdir, timeout, memory, throwError = true, allow = const fn = async (...args) => { let duration - let _stdout try { const { content, cleanupPromise } = await compilePromise @@ -47,7 +46,6 @@ module.exports = (snippet, { tmpdir, timeout, memory, throwError = true, allow = }) Readable.from(content).pipe(subprocess.stdin) const [{ stdout }] = await Promise.all([subprocess, cleanupPromise]) - _stdout = stdout const { isFulfilled, value, profiling, logging } = JSON.parse(stdout) profiling.duration = duration() debug('node', { @@ -63,12 +61,6 @@ module.exports = (snippet, { tmpdir, timeout, memory, throwError = true, allow = })() : { isFulfilled: false, value: deserializeError(value), profiling, logging } } catch (error) { - console.log('=========== DEBUG ===========') - console.log('error', error) - console.log('args', JSON.stringify(args)) - console.log('_stdout', JSON.stringify(_stdout)) - - console.log('=========== DEBUG ===========') if (error.signalCode === 'SIGTRAP') { throw createError({ name: 'MemoryError',