@weborigami/language 0.0.68 → 0.0.70
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/main.js +2 -0
- package/package.json +3 -3
- package/src/compiler/compile.js +1 -40
- package/src/compiler/origami.pegjs +41 -28
- package/src/compiler/parse.js +287 -193
- package/src/compiler/parserHelpers.js +51 -28
- package/src/runtime/WatchFilesMixin.js +1 -0
- package/src/runtime/evaluate.js +15 -15
- package/src/runtime/ops.js +54 -38
- package/src/runtime/symbols.js +3 -0
- package/src/runtime/taggedTemplate.js +9 -0
- package/test/compiler/compile.test.js +21 -0
- package/test/compiler/parse.test.js +160 -171
- package/test/runtime/taggedTemplate.test.js +10 -0
|
@@ -8,8 +8,8 @@ describe("Origami parser", () => {
|
|
|
8
8
|
test("absoluteFilePath", () => {
|
|
9
9
|
assertParse("absoluteFilePath", "/foo/bar", [
|
|
10
10
|
[ops.filesRoot],
|
|
11
|
-
[ops.
|
|
12
|
-
[ops.
|
|
11
|
+
[ops.literal, "foo/"],
|
|
12
|
+
[ops.literal, "bar"],
|
|
13
13
|
]);
|
|
14
14
|
});
|
|
15
15
|
|
|
@@ -17,20 +17,20 @@ describe("Origami parser", () => {
|
|
|
17
17
|
assertParse("array", "[]", [ops.array]);
|
|
18
18
|
assertParse("array", "[1, 2, 3]", [
|
|
19
19
|
ops.array,
|
|
20
|
-
[ops.
|
|
21
|
-
[ops.
|
|
22
|
-
[ops.
|
|
20
|
+
[ops.literal, 1],
|
|
21
|
+
[ops.literal, 2],
|
|
22
|
+
[ops.literal, 3],
|
|
23
23
|
]);
|
|
24
24
|
assertParse("array", "[ 1 , 2 , 3 ]", [
|
|
25
25
|
ops.array,
|
|
26
|
-
[ops.
|
|
27
|
-
[ops.
|
|
28
|
-
[ops.
|
|
26
|
+
[ops.literal, 1],
|
|
27
|
+
[ops.literal, 2],
|
|
28
|
+
[ops.literal, 3],
|
|
29
29
|
]);
|
|
30
30
|
assertParse("array", "[ 1, ...[2, 3]]", [
|
|
31
31
|
ops.merge,
|
|
32
|
-
[ops.array, [ops.
|
|
33
|
-
[ops.array, [ops.
|
|
32
|
+
[ops.array, [ops.literal, 1]],
|
|
33
|
+
[ops.array, [ops.literal, 2], [ops.literal, 3]],
|
|
34
34
|
]);
|
|
35
35
|
});
|
|
36
36
|
|
|
@@ -44,26 +44,26 @@ describe("Origami parser", () => {
|
|
|
44
44
|
]);
|
|
45
45
|
assertParse("expr", "foo.bar('hello', 'world')", [
|
|
46
46
|
[ops.scope, "foo.bar"],
|
|
47
|
-
[ops.
|
|
48
|
-
[ops.
|
|
47
|
+
[ops.literal, "hello"],
|
|
48
|
+
[ops.literal, "world"],
|
|
49
49
|
]);
|
|
50
50
|
assertParse("expr", "(fn)('a')", [
|
|
51
51
|
[ops.scope, "fn"],
|
|
52
|
-
[ops.
|
|
52
|
+
[ops.literal, "a"],
|
|
53
53
|
]);
|
|
54
|
-
assertParse("expr", "1", [ops.
|
|
54
|
+
assertParse("expr", "1", [ops.literal, 1]);
|
|
55
55
|
assertParse("expr", "{ a: 1, b: 2 }", [
|
|
56
56
|
ops.object,
|
|
57
|
-
["a", [ops.
|
|
58
|
-
["b", [ops.
|
|
57
|
+
["a", [ops.literal, 1]],
|
|
58
|
+
["b", [ops.literal, 2]],
|
|
59
59
|
]);
|
|
60
60
|
assertParse("expr", "serve { index.html: 'hello' }", [
|
|
61
61
|
[ops.scope, "serve"],
|
|
62
|
-
[ops.object, ["index.html", [ops.
|
|
62
|
+
[ops.object, ["index.html", [ops.literal, "hello"]]],
|
|
63
63
|
]);
|
|
64
64
|
assertParse("expr", "fn =`x`", [
|
|
65
65
|
[ops.scope, "fn"],
|
|
66
|
-
[ops.lambda, null, [ops.
|
|
66
|
+
[ops.lambda, null, [ops.template, [ops.literal, ["x"]]]],
|
|
67
67
|
]);
|
|
68
68
|
assertParse("expr", "copy app(formulas), files 'snapshot'", [
|
|
69
69
|
[ops.scope, "copy"],
|
|
@@ -73,7 +73,7 @@ describe("Origami parser", () => {
|
|
|
73
73
|
],
|
|
74
74
|
[
|
|
75
75
|
[ops.scope, "files"],
|
|
76
|
-
[ops.
|
|
76
|
+
[ops.literal, "snapshot"],
|
|
77
77
|
],
|
|
78
78
|
]);
|
|
79
79
|
assertParse("expr", "@map =`<li>${_}</li>`", [
|
|
@@ -82,20 +82,24 @@ describe("Origami parser", () => {
|
|
|
82
82
|
ops.lambda,
|
|
83
83
|
null,
|
|
84
84
|
[
|
|
85
|
-
ops.
|
|
86
|
-
[ops.
|
|
87
|
-
[ops.scope, "_"],
|
|
88
|
-
[ops.primitive, "</li>"],
|
|
85
|
+
ops.template,
|
|
86
|
+
[ops.literal, ["<li>", "</li>"]],
|
|
87
|
+
[ops.concat, [ops.scope, "_"]],
|
|
89
88
|
],
|
|
90
89
|
],
|
|
91
90
|
]);
|
|
92
91
|
assertParse("expr", `"https://example.com"`, [
|
|
93
|
-
ops.
|
|
92
|
+
ops.literal,
|
|
94
93
|
"https://example.com",
|
|
95
94
|
]);
|
|
96
95
|
assertParse("expr", "'Hello' -> test.orit", [
|
|
97
96
|
[ops.scope, "test.orit"],
|
|
98
|
-
[ops.
|
|
97
|
+
[ops.literal, "Hello"],
|
|
98
|
+
]);
|
|
99
|
+
assertParse("expr", "tag`Hello, ${name}!`", [
|
|
100
|
+
[ops.scope, "tag"],
|
|
101
|
+
[ops.literal, ["Hello, ", "!"]],
|
|
102
|
+
[ops.concat, [ops.scope, "name"]],
|
|
99
103
|
]);
|
|
100
104
|
});
|
|
101
105
|
|
|
@@ -138,12 +142,12 @@ describe("Origami parser", () => {
|
|
|
138
142
|
assertParse("expression", "path//key", [
|
|
139
143
|
ops.traverse,
|
|
140
144
|
[ops.scope, "path/"],
|
|
141
|
-
[ops.
|
|
145
|
+
[ops.literal, "key"],
|
|
142
146
|
]);
|
|
143
147
|
// Single slash at start of something = absolute file path
|
|
144
148
|
assertParse("expression", "/path", [
|
|
145
149
|
[ops.filesRoot],
|
|
146
|
-
[ops.
|
|
150
|
+
[ops.literal, "path"],
|
|
147
151
|
]);
|
|
148
152
|
// Consecutive slashes at start of something = comment
|
|
149
153
|
assertParse("expression", "path //comment", [ops.scope, "path"], false);
|
|
@@ -172,25 +176,10 @@ describe("Origami parser", () => {
|
|
|
172
176
|
assertParse("functionComposition", "fn()/key", [
|
|
173
177
|
ops.traverse,
|
|
174
178
|
[[ops.scope, "fn"], undefined],
|
|
175
|
-
[ops.
|
|
176
|
-
]);
|
|
177
|
-
assertParse("functionComposition", "tree/", [
|
|
178
|
-
ops.traverse,
|
|
179
|
-
[ops.scope, "tree/"],
|
|
180
|
-
]);
|
|
181
|
-
assertParse("functionComposition", "tree/key", [
|
|
182
|
-
ops.traverse,
|
|
183
|
-
[ops.scope, "tree/"],
|
|
184
|
-
[ops.primitive, "key"],
|
|
185
|
-
]);
|
|
186
|
-
assertParse("functionComposition", "tree/foo/bar", [
|
|
187
|
-
ops.traverse,
|
|
188
|
-
[ops.scope, "tree/"],
|
|
189
|
-
[ops.primitive, "foo/"],
|
|
190
|
-
[ops.primitive, "bar"],
|
|
179
|
+
[ops.literal, "key"],
|
|
191
180
|
]);
|
|
192
181
|
assertParse("functionComposition", "tree/key()", [
|
|
193
|
-
[ops.traverse, [ops.scope, "tree/"], [ops.
|
|
182
|
+
[ops.traverse, [ops.scope, "tree/"], [ops.literal, "key"]],
|
|
194
183
|
undefined,
|
|
195
184
|
]);
|
|
196
185
|
assertParse("functionComposition", "(tree)/", [
|
|
@@ -198,19 +187,19 @@ describe("Origami parser", () => {
|
|
|
198
187
|
[ops.scope, "tree"],
|
|
199
188
|
]);
|
|
200
189
|
assertParse("functionComposition", "fn()/key()", [
|
|
201
|
-
[ops.traverse, [[ops.scope, "fn"], undefined], [ops.
|
|
190
|
+
[ops.traverse, [[ops.scope, "fn"], undefined], [ops.literal, "key"]],
|
|
202
191
|
undefined,
|
|
203
192
|
]);
|
|
204
193
|
assertParse("functionComposition", "(fn())('arg')", [
|
|
205
194
|
[[ops.scope, "fn"], undefined],
|
|
206
|
-
[ops.
|
|
195
|
+
[ops.literal, "arg"],
|
|
207
196
|
]);
|
|
208
197
|
assertParse("functionComposition", "fn('a')('b')", [
|
|
209
198
|
[
|
|
210
199
|
[ops.scope, "fn"],
|
|
211
|
-
[ops.
|
|
200
|
+
[ops.literal, "a"],
|
|
212
201
|
],
|
|
213
|
-
[ops.
|
|
202
|
+
[ops.literal, "b"],
|
|
214
203
|
]);
|
|
215
204
|
assertParse("functionComposition", "(fn())(a, b)", [
|
|
216
205
|
[[ops.scope, "fn"], undefined],
|
|
@@ -219,8 +208,8 @@ describe("Origami parser", () => {
|
|
|
219
208
|
]);
|
|
220
209
|
assertParse("functionComposition", "{ a: 1, b: 2}/b", [
|
|
221
210
|
ops.traverse,
|
|
222
|
-
[ops.object, ["a", [ops.
|
|
223
|
-
[ops.
|
|
211
|
+
[ops.object, ["a", [ops.literal, 1]], ["b", [ops.literal, 2]]],
|
|
212
|
+
[ops.literal, "b"],
|
|
224
213
|
]);
|
|
225
214
|
assertParse("functionComposition", "fn arg", [
|
|
226
215
|
[ops.scope, "fn"],
|
|
@@ -228,8 +217,8 @@ describe("Origami parser", () => {
|
|
|
228
217
|
]);
|
|
229
218
|
assertParse("functionComposition", "fn 'a', 'b'", [
|
|
230
219
|
[ops.scope, "fn"],
|
|
231
|
-
[ops.
|
|
232
|
-
[ops.
|
|
220
|
+
[ops.literal, "a"],
|
|
221
|
+
[ops.literal, "b"],
|
|
233
222
|
]);
|
|
234
223
|
assertParse("functionComposition", "fn a(b), c", [
|
|
235
224
|
[ops.scope, "fn"],
|
|
@@ -243,20 +232,20 @@ describe("Origami parser", () => {
|
|
|
243
232
|
[ops.scope, "fn1"],
|
|
244
233
|
[
|
|
245
234
|
[ops.scope, "fn2"],
|
|
246
|
-
[ops.
|
|
235
|
+
[ops.literal, "arg"],
|
|
247
236
|
],
|
|
248
237
|
]);
|
|
249
238
|
assertParse("functionComposition", "(fn()) 'arg'", [
|
|
250
239
|
[[ops.scope, "fn"], undefined],
|
|
251
|
-
[ops.
|
|
240
|
+
[ops.literal, "arg"],
|
|
252
241
|
]);
|
|
253
242
|
assertParse("functionComposition", "tree/key arg", [
|
|
254
|
-
[ops.traverse, [ops.scope, "tree/"], [ops.
|
|
243
|
+
[ops.traverse, [ops.scope, "tree/"], [ops.literal, "key"]],
|
|
255
244
|
[ops.scope, "arg"],
|
|
256
245
|
]);
|
|
257
246
|
assertParse("functionComposition", "https://example.com/tree.yaml 'key'", [
|
|
258
|
-
[ops.https, [ops.
|
|
259
|
-
[ops.
|
|
247
|
+
[ops.https, [ops.literal, "example.com"], [ops.literal, "tree.yaml"]],
|
|
248
|
+
[ops.literal, "key"],
|
|
260
249
|
]);
|
|
261
250
|
});
|
|
262
251
|
|
|
@@ -267,9 +256,9 @@ describe("Origami parser", () => {
|
|
|
267
256
|
});
|
|
268
257
|
|
|
269
258
|
test("host", () => {
|
|
270
|
-
assertParse("host", "abc", [ops.
|
|
271
|
-
assertParse("host", "abc:123", [ops.
|
|
272
|
-
assertParse("host", "foo\\ bar", [ops.
|
|
259
|
+
assertParse("host", "abc", [ops.literal, "abc"]);
|
|
260
|
+
assertParse("host", "abc:123", [ops.literal, "abc:123"]);
|
|
261
|
+
assertParse("host", "foo\\ bar", [ops.literal, "foo bar"]);
|
|
273
262
|
});
|
|
274
263
|
|
|
275
264
|
test("identifier", () => {
|
|
@@ -289,46 +278,45 @@ describe("Origami parser", () => {
|
|
|
289
278
|
ops.lambda,
|
|
290
279
|
null,
|
|
291
280
|
[
|
|
292
|
-
ops.
|
|
293
|
-
[ops.
|
|
294
|
-
[ops.scope, "name"],
|
|
295
|
-
[ops.primitive, "."],
|
|
281
|
+
ops.template,
|
|
282
|
+
[ops.literal, ["Hello, ", "."]],
|
|
283
|
+
[ops.concat, [ops.scope, "name"]],
|
|
296
284
|
],
|
|
297
285
|
]);
|
|
298
286
|
});
|
|
299
287
|
|
|
300
288
|
test("leadingSlashPath", () => {
|
|
301
289
|
assertParse("leadingSlashPath", "/", []);
|
|
302
|
-
assertParse("leadingSlashPath", "/tree", [[ops.
|
|
303
|
-
assertParse("leadingSlashPath", "/tree/", [[ops.
|
|
290
|
+
assertParse("leadingSlashPath", "/tree", [[ops.literal, "tree"]]);
|
|
291
|
+
assertParse("leadingSlashPath", "/tree/", [[ops.literal, "tree/"]]);
|
|
304
292
|
});
|
|
305
293
|
|
|
306
294
|
test("list", () => {
|
|
307
|
-
assertParse("list", "1", [[ops.
|
|
295
|
+
assertParse("list", "1", [[ops.literal, 1]]);
|
|
308
296
|
assertParse("list", "1,2,3", [
|
|
309
|
-
[ops.
|
|
310
|
-
[ops.
|
|
311
|
-
[ops.
|
|
297
|
+
[ops.literal, 1],
|
|
298
|
+
[ops.literal, 2],
|
|
299
|
+
[ops.literal, 3],
|
|
312
300
|
]);
|
|
313
301
|
assertParse("list", "1, 2, 3,", [
|
|
314
|
-
[ops.
|
|
315
|
-
[ops.
|
|
316
|
-
[ops.
|
|
302
|
+
[ops.literal, 1],
|
|
303
|
+
[ops.literal, 2],
|
|
304
|
+
[ops.literal, 3],
|
|
317
305
|
]);
|
|
318
306
|
assertParse("list", "1 , 2 , 3", [
|
|
319
|
-
[ops.
|
|
320
|
-
[ops.
|
|
321
|
-
[ops.
|
|
307
|
+
[ops.literal, 1],
|
|
308
|
+
[ops.literal, 2],
|
|
309
|
+
[ops.literal, 3],
|
|
322
310
|
]);
|
|
323
311
|
assertParse("list", "1\n2\n3", [
|
|
324
|
-
[ops.
|
|
325
|
-
[ops.
|
|
326
|
-
[ops.
|
|
312
|
+
[ops.literal, 1],
|
|
313
|
+
[ops.literal, 2],
|
|
314
|
+
[ops.literal, 3],
|
|
327
315
|
]);
|
|
328
316
|
assertParse("list", "'a' , 'b' , 'c'", [
|
|
329
|
-
[ops.
|
|
330
|
-
[ops.
|
|
331
|
-
[ops.
|
|
317
|
+
[ops.literal, "a"],
|
|
318
|
+
[ops.literal, "b"],
|
|
319
|
+
[ops.literal, "c"],
|
|
332
320
|
]);
|
|
333
321
|
});
|
|
334
322
|
|
|
@@ -338,53 +326,53 @@ describe("Origami parser", () => {
|
|
|
338
326
|
|
|
339
327
|
test("new", () => {
|
|
340
328
|
assertParse("expression", "new:@js/Date('2025-01-01')", [
|
|
341
|
-
[ops.constructor, [ops.
|
|
342
|
-
[ops.
|
|
329
|
+
[ops.constructor, [ops.literal, "@js"], [ops.literal, "Date"]],
|
|
330
|
+
[ops.literal, "2025-01-01"],
|
|
343
331
|
]);
|
|
344
332
|
});
|
|
345
333
|
|
|
346
334
|
test("number", () => {
|
|
347
|
-
assertParse("number", "123", [ops.
|
|
348
|
-
assertParse("number", "-456", [ops.
|
|
349
|
-
assertParse("number", ".5", [ops.
|
|
350
|
-
assertParse("number", "123.45", [ops.
|
|
351
|
-
assertParse("number", "-678.90", [ops.
|
|
352
|
-
assertParse("number", "+123", [ops.
|
|
353
|
-
assertParse("number", "+456.78", [ops.
|
|
335
|
+
assertParse("number", "123", [ops.literal, 123]);
|
|
336
|
+
assertParse("number", "-456", [ops.literal, -456]);
|
|
337
|
+
assertParse("number", ".5", [ops.literal, 0.5]);
|
|
338
|
+
assertParse("number", "123.45", [ops.literal, 123.45]);
|
|
339
|
+
assertParse("number", "-678.90", [ops.literal, -678.9]);
|
|
340
|
+
assertParse("number", "+123", [ops.literal, 123]);
|
|
341
|
+
assertParse("number", "+456.78", [ops.literal, 456.78]);
|
|
354
342
|
});
|
|
355
343
|
|
|
356
344
|
test("object", () => {
|
|
357
345
|
assertParse("object", "{}", [ops.object]);
|
|
358
346
|
assertParse("object", "{ a: 1, b }", [
|
|
359
347
|
ops.object,
|
|
360
|
-
["a", [ops.
|
|
348
|
+
["a", [ops.literal, 1]],
|
|
361
349
|
["b", [ops.inherited, "b"]],
|
|
362
350
|
]);
|
|
363
351
|
assertParse("object", "{ sub: { a: 1 } }", [
|
|
364
352
|
ops.object,
|
|
365
|
-
["sub", [ops.object, ["a", [ops.
|
|
353
|
+
["sub", [ops.object, ["a", [ops.literal, 1]]]],
|
|
366
354
|
]);
|
|
367
355
|
assertParse("object", "{ sub: { a/: 1 } }", [
|
|
368
356
|
ops.object,
|
|
369
|
-
["sub", [ops.object, ["a/", [ops.
|
|
357
|
+
["sub", [ops.object, ["a/", [ops.literal, 1]]]],
|
|
370
358
|
]);
|
|
371
359
|
assertParse("object", `{ "a": 1, "b": 2 }`, [
|
|
372
360
|
ops.object,
|
|
373
|
-
["a", [ops.
|
|
374
|
-
["b", [ops.
|
|
361
|
+
["a", [ops.literal, 1]],
|
|
362
|
+
["b", [ops.literal, 2]],
|
|
375
363
|
]);
|
|
376
364
|
assertParse("object", "{ a = b, b = 2 }", [
|
|
377
365
|
ops.object,
|
|
378
366
|
["a", [ops.getter, [ops.scope, "b"]]],
|
|
379
|
-
["b", [ops.
|
|
367
|
+
["b", [ops.literal, 2]],
|
|
380
368
|
]);
|
|
381
369
|
assertParse("object", "{ a: { b: 1 } }", [
|
|
382
370
|
ops.object,
|
|
383
|
-
["a", [ops.object, ["b", [ops.
|
|
371
|
+
["a", [ops.object, ["b", [ops.literal, 1]]]],
|
|
384
372
|
]);
|
|
385
373
|
assertParse("object", "{ a: { b = 1 } }", [
|
|
386
374
|
ops.object,
|
|
387
|
-
["a", [ops.object, ["b", [ops.
|
|
375
|
+
["a", [ops.object, ["b", [ops.literal, 1]]]],
|
|
388
376
|
]);
|
|
389
377
|
assertParse("object", "{ a: { b = fn() } }", [
|
|
390
378
|
ops.object,
|
|
@@ -398,25 +386,26 @@ describe("Origami parser", () => {
|
|
|
398
386
|
ops.getter,
|
|
399
387
|
[
|
|
400
388
|
[ops.scope, "fn"],
|
|
401
|
-
[ops.
|
|
389
|
+
[ops.literal, "a"],
|
|
402
390
|
],
|
|
403
391
|
],
|
|
404
392
|
],
|
|
405
393
|
]);
|
|
406
394
|
assertParse("object", "{ a: 1, ...b }", [
|
|
407
395
|
ops.merge,
|
|
408
|
-
[ops.object, ["a", [ops.
|
|
396
|
+
[ops.object, ["a", [ops.literal, 1]]],
|
|
409
397
|
[ops.scope, "b"],
|
|
410
398
|
]);
|
|
411
399
|
assertParse("object", "{ (a): 1 }", [
|
|
412
400
|
ops.object,
|
|
413
|
-
["(a)", [ops.
|
|
401
|
+
["(a)", [ops.literal, 1]],
|
|
414
402
|
]);
|
|
415
403
|
});
|
|
416
404
|
|
|
417
405
|
test("objectEntry", () => {
|
|
418
406
|
assertParse("objectEntry", "foo", ["foo", [ops.inherited, "foo"]]);
|
|
419
407
|
assertParse("objectEntry", "x: y", ["x", [ops.scope, "y"]]);
|
|
408
|
+
assertParse("objectEntry", "a: a", ["a", [ops.inherited, "a"]]);
|
|
420
409
|
});
|
|
421
410
|
|
|
422
411
|
test("objectGetter", () => {
|
|
@@ -430,23 +419,23 @@ describe("Origami parser", () => {
|
|
|
430
419
|
ops.getter,
|
|
431
420
|
[
|
|
432
421
|
[ops.scope, "fn"],
|
|
433
|
-
[ops.
|
|
422
|
+
[ops.literal, "bar"],
|
|
434
423
|
],
|
|
435
424
|
],
|
|
436
425
|
]);
|
|
437
426
|
});
|
|
438
427
|
|
|
439
428
|
test("objectProperty", () => {
|
|
440
|
-
assertParse("objectProperty", "a: 1", ["a", [ops.
|
|
429
|
+
assertParse("objectProperty", "a: 1", ["a", [ops.literal, 1]]);
|
|
441
430
|
assertParse("objectProperty", "name: 'Alice'", [
|
|
442
431
|
"name",
|
|
443
|
-
[ops.
|
|
432
|
+
[ops.literal, "Alice"],
|
|
444
433
|
]);
|
|
445
434
|
assertParse("objectProperty", "x: fn('a')", [
|
|
446
435
|
"x",
|
|
447
436
|
[
|
|
448
437
|
[ops.scope, "fn"],
|
|
449
|
-
[ops.
|
|
438
|
+
[ops.literal, "a"],
|
|
450
439
|
],
|
|
451
440
|
]);
|
|
452
441
|
});
|
|
@@ -498,19 +487,19 @@ describe("Origami parser", () => {
|
|
|
498
487
|
});
|
|
499
488
|
|
|
500
489
|
test("path", () => {
|
|
501
|
-
assertParse("path", "tree/", [[ops.
|
|
490
|
+
assertParse("path", "tree/", [[ops.literal, "tree/"]]);
|
|
502
491
|
assertParse("path", "month/12", [
|
|
503
|
-
[ops.
|
|
504
|
-
[ops.
|
|
492
|
+
[ops.literal, "month/"],
|
|
493
|
+
[ops.literal, "12"],
|
|
505
494
|
]);
|
|
506
495
|
assertParse("path", "tree/foo/bar", [
|
|
507
|
-
[ops.
|
|
508
|
-
[ops.
|
|
509
|
-
[ops.
|
|
496
|
+
[ops.literal, "tree/"],
|
|
497
|
+
[ops.literal, "foo/"],
|
|
498
|
+
[ops.literal, "bar"],
|
|
510
499
|
]);
|
|
511
500
|
assertParse("path", "a///b", [
|
|
512
|
-
[ops.
|
|
513
|
-
[ops.
|
|
501
|
+
[ops.literal, "a/"],
|
|
502
|
+
[ops.literal, "b"],
|
|
514
503
|
]);
|
|
515
504
|
});
|
|
516
505
|
|
|
@@ -538,21 +527,21 @@ describe("Origami parser", () => {
|
|
|
538
527
|
test("protocolCall", () => {
|
|
539
528
|
assertParse("protocolCall", "foo://bar", [
|
|
540
529
|
[ops.scope, "foo"],
|
|
541
|
-
[ops.
|
|
530
|
+
[ops.literal, "bar"],
|
|
542
531
|
]);
|
|
543
532
|
assertParse("protocolCall", "https://example.com/foo/", [
|
|
544
533
|
ops.https,
|
|
545
|
-
[ops.
|
|
546
|
-
[ops.
|
|
534
|
+
[ops.literal, "example.com"],
|
|
535
|
+
[ops.literal, "foo/"],
|
|
547
536
|
]);
|
|
548
537
|
assertParse("protocolCall", "http:example.com", [
|
|
549
538
|
ops.http,
|
|
550
|
-
[ops.
|
|
539
|
+
[ops.literal, "example.com"],
|
|
551
540
|
]);
|
|
552
541
|
assertParse("protocolCall", "http://localhost:5000/foo", [
|
|
553
542
|
ops.http,
|
|
554
|
-
[ops.
|
|
555
|
-
[ops.
|
|
543
|
+
[ops.literal, "localhost:5000"],
|
|
544
|
+
[ops.literal, "foo"],
|
|
556
545
|
]);
|
|
557
546
|
});
|
|
558
547
|
|
|
@@ -561,17 +550,18 @@ describe("Origami parser", () => {
|
|
|
561
550
|
});
|
|
562
551
|
|
|
563
552
|
test("scopeTraverse", () => {
|
|
553
|
+
assertParse("scopeTraverse", "tree/", [ops.traverse, [ops.scope, "tree/"]]);
|
|
564
554
|
assertParse("scopeTraverse", "tree/foo/bar", [
|
|
565
555
|
ops.traverse,
|
|
566
556
|
[ops.scope, "tree/"],
|
|
567
|
-
[ops.
|
|
568
|
-
[ops.
|
|
557
|
+
[ops.literal, "foo/"],
|
|
558
|
+
[ops.literal, "bar"],
|
|
569
559
|
]);
|
|
570
560
|
assertParse("scopeTraverse", "tree/foo/bar/", [
|
|
571
561
|
ops.traverse,
|
|
572
562
|
[ops.scope, "tree/"],
|
|
573
|
-
[ops.
|
|
574
|
-
[ops.
|
|
563
|
+
[ops.literal, "foo/"],
|
|
564
|
+
[ops.literal, "bar/"],
|
|
575
565
|
]);
|
|
576
566
|
});
|
|
577
567
|
|
|
@@ -581,7 +571,7 @@ describe("Origami parser", () => {
|
|
|
581
571
|
`#!/usr/bin/env ori @invoke
|
|
582
572
|
'Hello'
|
|
583
573
|
`,
|
|
584
|
-
[ops.
|
|
574
|
+
[ops.literal, "Hello"],
|
|
585
575
|
false
|
|
586
576
|
);
|
|
587
577
|
});
|
|
@@ -596,83 +586,82 @@ describe("Origami parser", () => {
|
|
|
596
586
|
});
|
|
597
587
|
|
|
598
588
|
test("string", () => {
|
|
599
|
-
assertParse("string", '"foo"', [ops.
|
|
600
|
-
assertParse("string", "'bar'", [ops.
|
|
601
|
-
assertParse("string", '"foo bar"', [ops.
|
|
602
|
-
assertParse("string", "'bar baz'", [ops.
|
|
603
|
-
assertParse("string", `"foo\\"s bar"`, [ops.
|
|
604
|
-
assertParse("string", `'bar\\'s baz'`, [ops.
|
|
605
|
-
assertParse("string", `«string»`, [ops.
|
|
589
|
+
assertParse("string", '"foo"', [ops.literal, "foo"]);
|
|
590
|
+
assertParse("string", "'bar'", [ops.literal, "bar"]);
|
|
591
|
+
assertParse("string", '"foo bar"', [ops.literal, "foo bar"]);
|
|
592
|
+
assertParse("string", "'bar baz'", [ops.literal, "bar baz"]);
|
|
593
|
+
assertParse("string", `"foo\\"s bar"`, [ops.literal, `foo"s bar`]);
|
|
594
|
+
assertParse("string", `'bar\\'s baz'`, [ops.literal, `bar's baz`]);
|
|
595
|
+
assertParse("string", `«string»`, [ops.literal, "string"]);
|
|
606
596
|
assertParse("string", `"\\0\\b\\f\\n\\r\\t\\v"`, [
|
|
607
|
-
ops.
|
|
597
|
+
ops.literal,
|
|
608
598
|
"\0\b\f\n\r\t\v",
|
|
609
599
|
]);
|
|
610
600
|
});
|
|
611
601
|
|
|
602
|
+
test("taggedTemplate", () => {
|
|
603
|
+
assertParse("taggedTemplate", "tag`Hello, world.`", [
|
|
604
|
+
[ops.scope, "tag"],
|
|
605
|
+
[ops.literal, ["Hello, world."]],
|
|
606
|
+
]);
|
|
607
|
+
});
|
|
608
|
+
|
|
612
609
|
test("templateDocument", () => {
|
|
613
610
|
assertParse("templateDocument", "hello${foo}world", [
|
|
614
611
|
ops.lambda,
|
|
615
612
|
null,
|
|
616
613
|
[
|
|
617
|
-
ops.
|
|
618
|
-
[ops.
|
|
619
|
-
[ops.scope, "foo"],
|
|
620
|
-
[ops.primitive, "world"],
|
|
614
|
+
ops.template,
|
|
615
|
+
[ops.literal, ["hello", "world"]],
|
|
616
|
+
[ops.concat, [ops.scope, "foo"]],
|
|
621
617
|
],
|
|
622
618
|
]);
|
|
623
619
|
assertParse("templateDocument", "Documents can contain ` backticks", [
|
|
624
620
|
ops.lambda,
|
|
625
621
|
null,
|
|
626
|
-
[ops.
|
|
622
|
+
[ops.template, [ops.literal, ["Documents can contain ` backticks"]]],
|
|
627
623
|
]);
|
|
628
624
|
});
|
|
629
625
|
|
|
630
626
|
test("templateLiteral", () => {
|
|
631
627
|
assertParse("templateLiteral", "`Hello, world.`", [
|
|
632
|
-
ops.
|
|
633
|
-
"Hello, world.",
|
|
628
|
+
ops.template,
|
|
629
|
+
[ops.literal, ["Hello, world."]],
|
|
634
630
|
]);
|
|
635
631
|
assertParse("templateLiteral", "`foo ${x} bar`", [
|
|
636
|
-
ops.
|
|
637
|
-
[ops.
|
|
638
|
-
[ops.scope, "x"],
|
|
639
|
-
[ops.primitive, " bar"],
|
|
632
|
+
ops.template,
|
|
633
|
+
[ops.literal, ["foo ", " bar"]],
|
|
634
|
+
[ops.concat, [ops.scope, "x"]],
|
|
640
635
|
]);
|
|
641
|
-
assertParse("templateLiteral", "`${`nested`}`", [
|
|
642
|
-
|
|
643
|
-
ops.
|
|
644
|
-
[
|
|
645
|
-
[ops.scope, "map"],
|
|
646
|
-
[ops.scope, "people"],
|
|
647
|
-
[ops.lambda, null, [ops.concat, [ops.scope, "name"]]],
|
|
648
|
-
],
|
|
649
|
-
]);
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
test("templateLiteral (JS)", () => {
|
|
653
|
-
assertParse("templateLiteral", "`Hello, world.`", [
|
|
654
|
-
ops.primitive,
|
|
655
|
-
"Hello, world.",
|
|
656
|
-
]);
|
|
657
|
-
assertParse("templateLiteral", "`foo ${x} bar`", [
|
|
658
|
-
ops.concat,
|
|
659
|
-
[ops.primitive, "foo "],
|
|
660
|
-
[ops.scope, "x"],
|
|
661
|
-
[ops.primitive, " bar"],
|
|
636
|
+
assertParse("templateLiteral", "`${`nested`}`", [
|
|
637
|
+
ops.template,
|
|
638
|
+
[ops.literal, ["", ""]],
|
|
639
|
+
[ops.concat, [ops.template, [ops.literal, ["nested"]]]],
|
|
662
640
|
]);
|
|
663
|
-
assertParse("templateLiteral", "`${`nested`}`", [ops.primitive, "nested"]);
|
|
664
641
|
assertParse("templateLiteral", "`${map(people, =`${name}`)}`", [
|
|
665
|
-
ops.
|
|
642
|
+
ops.template,
|
|
643
|
+
[ops.literal, ["", ""]],
|
|
666
644
|
[
|
|
667
|
-
|
|
668
|
-
[
|
|
669
|
-
|
|
645
|
+
ops.concat,
|
|
646
|
+
[
|
|
647
|
+
[ops.scope, "map"],
|
|
648
|
+
[ops.scope, "people"],
|
|
649
|
+
[
|
|
650
|
+
ops.lambda,
|
|
651
|
+
null,
|
|
652
|
+
[
|
|
653
|
+
ops.template,
|
|
654
|
+
[ops.literal, ["", ""]],
|
|
655
|
+
[ops.concat, [ops.scope, "name"]],
|
|
656
|
+
],
|
|
657
|
+
],
|
|
658
|
+
],
|
|
670
659
|
],
|
|
671
660
|
]);
|
|
672
661
|
});
|
|
673
662
|
|
|
674
663
|
test("templateSubtitution", () => {
|
|
675
|
-
assertParse("templateSubstitution", "${foo}", [ops.scope, "foo"]);
|
|
664
|
+
assertParse("templateSubstitution", "${foo}", [ops.scope, "foo"], false);
|
|
676
665
|
});
|
|
677
666
|
|
|
678
667
|
test("whitespace block", () => {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import taggedTemplate from "../../src/runtime/taggedTemplate.js";
|
|
4
|
+
|
|
5
|
+
describe("taggedTemplate", () => {
|
|
6
|
+
test("joins strings and values together", () => {
|
|
7
|
+
const result = taggedTemplate`a ${"b"} c`;
|
|
8
|
+
assert.equal(result, "a b c");
|
|
9
|
+
});
|
|
10
|
+
});
|