@weborigami/language 0.0.69 → 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 +38 -26
- package/src/compiler/parse.js +284 -191
- package/src/compiler/parserHelpers.js +9 -13
- package/src/runtime/WatchFilesMixin.js +1 -0
- package/src/runtime/evaluate.js +15 -15
- package/src/runtime/ops.js +45 -29
- 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 +159 -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,19 +386,19 @@ 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
|
|
|
@@ -431,23 +419,23 @@ describe("Origami parser", () => {
|
|
|
431
419
|
ops.getter,
|
|
432
420
|
[
|
|
433
421
|
[ops.scope, "fn"],
|
|
434
|
-
[ops.
|
|
422
|
+
[ops.literal, "bar"],
|
|
435
423
|
],
|
|
436
424
|
],
|
|
437
425
|
]);
|
|
438
426
|
});
|
|
439
427
|
|
|
440
428
|
test("objectProperty", () => {
|
|
441
|
-
assertParse("objectProperty", "a: 1", ["a", [ops.
|
|
429
|
+
assertParse("objectProperty", "a: 1", ["a", [ops.literal, 1]]);
|
|
442
430
|
assertParse("objectProperty", "name: 'Alice'", [
|
|
443
431
|
"name",
|
|
444
|
-
[ops.
|
|
432
|
+
[ops.literal, "Alice"],
|
|
445
433
|
]);
|
|
446
434
|
assertParse("objectProperty", "x: fn('a')", [
|
|
447
435
|
"x",
|
|
448
436
|
[
|
|
449
437
|
[ops.scope, "fn"],
|
|
450
|
-
[ops.
|
|
438
|
+
[ops.literal, "a"],
|
|
451
439
|
],
|
|
452
440
|
]);
|
|
453
441
|
});
|
|
@@ -499,19 +487,19 @@ describe("Origami parser", () => {
|
|
|
499
487
|
});
|
|
500
488
|
|
|
501
489
|
test("path", () => {
|
|
502
|
-
assertParse("path", "tree/", [[ops.
|
|
490
|
+
assertParse("path", "tree/", [[ops.literal, "tree/"]]);
|
|
503
491
|
assertParse("path", "month/12", [
|
|
504
|
-
[ops.
|
|
505
|
-
[ops.
|
|
492
|
+
[ops.literal, "month/"],
|
|
493
|
+
[ops.literal, "12"],
|
|
506
494
|
]);
|
|
507
495
|
assertParse("path", "tree/foo/bar", [
|
|
508
|
-
[ops.
|
|
509
|
-
[ops.
|
|
510
|
-
[ops.
|
|
496
|
+
[ops.literal, "tree/"],
|
|
497
|
+
[ops.literal, "foo/"],
|
|
498
|
+
[ops.literal, "bar"],
|
|
511
499
|
]);
|
|
512
500
|
assertParse("path", "a///b", [
|
|
513
|
-
[ops.
|
|
514
|
-
[ops.
|
|
501
|
+
[ops.literal, "a/"],
|
|
502
|
+
[ops.literal, "b"],
|
|
515
503
|
]);
|
|
516
504
|
});
|
|
517
505
|
|
|
@@ -539,21 +527,21 @@ describe("Origami parser", () => {
|
|
|
539
527
|
test("protocolCall", () => {
|
|
540
528
|
assertParse("protocolCall", "foo://bar", [
|
|
541
529
|
[ops.scope, "foo"],
|
|
542
|
-
[ops.
|
|
530
|
+
[ops.literal, "bar"],
|
|
543
531
|
]);
|
|
544
532
|
assertParse("protocolCall", "https://example.com/foo/", [
|
|
545
533
|
ops.https,
|
|
546
|
-
[ops.
|
|
547
|
-
[ops.
|
|
534
|
+
[ops.literal, "example.com"],
|
|
535
|
+
[ops.literal, "foo/"],
|
|
548
536
|
]);
|
|
549
537
|
assertParse("protocolCall", "http:example.com", [
|
|
550
538
|
ops.http,
|
|
551
|
-
[ops.
|
|
539
|
+
[ops.literal, "example.com"],
|
|
552
540
|
]);
|
|
553
541
|
assertParse("protocolCall", "http://localhost:5000/foo", [
|
|
554
542
|
ops.http,
|
|
555
|
-
[ops.
|
|
556
|
-
[ops.
|
|
543
|
+
[ops.literal, "localhost:5000"],
|
|
544
|
+
[ops.literal, "foo"],
|
|
557
545
|
]);
|
|
558
546
|
});
|
|
559
547
|
|
|
@@ -562,17 +550,18 @@ describe("Origami parser", () => {
|
|
|
562
550
|
});
|
|
563
551
|
|
|
564
552
|
test("scopeTraverse", () => {
|
|
553
|
+
assertParse("scopeTraverse", "tree/", [ops.traverse, [ops.scope, "tree/"]]);
|
|
565
554
|
assertParse("scopeTraverse", "tree/foo/bar", [
|
|
566
555
|
ops.traverse,
|
|
567
556
|
[ops.scope, "tree/"],
|
|
568
|
-
[ops.
|
|
569
|
-
[ops.
|
|
557
|
+
[ops.literal, "foo/"],
|
|
558
|
+
[ops.literal, "bar"],
|
|
570
559
|
]);
|
|
571
560
|
assertParse("scopeTraverse", "tree/foo/bar/", [
|
|
572
561
|
ops.traverse,
|
|
573
562
|
[ops.scope, "tree/"],
|
|
574
|
-
[ops.
|
|
575
|
-
[ops.
|
|
563
|
+
[ops.literal, "foo/"],
|
|
564
|
+
[ops.literal, "bar/"],
|
|
576
565
|
]);
|
|
577
566
|
});
|
|
578
567
|
|
|
@@ -582,7 +571,7 @@ describe("Origami parser", () => {
|
|
|
582
571
|
`#!/usr/bin/env ori @invoke
|
|
583
572
|
'Hello'
|
|
584
573
|
`,
|
|
585
|
-
[ops.
|
|
574
|
+
[ops.literal, "Hello"],
|
|
586
575
|
false
|
|
587
576
|
);
|
|
588
577
|
});
|
|
@@ -597,83 +586,82 @@ describe("Origami parser", () => {
|
|
|
597
586
|
});
|
|
598
587
|
|
|
599
588
|
test("string", () => {
|
|
600
|
-
assertParse("string", '"foo"', [ops.
|
|
601
|
-
assertParse("string", "'bar'", [ops.
|
|
602
|
-
assertParse("string", '"foo bar"', [ops.
|
|
603
|
-
assertParse("string", "'bar baz'", [ops.
|
|
604
|
-
assertParse("string", `"foo\\"s bar"`, [ops.
|
|
605
|
-
assertParse("string", `'bar\\'s baz'`, [ops.
|
|
606
|
-
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"]);
|
|
607
596
|
assertParse("string", `"\\0\\b\\f\\n\\r\\t\\v"`, [
|
|
608
|
-
ops.
|
|
597
|
+
ops.literal,
|
|
609
598
|
"\0\b\f\n\r\t\v",
|
|
610
599
|
]);
|
|
611
600
|
});
|
|
612
601
|
|
|
602
|
+
test("taggedTemplate", () => {
|
|
603
|
+
assertParse("taggedTemplate", "tag`Hello, world.`", [
|
|
604
|
+
[ops.scope, "tag"],
|
|
605
|
+
[ops.literal, ["Hello, world."]],
|
|
606
|
+
]);
|
|
607
|
+
});
|
|
608
|
+
|
|
613
609
|
test("templateDocument", () => {
|
|
614
610
|
assertParse("templateDocument", "hello${foo}world", [
|
|
615
611
|
ops.lambda,
|
|
616
612
|
null,
|
|
617
613
|
[
|
|
618
|
-
ops.
|
|
619
|
-
[ops.
|
|
620
|
-
[ops.scope, "foo"],
|
|
621
|
-
[ops.primitive, "world"],
|
|
614
|
+
ops.template,
|
|
615
|
+
[ops.literal, ["hello", "world"]],
|
|
616
|
+
[ops.concat, [ops.scope, "foo"]],
|
|
622
617
|
],
|
|
623
618
|
]);
|
|
624
619
|
assertParse("templateDocument", "Documents can contain ` backticks", [
|
|
625
620
|
ops.lambda,
|
|
626
621
|
null,
|
|
627
|
-
[ops.
|
|
622
|
+
[ops.template, [ops.literal, ["Documents can contain ` backticks"]]],
|
|
628
623
|
]);
|
|
629
624
|
});
|
|
630
625
|
|
|
631
626
|
test("templateLiteral", () => {
|
|
632
627
|
assertParse("templateLiteral", "`Hello, world.`", [
|
|
633
|
-
ops.
|
|
634
|
-
"Hello, world.",
|
|
628
|
+
ops.template,
|
|
629
|
+
[ops.literal, ["Hello, world."]],
|
|
635
630
|
]);
|
|
636
631
|
assertParse("templateLiteral", "`foo ${x} bar`", [
|
|
637
|
-
ops.
|
|
638
|
-
[ops.
|
|
639
|
-
[ops.scope, "x"],
|
|
640
|
-
[ops.primitive, " bar"],
|
|
632
|
+
ops.template,
|
|
633
|
+
[ops.literal, ["foo ", " bar"]],
|
|
634
|
+
[ops.concat, [ops.scope, "x"]],
|
|
641
635
|
]);
|
|
642
|
-
assertParse("templateLiteral", "`${`nested`}`", [
|
|
643
|
-
|
|
644
|
-
ops.
|
|
645
|
-
[
|
|
646
|
-
[ops.scope, "map"],
|
|
647
|
-
[ops.scope, "people"],
|
|
648
|
-
[ops.lambda, null, [ops.concat, [ops.scope, "name"]]],
|
|
649
|
-
],
|
|
650
|
-
]);
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
test("templateLiteral (JS)", () => {
|
|
654
|
-
assertParse("templateLiteral", "`Hello, world.`", [
|
|
655
|
-
ops.primitive,
|
|
656
|
-
"Hello, world.",
|
|
657
|
-
]);
|
|
658
|
-
assertParse("templateLiteral", "`foo ${x} bar`", [
|
|
659
|
-
ops.concat,
|
|
660
|
-
[ops.primitive, "foo "],
|
|
661
|
-
[ops.scope, "x"],
|
|
662
|
-
[ops.primitive, " bar"],
|
|
636
|
+
assertParse("templateLiteral", "`${`nested`}`", [
|
|
637
|
+
ops.template,
|
|
638
|
+
[ops.literal, ["", ""]],
|
|
639
|
+
[ops.concat, [ops.template, [ops.literal, ["nested"]]]],
|
|
663
640
|
]);
|
|
664
|
-
assertParse("templateLiteral", "`${`nested`}`", [ops.primitive, "nested"]);
|
|
665
641
|
assertParse("templateLiteral", "`${map(people, =`${name}`)}`", [
|
|
666
|
-
ops.
|
|
642
|
+
ops.template,
|
|
643
|
+
[ops.literal, ["", ""]],
|
|
667
644
|
[
|
|
668
|
-
|
|
669
|
-
[
|
|
670
|
-
|
|
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
|
+
],
|
|
671
659
|
],
|
|
672
660
|
]);
|
|
673
661
|
});
|
|
674
662
|
|
|
675
663
|
test("templateSubtitution", () => {
|
|
676
|
-
assertParse("templateSubstitution", "${foo}", [ops.scope, "foo"]);
|
|
664
|
+
assertParse("templateSubstitution", "${foo}", [ops.scope, "foo"], false);
|
|
677
665
|
});
|
|
678
666
|
|
|
679
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
|
+
});
|