import { parse } from "@babel/parser"; const FENCED_CODE_BLOCK = /```(?:[^\n`]*)?\s*\n([\s\S]*?)```/i;const FUNCTION_DECLARATION = /^(?:async\s+)?function(?:\s+([a-zA-Z_$][a-zA-Z0-9_$]*))?\s*\(/;const CALLABLE_ERROR = "Code must evaluate to a function"; const extractCandidateSource = (code: string): string => { const trimmed = code.trim(); if (!trimmed) return ""; const fenced = trimmed.match(FENCED_CODE_BLOCK)?.[1]; return (fenced ?? trimmed).trim();}; const wrapCallableBody = (source: string): string => [ "const __fn = (", source, ");", `if (typeof __fn !== "function") throw new Error(${JSON.stringify(CALLABLE_ERROR)});`, "return await __fn();", ].join("\n"); const wrapNamedFunctionBody = (source: string, name: string): string => [source, `return await ${name}();`].join("\n"); const wrapAnonymousFunctionBody = (source: string): string => `return await (${source})();`; const sliceNode = ( source: string, node: { start?: number | null; end?: number | null; },): string => { const start = node.start ?? 0; const end = node.end ?? source.length; return source.slice(start, end);}; const unwrapExpression = (expression: { type: string; expression?: unknown }): unknown => { switch (expression.type) { case "ParenthesizedExpression": case "TSAsExpression": case "TSSatisfiesExpression": case "TSTypeAssertion": case "TSNonNullExpression": case "TSInstantiationExpression": return expression.expression ? unwrapExpression(expression.expression as { type: string }) : expression; default: return expression; }}; const renderExportDefaultBody = ( source: string, declaration: ExportDefaultDeclarationNode,): string => { if (declaration.type === "FunctionDeclaration") { const fnSource = sliceNode(source, declaration); const name = declaration.id?.name; return name ? wrapNamedFunctionBody(fnSource, name) : wrapAnonymousFunctionBody(fnSource); } const expression = unwrapExpression(declaration) as { type?: string; }; const expressionSource = sliceNode(source, declaration); if (expression?.type === "ArrowFunctionExpression" || expression?.type === "FunctionExpression") { return wrapCallableBody(expressionSource); } return `return (${expressionSource});`;}; type ExportDefaultDeclarationNode = { type: string; start?: number | null; end?: number | null; id?: { name?: string | null } | null; expression?: unknown;}; const renderParsedBody = (source: string): string => { const program = parse(source, { sourceType: "module", allowAwaitOutsideFunction: true, allowReturnOutsideFunction: true, allowImportExportEverywhere: true, plugins: ["typescript"], }).program; if (program.body.length !== 1) return source; const [statement] = program.body; if (!statement) return source; switch (statement.type) { case "ExpressionStatement": { const expression = unwrapExpression( statement.expression as { type: string; expression?: unknown }, ) as { type?: string; }; return expression?.type === "ArrowFunctionExpression" || expression?.type === "FunctionExpression" ? wrapCallableBody(source) : source; } case "FunctionDeclaration": return statement.id?.name ? wrapNamedFunctionBody(source, statement.id.name) : source; case "ExportDefaultDeclaration": return renderExportDefaultBody(source, statement.declaration); default: return source; }}; const renderHeuristicBody = (source: string): string => { const withoutDefaultExport = source.replace(/^export\s+default\s+/, "").trim(); if ( (withoutDefaultExport.startsWith("async") || withoutDefaultExport.startsWith("(")) && withoutDefaultExport.includes("=>") ) { return wrapCallableBody(withoutDefaultExport); } if (FUNCTION_DECLARATION.test(withoutDefaultExport)) { const name = withoutDefaultExport.match(FUNCTION_DECLARATION)?.[1]; return name ? wrapNamedFunctionBody(withoutDefaultExport, name) : wrapAnonymousFunctionBody(withoutDefaultExport); } return withoutDefaultExport;}; export const recoverExecutionBody = (code: string): string => { const source = extractCandidateSource(code); if (!source) return ""; // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: Babel parser throws for malformed candidate code, then recovery falls back to heuristics try { return renderParsedBody(source); } catch { return renderHeuristicBody(source); }};
import { parse } from "@babel/parser";
const FENCED_CODE_BLOCK = /```(?:[^\n`]*)?\s*\n([\s\S]*?)```/i;
const FUNCTION_DECLARATION = /^(?:async\s+)?function(?:\s+([a-zA-Z_$][a-zA-Z0-9_$]*))?\s*\(/;
const CALLABLE_ERROR = "Code must evaluate to a function";
const extractCandidateSource = (code: string): string => {
const trimmed = code.trim();
if (!trimmed) return "";
const fenced = trimmed.match(FENCED_CODE_BLOCK)?.[1];
return (fenced ?? trimmed).trim();
};
const wrapCallableBody = (source: string): string =>
[
"const __fn = (",
source,
");",
`if (typeof __fn !== "function") throw new Error(${JSON.stringify(CALLABLE_ERROR)});`,
"return await __fn();",
].join("\n");
const wrapNamedFunctionBody = (source: string, name: string): string =>
[source, `return await ${name}();`].join("\n");
const wrapAnonymousFunctionBody = (source: string): string => `return await (${source})();`;
const sliceNode = (
source: string,
node: {
start?: number | null;
end?: number | null;
},
): string => {
const start = node.start ?? 0;
const end = node.end ?? source.length;
return source.slice(start, end);
};
const unwrapExpression = (expression: { type: string; expression?: unknown }): unknown => {
switch (expression.type) {
case "ParenthesizedExpression":
case "TSAsExpression":
case "TSSatisfiesExpression":
case "TSTypeAssertion":
case "TSNonNullExpression":
case "TSInstantiationExpression":
return expression.expression
? unwrapExpression(expression.expression as { type: string })
: expression;
default:
return expression;
}
};
const renderExportDefaultBody = (
source: string,
declaration: ExportDefaultDeclarationNode,
): string => {
if (declaration.type === "FunctionDeclaration") {
const fnSource = sliceNode(source, declaration);
const name = declaration.id?.name;
return name ? wrapNamedFunctionBody(fnSource, name) : wrapAnonymousFunctionBody(fnSource);
}
const expression = unwrapExpression(declaration) as {
type?: string;
};
const expressionSource = sliceNode(source, declaration);
if (expression?.type === "ArrowFunctionExpression" || expression?.type === "FunctionExpression") {
return wrapCallableBody(expressionSource);
}
return `return (${expressionSource});`;
};
type ExportDefaultDeclarationNode = {
type: string;
start?: number | null;
end?: number | null;
id?: { name?: string | null } | null;
expression?: unknown;
};
const renderParsedBody = (source: string): string => {
const program = parse(source, {
sourceType: "module",
allowAwaitOutsideFunction: true,
allowReturnOutsideFunction: true,
allowImportExportEverywhere: true,
plugins: ["typescript"],
}).program;
if (program.body.length !== 1) return source;
const [statement] = program.body;
if (!statement) return source;
switch (statement.type) {
case "ExpressionStatement": {
const expression = unwrapExpression(
statement.expression as { type: string; expression?: unknown },
) as {
type?: string;
};
return expression?.type === "ArrowFunctionExpression" ||
expression?.type === "FunctionExpression"
? wrapCallableBody(source)
: source;
}
case "FunctionDeclaration":
return statement.id?.name ? wrapNamedFunctionBody(source, statement.id.name) : source;
case "ExportDefaultDeclaration":
return renderExportDefaultBody(source, statement.declaration);
default:
return source;
}
};
const renderHeuristicBody = (source: string): string => {
const withoutDefaultExport = source.replace(/^export\s+default\s+/, "").trim();
if (
(withoutDefaultExport.startsWith("async") || withoutDefaultExport.startsWith("(")) &&
withoutDefaultExport.includes("=>")
) {
return wrapCallableBody(withoutDefaultExport);
}
if (FUNCTION_DECLARATION.test(withoutDefaultExport)) {
const name = withoutDefaultExport.match(FUNCTION_DECLARATION)?.[1];
return name
? wrapNamedFunctionBody(withoutDefaultExport, name)
: wrapAnonymousFunctionBody(withoutDefaultExport);
}
return withoutDefaultExport;
};
export const recoverExecutionBody = (code: string): string => {
const source = extractCandidateSource(code);
if (!source) return "";
// oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: Babel parser throws for malformed candidate code, then recovery falls back to heuristics
try {
return renderParsedBody(source);
} catch {
return renderHeuristicBody(source);
}
};