@weborigami/language 0.2.3 → 0.2.4
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/package.json +3 -3
- package/src/compiler/origami.pegjs +10 -5
- package/src/compiler/parse.js +88 -45
- package/src/runtime/mergeTrees.js +23 -3
- package/test/compiler/parse.test.js +12 -0
- package/test/runtime/mergeTrees.test.js +33 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"yaml": "2.6.1"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@weborigami/async-tree": "0.2.
|
|
16
|
-
"@weborigami/types": "0.2.
|
|
15
|
+
"@weborigami/async-tree": "0.2.4",
|
|
16
|
+
"@weborigami/types": "0.2.4",
|
|
17
17
|
"watcher": "2.3.1"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
@@ -31,12 +31,12 @@ import {
|
|
|
31
31
|
|
|
32
32
|
// A block of optional whitespace
|
|
33
33
|
__
|
|
34
|
-
=
|
|
34
|
+
= whitespace* {
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
additiveExpression
|
|
39
|
-
= head:multiplicativeExpression tail:(
|
|
39
|
+
= head:multiplicativeExpression tail:(whitespace @additiveOperator whitespace @multiplicativeExpression)* {
|
|
40
40
|
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -148,8 +148,8 @@ comment "comment"
|
|
|
148
148
|
|
|
149
149
|
conditionalExpression
|
|
150
150
|
= condition:logicalOrExpression tail:(__
|
|
151
|
-
"?" __ @
|
|
152
|
-
":" __ @
|
|
151
|
+
"?" __ @shorthandFunction __
|
|
152
|
+
":" __ @shorthandFunction)?
|
|
153
153
|
{
|
|
154
154
|
if (!tail) {
|
|
155
155
|
return condition;
|
|
@@ -310,7 +310,7 @@ multiLineComment
|
|
|
310
310
|
= "/*" (!"*/" .)* "*/" { return null; }
|
|
311
311
|
|
|
312
312
|
multiplicativeExpression
|
|
313
|
-
= head:exponentiationExpression tail:(
|
|
313
|
+
= head:exponentiationExpression tail:(whitespace @multiplicativeOperator whitespace @exponentiationExpression)* {
|
|
314
314
|
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
315
315
|
}
|
|
316
316
|
|
|
@@ -625,5 +625,10 @@ unaryOperator
|
|
|
625
625
|
/ "-"
|
|
626
626
|
/ "~"
|
|
627
627
|
|
|
628
|
+
whitespace
|
|
629
|
+
= inlineSpace
|
|
630
|
+
/ newLine
|
|
631
|
+
/ comment
|
|
632
|
+
|
|
628
633
|
whitespaceWithNewLine
|
|
629
634
|
= inlineSpace* comment? newLine __
|
package/src/compiler/parse.js
CHANGED
|
@@ -202,7 +202,7 @@ function peg$parse(input, options) {
|
|
|
202
202
|
var peg$FAILED = {};
|
|
203
203
|
var peg$source = options.grammarSource;
|
|
204
204
|
|
|
205
|
-
var peg$startRuleFunctions = { __: peg$parse__, additiveExpression: peg$parseadditiveExpression, additiveOperator: peg$parseadditiveOperator, arguments: peg$parsearguments, arrayLiteral: peg$parsearrayLiteral, arrayEntries: peg$parsearrayEntries, arrayEntry: peg$parsearrayEntry, arrowFunction: peg$parsearrowFunction, bitwiseAndExpression: peg$parsebitwiseAndExpression, bitwiseAndOperator: peg$parsebitwiseAndOperator, bitwiseOrExpression: peg$parsebitwiseOrExpression, bitwiseOrOperator: peg$parsebitwiseOrOperator, bitwiseXorExpression: peg$parsebitwiseXorExpression, bitwiseXorOperator: peg$parsebitwiseXorOperator, callExpression: peg$parsecallExpression, closingBrace: peg$parseclosingBrace, closingBracket: peg$parseclosingBracket, closingParenthesis: peg$parseclosingParenthesis, commaExpression: peg$parsecommaExpression, comment: peg$parsecomment, conditionalExpression: peg$parseconditionalExpression, digits: peg$parsedigits, doubleArrow: peg$parsedoubleArrow, doubleQuoteString: peg$parsedoubleQuoteString, doubleQuoteStringChar: peg$parsedoubleQuoteStringChar, ellipsis: peg$parseellipsis, equalityExpression: peg$parseequalityExpression, equalityOperator: peg$parseequalityOperator, escapedChar: peg$parseescapedChar, exponentiationExpression: peg$parseexponentiationExpression, expression: peg$parseexpression, floatLiteral: peg$parsefloatLiteral, group: peg$parsegroup, guillemetString: peg$parseguillemetString, guillemetStringChar: peg$parseguillemetStringChar, homeDirectory: peg$parsehomeDirectory, host: peg$parsehost, identifier: peg$parseidentifier, identifierChar: peg$parseidentifierChar, identifierList: peg$parseidentifierList, implicitParenthesesCallExpression: peg$parseimplicitParenthesesCallExpression, implicitParensthesesArguments: peg$parseimplicitParensthesesArguments, inlineSpace: peg$parseinlineSpace, integerLiteral: peg$parseintegerLiteral, list: peg$parselist, literal: peg$parseliteral, logicalAndExpression: peg$parselogicalAndExpression, logicalOrExpression: peg$parselogicalOrExpression, multiLineComment: peg$parsemultiLineComment, multiplicativeExpression: peg$parsemultiplicativeExpression, multiplicativeOperator: peg$parsemultiplicativeOperator, namespace: peg$parsenamespace, newLine: peg$parsenewLine, numericLiteral: peg$parsenumericLiteral, nullishCoalescingExpression: peg$parsenullishCoalescingExpression, objectLiteral: peg$parseobjectLiteral, objectEntries: peg$parseobjectEntries, objectEntry: peg$parseobjectEntry, objectGetter: peg$parseobjectGetter, objectHiddenKey: peg$parseobjectHiddenKey, objectKey: peg$parseobjectKey, objectProperty: peg$parseobjectProperty, objectShorthandProperty: peg$parseobjectShorthandProperty, objectPublicKey: peg$parseobjectPublicKey, parenthesesArguments: peg$parseparenthesesArguments, path: peg$parsepath, pathArguments: peg$parsepathArguments, pathKey: peg$parsepathKey, pathSegment: peg$parsepathSegment, pathSegmentChar: peg$parsepathSegmentChar, pipelineExpression: peg$parsepipelineExpression, primary: peg$parseprimary, program: peg$parseprogram, protocolExpression: peg$parseprotocolExpression, qualifiedReference: peg$parsequalifiedReference, reference: peg$parsereference, relationalExpression: peg$parserelationalExpression, relationalOperator: peg$parserelationalOperator, rootDirectory: peg$parserootDirectory, scopeReference: peg$parsescopeReference, separator: peg$parseseparator, slashFollows: peg$parseslashFollows, shebang: peg$parseshebang, shiftExpression: peg$parseshiftExpression, shiftOperator: peg$parseshiftOperator, shorthandFunction: peg$parseshorthandFunction, singleArrow: peg$parsesingleArrow, singleLineComment: peg$parsesingleLineComment, singleQuoteString: peg$parsesingleQuoteString, singleQuoteStringChar: peg$parsesingleQuoteStringChar, spreadElement: peg$parsespreadElement, stringLiteral: peg$parsestringLiteral, templateDocument: peg$parsetemplateDocument, templateDocumentChar: peg$parsetemplateDocumentChar, templateDocumentText: peg$parsetemplateDocumentText, templateLiteral: peg$parsetemplateLiteral, templateLiteralChar: peg$parsetemplateLiteralChar, templateLiteralText: peg$parsetemplateLiteralText, templateSubstitution: peg$parsetemplateSubstitution, textChar: peg$parsetextChar, unaryExpression: peg$parseunaryExpression, unaryOperator: peg$parseunaryOperator, whitespaceWithNewLine: peg$parsewhitespaceWithNewLine };
|
|
205
|
+
var peg$startRuleFunctions = { __: peg$parse__, additiveExpression: peg$parseadditiveExpression, additiveOperator: peg$parseadditiveOperator, arguments: peg$parsearguments, arrayLiteral: peg$parsearrayLiteral, arrayEntries: peg$parsearrayEntries, arrayEntry: peg$parsearrayEntry, arrowFunction: peg$parsearrowFunction, bitwiseAndExpression: peg$parsebitwiseAndExpression, bitwiseAndOperator: peg$parsebitwiseAndOperator, bitwiseOrExpression: peg$parsebitwiseOrExpression, bitwiseOrOperator: peg$parsebitwiseOrOperator, bitwiseXorExpression: peg$parsebitwiseXorExpression, bitwiseXorOperator: peg$parsebitwiseXorOperator, callExpression: peg$parsecallExpression, closingBrace: peg$parseclosingBrace, closingBracket: peg$parseclosingBracket, closingParenthesis: peg$parseclosingParenthesis, commaExpression: peg$parsecommaExpression, comment: peg$parsecomment, conditionalExpression: peg$parseconditionalExpression, digits: peg$parsedigits, doubleArrow: peg$parsedoubleArrow, doubleQuoteString: peg$parsedoubleQuoteString, doubleQuoteStringChar: peg$parsedoubleQuoteStringChar, ellipsis: peg$parseellipsis, equalityExpression: peg$parseequalityExpression, equalityOperator: peg$parseequalityOperator, escapedChar: peg$parseescapedChar, exponentiationExpression: peg$parseexponentiationExpression, expression: peg$parseexpression, floatLiteral: peg$parsefloatLiteral, group: peg$parsegroup, guillemetString: peg$parseguillemetString, guillemetStringChar: peg$parseguillemetStringChar, homeDirectory: peg$parsehomeDirectory, host: peg$parsehost, identifier: peg$parseidentifier, identifierChar: peg$parseidentifierChar, identifierList: peg$parseidentifierList, implicitParenthesesCallExpression: peg$parseimplicitParenthesesCallExpression, implicitParensthesesArguments: peg$parseimplicitParensthesesArguments, inlineSpace: peg$parseinlineSpace, integerLiteral: peg$parseintegerLiteral, list: peg$parselist, literal: peg$parseliteral, logicalAndExpression: peg$parselogicalAndExpression, logicalOrExpression: peg$parselogicalOrExpression, multiLineComment: peg$parsemultiLineComment, multiplicativeExpression: peg$parsemultiplicativeExpression, multiplicativeOperator: peg$parsemultiplicativeOperator, namespace: peg$parsenamespace, newLine: peg$parsenewLine, numericLiteral: peg$parsenumericLiteral, nullishCoalescingExpression: peg$parsenullishCoalescingExpression, objectLiteral: peg$parseobjectLiteral, objectEntries: peg$parseobjectEntries, objectEntry: peg$parseobjectEntry, objectGetter: peg$parseobjectGetter, objectHiddenKey: peg$parseobjectHiddenKey, objectKey: peg$parseobjectKey, objectProperty: peg$parseobjectProperty, objectShorthandProperty: peg$parseobjectShorthandProperty, objectPublicKey: peg$parseobjectPublicKey, parenthesesArguments: peg$parseparenthesesArguments, path: peg$parsepath, pathArguments: peg$parsepathArguments, pathKey: peg$parsepathKey, pathSegment: peg$parsepathSegment, pathSegmentChar: peg$parsepathSegmentChar, pipelineExpression: peg$parsepipelineExpression, primary: peg$parseprimary, program: peg$parseprogram, protocolExpression: peg$parseprotocolExpression, qualifiedReference: peg$parsequalifiedReference, reference: peg$parsereference, relationalExpression: peg$parserelationalExpression, relationalOperator: peg$parserelationalOperator, rootDirectory: peg$parserootDirectory, scopeReference: peg$parsescopeReference, separator: peg$parseseparator, slashFollows: peg$parseslashFollows, shebang: peg$parseshebang, shiftExpression: peg$parseshiftExpression, shiftOperator: peg$parseshiftOperator, shorthandFunction: peg$parseshorthandFunction, singleArrow: peg$parsesingleArrow, singleLineComment: peg$parsesingleLineComment, singleQuoteString: peg$parsesingleQuoteString, singleQuoteStringChar: peg$parsesingleQuoteStringChar, spreadElement: peg$parsespreadElement, stringLiteral: peg$parsestringLiteral, templateDocument: peg$parsetemplateDocument, templateDocumentChar: peg$parsetemplateDocumentChar, templateDocumentText: peg$parsetemplateDocumentText, templateLiteral: peg$parsetemplateLiteral, templateLiteralChar: peg$parsetemplateLiteralChar, templateLiteralText: peg$parsetemplateLiteralText, templateSubstitution: peg$parsetemplateSubstitution, textChar: peg$parsetextChar, unaryExpression: peg$parseunaryExpression, unaryOperator: peg$parseunaryOperator, whitespace: peg$parsewhitespace, whitespaceWithNewLine: peg$parsewhitespaceWithNewLine };
|
|
206
206
|
var peg$startRuleFunction = peg$parse__;
|
|
207
207
|
|
|
208
208
|
var peg$c0 = "[";
|
|
@@ -791,22 +791,10 @@ function peg$parse(input, options) {
|
|
|
791
791
|
|
|
792
792
|
s0 = peg$currPos;
|
|
793
793
|
s1 = [];
|
|
794
|
-
s2 = peg$
|
|
795
|
-
if (s2 === peg$FAILED) {
|
|
796
|
-
s2 = peg$parsenewLine();
|
|
797
|
-
if (s2 === peg$FAILED) {
|
|
798
|
-
s2 = peg$parsecomment();
|
|
799
|
-
}
|
|
800
|
-
}
|
|
794
|
+
s2 = peg$parsewhitespace();
|
|
801
795
|
while (s2 !== peg$FAILED) {
|
|
802
796
|
s1.push(s2);
|
|
803
|
-
s2 = peg$
|
|
804
|
-
if (s2 === peg$FAILED) {
|
|
805
|
-
s2 = peg$parsenewLine();
|
|
806
|
-
if (s2 === peg$FAILED) {
|
|
807
|
-
s2 = peg$parsecomment();
|
|
808
|
-
}
|
|
809
|
-
}
|
|
797
|
+
s2 = peg$parsewhitespace();
|
|
810
798
|
}
|
|
811
799
|
peg$savedPos = s0;
|
|
812
800
|
s1 = peg$f0();
|
|
@@ -823,13 +811,23 @@ function peg$parse(input, options) {
|
|
|
823
811
|
if (s1 !== peg$FAILED) {
|
|
824
812
|
s2 = [];
|
|
825
813
|
s3 = peg$currPos;
|
|
826
|
-
s4 = peg$
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
814
|
+
s4 = peg$parsewhitespace();
|
|
815
|
+
if (s4 !== peg$FAILED) {
|
|
816
|
+
s5 = peg$parseadditiveOperator();
|
|
817
|
+
if (s5 !== peg$FAILED) {
|
|
818
|
+
s6 = peg$parsewhitespace();
|
|
819
|
+
if (s6 !== peg$FAILED) {
|
|
820
|
+
s7 = peg$parsemultiplicativeExpression();
|
|
821
|
+
if (s7 !== peg$FAILED) {
|
|
822
|
+
s3 = [ s5, s7 ];
|
|
823
|
+
} else {
|
|
824
|
+
peg$currPos = s3;
|
|
825
|
+
s3 = peg$FAILED;
|
|
826
|
+
}
|
|
827
|
+
} else {
|
|
828
|
+
peg$currPos = s3;
|
|
829
|
+
s3 = peg$FAILED;
|
|
830
|
+
}
|
|
833
831
|
} else {
|
|
834
832
|
peg$currPos = s3;
|
|
835
833
|
s3 = peg$FAILED;
|
|
@@ -841,13 +839,23 @@ function peg$parse(input, options) {
|
|
|
841
839
|
while (s3 !== peg$FAILED) {
|
|
842
840
|
s2.push(s3);
|
|
843
841
|
s3 = peg$currPos;
|
|
844
|
-
s4 = peg$
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
842
|
+
s4 = peg$parsewhitespace();
|
|
843
|
+
if (s4 !== peg$FAILED) {
|
|
844
|
+
s5 = peg$parseadditiveOperator();
|
|
845
|
+
if (s5 !== peg$FAILED) {
|
|
846
|
+
s6 = peg$parsewhitespace();
|
|
847
|
+
if (s6 !== peg$FAILED) {
|
|
848
|
+
s7 = peg$parsemultiplicativeExpression();
|
|
849
|
+
if (s7 !== peg$FAILED) {
|
|
850
|
+
s3 = [ s5, s7 ];
|
|
851
|
+
} else {
|
|
852
|
+
peg$currPos = s3;
|
|
853
|
+
s3 = peg$FAILED;
|
|
854
|
+
}
|
|
855
|
+
} else {
|
|
856
|
+
peg$currPos = s3;
|
|
857
|
+
s3 = peg$FAILED;
|
|
858
|
+
}
|
|
851
859
|
} else {
|
|
852
860
|
peg$currPos = s3;
|
|
853
861
|
s3 = peg$FAILED;
|
|
@@ -1565,7 +1573,7 @@ function peg$parse(input, options) {
|
|
|
1565
1573
|
}
|
|
1566
1574
|
if (s4 !== peg$FAILED) {
|
|
1567
1575
|
s5 = peg$parse__();
|
|
1568
|
-
s6 = peg$
|
|
1576
|
+
s6 = peg$parseshorthandFunction();
|
|
1569
1577
|
if (s6 !== peg$FAILED) {
|
|
1570
1578
|
s7 = peg$parse__();
|
|
1571
1579
|
if (input.charCodeAt(peg$currPos) === 58) {
|
|
@@ -1577,7 +1585,7 @@ function peg$parse(input, options) {
|
|
|
1577
1585
|
}
|
|
1578
1586
|
if (s8 !== peg$FAILED) {
|
|
1579
1587
|
s9 = peg$parse__();
|
|
1580
|
-
s10 = peg$
|
|
1588
|
+
s10 = peg$parseshorthandFunction();
|
|
1581
1589
|
if (s10 !== peg$FAILED) {
|
|
1582
1590
|
s2 = [ s6, s10 ];
|
|
1583
1591
|
} else {
|
|
@@ -2863,13 +2871,23 @@ function peg$parse(input, options) {
|
|
|
2863
2871
|
if (s1 !== peg$FAILED) {
|
|
2864
2872
|
s2 = [];
|
|
2865
2873
|
s3 = peg$currPos;
|
|
2866
|
-
s4 = peg$
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2874
|
+
s4 = peg$parsewhitespace();
|
|
2875
|
+
if (s4 !== peg$FAILED) {
|
|
2876
|
+
s5 = peg$parsemultiplicativeOperator();
|
|
2877
|
+
if (s5 !== peg$FAILED) {
|
|
2878
|
+
s6 = peg$parsewhitespace();
|
|
2879
|
+
if (s6 !== peg$FAILED) {
|
|
2880
|
+
s7 = peg$parseexponentiationExpression();
|
|
2881
|
+
if (s7 !== peg$FAILED) {
|
|
2882
|
+
s3 = [ s5, s7 ];
|
|
2883
|
+
} else {
|
|
2884
|
+
peg$currPos = s3;
|
|
2885
|
+
s3 = peg$FAILED;
|
|
2886
|
+
}
|
|
2887
|
+
} else {
|
|
2888
|
+
peg$currPos = s3;
|
|
2889
|
+
s3 = peg$FAILED;
|
|
2890
|
+
}
|
|
2873
2891
|
} else {
|
|
2874
2892
|
peg$currPos = s3;
|
|
2875
2893
|
s3 = peg$FAILED;
|
|
@@ -2881,13 +2899,23 @@ function peg$parse(input, options) {
|
|
|
2881
2899
|
while (s3 !== peg$FAILED) {
|
|
2882
2900
|
s2.push(s3);
|
|
2883
2901
|
s3 = peg$currPos;
|
|
2884
|
-
s4 = peg$
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2902
|
+
s4 = peg$parsewhitespace();
|
|
2903
|
+
if (s4 !== peg$FAILED) {
|
|
2904
|
+
s5 = peg$parsemultiplicativeOperator();
|
|
2905
|
+
if (s5 !== peg$FAILED) {
|
|
2906
|
+
s6 = peg$parsewhitespace();
|
|
2907
|
+
if (s6 !== peg$FAILED) {
|
|
2908
|
+
s7 = peg$parseexponentiationExpression();
|
|
2909
|
+
if (s7 !== peg$FAILED) {
|
|
2910
|
+
s3 = [ s5, s7 ];
|
|
2911
|
+
} else {
|
|
2912
|
+
peg$currPos = s3;
|
|
2913
|
+
s3 = peg$FAILED;
|
|
2914
|
+
}
|
|
2915
|
+
} else {
|
|
2916
|
+
peg$currPos = s3;
|
|
2917
|
+
s3 = peg$FAILED;
|
|
2918
|
+
}
|
|
2891
2919
|
} else {
|
|
2892
2920
|
peg$currPos = s3;
|
|
2893
2921
|
s3 = peg$FAILED;
|
|
@@ -4683,6 +4711,20 @@ function peg$parse(input, options) {
|
|
|
4683
4711
|
return s0;
|
|
4684
4712
|
}
|
|
4685
4713
|
|
|
4714
|
+
function peg$parsewhitespace() {
|
|
4715
|
+
var s0;
|
|
4716
|
+
|
|
4717
|
+
s0 = peg$parseinlineSpace();
|
|
4718
|
+
if (s0 === peg$FAILED) {
|
|
4719
|
+
s0 = peg$parsenewLine();
|
|
4720
|
+
if (s0 === peg$FAILED) {
|
|
4721
|
+
s0 = peg$parsecomment();
|
|
4722
|
+
}
|
|
4723
|
+
}
|
|
4724
|
+
|
|
4725
|
+
return s0;
|
|
4726
|
+
}
|
|
4727
|
+
|
|
4686
4728
|
function peg$parsewhitespaceWithNewLine() {
|
|
4687
4729
|
var s0, s1, s2, s3, s4;
|
|
4688
4730
|
|
|
@@ -4841,6 +4883,7 @@ const peg$allowedStartRules = [
|
|
|
4841
4883
|
"textChar",
|
|
4842
4884
|
"unaryExpression",
|
|
4843
4885
|
"unaryOperator",
|
|
4886
|
+
"whitespace",
|
|
4844
4887
|
"whitespaceWithNewLine"
|
|
4845
4888
|
];
|
|
4846
4889
|
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
isPlainObject,
|
|
3
|
+
isUnpackable,
|
|
4
|
+
merge,
|
|
5
|
+
Tree,
|
|
6
|
+
} from "@weborigami/async-tree";
|
|
2
7
|
|
|
3
8
|
/**
|
|
4
9
|
* Create a tree that's the result of merging the given trees.
|
|
@@ -28,8 +33,23 @@ export default async function mergeTrees(...trees) {
|
|
|
28
33
|
);
|
|
29
34
|
|
|
30
35
|
// If all trees are plain objects, return a plain object.
|
|
31
|
-
if (
|
|
32
|
-
|
|
36
|
+
if (
|
|
37
|
+
unpacked.every((tree) => isPlainObject(tree) && !Tree.isAsyncTree(tree))
|
|
38
|
+
) {
|
|
39
|
+
// If we do an Object.assign, we'd evaluate getters.
|
|
40
|
+
// To avoid that, we'll merge property descriptors.
|
|
41
|
+
const result = {};
|
|
42
|
+
for (const obj of unpacked) {
|
|
43
|
+
const descriptors = Object.getOwnPropertyDescriptors(obj);
|
|
44
|
+
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
45
|
+
if (descriptor.value !== undefined) {
|
|
46
|
+
result[key] = descriptor.value;
|
|
47
|
+
} else {
|
|
48
|
+
Object.defineProperty(result, key, descriptor);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
33
53
|
}
|
|
34
54
|
|
|
35
55
|
// If all trees are arrays, return an array.
|
|
@@ -433,6 +433,18 @@ describe("Origami parser", () => {
|
|
|
433
433
|
[ops.scope, "slug"],
|
|
434
434
|
],
|
|
435
435
|
]);
|
|
436
|
+
assertParse("expression", "keys ~", [
|
|
437
|
+
[ops.builtin, "keys"],
|
|
438
|
+
[ops.homeDirectory],
|
|
439
|
+
]);
|
|
440
|
+
assertParse("expression", "keys /Users/alice", [
|
|
441
|
+
[ops.builtin, "keys"],
|
|
442
|
+
[
|
|
443
|
+
ops.traverse,
|
|
444
|
+
[ops.rootDirectory, [ops.literal, "Users/"]],
|
|
445
|
+
[ops.literal, "alice"],
|
|
446
|
+
],
|
|
447
|
+
]);
|
|
436
448
|
|
|
437
449
|
// Verify parser treatment of identifiers containing operators
|
|
438
450
|
assertParse("expression", "a + b", [
|
|
@@ -1,50 +1,68 @@
|
|
|
1
|
-
import { Tree } from "@weborigami/async-tree";
|
|
1
|
+
import { ObjectTree, 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";
|
|
5
5
|
|
|
6
6
|
describe("mergeTrees", () => {
|
|
7
|
-
test("
|
|
8
|
-
|
|
7
|
+
test("if all arguments are plain objects, result is a plain object", async () => {
|
|
8
|
+
let calledFoo = false;
|
|
9
|
+
let calledBar = false;
|
|
10
|
+
const result = await mergeTrees.call(
|
|
9
11
|
null,
|
|
10
12
|
{
|
|
11
13
|
a: 1,
|
|
12
14
|
b: 2,
|
|
15
|
+
get foo() {
|
|
16
|
+
calledFoo = true;
|
|
17
|
+
return true;
|
|
18
|
+
},
|
|
13
19
|
},
|
|
14
20
|
{
|
|
15
21
|
b: 3,
|
|
16
22
|
c: 4,
|
|
23
|
+
get bar() {
|
|
24
|
+
calledBar = true;
|
|
25
|
+
return true;
|
|
26
|
+
},
|
|
17
27
|
}
|
|
18
28
|
);
|
|
19
|
-
|
|
20
|
-
|
|
29
|
+
|
|
30
|
+
// Shouldn't call functions when just getting keys
|
|
31
|
+
assert.deepEqual(Object.keys(result), ["a", "b", "foo", "c", "bar"]);
|
|
32
|
+
assert(!calledFoo);
|
|
33
|
+
assert(!calledBar);
|
|
34
|
+
|
|
35
|
+
assert.deepEqual(result, {
|
|
21
36
|
a: 1,
|
|
22
37
|
b: 3,
|
|
38
|
+
foo: true,
|
|
23
39
|
c: 4,
|
|
40
|
+
bar: true,
|
|
24
41
|
});
|
|
25
42
|
});
|
|
26
43
|
|
|
27
|
-
test("if all arguments are
|
|
28
|
-
const result = await mergeTrees.call(
|
|
44
|
+
test("if all arguments are arrays, result is an array", async () => {
|
|
45
|
+
const result = await mergeTrees.call(null, [1, 2], [3, 4]);
|
|
46
|
+
assert.deepEqual(result, [1, 2, 3, 4]);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("merges heterogenous arguments as trees", async () => {
|
|
50
|
+
const tree = await mergeTrees.call(
|
|
29
51
|
null,
|
|
30
|
-
{
|
|
52
|
+
new ObjectTree({
|
|
31
53
|
a: 1,
|
|
32
54
|
b: 2,
|
|
33
|
-
},
|
|
55
|
+
}),
|
|
34
56
|
{
|
|
35
57
|
b: 3,
|
|
36
58
|
c: 4,
|
|
37
59
|
}
|
|
38
60
|
);
|
|
39
|
-
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
assert.deepEqual(await Tree.plain(tree), {
|
|
40
63
|
a: 1,
|
|
41
64
|
b: 3,
|
|
42
65
|
c: 4,
|
|
43
66
|
});
|
|
44
67
|
});
|
|
45
|
-
|
|
46
|
-
test("if all arguments are arrays, result is an array", async () => {
|
|
47
|
-
const result = await mergeTrees.call(null, [1, 2], [3, 4]);
|
|
48
|
-
assert.deepEqual(result, [1, 2, 3, 4]);
|
|
49
|
-
});
|
|
50
68
|
});
|