@player-ui/player 0.3.1-next.0 → 0.3.1
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/dist/index.cjs.js +899 -336
- package/dist/index.d.ts +275 -93
- package/dist/index.esm.js +890 -334
- package/dist/player.dev.js +11429 -0
- package/dist/player.prod.js +2 -0
- package/package.json +16 -5
- package/src/binding/binding.ts +8 -0
- package/src/binding/index.ts +14 -4
- package/src/binding/resolver.ts +2 -4
- package/src/binding-grammar/custom/index.ts +17 -9
- package/src/controllers/constants/index.ts +9 -5
- package/src/controllers/{data.ts → data/controller.ts} +62 -61
- package/src/controllers/data/index.ts +1 -0
- package/src/controllers/data/utils.ts +42 -0
- package/src/controllers/flow/controller.ts +16 -12
- package/src/controllers/flow/flow.ts +6 -1
- package/src/controllers/index.ts +1 -1
- package/src/controllers/validation/binding-tracker.ts +42 -19
- package/src/controllers/validation/controller.ts +375 -148
- package/src/controllers/view/asset-transform.ts +4 -1
- package/src/controllers/view/controller.ts +20 -3
- package/src/data/dependency-tracker.ts +14 -0
- package/src/data/local-model.ts +25 -1
- package/src/data/model.ts +60 -8
- package/src/data/noop-model.ts +2 -0
- package/src/expressions/evaluator-functions.ts +24 -2
- package/src/expressions/evaluator.ts +38 -34
- package/src/expressions/index.ts +1 -0
- package/src/expressions/parser.ts +116 -44
- package/src/expressions/types.ts +50 -17
- package/src/expressions/utils.ts +143 -1
- package/src/player.ts +60 -46
- package/src/plugins/default-exp-plugin.ts +57 -0
- package/src/plugins/flow-exp-plugin.ts +2 -2
- package/src/schema/schema.ts +28 -9
- package/src/string-resolver/index.ts +26 -9
- package/src/types.ts +6 -3
- package/src/validator/binding-map-splice.ts +59 -0
- package/src/validator/index.ts +1 -0
- package/src/validator/types.ts +11 -3
- package/src/validator/validation-middleware.ts +58 -6
- package/src/view/parser/index.ts +51 -3
- package/src/view/plugins/applicability.ts +1 -1
- package/src/view/plugins/string-resolver.ts +35 -9
- package/src/view/plugins/template-plugin.ts +1 -6
- package/src/view/resolver/index.ts +119 -54
- package/src/view/resolver/types.ts +48 -7
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* An expression to AST parser based on JSEP: http://jsep.from.so/
|
|
4
4
|
*/
|
|
5
|
-
import type { ExpressionNode, ExpressionNodeType } from './types';
|
|
5
|
+
import type { ExpressionNode, ExpressionNodeType, NodeLocation } from './types';
|
|
6
6
|
import { ExpNodeOpaqueIdentifier } from './types';
|
|
7
7
|
|
|
8
8
|
const PERIOD_CODE = 46; // '.'
|
|
@@ -80,6 +80,18 @@ function throwError(message: string, index: number) {
|
|
|
80
80
|
throw err;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/** Create a new location marker that spans both nodes */
|
|
84
|
+
function createSpanningLocation(start?: NodeLocation, end?: NodeLocation) {
|
|
85
|
+
if (!start || !end) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
start: start.start,
|
|
91
|
+
end: end.end,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
83
95
|
/** Get return the longest key length of any object */
|
|
84
96
|
function getMaxKeyLen(obj: object): number {
|
|
85
97
|
let maxLen = 0;
|
|
@@ -121,7 +133,8 @@ function binaryPrecedence(opVal: string): number {
|
|
|
121
133
|
function createBinaryExpression(
|
|
122
134
|
operator: string | boolean,
|
|
123
135
|
left: string,
|
|
124
|
-
right: string
|
|
136
|
+
right: string,
|
|
137
|
+
location?: NodeLocation
|
|
125
138
|
) {
|
|
126
139
|
let type: ExpressionNodeType;
|
|
127
140
|
|
|
@@ -146,6 +159,7 @@ function createBinaryExpression(
|
|
|
146
159
|
operator,
|
|
147
160
|
left,
|
|
148
161
|
right,
|
|
162
|
+
location,
|
|
149
163
|
};
|
|
150
164
|
}
|
|
151
165
|
|
|
@@ -181,7 +195,15 @@ function isModelRefStart(ch0: number, ch1: number) {
|
|
|
181
195
|
}
|
|
182
196
|
|
|
183
197
|
/** Parse out an expression from the string */
|
|
184
|
-
export
|
|
198
|
+
export function parseExpression(
|
|
199
|
+
expr: string,
|
|
200
|
+
options?: {
|
|
201
|
+
/** If true (the default), will throw on invalid expressions */
|
|
202
|
+
strict?: boolean;
|
|
203
|
+
}
|
|
204
|
+
): ExpressionNode {
|
|
205
|
+
const strictMode = options?.strict ?? true;
|
|
206
|
+
|
|
185
207
|
// `index` stores the character number we are currently at while `length` is a constant
|
|
186
208
|
// All of the gobbles below will modify `index` as we move along
|
|
187
209
|
const charAtFunc = expr.charAt;
|
|
@@ -190,6 +212,18 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
190
212
|
|
|
191
213
|
let index = 0;
|
|
192
214
|
|
|
215
|
+
/** Create a location object */
|
|
216
|
+
const getLocation = (startChar: number) => {
|
|
217
|
+
return {
|
|
218
|
+
start: {
|
|
219
|
+
character: startChar,
|
|
220
|
+
},
|
|
221
|
+
end: {
|
|
222
|
+
character: index,
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
|
|
193
227
|
/** Grab the char at the index from the expression */
|
|
194
228
|
function exprI(i: number) {
|
|
195
229
|
return charAtFunc.call(expr, i);
|
|
@@ -217,13 +251,14 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
217
251
|
let key;
|
|
218
252
|
let value;
|
|
219
253
|
let chCode;
|
|
254
|
+
const startCharIndex = index;
|
|
255
|
+
|
|
220
256
|
// get rid of OCURL_CODE
|
|
221
257
|
++index;
|
|
222
258
|
|
|
223
259
|
while (index < length) {
|
|
224
260
|
gobbleSpaces();
|
|
225
261
|
chCode = exprICode(index);
|
|
226
|
-
|
|
227
262
|
// check for end
|
|
228
263
|
if (chCode === CCURL_CODE) {
|
|
229
264
|
// if we are at the end but a key was defined
|
|
@@ -244,7 +279,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
244
279
|
key = gobbleStringLiteral();
|
|
245
280
|
// remove spaces
|
|
246
281
|
gobbleSpaces();
|
|
247
|
-
|
|
248
282
|
// remove colon
|
|
249
283
|
if (exprICode(index) === COLON_CODE) {
|
|
250
284
|
index++;
|
|
@@ -258,7 +292,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
258
292
|
attributes.push({ key, value });
|
|
259
293
|
gobbleSpaces();
|
|
260
294
|
chCode = exprICode(index);
|
|
261
|
-
|
|
262
295
|
if (chCode === COMMA_CODE) {
|
|
263
296
|
index++;
|
|
264
297
|
} else if (chCode !== CCURL_CODE) {
|
|
@@ -282,6 +315,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
282
315
|
__id: ExpNodeOpaqueIdentifier,
|
|
283
316
|
type: 'Object',
|
|
284
317
|
attributes,
|
|
318
|
+
location: getLocation(startCharIndex),
|
|
285
319
|
};
|
|
286
320
|
}
|
|
287
321
|
|
|
@@ -290,7 +324,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
290
324
|
*/
|
|
291
325
|
function gobbleSpaces() {
|
|
292
326
|
let ch = exprICode(index);
|
|
293
|
-
|
|
294
327
|
// Space or tab
|
|
295
328
|
while (ch === 32 || ch === 9) {
|
|
296
329
|
ch = exprICode(++index);
|
|
@@ -303,6 +336,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
303
336
|
function gobbleExpression(): ExpressionNode {
|
|
304
337
|
const test = gobbleBinaryExpression();
|
|
305
338
|
gobbleSpaces();
|
|
339
|
+
const startCharIndex = index;
|
|
306
340
|
|
|
307
341
|
if (index < length && exprICode(index) === QUMARK_CODE) {
|
|
308
342
|
// Ternary expression: test ? consequent : alternate
|
|
@@ -329,6 +363,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
329
363
|
test,
|
|
330
364
|
consequent,
|
|
331
365
|
alternate,
|
|
366
|
+
location: getLocation(startCharIndex),
|
|
332
367
|
};
|
|
333
368
|
}
|
|
334
369
|
|
|
@@ -353,7 +388,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
353
388
|
while (tcLen > 0) {
|
|
354
389
|
if (Object.prototype.hasOwnProperty.call(binaryOps, toCheck)) {
|
|
355
390
|
index += tcLen;
|
|
356
|
-
|
|
357
391
|
return toCheck;
|
|
358
392
|
}
|
|
359
393
|
|
|
@@ -395,7 +429,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
395
429
|
|
|
396
430
|
// Properly deal with precedence using [recursive descent](http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm)
|
|
397
431
|
biop = gobbleBinaryOp();
|
|
398
|
-
|
|
399
432
|
while (biop) {
|
|
400
433
|
prec = binaryPrecedence(biop);
|
|
401
434
|
|
|
@@ -410,7 +443,12 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
410
443
|
right = stack.pop();
|
|
411
444
|
biop = stack.pop().value;
|
|
412
445
|
left = stack.pop();
|
|
413
|
-
node = createBinaryExpression(
|
|
446
|
+
node = createBinaryExpression(
|
|
447
|
+
biop,
|
|
448
|
+
left,
|
|
449
|
+
right,
|
|
450
|
+
createSpanningLocation(left.location, right.location)
|
|
451
|
+
);
|
|
414
452
|
stack.push(node);
|
|
415
453
|
}
|
|
416
454
|
|
|
@@ -428,7 +466,12 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
428
466
|
node = stack[i];
|
|
429
467
|
|
|
430
468
|
while (i > 1) {
|
|
431
|
-
node = createBinaryExpression(
|
|
469
|
+
node = createBinaryExpression(
|
|
470
|
+
stack[i - 1].value,
|
|
471
|
+
stack[i - 2],
|
|
472
|
+
node,
|
|
473
|
+
createSpanningLocation(stack[i - 2].location, node.location)
|
|
474
|
+
);
|
|
432
475
|
i -= 2;
|
|
433
476
|
}
|
|
434
477
|
|
|
@@ -442,6 +485,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
442
485
|
function gobbleToken(): any {
|
|
443
486
|
gobbleSpaces();
|
|
444
487
|
const ch = exprICode(index);
|
|
488
|
+
const startCharIndex = index;
|
|
445
489
|
|
|
446
490
|
if (isDecimalDigit(ch) || ch === PERIOD_CODE) {
|
|
447
491
|
// Char code 46 is a dot `.` which can start off a numeric literal
|
|
@@ -478,13 +522,13 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
478
522
|
while (tcLen > 0) {
|
|
479
523
|
if (Object.prototype.hasOwnProperty.call(unaryOps, toCheck)) {
|
|
480
524
|
index += tcLen;
|
|
481
|
-
|
|
482
525
|
return {
|
|
483
526
|
__id: ExpNodeOpaqueIdentifier,
|
|
484
527
|
type: 'UnaryExpression',
|
|
485
528
|
operator: toCheck,
|
|
486
529
|
argument: gobbleToken(),
|
|
487
530
|
prefix: true,
|
|
531
|
+
location: getLocation(startCharIndex),
|
|
488
532
|
};
|
|
489
533
|
}
|
|
490
534
|
|
|
@@ -500,6 +544,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
500
544
|
*/
|
|
501
545
|
function gobbleNumericLiteral() {
|
|
502
546
|
let num = '';
|
|
547
|
+
const startCharIndex = index;
|
|
503
548
|
|
|
504
549
|
while (isDecimalDigit(exprICode(index))) {
|
|
505
550
|
num += exprI(index++);
|
|
@@ -515,7 +560,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
515
560
|
}
|
|
516
561
|
|
|
517
562
|
let ch = exprI(index);
|
|
518
|
-
|
|
519
563
|
if (ch === 'e' || ch === 'E') {
|
|
520
564
|
// Exponent marker
|
|
521
565
|
num += exprI(index++);
|
|
@@ -537,7 +581,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
537
581
|
}
|
|
538
582
|
|
|
539
583
|
const chCode = exprICode(index);
|
|
540
|
-
|
|
541
584
|
// Check to make sure this isn't a variable name that start with a number (123abc)
|
|
542
585
|
if (isIdentifierStart(chCode)) {
|
|
543
586
|
throwError(
|
|
@@ -553,6 +596,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
553
596
|
type: 'Literal',
|
|
554
597
|
value: parseFloat(num),
|
|
555
598
|
raw: num,
|
|
599
|
+
location: getLocation(startCharIndex),
|
|
556
600
|
};
|
|
557
601
|
}
|
|
558
602
|
|
|
@@ -564,6 +608,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
564
608
|
const quote = exprI(index++);
|
|
565
609
|
let str = '';
|
|
566
610
|
let closed = false;
|
|
611
|
+
const startCharIndex = index;
|
|
567
612
|
|
|
568
613
|
while (index < length) {
|
|
569
614
|
let ch = exprI(index++);
|
|
@@ -613,6 +658,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
613
658
|
type: 'Literal',
|
|
614
659
|
value: str,
|
|
615
660
|
raw: `${quote}${str}${quote}`,
|
|
661
|
+
location: getLocation(startCharIndex),
|
|
616
662
|
};
|
|
617
663
|
}
|
|
618
664
|
|
|
@@ -624,9 +670,9 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
624
670
|
let str = '';
|
|
625
671
|
let closed = false;
|
|
626
672
|
let openBraceCount = 1;
|
|
673
|
+
const startCharIndex = index;
|
|
627
674
|
|
|
628
675
|
index += 2; // Skip the {{
|
|
629
|
-
|
|
630
676
|
while (index < length) {
|
|
631
677
|
const ch = exprI(index++);
|
|
632
678
|
|
|
@@ -657,6 +703,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
657
703
|
__id: ExpNodeOpaqueIdentifier,
|
|
658
704
|
type: 'ModelRef',
|
|
659
705
|
ref: str,
|
|
706
|
+
location: getLocation(startCharIndex),
|
|
660
707
|
};
|
|
661
708
|
}
|
|
662
709
|
|
|
@@ -678,7 +725,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
678
725
|
|
|
679
726
|
while (index < length) {
|
|
680
727
|
ch = exprICode(index);
|
|
681
|
-
|
|
682
728
|
if (isIdentifierPart(ch)) {
|
|
683
729
|
index++;
|
|
684
730
|
} else {
|
|
@@ -694,6 +740,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
694
740
|
type: 'Literal',
|
|
695
741
|
value: (literals as any)[identifier],
|
|
696
742
|
raw: identifier,
|
|
743
|
+
location: getLocation(start),
|
|
697
744
|
};
|
|
698
745
|
}
|
|
699
746
|
|
|
@@ -701,6 +748,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
701
748
|
return {
|
|
702
749
|
__id: ExpNodeOpaqueIdentifier,
|
|
703
750
|
type: 'ThisExpression',
|
|
751
|
+
location: getLocation(start),
|
|
704
752
|
};
|
|
705
753
|
}
|
|
706
754
|
|
|
@@ -708,6 +756,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
708
756
|
__id: ExpNodeOpaqueIdentifier,
|
|
709
757
|
type: 'Identifier',
|
|
710
758
|
name: identifier,
|
|
759
|
+
location: getLocation(start),
|
|
711
760
|
};
|
|
712
761
|
}
|
|
713
762
|
|
|
@@ -748,6 +797,10 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
748
797
|
args.push(node);
|
|
749
798
|
}
|
|
750
799
|
|
|
800
|
+
if (charIndex !== termination) {
|
|
801
|
+
throwError(`Expected ${String.fromCharCode(termination)}`, index);
|
|
802
|
+
}
|
|
803
|
+
|
|
751
804
|
return args;
|
|
752
805
|
}
|
|
753
806
|
|
|
@@ -761,7 +814,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
761
814
|
let charIndex = exprICode(index);
|
|
762
815
|
let node: any =
|
|
763
816
|
charIndex === OPAREN_CODE ? gobbleGroup() : gobbleIdentifier();
|
|
764
|
-
|
|
817
|
+
const startCharIndex = index;
|
|
765
818
|
gobbleSpaces();
|
|
766
819
|
charIndex = exprICode(index);
|
|
767
820
|
|
|
@@ -781,6 +834,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
781
834
|
computed: false,
|
|
782
835
|
object: node,
|
|
783
836
|
property: gobbleIdentifier(),
|
|
837
|
+
location: getLocation(startCharIndex),
|
|
784
838
|
};
|
|
785
839
|
} else if (charIndex === OBRACK_CODE) {
|
|
786
840
|
node = {
|
|
@@ -789,6 +843,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
789
843
|
computed: true,
|
|
790
844
|
object: node,
|
|
791
845
|
property: gobbleExpression(),
|
|
846
|
+
location: getLocation(startCharIndex),
|
|
792
847
|
};
|
|
793
848
|
|
|
794
849
|
gobbleSpaces();
|
|
@@ -806,6 +861,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
806
861
|
type: 'CallExpression',
|
|
807
862
|
args: gobbleArguments(CPAREN_CODE),
|
|
808
863
|
callTarget: node,
|
|
864
|
+
location: getLocation(startCharIndex),
|
|
809
865
|
};
|
|
810
866
|
}
|
|
811
867
|
|
|
@@ -817,7 +873,7 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
817
873
|
}
|
|
818
874
|
|
|
819
875
|
/**
|
|
820
|
-
* Responsible for parsing a group within parentheses `()`
|
|
876
|
+
* Responsible for parsing a group of things within parentheses `()`
|
|
821
877
|
* This function assumes that it needs to gobble the opening parenthesis
|
|
822
878
|
* and then tries to gobble everything within that parenthesis, assuming
|
|
823
879
|
* that the next thing it should see is the close parenthesis. If not,
|
|
@@ -830,7 +886,6 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
830
886
|
|
|
831
887
|
if (exprICode(index) === CPAREN_CODE) {
|
|
832
888
|
index++;
|
|
833
|
-
|
|
834
889
|
return node;
|
|
835
890
|
}
|
|
836
891
|
|
|
@@ -843,47 +898,64 @@ export default function parseExpression(expr: string): ExpressionNode {
|
|
|
843
898
|
* and then tries to gobble the expressions as arguments.
|
|
844
899
|
*/
|
|
845
900
|
function gobbleArray() {
|
|
901
|
+
const startCharIndex = index;
|
|
846
902
|
index++;
|
|
847
903
|
|
|
848
904
|
return {
|
|
849
905
|
__id: ExpNodeOpaqueIdentifier,
|
|
850
906
|
type: 'ArrayExpression',
|
|
851
907
|
elements: gobbleArguments(CBRACK_CODE),
|
|
908
|
+
location: getLocation(startCharIndex),
|
|
852
909
|
};
|
|
853
910
|
}
|
|
854
911
|
|
|
855
912
|
const nodes = [];
|
|
856
913
|
|
|
857
|
-
|
|
858
|
-
|
|
914
|
+
try {
|
|
915
|
+
while (index < length) {
|
|
916
|
+
const chIndex = exprICode(index);
|
|
917
|
+
|
|
918
|
+
// Expressions can be separated by semicolons, commas, or just inferred without any
|
|
919
|
+
// separators
|
|
920
|
+
if (chIndex === SEMCOL_CODE || chIndex === COMMA_CODE) {
|
|
921
|
+
index++; // ignore separators
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
const node = gobbleExpression();
|
|
859
926
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
927
|
+
// Try to gobble each expression individually
|
|
928
|
+
if (node) {
|
|
929
|
+
nodes.push(node);
|
|
930
|
+
// If we weren't able to find a binary expression and are out of room, then
|
|
931
|
+
// the expression passed in probably has too much
|
|
932
|
+
} else if (index < length) {
|
|
933
|
+
throwError(`Unexpected "${exprI(index)}"`, index);
|
|
934
|
+
}
|
|
865
935
|
}
|
|
866
936
|
|
|
867
|
-
|
|
937
|
+
// If there's only one expression just try returning the expression
|
|
938
|
+
if (nodes.length === 1) {
|
|
939
|
+
return nodes[0];
|
|
940
|
+
}
|
|
868
941
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
}
|
|
875
|
-
|
|
942
|
+
return {
|
|
943
|
+
__id: ExpNodeOpaqueIdentifier,
|
|
944
|
+
type: 'Compound',
|
|
945
|
+
body: nodes,
|
|
946
|
+
location: getLocation(0),
|
|
947
|
+
};
|
|
948
|
+
} catch (e) {
|
|
949
|
+
if (strictMode || !(e instanceof Error)) {
|
|
950
|
+
throw e;
|
|
876
951
|
}
|
|
877
|
-
}
|
|
878
952
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
953
|
+
return {
|
|
954
|
+
__id: ExpNodeOpaqueIdentifier,
|
|
955
|
+
type: 'Compound',
|
|
956
|
+
body: nodes,
|
|
957
|
+
location: getLocation(0),
|
|
958
|
+
error: e,
|
|
959
|
+
};
|
|
882
960
|
}
|
|
883
|
-
|
|
884
|
-
return {
|
|
885
|
-
__id: ExpNodeOpaqueIdentifier,
|
|
886
|
-
type: 'Compound',
|
|
887
|
-
body: nodes,
|
|
888
|
-
};
|
|
889
961
|
}
|
package/src/expressions/types.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import type { DataModelWithParser } from '../data';
|
|
2
2
|
import type { Logger } from '../logger';
|
|
3
3
|
|
|
4
|
+
export type ExpressionObjectType = {
|
|
5
|
+
/** The expression to eval */
|
|
6
|
+
value: BasicExpressionTypes;
|
|
7
|
+
};
|
|
8
|
+
|
|
4
9
|
export type ExpressionLiteralType =
|
|
5
10
|
| string
|
|
6
11
|
| number
|
|
7
12
|
| boolean
|
|
8
13
|
| undefined
|
|
9
14
|
| null;
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
|
|
16
|
+
export type BasicExpressionTypes =
|
|
12
17
|
| ExpressionLiteralType
|
|
13
|
-
|
|
|
14
|
-
|
|
|
18
|
+
| ExpressionObjectType
|
|
19
|
+
| Array<ExpressionLiteralType | ExpressionObjectType>;
|
|
20
|
+
|
|
21
|
+
export type ExpressionType = BasicExpressionTypes | ExpressionNode;
|
|
15
22
|
|
|
16
23
|
export interface OperatorProcessingOptions {
|
|
17
24
|
/**
|
|
@@ -53,7 +60,28 @@ export const ExpNodeOpaqueIdentifier = Symbol('Expression Node ID');
|
|
|
53
60
|
|
|
54
61
|
/** Checks if the input is an already processed Expression node */
|
|
55
62
|
export function isExpressionNode(x: any): x is ExpressionNode {
|
|
56
|
-
return
|
|
63
|
+
return (
|
|
64
|
+
typeof x === 'object' &&
|
|
65
|
+
x !== null &&
|
|
66
|
+
!Array.isArray(x) &&
|
|
67
|
+
x.__id === ExpNodeOpaqueIdentifier
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface NodePosition {
|
|
72
|
+
/** The character location */
|
|
73
|
+
character: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface NodeLocation {
|
|
77
|
+
// We only care about the character offset, not the line/column for now
|
|
78
|
+
// But making these objects allows us to add more (like line number) later
|
|
79
|
+
|
|
80
|
+
/** The start of the node */
|
|
81
|
+
start: NodePosition;
|
|
82
|
+
|
|
83
|
+
/** The end of the node */
|
|
84
|
+
end: NodePosition;
|
|
57
85
|
}
|
|
58
86
|
|
|
59
87
|
export interface BaseNode<T> {
|
|
@@ -62,6 +90,15 @@ export interface BaseNode<T> {
|
|
|
62
90
|
|
|
63
91
|
/** How to tell this apart from other objects */
|
|
64
92
|
__id: typeof ExpNodeOpaqueIdentifier;
|
|
93
|
+
|
|
94
|
+
/** The location of the node in the source expression string */
|
|
95
|
+
location?: NodeLocation;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The error that occurred while parsing this node
|
|
99
|
+
* This is only set if the parsing mode is set to non-strict
|
|
100
|
+
*/
|
|
101
|
+
error?: Error;
|
|
65
102
|
}
|
|
66
103
|
|
|
67
104
|
/** A helper interface for nodes that container left and right children */
|
|
@@ -88,13 +125,9 @@ export interface BinaryNode
|
|
|
88
125
|
operator: string;
|
|
89
126
|
}
|
|
90
127
|
|
|
91
|
-
export interface LogicalNode
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
/** The right hand side of the equation */
|
|
96
|
-
right: any;
|
|
97
|
-
|
|
128
|
+
export interface LogicalNode
|
|
129
|
+
extends BaseNode<'LogicalExpression'>,
|
|
130
|
+
DirectionalNode {
|
|
98
131
|
/** The logical operation to perform on the nodes */
|
|
99
132
|
operator: string;
|
|
100
133
|
}
|
|
@@ -104,7 +137,7 @@ export interface UnaryNode extends BaseNode<'UnaryExpression'> {
|
|
|
104
137
|
operator: string;
|
|
105
138
|
|
|
106
139
|
/** The single argument that the operation should be performed on */
|
|
107
|
-
argument:
|
|
140
|
+
argument: ExpressionNode;
|
|
108
141
|
}
|
|
109
142
|
|
|
110
143
|
export type ThisNode = BaseNode<'ThisExpression'>;
|
|
@@ -118,10 +151,10 @@ export interface ObjectNode extends BaseNode<'Object'> {
|
|
|
118
151
|
/** */
|
|
119
152
|
attributes: Array<{
|
|
120
153
|
/** The property name of the object */
|
|
121
|
-
key:
|
|
154
|
+
key: ExpressionNode;
|
|
122
155
|
|
|
123
156
|
/** the associated value */
|
|
124
|
-
value:
|
|
157
|
+
value: ExpressionNode;
|
|
125
158
|
}>;
|
|
126
159
|
}
|
|
127
160
|
|
|
@@ -155,7 +188,7 @@ export interface CompoundNode extends BaseNode<'Compound'> {
|
|
|
155
188
|
|
|
156
189
|
export interface CallExpressionNode extends BaseNode<'CallExpression'> {
|
|
157
190
|
/** The arguments to the function */
|
|
158
|
-
args:
|
|
191
|
+
args: ExpressionNode[];
|
|
159
192
|
|
|
160
193
|
/** The function name */
|
|
161
194
|
callTarget: IdentifierNode;
|
|
@@ -163,7 +196,7 @@ export interface CallExpressionNode extends BaseNode<'CallExpression'> {
|
|
|
163
196
|
|
|
164
197
|
export interface ArrayExpressionNode extends BaseNode<'ArrayExpression'> {
|
|
165
198
|
/** The items in an array */
|
|
166
|
-
elements:
|
|
199
|
+
elements: ExpressionNode[];
|
|
167
200
|
}
|
|
168
201
|
|
|
169
202
|
export interface IdentifierNode extends BaseNode<'Identifier'> {
|