@herb-tools/core 0.1.1 → 0.3.0

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/src/nodes.ts CHANGED
@@ -1,49 +1,28 @@
1
1
  // NOTE: This file is generated by the templates/template.rb script and should not
2
2
  // be modified manually. See /Users/marcoroth/Development/herb-release/templates/javascript/packages/core/src/nodes.ts.erb
3
3
 
4
- import { Node } from "./node.js"
5
- import { Location, SerializedLocation } from "./location.js"
4
+ import { Location } from "./location.js"
6
5
  import { Token, SerializedToken } from "./token.js"
7
- import { HerbError, SerializedHerbError } from "./error.js"
6
+ import { HerbError } from "./errors.js"
8
7
  import { convertToUTF8 } from "./util.js"
9
8
 
10
- import type { SerializedNode, BaseNodeProps } from "./node.js"
9
+ import type { SerializedLocation } from "./location.js"
10
+ import type { SerializedHerbError } from "./errors.js"
11
+ import type { Visitor } from "./visitor.js"
11
12
 
12
- export function fromSerializedNode(node: SerializedNode): Node {
13
- switch (node.type) {
14
- case "AST_DOCUMENT_NODE": return DocumentNode.from(node as SerializedDocumentNode);
15
- case "AST_LITERAL_NODE": return LiteralNode.from(node as SerializedLiteralNode);
16
- case "AST_HTML_OPEN_TAG_NODE": return HTMLOpenTagNode.from(node as SerializedHTMLOpenTagNode);
17
- case "AST_HTML_CLOSE_TAG_NODE": return HTMLCloseTagNode.from(node as SerializedHTMLCloseTagNode);
18
- case "AST_HTML_SELF_CLOSE_TAG_NODE": return HTMLSelfCloseTagNode.from(node as SerializedHTMLSelfCloseTagNode);
19
- case "AST_HTML_ELEMENT_NODE": return HTMLElementNode.from(node as SerializedHTMLElementNode);
20
- case "AST_HTML_ATTRIBUTE_VALUE_NODE": return HTMLAttributeValueNode.from(node as SerializedHTMLAttributeValueNode);
21
- case "AST_HTML_ATTRIBUTE_NAME_NODE": return HTMLAttributeNameNode.from(node as SerializedHTMLAttributeNameNode);
22
- case "AST_HTML_ATTRIBUTE_NODE": return HTMLAttributeNode.from(node as SerializedHTMLAttributeNode);
23
- case "AST_HTML_TEXT_NODE": return HTMLTextNode.from(node as SerializedHTMLTextNode);
24
- case "AST_HTML_COMMENT_NODE": return HTMLCommentNode.from(node as SerializedHTMLCommentNode);
25
- case "AST_HTML_DOCTYPE_NODE": return HTMLDoctypeNode.from(node as SerializedHTMLDoctypeNode);
26
- case "AST_WHITESPACE_NODE": return WhitespaceNode.from(node as SerializedWhitespaceNode);
27
- case "AST_ERB_CONTENT_NODE": return ERBContentNode.from(node as SerializedERBContentNode);
28
- case "AST_ERB_END_NODE": return ERBEndNode.from(node as SerializedERBEndNode);
29
- case "AST_ERB_ELSE_NODE": return ERBElseNode.from(node as SerializedERBElseNode);
30
- case "AST_ERB_IF_NODE": return ERBIfNode.from(node as SerializedERBIfNode);
31
- case "AST_ERB_BLOCK_NODE": return ERBBlockNode.from(node as SerializedERBBlockNode);
32
- case "AST_ERB_WHEN_NODE": return ERBWhenNode.from(node as SerializedERBWhenNode);
33
- case "AST_ERB_CASE_NODE": return ERBCaseNode.from(node as SerializedERBCaseNode);
34
- case "AST_ERB_WHILE_NODE": return ERBWhileNode.from(node as SerializedERBWhileNode);
35
- case "AST_ERB_UNTIL_NODE": return ERBUntilNode.from(node as SerializedERBUntilNode);
36
- case "AST_ERB_FOR_NODE": return ERBForNode.from(node as SerializedERBForNode);
37
- case "AST_ERB_RESCUE_NODE": return ERBRescueNode.from(node as SerializedERBRescueNode);
38
- case "AST_ERB_ENSURE_NODE": return ERBEnsureNode.from(node as SerializedERBEnsureNode);
39
- case "AST_ERB_BEGIN_NODE": return ERBBeginNode.from(node as SerializedERBBeginNode);
40
- case "AST_ERB_UNLESS_NODE": return ERBUnlessNode.from(node as SerializedERBUnlessNode);
13
+ export type SerializedNodeType = string
41
14
 
42
- default:
43
- throw new Error(`Unknown node type: ${node.type}`);
44
- }
15
+ export interface SerializedNode {
16
+ type: SerializedNodeType
17
+ location: SerializedLocation
18
+ errors: SerializedHerbError[]
19
+ }
20
+
21
+ export interface BaseNodeProps {
22
+ type: NodeType
23
+ location: Location
24
+ errors: HerbError[]
45
25
  }
46
- export type SerializedNodeType = string
47
26
 
48
27
  export type NodeType =
49
28
  | "AST_DOCUMENT_NODE"
@@ -66,6 +45,7 @@ export type NodeType =
66
45
  | "AST_ERB_BLOCK_NODE"
67
46
  | "AST_ERB_WHEN_NODE"
68
47
  | "AST_ERB_CASE_NODE"
48
+ | "AST_ERB_CASE_MATCH_NODE"
69
49
  | "AST_ERB_WHILE_NODE"
70
50
  | "AST_ERB_UNTIL_NODE"
71
51
  | "AST_ERB_FOR_NODE"
@@ -73,6 +53,105 @@ export type NodeType =
73
53
  | "AST_ERB_ENSURE_NODE"
74
54
  | "AST_ERB_BEGIN_NODE"
75
55
  | "AST_ERB_UNLESS_NODE"
56
+ | "AST_ERB_YIELD_NODE"
57
+ | "AST_ERB_IN_NODE"
58
+
59
+ export abstract class Node implements BaseNodeProps {
60
+ readonly type: NodeType
61
+ readonly location: Location
62
+ readonly errors: HerbError[]
63
+
64
+ static from(node: SerializedNode): Node {
65
+ return fromSerializedNode(node)
66
+ }
67
+
68
+ constructor(type: NodeType, location: Location, errors: HerbError[]) {
69
+ this.type = type
70
+ this.location = location
71
+ this.errors = errors
72
+ }
73
+
74
+ toJSON(): SerializedNode {
75
+ return {
76
+ type: this.type,
77
+ location: this.location.toJSON(),
78
+ errors: this.errors,
79
+ }
80
+ }
81
+
82
+ inspect(): string {
83
+ return this.treeInspect(0)
84
+ }
85
+
86
+ get isSingleLine(): boolean {
87
+ return this.location.start.line === this.location.end.line
88
+ }
89
+
90
+ abstract treeInspect(indent?: number): string
91
+ abstract recursiveErrors(): HerbError[]
92
+ abstract accept(visitor: Visitor): void
93
+ abstract childNodes(): (Node | null | undefined)[]
94
+ abstract compactChildNodes(): Node[]
95
+
96
+ protected inspectArray(
97
+ array: (Node | HerbError)[] | null | undefined,
98
+ prefix: string,
99
+ ): string {
100
+ if (!array) return "∅\n"
101
+ if (array.length === 0) return "[]\n"
102
+
103
+ let output = `(${array.length} item${array.length == 1 ? "" : "s"})\n`
104
+
105
+ array.forEach((item, index) => {
106
+ const isLast = index === array.length - 1
107
+
108
+ if (item instanceof Node || item instanceof HerbError) {
109
+ output += this.inspectNode(
110
+ item,
111
+ prefix,
112
+ isLast ? " " : "│ ",
113
+ isLast,
114
+ false,
115
+ )
116
+ } else {
117
+ const symbol = isLast ? "└── " : "├── "
118
+ output += `${prefix}${symbol} ${item}\n`
119
+ }
120
+ })
121
+
122
+ output += `${prefix}\n`
123
+
124
+ return output
125
+ }
126
+
127
+ protected inspectNode(
128
+ node: Node | HerbError | undefined | null,
129
+ prefix: string,
130
+ prefix2: string = " ",
131
+ last: boolean = true,
132
+ trailingNewline: boolean = true,
133
+ ): string {
134
+ if (!node) return "∅\n"
135
+
136
+ let output = trailingNewline ? "\n" : ""
137
+ output += `${prefix}`
138
+
139
+ output += last ? "└── " : "├── "
140
+ output += node
141
+ .treeInspect()
142
+ .trimStart()
143
+ .split("\n")
144
+ .map((line, index) =>
145
+ index == 0 ? line.trimStart() : `${prefix}${prefix2}${line}`,
146
+ )
147
+ .join("\n")
148
+ .trimStart()
149
+
150
+ output += `\n`
151
+
152
+ return output
153
+ }
154
+ }
76
155
 
77
156
  export interface SerializedDocumentNode extends SerializedNode {
78
157
  type: "AST_DOCUMENT_NODE";
@@ -100,10 +179,18 @@ export class DocumentNode extends Node {
100
179
  this.children = props.children;
101
180
  }
102
181
 
103
- childNodes(): Node[] {
182
+ accept(visitor: Visitor): void {
183
+ visitor.visitDocumentNode(this)
184
+ }
185
+
186
+ childNodes(): (Node | null | undefined)[] {
104
187
  return [
105
188
  ...this.children,
106
- ].filter(node => node !== null && node !== undefined) as Node[];
189
+ ];
190
+ }
191
+
192
+ compactChildNodes(): Node[] {
193
+ return this.childNodes().filter(node => node !== null && node !== undefined)
107
194
  }
108
195
 
109
196
  recursiveErrors(): HerbError[] {
@@ -160,9 +247,17 @@ export class LiteralNode extends Node {
160
247
  this.content = convertToUTF8(props.content);
161
248
  }
162
249
 
163
- childNodes(): Node[] {
250
+ accept(visitor: Visitor): void {
251
+ visitor.visitLiteralNode(this)
252
+ }
253
+
254
+ childNodes(): (Node | null | undefined)[] {
164
255
  return [
165
- ].filter(node => node !== null && node !== undefined) as Node[];
256
+ ];
257
+ }
258
+
259
+ compactChildNodes(): Node[] {
260
+ return this.childNodes().filter(node => node !== null && node !== undefined)
166
261
  }
167
262
 
168
263
  recursiveErrors(): HerbError[] {
@@ -238,10 +333,18 @@ export class HTMLOpenTagNode extends Node {
238
333
  this.is_void = props.is_void;
239
334
  }
240
335
 
241
- childNodes(): Node[] {
336
+ accept(visitor: Visitor): void {
337
+ visitor.visitHTMLOpenTagNode(this)
338
+ }
339
+
340
+ childNodes(): (Node | null | undefined)[] {
242
341
  return [
243
342
  ...this.children,
244
- ].filter(node => node !== null && node !== undefined) as Node[];
343
+ ];
344
+ }
345
+
346
+ compactChildNodes(): Node[] {
347
+ return this.childNodes().filter(node => node !== null && node !== undefined)
245
348
  }
246
349
 
247
350
  recursiveErrors(): HerbError[] {
@@ -316,9 +419,17 @@ export class HTMLCloseTagNode extends Node {
316
419
  this.tag_closing = props.tag_closing;
317
420
  }
318
421
 
319
- childNodes(): Node[] {
422
+ accept(visitor: Visitor): void {
423
+ visitor.visitHTMLCloseTagNode(this)
424
+ }
425
+
426
+ childNodes(): (Node | null | undefined)[] {
320
427
  return [
321
- ].filter(node => node !== null && node !== undefined) as Node[];
428
+ ];
429
+ }
430
+
431
+ compactChildNodes(): Node[] {
432
+ return this.childNodes().filter(node => node !== null && node !== undefined)
322
433
  }
323
434
 
324
435
  recursiveErrors(): HerbError[] {
@@ -364,7 +475,7 @@ export interface SerializedHTMLSelfCloseTagNode extends SerializedNode {
364
475
  export interface HTMLSelfCloseTagNodeProps extends BaseNodeProps {
365
476
  tag_opening: Token | null;
366
477
  tag_name: Token | null;
367
- attributes: Node[];
478
+ attributes: any[];
368
479
  tag_closing: Token | null;
369
480
  is_void: boolean;
370
481
  }
@@ -372,7 +483,7 @@ export interface HTMLSelfCloseTagNodeProps extends BaseNodeProps {
372
483
  export class HTMLSelfCloseTagNode extends Node {
373
484
  readonly tag_opening: Token | null;
374
485
  readonly tag_name: Token | null;
375
- readonly attributes: Node[];
486
+ readonly attributes: any[];
376
487
  readonly tag_closing: Token | null;
377
488
  readonly is_void: boolean;
378
489
 
@@ -398,10 +509,18 @@ export class HTMLSelfCloseTagNode extends Node {
398
509
  this.is_void = props.is_void;
399
510
  }
400
511
 
401
- childNodes(): Node[] {
512
+ accept(visitor: Visitor): void {
513
+ visitor.visitHTMLSelfCloseTagNode(this)
514
+ }
515
+
516
+ childNodes(): (Node | null | undefined)[] {
402
517
  return [
403
518
  ...this.attributes,
404
- ].filter(node => node !== null && node !== undefined) as Node[];
519
+ ];
520
+ }
521
+
522
+ compactChildNodes(): Node[] {
523
+ return this.childNodes().filter(node => node !== null && node !== undefined)
405
524
  }
406
525
 
407
526
  recursiveErrors(): HerbError[] {
@@ -486,12 +605,20 @@ export class HTMLElementNode extends Node {
486
605
  this.is_void = props.is_void;
487
606
  }
488
607
 
489
- childNodes(): Node[] {
608
+ accept(visitor: Visitor): void {
609
+ visitor.visitHTMLElementNode(this)
610
+ }
611
+
612
+ childNodes(): (Node | null | undefined)[] {
490
613
  return [
491
614
  this.open_tag,
492
615
  ...this.body,
493
616
  this.close_tag,
494
- ].filter(node => node !== null && node !== undefined) as Node[];
617
+ ];
618
+ }
619
+
620
+ compactChildNodes(): Node[] {
621
+ return this.childNodes().filter(node => node !== null && node !== undefined)
495
622
  }
496
623
 
497
624
  recursiveErrors(): HerbError[] {
@@ -573,10 +700,18 @@ export class HTMLAttributeValueNode extends Node {
573
700
  this.quoted = props.quoted;
574
701
  }
575
702
 
576
- childNodes(): Node[] {
703
+ accept(visitor: Visitor): void {
704
+ visitor.visitHTMLAttributeValueNode(this)
705
+ }
706
+
707
+ childNodes(): (Node | null | undefined)[] {
577
708
  return [
578
709
  ...this.children,
579
- ].filter(node => node !== null && node !== undefined) as Node[];
710
+ ];
711
+ }
712
+
713
+ compactChildNodes(): Node[] {
714
+ return this.childNodes().filter(node => node !== null && node !== undefined)
580
715
  }
581
716
 
582
717
  recursiveErrors(): HerbError[] {
@@ -639,9 +774,17 @@ export class HTMLAttributeNameNode extends Node {
639
774
  this.name = props.name;
640
775
  }
641
776
 
642
- childNodes(): Node[] {
777
+ accept(visitor: Visitor): void {
778
+ visitor.visitHTMLAttributeNameNode(this)
779
+ }
780
+
781
+ childNodes(): (Node | null | undefined)[] {
643
782
  return [
644
- ].filter(node => node !== null && node !== undefined) as Node[];
783
+ ];
784
+ }
785
+
786
+ compactChildNodes(): Node[] {
787
+ return this.childNodes().filter(node => node !== null && node !== undefined)
645
788
  }
646
789
 
647
790
  recursiveErrors(): HerbError[] {
@@ -707,11 +850,19 @@ export class HTMLAttributeNode extends Node {
707
850
  this.value = props.value;
708
851
  }
709
852
 
710
- childNodes(): Node[] {
853
+ accept(visitor: Visitor): void {
854
+ visitor.visitHTMLAttributeNode(this)
855
+ }
856
+
857
+ childNodes(): (Node | null | undefined)[] {
711
858
  return [
712
859
  this.name,
713
860
  this.value,
714
- ].filter(node => node !== null && node !== undefined) as Node[];
861
+ ];
862
+ }
863
+
864
+ compactChildNodes(): Node[] {
865
+ return this.childNodes().filter(node => node !== null && node !== undefined)
715
866
  }
716
867
 
717
868
  recursiveErrors(): HerbError[] {
@@ -773,9 +924,17 @@ export class HTMLTextNode extends Node {
773
924
  this.content = convertToUTF8(props.content);
774
925
  }
775
926
 
776
- childNodes(): Node[] {
927
+ accept(visitor: Visitor): void {
928
+ visitor.visitHTMLTextNode(this)
929
+ }
930
+
931
+ childNodes(): (Node | null | undefined)[] {
777
932
  return [
778
- ].filter(node => node !== null && node !== undefined) as Node[];
933
+ ];
934
+ }
935
+
936
+ compactChildNodes(): Node[] {
937
+ return this.childNodes().filter(node => node !== null && node !== undefined)
779
938
  }
780
939
 
781
940
  recursiveErrors(): HerbError[] {
@@ -841,10 +1000,18 @@ export class HTMLCommentNode extends Node {
841
1000
  this.comment_end = props.comment_end;
842
1001
  }
843
1002
 
844
- childNodes(): Node[] {
1003
+ accept(visitor: Visitor): void {
1004
+ visitor.visitHTMLCommentNode(this)
1005
+ }
1006
+
1007
+ childNodes(): (Node | null | undefined)[] {
845
1008
  return [
846
1009
  ...this.children,
847
- ].filter(node => node !== null && node !== undefined) as Node[];
1010
+ ];
1011
+ }
1012
+
1013
+ compactChildNodes(): Node[] {
1014
+ return this.childNodes().filter(node => node !== null && node !== undefined)
848
1015
  }
849
1016
 
850
1017
  recursiveErrors(): HerbError[] {
@@ -915,10 +1082,18 @@ export class HTMLDoctypeNode extends Node {
915
1082
  this.tag_closing = props.tag_closing;
916
1083
  }
917
1084
 
918
- childNodes(): Node[] {
1085
+ accept(visitor: Visitor): void {
1086
+ visitor.visitHTMLDoctypeNode(this)
1087
+ }
1088
+
1089
+ childNodes(): (Node | null | undefined)[] {
919
1090
  return [
920
1091
  ...this.children,
921
- ].filter(node => node !== null && node !== undefined) as Node[];
1092
+ ];
1093
+ }
1094
+
1095
+ compactChildNodes(): Node[] {
1096
+ return this.childNodes().filter(node => node !== null && node !== undefined)
922
1097
  }
923
1098
 
924
1099
  recursiveErrors(): HerbError[] {
@@ -979,9 +1154,17 @@ export class WhitespaceNode extends Node {
979
1154
  this.value = props.value;
980
1155
  }
981
1156
 
982
- childNodes(): Node[] {
1157
+ accept(visitor: Visitor): void {
1158
+ visitor.visitWhitespaceNode(this)
1159
+ }
1160
+
1161
+ childNodes(): (Node | null | undefined)[] {
983
1162
  return [
984
- ].filter(node => node !== null && node !== undefined) as Node[];
1163
+ ];
1164
+ }
1165
+
1166
+ compactChildNodes(): Node[] {
1167
+ return this.childNodes().filter(node => node !== null && node !== undefined)
985
1168
  }
986
1169
 
987
1170
  recursiveErrors(): HerbError[] {
@@ -1062,9 +1245,17 @@ export class ERBContentNode extends Node {
1062
1245
  this.valid = props.valid;
1063
1246
  }
1064
1247
 
1065
- childNodes(): Node[] {
1248
+ accept(visitor: Visitor): void {
1249
+ visitor.visitERBContentNode(this)
1250
+ }
1251
+
1252
+ childNodes(): (Node | null | undefined)[] {
1066
1253
  return [
1067
- ].filter(node => node !== null && node !== undefined) as Node[];
1254
+ ];
1255
+ }
1256
+
1257
+ compactChildNodes(): Node[] {
1258
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1068
1259
  }
1069
1260
 
1070
1261
  recursiveErrors(): HerbError[] {
@@ -1140,9 +1331,17 @@ export class ERBEndNode extends Node {
1140
1331
  this.tag_closing = props.tag_closing;
1141
1332
  }
1142
1333
 
1143
- childNodes(): Node[] {
1334
+ accept(visitor: Visitor): void {
1335
+ visitor.visitERBEndNode(this)
1336
+ }
1337
+
1338
+ childNodes(): (Node | null | undefined)[] {
1144
1339
  return [
1145
- ].filter(node => node !== null && node !== undefined) as Node[];
1340
+ ];
1341
+ }
1342
+
1343
+ compactChildNodes(): Node[] {
1344
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1146
1345
  }
1147
1346
 
1148
1347
  recursiveErrors(): HerbError[] {
@@ -1217,10 +1416,18 @@ export class ERBElseNode extends Node {
1217
1416
  this.statements = props.statements;
1218
1417
  }
1219
1418
 
1220
- childNodes(): Node[] {
1419
+ accept(visitor: Visitor): void {
1420
+ visitor.visitERBElseNode(this)
1421
+ }
1422
+
1423
+ childNodes(): (Node | null | undefined)[] {
1221
1424
  return [
1222
1425
  ...this.statements,
1223
- ].filter(node => node !== null && node !== undefined) as Node[];
1426
+ ];
1427
+ }
1428
+
1429
+ compactChildNodes(): Node[] {
1430
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1224
1431
  }
1225
1432
 
1226
1433
  recursiveErrors(): HerbError[] {
@@ -1308,12 +1515,20 @@ export class ERBIfNode extends Node {
1308
1515
  this.end_node = props.end_node;
1309
1516
  }
1310
1517
 
1311
- childNodes(): Node[] {
1518
+ accept(visitor: Visitor): void {
1519
+ visitor.visitERBIfNode(this)
1520
+ }
1521
+
1522
+ childNodes(): (Node | null | undefined)[] {
1312
1523
  return [
1313
1524
  ...this.statements,
1314
1525
  this.subsequent,
1315
1526
  this.end_node,
1316
- ].filter(node => node !== null && node !== undefined) as Node[];
1527
+ ];
1528
+ }
1529
+
1530
+ compactChildNodes(): Node[] {
1531
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1317
1532
  }
1318
1533
 
1319
1534
  recursiveErrors(): HerbError[] {
@@ -1402,11 +1617,19 @@ export class ERBBlockNode extends Node {
1402
1617
  this.end_node = props.end_node;
1403
1618
  }
1404
1619
 
1405
- childNodes(): Node[] {
1620
+ accept(visitor: Visitor): void {
1621
+ visitor.visitERBBlockNode(this)
1622
+ }
1623
+
1624
+ childNodes(): (Node | null | undefined)[] {
1406
1625
  return [
1407
1626
  ...this.body,
1408
1627
  this.end_node,
1409
- ].filter(node => node !== null && node !== undefined) as Node[];
1628
+ ];
1629
+ }
1630
+
1631
+ compactChildNodes(): Node[] {
1632
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1410
1633
  }
1411
1634
 
1412
1635
  recursiveErrors(): HerbError[] {
@@ -1487,10 +1710,18 @@ export class ERBWhenNode extends Node {
1487
1710
  this.statements = props.statements;
1488
1711
  }
1489
1712
 
1490
- childNodes(): Node[] {
1713
+ accept(visitor: Visitor): void {
1714
+ visitor.visitERBWhenNode(this)
1715
+ }
1716
+
1717
+ childNodes(): (Node | null | undefined)[] {
1491
1718
  return [
1492
1719
  ...this.statements,
1493
- ].filter(node => node !== null && node !== undefined) as Node[];
1720
+ ];
1721
+ }
1722
+
1723
+ compactChildNodes(): Node[] {
1724
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1494
1725
  }
1495
1726
 
1496
1727
  recursiveErrors(): HerbError[] {
@@ -1543,7 +1774,7 @@ export interface ERBCaseNodeProps extends BaseNodeProps {
1543
1774
  content: Token | null;
1544
1775
  tag_closing: Token | null;
1545
1776
  children: Node[];
1546
- conditions: Node[];
1777
+ conditions: any[];
1547
1778
  else_clause: Node | null;
1548
1779
  end_node: Node | null;
1549
1780
  }
@@ -1553,7 +1784,7 @@ export class ERBCaseNode extends Node {
1553
1784
  readonly content: Token | null;
1554
1785
  readonly tag_closing: Token | null;
1555
1786
  readonly children: Node[];
1556
- readonly conditions: Node[];
1787
+ readonly conditions: any[];
1557
1788
  readonly else_clause: Node | null;
1558
1789
  readonly end_node: Node | null;
1559
1790
 
@@ -1583,13 +1814,21 @@ export class ERBCaseNode extends Node {
1583
1814
  this.end_node = props.end_node;
1584
1815
  }
1585
1816
 
1586
- childNodes(): Node[] {
1817
+ accept(visitor: Visitor): void {
1818
+ visitor.visitERBCaseNode(this)
1819
+ }
1820
+
1821
+ childNodes(): (Node | null | undefined)[] {
1587
1822
  return [
1588
1823
  ...this.children,
1589
1824
  ...this.conditions,
1590
1825
  this.else_clause,
1591
1826
  this.end_node,
1592
- ].filter(node => node !== null && node !== undefined) as Node[];
1827
+ ];
1828
+ }
1829
+
1830
+ compactChildNodes(): Node[] {
1831
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1593
1832
  }
1594
1833
 
1595
1834
  recursiveErrors(): HerbError[] {
@@ -1635,6 +1874,122 @@ export class ERBCaseNode extends Node {
1635
1874
  }
1636
1875
  }
1637
1876
 
1877
+ export interface SerializedERBCaseMatchNode extends SerializedNode {
1878
+ type: "AST_ERB_CASE_MATCH_NODE";
1879
+ tag_opening: SerializedToken | null;
1880
+ content: SerializedToken | null;
1881
+ tag_closing: SerializedToken | null;
1882
+ children: SerializedNode[];
1883
+ conditions: SerializedNode[];
1884
+ else_clause: SerializedNode | null;
1885
+ end_node: SerializedNode | null;
1886
+ }
1887
+
1888
+ export interface ERBCaseMatchNodeProps extends BaseNodeProps {
1889
+ tag_opening: Token | null;
1890
+ content: Token | null;
1891
+ tag_closing: Token | null;
1892
+ children: Node[];
1893
+ conditions: any[];
1894
+ else_clause: Node | null;
1895
+ end_node: Node | null;
1896
+ }
1897
+
1898
+ export class ERBCaseMatchNode extends Node {
1899
+ readonly tag_opening: Token | null;
1900
+ readonly content: Token | null;
1901
+ readonly tag_closing: Token | null;
1902
+ readonly children: Node[];
1903
+ readonly conditions: any[];
1904
+ readonly else_clause: Node | null;
1905
+ readonly end_node: Node | null;
1906
+
1907
+ static from(data: SerializedERBCaseMatchNode): ERBCaseMatchNode {
1908
+ return new ERBCaseMatchNode({
1909
+ type: data.type,
1910
+ location: Location.from(data.location),
1911
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1912
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1913
+ content: data.content ? Token.from(data.content) : null,
1914
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1915
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1916
+ conditions: (data.conditions || []).map(node => fromSerializedNode(node)),
1917
+ else_clause: data.else_clause ? fromSerializedNode((data.else_clause as any)) : null,
1918
+ end_node: data.end_node ? fromSerializedNode((data.end_node as any)) : null,
1919
+ })
1920
+ }
1921
+
1922
+ constructor(props: ERBCaseMatchNodeProps) {
1923
+ super(props.type, props.location, props.errors);
1924
+ this.tag_opening = props.tag_opening;
1925
+ this.content = props.content;
1926
+ this.tag_closing = props.tag_closing;
1927
+ this.children = props.children;
1928
+ this.conditions = props.conditions;
1929
+ this.else_clause = props.else_clause;
1930
+ this.end_node = props.end_node;
1931
+ }
1932
+
1933
+ accept(visitor: Visitor): void {
1934
+ visitor.visitERBCaseMatchNode(this)
1935
+ }
1936
+
1937
+ childNodes(): (Node | null | undefined)[] {
1938
+ return [
1939
+ ...this.children,
1940
+ ...this.conditions,
1941
+ this.else_clause,
1942
+ this.end_node,
1943
+ ];
1944
+ }
1945
+
1946
+ compactChildNodes(): Node[] {
1947
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1948
+ }
1949
+
1950
+ recursiveErrors(): HerbError[] {
1951
+ return [
1952
+ ...this.errors,
1953
+ ...this.children.map(node => node.recursiveErrors()),
1954
+ ...this.conditions.map(node => node.recursiveErrors()),
1955
+ this.else_clause ? this.else_clause.recursiveErrors() : [],
1956
+ this.end_node ? this.end_node.recursiveErrors() : [],
1957
+ ].flat();
1958
+ }
1959
+
1960
+ toJSON(): SerializedERBCaseMatchNode {
1961
+ return {
1962
+ ...super.toJSON(),
1963
+ type: "AST_ERB_CASE_MATCH_NODE",
1964
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1965
+ content: this.content ? this.content.toJSON() : null,
1966
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1967
+ children: this.children.map(node => node.toJSON()),
1968
+ conditions: this.conditions.map(node => node.toJSON()),
1969
+ else_clause: this.else_clause ? this.else_clause.toJSON() : null,
1970
+ end_node: this.end_node ? this.end_node.toJSON() : null,
1971
+ };
1972
+ }
1973
+
1974
+ treeInspect(): string {
1975
+ let output = "";
1976
+
1977
+ output += `@ ERBCaseMatchNode ${this.location.treeInspectWithLabel()}\n`;
1978
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1979
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1980
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1981
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1982
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1983
+ output += `├── conditions: ${this.inspectArray(this.conditions, "│ ")}`;
1984
+ output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
1985
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
1986
+
1987
+ // output += "\n";
1988
+
1989
+ return output
1990
+ }
1991
+ }
1992
+
1638
1993
  export interface SerializedERBWhileNode extends SerializedNode {
1639
1994
  type: "AST_ERB_WHILE_NODE";
1640
1995
  tag_opening: SerializedToken | null;
@@ -1681,11 +2036,19 @@ export class ERBWhileNode extends Node {
1681
2036
  this.end_node = props.end_node;
1682
2037
  }
1683
2038
 
1684
- childNodes(): Node[] {
2039
+ accept(visitor: Visitor): void {
2040
+ visitor.visitERBWhileNode(this)
2041
+ }
2042
+
2043
+ childNodes(): (Node | null | undefined)[] {
1685
2044
  return [
1686
2045
  ...this.statements,
1687
2046
  this.end_node,
1688
- ].filter(node => node !== null && node !== undefined) as Node[];
2047
+ ];
2048
+ }
2049
+
2050
+ compactChildNodes(): Node[] {
2051
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1689
2052
  }
1690
2053
 
1691
2054
  recursiveErrors(): HerbError[] {
@@ -1771,11 +2134,19 @@ export class ERBUntilNode extends Node {
1771
2134
  this.end_node = props.end_node;
1772
2135
  }
1773
2136
 
1774
- childNodes(): Node[] {
2137
+ accept(visitor: Visitor): void {
2138
+ visitor.visitERBUntilNode(this)
2139
+ }
2140
+
2141
+ childNodes(): (Node | null | undefined)[] {
1775
2142
  return [
1776
2143
  ...this.statements,
1777
2144
  this.end_node,
1778
- ].filter(node => node !== null && node !== undefined) as Node[];
2145
+ ];
2146
+ }
2147
+
2148
+ compactChildNodes(): Node[] {
2149
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1779
2150
  }
1780
2151
 
1781
2152
  recursiveErrors(): HerbError[] {
@@ -1861,11 +2232,19 @@ export class ERBForNode extends Node {
1861
2232
  this.end_node = props.end_node;
1862
2233
  }
1863
2234
 
1864
- childNodes(): Node[] {
2235
+ accept(visitor: Visitor): void {
2236
+ visitor.visitERBForNode(this)
2237
+ }
2238
+
2239
+ childNodes(): (Node | null | undefined)[] {
1865
2240
  return [
1866
2241
  ...this.statements,
1867
2242
  this.end_node,
1868
- ].filter(node => node !== null && node !== undefined) as Node[];
2243
+ ];
2244
+ }
2245
+
2246
+ compactChildNodes(): Node[] {
2247
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1869
2248
  }
1870
2249
 
1871
2250
  recursiveErrors(): HerbError[] {
@@ -1951,11 +2330,19 @@ export class ERBRescueNode extends Node {
1951
2330
  this.subsequent = props.subsequent;
1952
2331
  }
1953
2332
 
1954
- childNodes(): Node[] {
2333
+ accept(visitor: Visitor): void {
2334
+ visitor.visitERBRescueNode(this)
2335
+ }
2336
+
2337
+ childNodes(): (Node | null | undefined)[] {
1955
2338
  return [
1956
2339
  ...this.statements,
1957
2340
  this.subsequent,
1958
- ].filter(node => node !== null && node !== undefined) as Node[];
2341
+ ];
2342
+ }
2343
+
2344
+ compactChildNodes(): Node[] {
2345
+ return this.childNodes().filter(node => node !== null && node !== undefined)
1959
2346
  }
1960
2347
 
1961
2348
  recursiveErrors(): HerbError[] {
@@ -2036,10 +2423,18 @@ export class ERBEnsureNode extends Node {
2036
2423
  this.statements = props.statements;
2037
2424
  }
2038
2425
 
2039
- childNodes(): Node[] {
2426
+ accept(visitor: Visitor): void {
2427
+ visitor.visitERBEnsureNode(this)
2428
+ }
2429
+
2430
+ childNodes(): (Node | null | undefined)[] {
2040
2431
  return [
2041
2432
  ...this.statements,
2042
- ].filter(node => node !== null && node !== undefined) as Node[];
2433
+ ];
2434
+ }
2435
+
2436
+ compactChildNodes(): Node[] {
2437
+ return this.childNodes().filter(node => node !== null && node !== undefined)
2043
2438
  }
2044
2439
 
2045
2440
  recursiveErrors(): HerbError[] {
@@ -2137,14 +2532,22 @@ export class ERBBeginNode extends Node {
2137
2532
  this.end_node = props.end_node;
2138
2533
  }
2139
2534
 
2140
- childNodes(): Node[] {
2535
+ accept(visitor: Visitor): void {
2536
+ visitor.visitERBBeginNode(this)
2537
+ }
2538
+
2539
+ childNodes(): (Node | null | undefined)[] {
2141
2540
  return [
2142
2541
  ...this.statements,
2143
2542
  this.rescue_clause,
2144
2543
  this.else_clause,
2145
2544
  this.ensure_clause,
2146
2545
  this.end_node,
2147
- ].filter(node => node !== null && node !== undefined) as Node[];
2546
+ ];
2547
+ }
2548
+
2549
+ compactChildNodes(): Node[] {
2550
+ return this.childNodes().filter(node => node !== null && node !== undefined)
2148
2551
  }
2149
2552
 
2150
2553
  recursiveErrors(): HerbError[] {
@@ -2244,12 +2647,20 @@ export class ERBUnlessNode extends Node {
2244
2647
  this.end_node = props.end_node;
2245
2648
  }
2246
2649
 
2247
- childNodes(): Node[] {
2650
+ accept(visitor: Visitor): void {
2651
+ visitor.visitERBUnlessNode(this)
2652
+ }
2653
+
2654
+ childNodes(): (Node | null | undefined)[] {
2248
2655
  return [
2249
2656
  ...this.statements,
2250
2657
  this.else_clause,
2251
2658
  this.end_node,
2252
- ].filter(node => node !== null && node !== undefined) as Node[];
2659
+ ];
2660
+ }
2661
+
2662
+ compactChildNodes(): Node[] {
2663
+ return this.childNodes().filter(node => node !== null && node !== undefined)
2253
2664
  }
2254
2665
 
2255
2666
  recursiveErrors(): HerbError[] {
@@ -2292,3 +2703,210 @@ export class ERBUnlessNode extends Node {
2292
2703
  }
2293
2704
  }
2294
2705
 
2706
+ export interface SerializedERBYieldNode extends SerializedNode {
2707
+ type: "AST_ERB_YIELD_NODE";
2708
+ tag_opening: SerializedToken | null;
2709
+ content: SerializedToken | null;
2710
+ tag_closing: SerializedToken | null;
2711
+ }
2712
+
2713
+ export interface ERBYieldNodeProps extends BaseNodeProps {
2714
+ tag_opening: Token | null;
2715
+ content: Token | null;
2716
+ tag_closing: Token | null;
2717
+ }
2718
+
2719
+ export class ERBYieldNode extends Node {
2720
+ readonly tag_opening: Token | null;
2721
+ readonly content: Token | null;
2722
+ readonly tag_closing: Token | null;
2723
+
2724
+ static from(data: SerializedERBYieldNode): ERBYieldNode {
2725
+ return new ERBYieldNode({
2726
+ type: data.type,
2727
+ location: Location.from(data.location),
2728
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2729
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2730
+ content: data.content ? Token.from(data.content) : null,
2731
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2732
+ })
2733
+ }
2734
+
2735
+ constructor(props: ERBYieldNodeProps) {
2736
+ super(props.type, props.location, props.errors);
2737
+ this.tag_opening = props.tag_opening;
2738
+ this.content = props.content;
2739
+ this.tag_closing = props.tag_closing;
2740
+ }
2741
+
2742
+ accept(visitor: Visitor): void {
2743
+ visitor.visitERBYieldNode(this)
2744
+ }
2745
+
2746
+ childNodes(): (Node | null | undefined)[] {
2747
+ return [
2748
+ ];
2749
+ }
2750
+
2751
+ compactChildNodes(): Node[] {
2752
+ return this.childNodes().filter(node => node !== null && node !== undefined)
2753
+ }
2754
+
2755
+ recursiveErrors(): HerbError[] {
2756
+ return [
2757
+ ...this.errors,
2758
+ ].flat();
2759
+ }
2760
+
2761
+ toJSON(): SerializedERBYieldNode {
2762
+ return {
2763
+ ...super.toJSON(),
2764
+ type: "AST_ERB_YIELD_NODE",
2765
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2766
+ content: this.content ? this.content.toJSON() : null,
2767
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2768
+ };
2769
+ }
2770
+
2771
+ treeInspect(): string {
2772
+ let output = "";
2773
+
2774
+ output += `@ ERBYieldNode ${this.location.treeInspectWithLabel()}\n`;
2775
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2776
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2777
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2778
+ output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2779
+
2780
+ // output += "\n";
2781
+
2782
+ return output
2783
+ }
2784
+ }
2785
+
2786
+ export interface SerializedERBInNode extends SerializedNode {
2787
+ type: "AST_ERB_IN_NODE";
2788
+ tag_opening: SerializedToken | null;
2789
+ content: SerializedToken | null;
2790
+ tag_closing: SerializedToken | null;
2791
+ statements: SerializedNode[];
2792
+ }
2793
+
2794
+ export interface ERBInNodeProps extends BaseNodeProps {
2795
+ tag_opening: Token | null;
2796
+ content: Token | null;
2797
+ tag_closing: Token | null;
2798
+ statements: Node[];
2799
+ }
2800
+
2801
+ export class ERBInNode extends Node {
2802
+ readonly tag_opening: Token | null;
2803
+ readonly content: Token | null;
2804
+ readonly tag_closing: Token | null;
2805
+ readonly statements: Node[];
2806
+
2807
+ static from(data: SerializedERBInNode): ERBInNode {
2808
+ return new ERBInNode({
2809
+ type: data.type,
2810
+ location: Location.from(data.location),
2811
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2812
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2813
+ content: data.content ? Token.from(data.content) : null,
2814
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2815
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
2816
+ })
2817
+ }
2818
+
2819
+ constructor(props: ERBInNodeProps) {
2820
+ super(props.type, props.location, props.errors);
2821
+ this.tag_opening = props.tag_opening;
2822
+ this.content = props.content;
2823
+ this.tag_closing = props.tag_closing;
2824
+ this.statements = props.statements;
2825
+ }
2826
+
2827
+ accept(visitor: Visitor): void {
2828
+ visitor.visitERBInNode(this)
2829
+ }
2830
+
2831
+ childNodes(): (Node | null | undefined)[] {
2832
+ return [
2833
+ ...this.statements,
2834
+ ];
2835
+ }
2836
+
2837
+ compactChildNodes(): Node[] {
2838
+ return this.childNodes().filter(node => node !== null && node !== undefined)
2839
+ }
2840
+
2841
+ recursiveErrors(): HerbError[] {
2842
+ return [
2843
+ ...this.errors,
2844
+ ...this.statements.map(node => node.recursiveErrors()),
2845
+ ].flat();
2846
+ }
2847
+
2848
+ toJSON(): SerializedERBInNode {
2849
+ return {
2850
+ ...super.toJSON(),
2851
+ type: "AST_ERB_IN_NODE",
2852
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2853
+ content: this.content ? this.content.toJSON() : null,
2854
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2855
+ statements: this.statements.map(node => node.toJSON()),
2856
+ };
2857
+ }
2858
+
2859
+ treeInspect(): string {
2860
+ let output = "";
2861
+
2862
+ output += `@ ERBInNode ${this.location.treeInspectWithLabel()}\n`;
2863
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2864
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2865
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2866
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2867
+ output += `└── statements: ${this.inspectArray(this.statements, " ")}`;
2868
+
2869
+ // output += "\n";
2870
+
2871
+ return output
2872
+ }
2873
+ }
2874
+
2875
+
2876
+ export function fromSerializedNode(node: SerializedNode): Node {
2877
+ switch (node.type) {
2878
+ case "AST_DOCUMENT_NODE": return DocumentNode.from(node as SerializedDocumentNode);
2879
+ case "AST_LITERAL_NODE": return LiteralNode.from(node as SerializedLiteralNode);
2880
+ case "AST_HTML_OPEN_TAG_NODE": return HTMLOpenTagNode.from(node as SerializedHTMLOpenTagNode);
2881
+ case "AST_HTML_CLOSE_TAG_NODE": return HTMLCloseTagNode.from(node as SerializedHTMLCloseTagNode);
2882
+ case "AST_HTML_SELF_CLOSE_TAG_NODE": return HTMLSelfCloseTagNode.from(node as SerializedHTMLSelfCloseTagNode);
2883
+ case "AST_HTML_ELEMENT_NODE": return HTMLElementNode.from(node as SerializedHTMLElementNode);
2884
+ case "AST_HTML_ATTRIBUTE_VALUE_NODE": return HTMLAttributeValueNode.from(node as SerializedHTMLAttributeValueNode);
2885
+ case "AST_HTML_ATTRIBUTE_NAME_NODE": return HTMLAttributeNameNode.from(node as SerializedHTMLAttributeNameNode);
2886
+ case "AST_HTML_ATTRIBUTE_NODE": return HTMLAttributeNode.from(node as SerializedHTMLAttributeNode);
2887
+ case "AST_HTML_TEXT_NODE": return HTMLTextNode.from(node as SerializedHTMLTextNode);
2888
+ case "AST_HTML_COMMENT_NODE": return HTMLCommentNode.from(node as SerializedHTMLCommentNode);
2889
+ case "AST_HTML_DOCTYPE_NODE": return HTMLDoctypeNode.from(node as SerializedHTMLDoctypeNode);
2890
+ case "AST_WHITESPACE_NODE": return WhitespaceNode.from(node as SerializedWhitespaceNode);
2891
+ case "AST_ERB_CONTENT_NODE": return ERBContentNode.from(node as SerializedERBContentNode);
2892
+ case "AST_ERB_END_NODE": return ERBEndNode.from(node as SerializedERBEndNode);
2893
+ case "AST_ERB_ELSE_NODE": return ERBElseNode.from(node as SerializedERBElseNode);
2894
+ case "AST_ERB_IF_NODE": return ERBIfNode.from(node as SerializedERBIfNode);
2895
+ case "AST_ERB_BLOCK_NODE": return ERBBlockNode.from(node as SerializedERBBlockNode);
2896
+ case "AST_ERB_WHEN_NODE": return ERBWhenNode.from(node as SerializedERBWhenNode);
2897
+ case "AST_ERB_CASE_NODE": return ERBCaseNode.from(node as SerializedERBCaseNode);
2898
+ case "AST_ERB_CASE_MATCH_NODE": return ERBCaseMatchNode.from(node as SerializedERBCaseMatchNode);
2899
+ case "AST_ERB_WHILE_NODE": return ERBWhileNode.from(node as SerializedERBWhileNode);
2900
+ case "AST_ERB_UNTIL_NODE": return ERBUntilNode.from(node as SerializedERBUntilNode);
2901
+ case "AST_ERB_FOR_NODE": return ERBForNode.from(node as SerializedERBForNode);
2902
+ case "AST_ERB_RESCUE_NODE": return ERBRescueNode.from(node as SerializedERBRescueNode);
2903
+ case "AST_ERB_ENSURE_NODE": return ERBEnsureNode.from(node as SerializedERBEnsureNode);
2904
+ case "AST_ERB_BEGIN_NODE": return ERBBeginNode.from(node as SerializedERBBeginNode);
2905
+ case "AST_ERB_UNLESS_NODE": return ERBUnlessNode.from(node as SerializedERBUnlessNode);
2906
+ case "AST_ERB_YIELD_NODE": return ERBYieldNode.from(node as SerializedERBYieldNode);
2907
+ case "AST_ERB_IN_NODE": return ERBInNode.from(node as SerializedERBInNode);
2908
+
2909
+ default:
2910
+ throw new Error(`Unknown node type: ${node.type}`);
2911
+ }
2912
+ }