slavery-js
Version:
A simple clustering app that allows you to scale an application on multiple thread, containers or machines
74 lines (60 loc) • 2.9 kB
text/typescript
import * as esprima from 'esprima';
type ParsedFunction = {
outer_function: Function
inner_functions: { name: string; fn: Function }[];
};
function extractFunctions(code: string): ParsedFunction {
const ast = esprima.parseScript(code, { range: true });
let outer = '';
const inner: { name: string; fn: string }[] = [];
for (const node of ast.body) {
if (node.type === 'FunctionDeclaration' && node.id?.name === 'hello') {
// Get outer function source code
const [start, end] = node.range!;
const outerSource = code.slice(start, end);
// Filter out inner functions from the body
const innerRanges: [number, number][] = [];
for (const stmt of node.body.body) {
if (stmt.type === 'FunctionDeclaration') {
const innerCode = code.slice(stmt.range![0], stmt.range![1]);
inner.push({ name: stmt.id!.name, fn: innerCode });
innerRanges.push([stmt.range![0], stmt.range![1]]);
}
// Variable declarations like: let fn = function(...) { ... }
if (
stmt.type === 'VariableDeclaration'
) {
for (const decl of stmt.declarations) {
if (
decl.init &&
(decl.init.type === 'FunctionExpression' ||
decl.init.type === 'ArrowFunctionExpression')
) {
const fnName = (decl.id as any).name;
const fnCode = code.slice(stmt.range![0], stmt.range![1]);
// Convert to "function name(args) { ... }" format
const args = decl.init.params.map((p) => code.slice(p.range![0], p.range![1])).join(', ');
const bodyCode = code.slice(decl.init.body.range![0], decl.init.body.range![1]);
const formattedFn = `function ${fnName}(${args}) ${bodyCode}`;
inner.push({ name: fnName, fn: formattedFn });
innerRanges.push([stmt.range![0], stmt.range![1]]);
}
}
}
}
// Remove inner function code from outer function body
let cleanedBody = code.slice(node.body.range![0] + 1, node.body.range![1] - 1);
for (const [start, end] of innerRanges) {
const innerCode = code.slice(start, end);
cleanedBody = cleanedBody.replace(innerCode, '');
}
outer = `${code.slice(node.range![0], node.body.range![0] + 1)}${cleanedBody}\n}`;
}
}
// create the functions objects
let outer_function = new Function(outer);
let inner_functions = inner.map((fn) => ({ name: fn.name, fn: new Function(fn.fn) }));
// return
return { outer_function, inner_functions };
}
export default extractFunctions;