@weborigami/language 0.5.8 → 0.6.1

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 (57) hide show
  1. package/index.ts +3 -4
  2. package/main.js +2 -4
  3. package/package.json +4 -5
  4. package/src/compiler/optimize.js +3 -1
  5. package/src/compiler/parserHelpers.js +1 -7
  6. package/src/handlers/csv_handler.js +13 -8
  7. package/src/handlers/getSource.js +36 -0
  8. package/src/handlers/ori_handler.js +5 -20
  9. package/src/handlers/oridocument_handler.js +5 -28
  10. package/src/handlers/tsv_handler.js +10 -1
  11. package/src/handlers/yaml_handler.js +75 -3
  12. package/src/project/jsGlobals.js +5 -1
  13. package/src/project/projectConfig.js +4 -4
  14. package/src/project/projectRoot.js +8 -9
  15. package/src/protocols/constructSiteTree.js +4 -4
  16. package/src/protocols/explore.js +2 -3
  17. package/src/protocols/fetchAndHandleExtension.js +0 -1
  18. package/src/protocols/files.js +2 -3
  19. package/src/protocols/http.js +0 -1
  20. package/src/protocols/https.js +0 -1
  21. package/src/protocols/httpstree.js +2 -3
  22. package/src/protocols/httptree.js +2 -3
  23. package/src/runtime/HandleExtensionsTransform.js +32 -8
  24. package/src/runtime/ImportModulesMixin.js +2 -2
  25. package/src/runtime/{OrigamiFiles.js → OrigamiFileMap.d.ts} +3 -3
  26. package/src/runtime/{OrigamiFiles.d.ts → OrigamiFileMap.js} +3 -5
  27. package/src/runtime/errors.js +9 -2
  28. package/src/runtime/evaluate.js +1 -1
  29. package/src/runtime/expressionFunction.js +3 -3
  30. package/src/runtime/expressionObject.js +19 -8
  31. package/src/runtime/handleExtension.js +2 -11
  32. package/src/runtime/mergeTrees.js +4 -7
  33. package/src/runtime/ops.js +13 -13
  34. package/test/cases/logicalAndExpression.yaml +7 -8
  35. package/test/compiler/compile.test.js +1 -1
  36. package/test/compiler/optimize.test.js +2 -2
  37. package/test/compiler/parse.test.js +13 -19
  38. package/test/generated/logicalAndExpression.test.js +4 -0
  39. package/test/handlers/csv_handler.test.js +5 -5
  40. package/test/handlers/js_handler.test.js +2 -2
  41. package/test/handlers/ori_handler.test.js +8 -8
  42. package/test/handlers/oridocument_handler.test.js +3 -3
  43. package/test/handlers/tsv_handler.test.js +5 -5
  44. package/test/handlers/wasm_handler.test.js +2 -2
  45. package/test/handlers/yaml_handler.test.js +31 -1
  46. package/test/runtime/OrigamiFileMap.test.js +40 -0
  47. package/test/runtime/evaluate.test.js +3 -3
  48. package/test/runtime/expressionObject.test.js +14 -6
  49. package/test/runtime/handleExtension.test.js +2 -9
  50. package/test/runtime/mergeTrees.test.js +2 -2
  51. package/test/runtime/ops.test.js +18 -12
  52. package/src/runtime/InvokeFunctionsTransform.d.ts +0 -5
  53. package/src/runtime/InvokeFunctionsTransform.js +0 -25
  54. package/src/runtime/functionResultsMap.js +0 -17
  55. package/test/runtime/OrigamiFiles.test.js +0 -35
  56. package/test/runtime/fixtures/subgraph = this.js +0 -5
  57. package/test/runtime/functionResultsMap.test.js +0 -20
@@ -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 () => {
@@ -1,3 +1,4 @@
1
+ import { Tree } from "@weborigami/async-tree";
1
2
  import assert from "node:assert";
2
3
  import { describe, test } from "node:test";
3
4
  import yaml_handler from "../../src/handlers/yaml_handler.js";
@@ -8,10 +9,39 @@ describe(".yaml handler", () => {
8
9
  a: 1
9
10
  b: 2
10
11
  `;
11
- const data = yaml_handler.unpack(text);
12
+ const data = await yaml_handler.unpack(text);
12
13
  assert.deepEqual(data, {
13
14
  a: 1,
14
15
  b: 2,
15
16
  });
16
17
  });
18
+
19
+ test("defines !ori tag for Origami expressions", async () => {
20
+ const text = `
21
+ message: Hello
22
+ answer: !ori 1 + 1
23
+ `;
24
+ const data = await yaml_handler.unpack(text);
25
+ const plain = await Tree.plain(data);
26
+ assert.deepEqual(plain, {
27
+ message: "Hello",
28
+ answer: 2,
29
+ });
30
+ });
31
+
32
+ test("defines !ori.call tag for Origami function invocation", async () => {
33
+ const text = `
34
+ message: Hello
35
+ answer: !ori.call
36
+ - (a, b) => a + b
37
+ - 2
38
+ - 3
39
+ `;
40
+ const data = await yaml_handler.unpack(text);
41
+ const plain = await Tree.plain(data);
42
+ assert.deepEqual(plain, {
43
+ message: "Hello",
44
+ answer: 5,
45
+ });
46
+ });
17
47
  });
@@ -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";
@@ -15,17 +15,10 @@ describe("handleExtension", () => {
15
15
  const data = await withHandler.unpack();
16
16
  assert.deepEqual(data, { bar: 2 });
17
17
  });
18
-
19
- test("immediately unpacks if key ends in slash", async () => {
20
- const fixture = createFixture();
21
- const jsonFile = await fixture.get("bar.json");
22
- const data = await handleExtension(jsonFile, "bar.json/", fixture);
23
- assert.deepEqual(data, { bar: 2 });
24
- });
25
18
  });
26
19
 
27
20
  function createFixture() {
28
- return new ObjectTree({
21
+ return new ObjectMap({
29
22
  foo: 1, // No extension, should be left alone
30
23
  "bar.json": `{ "bar": 2 }`,
31
24
  });
@@ -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 { 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,11 +156,14 @@ describe("ops", () => {
156
156
  });
157
157
 
158
158
  test("ops.inherited walks up the object parent chain", async () => {
159
- const tree = new DeepObjectTree({
160
- a: {
161
- b: {},
159
+ const tree = new ObjectMap(
160
+ {
161
+ a: {
162
+ b: {},
163
+ },
162
164
  },
163
- });
165
+ { deep: true }
166
+ );
164
167
  const b = await Tree.traverse(tree, "a", "b");
165
168
  assert.equal(await ops.inherited(2, { object: b }), tree);
166
169
  });
@@ -368,12 +371,15 @@ describe("ops", () => {
368
371
 
369
372
  describe("ops.scope", () => {
370
373
  test("returns the scope of the given tree", async () => {
371
- const tree = new DeepObjectTree({
372
- a: {
373
- b: {},
374
+ const tree = new ObjectMap(
375
+ {
376
+ a: {
377
+ b: {},
378
+ },
379
+ c: 1,
374
380
  },
375
- c: 1,
376
- });
381
+ { deep: true }
382
+ );
377
383
  const a = await tree.get("a");
378
384
  const b = await a.get("b");
379
385
  const scope = await ops.scope(b);
@@ -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
- }
@@ -1,35 +0,0 @@
1
- import assert from "node:assert";
2
- import * as fs from "node:fs/promises";
3
- import path from "node:path";
4
- import { describe, test } from "node:test";
5
- import { fileURLToPath } from "node:url";
6
- import OrigamiFiles from "../../src/runtime/OrigamiFiles.js";
7
-
8
- const dirname = path.dirname(fileURLToPath(import.meta.url));
9
- const tempDirectory = path.join(dirname, "fixtures/temp");
10
-
11
- describe("OrigamiFiles", () => {
12
- test("can watch its folder for changes", { timeout: 2000 }, async () => {
13
- await createTempDirectory();
14
- const tempFiles = new OrigamiFiles(tempDirectory);
15
- const changedFileName = await new Promise(async (resolve) => {
16
- tempFiles.addEventListener("change", (event) => {
17
- resolve(/** @type {any} */ (event).options.key);
18
- });
19
- await tempFiles.set(
20
- "foo.txt",
21
- "This file is left over from testing and can be removed."
22
- );
23
- });
24
- await removeTempDirectory();
25
- assert.equal(changedFileName, "foo.txt");
26
- });
27
- });
28
-
29
- async function createTempDirectory() {
30
- await fs.mkdir(tempDirectory, { recursive: true });
31
- }
32
-
33
- async function removeTempDirectory() {
34
- await fs.rm(tempDirectory, { recursive: true });
35
- }
@@ -1,5 +0,0 @@
1
- import { ObjectTree } from "@weborigami/async-tree";
2
- export default new ObjectTree({
3
- a: "Hello, a.",
4
- b: "Hello, b.",
5
- });
@@ -1,20 +0,0 @@
1
- import { ObjectTree, Tree } from "@weborigami/async-tree";
2
- import assert from "node:assert";
3
- import { describe, test } from "node:test";
4
- import functionResultsMap from "../../src/runtime/functionResultsMap.js";
5
-
6
- describe("functionResultsMap", () => {
7
- test("get() invokes functions, returns other values as is", async () => {
8
- const tree = new ObjectTree({
9
- fn: function () {
10
- return "Hello";
11
- },
12
- string: "string",
13
- });
14
- const fixture = await functionResultsMap(tree);
15
- assert.deepEqual(await Tree.plain(fixture), {
16
- fn: "Hello",
17
- string: "string",
18
- });
19
- });
20
- });