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, 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 } } 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' }) diff --git a/src/template/index.js b/src/template/index.js index b8764c8..99d52ac 100644 --- a/src/template/index.js +++ b/src/template/index.js @@ -2,23 +2,23 @@ const SERIALIZE_ERROR = require('./serialize-error') -module.exports = snippet => ` - 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) + } } - } - ;(async (send) => { - process.stdout.write = function () {} let value let isFulfilled - try { value = await (${snippet.toString()})(...args) isFulfilled = true @@ -26,11 +26,8 @@ module.exports = snippet => ` value = ${SERIALIZE_ERROR}(error) isFulfilled = false } finally { - send(JSON.stringify({ - isFulfilled, - logging, - value, - profiling: { memory: process.memoryUsage().rss } - })) + respond(isFulfilled, value, logging) } - })(process.stdout.write.bind(process.stdout))` + }) + .catch(e => respond(false, ${SERIALIZE_ERROR}(e))) +})(process.stdout.write.bind(process.stdout))`