@weborigami/language 0.0.38 → 0.0.40

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.
@@ -32,7 +32,7 @@ export default function FileLoadersTransform(Base) {
32
32
  value = new String(input);
33
33
  const parent = this;
34
34
  value.parent = parent;
35
- value.unpack = () => unpackFn(input, { key, parent });
35
+ value.unpack = unpackFn.bind(null, input, { key, parent });
36
36
  }
37
37
  }
38
38
  }
@@ -1,4 +1,8 @@
1
- import { Tree, getRealmObjectPrototype } from "@weborigami/async-tree";
1
+ import {
2
+ Tree,
3
+ getRealmObjectPrototype,
4
+ isPlainObject,
5
+ } from "@weborigami/async-tree";
2
6
 
3
7
  /**
4
8
  * Concatenate the text values in a tree.
@@ -24,6 +28,22 @@ async function getText(value, scope) {
24
28
  value = await value.call(scope);
25
29
  }
26
30
 
31
+ // We'd prefer to use Tree.isTreelike() here, but that counts an object with
32
+ // an unpack() function as a treelike object. In this case, we don't want to
33
+ // unpack anything that's not already treelike.
34
+ const isTreelike =
35
+ Tree.isAsyncTree(value) ||
36
+ value instanceof Function ||
37
+ value instanceof Array ||
38
+ value instanceof Set ||
39
+ isPlainObject(value);
40
+ if (isTreelike) {
41
+ // The mapReduce operation above only implicit casts its top-level input to
42
+ // a tree. If we're asked for the text of a treelike value, we need to
43
+ // explicitly recurse.
44
+ return concatTreeValues.call(scope, value);
45
+ }
46
+
27
47
  // Convert to text, preferring .toString but avoiding dumb Object.toString.
28
48
  // Exception: if the result is an array, we'll concatenate the values.
29
49
  let text;
@@ -10,6 +10,9 @@ import Scope from "./Scope.js";
10
10
  import concatTreeValues from "./concatTreeValues.js";
11
11
  import { OrigamiTree, evaluate, expressionFunction } from "./internal.js";
12
12
 
13
+ // For memoizing lambda functions
14
+ const lambdaFnMap = new Map();
15
+
13
16
  /**
14
17
  * Construct an array.
15
18
  *
@@ -130,6 +133,9 @@ inherited.toString = () => "«ops.inherited»";
130
133
  * @param {Code} code
131
134
  */
132
135
  export function lambda(code) {
136
+ if (lambdaFnMap.has(code)) {
137
+ return lambdaFnMap.get(code);
138
+ }
133
139
  /** @this {AsyncTree|null} */
134
140
  async function invoke(input) {
135
141
  // Add ambients to scope.
@@ -142,6 +148,7 @@ export function lambda(code) {
142
148
  return result;
143
149
  }
144
150
  invoke.code = code;
151
+ lambdaFnMap.set(code, invoke);
145
152
  return invoke;
146
153
  }
147
154
  lambda.toString = () => "«ops.lambda»";
@@ -182,7 +189,9 @@ export async function tree(...entries) {
182
189
  return [key, value];
183
190
  });
184
191
  const object = Object.fromEntries(fns);
185
- return new OrigamiTree(object);
192
+ const result = new OrigamiTree(object);
193
+ result.scope = new Scope(result, this);
194
+ return result;
186
195
  }
187
196
  tree.toString = () => "«ops.tree»";
188
197
 
@@ -93,7 +93,7 @@ describe("Origami parser", () => {
93
93
  "expression",
94
94
  `
95
95
  {
96
- index.html = index.orit(teamData.yaml)
96
+ index.html = index.ori(teamData.yaml)
97
97
  thumbnails = @map(images, { valueMap: thumbnail.js })
98
98
  }
99
99
  `,
@@ -102,7 +102,7 @@ describe("Origami parser", () => {
102
102
  [
103
103
  "index.html",
104
104
  [
105
- [ops.scope, "index.orit"],
105
+ [ops.scope, "index.ori"],
106
106
  [ops.scope, "teamData.yaml"],
107
107
  ],
108
108
  ],
@@ -1,4 +1,4 @@
1
- import { ObjectTree } from "@weborigami/async-tree";
1
+ import { DeepObjectTree, ObjectTree } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
  import InheritScopeMixin from "../../src/runtime/InheritScopeMixin.js";
@@ -16,7 +16,7 @@ describe("InheritScopeMixin", () => {
16
16
  });
17
17
 
18
18
  test("adds a subtree's parent to the subtrees's scope", async () => {
19
- const fixture = new (InheritScopeMixin(ObjectTree))({
19
+ const fixture = new (InheritScopeMixin(DeepObjectTree))({
20
20
  a: 1,
21
21
  subtree: {
22
22
  b: 2,
@@ -1,4 +1,4 @@
1
- import { Tree } from "@weborigami/async-tree";
1
+ import { FunctionTree, Tree } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
4
  import concatTreeValues from "../../src/runtime/concatTreeValues.js";
@@ -17,4 +17,17 @@ describe("concatTreeValues", () => {
17
17
  const result = await concatTreeValues.call(null, tree);
18
18
  assert.equal(result, "ABCDE");
19
19
  });
20
+
21
+ test("concatenates deep tree-like values", async () => {
22
+ const letters = ["a", "b", "c"];
23
+ const specimens = new FunctionTree(
24
+ (letter) => ({
25
+ lowercase: letter,
26
+ uppercase: letter.toUpperCase(),
27
+ }),
28
+ letters
29
+ );
30
+ const result = await concatTreeValues.call(null, specimens);
31
+ assert.equal(result, "aAbBcC");
32
+ });
20
33
  });