import { ObjectTree } from "@weborigami/async-tree"; import assert from "node:assert"; import { describe, test } from "node:test"; import * as ops from "../../src/runtime/ops.js"; import evaluate from "../../src/runtime/evaluate.js"; describe("evaluate", () => { test("can retrieve values from scope", async () => { const code = createCode([ops.scope, "message"]); const parent = new ObjectTree({ message: "Hello", }); const tree = new ObjectTree({}); tree.parent = parent; const result = await evaluate.call(tree, code); assert.equal(result, "Hello"); }); test("can invoke functions in scope", async () => { // Match the array representation of code generated by the parser. const code = createCode([ [ops.scope, "greet"], [ops.scope, "name"], ]); const tree = new ObjectTree({ async greet(name) { return `Hello ${name}`; }, name: "world", }); const result = await evaluate.call(tree, code); assert.equal(result, "Hello world"); }); test("passes context to invoked functions", async () => { const code = createCode([ops.scope, "fn"]); const tree = new ObjectTree({ async fn() { assert.equal(this, tree); }, }); await evaluate.call(tree, code); }); test("evaluates a function with fixed number of arguments", async () => { const fn = (x, y) => ({ c: `${x}${y}c`, }); const code = createCode([ops.traverse, fn, "a", "b", "c"]); assert.equal(await evaluate.call(null, code), "abc"); }); test("if object in function position isn't a function, can unpack it", async () => { const fn = (...args) => args.join(","); const packed = new String(); /** @type {any} */ (packed).unpack = async () => fn; const code = createCode([packed, "a", "b", "c"]); const result = await evaluate.call(null, code); assert.equal(result, "a,b,c"); }); test("by defalut sets the parent of a returned tree to the current tree", async () => { const fn = () => new ObjectTree({}); const code = createCode([fn]); const tree = new ObjectTree({}); const result = await evaluate.call(tree, code); assert.equal(result.parent, tree); }); }); /** * @returns {import("../../index.ts").Code} */ function createCode(array) { const code = array; /** @type {any} */ (code).location = { source: { text: "", }, }; return code; }