Tengo declaraciones de funciones de Javascript como una cadena (obtenidas de Function.toString ), y quiero envolver todas las declaraciones de variables con una función (también en Javascript), por ejemplo, const value = 42 a const value = wrapper(42) .
Primero pensé en usar RegEx para obtener los valores y la ubicación originales y luego reemplazarlos con el valor envuelto, pero RegEx se volvió demasiado complejo muy rápido debido a la necesidad de pensar en cosas como cadenas y objetos de varias líneas. El uso de RegEx también afectaría la facilidad de que otras personas contribuyan al proyecto.
Después de eso, busqué usar un módulo para esto, encontré Acorn (usado por Babel, Svelte. Analiza el Javascript en un ESTree, la especificación para los árboles de sintaxis abstracta de Javascript): https://github.com/acornjs/acorn , pero No pude encontrar una manera de analizar el ESTree de nuevo a una declaración de función de Javascript después de realizar las modificaciones.
¿Hay alguna forma de analizar el ESTree de nuevo a una función u otra solución mejor?
Realmente no necesita una función para volver a convertir el árbol en código. En su lugar, tome nota de las compensaciones donde debe ocurrir el cambio y luego no aplique el cambio en el árbol, sino en la cadena original.
Aquí hay una demostración con la API de bellota:
function test () { // The function we want to tamper with const value = 42, prefix = "prefix"; let x = 3; for (let i = 0; i < 10; i++) { x = (x * 997 + value) % 1000; } return prefix + " " + x; } function addInitWrappers(str) { // Returns an updated string let ast = acorn.parse(str, {ecmaVersion: 2020}); function* iter(node) { if (Object(node) !== node) return; // Primitive if (node.type == "VariableDeclaration" && node.kind == "const") { for (let {init} of node.declarations) { yield init; // yield the offset where this initialisation occurs } } for (let value of Object.values(node)) { yield* iter(value); } } // Inject the wrapper -- starting at the back for (let {start, end} of [...iter(ast)].reverse()) { str = str.slice(0, start) + "wrapper(" + str.slice(start, end) + ")" + str.slice(end); } return str; } function wrapper(value) { // A wrapper function to demo with return value + 1; } console.log("before wrapping test() returns:", test()); let str = test.toString(); str = addInitWrappers(str); eval(str); // Override the test function with its new definition console.log("after wrapping test() returns:", test()); <script src="https://cdnjs.cloudflare.com/ajax/libs/acorn/8.7.1/acorn.min.js"></script>