@herb-tools/core 0.5.0 → 0.6.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.
@@ -1,55 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const expectedFunctions = [
4
- "parse",
5
- "lex",
6
- "parseFile",
7
- "lexFile",
8
- "extractRuby",
9
- "extractHTML",
10
- "version",
11
- ];
12
- // NOTE: This function should never be called and is only for type checking
13
- // so we can make sure `expectedFunctions` matches the functions defined
14
- // in `LibHerbBackendFunctions` and the other way around.
15
- //
16
- function _TYPECHECK() {
17
- const checkFunctionsExist = true;
18
- const checkInterfaceComplete = true;
19
- return { checkFunctionsExist, checkInterfaceComplete };
20
- }
21
- function isLibHerbBackend(object, libherbpath = "unknown") {
22
- for (const expectedFunction of expectedFunctions) {
23
- if (object[expectedFunction] === undefined) {
24
- throw new Error(`Libherb at "${libherbpath}" doesn't expose function "${expectedFunction}".`);
25
- }
26
- if (typeof object[expectedFunction] !== "function") {
27
- throw new Error(`Libherb at "${libherbpath}" has "${expectedFunction}" but it's not a function.`);
28
- }
29
- }
30
- return true;
31
- }
32
- function ensureLibHerbBackend(object, libherbpath = "unknown") {
33
- isLibHerbBackend(object, libherbpath);
34
- return object;
35
- }
36
-
37
- /**
38
- * Converts a Diagnostic to Monaco/VSCode-compatible MonacoDiagnostic format
39
- */
40
- function toMonacoDiagnostic(diagnostic) {
41
- const { message, location } = diagnostic;
42
- const severity = diagnostic.severity === "hint" ? "info" : diagnostic.severity;
43
- return {
44
- line: location.start.line,
45
- column: location.start.column,
46
- endLine: location.end.line,
47
- endColumn: location.end.column,
48
- message,
49
- severity
50
- };
51
- }
52
-
53
3
  class Position {
54
4
  line;
55
5
  column;
@@ -181,7 +131,7 @@ class Token {
181
131
  }
182
132
 
183
133
  // NOTE: This file is generated by the templates/template.rb script and should not
184
- // be modified manually. See /Users/marcoroth/Development/herb-release-0.5.0/templates/javascript/packages/core/src/errors.ts.erb
134
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.6.1/templates/javascript/packages/core/src/errors.ts.erb
185
135
  class HerbError {
186
136
  type;
187
137
  message;
@@ -622,12 +572,6 @@ function fromSerializedError(error) {
622
572
  }
623
573
  }
624
574
 
625
- var name = "@herb-tools/core";
626
- var version = "0.5.0";
627
- var packageJSON = {
628
- name: name,
629
- version: version};
630
-
631
575
  function ensureString(object) {
632
576
  if (typeof object === "string") {
633
577
  return object;
@@ -643,139 +587,8 @@ function convertToUTF8(string) {
643
587
  return decoder.decode(new Uint8Array(bytes));
644
588
  }
645
589
 
646
- class Result {
647
- source;
648
- warnings;
649
- errors;
650
- constructor(source, warnings = [], errors = []) {
651
- this.source = source;
652
- this.warnings = warnings || [];
653
- this.errors = errors || [];
654
- }
655
- /**
656
- * Determines if the parsing was successful.
657
- * @returns `true` if there are no errors, otherwise `false`.
658
- */
659
- get successful() {
660
- return this.errors.length === 0;
661
- }
662
- /**
663
- * Determines if the parsing failed.
664
- * @returns `true` if there are errors, otherwise `false`.
665
- */
666
- get failed() {
667
- return this.errors.length > 0;
668
- }
669
- }
670
-
671
- class TokenList {
672
- list;
673
- static from(list) {
674
- return new TokenList(list.map((token) => Token.from(token)));
675
- }
676
- constructor(list) {
677
- this.list = list;
678
- }
679
- get length() {
680
- return this.list.length;
681
- }
682
- get tokens() {
683
- return this.list;
684
- }
685
- [Symbol.iterator]() {
686
- return this.list[Symbol.iterator]();
687
- }
688
- at(index) {
689
- return this.list.at(index);
690
- }
691
- forEach(callback) {
692
- this.list.forEach(callback);
693
- }
694
- map(callback) {
695
- return this.list.map(callback);
696
- }
697
- filter(predicate) {
698
- return this.list.filter(predicate);
699
- }
700
- __getobj__() {
701
- return this.list;
702
- }
703
- inspect() {
704
- return this.list.map((token) => token.inspect()).join("\n") + "\n";
705
- }
706
- toString() {
707
- return this.inspect();
708
- }
709
- }
710
-
711
- class HerbWarning {
712
- message;
713
- location;
714
- static from(warning) {
715
- return new HerbWarning(warning.message, Location.from(warning.location));
716
- }
717
- constructor(message, location) {
718
- this.message = message;
719
- this.location = location;
720
- }
721
- }
722
-
723
- /**
724
- * Represents the result of a lexical analysis, extending the base `Result` class.
725
- * It contains the token list, source code, warnings, and errors.
726
- */
727
- class LexResult extends Result {
728
- /** The list of tokens generated from the source code. */
729
- value;
730
- /**
731
- * Creates a `LexResult` instance from a serialized result.
732
- * @param result - The serialized lexical result containing tokens, source, warnings, and errors.
733
- * @returns A new `LexResult` instance.
734
- */
735
- static from(result) {
736
- return new LexResult(TokenList.from(result.tokens || []), result.source, result.warnings.map((warning) => HerbWarning.from(warning)), result.errors.map((error) => HerbError.from(error)));
737
- }
738
- /**
739
- * Constructs a new `LexResult`.
740
- * @param value - The list of tokens.
741
- * @param source - The source code that was lexed.
742
- * @param warnings - An array of warnings encountered during lexing.
743
- * @param errors - An array of errors encountered during lexing.
744
- */
745
- constructor(value, source, warnings = [], errors = []) {
746
- super(source, warnings, errors);
747
- this.value = value;
748
- }
749
- /**
750
- * Determines if the lexing was successful.
751
- * @returns `true` if there are no errors, otherwise `false`.
752
- */
753
- get successful() {
754
- return this.errors.length === 0;
755
- }
756
- /**
757
- * Determines if the lexing failed.
758
- * @returns `true` if there are errors, otherwise `false`.
759
- */
760
- get failed() {
761
- return this.errors.length > 0;
762
- }
763
- /**
764
- * Converts the `LexResult` to a JSON representation.
765
- * @returns An object containing the token list, source, warnings, and errors.
766
- */
767
- toJSON() {
768
- return {
769
- value: this.value,
770
- source: this.source,
771
- warnings: this.warnings,
772
- errors: this.errors,
773
- };
774
- }
775
- }
776
-
777
590
  // NOTE: This file is generated by the templates/template.rb script and should not
778
- // be modified manually. See /Users/marcoroth/Development/herb-release-0.5.0/templates/javascript/packages/core/src/nodes.ts.erb
591
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.6.1/templates/javascript/packages/core/src/nodes.ts.erb
779
592
  class Node {
780
593
  type;
781
594
  location;
@@ -783,6 +596,9 @@ class Node {
783
596
  static from(node) {
784
597
  return fromSerializedNode(node);
785
598
  }
599
+ static get type() {
600
+ throw new Error("AST_NODE");
601
+ }
786
602
  constructor(type, location, errors) {
787
603
  this.type = type;
788
604
  this.location = location;
@@ -798,6 +614,12 @@ class Node {
798
614
  inspect() {
799
615
  return this.treeInspect(0);
800
616
  }
617
+ is(nodeClass) {
618
+ return this.type === nodeClass.type;
619
+ }
620
+ isOfType(type) {
621
+ return this.type === type;
622
+ }
801
623
  get isSingleLine() {
802
624
  return this.location.start.line === this.location.end.line;
803
625
  }
@@ -839,6 +661,9 @@ class Node {
839
661
  }
840
662
  class DocumentNode extends Node {
841
663
  children;
664
+ static get type() {
665
+ return "AST_DOCUMENT_NODE";
666
+ }
842
667
  static from(data) {
843
668
  return new DocumentNode({
844
669
  type: data.type,
@@ -880,12 +705,14 @@ class DocumentNode extends Node {
880
705
  output += `@ DocumentNode ${this.location.treeInspectWithLabel()}\n`;
881
706
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
882
707
  output += `└── children: ${this.inspectArray(this.children, " ")}`;
883
- // output += "\n";
884
708
  return output;
885
709
  }
886
710
  }
887
711
  class LiteralNode extends Node {
888
712
  content;
713
+ static get type() {
714
+ return "AST_LITERAL_NODE";
715
+ }
889
716
  static from(data) {
890
717
  return new LiteralNode({
891
718
  type: data.type,
@@ -924,7 +751,6 @@ class LiteralNode extends Node {
924
751
  output += `@ LiteralNode ${this.location.treeInspectWithLabel()}\n`;
925
752
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
926
753
  output += `└── content: ${this.content ? JSON.stringify(this.content) : "∅"}\n`;
927
- // output += "\n";
928
754
  return output;
929
755
  }
930
756
  }
@@ -934,6 +760,9 @@ class HTMLOpenTagNode extends Node {
934
760
  tag_closing;
935
761
  children;
936
762
  is_void;
763
+ static get type() {
764
+ return "AST_HTML_OPEN_TAG_NODE";
765
+ }
937
766
  static from(data) {
938
767
  return new HTMLOpenTagNode({
939
768
  type: data.type,
@@ -991,14 +820,17 @@ class HTMLOpenTagNode extends Node {
991
820
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
992
821
  output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
993
822
  output += `└── is_void: ${typeof this.is_void === 'boolean' ? String(this.is_void) : "∅"}\n`;
994
- // output += "\n";
995
823
  return output;
996
824
  }
997
825
  }
998
826
  class HTMLCloseTagNode extends Node {
999
827
  tag_opening;
1000
828
  tag_name;
829
+ children;
1001
830
  tag_closing;
831
+ static get type() {
832
+ return "AST_HTML_CLOSE_TAG_NODE";
833
+ }
1002
834
  static from(data) {
1003
835
  return new HTMLCloseTagNode({
1004
836
  type: data.type,
@@ -1006,6 +838,7 @@ class HTMLCloseTagNode extends Node {
1006
838
  errors: (data.errors || []).map(error => HerbError.from(error)),
1007
839
  tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1008
840
  tag_name: data.tag_name ? Token.from(data.tag_name) : null,
841
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1009
842
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1010
843
  });
1011
844
  }
@@ -1013,13 +846,16 @@ class HTMLCloseTagNode extends Node {
1013
846
  super(props.type, props.location, props.errors);
1014
847
  this.tag_opening = props.tag_opening;
1015
848
  this.tag_name = props.tag_name;
849
+ this.children = props.children;
1016
850
  this.tag_closing = props.tag_closing;
1017
851
  }
1018
852
  accept(visitor) {
1019
853
  visitor.visitHTMLCloseTagNode(this);
1020
854
  }
1021
855
  childNodes() {
1022
- return [];
856
+ return [
857
+ ...this.children,
858
+ ];
1023
859
  }
1024
860
  compactChildNodes() {
1025
861
  return this.childNodes().filter(node => node !== null && node !== undefined);
@@ -1027,6 +863,7 @@ class HTMLCloseTagNode extends Node {
1027
863
  recursiveErrors() {
1028
864
  return [
1029
865
  ...this.errors,
866
+ ...this.children.map(node => node.recursiveErrors()),
1030
867
  ].flat();
1031
868
  }
1032
869
  toJSON() {
@@ -1035,6 +872,7 @@ class HTMLCloseTagNode extends Node {
1035
872
  type: "AST_HTML_CLOSE_TAG_NODE",
1036
873
  tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1037
874
  tag_name: this.tag_name ? this.tag_name.toJSON() : null,
875
+ children: this.children.map(node => node.toJSON()),
1038
876
  tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1039
877
  };
1040
878
  }
@@ -1044,43 +882,48 @@ class HTMLCloseTagNode extends Node {
1044
882
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1045
883
  output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1046
884
  output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
885
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1047
886
  output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1048
- // output += "\n";
1049
887
  return output;
1050
888
  }
1051
889
  }
1052
- class HTMLSelfCloseTagNode extends Node {
1053
- tag_opening;
890
+ class HTMLElementNode extends Node {
891
+ open_tag;
1054
892
  tag_name;
1055
- attributes;
1056
- tag_closing;
893
+ body;
894
+ close_tag;
1057
895
  is_void;
896
+ static get type() {
897
+ return "AST_HTML_ELEMENT_NODE";
898
+ }
1058
899
  static from(data) {
1059
- return new HTMLSelfCloseTagNode({
900
+ return new HTMLElementNode({
1060
901
  type: data.type,
1061
902
  location: Location.from(data.location),
1062
903
  errors: (data.errors || []).map(error => HerbError.from(error)),
1063
- tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
904
+ open_tag: data.open_tag ? fromSerializedNode((data.open_tag)) : null,
1064
905
  tag_name: data.tag_name ? Token.from(data.tag_name) : null,
1065
- attributes: (data.attributes || []).map(node => fromSerializedNode(node)),
1066
- tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
906
+ body: (data.body || []).map(node => fromSerializedNode(node)),
907
+ close_tag: data.close_tag ? fromSerializedNode((data.close_tag)) : null,
1067
908
  is_void: data.is_void,
1068
909
  });
1069
910
  }
1070
911
  constructor(props) {
1071
912
  super(props.type, props.location, props.errors);
1072
- this.tag_opening = props.tag_opening;
913
+ this.open_tag = props.open_tag;
1073
914
  this.tag_name = props.tag_name;
1074
- this.attributes = props.attributes;
1075
- this.tag_closing = props.tag_closing;
915
+ this.body = props.body;
916
+ this.close_tag = props.close_tag;
1076
917
  this.is_void = props.is_void;
1077
918
  }
1078
919
  accept(visitor) {
1079
- visitor.visitHTMLSelfCloseTagNode(this);
920
+ visitor.visitHTMLElementNode(this);
1080
921
  }
1081
922
  childNodes() {
1082
923
  return [
1083
- ...this.attributes,
924
+ this.open_tag,
925
+ ...this.body,
926
+ this.close_tag,
1084
927
  ];
1085
928
  }
1086
929
  compactChildNodes() {
@@ -1089,111 +932,44 @@ class HTMLSelfCloseTagNode extends Node {
1089
932
  recursiveErrors() {
1090
933
  return [
1091
934
  ...this.errors,
1092
- ...this.attributes.map(node => node.recursiveErrors()),
935
+ this.open_tag ? this.open_tag.recursiveErrors() : [],
936
+ ...this.body.map(node => node.recursiveErrors()),
937
+ this.close_tag ? this.close_tag.recursiveErrors() : [],
1093
938
  ].flat();
1094
939
  }
1095
940
  toJSON() {
1096
941
  return {
1097
942
  ...super.toJSON(),
1098
- type: "AST_HTML_SELF_CLOSE_TAG_NODE",
1099
- tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
943
+ type: "AST_HTML_ELEMENT_NODE",
944
+ open_tag: this.open_tag ? this.open_tag.toJSON() : null,
1100
945
  tag_name: this.tag_name ? this.tag_name.toJSON() : null,
1101
- attributes: this.attributes.map(node => node.toJSON()),
1102
- tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
946
+ body: this.body.map(node => node.toJSON()),
947
+ close_tag: this.close_tag ? this.close_tag.toJSON() : null,
1103
948
  is_void: this.is_void,
1104
949
  };
1105
950
  }
1106
951
  treeInspect() {
1107
952
  let output = "";
1108
- output += `@ HTMLSelfCloseTagNode ${this.location.treeInspectWithLabel()}\n`;
953
+ output += `@ HTMLElementNode ${this.location.treeInspectWithLabel()}\n`;
1109
954
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1110
- output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : ""}\n`;
955
+ output += `├── open_tag: ${this.inspectNode(this.open_tag, "")}`;
1111
956
  output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
1112
- output += `├── attributes: ${this.inspectArray(this.attributes, "│ ")}`;
1113
- output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : ""}\n`;
957
+ output += `├── body: ${this.inspectArray(this.body, "│ ")}`;
958
+ output += `├── close_tag: ${this.inspectNode(this.close_tag, "")}`;
1114
959
  output += `└── is_void: ${typeof this.is_void === 'boolean' ? String(this.is_void) : "∅"}\n`;
1115
- // output += "\n";
1116
960
  return output;
1117
961
  }
1118
962
  }
1119
- class HTMLElementNode extends Node {
1120
- open_tag;
1121
- tag_name;
1122
- body;
1123
- close_tag;
1124
- is_void;
963
+ class HTMLAttributeValueNode extends Node {
964
+ open_quote;
965
+ children;
966
+ close_quote;
967
+ quoted;
968
+ static get type() {
969
+ return "AST_HTML_ATTRIBUTE_VALUE_NODE";
970
+ }
1125
971
  static from(data) {
1126
- return new HTMLElementNode({
1127
- type: data.type,
1128
- location: Location.from(data.location),
1129
- errors: (data.errors || []).map(error => HerbError.from(error)),
1130
- open_tag: data.open_tag ? fromSerializedNode(data.open_tag) : null,
1131
- tag_name: data.tag_name ? Token.from(data.tag_name) : null,
1132
- body: (data.body || []).map(node => fromSerializedNode(node)),
1133
- close_tag: data.close_tag ? fromSerializedNode(data.close_tag) : null,
1134
- is_void: data.is_void,
1135
- });
1136
- }
1137
- constructor(props) {
1138
- super(props.type, props.location, props.errors);
1139
- this.open_tag = props.open_tag;
1140
- this.tag_name = props.tag_name;
1141
- this.body = props.body;
1142
- this.close_tag = props.close_tag;
1143
- this.is_void = props.is_void;
1144
- }
1145
- accept(visitor) {
1146
- visitor.visitHTMLElementNode(this);
1147
- }
1148
- childNodes() {
1149
- return [
1150
- this.open_tag,
1151
- ...this.body,
1152
- this.close_tag,
1153
- ];
1154
- }
1155
- compactChildNodes() {
1156
- return this.childNodes().filter(node => node !== null && node !== undefined);
1157
- }
1158
- recursiveErrors() {
1159
- return [
1160
- ...this.errors,
1161
- this.open_tag ? this.open_tag.recursiveErrors() : [],
1162
- ...this.body.map(node => node.recursiveErrors()),
1163
- this.close_tag ? this.close_tag.recursiveErrors() : [],
1164
- ].flat();
1165
- }
1166
- toJSON() {
1167
- return {
1168
- ...super.toJSON(),
1169
- type: "AST_HTML_ELEMENT_NODE",
1170
- open_tag: this.open_tag ? this.open_tag.toJSON() : null,
1171
- tag_name: this.tag_name ? this.tag_name.toJSON() : null,
1172
- body: this.body.map(node => node.toJSON()),
1173
- close_tag: this.close_tag ? this.close_tag.toJSON() : null,
1174
- is_void: this.is_void,
1175
- };
1176
- }
1177
- treeInspect() {
1178
- let output = "";
1179
- output += `@ HTMLElementNode ${this.location.treeInspectWithLabel()}\n`;
1180
- output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1181
- output += `├── open_tag: ${this.inspectNode(this.open_tag, "│ ")}`;
1182
- output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
1183
- output += `├── body: ${this.inspectArray(this.body, "│ ")}`;
1184
- output += `├── close_tag: ${this.inspectNode(this.close_tag, "│ ")}`;
1185
- output += `└── is_void: ${typeof this.is_void === 'boolean' ? String(this.is_void) : "∅"}\n`;
1186
- // output += "\n";
1187
- return output;
1188
- }
1189
- }
1190
- class HTMLAttributeValueNode extends Node {
1191
- open_quote;
1192
- children;
1193
- close_quote;
1194
- quoted;
1195
- static from(data) {
1196
- return new HTMLAttributeValueNode({
972
+ return new HTMLAttributeValueNode({
1197
973
  type: data.type,
1198
974
  location: Location.from(data.location),
1199
975
  errors: (data.errors || []).map(error => HerbError.from(error)),
@@ -1245,29 +1021,33 @@ class HTMLAttributeValueNode extends Node {
1245
1021
  output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1246
1022
  output += `├── close_quote: ${this.close_quote ? this.close_quote.treeInspect() : "∅"}\n`;
1247
1023
  output += `└── quoted: ${typeof this.quoted === 'boolean' ? String(this.quoted) : "∅"}\n`;
1248
- // output += "\n";
1249
1024
  return output;
1250
1025
  }
1251
1026
  }
1252
1027
  class HTMLAttributeNameNode extends Node {
1253
- name;
1028
+ children;
1029
+ static get type() {
1030
+ return "AST_HTML_ATTRIBUTE_NAME_NODE";
1031
+ }
1254
1032
  static from(data) {
1255
1033
  return new HTMLAttributeNameNode({
1256
1034
  type: data.type,
1257
1035
  location: Location.from(data.location),
1258
1036
  errors: (data.errors || []).map(error => HerbError.from(error)),
1259
- name: data.name ? Token.from(data.name) : null,
1037
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1260
1038
  });
1261
1039
  }
1262
1040
  constructor(props) {
1263
1041
  super(props.type, props.location, props.errors);
1264
- this.name = props.name;
1042
+ this.children = props.children;
1265
1043
  }
1266
1044
  accept(visitor) {
1267
1045
  visitor.visitHTMLAttributeNameNode(this);
1268
1046
  }
1269
1047
  childNodes() {
1270
- return [];
1048
+ return [
1049
+ ...this.children,
1050
+ ];
1271
1051
  }
1272
1052
  compactChildNodes() {
1273
1053
  return this.childNodes().filter(node => node !== null && node !== undefined);
@@ -1275,21 +1055,21 @@ class HTMLAttributeNameNode extends Node {
1275
1055
  recursiveErrors() {
1276
1056
  return [
1277
1057
  ...this.errors,
1058
+ ...this.children.map(node => node.recursiveErrors()),
1278
1059
  ].flat();
1279
1060
  }
1280
1061
  toJSON() {
1281
1062
  return {
1282
1063
  ...super.toJSON(),
1283
1064
  type: "AST_HTML_ATTRIBUTE_NAME_NODE",
1284
- name: this.name ? this.name.toJSON() : null,
1065
+ children: this.children.map(node => node.toJSON()),
1285
1066
  };
1286
1067
  }
1287
1068
  treeInspect() {
1288
1069
  let output = "";
1289
1070
  output += `@ HTMLAttributeNameNode ${this.location.treeInspectWithLabel()}\n`;
1290
1071
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1291
- output += `└── name: ${this.name ? this.name.treeInspect() : ""}\n`;
1292
- // output += "\n";
1072
+ output += `└── children: ${this.inspectArray(this.children, " ")}`;
1293
1073
  return output;
1294
1074
  }
1295
1075
  }
@@ -1297,14 +1077,17 @@ class HTMLAttributeNode extends Node {
1297
1077
  name;
1298
1078
  equals;
1299
1079
  value;
1080
+ static get type() {
1081
+ return "AST_HTML_ATTRIBUTE_NODE";
1082
+ }
1300
1083
  static from(data) {
1301
1084
  return new HTMLAttributeNode({
1302
1085
  type: data.type,
1303
1086
  location: Location.from(data.location),
1304
1087
  errors: (data.errors || []).map(error => HerbError.from(error)),
1305
- name: data.name ? fromSerializedNode(data.name) : null,
1088
+ name: data.name ? fromSerializedNode((data.name)) : null,
1306
1089
  equals: data.equals ? Token.from(data.equals) : null,
1307
- value: data.value ? fromSerializedNode(data.value) : null,
1090
+ value: data.value ? fromSerializedNode((data.value)) : null,
1308
1091
  });
1309
1092
  }
1310
1093
  constructor(props) {
@@ -1348,12 +1131,14 @@ class HTMLAttributeNode extends Node {
1348
1131
  output += `├── name: ${this.inspectNode(this.name, "│ ")}`;
1349
1132
  output += `├── equals: ${this.equals ? this.equals.treeInspect() : "∅"}\n`;
1350
1133
  output += `└── value: ${this.inspectNode(this.value, " ")}`;
1351
- // output += "\n";
1352
1134
  return output;
1353
1135
  }
1354
1136
  }
1355
1137
  class HTMLTextNode extends Node {
1356
1138
  content;
1139
+ static get type() {
1140
+ return "AST_HTML_TEXT_NODE";
1141
+ }
1357
1142
  static from(data) {
1358
1143
  return new HTMLTextNode({
1359
1144
  type: data.type,
@@ -1392,7 +1177,6 @@ class HTMLTextNode extends Node {
1392
1177
  output += `@ HTMLTextNode ${this.location.treeInspectWithLabel()}\n`;
1393
1178
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1394
1179
  output += `└── content: ${this.content ? JSON.stringify(this.content) : "∅"}\n`;
1395
- // output += "\n";
1396
1180
  return output;
1397
1181
  }
1398
1182
  }
@@ -1400,6 +1184,9 @@ class HTMLCommentNode extends Node {
1400
1184
  comment_start;
1401
1185
  children;
1402
1186
  comment_end;
1187
+ static get type() {
1188
+ return "AST_HTML_COMMENT_NODE";
1189
+ }
1403
1190
  static from(data) {
1404
1191
  return new HTMLCommentNode({
1405
1192
  type: data.type,
@@ -1449,7 +1236,6 @@ class HTMLCommentNode extends Node {
1449
1236
  output += `├── comment_start: ${this.comment_start ? this.comment_start.treeInspect() : "∅"}\n`;
1450
1237
  output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1451
1238
  output += `└── comment_end: ${this.comment_end ? this.comment_end.treeInspect() : "∅"}\n`;
1452
- // output += "\n";
1453
1239
  return output;
1454
1240
  }
1455
1241
  }
@@ -1457,6 +1243,9 @@ class HTMLDoctypeNode extends Node {
1457
1243
  tag_opening;
1458
1244
  children;
1459
1245
  tag_closing;
1246
+ static get type() {
1247
+ return "AST_HTML_DOCTYPE_NODE";
1248
+ }
1460
1249
  static from(data) {
1461
1250
  return new HTMLDoctypeNode({
1462
1251
  type: data.type,
@@ -1506,12 +1295,132 @@ class HTMLDoctypeNode extends Node {
1506
1295
  output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1507
1296
  output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1508
1297
  output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1509
- // output += "\n";
1298
+ return output;
1299
+ }
1300
+ }
1301
+ class XMLDeclarationNode extends Node {
1302
+ tag_opening;
1303
+ children;
1304
+ tag_closing;
1305
+ static get type() {
1306
+ return "AST_XML_DECLARATION_NODE";
1307
+ }
1308
+ static from(data) {
1309
+ return new XMLDeclarationNode({
1310
+ type: data.type,
1311
+ location: Location.from(data.location),
1312
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1313
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1314
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1315
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1316
+ });
1317
+ }
1318
+ constructor(props) {
1319
+ super(props.type, props.location, props.errors);
1320
+ this.tag_opening = props.tag_opening;
1321
+ this.children = props.children;
1322
+ this.tag_closing = props.tag_closing;
1323
+ }
1324
+ accept(visitor) {
1325
+ visitor.visitXMLDeclarationNode(this);
1326
+ }
1327
+ childNodes() {
1328
+ return [
1329
+ ...this.children,
1330
+ ];
1331
+ }
1332
+ compactChildNodes() {
1333
+ return this.childNodes().filter(node => node !== null && node !== undefined);
1334
+ }
1335
+ recursiveErrors() {
1336
+ return [
1337
+ ...this.errors,
1338
+ ...this.children.map(node => node.recursiveErrors()),
1339
+ ].flat();
1340
+ }
1341
+ toJSON() {
1342
+ return {
1343
+ ...super.toJSON(),
1344
+ type: "AST_XML_DECLARATION_NODE",
1345
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1346
+ children: this.children.map(node => node.toJSON()),
1347
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1348
+ };
1349
+ }
1350
+ treeInspect() {
1351
+ let output = "";
1352
+ output += `@ XMLDeclarationNode ${this.location.treeInspectWithLabel()}\n`;
1353
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1354
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1355
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1356
+ output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1357
+ return output;
1358
+ }
1359
+ }
1360
+ class CDATANode extends Node {
1361
+ tag_opening;
1362
+ children;
1363
+ tag_closing;
1364
+ static get type() {
1365
+ return "AST_CDATA_NODE";
1366
+ }
1367
+ static from(data) {
1368
+ return new CDATANode({
1369
+ type: data.type,
1370
+ location: Location.from(data.location),
1371
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1372
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1373
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1374
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1375
+ });
1376
+ }
1377
+ constructor(props) {
1378
+ super(props.type, props.location, props.errors);
1379
+ this.tag_opening = props.tag_opening;
1380
+ this.children = props.children;
1381
+ this.tag_closing = props.tag_closing;
1382
+ }
1383
+ accept(visitor) {
1384
+ visitor.visitCDATANode(this);
1385
+ }
1386
+ childNodes() {
1387
+ return [
1388
+ ...this.children,
1389
+ ];
1390
+ }
1391
+ compactChildNodes() {
1392
+ return this.childNodes().filter(node => node !== null && node !== undefined);
1393
+ }
1394
+ recursiveErrors() {
1395
+ return [
1396
+ ...this.errors,
1397
+ ...this.children.map(node => node.recursiveErrors()),
1398
+ ].flat();
1399
+ }
1400
+ toJSON() {
1401
+ return {
1402
+ ...super.toJSON(),
1403
+ type: "AST_CDATA_NODE",
1404
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1405
+ children: this.children.map(node => node.toJSON()),
1406
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1407
+ };
1408
+ }
1409
+ treeInspect() {
1410
+ let output = "";
1411
+ output += `@ CDATANode ${this.location.treeInspectWithLabel()}\n`;
1412
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1413
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1414
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1415
+ output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1510
1416
  return output;
1511
1417
  }
1512
1418
  }
1513
1419
  class WhitespaceNode extends Node {
1514
1420
  value;
1421
+ static get type() {
1422
+ return "AST_WHITESPACE_NODE";
1423
+ }
1515
1424
  static from(data) {
1516
1425
  return new WhitespaceNode({
1517
1426
  type: data.type,
@@ -1550,7 +1459,6 @@ class WhitespaceNode extends Node {
1550
1459
  output += `@ WhitespaceNode ${this.location.treeInspectWithLabel()}\n`;
1551
1460
  output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1552
1461
  output += `└── value: ${this.value ? this.value.treeInspect() : "∅"}\n`;
1553
- // output += "\n";
1554
1462
  return output;
1555
1463
  }
1556
1464
  }
@@ -1561,6 +1469,9 @@ class ERBContentNode extends Node {
1561
1469
  // no-op for analyzed_ruby
1562
1470
  parsed;
1563
1471
  valid;
1472
+ static get type() {
1473
+ return "AST_ERB_CONTENT_NODE";
1474
+ }
1564
1475
  static from(data) {
1565
1476
  return new ERBContentNode({
1566
1477
  type: data.type,
@@ -1619,7 +1530,6 @@ class ERBContentNode extends Node {
1619
1530
  // no-op for analyzed_ruby
1620
1531
  output += `├── parsed: ${typeof this.parsed === 'boolean' ? String(this.parsed) : "∅"}\n`;
1621
1532
  output += `└── valid: ${typeof this.valid === 'boolean' ? String(this.valid) : "∅"}\n`;
1622
- // output += "\n";
1623
1533
  return output;
1624
1534
  }
1625
1535
  }
@@ -1627,6 +1537,9 @@ class ERBEndNode extends Node {
1627
1537
  tag_opening;
1628
1538
  content;
1629
1539
  tag_closing;
1540
+ static get type() {
1541
+ return "AST_ERB_END_NODE";
1542
+ }
1630
1543
  static from(data) {
1631
1544
  return new ERBEndNode({
1632
1545
  type: data.type,
@@ -1673,7 +1586,6 @@ class ERBEndNode extends Node {
1673
1586
  output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1674
1587
  output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1675
1588
  output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1676
- // output += "\n";
1677
1589
  return output;
1678
1590
  }
1679
1591
  }
@@ -1682,6 +1594,9 @@ class ERBElseNode extends Node {
1682
1594
  content;
1683
1595
  tag_closing;
1684
1596
  statements;
1597
+ static get type() {
1598
+ return "AST_ERB_ELSE_NODE";
1599
+ }
1685
1600
  static from(data) {
1686
1601
  return new ERBElseNode({
1687
1602
  type: data.type,
@@ -1735,7 +1650,6 @@ class ERBElseNode extends Node {
1735
1650
  output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1736
1651
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1737
1652
  output += `└── statements: ${this.inspectArray(this.statements, " ")}`;
1738
- // output += "\n";
1739
1653
  return output;
1740
1654
  }
1741
1655
  }
@@ -1746,6 +1660,9 @@ class ERBIfNode extends Node {
1746
1660
  statements;
1747
1661
  subsequent;
1748
1662
  end_node;
1663
+ static get type() {
1664
+ return "AST_ERB_IF_NODE";
1665
+ }
1749
1666
  static from(data) {
1750
1667
  return new ERBIfNode({
1751
1668
  type: data.type,
@@ -1755,8 +1672,8 @@ class ERBIfNode extends Node {
1755
1672
  content: data.content ? Token.from(data.content) : null,
1756
1673
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1757
1674
  statements: (data.statements || []).map(node => fromSerializedNode(node)),
1758
- subsequent: data.subsequent ? fromSerializedNode(data.subsequent) : null,
1759
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
1675
+ subsequent: data.subsequent ? fromSerializedNode((data.subsequent)) : null,
1676
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
1760
1677
  });
1761
1678
  }
1762
1679
  constructor(props) {
@@ -1811,7 +1728,6 @@ class ERBIfNode extends Node {
1811
1728
  output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
1812
1729
  output += `├── subsequent: ${this.inspectNode(this.subsequent, "│ ")}`;
1813
1730
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
1814
- // output += "\n";
1815
1731
  return output;
1816
1732
  }
1817
1733
  }
@@ -1821,6 +1737,9 @@ class ERBBlockNode extends Node {
1821
1737
  tag_closing;
1822
1738
  body;
1823
1739
  end_node;
1740
+ static get type() {
1741
+ return "AST_ERB_BLOCK_NODE";
1742
+ }
1824
1743
  static from(data) {
1825
1744
  return new ERBBlockNode({
1826
1745
  type: data.type,
@@ -1830,7 +1749,7 @@ class ERBBlockNode extends Node {
1830
1749
  content: data.content ? Token.from(data.content) : null,
1831
1750
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1832
1751
  body: (data.body || []).map(node => fromSerializedNode(node)),
1833
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
1752
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
1834
1753
  });
1835
1754
  }
1836
1755
  constructor(props) {
@@ -1880,7 +1799,6 @@ class ERBBlockNode extends Node {
1880
1799
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1881
1800
  output += `├── body: ${this.inspectArray(this.body, "│ ")}`;
1882
1801
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
1883
- // output += "\n";
1884
1802
  return output;
1885
1803
  }
1886
1804
  }
@@ -1889,6 +1807,9 @@ class ERBWhenNode extends Node {
1889
1807
  content;
1890
1808
  tag_closing;
1891
1809
  statements;
1810
+ static get type() {
1811
+ return "AST_ERB_WHEN_NODE";
1812
+ }
1892
1813
  static from(data) {
1893
1814
  return new ERBWhenNode({
1894
1815
  type: data.type,
@@ -1942,7 +1863,6 @@ class ERBWhenNode extends Node {
1942
1863
  output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1943
1864
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1944
1865
  output += `└── statements: ${this.inspectArray(this.statements, " ")}`;
1945
- // output += "\n";
1946
1866
  return output;
1947
1867
  }
1948
1868
  }
@@ -1954,6 +1874,9 @@ class ERBCaseNode extends Node {
1954
1874
  conditions;
1955
1875
  else_clause;
1956
1876
  end_node;
1877
+ static get type() {
1878
+ return "AST_ERB_CASE_NODE";
1879
+ }
1957
1880
  static from(data) {
1958
1881
  return new ERBCaseNode({
1959
1882
  type: data.type,
@@ -1964,8 +1887,8 @@ class ERBCaseNode extends Node {
1964
1887
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1965
1888
  children: (data.children || []).map(node => fromSerializedNode(node)),
1966
1889
  conditions: (data.conditions || []).map(node => fromSerializedNode(node)),
1967
- else_clause: data.else_clause ? fromSerializedNode(data.else_clause) : null,
1968
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
1890
+ else_clause: data.else_clause ? fromSerializedNode((data.else_clause)) : null,
1891
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
1969
1892
  });
1970
1893
  }
1971
1894
  constructor(props) {
@@ -2025,7 +1948,6 @@ class ERBCaseNode extends Node {
2025
1948
  output += `├── conditions: ${this.inspectArray(this.conditions, "│ ")}`;
2026
1949
  output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
2027
1950
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2028
- // output += "\n";
2029
1951
  return output;
2030
1952
  }
2031
1953
  }
@@ -2037,6 +1959,9 @@ class ERBCaseMatchNode extends Node {
2037
1959
  conditions;
2038
1960
  else_clause;
2039
1961
  end_node;
1962
+ static get type() {
1963
+ return "AST_ERB_CASE_MATCH_NODE";
1964
+ }
2040
1965
  static from(data) {
2041
1966
  return new ERBCaseMatchNode({
2042
1967
  type: data.type,
@@ -2047,8 +1972,8 @@ class ERBCaseMatchNode extends Node {
2047
1972
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2048
1973
  children: (data.children || []).map(node => fromSerializedNode(node)),
2049
1974
  conditions: (data.conditions || []).map(node => fromSerializedNode(node)),
2050
- else_clause: data.else_clause ? fromSerializedNode(data.else_clause) : null,
2051
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
1975
+ else_clause: data.else_clause ? fromSerializedNode((data.else_clause)) : null,
1976
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
2052
1977
  });
2053
1978
  }
2054
1979
  constructor(props) {
@@ -2108,7 +2033,6 @@ class ERBCaseMatchNode extends Node {
2108
2033
  output += `├── conditions: ${this.inspectArray(this.conditions, "│ ")}`;
2109
2034
  output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
2110
2035
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2111
- // output += "\n";
2112
2036
  return output;
2113
2037
  }
2114
2038
  }
@@ -2118,6 +2042,9 @@ class ERBWhileNode extends Node {
2118
2042
  tag_closing;
2119
2043
  statements;
2120
2044
  end_node;
2045
+ static get type() {
2046
+ return "AST_ERB_WHILE_NODE";
2047
+ }
2121
2048
  static from(data) {
2122
2049
  return new ERBWhileNode({
2123
2050
  type: data.type,
@@ -2127,7 +2054,7 @@ class ERBWhileNode extends Node {
2127
2054
  content: data.content ? Token.from(data.content) : null,
2128
2055
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2129
2056
  statements: (data.statements || []).map(node => fromSerializedNode(node)),
2130
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2057
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
2131
2058
  });
2132
2059
  }
2133
2060
  constructor(props) {
@@ -2177,7 +2104,6 @@ class ERBWhileNode extends Node {
2177
2104
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2178
2105
  output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2179
2106
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2180
- // output += "\n";
2181
2107
  return output;
2182
2108
  }
2183
2109
  }
@@ -2187,6 +2113,9 @@ class ERBUntilNode extends Node {
2187
2113
  tag_closing;
2188
2114
  statements;
2189
2115
  end_node;
2116
+ static get type() {
2117
+ return "AST_ERB_UNTIL_NODE";
2118
+ }
2190
2119
  static from(data) {
2191
2120
  return new ERBUntilNode({
2192
2121
  type: data.type,
@@ -2196,7 +2125,7 @@ class ERBUntilNode extends Node {
2196
2125
  content: data.content ? Token.from(data.content) : null,
2197
2126
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2198
2127
  statements: (data.statements || []).map(node => fromSerializedNode(node)),
2199
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2128
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
2200
2129
  });
2201
2130
  }
2202
2131
  constructor(props) {
@@ -2246,7 +2175,6 @@ class ERBUntilNode extends Node {
2246
2175
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2247
2176
  output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2248
2177
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2249
- // output += "\n";
2250
2178
  return output;
2251
2179
  }
2252
2180
  }
@@ -2256,6 +2184,9 @@ class ERBForNode extends Node {
2256
2184
  tag_closing;
2257
2185
  statements;
2258
2186
  end_node;
2187
+ static get type() {
2188
+ return "AST_ERB_FOR_NODE";
2189
+ }
2259
2190
  static from(data) {
2260
2191
  return new ERBForNode({
2261
2192
  type: data.type,
@@ -2265,7 +2196,7 @@ class ERBForNode extends Node {
2265
2196
  content: data.content ? Token.from(data.content) : null,
2266
2197
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2267
2198
  statements: (data.statements || []).map(node => fromSerializedNode(node)),
2268
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2199
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
2269
2200
  });
2270
2201
  }
2271
2202
  constructor(props) {
@@ -2315,7 +2246,6 @@ class ERBForNode extends Node {
2315
2246
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2316
2247
  output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2317
2248
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2318
- // output += "\n";
2319
2249
  return output;
2320
2250
  }
2321
2251
  }
@@ -2325,6 +2255,9 @@ class ERBRescueNode extends Node {
2325
2255
  tag_closing;
2326
2256
  statements;
2327
2257
  subsequent;
2258
+ static get type() {
2259
+ return "AST_ERB_RESCUE_NODE";
2260
+ }
2328
2261
  static from(data) {
2329
2262
  return new ERBRescueNode({
2330
2263
  type: data.type,
@@ -2334,7 +2267,7 @@ class ERBRescueNode extends Node {
2334
2267
  content: data.content ? Token.from(data.content) : null,
2335
2268
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2336
2269
  statements: (data.statements || []).map(node => fromSerializedNode(node)),
2337
- subsequent: data.subsequent ? fromSerializedNode(data.subsequent) : null,
2270
+ subsequent: data.subsequent ? fromSerializedNode((data.subsequent)) : null,
2338
2271
  });
2339
2272
  }
2340
2273
  constructor(props) {
@@ -2384,7 +2317,6 @@ class ERBRescueNode extends Node {
2384
2317
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2385
2318
  output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2386
2319
  output += `└── subsequent: ${this.inspectNode(this.subsequent, " ")}`;
2387
- // output += "\n";
2388
2320
  return output;
2389
2321
  }
2390
2322
  }
@@ -2393,6 +2325,9 @@ class ERBEnsureNode extends Node {
2393
2325
  content;
2394
2326
  tag_closing;
2395
2327
  statements;
2328
+ static get type() {
2329
+ return "AST_ERB_ENSURE_NODE";
2330
+ }
2396
2331
  static from(data) {
2397
2332
  return new ERBEnsureNode({
2398
2333
  type: data.type,
@@ -2446,7 +2381,6 @@ class ERBEnsureNode extends Node {
2446
2381
  output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2447
2382
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2448
2383
  output += `└── statements: ${this.inspectArray(this.statements, " ")}`;
2449
- // output += "\n";
2450
2384
  return output;
2451
2385
  }
2452
2386
  }
@@ -2459,6 +2393,9 @@ class ERBBeginNode extends Node {
2459
2393
  else_clause;
2460
2394
  ensure_clause;
2461
2395
  end_node;
2396
+ static get type() {
2397
+ return "AST_ERB_BEGIN_NODE";
2398
+ }
2462
2399
  static from(data) {
2463
2400
  return new ERBBeginNode({
2464
2401
  type: data.type,
@@ -2468,10 +2405,10 @@ class ERBBeginNode extends Node {
2468
2405
  content: data.content ? Token.from(data.content) : null,
2469
2406
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2470
2407
  statements: (data.statements || []).map(node => fromSerializedNode(node)),
2471
- rescue_clause: data.rescue_clause ? fromSerializedNode(data.rescue_clause) : null,
2472
- else_clause: data.else_clause ? fromSerializedNode(data.else_clause) : null,
2473
- ensure_clause: data.ensure_clause ? fromSerializedNode(data.ensure_clause) : null,
2474
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2408
+ rescue_clause: data.rescue_clause ? fromSerializedNode((data.rescue_clause)) : null,
2409
+ else_clause: data.else_clause ? fromSerializedNode((data.else_clause)) : null,
2410
+ ensure_clause: data.ensure_clause ? fromSerializedNode((data.ensure_clause)) : null,
2411
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
2475
2412
  });
2476
2413
  }
2477
2414
  constructor(props) {
@@ -2536,7 +2473,6 @@ class ERBBeginNode extends Node {
2536
2473
  output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
2537
2474
  output += `├── ensure_clause: ${this.inspectNode(this.ensure_clause, "│ ")}`;
2538
2475
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2539
- // output += "\n";
2540
2476
  return output;
2541
2477
  }
2542
2478
  }
@@ -2547,6 +2483,9 @@ class ERBUnlessNode extends Node {
2547
2483
  statements;
2548
2484
  else_clause;
2549
2485
  end_node;
2486
+ static get type() {
2487
+ return "AST_ERB_UNLESS_NODE";
2488
+ }
2550
2489
  static from(data) {
2551
2490
  return new ERBUnlessNode({
2552
2491
  type: data.type,
@@ -2556,8 +2495,8 @@ class ERBUnlessNode extends Node {
2556
2495
  content: data.content ? Token.from(data.content) : null,
2557
2496
  tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2558
2497
  statements: (data.statements || []).map(node => fromSerializedNode(node)),
2559
- else_clause: data.else_clause ? fromSerializedNode(data.else_clause) : null,
2560
- end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2498
+ else_clause: data.else_clause ? fromSerializedNode((data.else_clause)) : null,
2499
+ end_node: data.end_node ? fromSerializedNode((data.end_node)) : null,
2561
2500
  });
2562
2501
  }
2563
2502
  constructor(props) {
@@ -2612,7 +2551,6 @@ class ERBUnlessNode extends Node {
2612
2551
  output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2613
2552
  output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
2614
2553
  output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2615
- // output += "\n";
2616
2554
  return output;
2617
2555
  }
2618
2556
  }
@@ -2620,6 +2558,9 @@ class ERBYieldNode extends Node {
2620
2558
  tag_opening;
2621
2559
  content;
2622
2560
  tag_closing;
2561
+ static get type() {
2562
+ return "AST_ERB_YIELD_NODE";
2563
+ }
2623
2564
  static from(data) {
2624
2565
  return new ERBYieldNode({
2625
2566
  type: data.type,
@@ -2666,7 +2607,6 @@ class ERBYieldNode extends Node {
2666
2607
  output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2667
2608
  output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2668
2609
  output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2669
- // output += "\n";
2670
2610
  return output;
2671
2611
  }
2672
2612
  }
@@ -2675,6 +2615,9 @@ class ERBInNode extends Node {
2675
2615
  content;
2676
2616
  tag_closing;
2677
2617
  statements;
2618
+ static get type() {
2619
+ return "AST_ERB_IN_NODE";
2620
+ }
2678
2621
  static from(data) {
2679
2622
  return new ERBInNode({
2680
2623
  type: data.type,
@@ -2728,7 +2671,6 @@ class ERBInNode extends Node {
2728
2671
  output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2729
2672
  output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2730
2673
  output += `└── statements: ${this.inspectArray(this.statements, " ")}`;
2731
- // output += "\n";
2732
2674
  return output;
2733
2675
  }
2734
2676
  }
@@ -2738,7 +2680,6 @@ function fromSerializedNode(node) {
2738
2680
  case "AST_LITERAL_NODE": return LiteralNode.from(node);
2739
2681
  case "AST_HTML_OPEN_TAG_NODE": return HTMLOpenTagNode.from(node);
2740
2682
  case "AST_HTML_CLOSE_TAG_NODE": return HTMLCloseTagNode.from(node);
2741
- case "AST_HTML_SELF_CLOSE_TAG_NODE": return HTMLSelfCloseTagNode.from(node);
2742
2683
  case "AST_HTML_ELEMENT_NODE": return HTMLElementNode.from(node);
2743
2684
  case "AST_HTML_ATTRIBUTE_VALUE_NODE": return HTMLAttributeValueNode.from(node);
2744
2685
  case "AST_HTML_ATTRIBUTE_NAME_NODE": return HTMLAttributeNameNode.from(node);
@@ -2746,6 +2687,8 @@ function fromSerializedNode(node) {
2746
2687
  case "AST_HTML_TEXT_NODE": return HTMLTextNode.from(node);
2747
2688
  case "AST_HTML_COMMENT_NODE": return HTMLCommentNode.from(node);
2748
2689
  case "AST_HTML_DOCTYPE_NODE": return HTMLDoctypeNode.from(node);
2690
+ case "AST_XML_DECLARATION_NODE": return XMLDeclarationNode.from(node);
2691
+ case "AST_CDATA_NODE": return CDATANode.from(node);
2749
2692
  case "AST_WHITESPACE_NODE": return WhitespaceNode.from(node);
2750
2693
  case "AST_ERB_CONTENT_NODE": return ERBContentNode.from(node);
2751
2694
  case "AST_ERB_END_NODE": return ERBEndNode.from(node);
@@ -2787,8 +2730,42 @@ const ERBNodeClasses = [
2787
2730
  ERBYieldNode,
2788
2731
  ERBInNode,
2789
2732
  ];
2790
- function isERBNode(node) {
2791
- return node.constructor.name.startsWith("ERB");
2733
+
2734
+ class Result {
2735
+ source;
2736
+ warnings;
2737
+ errors;
2738
+ constructor(source, warnings = [], errors = []) {
2739
+ this.source = source;
2740
+ this.warnings = warnings || [];
2741
+ this.errors = errors || [];
2742
+ }
2743
+ /**
2744
+ * Determines if the parsing was successful.
2745
+ * @returns `true` if there are no errors, otherwise `false`.
2746
+ */
2747
+ get successful() {
2748
+ return this.errors.length === 0;
2749
+ }
2750
+ /**
2751
+ * Determines if the parsing failed.
2752
+ * @returns `true` if there are errors, otherwise `false`.
2753
+ */
2754
+ get failed() {
2755
+ return this.errors.length > 0;
2756
+ }
2757
+ }
2758
+
2759
+ class HerbWarning {
2760
+ message;
2761
+ location;
2762
+ static from(warning) {
2763
+ return new HerbWarning(warning.message, Location.from(warning.location));
2764
+ }
2765
+ constructor(message, location) {
2766
+ this.message = message;
2767
+ this.location = location;
2768
+ }
2792
2769
  }
2793
2770
 
2794
2771
  /**
@@ -2858,23 +2835,1017 @@ class ParseResult extends Result {
2858
2835
  }
2859
2836
  }
2860
2837
 
2838
+ // NOTE: This file is generated by the templates/template.rb script and should not
2839
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.6.1/templates/javascript/packages/core/src/node-type-guards.ts.erb
2861
2840
  /**
2862
- * The main Herb parser interface, providing methods to lex and parse input.
2841
+ * Type guard functions for AST nodes.
2842
+ * These functions provide type checking by combining both instanceof
2843
+ * checks and type string comparisons for maximum reliability across different
2844
+ * runtime scenarios (e.g., serialized/deserialized nodes).
2863
2845
  */
2864
- class HerbBackend {
2865
- /** The backend instance handling lexing and parsing. */
2866
- backend = undefined;
2867
- backendPromise;
2868
- /**
2869
- * Creates a new Herb instance.
2870
- * @param backendPromise - A promise resolving to a `LibHerbBackend` implementation for lexing and parsing.
2871
- * @throws Error if no valid backend is provided.
2872
- */
2873
- constructor(backendPromise) {
2874
- if (!backendPromise) {
2875
- throw new Error("No LibHerb backend provided");
2876
- }
2877
- this.backendPromise = backendPromise;
2846
+ /**
2847
+ * Checks if a node is a DocumentNode
2848
+ */
2849
+ function isDocumentNode(node) {
2850
+ return node instanceof DocumentNode || node.type === "AST_DOCUMENT_NODE" || node.constructor.type === "AST_DOCUMENT_NODE";
2851
+ }
2852
+ /**
2853
+ * Checks if a node is a LiteralNode
2854
+ */
2855
+ function isLiteralNode(node) {
2856
+ return node instanceof LiteralNode || node.type === "AST_LITERAL_NODE" || node.constructor.type === "AST_LITERAL_NODE";
2857
+ }
2858
+ /**
2859
+ * Checks if a node is a HTMLOpenTagNode
2860
+ */
2861
+ function isHTMLOpenTagNode(node) {
2862
+ return node instanceof HTMLOpenTagNode || node.type === "AST_HTML_OPEN_TAG_NODE" || node.constructor.type === "AST_HTML_OPEN_TAG_NODE";
2863
+ }
2864
+ /**
2865
+ * Checks if a node is a HTMLCloseTagNode
2866
+ */
2867
+ function isHTMLCloseTagNode(node) {
2868
+ return node instanceof HTMLCloseTagNode || node.type === "AST_HTML_CLOSE_TAG_NODE" || node.constructor.type === "AST_HTML_CLOSE_TAG_NODE";
2869
+ }
2870
+ /**
2871
+ * Checks if a node is a HTMLElementNode
2872
+ */
2873
+ function isHTMLElementNode(node) {
2874
+ return node instanceof HTMLElementNode || node.type === "AST_HTML_ELEMENT_NODE" || node.constructor.type === "AST_HTML_ELEMENT_NODE";
2875
+ }
2876
+ /**
2877
+ * Checks if a node is a HTMLAttributeValueNode
2878
+ */
2879
+ function isHTMLAttributeValueNode(node) {
2880
+ return node instanceof HTMLAttributeValueNode || node.type === "AST_HTML_ATTRIBUTE_VALUE_NODE" || node.constructor.type === "AST_HTML_ATTRIBUTE_VALUE_NODE";
2881
+ }
2882
+ /**
2883
+ * Checks if a node is a HTMLAttributeNameNode
2884
+ */
2885
+ function isHTMLAttributeNameNode(node) {
2886
+ return node instanceof HTMLAttributeNameNode || node.type === "AST_HTML_ATTRIBUTE_NAME_NODE" || node.constructor.type === "AST_HTML_ATTRIBUTE_NAME_NODE";
2887
+ }
2888
+ /**
2889
+ * Checks if a node is a HTMLAttributeNode
2890
+ */
2891
+ function isHTMLAttributeNode(node) {
2892
+ return node instanceof HTMLAttributeNode || node.type === "AST_HTML_ATTRIBUTE_NODE" || node.constructor.type === "AST_HTML_ATTRIBUTE_NODE";
2893
+ }
2894
+ /**
2895
+ * Checks if a node is a HTMLTextNode
2896
+ */
2897
+ function isHTMLTextNode(node) {
2898
+ return node instanceof HTMLTextNode || node.type === "AST_HTML_TEXT_NODE" || node.constructor.type === "AST_HTML_TEXT_NODE";
2899
+ }
2900
+ /**
2901
+ * Checks if a node is a HTMLCommentNode
2902
+ */
2903
+ function isHTMLCommentNode(node) {
2904
+ return node instanceof HTMLCommentNode || node.type === "AST_HTML_COMMENT_NODE" || node.constructor.type === "AST_HTML_COMMENT_NODE";
2905
+ }
2906
+ /**
2907
+ * Checks if a node is a HTMLDoctypeNode
2908
+ */
2909
+ function isHTMLDoctypeNode(node) {
2910
+ return node instanceof HTMLDoctypeNode || node.type === "AST_HTML_DOCTYPE_NODE" || node.constructor.type === "AST_HTML_DOCTYPE_NODE";
2911
+ }
2912
+ /**
2913
+ * Checks if a node is a XMLDeclarationNode
2914
+ */
2915
+ function isXMLDeclarationNode(node) {
2916
+ return node instanceof XMLDeclarationNode || node.type === "AST_XML_DECLARATION_NODE" || node.constructor.type === "AST_XML_DECLARATION_NODE";
2917
+ }
2918
+ /**
2919
+ * Checks if a node is a CDATANode
2920
+ */
2921
+ function isCDATANode(node) {
2922
+ return node instanceof CDATANode || node.type === "AST_CDATA_NODE" || node.constructor.type === "AST_CDATA_NODE";
2923
+ }
2924
+ /**
2925
+ * Checks if a node is a WhitespaceNode
2926
+ */
2927
+ function isWhitespaceNode(node) {
2928
+ return node instanceof WhitespaceNode || node.type === "AST_WHITESPACE_NODE" || node.constructor.type === "AST_WHITESPACE_NODE";
2929
+ }
2930
+ /**
2931
+ * Checks if a node is a ERBContentNode
2932
+ */
2933
+ function isERBContentNode(node) {
2934
+ return node instanceof ERBContentNode || node.type === "AST_ERB_CONTENT_NODE" || node.constructor.type === "AST_ERB_CONTENT_NODE";
2935
+ }
2936
+ /**
2937
+ * Checks if a node is a ERBEndNode
2938
+ */
2939
+ function isERBEndNode(node) {
2940
+ return node instanceof ERBEndNode || node.type === "AST_ERB_END_NODE" || node.constructor.type === "AST_ERB_END_NODE";
2941
+ }
2942
+ /**
2943
+ * Checks if a node is a ERBElseNode
2944
+ */
2945
+ function isERBElseNode(node) {
2946
+ return node instanceof ERBElseNode || node.type === "AST_ERB_ELSE_NODE" || node.constructor.type === "AST_ERB_ELSE_NODE";
2947
+ }
2948
+ /**
2949
+ * Checks if a node is a ERBIfNode
2950
+ */
2951
+ function isERBIfNode(node) {
2952
+ return node instanceof ERBIfNode || node.type === "AST_ERB_IF_NODE" || node.constructor.type === "AST_ERB_IF_NODE";
2953
+ }
2954
+ /**
2955
+ * Checks if a node is a ERBBlockNode
2956
+ */
2957
+ function isERBBlockNode(node) {
2958
+ return node instanceof ERBBlockNode || node.type === "AST_ERB_BLOCK_NODE" || node.constructor.type === "AST_ERB_BLOCK_NODE";
2959
+ }
2960
+ /**
2961
+ * Checks if a node is a ERBWhenNode
2962
+ */
2963
+ function isERBWhenNode(node) {
2964
+ return node instanceof ERBWhenNode || node.type === "AST_ERB_WHEN_NODE" || node.constructor.type === "AST_ERB_WHEN_NODE";
2965
+ }
2966
+ /**
2967
+ * Checks if a node is a ERBCaseNode
2968
+ */
2969
+ function isERBCaseNode(node) {
2970
+ return node instanceof ERBCaseNode || node.type === "AST_ERB_CASE_NODE" || node.constructor.type === "AST_ERB_CASE_NODE";
2971
+ }
2972
+ /**
2973
+ * Checks if a node is a ERBCaseMatchNode
2974
+ */
2975
+ function isERBCaseMatchNode(node) {
2976
+ return node instanceof ERBCaseMatchNode || node.type === "AST_ERB_CASE_MATCH_NODE" || node.constructor.type === "AST_ERB_CASE_MATCH_NODE";
2977
+ }
2978
+ /**
2979
+ * Checks if a node is a ERBWhileNode
2980
+ */
2981
+ function isERBWhileNode(node) {
2982
+ return node instanceof ERBWhileNode || node.type === "AST_ERB_WHILE_NODE" || node.constructor.type === "AST_ERB_WHILE_NODE";
2983
+ }
2984
+ /**
2985
+ * Checks if a node is a ERBUntilNode
2986
+ */
2987
+ function isERBUntilNode(node) {
2988
+ return node instanceof ERBUntilNode || node.type === "AST_ERB_UNTIL_NODE" || node.constructor.type === "AST_ERB_UNTIL_NODE";
2989
+ }
2990
+ /**
2991
+ * Checks if a node is a ERBForNode
2992
+ */
2993
+ function isERBForNode(node) {
2994
+ return node instanceof ERBForNode || node.type === "AST_ERB_FOR_NODE" || node.constructor.type === "AST_ERB_FOR_NODE";
2995
+ }
2996
+ /**
2997
+ * Checks if a node is a ERBRescueNode
2998
+ */
2999
+ function isERBRescueNode(node) {
3000
+ return node instanceof ERBRescueNode || node.type === "AST_ERB_RESCUE_NODE" || node.constructor.type === "AST_ERB_RESCUE_NODE";
3001
+ }
3002
+ /**
3003
+ * Checks if a node is a ERBEnsureNode
3004
+ */
3005
+ function isERBEnsureNode(node) {
3006
+ return node instanceof ERBEnsureNode || node.type === "AST_ERB_ENSURE_NODE" || node.constructor.type === "AST_ERB_ENSURE_NODE";
3007
+ }
3008
+ /**
3009
+ * Checks if a node is a ERBBeginNode
3010
+ */
3011
+ function isERBBeginNode(node) {
3012
+ return node instanceof ERBBeginNode || node.type === "AST_ERB_BEGIN_NODE" || node.constructor.type === "AST_ERB_BEGIN_NODE";
3013
+ }
3014
+ /**
3015
+ * Checks if a node is a ERBUnlessNode
3016
+ */
3017
+ function isERBUnlessNode(node) {
3018
+ return node instanceof ERBUnlessNode || node.type === "AST_ERB_UNLESS_NODE" || node.constructor.type === "AST_ERB_UNLESS_NODE";
3019
+ }
3020
+ /**
3021
+ * Checks if a node is a ERBYieldNode
3022
+ */
3023
+ function isERBYieldNode(node) {
3024
+ return node instanceof ERBYieldNode || node.type === "AST_ERB_YIELD_NODE" || node.constructor.type === "AST_ERB_YIELD_NODE";
3025
+ }
3026
+ /**
3027
+ * Checks if a node is a ERBInNode
3028
+ */
3029
+ function isERBInNode(node) {
3030
+ return node instanceof ERBInNode || node.type === "AST_ERB_IN_NODE" || node.constructor.type === "AST_ERB_IN_NODE";
3031
+ }
3032
+ /**
3033
+ * Convenience type guards for common node categories
3034
+ */
3035
+ /**
3036
+ * Checks if a node is any HTML node type
3037
+ */
3038
+ function isHTMLNode(node) {
3039
+ return isHTMLOpenTagNode(node) ||
3040
+ isHTMLCloseTagNode(node) ||
3041
+ isHTMLElementNode(node) ||
3042
+ isHTMLAttributeValueNode(node) ||
3043
+ isHTMLAttributeNameNode(node) ||
3044
+ isHTMLAttributeNode(node) ||
3045
+ isHTMLTextNode(node) ||
3046
+ isHTMLCommentNode(node) ||
3047
+ isHTMLDoctypeNode(node);
3048
+ }
3049
+ /**
3050
+ * Checks if a node is any ERB node type
3051
+ */
3052
+ function isERBNode(node) {
3053
+ return isERBContentNode(node) ||
3054
+ isERBEndNode(node) ||
3055
+ isERBElseNode(node) ||
3056
+ isERBIfNode(node) ||
3057
+ isERBBlockNode(node) ||
3058
+ isERBWhenNode(node) ||
3059
+ isERBCaseNode(node) ||
3060
+ isERBCaseMatchNode(node) ||
3061
+ isERBWhileNode(node) ||
3062
+ isERBUntilNode(node) ||
3063
+ isERBForNode(node) ||
3064
+ isERBRescueNode(node) ||
3065
+ isERBEnsureNode(node) ||
3066
+ isERBBeginNode(node) ||
3067
+ isERBUnlessNode(node) ||
3068
+ isERBYieldNode(node) ||
3069
+ isERBInNode(node);
3070
+ }
3071
+ /**
3072
+ * Map of node classes to their corresponding type guard functions
3073
+ *
3074
+ * @example
3075
+ * const guard = NODE_TYPE_GUARDS[HTMLTextNode]
3076
+ *
3077
+ * if (guard(node)) {
3078
+ * // node is HTMLTextNode
3079
+ * }
3080
+ */
3081
+ const NODE_TYPE_GUARDS = new Map([
3082
+ [DocumentNode, isDocumentNode],
3083
+ [LiteralNode, isLiteralNode],
3084
+ [HTMLOpenTagNode, isHTMLOpenTagNode],
3085
+ [HTMLCloseTagNode, isHTMLCloseTagNode],
3086
+ [HTMLElementNode, isHTMLElementNode],
3087
+ [HTMLAttributeValueNode, isHTMLAttributeValueNode],
3088
+ [HTMLAttributeNameNode, isHTMLAttributeNameNode],
3089
+ [HTMLAttributeNode, isHTMLAttributeNode],
3090
+ [HTMLTextNode, isHTMLTextNode],
3091
+ [HTMLCommentNode, isHTMLCommentNode],
3092
+ [HTMLDoctypeNode, isHTMLDoctypeNode],
3093
+ [XMLDeclarationNode, isXMLDeclarationNode],
3094
+ [CDATANode, isCDATANode],
3095
+ [WhitespaceNode, isWhitespaceNode],
3096
+ [ERBContentNode, isERBContentNode],
3097
+ [ERBEndNode, isERBEndNode],
3098
+ [ERBElseNode, isERBElseNode],
3099
+ [ERBIfNode, isERBIfNode],
3100
+ [ERBBlockNode, isERBBlockNode],
3101
+ [ERBWhenNode, isERBWhenNode],
3102
+ [ERBCaseNode, isERBCaseNode],
3103
+ [ERBCaseMatchNode, isERBCaseMatchNode],
3104
+ [ERBWhileNode, isERBWhileNode],
3105
+ [ERBUntilNode, isERBUntilNode],
3106
+ [ERBForNode, isERBForNode],
3107
+ [ERBRescueNode, isERBRescueNode],
3108
+ [ERBEnsureNode, isERBEnsureNode],
3109
+ [ERBBeginNode, isERBBeginNode],
3110
+ [ERBUnlessNode, isERBUnlessNode],
3111
+ [ERBYieldNode, isERBYieldNode],
3112
+ [ERBInNode, isERBInNode],
3113
+ ]);
3114
+ /**
3115
+ * Map of AST node type strings to their corresponding type guard functions
3116
+ *
3117
+ * @example
3118
+ * const guard = AST_TYPE_GUARDS["AST_HTML_TEXT_NODE"]
3119
+ *
3120
+ * if (guard(node)) {
3121
+ * // node is HTMLTextNode
3122
+ * }
3123
+ */
3124
+ const AST_TYPE_GUARDS = new Map([
3125
+ ["AST_DOCUMENT_NODE", isDocumentNode],
3126
+ ["AST_LITERAL_NODE", isLiteralNode],
3127
+ ["AST_HTML_OPEN_TAG_NODE", isHTMLOpenTagNode],
3128
+ ["AST_HTML_CLOSE_TAG_NODE", isHTMLCloseTagNode],
3129
+ ["AST_HTML_ELEMENT_NODE", isHTMLElementNode],
3130
+ ["AST_HTML_ATTRIBUTE_VALUE_NODE", isHTMLAttributeValueNode],
3131
+ ["AST_HTML_ATTRIBUTE_NAME_NODE", isHTMLAttributeNameNode],
3132
+ ["AST_HTML_ATTRIBUTE_NODE", isHTMLAttributeNode],
3133
+ ["AST_HTML_TEXT_NODE", isHTMLTextNode],
3134
+ ["AST_HTML_COMMENT_NODE", isHTMLCommentNode],
3135
+ ["AST_HTML_DOCTYPE_NODE", isHTMLDoctypeNode],
3136
+ ["AST_XML_DECLARATION_NODE", isXMLDeclarationNode],
3137
+ ["AST_CDATA_NODE", isCDATANode],
3138
+ ["AST_WHITESPACE_NODE", isWhitespaceNode],
3139
+ ["AST_ERB_CONTENT_NODE", isERBContentNode],
3140
+ ["AST_ERB_END_NODE", isERBEndNode],
3141
+ ["AST_ERB_ELSE_NODE", isERBElseNode],
3142
+ ["AST_ERB_IF_NODE", isERBIfNode],
3143
+ ["AST_ERB_BLOCK_NODE", isERBBlockNode],
3144
+ ["AST_ERB_WHEN_NODE", isERBWhenNode],
3145
+ ["AST_ERB_CASE_NODE", isERBCaseNode],
3146
+ ["AST_ERB_CASE_MATCH_NODE", isERBCaseMatchNode],
3147
+ ["AST_ERB_WHILE_NODE", isERBWhileNode],
3148
+ ["AST_ERB_UNTIL_NODE", isERBUntilNode],
3149
+ ["AST_ERB_FOR_NODE", isERBForNode],
3150
+ ["AST_ERB_RESCUE_NODE", isERBRescueNode],
3151
+ ["AST_ERB_ENSURE_NODE", isERBEnsureNode],
3152
+ ["AST_ERB_BEGIN_NODE", isERBBeginNode],
3153
+ ["AST_ERB_UNLESS_NODE", isERBUnlessNode],
3154
+ ["AST_ERB_YIELD_NODE", isERBYieldNode],
3155
+ ["AST_ERB_IN_NODE", isERBInNode],
3156
+ ]);
3157
+ /**
3158
+ * Checks if a node matches any of the provided type identifiers with proper type narrowing
3159
+ * Supports AST type strings, node classes, or type guard functions
3160
+ *
3161
+ * @example
3162
+ * if (isAnyOf(node, "AST_HTML_TEXT_NODE", "AST_LITERAL_NODE")) {
3163
+ * // node is narrowed to HTMLTextNode | LiteralNode
3164
+ * }
3165
+ *
3166
+ * @example
3167
+ * if (isAnyOf(node, HTMLTextNode, LiteralNode)) {
3168
+ * // node is narrowed to HTMLTextNode | LiteralNode
3169
+ * }
3170
+ */
3171
+ function isAnyOf(node, ...types) {
3172
+ return types.some(type => {
3173
+ if (typeof type === 'string') {
3174
+ return isNode(node, type);
3175
+ }
3176
+ else if (typeof type === 'function' && type.prototype && type.prototype.constructor === type && NODE_TYPE_GUARDS.has(type)) {
3177
+ return isNode(node, type);
3178
+ }
3179
+ else if (typeof type === 'function') {
3180
+ return type(node);
3181
+ }
3182
+ else {
3183
+ return false;
3184
+ }
3185
+ });
3186
+ }
3187
+ /**
3188
+ * Checks if a node does NOT match any of the provided type identifiers
3189
+ * Supports AST type strings, node classes, or type guard functions
3190
+ * This is the logical inverse of isAnyOf
3191
+ *
3192
+ * @example
3193
+ * if (isNoneOf(node, "AST_HTML_TEXT_NODE", "AST_LITERAL_NODE")) {
3194
+ * // node is neither HTMLTextNode nor LiteralNode
3195
+ * }
3196
+ *
3197
+ * @example
3198
+ * if (isNoneOf(node, HTMLTextNode, LiteralNode)) {
3199
+ * // node is neither HTMLTextNode nor LiteralNode
3200
+ * }
3201
+ *
3202
+ * @example
3203
+ * if (isNoneOf(node, isHTMLTextNode, isLiteralNode)) {
3204
+ * // node is neither HTMLTextNode nor LiteralNode
3205
+ * }
3206
+ */
3207
+ function isNoneOf(node, ...types) {
3208
+ return !isAnyOf(node, ...types);
3209
+ }
3210
+ function areAllOfType(nodes, ...types) {
3211
+ return nodes.every(node => isAnyOf(node, ...types));
3212
+ }
3213
+ function filterNodes(nodes, ...types) {
3214
+ if (!nodes)
3215
+ return [];
3216
+ return nodes.filter(node => isAnyOf(node, ...types));
3217
+ }
3218
+ function isNode(node, type) {
3219
+ if (!node)
3220
+ return false;
3221
+ if (typeof type === 'string') {
3222
+ const guard = AST_TYPE_GUARDS.get(type);
3223
+ return guard ? guard(node) : false;
3224
+ }
3225
+ else if (typeof type === 'function') {
3226
+ const guard = NODE_TYPE_GUARDS.get(type);
3227
+ return guard ? guard(node) : false;
3228
+ }
3229
+ else {
3230
+ return false;
3231
+ }
3232
+ }
3233
+ function isToken(object) {
3234
+ return (object instanceof Token) || (object?.constructor?.name === "Token" && "value" in object) || object.type?.startsWith('TOKEN_');
3235
+ }
3236
+ function isParseResult(object) {
3237
+ return (object instanceof ParseResult) || (object?.constructor?.name === "ParseResult" && "value" in object);
3238
+ }
3239
+ /**
3240
+ * Checks if a node has children (contains other nodes)
3241
+ */
3242
+ function hasChildren(node) {
3243
+ return isDocumentNode(node) ||
3244
+ isHTMLOpenTagNode(node) ||
3245
+ isHTMLCloseTagNode(node) ||
3246
+ isHTMLElementNode(node) ||
3247
+ isHTMLAttributeValueNode(node) ||
3248
+ isHTMLAttributeNameNode(node) ||
3249
+ isHTMLCommentNode(node) ||
3250
+ isHTMLDoctypeNode(node) ||
3251
+ isERBElseNode(node) ||
3252
+ isERBIfNode(node) ||
3253
+ isERBBlockNode(node) ||
3254
+ isERBWhenNode(node) ||
3255
+ isERBCaseNode(node) ||
3256
+ isERBCaseMatchNode(node) ||
3257
+ isERBWhileNode(node) ||
3258
+ isERBUntilNode(node) ||
3259
+ isERBForNode(node) ||
3260
+ isERBRescueNode(node) ||
3261
+ isERBEnsureNode(node) ||
3262
+ isERBBeginNode(node) ||
3263
+ isERBUnlessNode(node) ||
3264
+ isERBInNode(node);
3265
+ }
3266
+ /**
3267
+ * Filter functions for extracting specific node types from arrays
3268
+ */
3269
+ /**
3270
+ * Filters an array of nodes to only include DocumentNode nodes
3271
+ */
3272
+ function filterDocumentNodes(nodes) {
3273
+ return nodes.filter(isDocumentNode);
3274
+ }
3275
+ /**
3276
+ * Filters an array of nodes to only include LiteralNode nodes
3277
+ */
3278
+ function filterLiteralNodes(nodes) {
3279
+ return nodes.filter(isLiteralNode);
3280
+ }
3281
+ /**
3282
+ * Filters an array of nodes to only include HTMLOpenTagNode nodes
3283
+ */
3284
+ function filterHTMLOpenTagNodes(nodes) {
3285
+ return nodes.filter(isHTMLOpenTagNode);
3286
+ }
3287
+ /**
3288
+ * Filters an array of nodes to only include HTMLCloseTagNode nodes
3289
+ */
3290
+ function filterHTMLCloseTagNodes(nodes) {
3291
+ return nodes.filter(isHTMLCloseTagNode);
3292
+ }
3293
+ /**
3294
+ * Filters an array of nodes to only include HTMLElementNode nodes
3295
+ */
3296
+ function filterHTMLElementNodes(nodes) {
3297
+ return nodes.filter(isHTMLElementNode);
3298
+ }
3299
+ /**
3300
+ * Filters an array of nodes to only include HTMLAttributeValueNode nodes
3301
+ */
3302
+ function filterHTMLAttributeValueNodes(nodes) {
3303
+ return nodes.filter(isHTMLAttributeValueNode);
3304
+ }
3305
+ /**
3306
+ * Filters an array of nodes to only include HTMLAttributeNameNode nodes
3307
+ */
3308
+ function filterHTMLAttributeNameNodes(nodes) {
3309
+ return nodes.filter(isHTMLAttributeNameNode);
3310
+ }
3311
+ /**
3312
+ * Filters an array of nodes to only include HTMLAttributeNode nodes
3313
+ */
3314
+ function filterHTMLAttributeNodes(nodes) {
3315
+ return nodes.filter(isHTMLAttributeNode);
3316
+ }
3317
+ /**
3318
+ * Filters an array of nodes to only include HTMLTextNode nodes
3319
+ */
3320
+ function filterHTMLTextNodes(nodes) {
3321
+ return nodes.filter(isHTMLTextNode);
3322
+ }
3323
+ /**
3324
+ * Filters an array of nodes to only include HTMLCommentNode nodes
3325
+ */
3326
+ function filterHTMLCommentNodes(nodes) {
3327
+ return nodes.filter(isHTMLCommentNode);
3328
+ }
3329
+ /**
3330
+ * Filters an array of nodes to only include HTMLDoctypeNode nodes
3331
+ */
3332
+ function filterHTMLDoctypeNodes(nodes) {
3333
+ return nodes.filter(isHTMLDoctypeNode);
3334
+ }
3335
+ /**
3336
+ * Filters an array of nodes to only include XMLDeclarationNode nodes
3337
+ */
3338
+ function filterXMLDeclarationNodes(nodes) {
3339
+ return nodes.filter(isXMLDeclarationNode);
3340
+ }
3341
+ /**
3342
+ * Filters an array of nodes to only include CDATANode nodes
3343
+ */
3344
+ function filterCDATANodes(nodes) {
3345
+ return nodes.filter(isCDATANode);
3346
+ }
3347
+ /**
3348
+ * Filters an array of nodes to only include WhitespaceNode nodes
3349
+ */
3350
+ function filterWhitespaceNodes(nodes) {
3351
+ return nodes.filter(isWhitespaceNode);
3352
+ }
3353
+ /**
3354
+ * Filters an array of nodes to only include ERBContentNode nodes
3355
+ */
3356
+ function filterERBContentNodes(nodes) {
3357
+ return nodes.filter(isERBContentNode);
3358
+ }
3359
+ /**
3360
+ * Filters an array of nodes to only include ERBEndNode nodes
3361
+ */
3362
+ function filterERBEndNodes(nodes) {
3363
+ return nodes.filter(isERBEndNode);
3364
+ }
3365
+ /**
3366
+ * Filters an array of nodes to only include ERBElseNode nodes
3367
+ */
3368
+ function filterERBElseNodes(nodes) {
3369
+ return nodes.filter(isERBElseNode);
3370
+ }
3371
+ /**
3372
+ * Filters an array of nodes to only include ERBIfNode nodes
3373
+ */
3374
+ function filterERBIfNodes(nodes) {
3375
+ return nodes.filter(isERBIfNode);
3376
+ }
3377
+ /**
3378
+ * Filters an array of nodes to only include ERBBlockNode nodes
3379
+ */
3380
+ function filterERBBlockNodes(nodes) {
3381
+ return nodes.filter(isERBBlockNode);
3382
+ }
3383
+ /**
3384
+ * Filters an array of nodes to only include ERBWhenNode nodes
3385
+ */
3386
+ function filterERBWhenNodes(nodes) {
3387
+ return nodes.filter(isERBWhenNode);
3388
+ }
3389
+ /**
3390
+ * Filters an array of nodes to only include ERBCaseNode nodes
3391
+ */
3392
+ function filterERBCaseNodes(nodes) {
3393
+ return nodes.filter(isERBCaseNode);
3394
+ }
3395
+ /**
3396
+ * Filters an array of nodes to only include ERBCaseMatchNode nodes
3397
+ */
3398
+ function filterERBCaseMatchNodes(nodes) {
3399
+ return nodes.filter(isERBCaseMatchNode);
3400
+ }
3401
+ /**
3402
+ * Filters an array of nodes to only include ERBWhileNode nodes
3403
+ */
3404
+ function filterERBWhileNodes(nodes) {
3405
+ return nodes.filter(isERBWhileNode);
3406
+ }
3407
+ /**
3408
+ * Filters an array of nodes to only include ERBUntilNode nodes
3409
+ */
3410
+ function filterERBUntilNodes(nodes) {
3411
+ return nodes.filter(isERBUntilNode);
3412
+ }
3413
+ /**
3414
+ * Filters an array of nodes to only include ERBForNode nodes
3415
+ */
3416
+ function filterERBForNodes(nodes) {
3417
+ return nodes.filter(isERBForNode);
3418
+ }
3419
+ /**
3420
+ * Filters an array of nodes to only include ERBRescueNode nodes
3421
+ */
3422
+ function filterERBRescueNodes(nodes) {
3423
+ return nodes.filter(isERBRescueNode);
3424
+ }
3425
+ /**
3426
+ * Filters an array of nodes to only include ERBEnsureNode nodes
3427
+ */
3428
+ function filterERBEnsureNodes(nodes) {
3429
+ return nodes.filter(isERBEnsureNode);
3430
+ }
3431
+ /**
3432
+ * Filters an array of nodes to only include ERBBeginNode nodes
3433
+ */
3434
+ function filterERBBeginNodes(nodes) {
3435
+ return nodes.filter(isERBBeginNode);
3436
+ }
3437
+ /**
3438
+ * Filters an array of nodes to only include ERBUnlessNode nodes
3439
+ */
3440
+ function filterERBUnlessNodes(nodes) {
3441
+ return nodes.filter(isERBUnlessNode);
3442
+ }
3443
+ /**
3444
+ * Filters an array of nodes to only include ERBYieldNode nodes
3445
+ */
3446
+ function filterERBYieldNodes(nodes) {
3447
+ return nodes.filter(isERBYieldNode);
3448
+ }
3449
+ /**
3450
+ * Filters an array of nodes to only include ERBInNode nodes
3451
+ */
3452
+ function filterERBInNodes(nodes) {
3453
+ return nodes.filter(isERBInNode);
3454
+ }
3455
+
3456
+ /**
3457
+ * Checks if a node is an ERB output node (generates content: <%= %> or <%== %>)
3458
+ */
3459
+ function isERBOutputNode(node) {
3460
+ return isNode(node, ERBContentNode) && ["<%=", "<%=="].includes(node.tag_opening?.value);
3461
+ }
3462
+ /**
3463
+ * Checks if a node is a non-output ERB node (control flow: <% %>)
3464
+ */
3465
+ function isERBControlFlowNode(node) {
3466
+ return isAnyOf(node, ERBIfNode, ERBUnlessNode, ERBBlockNode, ERBCaseNode, ERBCaseMatchNode, ERBWhileNode, ERBForNode, ERBBeginNode);
3467
+ }
3468
+ /**
3469
+ * Checks if an array of nodes contains any ERB content nodes
3470
+ */
3471
+ function hasERBContent(nodes) {
3472
+ return nodes.some(isERBContentNode);
3473
+ }
3474
+ /**
3475
+ * Checks if an array of nodes contains any ERB output nodes (dynamic content)
3476
+ */
3477
+ function hasERBOutput(nodes) {
3478
+ return nodes.some(isERBOutputNode);
3479
+ }
3480
+ /**
3481
+ * Extracts a static string from an array of literal nodes
3482
+ * Returns null if any node is not a literal node
3483
+ */
3484
+ function getStaticStringFromNodes(nodes) {
3485
+ if (!areAllOfType(nodes, LiteralNode)) {
3486
+ return null;
3487
+ }
3488
+ return nodes.map(node => node.content).join("");
3489
+ }
3490
+ /**
3491
+ * Extracts static content from nodes, including mixed literal/ERB content
3492
+ * Returns the concatenated literal content, or null if no literal nodes exist
3493
+ */
3494
+ function getStaticContentFromNodes(nodes) {
3495
+ const literalNodes = filterLiteralNodes(nodes);
3496
+ if (literalNodes.length === 0) {
3497
+ return null;
3498
+ }
3499
+ return literalNodes.map(node => node.content).join("");
3500
+ }
3501
+ /**
3502
+ * Checks if nodes contain any literal content (for static validation)
3503
+ */
3504
+ function hasStaticContent(nodes) {
3505
+ return nodes.some(isLiteralNode);
3506
+ }
3507
+ /**
3508
+ * Checks if nodes are effectively static (only literals and non-output ERB)
3509
+ * Non-output ERB like <% if %> doesn't affect static validation
3510
+ */
3511
+ function isEffectivelyStatic(nodes) {
3512
+ return !hasERBOutput(nodes);
3513
+ }
3514
+ /**
3515
+ * Gets static-validatable content from nodes (ignores control ERB, includes literals)
3516
+ * Returns concatenated literal content for validation, or null if contains output ERB
3517
+ */
3518
+ function getValidatableStaticContent(nodes) {
3519
+ if (hasERBOutput(nodes)) {
3520
+ return null;
3521
+ }
3522
+ return filterLiteralNodes(nodes).map(node => node.content).join("");
3523
+ }
3524
+ /**
3525
+ * Extracts a combined string from nodes, including ERB content
3526
+ * For ERB nodes, includes the full tag syntax (e.g., "<%= foo %>")
3527
+ * This is useful for debugging or displaying the full attribute name
3528
+ */
3529
+ function getCombinedStringFromNodes(nodes) {
3530
+ return nodes.map(node => {
3531
+ if (isLiteralNode(node)) {
3532
+ return node.content;
3533
+ }
3534
+ else if (isERBContentNode(node)) {
3535
+ const opening = node.tag_opening?.value || "";
3536
+ const content = node.content?.value || "";
3537
+ const closing = node.tag_closing?.value || "";
3538
+ return `${opening}${content}${closing}`;
3539
+ }
3540
+ else {
3541
+ // For other node types, return a placeholder or empty string
3542
+ return `[${node.type}]`;
3543
+ }
3544
+ }).join("");
3545
+ }
3546
+ /**
3547
+ * Checks if an HTML attribute name node has a static (literal-only) name
3548
+ */
3549
+ function hasStaticAttributeName(attributeNameNode) {
3550
+ if (!attributeNameNode.children) {
3551
+ return false;
3552
+ }
3553
+ return areAllOfType(attributeNameNode.children, LiteralNode);
3554
+ }
3555
+ /**
3556
+ * Checks if an HTML attribute name node has dynamic content (contains ERB)
3557
+ */
3558
+ function hasDynamicAttributeName(attributeNameNode) {
3559
+ if (!attributeNameNode.children) {
3560
+ return false;
3561
+ }
3562
+ return hasERBContent(attributeNameNode.children);
3563
+ }
3564
+ /**
3565
+ * Gets the static string value of an HTML attribute name node
3566
+ * Returns null if the attribute name contains dynamic content (ERB)
3567
+ */
3568
+ function getStaticAttributeName(attributeNameNode) {
3569
+ if (!attributeNameNode.children) {
3570
+ return null;
3571
+ }
3572
+ return getStaticStringFromNodes(attributeNameNode.children);
3573
+ }
3574
+ /**
3575
+ * Gets the combined string representation of an HTML attribute name node
3576
+ * This includes both static and dynamic content, useful for debugging
3577
+ */
3578
+ function getCombinedAttributeName(attributeNameNode) {
3579
+ if (!attributeNameNode.children) {
3580
+ return "";
3581
+ }
3582
+ return getCombinedStringFromNodes(attributeNameNode.children);
3583
+ }
3584
+ /**
3585
+ * Gets the tag name of an HTML element node
3586
+ */
3587
+ function getTagName(node) {
3588
+ return node.tag_name?.value ?? "";
3589
+ }
3590
+ /**
3591
+ * Check if a node is a comment (HTML comment or ERB comment)
3592
+ */
3593
+ function isCommentNode(node) {
3594
+ return isNode(node, HTMLCommentNode) || (isERBNode(node) && !isERBControlFlowNode(node));
3595
+ }
3596
+ /**
3597
+ * Compares two positions to determine if the first comes before the second
3598
+ * Returns true if pos1 comes before pos2 in source order
3599
+ * @param inclusive - If true, returns true when positions are equal
3600
+ */
3601
+ function isPositionBefore(position1, position2, inclusive = false) {
3602
+ if (position1.line < position2.line)
3603
+ return true;
3604
+ if (position1.line > position2.line)
3605
+ return false;
3606
+ return inclusive ? position1.column <= position2.column : position1.column < position2.column;
3607
+ }
3608
+ /**
3609
+ * Compares two positions to determine if they are equal
3610
+ * Returns true if pos1 and pos2 are at the same location
3611
+ */
3612
+ function isPositionEqual(position1, position2) {
3613
+ return position1.line === position2.line && position1.column === position2.column;
3614
+ }
3615
+ /**
3616
+ * Compares two positions to determine if the first comes after the second
3617
+ * Returns true if pos1 comes after pos2 in source order
3618
+ * @param inclusive - If true, returns true when positions are equal
3619
+ */
3620
+ function isPositionAfter(position1, position2, inclusive = false) {
3621
+ if (position1.line > position2.line)
3622
+ return true;
3623
+ if (position1.line < position2.line)
3624
+ return false;
3625
+ return inclusive ? position1.column >= position2.column : position1.column > position2.column;
3626
+ }
3627
+ /**
3628
+ * Gets nodes that appear before the specified location in source order
3629
+ * Uses line and column positions to determine ordering
3630
+ */
3631
+ function getNodesBeforeLocation(nodes, location) {
3632
+ return nodes.filter(node => node.location && isPositionBefore(node.location.end, location.start));
3633
+ }
3634
+ /**
3635
+ * Gets nodes that appear after the specified location in source order
3636
+ * Uses line and column positions to determine ordering
3637
+ */
3638
+ function getNodesAfterLocation(nodes, location) {
3639
+ return nodes.filter(node => node.location && isPositionAfter(node.location.start, location.end));
3640
+ }
3641
+ /**
3642
+ * Splits nodes into before and after the specified location
3643
+ * Returns an object with `before` and `after` arrays
3644
+ */
3645
+ function splitNodesAroundLocation(nodes, location) {
3646
+ return {
3647
+ before: getNodesBeforeLocation(nodes, location),
3648
+ after: getNodesAfterLocation(nodes, location)
3649
+ };
3650
+ }
3651
+ /**
3652
+ * Splits nodes at a specific position
3653
+ * Returns nodes that end before the position and nodes that start after the position
3654
+ * More precise than splitNodesAroundLocation as it uses a single position point
3655
+ * Uses the same defaults as the individual functions: before=exclusive, after=inclusive
3656
+ */
3657
+ function splitNodesAroundPosition(nodes, position) {
3658
+ return {
3659
+ before: getNodesBeforePosition(nodes, position), // uses default: inclusive = false
3660
+ after: getNodesAfterPosition(nodes, position) // uses default: inclusive = true
3661
+ };
3662
+ }
3663
+ /**
3664
+ * Gets nodes that end before the specified position
3665
+ * @param inclusive - If true, includes nodes that end exactly at the position (default: false, matching half-open interval semantics)
3666
+ */
3667
+ function getNodesBeforePosition(nodes, position, inclusive = false) {
3668
+ return nodes.filter(node => node.location && isPositionBefore(node.location.end, position, inclusive));
3669
+ }
3670
+ /**
3671
+ * Gets nodes that start after the specified position
3672
+ * @param inclusive - If true, includes nodes that start exactly at the position (default: true, matching typical boundary behavior)
3673
+ */
3674
+ function getNodesAfterPosition(nodes, position, inclusive = true) {
3675
+ return nodes.filter(node => node.location && isPositionAfter(node.location.start, position, inclusive));
3676
+ }
3677
+
3678
+ const expectedFunctions = [
3679
+ "parse",
3680
+ "lex",
3681
+ "parseFile",
3682
+ "lexFile",
3683
+ "extractRuby",
3684
+ "extractHTML",
3685
+ "version",
3686
+ ];
3687
+ // NOTE: This function should never be called and is only for type checking
3688
+ // so we can make sure `expectedFunctions` matches the functions defined
3689
+ // in `LibHerbBackendFunctions` and the other way around.
3690
+ //
3691
+ function _TYPECHECK() {
3692
+ const checkFunctionsExist = true;
3693
+ const checkInterfaceComplete = true;
3694
+ return { checkFunctionsExist, checkInterfaceComplete };
3695
+ }
3696
+ function isLibHerbBackend(object, libherbpath = "unknown") {
3697
+ for (const expectedFunction of expectedFunctions) {
3698
+ if (object[expectedFunction] === undefined) {
3699
+ throw new Error(`Libherb at "${libherbpath}" doesn't expose function "${expectedFunction}".`);
3700
+ }
3701
+ if (typeof object[expectedFunction] !== "function") {
3702
+ throw new Error(`Libherb at "${libherbpath}" has "${expectedFunction}" but it's not a function.`);
3703
+ }
3704
+ }
3705
+ return true;
3706
+ }
3707
+ function ensureLibHerbBackend(object, libherbpath = "unknown") {
3708
+ isLibHerbBackend(object, libherbpath);
3709
+ return object;
3710
+ }
3711
+
3712
+ /**
3713
+ * Converts a Diagnostic to Monaco/VSCode-compatible MonacoDiagnostic format
3714
+ */
3715
+ function toMonacoDiagnostic(diagnostic) {
3716
+ const { message, location } = diagnostic;
3717
+ const severity = diagnostic.severity === "hint" ? "info" : diagnostic.severity;
3718
+ return {
3719
+ line: location.start.line,
3720
+ column: location.start.column,
3721
+ endLine: location.end.line,
3722
+ endColumn: location.end.column,
3723
+ message,
3724
+ severity
3725
+ };
3726
+ }
3727
+
3728
+ var name = "@herb-tools/core";
3729
+ var version = "0.6.1";
3730
+ var packageJSON = {
3731
+ name: name,
3732
+ version: version};
3733
+
3734
+ class TokenList {
3735
+ list;
3736
+ static from(list) {
3737
+ return new TokenList(list.map((token) => Token.from(token)));
3738
+ }
3739
+ constructor(list) {
3740
+ this.list = list;
3741
+ }
3742
+ get length() {
3743
+ return this.list.length;
3744
+ }
3745
+ get tokens() {
3746
+ return this.list;
3747
+ }
3748
+ [Symbol.iterator]() {
3749
+ return this.list[Symbol.iterator]();
3750
+ }
3751
+ at(index) {
3752
+ return this.list.at(index);
3753
+ }
3754
+ forEach(callback) {
3755
+ this.list.forEach(callback);
3756
+ }
3757
+ map(callback) {
3758
+ return this.list.map(callback);
3759
+ }
3760
+ filter(predicate) {
3761
+ return this.list.filter(predicate);
3762
+ }
3763
+ __getobj__() {
3764
+ return this.list;
3765
+ }
3766
+ inspect() {
3767
+ return this.list.map((token) => token.inspect()).join("\n") + "\n";
3768
+ }
3769
+ toString() {
3770
+ return this.inspect();
3771
+ }
3772
+ }
3773
+
3774
+ /**
3775
+ * Represents the result of a lexical analysis, extending the base `Result` class.
3776
+ * It contains the token list, source code, warnings, and errors.
3777
+ */
3778
+ class LexResult extends Result {
3779
+ /** The list of tokens generated from the source code. */
3780
+ value;
3781
+ /**
3782
+ * Creates a `LexResult` instance from a serialized result.
3783
+ * @param result - The serialized lexical result containing tokens, source, warnings, and errors.
3784
+ * @returns A new `LexResult` instance.
3785
+ */
3786
+ static from(result) {
3787
+ return new LexResult(TokenList.from(result.tokens || []), result.source, result.warnings.map((warning) => HerbWarning.from(warning)), result.errors.map((error) => HerbError.from(error)));
3788
+ }
3789
+ /**
3790
+ * Constructs a new `LexResult`.
3791
+ * @param value - The list of tokens.
3792
+ * @param source - The source code that was lexed.
3793
+ * @param warnings - An array of warnings encountered during lexing.
3794
+ * @param errors - An array of errors encountered during lexing.
3795
+ */
3796
+ constructor(value, source, warnings = [], errors = []) {
3797
+ super(source, warnings, errors);
3798
+ this.value = value;
3799
+ }
3800
+ /**
3801
+ * Determines if the lexing was successful.
3802
+ * @returns `true` if there are no errors, otherwise `false`.
3803
+ */
3804
+ get successful() {
3805
+ return this.errors.length === 0;
3806
+ }
3807
+ /**
3808
+ * Determines if the lexing failed.
3809
+ * @returns `true` if there are errors, otherwise `false`.
3810
+ */
3811
+ get failed() {
3812
+ return this.errors.length > 0;
3813
+ }
3814
+ /**
3815
+ * Converts the `LexResult` to a JSON representation.
3816
+ * @returns An object containing the token list, source, warnings, and errors.
3817
+ */
3818
+ toJSON() {
3819
+ return {
3820
+ value: this.value,
3821
+ source: this.source,
3822
+ warnings: this.warnings,
3823
+ errors: this.errors,
3824
+ };
3825
+ }
3826
+ }
3827
+
3828
+ const DEFAULT_PARSER_OPTIONS = {
3829
+ track_whitespace: false,
3830
+ };
3831
+
3832
+ /**
3833
+ * The main Herb parser interface, providing methods to lex and parse input.
3834
+ */
3835
+ class HerbBackend {
3836
+ /** The backend instance handling lexing and parsing. */
3837
+ backend = undefined;
3838
+ backendPromise;
3839
+ /**
3840
+ * Creates a new Herb instance.
3841
+ * @param backendPromise - A promise resolving to a `LibHerbBackend` implementation for lexing and parsing.
3842
+ * @throws Error if no valid backend is provided.
3843
+ */
3844
+ constructor(backendPromise) {
3845
+ if (!backendPromise) {
3846
+ throw new Error("No LibHerb backend provided");
3847
+ }
3848
+ this.backendPromise = backendPromise;
2878
3849
  }
2879
3850
  /**
2880
3851
  * Loads the backend by resolving the backend promise.
@@ -2908,12 +3879,14 @@ class HerbBackend {
2908
3879
  /**
2909
3880
  * Parses the given source string into a `ParseResult`.
2910
3881
  * @param source - The source code to parse.
3882
+ * @param options - Optional parsing options.
2911
3883
  * @returns A `ParseResult` instance.
2912
3884
  * @throws Error if the backend is not loaded.
2913
3885
  */
2914
- parse(source) {
3886
+ parse(source, options) {
2915
3887
  this.ensureBackend();
2916
- return ParseResult.from(this.backend.parse(ensureString(source)));
3888
+ const mergedOptions = { ...DEFAULT_PARSER_OPTIONS, ...options };
3889
+ return ParseResult.from(this.backend.parse(ensureString(source), mergedOptions));
2917
3890
  }
2918
3891
  /**
2919
3892
  * Parses a file.
@@ -2976,7 +3949,7 @@ class HerbBackend {
2976
3949
  }
2977
3950
 
2978
3951
  // NOTE: This file is generated by the templates/template.rb script and should not
2979
- // be modified manually. See /Users/marcoroth/Development/herb-release-0.5.0/templates/javascript/packages/core/src/visitor.ts.erb
3952
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.6.1/templates/javascript/packages/core/src/visitor.ts.erb
2980
3953
  class Visitor {
2981
3954
  visit(node) {
2982
3955
  if (!node)
@@ -3001,9 +3974,6 @@ class Visitor {
3001
3974
  visitHTMLCloseTagNode(node) {
3002
3975
  this.visitChildNodes(node);
3003
3976
  }
3004
- visitHTMLSelfCloseTagNode(node) {
3005
- this.visitChildNodes(node);
3006
- }
3007
3977
  visitHTMLElementNode(node) {
3008
3978
  this.visitChildNodes(node);
3009
3979
  }
@@ -3025,6 +3995,12 @@ class Visitor {
3025
3995
  visitHTMLDoctypeNode(node) {
3026
3996
  this.visitChildNodes(node);
3027
3997
  }
3998
+ visitXMLDeclarationNode(node) {
3999
+ this.visitChildNodes(node);
4000
+ }
4001
+ visitCDATANode(node) {
4002
+ this.visitChildNodes(node);
4003
+ }
3028
4004
  visitWhitespaceNode(node) {
3029
4005
  this.visitChildNodes(node);
3030
4006
  }
@@ -3081,6 +4057,9 @@ class Visitor {
3081
4057
  }
3082
4058
  }
3083
4059
 
4060
+ exports.AST_TYPE_GUARDS = AST_TYPE_GUARDS;
4061
+ exports.CDATANode = CDATANode;
4062
+ exports.DEFAULT_PARSER_OPTIONS = DEFAULT_PARSER_OPTIONS;
3084
4063
  exports.DocumentNode = DocumentNode;
3085
4064
  exports.ERBBeginNode = ERBBeginNode;
3086
4065
  exports.ERBBlockNode = ERBBlockNode;
@@ -3108,7 +4087,6 @@ exports.HTMLCommentNode = HTMLCommentNode;
3108
4087
  exports.HTMLDoctypeNode = HTMLDoctypeNode;
3109
4088
  exports.HTMLElementNode = HTMLElementNode;
3110
4089
  exports.HTMLOpenTagNode = HTMLOpenTagNode;
3111
- exports.HTMLSelfCloseTagNode = HTMLSelfCloseTagNode;
3112
4090
  exports.HTMLTextNode = HTMLTextNode;
3113
4091
  exports.HerbBackend = HerbBackend;
3114
4092
  exports.HerbError = HerbError;
@@ -3118,6 +4096,7 @@ exports.LiteralNode = LiteralNode;
3118
4096
  exports.Location = Location;
3119
4097
  exports.MissingClosingTagError = MissingClosingTagError;
3120
4098
  exports.MissingOpeningTagError = MissingOpeningTagError;
4099
+ exports.NODE_TYPE_GUARDS = NODE_TYPE_GUARDS;
3121
4100
  exports.Node = Node;
3122
4101
  exports.ParseResult = ParseResult;
3123
4102
  exports.Position = Position;
@@ -3134,13 +4113,109 @@ exports.UnexpectedTokenError = UnexpectedTokenError;
3134
4113
  exports.Visitor = Visitor;
3135
4114
  exports.VoidElementClosingTagError = VoidElementClosingTagError;
3136
4115
  exports.WhitespaceNode = WhitespaceNode;
4116
+ exports.XMLDeclarationNode = XMLDeclarationNode;
3137
4117
  exports._TYPECHECK = _TYPECHECK;
4118
+ exports.areAllOfType = areAllOfType;
3138
4119
  exports.convertToUTF8 = convertToUTF8;
3139
4120
  exports.ensureLibHerbBackend = ensureLibHerbBackend;
3140
4121
  exports.ensureString = ensureString;
4122
+ exports.filterCDATANodes = filterCDATANodes;
4123
+ exports.filterDocumentNodes = filterDocumentNodes;
4124
+ exports.filterERBBeginNodes = filterERBBeginNodes;
4125
+ exports.filterERBBlockNodes = filterERBBlockNodes;
4126
+ exports.filterERBCaseMatchNodes = filterERBCaseMatchNodes;
4127
+ exports.filterERBCaseNodes = filterERBCaseNodes;
4128
+ exports.filterERBContentNodes = filterERBContentNodes;
4129
+ exports.filterERBElseNodes = filterERBElseNodes;
4130
+ exports.filterERBEndNodes = filterERBEndNodes;
4131
+ exports.filterERBEnsureNodes = filterERBEnsureNodes;
4132
+ exports.filterERBForNodes = filterERBForNodes;
4133
+ exports.filterERBIfNodes = filterERBIfNodes;
4134
+ exports.filterERBInNodes = filterERBInNodes;
4135
+ exports.filterERBRescueNodes = filterERBRescueNodes;
4136
+ exports.filterERBUnlessNodes = filterERBUnlessNodes;
4137
+ exports.filterERBUntilNodes = filterERBUntilNodes;
4138
+ exports.filterERBWhenNodes = filterERBWhenNodes;
4139
+ exports.filterERBWhileNodes = filterERBWhileNodes;
4140
+ exports.filterERBYieldNodes = filterERBYieldNodes;
4141
+ exports.filterHTMLAttributeNameNodes = filterHTMLAttributeNameNodes;
4142
+ exports.filterHTMLAttributeNodes = filterHTMLAttributeNodes;
4143
+ exports.filterHTMLAttributeValueNodes = filterHTMLAttributeValueNodes;
4144
+ exports.filterHTMLCloseTagNodes = filterHTMLCloseTagNodes;
4145
+ exports.filterHTMLCommentNodes = filterHTMLCommentNodes;
4146
+ exports.filterHTMLDoctypeNodes = filterHTMLDoctypeNodes;
4147
+ exports.filterHTMLElementNodes = filterHTMLElementNodes;
4148
+ exports.filterHTMLOpenTagNodes = filterHTMLOpenTagNodes;
4149
+ exports.filterHTMLTextNodes = filterHTMLTextNodes;
4150
+ exports.filterLiteralNodes = filterLiteralNodes;
4151
+ exports.filterNodes = filterNodes;
4152
+ exports.filterWhitespaceNodes = filterWhitespaceNodes;
4153
+ exports.filterXMLDeclarationNodes = filterXMLDeclarationNodes;
3141
4154
  exports.fromSerializedError = fromSerializedError;
3142
4155
  exports.fromSerializedNode = fromSerializedNode;
4156
+ exports.getCombinedAttributeName = getCombinedAttributeName;
4157
+ exports.getCombinedStringFromNodes = getCombinedStringFromNodes;
4158
+ exports.getNodesAfterLocation = getNodesAfterLocation;
4159
+ exports.getNodesAfterPosition = getNodesAfterPosition;
4160
+ exports.getNodesBeforeLocation = getNodesBeforeLocation;
4161
+ exports.getNodesBeforePosition = getNodesBeforePosition;
4162
+ exports.getStaticAttributeName = getStaticAttributeName;
4163
+ exports.getStaticContentFromNodes = getStaticContentFromNodes;
4164
+ exports.getStaticStringFromNodes = getStaticStringFromNodes;
4165
+ exports.getTagName = getTagName;
4166
+ exports.getValidatableStaticContent = getValidatableStaticContent;
4167
+ exports.hasChildren = hasChildren;
4168
+ exports.hasDynamicAttributeName = hasDynamicAttributeName;
4169
+ exports.hasERBContent = hasERBContent;
4170
+ exports.hasERBOutput = hasERBOutput;
4171
+ exports.hasStaticAttributeName = hasStaticAttributeName;
4172
+ exports.hasStaticContent = hasStaticContent;
4173
+ exports.isAnyOf = isAnyOf;
4174
+ exports.isCDATANode = isCDATANode;
4175
+ exports.isCommentNode = isCommentNode;
4176
+ exports.isDocumentNode = isDocumentNode;
4177
+ exports.isERBBeginNode = isERBBeginNode;
4178
+ exports.isERBBlockNode = isERBBlockNode;
4179
+ exports.isERBCaseMatchNode = isERBCaseMatchNode;
4180
+ exports.isERBCaseNode = isERBCaseNode;
4181
+ exports.isERBContentNode = isERBContentNode;
4182
+ exports.isERBControlFlowNode = isERBControlFlowNode;
4183
+ exports.isERBElseNode = isERBElseNode;
4184
+ exports.isERBEndNode = isERBEndNode;
4185
+ exports.isERBEnsureNode = isERBEnsureNode;
4186
+ exports.isERBForNode = isERBForNode;
4187
+ exports.isERBIfNode = isERBIfNode;
4188
+ exports.isERBInNode = isERBInNode;
3143
4189
  exports.isERBNode = isERBNode;
4190
+ exports.isERBOutputNode = isERBOutputNode;
4191
+ exports.isERBRescueNode = isERBRescueNode;
4192
+ exports.isERBUnlessNode = isERBUnlessNode;
4193
+ exports.isERBUntilNode = isERBUntilNode;
4194
+ exports.isERBWhenNode = isERBWhenNode;
4195
+ exports.isERBWhileNode = isERBWhileNode;
4196
+ exports.isERBYieldNode = isERBYieldNode;
4197
+ exports.isEffectivelyStatic = isEffectivelyStatic;
4198
+ exports.isHTMLAttributeNameNode = isHTMLAttributeNameNode;
4199
+ exports.isHTMLAttributeNode = isHTMLAttributeNode;
4200
+ exports.isHTMLAttributeValueNode = isHTMLAttributeValueNode;
4201
+ exports.isHTMLCloseTagNode = isHTMLCloseTagNode;
4202
+ exports.isHTMLCommentNode = isHTMLCommentNode;
4203
+ exports.isHTMLDoctypeNode = isHTMLDoctypeNode;
4204
+ exports.isHTMLElementNode = isHTMLElementNode;
4205
+ exports.isHTMLNode = isHTMLNode;
4206
+ exports.isHTMLOpenTagNode = isHTMLOpenTagNode;
4207
+ exports.isHTMLTextNode = isHTMLTextNode;
3144
4208
  exports.isLibHerbBackend = isLibHerbBackend;
4209
+ exports.isLiteralNode = isLiteralNode;
4210
+ exports.isNode = isNode;
4211
+ exports.isNoneOf = isNoneOf;
4212
+ exports.isParseResult = isParseResult;
4213
+ exports.isPositionAfter = isPositionAfter;
4214
+ exports.isPositionEqual = isPositionEqual;
4215
+ exports.isToken = isToken;
4216
+ exports.isWhitespaceNode = isWhitespaceNode;
4217
+ exports.isXMLDeclarationNode = isXMLDeclarationNode;
4218
+ exports.splitNodesAroundLocation = splitNodesAroundLocation;
4219
+ exports.splitNodesAroundPosition = splitNodesAroundPosition;
3145
4220
  exports.toMonacoDiagnostic = toMonacoDiagnostic;
3146
4221
  //# sourceMappingURL=herb-core.cjs.map