@weborigami/language 0.0.66-beta.1 → 0.0.66-beta.2

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.
@@ -8,7 +8,7 @@ describe("Origami parser", () => {
8
8
  test("absoluteFilePath", () => {
9
9
  assertParse("absoluteFilePath", "/foo/bar", [
10
10
  [ops.filesRoot],
11
- [ops.primitive, "foo"],
11
+ [ops.primitive, "foo/"],
12
12
  [ops.primitive, "bar"],
13
13
  ]);
14
14
  });
@@ -134,11 +134,10 @@ describe("Origami parser", () => {
134
134
  ]
135
135
  );
136
136
 
137
- // Consecutive slahes inside a path = empty string key
137
+ // Consecutive slahes in a path are removed
138
138
  assertParse("expression", "path//key", [
139
139
  ops.traverse,
140
- [ops.scope, "path"],
141
- [ops.primitive, ""],
140
+ [ops.scope, "path/"],
142
141
  [ops.primitive, "key"],
143
142
  ]);
144
143
  // Single slash at start of something = absolute file path
@@ -177,24 +176,27 @@ describe("Origami parser", () => {
177
176
  ]);
178
177
  assertParse("functionComposition", "tree/", [
179
178
  ops.traverse,
180
- [ops.scope, "tree"],
181
- [ops.primitive, ""],
179
+ [ops.scope, "tree/"],
182
180
  ]);
183
181
  assertParse("functionComposition", "tree/key", [
184
182
  ops.traverse,
185
- [ops.scope, "tree"],
183
+ [ops.scope, "tree/"],
186
184
  [ops.primitive, "key"],
187
185
  ]);
188
186
  assertParse("functionComposition", "tree/foo/bar", [
189
187
  ops.traverse,
190
- [ops.scope, "tree"],
191
- [ops.primitive, "foo"],
188
+ [ops.scope, "tree/"],
189
+ [ops.primitive, "foo/"],
192
190
  [ops.primitive, "bar"],
193
191
  ]);
194
192
  assertParse("functionComposition", "tree/key()", [
195
- [ops.traverse, [ops.scope, "tree"], [ops.primitive, "key"]],
193
+ [ops.traverse, [ops.scope, "tree/"], [ops.primitive, "key"]],
196
194
  undefined,
197
195
  ]);
196
+ assertParse("functionComposition", "(tree)/", [
197
+ ops.unpack,
198
+ [ops.scope, "tree"],
199
+ ]);
198
200
  assertParse("functionComposition", "fn()/key()", [
199
201
  [ops.traverse, [[ops.scope, "fn"], undefined], [ops.primitive, "key"]],
200
202
  undefined,
@@ -249,7 +251,7 @@ describe("Origami parser", () => {
249
251
  [ops.primitive, "arg"],
250
252
  ]);
251
253
  assertParse("functionComposition", "tree/key arg", [
252
- [ops.traverse, [ops.scope, "tree"], [ops.primitive, "key"]],
254
+ [ops.traverse, [ops.scope, "tree/"], [ops.primitive, "key"]],
253
255
  [ops.scope, "arg"],
254
256
  ]);
255
257
  assertParse("functionComposition", "https://example.com/tree.yaml 'key'", [
@@ -267,6 +269,7 @@ describe("Origami parser", () => {
267
269
  test("host", () => {
268
270
  assertParse("host", "abc", [ops.primitive, "abc"]);
269
271
  assertParse("host", "abc:123", [ops.primitive, "abc:123"]);
272
+ assertParse("host", "foo\\ bar", [ops.primitive, "foo bar"]);
270
273
  });
271
274
 
272
275
  test("identifier", () => {
@@ -295,10 +298,9 @@ describe("Origami parser", () => {
295
298
  });
296
299
 
297
300
  test("leadingSlashPath", () => {
298
- assertParse("leadingSlashPath", "/tree/", [
299
- [ops.primitive, "tree"],
300
- [ops.primitive, ""],
301
- ]);
301
+ assertParse("leadingSlashPath", "/", []);
302
+ assertParse("leadingSlashPath", "/tree", [[ops.primitive, "tree"]]);
303
+ assertParse("leadingSlashPath", "/tree/", [[ops.primitive, "tree/"]]);
302
304
  });
303
305
 
304
306
  test("list", () => {
@@ -358,16 +360,36 @@ describe("Origami parser", () => {
358
360
  ["a", [ops.primitive, 1]],
359
361
  ["b", [ops.inherited, "b"]],
360
362
  ]);
363
+ assertParse("object", "{ sub: { a: 1 } }", [
364
+ ops.object,
365
+ ["sub", [ops.object, ["a", [ops.primitive, 1]]]],
366
+ ]);
367
+ assertParse("object", "{ sub: { a/: 1 } }", [
368
+ ops.object,
369
+ ["sub", [ops.object, ["a/", [ops.primitive, 1]]]],
370
+ ]);
361
371
  assertParse("object", `{ "a": 1, "b": 2 }`, [
362
372
  ops.object,
363
373
  ["a", [ops.primitive, 1]],
364
374
  ["b", [ops.primitive, 2]],
365
375
  ]);
366
- assertParse("object", "{ a = b, b: 2 }", [
376
+ assertParse("object", "{ a = b, b = 2 }", [
367
377
  ops.object,
368
378
  ["a", [ops.getter, [ops.scope, "b"]]],
369
379
  ["b", [ops.primitive, 2]],
370
380
  ]);
381
+ assertParse("object", "{ a: { b: 1 } }", [
382
+ ops.object,
383
+ ["a", [ops.object, ["b", [ops.primitive, 1]]]],
384
+ ]);
385
+ assertParse("object", "{ a: { b = 1 } }", [
386
+ ops.object,
387
+ ["a", [ops.object, ["b", [ops.primitive, 1]]]],
388
+ ]);
389
+ assertParse("object", "{ a: { b = fn() } }", [
390
+ ops.object,
391
+ ["a/", [ops.object, ["b", [ops.getter, [[ops.scope, "fn"], undefined]]]]],
392
+ ]);
371
393
  assertParse("object", "{ x = fn('a') }", [
372
394
  ops.object,
373
395
  [
@@ -429,6 +451,12 @@ describe("Origami parser", () => {
429
451
  ]);
430
452
  });
431
453
 
454
+ test("objectPublicKey", () => {
455
+ assertParse("objectPublicKey", "a", "a", false);
456
+ assertParse("objectPublicKey", "markdown/", "markdown/", false);
457
+ assertParse("objectPublicKey", "foo\\ bar", "foo bar", false);
458
+ });
459
+
432
460
  test("parameterizedLambda", () => {
433
461
  assertParse("parameterizedLambda", "() => foo", [
434
462
  ops.lambda,
@@ -470,19 +498,20 @@ describe("Origami parser", () => {
470
498
  });
471
499
 
472
500
  test("path", () => {
473
- assertParse("path", "tree/", [
474
- [ops.primitive, "tree"],
475
- [ops.primitive, ""],
476
- ]);
501
+ assertParse("path", "tree/", [[ops.primitive, "tree/"]]);
477
502
  assertParse("path", "month/12", [
478
- [ops.primitive, "month"],
503
+ [ops.primitive, "month/"],
479
504
  [ops.primitive, "12"],
480
505
  ]);
481
506
  assertParse("path", "tree/foo/bar", [
482
- [ops.primitive, "tree"],
483
- [ops.primitive, "foo"],
507
+ [ops.primitive, "tree/"],
508
+ [ops.primitive, "foo/"],
484
509
  [ops.primitive, "bar"],
485
510
  ]);
511
+ assertParse("path", "a///b", [
512
+ [ops.primitive, "a/"],
513
+ [ops.primitive, "b"],
514
+ ]);
486
515
  });
487
516
 
488
517
  test("pipeline", () => {
@@ -514,8 +543,7 @@ describe("Origami parser", () => {
514
543
  assertParse("protocolCall", "https://example.com/foo/", [
515
544
  ops.https,
516
545
  [ops.primitive, "example.com"],
517
- [ops.primitive, "foo"],
518
- [ops.primitive, ""],
546
+ [ops.primitive, "foo/"],
519
547
  ]);
520
548
  assertParse("protocolCall", "http:example.com", [
521
549
  ops.http,
@@ -528,6 +556,25 @@ describe("Origami parser", () => {
528
556
  ]);
529
557
  });
530
558
 
559
+ test("scopeReference", () => {
560
+ assertParse("scopeReference", "x", [ops.scope, "x"]);
561
+ });
562
+
563
+ test("scopeTraverse", () => {
564
+ assertParse("scopeTraverse", "tree/foo/bar", [
565
+ ops.traverse,
566
+ [ops.scope, "tree/"],
567
+ [ops.primitive, "foo/"],
568
+ [ops.primitive, "bar"],
569
+ ]);
570
+ assertParse("scopeTraverse", "tree/foo/bar/", [
571
+ ops.traverse,
572
+ [ops.scope, "tree/"],
573
+ [ops.primitive, "foo/"],
574
+ [ops.primitive, "bar/"],
575
+ ]);
576
+ });
577
+
531
578
  test("shebang", () => {
532
579
  assertParse(
533
580
  "expression",
@@ -543,10 +590,6 @@ describe("Origami parser", () => {
543
590
  assertParse("singleLineComment", "// Hello, world!", null, false);
544
591
  });
545
592
 
546
- test("scopeReference", () => {
547
- assertParse("scopeReference", "x", [ops.scope, "x"]);
548
- });
549
-
550
593
  test("spread", () => {
551
594
  assertParse("spread", "...a", [ops.spread, [ops.scope, "a"]]);
552
595
  assertParse("spread", "…a", [ops.spread, [ops.scope, "a"]]);
@@ -1,7 +1,7 @@
1
1
  import { ObjectTree } from "@weborigami/async-tree";
2
2
  import assert from "node:assert";
3
3
  import { describe, test } from "node:test";
4
- import { attachHandlerIfApplicable } from "../../src/runtime/extensions.js";
4
+ import { handleExtension } from "../../src/runtime/extensions.js";
5
5
 
6
6
  describe("extensions", () => {
7
7
  test("attaches an unpack method to a value with an extension", async () => {
@@ -10,15 +10,18 @@ describe("extensions", () => {
10
10
  assert(typeof numberValue === "number");
11
11
  assert.equal(numberValue, 1);
12
12
  const jsonFile = await fixture.get("bar.json");
13
- const withHandler = await attachHandlerIfApplicable(
14
- fixture,
15
- jsonFile,
16
- "bar.json"
17
- );
13
+ const withHandler = await handleExtension(fixture, jsonFile, "bar.json");
18
14
  assert.equal(String(withHandler), `{ "bar": 2 }`);
19
15
  const data = await withHandler.unpack();
20
16
  assert.deepEqual(data, { bar: 2 });
21
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(fixture, jsonFile, "bar.json/");
23
+ assert.deepEqual(data, { bar: 2 });
24
+ });
22
25
  });
23
26
 
24
27
  function createFixture() {
@@ -5,7 +5,7 @@ import { describe, test } from "node:test";
5
5
  import { evaluate, ops } from "../../src/runtime/internal.js";
6
6
 
7
7
  describe("ops", () => {
8
- test("can resolve substitutions in a template literal", async () => {
8
+ test("ops.concat concatenates tree value text", async () => {
9
9
  const scope = new ObjectTree({
10
10
  name: "world",
11
11
  });
@@ -16,7 +16,33 @@ describe("ops", () => {
16
16
  assert.equal(result, "Hello, world.");
17
17
  });
18
18
 
19
- test("can invoke a lambda", async () => {
19
+ test("ops.constructor returns a constructor", async () => {
20
+ const scope = new ObjectTree({
21
+ "@js": {
22
+ Number: Number,
23
+ },
24
+ });
25
+ const fn = await ops.constructor.call(scope, "@js", "Number");
26
+ const number = fn("1");
27
+ assert(number instanceof Number);
28
+ assert.equal(number, 1);
29
+ });
30
+
31
+ test("ops.inherited searches inherited scope", async () => {
32
+ const parent = new ObjectTree({
33
+ a: 1, // This is the inherited value we want
34
+ });
35
+ /** @type {any} */
36
+ const child = new ObjectTree({
37
+ a: 2, // Should be ignored
38
+ });
39
+ child.parent = parent;
40
+ const code = createCode([ops.inherited, "a"]);
41
+ const result = await evaluate.call(child, code);
42
+ assert.equal(result, 1);
43
+ });
44
+
45
+ test("ops.lambda defines a function", async () => {
20
46
  const scope = new ObjectTree({
21
47
  message: "Hello",
22
48
  });
@@ -28,14 +54,14 @@ describe("ops", () => {
28
54
  assert.equal(result, "Hello");
29
55
  });
30
56
 
31
- test("lambda adds input to scope as `_`", async () => {
57
+ test("ops.lambda adds input to scope as `_`", async () => {
32
58
  const code = createCode([ops.lambda, null, [ops.scope, "_"]]);
33
59
  const fn = await evaluate.call(null, code);
34
60
  const result = await fn("Hello");
35
61
  assert.equal(result, "Hello");
36
62
  });
37
63
 
38
- test("parameterized lambda adds input args to scope", async () => {
64
+ test("ops.lambda adds input parameters to scope", async () => {
39
65
  const code = createCode([
40
66
  ops.lambda,
41
67
  ["a", "b"],
@@ -46,7 +72,7 @@ describe("ops", () => {
46
72
  assert.equal(result, "yx");
47
73
  });
48
74
 
49
- test("a lambda can reference itself with @recurse", async () => {
75
+ test("ops.lambda function can reference itself with @recurse", async () => {
50
76
  const code = createCode([ops.lambda, null, [ops.scope, "@recurse"]]);
51
77
  const fn = await evaluate.call(null, code);
52
78
  const result = await fn();
@@ -55,7 +81,7 @@ describe("ops", () => {
55
81
  assert.equal(result.code, fn.code);
56
82
  });
57
83
 
58
- test("can instantiate an object", async () => {
84
+ test("ops.object instantiates an object", async () => {
59
85
  const scope = new ObjectTree({
60
86
  upper: (s) => s.toUpperCase(),
61
87
  });
@@ -71,7 +97,7 @@ describe("ops", () => {
71
97
  assert.equal(result.world, "WORLD");
72
98
  });
73
99
 
74
- test("can instantiate an array", async () => {
100
+ test("ops.object instantiates an array", async () => {
75
101
  const scope = new ObjectTree({
76
102
  upper: (s) => s.toUpperCase(),
77
103
  });
@@ -85,30 +111,11 @@ describe("ops", () => {
85
111
  assert.deepEqual(result, ["Hello", 1, "WORLD"]);
86
112
  });
87
113
 
88
- test("can search inherited scope", async () => {
89
- const parent = new ObjectTree({
90
- a: 1, // This is the inherited value we want
91
- });
92
- /** @type {any} */
93
- const child = new ObjectTree({
94
- a: 2, // Should be ignored
95
- });
96
- child.parent = parent;
97
- const code = createCode([ops.inherited, "a"]);
98
- const result = await evaluate.call(child, code);
99
- assert.equal(result, 1);
100
- });
101
-
102
- test("returns a constructor", async () => {
103
- const scope = new ObjectTree({
104
- "@js": {
105
- Number: Number,
106
- },
107
- });
108
- const fn = await ops.constructor.call(scope, "@js", "Number");
109
- const number = fn("1");
110
- assert(number instanceof Number);
111
- assert.equal(number, 1);
114
+ test("ops.unpack unpacks a value", async () => {
115
+ const fixture = new String("packed");
116
+ /** @type {any} */ (fixture).unpack = async () => "unpacked";
117
+ const result = await ops.unpack.call(null, fixture);
118
+ assert.equal(result, "unpacked");
112
119
  });
113
120
  });
114
121