@weborigami/language 0.0.38 → 0.0.39
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 +4 -1
- package/package.json +3 -3
- package/src/compiler/origami.pegjs +2 -1
- package/src/compiler/parse.js +85 -67
- package/src/runtime/concatTreeValues.js +7 -0
- package/src/runtime/ops.js +7 -0
- package/test/compiler/parse.test.js +2 -2
- package/test/runtime/{concatTreeValues.js → concatTreeValues.test.js} +14 -1
package/index.ts
CHANGED
|
@@ -14,7 +14,10 @@ export type Constructor<T> = new (...args: any[]) => T;
|
|
|
14
14
|
*/
|
|
15
15
|
export type FileUnpackFunction = (
|
|
16
16
|
input: StringLike,
|
|
17
|
-
options?: {
|
|
17
|
+
options?: {
|
|
18
|
+
key?: any,
|
|
19
|
+
parent?: AsyncTree | null
|
|
20
|
+
}
|
|
18
21
|
) => any;
|
|
19
22
|
|
|
20
23
|
/**
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.39",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
7
7
|
"types": "./index.ts",
|
|
8
8
|
"devDependencies": {
|
|
9
|
-
"@types/node": "20.
|
|
10
|
-
"typescript": "5.
|
|
9
|
+
"@types/node": "20.11.3",
|
|
10
|
+
"typescript": "5.3.3"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@weborigami/types": "*",
|
|
@@ -205,9 +205,10 @@ protocol
|
|
|
205
205
|
reservedProtocol
|
|
206
206
|
= "https" { return ops.https; }
|
|
207
207
|
/ "http" { return ops.http; }
|
|
208
|
+
/ "package" { return [ops.scope, "@package"] } // Alias
|
|
208
209
|
/ "treehttps" { return ops.treeHttps; }
|
|
209
210
|
/ "treehttp" { return ops.treeHttp; }
|
|
210
|
-
/ "tree" { return ops.treeHttps; } //
|
|
211
|
+
/ "tree" { return ops.treeHttps; } // Alias
|
|
211
212
|
|
|
212
213
|
scopeReference
|
|
213
214
|
= key:identifier { return [ops.scope, key]; }
|
package/src/compiler/parse.js
CHANGED
|
@@ -204,13 +204,14 @@ function peg$parse(input, options) {
|
|
|
204
204
|
var peg$c16 = ",";
|
|
205
205
|
var peg$c17 = "https";
|
|
206
206
|
var peg$c18 = "http";
|
|
207
|
-
var peg$c19 = "
|
|
208
|
-
var peg$c20 = "
|
|
209
|
-
var peg$c21 = "
|
|
210
|
-
var peg$c22 = "
|
|
211
|
-
var peg$c23 = "
|
|
212
|
-
var peg$c24 = "
|
|
213
|
-
var peg$c25 = "
|
|
207
|
+
var peg$c19 = "package";
|
|
208
|
+
var peg$c20 = "treehttps";
|
|
209
|
+
var peg$c21 = "treehttp";
|
|
210
|
+
var peg$c22 = "tree";
|
|
211
|
+
var peg$c23 = "'";
|
|
212
|
+
var peg$c24 = "{{";
|
|
213
|
+
var peg$c25 = "`";
|
|
214
|
+
var peg$c26 = "}}";
|
|
214
215
|
|
|
215
216
|
var peg$r0 = /^[^\n\r]/;
|
|
216
217
|
var peg$r1 = /^[0-9]/;
|
|
@@ -244,14 +245,15 @@ function peg$parse(input, options) {
|
|
|
244
245
|
var peg$e23 = peg$classExpectation(["+", "-"], false, false);
|
|
245
246
|
var peg$e24 = peg$literalExpectation("https", false);
|
|
246
247
|
var peg$e25 = peg$literalExpectation("http", false);
|
|
247
|
-
var peg$e26 = peg$literalExpectation("
|
|
248
|
-
var peg$e27 = peg$literalExpectation("
|
|
249
|
-
var peg$e28 = peg$literalExpectation("
|
|
250
|
-
var peg$e29 = peg$literalExpectation("
|
|
251
|
-
var peg$e30 = peg$
|
|
252
|
-
var peg$e31 = peg$
|
|
253
|
-
var peg$e32 = peg$literalExpectation("
|
|
254
|
-
var peg$e33 = peg$literalExpectation("
|
|
248
|
+
var peg$e26 = peg$literalExpectation("package", false);
|
|
249
|
+
var peg$e27 = peg$literalExpectation("treehttps", false);
|
|
250
|
+
var peg$e28 = peg$literalExpectation("treehttp", false);
|
|
251
|
+
var peg$e29 = peg$literalExpectation("tree", false);
|
|
252
|
+
var peg$e30 = peg$literalExpectation("'", false);
|
|
253
|
+
var peg$e31 = peg$otherExpectation("Origami template");
|
|
254
|
+
var peg$e32 = peg$literalExpectation("{{", false);
|
|
255
|
+
var peg$e33 = peg$literalExpectation("`", false);
|
|
256
|
+
var peg$e34 = peg$literalExpectation("}}", false);
|
|
255
257
|
|
|
256
258
|
var peg$f0 = function() { return ""; };
|
|
257
259
|
var peg$f1 = function(path) { return [[ops.filesRoot], ...path]; };
|
|
@@ -288,18 +290,19 @@ function peg$parse(input, options) {
|
|
|
288
290
|
};
|
|
289
291
|
var peg$f23 = function() { return ops.https; };
|
|
290
292
|
var peg$f24 = function() { return ops.http; };
|
|
291
|
-
var peg$f25 = function() { return ops.
|
|
292
|
-
var peg$f26 = function() { return ops.
|
|
293
|
-
var peg$f27 = function() { return ops.
|
|
294
|
-
var peg$f28 = function(
|
|
295
|
-
var peg$f29 = function(
|
|
296
|
-
var peg$f30 = function(
|
|
297
|
-
var peg$f31 = function(
|
|
298
|
-
var peg$f32 = function(
|
|
299
|
-
var peg$f33 = function(
|
|
300
|
-
var peg$f34 = function(
|
|
301
|
-
var peg$f35 = function(
|
|
302
|
-
var peg$f36 = function(
|
|
293
|
+
var peg$f25 = function() { return [ops.scope, "@package"] };
|
|
294
|
+
var peg$f26 = function() { return ops.treeHttps; };
|
|
295
|
+
var peg$f27 = function() { return ops.treeHttp; };
|
|
296
|
+
var peg$f28 = function() { return ops.treeHttps; };
|
|
297
|
+
var peg$f29 = function(key) { return [ops.scope, key]; };
|
|
298
|
+
var peg$f30 = function(chars) { return chars.join(""); };
|
|
299
|
+
var peg$f31 = function(contents) { return [ops.lambda, contents]; };
|
|
300
|
+
var peg$f32 = function(parts) { return makeTemplate(parts); };
|
|
301
|
+
var peg$f33 = function(chars) { return chars.join(""); };
|
|
302
|
+
var peg$f34 = function(parts) { return makeTemplate(parts); };
|
|
303
|
+
var peg$f35 = function(chars) { return chars.join(""); };
|
|
304
|
+
var peg$f36 = function(assignments) { return [ops.tree, ...(assignments ?? [])]; };
|
|
305
|
+
var peg$f37 = function(head, tail) {
|
|
303
306
|
return [head].concat(tail);
|
|
304
307
|
};
|
|
305
308
|
var peg$currPos = 0;
|
|
@@ -1708,9 +1711,9 @@ function peg$parse(input, options) {
|
|
|
1708
1711
|
s0 = s1;
|
|
1709
1712
|
if (s0 === peg$FAILED) {
|
|
1710
1713
|
s0 = peg$currPos;
|
|
1711
|
-
if (input.substr(peg$currPos,
|
|
1714
|
+
if (input.substr(peg$currPos, 7) === peg$c19) {
|
|
1712
1715
|
s1 = peg$c19;
|
|
1713
|
-
peg$currPos +=
|
|
1716
|
+
peg$currPos += 7;
|
|
1714
1717
|
} else {
|
|
1715
1718
|
s1 = peg$FAILED;
|
|
1716
1719
|
if (peg$silentFails === 0) { peg$fail(peg$e26); }
|
|
@@ -1722,9 +1725,9 @@ function peg$parse(input, options) {
|
|
|
1722
1725
|
s0 = s1;
|
|
1723
1726
|
if (s0 === peg$FAILED) {
|
|
1724
1727
|
s0 = peg$currPos;
|
|
1725
|
-
if (input.substr(peg$currPos,
|
|
1728
|
+
if (input.substr(peg$currPos, 9) === peg$c20) {
|
|
1726
1729
|
s1 = peg$c20;
|
|
1727
|
-
peg$currPos +=
|
|
1730
|
+
peg$currPos += 9;
|
|
1728
1731
|
} else {
|
|
1729
1732
|
s1 = peg$FAILED;
|
|
1730
1733
|
if (peg$silentFails === 0) { peg$fail(peg$e27); }
|
|
@@ -1736,9 +1739,9 @@ function peg$parse(input, options) {
|
|
|
1736
1739
|
s0 = s1;
|
|
1737
1740
|
if (s0 === peg$FAILED) {
|
|
1738
1741
|
s0 = peg$currPos;
|
|
1739
|
-
if (input.substr(peg$currPos,
|
|
1742
|
+
if (input.substr(peg$currPos, 8) === peg$c21) {
|
|
1740
1743
|
s1 = peg$c21;
|
|
1741
|
-
peg$currPos +=
|
|
1744
|
+
peg$currPos += 8;
|
|
1742
1745
|
} else {
|
|
1743
1746
|
s1 = peg$FAILED;
|
|
1744
1747
|
if (peg$silentFails === 0) { peg$fail(peg$e28); }
|
|
@@ -1748,6 +1751,21 @@ function peg$parse(input, options) {
|
|
|
1748
1751
|
s1 = peg$f27();
|
|
1749
1752
|
}
|
|
1750
1753
|
s0 = s1;
|
|
1754
|
+
if (s0 === peg$FAILED) {
|
|
1755
|
+
s0 = peg$currPos;
|
|
1756
|
+
if (input.substr(peg$currPos, 4) === peg$c22) {
|
|
1757
|
+
s1 = peg$c22;
|
|
1758
|
+
peg$currPos += 4;
|
|
1759
|
+
} else {
|
|
1760
|
+
s1 = peg$FAILED;
|
|
1761
|
+
if (peg$silentFails === 0) { peg$fail(peg$e29); }
|
|
1762
|
+
}
|
|
1763
|
+
if (s1 !== peg$FAILED) {
|
|
1764
|
+
peg$savedPos = s0;
|
|
1765
|
+
s1 = peg$f28();
|
|
1766
|
+
}
|
|
1767
|
+
s0 = s1;
|
|
1768
|
+
}
|
|
1751
1769
|
}
|
|
1752
1770
|
}
|
|
1753
1771
|
}
|
|
@@ -1763,7 +1781,7 @@ function peg$parse(input, options) {
|
|
|
1763
1781
|
s1 = peg$parseidentifier();
|
|
1764
1782
|
if (s1 !== peg$FAILED) {
|
|
1765
1783
|
peg$savedPos = s0;
|
|
1766
|
-
s1 = peg$
|
|
1784
|
+
s1 = peg$f29(s1);
|
|
1767
1785
|
}
|
|
1768
1786
|
s0 = s1;
|
|
1769
1787
|
|
|
@@ -1775,11 +1793,11 @@ function peg$parse(input, options) {
|
|
|
1775
1793
|
|
|
1776
1794
|
s0 = peg$currPos;
|
|
1777
1795
|
if (input.charCodeAt(peg$currPos) === 39) {
|
|
1778
|
-
s1 = peg$
|
|
1796
|
+
s1 = peg$c23;
|
|
1779
1797
|
peg$currPos++;
|
|
1780
1798
|
} else {
|
|
1781
1799
|
s1 = peg$FAILED;
|
|
1782
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
1800
|
+
if (peg$silentFails === 0) { peg$fail(peg$e30); }
|
|
1783
1801
|
}
|
|
1784
1802
|
if (s1 !== peg$FAILED) {
|
|
1785
1803
|
s2 = [];
|
|
@@ -1789,15 +1807,15 @@ function peg$parse(input, options) {
|
|
|
1789
1807
|
s3 = peg$parsesingleQuoteStringChar();
|
|
1790
1808
|
}
|
|
1791
1809
|
if (input.charCodeAt(peg$currPos) === 39) {
|
|
1792
|
-
s3 = peg$
|
|
1810
|
+
s3 = peg$c23;
|
|
1793
1811
|
peg$currPos++;
|
|
1794
1812
|
} else {
|
|
1795
1813
|
s3 = peg$FAILED;
|
|
1796
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
1814
|
+
if (peg$silentFails === 0) { peg$fail(peg$e30); }
|
|
1797
1815
|
}
|
|
1798
1816
|
if (s3 !== peg$FAILED) {
|
|
1799
1817
|
peg$savedPos = s0;
|
|
1800
|
-
s0 = peg$
|
|
1818
|
+
s0 = peg$f30(s2);
|
|
1801
1819
|
} else {
|
|
1802
1820
|
peg$currPos = s0;
|
|
1803
1821
|
s0 = peg$FAILED;
|
|
@@ -1817,11 +1835,11 @@ function peg$parse(input, options) {
|
|
|
1817
1835
|
s1 = peg$currPos;
|
|
1818
1836
|
peg$silentFails++;
|
|
1819
1837
|
if (input.charCodeAt(peg$currPos) === 39) {
|
|
1820
|
-
s2 = peg$
|
|
1838
|
+
s2 = peg$c23;
|
|
1821
1839
|
peg$currPos++;
|
|
1822
1840
|
} else {
|
|
1823
1841
|
s2 = peg$FAILED;
|
|
1824
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
1842
|
+
if (peg$silentFails === 0) { peg$fail(peg$e30); }
|
|
1825
1843
|
}
|
|
1826
1844
|
if (s2 === peg$FAILED) {
|
|
1827
1845
|
s2 = peg$parsenewLine();
|
|
@@ -1875,11 +1893,11 @@ function peg$parse(input, options) {
|
|
|
1875
1893
|
s0 = peg$currPos;
|
|
1876
1894
|
s1 = peg$parsetemplateDocumentContents();
|
|
1877
1895
|
peg$savedPos = s0;
|
|
1878
|
-
s1 = peg$
|
|
1896
|
+
s1 = peg$f31(s1);
|
|
1879
1897
|
s0 = s1;
|
|
1880
1898
|
peg$silentFails--;
|
|
1881
1899
|
s1 = peg$FAILED;
|
|
1882
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
1900
|
+
if (peg$silentFails === 0) { peg$fail(peg$e31); }
|
|
1883
1901
|
|
|
1884
1902
|
return s0;
|
|
1885
1903
|
}
|
|
@@ -1890,12 +1908,12 @@ function peg$parse(input, options) {
|
|
|
1890
1908
|
s0 = peg$currPos;
|
|
1891
1909
|
s1 = peg$currPos;
|
|
1892
1910
|
peg$silentFails++;
|
|
1893
|
-
if (input.substr(peg$currPos, 2) === peg$
|
|
1894
|
-
s2 = peg$
|
|
1911
|
+
if (input.substr(peg$currPos, 2) === peg$c24) {
|
|
1912
|
+
s2 = peg$c24;
|
|
1895
1913
|
peg$currPos += 2;
|
|
1896
1914
|
} else {
|
|
1897
1915
|
s2 = peg$FAILED;
|
|
1898
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
1916
|
+
if (peg$silentFails === 0) { peg$fail(peg$e32); }
|
|
1899
1917
|
}
|
|
1900
1918
|
peg$silentFails--;
|
|
1901
1919
|
if (s2 === peg$FAILED) {
|
|
@@ -1937,7 +1955,7 @@ function peg$parse(input, options) {
|
|
|
1937
1955
|
}
|
|
1938
1956
|
}
|
|
1939
1957
|
peg$savedPos = s0;
|
|
1940
|
-
s1 = peg$
|
|
1958
|
+
s1 = peg$f32(s1);
|
|
1941
1959
|
s0 = s1;
|
|
1942
1960
|
|
|
1943
1961
|
return s0;
|
|
@@ -1959,7 +1977,7 @@ function peg$parse(input, options) {
|
|
|
1959
1977
|
}
|
|
1960
1978
|
if (s1 !== peg$FAILED) {
|
|
1961
1979
|
peg$savedPos = s0;
|
|
1962
|
-
s1 = peg$
|
|
1980
|
+
s1 = peg$f33(s1);
|
|
1963
1981
|
}
|
|
1964
1982
|
s0 = s1;
|
|
1965
1983
|
|
|
@@ -1971,20 +1989,20 @@ function peg$parse(input, options) {
|
|
|
1971
1989
|
|
|
1972
1990
|
s0 = peg$currPos;
|
|
1973
1991
|
if (input.charCodeAt(peg$currPos) === 96) {
|
|
1974
|
-
s1 = peg$
|
|
1992
|
+
s1 = peg$c25;
|
|
1975
1993
|
peg$currPos++;
|
|
1976
1994
|
} else {
|
|
1977
1995
|
s1 = peg$FAILED;
|
|
1978
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
1996
|
+
if (peg$silentFails === 0) { peg$fail(peg$e33); }
|
|
1979
1997
|
}
|
|
1980
1998
|
if (s1 !== peg$FAILED) {
|
|
1981
1999
|
s2 = peg$parsetemplateLiteralContents();
|
|
1982
2000
|
if (input.charCodeAt(peg$currPos) === 96) {
|
|
1983
|
-
s3 = peg$
|
|
2001
|
+
s3 = peg$c25;
|
|
1984
2002
|
peg$currPos++;
|
|
1985
2003
|
} else {
|
|
1986
2004
|
s3 = peg$FAILED;
|
|
1987
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
2005
|
+
if (peg$silentFails === 0) { peg$fail(peg$e33); }
|
|
1988
2006
|
}
|
|
1989
2007
|
if (s3 !== peg$FAILED) {
|
|
1990
2008
|
s0 = s2;
|
|
@@ -2007,19 +2025,19 @@ function peg$parse(input, options) {
|
|
|
2007
2025
|
s1 = peg$currPos;
|
|
2008
2026
|
peg$silentFails++;
|
|
2009
2027
|
if (input.charCodeAt(peg$currPos) === 96) {
|
|
2010
|
-
s2 = peg$
|
|
2028
|
+
s2 = peg$c25;
|
|
2011
2029
|
peg$currPos++;
|
|
2012
2030
|
} else {
|
|
2013
2031
|
s2 = peg$FAILED;
|
|
2014
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
2032
|
+
if (peg$silentFails === 0) { peg$fail(peg$e33); }
|
|
2015
2033
|
}
|
|
2016
2034
|
if (s2 === peg$FAILED) {
|
|
2017
|
-
if (input.substr(peg$currPos, 2) === peg$
|
|
2018
|
-
s2 = peg$
|
|
2035
|
+
if (input.substr(peg$currPos, 2) === peg$c24) {
|
|
2036
|
+
s2 = peg$c24;
|
|
2019
2037
|
peg$currPos += 2;
|
|
2020
2038
|
} else {
|
|
2021
2039
|
s2 = peg$FAILED;
|
|
2022
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
2040
|
+
if (peg$silentFails === 0) { peg$fail(peg$e32); }
|
|
2023
2041
|
}
|
|
2024
2042
|
}
|
|
2025
2043
|
peg$silentFails--;
|
|
@@ -2062,7 +2080,7 @@ function peg$parse(input, options) {
|
|
|
2062
2080
|
}
|
|
2063
2081
|
}
|
|
2064
2082
|
peg$savedPos = s0;
|
|
2065
|
-
s1 = peg$
|
|
2083
|
+
s1 = peg$f34(s1);
|
|
2066
2084
|
s0 = s1;
|
|
2067
2085
|
|
|
2068
2086
|
return s0;
|
|
@@ -2084,7 +2102,7 @@ function peg$parse(input, options) {
|
|
|
2084
2102
|
}
|
|
2085
2103
|
if (s1 !== peg$FAILED) {
|
|
2086
2104
|
peg$savedPos = s0;
|
|
2087
|
-
s1 = peg$
|
|
2105
|
+
s1 = peg$f35(s1);
|
|
2088
2106
|
}
|
|
2089
2107
|
s0 = s1;
|
|
2090
2108
|
|
|
@@ -2095,22 +2113,22 @@ function peg$parse(input, options) {
|
|
|
2095
2113
|
var s0, s1, s2, s3;
|
|
2096
2114
|
|
|
2097
2115
|
s0 = peg$currPos;
|
|
2098
|
-
if (input.substr(peg$currPos, 2) === peg$
|
|
2099
|
-
s1 = peg$
|
|
2116
|
+
if (input.substr(peg$currPos, 2) === peg$c24) {
|
|
2117
|
+
s1 = peg$c24;
|
|
2100
2118
|
peg$currPos += 2;
|
|
2101
2119
|
} else {
|
|
2102
2120
|
s1 = peg$FAILED;
|
|
2103
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
2121
|
+
if (peg$silentFails === 0) { peg$fail(peg$e32); }
|
|
2104
2122
|
}
|
|
2105
2123
|
if (s1 !== peg$FAILED) {
|
|
2106
2124
|
s2 = peg$parseexpression();
|
|
2107
2125
|
if (s2 !== peg$FAILED) {
|
|
2108
|
-
if (input.substr(peg$currPos, 2) === peg$
|
|
2109
|
-
s3 = peg$
|
|
2126
|
+
if (input.substr(peg$currPos, 2) === peg$c26) {
|
|
2127
|
+
s3 = peg$c26;
|
|
2110
2128
|
peg$currPos += 2;
|
|
2111
2129
|
} else {
|
|
2112
2130
|
s3 = peg$FAILED;
|
|
2113
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
2131
|
+
if (peg$silentFails === 0) { peg$fail(peg$e34); }
|
|
2114
2132
|
}
|
|
2115
2133
|
if (s3 !== peg$FAILED) {
|
|
2116
2134
|
s0 = s2;
|
|
@@ -2173,7 +2191,7 @@ function peg$parse(input, options) {
|
|
|
2173
2191
|
}
|
|
2174
2192
|
if (s4 !== peg$FAILED) {
|
|
2175
2193
|
peg$savedPos = s0;
|
|
2176
|
-
s0 = peg$
|
|
2194
|
+
s0 = peg$f36(s3);
|
|
2177
2195
|
} else {
|
|
2178
2196
|
peg$currPos = s0;
|
|
2179
2197
|
s0 = peg$FAILED;
|
|
@@ -2230,7 +2248,7 @@ function peg$parse(input, options) {
|
|
|
2230
2248
|
}
|
|
2231
2249
|
s4 = peg$parse__();
|
|
2232
2250
|
peg$savedPos = s0;
|
|
2233
|
-
s0 = peg$
|
|
2251
|
+
s0 = peg$f37(s1, s2);
|
|
2234
2252
|
} else {
|
|
2235
2253
|
peg$currPos = s0;
|
|
2236
2254
|
s0 = peg$FAILED;
|
|
@@ -24,6 +24,13 @@ async function getText(value, scope) {
|
|
|
24
24
|
value = await value.call(scope);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
if (Tree.isTreelike(value)) {
|
|
28
|
+
// The mapReduce operation above only implicit casts its top-level input to
|
|
29
|
+
// a tree. If we're asked for the text of a treelike value, we need to
|
|
30
|
+
// explicitly recurse.
|
|
31
|
+
return concatTreeValues.call(scope, value);
|
|
32
|
+
}
|
|
33
|
+
|
|
27
34
|
// Convert to text, preferring .toString but avoiding dumb Object.toString.
|
|
28
35
|
// Exception: if the result is an array, we'll concatenate the values.
|
|
29
36
|
let text;
|
package/src/runtime/ops.js
CHANGED
|
@@ -10,6 +10,9 @@ import Scope from "./Scope.js";
|
|
|
10
10
|
import concatTreeValues from "./concatTreeValues.js";
|
|
11
11
|
import { OrigamiTree, evaluate, expressionFunction } from "./internal.js";
|
|
12
12
|
|
|
13
|
+
// For memoizing lambda functions
|
|
14
|
+
const lambdaFnMap = new Map();
|
|
15
|
+
|
|
13
16
|
/**
|
|
14
17
|
* Construct an array.
|
|
15
18
|
*
|
|
@@ -130,6 +133,9 @@ inherited.toString = () => "«ops.inherited»";
|
|
|
130
133
|
* @param {Code} code
|
|
131
134
|
*/
|
|
132
135
|
export function lambda(code) {
|
|
136
|
+
if (lambdaFnMap.has(code)) {
|
|
137
|
+
return lambdaFnMap.get(code);
|
|
138
|
+
}
|
|
133
139
|
/** @this {AsyncTree|null} */
|
|
134
140
|
async function invoke(input) {
|
|
135
141
|
// Add ambients to scope.
|
|
@@ -142,6 +148,7 @@ export function lambda(code) {
|
|
|
142
148
|
return result;
|
|
143
149
|
}
|
|
144
150
|
invoke.code = code;
|
|
151
|
+
lambdaFnMap.set(code, invoke);
|
|
145
152
|
return invoke;
|
|
146
153
|
}
|
|
147
154
|
lambda.toString = () => "«ops.lambda»";
|
|
@@ -93,7 +93,7 @@ describe("Origami parser", () => {
|
|
|
93
93
|
"expression",
|
|
94
94
|
`
|
|
95
95
|
{
|
|
96
|
-
index.html = index.
|
|
96
|
+
index.html = index.ori(teamData.yaml)
|
|
97
97
|
thumbnails = @map(images, { valueMap: thumbnail.js })
|
|
98
98
|
}
|
|
99
99
|
`,
|
|
@@ -102,7 +102,7 @@ describe("Origami parser", () => {
|
|
|
102
102
|
[
|
|
103
103
|
"index.html",
|
|
104
104
|
[
|
|
105
|
-
[ops.scope, "index.
|
|
105
|
+
[ops.scope, "index.ori"],
|
|
106
106
|
[ops.scope, "teamData.yaml"],
|
|
107
107
|
],
|
|
108
108
|
],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Tree } from "@weborigami/async-tree";
|
|
1
|
+
import { FunctionTree, Tree } from "@weborigami/async-tree";
|
|
2
2
|
import assert from "node:assert";
|
|
3
3
|
import { describe, test } from "node:test";
|
|
4
4
|
import concatTreeValues from "../../src/runtime/concatTreeValues.js";
|
|
@@ -17,4 +17,17 @@ describe("concatTreeValues", () => {
|
|
|
17
17
|
const result = await concatTreeValues.call(null, tree);
|
|
18
18
|
assert.equal(result, "ABCDE");
|
|
19
19
|
});
|
|
20
|
+
|
|
21
|
+
test("concatenates deep tree-like values", async () => {
|
|
22
|
+
const letters = ["a", "b", "c"];
|
|
23
|
+
const specimens = new FunctionTree(
|
|
24
|
+
(letter) => ({
|
|
25
|
+
lowercase: letter,
|
|
26
|
+
uppercase: letter.toUpperCase(),
|
|
27
|
+
}),
|
|
28
|
+
letters
|
|
29
|
+
);
|
|
30
|
+
const result = await concatTreeValues.call(null, specimens);
|
|
31
|
+
assert.equal(result, "aAbBcC");
|
|
32
|
+
});
|
|
20
33
|
});
|