Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compile/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 10 additions & 10 deletions src/compile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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 }
}

Expand Down
18 changes: 18 additions & 0 deletions src/compile/transform-dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' })

Expand Down
33 changes: 15 additions & 18 deletions src/template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,32 @@

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
} catch (error) {
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))`