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