48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
import { AsyncLocalStorage } from 'async_hooks'
|
|
|
|
export const fnStorage = new AsyncLocalStorage<{
|
|
fns: Map<string, string>
|
|
counter: number
|
|
}>()
|
|
|
|
export function fe<T extends Record<string, unknown>>(
|
|
fn: (args?: T) => void,
|
|
args?: T
|
|
): string {
|
|
const store = fnStorage.getStore()
|
|
if (!store) {
|
|
// Fallback to IIFE if outside request context
|
|
return args
|
|
? `(${fn.toString()})(${JSON.stringify(args)})`
|
|
: `(${fn.toString()})()`
|
|
}
|
|
|
|
const fnStr = fn.toString()
|
|
|
|
// Dedupe by function body
|
|
for (const [name, body] of store.fns)
|
|
if (body === fnStr)
|
|
return args ? `${name}(${JSON.stringify(args)})` : `${name}()`
|
|
|
|
const name = `frontendFn${store.counter++}`
|
|
store.fns.set(name, fnStr)
|
|
|
|
return args ? `${name}(${JSON.stringify(args)})` : `${name}()`
|
|
}
|
|
|
|
export function feFunctions(): string[] {
|
|
const store = fnStorage.getStore()
|
|
if (!store?.fns.size) return []
|
|
|
|
return [...store.fns.entries()].map(([name, body]) => {
|
|
// Handle arrow functions vs regular functions
|
|
if (body.startsWith('(') || body.startsWith('async ('))
|
|
return `const ${name} = ${body};`
|
|
|
|
// Named function - rename it
|
|
return body.replace(/^(async\s+)?function\s*\w*/, `$1function ${name}`)
|
|
})
|
|
}
|
|
|
|
// Keep for backwards compat
|
|
export const frontend = fe |