From 2c7cc5d325d8389a0552376ff608894ea530c624 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 8 Nov 2022 20:23:30 +0100 Subject: [PATCH] core evaluate now works without transpiler --- packages/core/evaluate.mjs | 16 +++++++++++++--- packages/eval/shapeshifter.mjs | 7 ++++--- packages/eval/test/shapeshifter.test.mjs | 20 +++++++++++++------- packages/transpiler/transpiler.mjs | 2 +- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/core/evaluate.mjs b/packages/core/evaluate.mjs index 7e7fe1d1..eea5a90b 100644 --- a/packages/core/evaluate.mjs +++ b/packages/core/evaluate.mjs @@ -24,8 +24,16 @@ export const evalScope = async (...args) => { Object.assign(globalThis, ...modules, Pattern.prototype.bootstrap()); }; -function safeEval(str) { - return Function('"use strict";return (' + str + ')')(); +function safeEval(str, options = {}) { + const { wrapExpression = true, wrapAsync = true } = options; + if (wrapExpression) { + str = `{${str}}`; + } + if (wrapAsync) { + str = `(async ()=>${str})()`; + } + const body = `"use strict";return (${str})`; + return Function(body)(); } export const evaluate = async (code, transpiler) => { @@ -35,7 +43,9 @@ export const evaluate = async (code, transpiler) => { if (transpiler) { code = transpiler(code); // transform syntactically correct js code to semantically usable code } - let evaluated = await safeEval(code); + // if no transpiler is given, we expect a single instruction (!wrapExpression) + const options = { wrapExpression: !!transpiler }; + let evaluated = await safeEval(code, options); if (!isPattern(evaluated)) { console.log('evaluated', evaluated); const message = `got "${typeof evaluated}" instead of pattern`; diff --git a/packages/eval/shapeshifter.mjs b/packages/eval/shapeshifter.mjs index 500eb0ea..b8ffffd3 100644 --- a/packages/eval/shapeshifter.mjs +++ b/packages/eval/shapeshifter.mjs @@ -30,7 +30,8 @@ const isNote = (name) => /^[a-gC-G][bs]?[0-9]$/.test(name); const addLocations = true; export const addMiniLocations = true; export const minifyStrings = true; -export const wrappedAsync = true; +export const wrappedAsync = false; // this is now handled by core evaluate by default +export const shouldAddReturn = true; export default (_code) => { const { code, addReturn } = wrapAsync(_code); @@ -125,7 +126,7 @@ export default (_code) => { }, }); // add return to last statement (because it's wrapped in an async function artificially) - if (wrappedAsync) { + if (shouldAddReturn) { addReturn(shifted); } const generated = undisguiseImports(codegen(shifted)); @@ -153,7 +154,7 @@ ${code} })()`; } const addReturn = (ast) => { - const body = ast.statements[0].expression.callee.body; // actual code ast inside async function body + const body = wrappedAsync ? ast.statements[0].expression.callee.body : ast; body.statements = body.statements .slice(0, -1) .concat([new ReturnStatement({ expression: body.statements.slice(-1)[0] })]); diff --git a/packages/eval/test/shapeshifter.test.mjs b/packages/eval/test/shapeshifter.test.mjs index 39d9d715..ae958326 100644 --- a/packages/eval/test/shapeshifter.test.mjs +++ b/packages/eval/test/shapeshifter.test.mjs @@ -5,15 +5,21 @@ This program is free software: you can redistribute it and/or modify it under th */ import { describe, it, expect } from 'vitest'; -import shapeshifter from '../shapeshifter.mjs'; +import shapeshifter, { wrappedAsync } from '../shapeshifter.mjs'; describe('shapeshifter', () => { it('Should shift simple double quote string', () => { - expect(shapeshifter('"c3"')).toEqual('(async()=>{return mini("c3").withMiniLocation([1,0,15],[1,4,19])})()'); - }); - it('Should handle dynamic imports', () => { - expect(shapeshifter('const { default: foo } = await import(\'https://bar.com/foo.js\');"c3"')).toEqual( - '(async()=>{const{default:foo}=await import("https://bar.com/foo.js");return mini("c3").withMiniLocation([1,64,79],[1,68,83])})()', - ); + if (wrappedAsync) { + expect(shapeshifter('"c3"')).toEqual('(async()=>{return mini("c3").withMiniLocation([1,0,15],[1,4,19])})()'); + } else { + expect(shapeshifter('"c3"')).toEqual('return mini("c3").withMiniLocation([1,0,0],[1,4,4])'); + } }); + if (wrappedAsync) { + it('Should handle dynamic imports', () => { + expect(shapeshifter('const { default: foo } = await import(\'https://bar.com/foo.js\');"c3"')).toEqual( + 'const{default:foo}=await import("https://bar.com/foo.js");return mini("c3").withMiniLocation([1,64,79],[1,68,83])', + ); + }); + } }); diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index a08cbd71..00f5782d 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -4,7 +4,7 @@ import { walk } from 'estree-walker'; import { isNote } from '@strudel.cycles/core'; export function transpiler(input, options = {}) { - const { wrapAsync = true, addReturn = true } = options; + const { wrapAsync = false, addReturn = true } = options; let ast = parse(input, { ecmaVersion: 2022,