@weborigami/language 0.5.7 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/index.ts +3 -4
  2. package/main.js +1 -3
  3. package/package.json +4 -5
  4. package/src/handlers/csv_handler.js +13 -8
  5. package/src/handlers/handlers.js +2 -0
  6. package/src/handlers/sh_handler.js +65 -0
  7. package/src/handlers/tsv_handler.js +63 -0
  8. package/src/project/jsGlobals.js +5 -1
  9. package/src/project/projectConfig.js +4 -4
  10. package/src/project/projectRoot.js +8 -9
  11. package/src/protocols/constructSiteTree.js +4 -4
  12. package/src/protocols/explore.js +2 -3
  13. package/src/protocols/fetchAndHandleExtension.js +0 -1
  14. package/src/protocols/files.js +2 -3
  15. package/src/protocols/http.js +0 -1
  16. package/src/protocols/https.js +0 -1
  17. package/src/protocols/httpstree.js +2 -3
  18. package/src/protocols/httptree.js +2 -3
  19. package/src/runtime/HandleExtensionsTransform.js +32 -8
  20. package/src/runtime/ImportModulesMixin.js +2 -2
  21. package/src/runtime/{OrigamiFiles.js → OrigamiFileMap.d.ts} +3 -3
  22. package/src/runtime/{OrigamiFiles.d.ts → OrigamiFileMap.js} +3 -5
  23. package/src/runtime/expressionFunction.js +3 -3
  24. package/src/runtime/expressionObject.js +19 -8
  25. package/src/runtime/handleExtension.js +2 -6
  26. package/src/runtime/mergeTrees.js +4 -7
  27. package/src/runtime/ops.js +13 -13
  28. package/test/cases/logicalAndExpression.yaml +7 -8
  29. package/test/compiler/compile.test.js +1 -1
  30. package/test/compiler/optimize.test.js +2 -2
  31. package/test/generated/logicalAndExpression.test.js +4 -0
  32. package/test/handlers/{csv.handler.test.js → csv_handler.test.js} +5 -5
  33. package/test/handlers/{js.handler.test.js → js_handler.test.js} +2 -2
  34. package/test/handlers/{ori.handler.test.js → ori_handler.test.js} +8 -8
  35. package/test/handlers/{oridocument.handler.test.js → oridocument_handler.test.js} +3 -3
  36. package/test/handlers/sh_handler.test.js +14 -0
  37. package/test/handlers/tsv_handler.test.js +28 -0
  38. package/test/handlers/{wasm.handler.test.js → wasm_handler.test.js} +2 -2
  39. package/test/runtime/OrigamiFileMap.test.js +40 -0
  40. package/test/runtime/evaluate.test.js +3 -3
  41. package/test/runtime/expressionObject.test.js +14 -6
  42. package/test/runtime/handleExtension.test.js +2 -2
  43. package/test/runtime/mergeTrees.test.js +2 -2
  44. package/test/runtime/ops.test.js +5 -5
  45. package/src/runtime/InvokeFunctionsTransform.d.ts +0 -5
  46. package/src/runtime/InvokeFunctionsTransform.js +0 -25
  47. package/src/runtime/functionResultsMap.js +0 -17
  48. package/test/runtime/OrigamiFiles.test.js +0 -35
  49. package/test/runtime/fixtures/subgraph = this.js +0 -5
  50. package/test/runtime/functionResultsMap.test.js +0 -20
  51. /package/test/handlers/{jpeg.handler.test.js → jpeg_handler.test.js} +0 -0
  52. /package/test/handlers/{json.handler.test.js → json_handler.test.js} +0 -0
  53. /package/test/handlers/{txt.handler.test.js → txt_handler.test.js} +0 -0
  54. /package/test/handlers/{yaml.handler.test.js → yaml_handler.test.js} +0 -0
@@ -18,7 +18,7 @@ let projectGlobals;
18
18
  *
19
19
  * @param {any} value
20
20
  * @param {any} key
21
- * @param {import("@weborigami/types").AsyncTree} [parent]
21
+ * @param {import("@weborigami/async-tree").SyncOrAsyncMap} [parent]
22
22
  */
23
23
  export default async function handleExtension(value, key, parent) {
24
24
  projectGlobals ??= await globals();
@@ -28,13 +28,9 @@ export default async function handleExtension(value, key, parent) {
28
28
  key = trailingSlash.remove(key);
29
29
  }
30
30
 
31
- // Special cases: `.ori.<ext>` extensions are Origami documents,
32
- // `.jse.<ext>` are JSE documents.
33
- // TODO: Remove .jse.<ext>
31
+ // Special cases: `.ori.<ext>` extensions are Origami documents
34
32
  const extname = key.match(/\.ori\.\S+$/)
35
33
  ? ".oridocument"
36
- : key.match(/\.jse\.\S+$/)
37
- ? ".jsedocument"
38
34
  : extension.extname(key);
39
35
  if (extname) {
40
36
  const handlerName = `${extname.slice(1)}_handler`;
@@ -3,14 +3,13 @@ import { isPlainObject, isUnpackable, Tree } from "@weborigami/async-tree";
3
3
  /**
4
4
  * Create a tree that's the result of merging the given trees.
5
5
  *
6
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
7
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
6
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
8
7
  *
9
- * @param {(Treelike|null)[]} trees
8
+ * @param {(Maplike|null)[]} trees
10
9
  */
11
10
  export default async function mergeTrees(...trees) {
12
11
  // Filter out null or undefined trees.
13
- /** @type {Treelike[]}
12
+ /** @type {Maplike[]}
14
13
  * @ts-ignore */
15
14
  const filtered = trees.filter((tree) => tree);
16
15
 
@@ -27,9 +26,7 @@ export default async function mergeTrees(...trees) {
27
26
  );
28
27
 
29
28
  // If all trees are plain objects, return a plain object.
30
- if (
31
- unpacked.every((tree) => isPlainObject(tree) && !Tree.isAsyncTree(tree))
32
- ) {
29
+ if (unpacked.every((tree) => isPlainObject(tree) && !Tree.isMap(tree))) {
33
30
  // If we do an Object.assign, we'd evaluate getters.
34
31
  // To avoid that, we'll merge property descriptors.
35
32
  const result = {};
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * @typedef {import("../../index.ts").AnnotatedCode} AnnotatedCode
3
- * @typedef {import("@weborigami/async-tree").PlainObject} PlainObject
4
- * @typedef {import("@weborigami/async-tree").Treelike} Treelike
5
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
6
3
  * @typedef {import("../../index.ts").RuntimeState} RuntimeState
4
+ * @typedef {import("@weborigami/async-tree").Maplike} Maplike
5
+ * @typedef {import("@weborigami/async-tree").PlainObject} PlainObject
6
+ * @typedef {import("@weborigami/async-tree").SyncOrAsyncMap} SyncOrAsyncMap
7
7
  */
8
8
 
9
- import { isUnpackable, symbols, Tree } from "@weborigami/async-tree";
9
+ import { getParent, isUnpackable, Tree } from "@weborigami/async-tree";
10
10
  import os from "node:os";
11
11
  import expressionObject from "./expressionObject.js";
12
12
  import { evaluate } from "./internal.js";
13
13
  import mergeTrees from "./mergeTrees.js";
14
- import OrigamiFiles from "./OrigamiFiles.js";
14
+ import OrigamiFileMap from "./OrigamiFileMap.js";
15
15
  import { codeSymbol } from "./symbols.js";
16
16
 
17
17
  function addOpLabel(op, label) {
@@ -176,7 +176,7 @@ addOpLabel(greaterThanOrEqual, "«ops.greaterThanOrEqual»");
176
176
  * Files tree for the user's home directory.
177
177
  */
178
178
  export async function homeDirectory(...keys) {
179
- const tree = new OrigamiFiles(os.homedir());
179
+ const tree = new OrigamiFileMap(os.homedir());
180
180
  return keys.length > 0 ? Tree.traverse(tree, ...keys) : tree;
181
181
  }
182
182
  addOpLabel(homeDirectory, "«ops.homeDirectory»");
@@ -196,7 +196,7 @@ export async function inherited(depth, state) {
196
196
  `Origami internal error: Can't find context object`
197
197
  );
198
198
  }
199
- current = current.parent ?? current[symbols.parent];
199
+ current = getParent(current);
200
200
  }
201
201
  return current;
202
202
  }
@@ -406,11 +406,11 @@ export async function params(depth, state = {}) {
406
406
  addOpLabel(params, "«ops.params»");
407
407
  params.needsState = true;
408
408
 
409
- // export function optionalTraverse(treelike, key) {
410
- // if (!treelike) {
409
+ // export function optionalTraverse(maplike, key) {
410
+ // if (!maplike) {
411
411
  // return undefined;
412
412
  // }
413
- // return Tree.traverseOrThrow(treelike, key);
413
+ // return Tree.traverseOrThrow(maplike, key);
414
414
  // }
415
415
  // addOpLabel(optionalTraverse, "«ops.optionalTraverse");
416
416
 
@@ -436,7 +436,7 @@ export async function property(object, key) {
436
436
  if (key in object) {
437
437
  // Object defines the property, get it
438
438
  let value = object[key];
439
- // Is value an instance method? Copied from ObjectTree.
439
+ // Is value an instance method? Copied from ObjectMap.
440
440
  const isInstanceMethod =
441
441
  value instanceof Function && !Object.hasOwn(object, key);
442
442
  if (isInstanceMethod) {
@@ -460,7 +460,7 @@ addOpLabel(remainder, "«ops.remainder»");
460
460
  * Files tree for the filesystem root.
461
461
  */
462
462
  export async function rootDirectory(...keys) {
463
- const tree = new OrigamiFiles("/");
463
+ const tree = new OrigamiFileMap("/");
464
464
  return keys.length > 0 ? Tree.traverse(tree, ...keys) : tree;
465
465
  }
466
466
  addOpLabel(rootDirectory, "«ops.rootDirectory»");
@@ -468,7 +468,7 @@ addOpLabel(rootDirectory, "«ops.rootDirectory»");
468
468
  /**
469
469
  * Return the scope of the current tree
470
470
  *
471
- * @param {AsyncTree} parent
471
+ * @param {SyncOrAsyncMap} parent
472
472
  */
473
473
  export async function scope(parent) {
474
474
  if (!parent) {
@@ -108,14 +108,13 @@
108
108
  expected: false
109
109
  description: "Complex nesting with false at inner-most"
110
110
 
111
- # TODO: Uncomment when we can do math
112
- # - source: "true && (1 + 1 === 2)"
113
- # expected: true
114
- # description: "Combines logical AND with equality comparison"
115
-
116
- # - source: "false && (5 > 2)"
117
- # expected: false
118
- # description: "Logical AND with greater-than comparison"
111
+ - source: "true && (1 + 1 === 2)"
112
+ expected: true
113
+ description: "Combines logical AND with equality comparison"
114
+
115
+ - source: "false && (5 > 2)"
116
+ expected: false
117
+ description: "Logical AND with greater-than comparison"
119
118
 
120
119
  - source: "true && (3 || 0)"
121
120
  expected: 3
@@ -130,7 +130,7 @@ async function assertCompile(text, expected, options = {}) {
130
130
  const parent = options.target ?? null;
131
131
  const fn = compile.expression(text, { globals, mode, parent });
132
132
  let result = await fn();
133
- if (Tree.isTreelike(result)) {
133
+ if (Tree.isMaplike(result)) {
134
134
  result = await Tree.plain(result);
135
135
  }
136
136
  assert.deepEqual(result, expected);
@@ -1,4 +1,4 @@
1
- import { ObjectTree } from "@weborigami/async-tree";
1
+ import { SyncMap } from "@weborigami/async-tree";
2
2
  import { describe, test } from "node:test";
3
3
  import * as compile from "../../src/compiler/compile.js";
4
4
  import {
@@ -313,7 +313,7 @@ describe("optimize", () => {
313
313
  });
314
314
 
315
315
  function assertCompile(expression, expected, mode = "shell") {
316
- const parent = new ObjectTree({});
316
+ const parent = new SyncMap();
317
317
  const globals = {};
318
318
  const fn = compile.expression(expression, { globals, mode, parent });
319
319
  const actual = fn.code;
@@ -33,6 +33,8 @@ describe("logicalAndExpression - JavaScript", () => {
33
33
  assert.strictEqual((true && true) && true, true, "Nested logical ANDs with all true");
34
34
  assert.strictEqual(true && (true && false), false, "Nested logical ANDs with false in inner");
35
35
  assert.strictEqual((true && (false && true)), false, "Complex nesting with false at inner-most");
36
+ assert.strictEqual(true && (1 + 1 === 2), true, "Combines logical AND with equality comparison");
37
+ assert.strictEqual(false && (5 > 2), false, "Logical AND with greater-than comparison");
36
38
  assert.strictEqual(true && (3 || 0), 3, "Logical AND with logical OR");
37
39
  assert.strictEqual(true && (0 || 3), 3, "Logical AND with logical OR and falsy values");
38
40
  assert.strictEqual('' && false, "", "Falsy string and false");
@@ -70,6 +72,8 @@ describe("logicalAndExpression - Origami", async() => {
70
72
  assert.strictEqual(await oriEval("(true && true) && true"), true, "Nested logical ANDs with all true");
71
73
  assert.strictEqual(await oriEval("true && (true && false)"), false, "Nested logical ANDs with false in inner");
72
74
  assert.strictEqual(await oriEval("(true && (false && true))"), false, "Complex nesting with false at inner-most");
75
+ assert.strictEqual(await oriEval("true && (1 + 1 === 2)"), true, "Combines logical AND with equality comparison");
76
+ assert.strictEqual(await oriEval("false && (5 > 2)"), false, "Logical AND with greater-than comparison");
73
77
  assert.strictEqual(await oriEval("true && (3 || 0)"), 3, "Logical AND with logical OR");
74
78
  assert.strictEqual(await oriEval("true && (0 || 3)"), 3, "Logical AND with logical OR and falsy values");
75
79
  assert.strictEqual(await oriEval("'' && false"), "", "Falsy string and false");
@@ -10,17 +10,17 @@ Bob,25,Los Angeles
10
10
  "Carol ""CJ""",22,Chicago`;
11
11
  const result = csv_handler.unpack(csvText);
12
12
  assert.deepStrictEqual(result, [
13
- { name: "Alice", age: "30", city: "New York, NY" },
14
- { name: "Bob", age: "25", city: "Los Angeles" },
15
- { name: 'Carol "CJ"', age: "22", city: "Chicago" },
13
+ { name: "Alice", age: 30, city: "New York, NY" },
14
+ { name: "Bob", age: 25, city: "Los Angeles" },
15
+ { name: 'Carol "CJ"', age: 22, city: "Chicago" },
16
16
  ]);
17
17
  });
18
18
 
19
19
  test("handles CRLF line endings", () => {
20
20
  const textCRLF = `name,age,city\r\nAlice,30,"New York, NY"\r\nBob,25,Los Angeles\r\n`;
21
21
  const expected = [
22
- { name: "Alice", age: "30", city: "New York, NY" },
23
- { name: "Bob", age: "25", city: "Los Angeles" },
22
+ { name: "Alice", age: 30, city: "New York, NY" },
23
+ { name: "Bob", age: 25, city: "Los Angeles" },
24
24
  ];
25
25
  const result = csv_handler.unpack(textCRLF);
26
26
  assert.deepStrictEqual(result, expected);
@@ -1,11 +1,11 @@
1
- import { FileTree } from "@weborigami/async-tree";
1
+ import { FileMap } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
  import js_handler from "../../src/handlers/js_handler.js";
5
5
  import ImportModulesMixin from "../../src/runtime/ImportModulesMixin.js";
6
6
 
7
7
  const fixturesUrl = new URL("fixtures", import.meta.url);
8
- const fixturesTree = new (ImportModulesMixin(FileTree))(fixturesUrl);
8
+ const fixturesTree = new (ImportModulesMixin(FileMap))(fixturesUrl);
9
9
 
10
10
  describe(".js handler", () => {
11
11
  test("loads .js file that exports a string", async () => {
@@ -1,11 +1,11 @@
1
- import { ObjectTree, Tree } from "@weborigami/async-tree";
1
+ import { ObjectMap, Tree } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
  import ori_handler from "../../src/handlers/ori_handler.js";
5
- import OrigamiFiles from "../../src/runtime/OrigamiFiles.js";
5
+ import OrigamiFileMap from "../../src/runtime/OrigamiFileMap.js";
6
6
 
7
7
  const fixturesUrl = new URL("fixtures", import.meta.url);
8
- const fixtures = new OrigamiFiles(fixturesUrl);
8
+ const fixtures = new OrigamiFileMap(fixturesUrl);
9
9
 
10
10
  describe(".ori handler", async () => {
11
11
  test("loads a string expression", async () => {
@@ -15,7 +15,7 @@ describe(".ori handler", async () => {
15
15
  });
16
16
 
17
17
  test("loads a tree expression", async () => {
18
- const parent = new ObjectTree({
18
+ const parent = new ObjectMap({
19
19
  name: "world",
20
20
  });
21
21
  const source = `{
@@ -43,15 +43,15 @@ describe(".ori handler", async () => {
43
43
  });
44
44
 
45
45
  test("loads an object containing an object shorthand", async () => {
46
- const assets = new ObjectTree({});
47
- const parent = new ObjectTree({ assets });
46
+ const assets = new ObjectMap({});
47
+ const parent = new ObjectMap({ assets });
48
48
  const source = `{ assets }`;
49
49
  const object = await ori_handler.unpack(source, { parent });
50
50
  assert.equal(object.assets, assets);
51
51
  });
52
52
 
53
53
  test("loads a template literal", async () => {
54
- const scope = new ObjectTree({
54
+ const scope = new ObjectMap({
55
55
  name: "Alice",
56
56
  });
57
57
  const source = `\`Hello, \${name}!\``;
@@ -62,7 +62,7 @@ describe(".ori handler", async () => {
62
62
  });
63
63
 
64
64
  test("loads a template lambda that reads from parent scope", async () => {
65
- const parent = new ObjectTree({
65
+ const parent = new ObjectMap({
66
66
  name: "Alice",
67
67
  });
68
68
  const source = `() => \`Hello, \${name}!\``;
@@ -1,11 +1,11 @@
1
- import { ObjectTree } from "@weborigami/async-tree";
1
+ import { ObjectMap } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
  import oridocument_handler from "../../src/handlers/oridocument_handler.js";
5
5
 
6
6
  describe("Origami document handler", () => {
7
7
  test("unpacks text with Origami expressions", async () => {
8
- const parent = new ObjectTree({
8
+ const parent = new ObjectMap({
9
9
  name: "world",
10
10
  });
11
11
  const text = "Hello, ${ name }!";
@@ -28,7 +28,7 @@ describe("Origami document handler", () => {
28
28
  });
29
29
 
30
30
  test("YAML front matter is returned with _body", async () => {
31
- const parent = new ObjectTree({
31
+ const parent = new ObjectMap({
32
32
  message: "Hello",
33
33
  });
34
34
  const text = `---
@@ -0,0 +1,14 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import sh_handler from "../../src/handlers/sh_handler.js";
4
+
5
+ describe(".sh handler", () => {
6
+ test("invokes shell commands", async () => {
7
+ const text = `echo Hello
8
+ cat
9
+ `;
10
+ const fn = await sh_handler.unpack(text);
11
+ const output = await fn("Input text");
12
+ assert.equal(output, "Hello\nInput text");
13
+ });
14
+ });
@@ -0,0 +1,28 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import tsv_handler from "../../src/handlers/tsv_handler.js";
4
+
5
+ describe(".tsv handler", () => {
6
+ test("parses TSV text into array of objects", () => {
7
+ const TSVText = `name age city
8
+ Alice\t30\tNew York, NY
9
+ Bob\t25\tLos Angeles
10
+ Carol\t22\tChicago`;
11
+ const result = tsv_handler.unpack(TSVText);
12
+ assert.deepStrictEqual(result, [
13
+ { name: "Alice", age: 30, city: "New York, NY" },
14
+ { name: "Bob", age: 25, city: "Los Angeles" },
15
+ { name: "Carol", age: 22, city: "Chicago" },
16
+ ]);
17
+ });
18
+
19
+ test("handles CRLF line endings", () => {
20
+ const textCRLF = `name\tage\tcity\r\nAlice\t30\tNew York, NY\r\nBob\t25\tLos Angeles\r\n`;
21
+ const expected = [
22
+ { name: "Alice", age: 30, city: "New York, NY" },
23
+ { name: "Bob", age: 25, city: "Los Angeles" },
24
+ ];
25
+ const result = tsv_handler.unpack(textCRLF);
26
+ assert.deepStrictEqual(result, expected);
27
+ });
28
+ });
@@ -1,11 +1,11 @@
1
- import { FileTree } from "@weborigami/async-tree";
1
+ import { FileMap } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
  import wasm_handler from "../../src/handlers/wasm_handler.js";
5
5
  import ImportModulesMixin from "../../src/runtime/ImportModulesMixin.js";
6
6
 
7
7
  const fixturesUrl = new URL("fixtures", import.meta.url);
8
- const fixturesTree = new (ImportModulesMixin(FileTree))(fixturesUrl);
8
+ const fixturesTree = new (ImportModulesMixin(FileMap))(fixturesUrl);
9
9
 
10
10
  describe(".wasm handler", () => {
11
11
  test("loads .wasm file that exports a function", async () => {
@@ -0,0 +1,40 @@
1
+ import assert from "node:assert";
2
+ import * as fs from "node:fs";
3
+ import path from "node:path";
4
+ import { describe, test } from "node:test";
5
+ import { fileURLToPath } from "node:url";
6
+ import OrigamiFileMap from "../../src/runtime/OrigamiFileMap.js";
7
+
8
+ const dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const tempDirectory = path.join(dirname, "fixtures/temp/OrigamiFileMap");
10
+
11
+ describe("OrigamiFileMap", () => {
12
+ test.skip("can watch its folder for changes", { timeout: 2000 }, async () => {
13
+ createTempDirectory();
14
+
15
+ const tempFiles = new OrigamiFileMap(tempDirectory);
16
+ const changedFileName = await new Promise(async (resolve) => {
17
+ tempFiles.addEventListener("change", (event) => {
18
+ resolve(/** @type {any} */ (event).options.key);
19
+ });
20
+ tempFiles.set(
21
+ "foo.txt",
22
+ "This file is left over from testing and can be removed."
23
+ );
24
+ });
25
+ removeTempDirectory();
26
+ assert.equal(changedFileName, "foo.txt");
27
+ });
28
+ });
29
+
30
+ function createTempDirectory() {
31
+ // Remove any existing files or directories inside the temp directory so
32
+ // tests start from a clean slate. Use force so this is safe if the
33
+ // directory doesn't exist.
34
+ fs.rmSync(tempDirectory, { force: true, recursive: true });
35
+ fs.mkdirSync(tempDirectory, { recursive: true });
36
+ }
37
+
38
+ function removeTempDirectory() {
39
+ fs.rmSync(tempDirectory, { force: true, recursive: true });
40
+ }
@@ -1,7 +1,7 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
3
 
4
- import { ObjectTree } from "@weborigami/async-tree";
4
+ import { SyncMap } from "@weborigami/async-tree";
5
5
  import evaluate from "../../src/runtime/evaluate.js";
6
6
  import { createCode } from "../compiler/codeHelpers.js";
7
7
 
@@ -27,12 +27,12 @@ describe("evaluate", () => {
27
27
  });
28
28
 
29
29
  test("if function has containerAsTarget, it gets bound to state.container", async () => {
30
- /** @this {import("@weborigami/types").AsyncTree} */
30
+ /** @this {import("@weborigami/async-tree").SyncOrAsyncMap} */
31
31
  const fn = function () {
32
32
  return this;
33
33
  };
34
34
  fn.containerAsTarget = true;
35
- const container = new ObjectTree({});
35
+ const container = new SyncMap();
36
36
  const state = { container };
37
37
  const code = createCode([fn]);
38
38
  const result = await evaluate(code, state);
@@ -1,4 +1,4 @@
1
- import { ObjectTree, symbols, Tree } from "@weborigami/async-tree";
1
+ import { ObjectMap, symbols, SyncMap, Tree } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
 
@@ -7,7 +7,7 @@ import { ops } from "../../src/runtime/internal.js";
7
7
 
8
8
  describe("expressionObject", () => {
9
9
  test("can instantiate an object", async () => {
10
- const container = new ObjectTree({
10
+ const container = new ObjectMap({
11
11
  upper: (s) => s.toUpperCase(),
12
12
  });
13
13
 
@@ -15,7 +15,7 @@ describe("expressionObject", () => {
15
15
  ["hello", [[[ops.scope, container], "upper"], "hello"]],
16
16
  ["world", [[[ops.scope, container], "upper"], "world"]],
17
17
  ];
18
- const context = new ObjectTree({});
18
+ const context = new SyncMap();
19
19
 
20
20
  const object = await expressionObject(entries, { object: context });
21
21
  assert.equal(await object.hello, "HELLO");
@@ -43,7 +43,7 @@ describe("expressionObject", () => {
43
43
  ["name", "world"],
44
44
  ["message", [ops.concat, "Hello, ", [[ops.inherited, 0], "name"], "!"]],
45
45
  ];
46
- const context = new ObjectTree({});
46
+ const context = new SyncMap();
47
47
  const object = await expressionObject(entries, { object: context });
48
48
  assert.deepEqual(await Tree.plain(object), {
49
49
  name: "world",
@@ -54,7 +54,7 @@ describe("expressionObject", () => {
54
54
 
55
55
  test("returned object values can be unpacked", async () => {
56
56
  const entries = [["data.json", `{ "a": 1 }`]];
57
- const context = new ObjectTree({});
57
+ const context = new SyncMap();
58
58
  const result = await expressionObject(entries, { object: context });
59
59
  const dataJson = await result["data.json"];
60
60
  const json = await dataJson.unpack();
@@ -77,7 +77,7 @@ describe("expressionObject", () => {
77
77
  ["getter", [ops.getter, [ops.object, ["b", [ops.literal, 2]]]]],
78
78
  ["hasSlash/", "This isn't really a tree but says it is"],
79
79
  ["message", "Hello"],
80
- // Immediate treelike value, should have a slash
80
+ // Immediate maplike value, should have a slash
81
81
  ["object", [ops.object, ["b", [ops.literal, 2]]]],
82
82
  ];
83
83
  const object = await expressionObject(entries);
@@ -88,4 +88,12 @@ describe("expressionObject", () => {
88
88
  "object/",
89
89
  ]);
90
90
  });
91
+
92
+ test("sets symbols.async on objects with getters", async () => {
93
+ const noGetter = await expressionObject([["eager", 1]]);
94
+ assert.equal(noGetter[symbols.async], undefined);
95
+
96
+ const hasGetter = await expressionObject([["lazy", [ops.getter, [2]]]]);
97
+ assert.equal(hasGetter[symbols.async], true);
98
+ });
91
99
  });
@@ -1,4 +1,4 @@
1
- import { ObjectTree } from "@weborigami/async-tree";
1
+ import { ObjectMap } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
  import handleExtension from "../../src/runtime/handleExtension.js";
@@ -25,7 +25,7 @@ describe("handleExtension", () => {
25
25
  });
26
26
 
27
27
  function createFixture() {
28
- return new ObjectTree({
28
+ return new ObjectMap({
29
29
  foo: 1, // No extension, should be left alone
30
30
  "bar.json": `{ "bar": 2 }`,
31
31
  });
@@ -1,4 +1,4 @@
1
- import { ObjectTree, Tree } from "@weborigami/async-tree";
1
+ import { ObjectMap, Tree } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
  import mergeTrees from "../../src/runtime/mergeTrees.js";
@@ -42,7 +42,7 @@ describe("mergeTrees", () => {
42
42
 
43
43
  test("merges heterogenous arguments as trees", async () => {
44
44
  const tree = await mergeTrees(
45
- new ObjectTree({
45
+ new ObjectMap({
46
46
  a: 1,
47
47
  b: 2,
48
48
  }),
@@ -1,4 +1,4 @@
1
- import { DeepObjectTree, ObjectTree, Tree } from "@weborigami/async-tree";
1
+ import { DeepObjectMap, ObjectMap, Tree } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
 
@@ -128,12 +128,12 @@ describe("ops", () => {
128
128
  assert.deepEqual(await ops.flat(1, 2, [3]), [1, 2, 3]);
129
129
  });
130
130
 
131
- test("flattens treelike objects", async () => {
131
+ test("flattens maplike objects", async () => {
132
132
  const object = {
133
133
  a: 1,
134
134
  b: 2,
135
135
  };
136
- const tree = new ObjectTree({
136
+ const tree = new ObjectMap({
137
137
  c: 3,
138
138
  d: 4,
139
139
  });
@@ -156,7 +156,7 @@ describe("ops", () => {
156
156
  });
157
157
 
158
158
  test("ops.inherited walks up the object parent chain", async () => {
159
- const tree = new DeepObjectTree({
159
+ const tree = new DeepObjectMap({
160
160
  a: {
161
161
  b: {},
162
162
  },
@@ -368,7 +368,7 @@ describe("ops", () => {
368
368
 
369
369
  describe("ops.scope", () => {
370
370
  test("returns the scope of the given tree", async () => {
371
- const tree = new DeepObjectTree({
371
+ const tree = new DeepObjectMap({
372
372
  a: {
373
373
  b: {},
374
374
  },
@@ -1,5 +0,0 @@
1
- import { Mixin } from "../../index.ts";
2
-
3
- declare const InvokeFunctionsTransform: Mixin<{}>;
4
-
5
- export default InvokeFunctionsTransform;
@@ -1,25 +0,0 @@
1
- import { Tree } from "@weborigami/async-tree";
2
-
3
- /**
4
- * When using `get` to retrieve a value from a tree, if the value is a
5
- * function, invoke it and return the result.
6
- *
7
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
- * @typedef {import("../../index.js").Constructor<AsyncTree>} AsyncTreeConstructor
9
- * @param {AsyncTreeConstructor} Base
10
- */
11
- export default function InvokeFunctionsTransform(Base) {
12
- return class InvokeFunctions extends Base {
13
- async get(key) {
14
- let value = await super.get(key);
15
- if (typeof value === "function") {
16
- value = await value();
17
-
18
- if (Tree.isAsyncTree(value) && !value.parent) {
19
- value.parent = this;
20
- }
21
- }
22
- return value;
23
- }
24
- };
25
- }
@@ -1,17 +0,0 @@
1
- import { Tree } from "@weborigami/async-tree";
2
-
3
- /**
4
- * When using `get` to retrieve a value from a tree, if the value is a
5
- * function, invoke it and return the result.
6
- */
7
- export default async function functionResultsMap(treelike) {
8
- return Tree.map(treelike, {
9
- description: "functionResultsMap",
10
-
11
- value: async (sourceValue, sourceKey, tree) => {
12
- const resultValue =
13
- typeof sourceValue === "function" ? await sourceValue() : sourceValue;
14
- return resultValue;
15
- },
16
- });
17
- }