@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.
- package/index.ts +3 -4
- package/main.js +1 -3
- package/package.json +4 -5
- package/src/handlers/csv_handler.js +13 -8
- package/src/handlers/handlers.js +2 -0
- package/src/handlers/sh_handler.js +65 -0
- package/src/handlers/tsv_handler.js +63 -0
- package/src/project/jsGlobals.js +5 -1
- package/src/project/projectConfig.js +4 -4
- package/src/project/projectRoot.js +8 -9
- package/src/protocols/constructSiteTree.js +4 -4
- package/src/protocols/explore.js +2 -3
- package/src/protocols/fetchAndHandleExtension.js +0 -1
- package/src/protocols/files.js +2 -3
- package/src/protocols/http.js +0 -1
- package/src/protocols/https.js +0 -1
- package/src/protocols/httpstree.js +2 -3
- package/src/protocols/httptree.js +2 -3
- package/src/runtime/HandleExtensionsTransform.js +32 -8
- package/src/runtime/ImportModulesMixin.js +2 -2
- package/src/runtime/{OrigamiFiles.js → OrigamiFileMap.d.ts} +3 -3
- package/src/runtime/{OrigamiFiles.d.ts → OrigamiFileMap.js} +3 -5
- package/src/runtime/expressionFunction.js +3 -3
- package/src/runtime/expressionObject.js +19 -8
- package/src/runtime/handleExtension.js +2 -6
- package/src/runtime/mergeTrees.js +4 -7
- package/src/runtime/ops.js +13 -13
- package/test/cases/logicalAndExpression.yaml +7 -8
- package/test/compiler/compile.test.js +1 -1
- package/test/compiler/optimize.test.js +2 -2
- package/test/generated/logicalAndExpression.test.js +4 -0
- package/test/handlers/{csv.handler.test.js → csv_handler.test.js} +5 -5
- package/test/handlers/{js.handler.test.js → js_handler.test.js} +2 -2
- package/test/handlers/{ori.handler.test.js → ori_handler.test.js} +8 -8
- package/test/handlers/{oridocument.handler.test.js → oridocument_handler.test.js} +3 -3
- package/test/handlers/sh_handler.test.js +14 -0
- package/test/handlers/tsv_handler.test.js +28 -0
- package/test/handlers/{wasm.handler.test.js → wasm_handler.test.js} +2 -2
- package/test/runtime/OrigamiFileMap.test.js +40 -0
- package/test/runtime/evaluate.test.js +3 -3
- package/test/runtime/expressionObject.test.js +14 -6
- package/test/runtime/handleExtension.test.js +2 -2
- package/test/runtime/mergeTrees.test.js +2 -2
- package/test/runtime/ops.test.js +5 -5
- package/src/runtime/InvokeFunctionsTransform.d.ts +0 -5
- package/src/runtime/InvokeFunctionsTransform.js +0 -25
- package/src/runtime/functionResultsMap.js +0 -17
- package/test/runtime/OrigamiFiles.test.js +0 -35
- package/test/runtime/fixtures/subgraph = this.js +0 -5
- package/test/runtime/functionResultsMap.test.js +0 -20
- /package/test/handlers/{jpeg.handler.test.js → jpeg_handler.test.js} +0 -0
- /package/test/handlers/{json.handler.test.js → json_handler.test.js} +0 -0
- /package/test/handlers/{txt.handler.test.js → txt_handler.test.js} +0 -0
- /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/
|
|
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/
|
|
7
|
-
* @typedef {import("@weborigami/async-tree").Treelike} Treelike
|
|
6
|
+
* @typedef {import("@weborigami/async-tree").Maplike} Maplike
|
|
8
7
|
*
|
|
9
|
-
* @param {(
|
|
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 {
|
|
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 = {};
|
package/src/runtime/ops.js
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
410
|
-
// if (!
|
|
409
|
+
// export function optionalTraverse(maplike, key) {
|
|
410
|
+
// if (!maplike) {
|
|
411
411
|
// return undefined;
|
|
412
412
|
// }
|
|
413
|
-
// return Tree.traverseOrThrow(
|
|
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
|
|
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
|
|
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 {
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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.
|
|
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 {
|
|
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
|
|
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:
|
|
14
|
-
{ name: "Bob", age:
|
|
15
|
-
{ name: 'Carol "CJ"', age:
|
|
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:
|
|
23
|
-
{ name: "Bob", age:
|
|
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 {
|
|
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(
|
|
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 {
|
|
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
|
|
5
|
+
import OrigamiFileMap from "../../src/runtime/OrigamiFileMap.js";
|
|
6
6
|
|
|
7
7
|
const fixturesUrl = new URL("fixtures", import.meta.url);
|
|
8
|
-
const fixtures = new
|
|
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
|
|
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
|
|
47
|
-
const parent = new
|
|
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
|
|
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
|
|
65
|
+
const parent = new ObjectMap({
|
|
66
66
|
name: "Alice",
|
|
67
67
|
});
|
|
68
68
|
const source = `() => \`Hello, \${name}!\``;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
|
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 {
|
|
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(
|
|
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 {
|
|
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/
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
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 {
|
|
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
|
|
45
|
+
new ObjectMap({
|
|
46
46
|
a: 1,
|
|
47
47
|
b: 2,
|
|
48
48
|
}),
|
package/test/runtime/ops.test.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
131
|
+
test("flattens maplike objects", async () => {
|
|
132
132
|
const object = {
|
|
133
133
|
a: 1,
|
|
134
134
|
b: 2,
|
|
135
135
|
};
|
|
136
|
-
const tree = new
|
|
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
|
|
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
|
|
371
|
+
const tree = new DeepObjectMap({
|
|
372
372
|
a: {
|
|
373
373
|
b: {},
|
|
374
374
|
},
|
|
@@ -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
|
-
}
|