@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.
Files changed (47) hide show
  1. package/dist/index.cjs.js +899 -336
  2. package/dist/index.d.ts +275 -93
  3. package/dist/index.esm.js +890 -334
  4. package/dist/player.dev.js +11429 -0
  5. package/dist/player.prod.js +2 -0
  6. package/package.json +16 -5
  7. package/src/binding/binding.ts +8 -0
  8. package/src/binding/index.ts +14 -4
  9. package/src/binding/resolver.ts +2 -4
  10. package/src/binding-grammar/custom/index.ts +17 -9
  11. package/src/controllers/constants/index.ts +9 -5
  12. package/src/controllers/{data.ts → data/controller.ts} +62 -61
  13. package/src/controllers/data/index.ts +1 -0
  14. package/src/controllers/data/utils.ts +42 -0
  15. package/src/controllers/flow/controller.ts +16 -12
  16. package/src/controllers/flow/flow.ts +6 -1
  17. package/src/controllers/index.ts +1 -1
  18. package/src/controllers/validation/binding-tracker.ts +42 -19
  19. package/src/controllers/validation/controller.ts +375 -148
  20. package/src/controllers/view/asset-transform.ts +4 -1
  21. package/src/controllers/view/controller.ts +20 -3
  22. package/src/data/dependency-tracker.ts +14 -0
  23. package/src/data/local-model.ts +25 -1
  24. package/src/data/model.ts +60 -8
  25. package/src/data/noop-model.ts +2 -0
  26. package/src/expressions/evaluator-functions.ts +24 -2
  27. package/src/expressions/evaluator.ts +38 -34
  28. package/src/expressions/index.ts +1 -0
  29. package/src/expressions/parser.ts +116 -44
  30. package/src/expressions/types.ts +50 -17
  31. package/src/expressions/utils.ts +143 -1
  32. package/src/player.ts +60 -46
  33. package/src/plugins/default-exp-plugin.ts +57 -0
  34. package/src/plugins/flow-exp-plugin.ts +2 -2
  35. package/src/schema/schema.ts +28 -9
  36. package/src/string-resolver/index.ts +26 -9
  37. package/src/types.ts +6 -3
  38. package/src/validator/binding-map-splice.ts +59 -0
  39. package/src/validator/index.ts +1 -0
  40. package/src/validator/types.ts +11 -3
  41. package/src/validator/validation-middleware.ts +58 -6
  42. package/src/view/parser/index.ts +51 -3
  43. package/src/view/plugins/applicability.ts +1 -1
  44. package/src/view/plugins/string-resolver.ts +35 -9
  45. package/src/view/plugins/template-plugin.ts +1 -6
  46. package/src/view/resolver/index.ts +119 -54
  47. 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 default function parseExpression(expr: string): ExpressionNode {
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(biop, left, right);
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(stack[i - 1].value, stack[i - 2], node);
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
- while (index < length) {
858
- const chIndex = exprICode(index);
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
- // Expressions can be separated by semicolons, commas, or just inferred without any
861
- // separators
862
- if (chIndex === SEMCOL_CODE || chIndex === COMMA_CODE) {
863
- index++; // ignore separators
864
- continue;
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
- const node = gobbleExpression();
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
- // Try to gobble each expression individually
870
- if (node) {
871
- nodes.push(node);
872
- // If we weren't able to find a binary expression and are out of room, then
873
- // the expression passed in probably has too much
874
- } else if (index < length) {
875
- throwError(`Unexpected "${exprI(index)}"`, index);
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
- // If there's only one expression just try returning the expression
880
- if (nodes.length === 1) {
881
- return nodes[0];
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
  }
@@ -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
- export type ExpressionType =
11
- | object
15
+
16
+ export type BasicExpressionTypes =
12
17
  | ExpressionLiteralType
13
- | Array<ExpressionLiteralType>
14
- | ExpressionNode;
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 typeof x === 'object' && x.__id === ExpNodeOpaqueIdentifier;
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 extends BaseNode<'LogicalExpression'> {
92
- /** The left hand side of the equation */
93
- left: any;
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: any;
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: any;
154
+ key: ExpressionNode;
122
155
 
123
156
  /** the associated value */
124
- value: any;
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: any[];
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: any[];
199
+ elements: ExpressionNode[];
167
200
  }
168
201
 
169
202
  export interface IdentifierNode extends BaseNode<'Identifier'> {