@herb-tools/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/README.md +9 -0
  3. package/dist/herb-core.browser.js +2704 -0
  4. package/dist/herb-core.browser.js.map +1 -0
  5. package/dist/herb-core.cjs +2759 -0
  6. package/dist/herb-core.cjs.map +1 -0
  7. package/dist/herb-core.esm.js +2704 -0
  8. package/dist/herb-core.esm.js.map +1 -0
  9. package/dist/herb-core.umd.js +2765 -0
  10. package/dist/herb-core.umd.js.map +1 -0
  11. package/dist/types/ast.d.ts +4 -0
  12. package/dist/types/backend.d.ts +24 -0
  13. package/dist/types/error.d.ts +16 -0
  14. package/dist/types/errors.d.ts +222 -0
  15. package/dist/types/herb-backend.d.ts +87 -0
  16. package/dist/types/index.d.ts +15 -0
  17. package/dist/types/lex-result.d.ts +50 -0
  18. package/dist/types/location.d.ts +18 -0
  19. package/dist/types/node.d.ts +27 -0
  20. package/dist/types/nodes.d.ts +682 -0
  21. package/dist/types/parse-result.d.ts +62 -0
  22. package/dist/types/position.d.ts +15 -0
  23. package/dist/types/range.d.ts +12 -0
  24. package/dist/types/result.d.ts +10 -0
  25. package/dist/types/token-list.d.ts +16 -0
  26. package/dist/types/token.d.ts +22 -0
  27. package/dist/types/util.d.ts +2 -0
  28. package/dist/types/visitor.d.ts +11 -0
  29. package/dist/types/warning.d.ts +11 -0
  30. package/package.json +49 -0
  31. package/src/ast.ts +7 -0
  32. package/src/backend.ts +85 -0
  33. package/src/error.ts +38 -0
  34. package/src/errors.ts +820 -0
  35. package/src/herb-backend.ts +152 -0
  36. package/src/index.ts +15 -0
  37. package/src/lex-result.ts +78 -0
  38. package/src/location.ts +51 -0
  39. package/src/node.ts +106 -0
  40. package/src/nodes.ts +2294 -0
  41. package/src/parse-result.ts +101 -0
  42. package/src/position.ts +38 -0
  43. package/src/range.ts +35 -0
  44. package/src/result.ts +26 -0
  45. package/src/token-list.ts +57 -0
  46. package/src/token.ts +63 -0
  47. package/src/util.ts +19 -0
  48. package/src/visitor.ts +14 -0
  49. package/src/warning.ts +20 -0
@@ -0,0 +1,2759 @@
1
+ 'use strict';
2
+
3
+ class ASTNode {
4
+ errors;
5
+ constructor() {
6
+ this.errors = [];
7
+ }
8
+ }
9
+
10
+ const expectedFunctions = [
11
+ "parse",
12
+ "lex",
13
+ "parseFile",
14
+ "lexFile",
15
+ "extractRuby",
16
+ "extractHTML",
17
+ "version",
18
+ ];
19
+ // NOTE: This function should never be called and is only for type checking
20
+ // so we can make sure `expectedFunctions` matches the functions defined
21
+ // in `LibHerbBackendFunctions` and the other way around.
22
+ //
23
+ function _TYPECHECK() {
24
+ const checkFunctionsExist = true;
25
+ const checkInterfaceComplete = true;
26
+ return { checkFunctionsExist, checkInterfaceComplete };
27
+ }
28
+ function isLibHerbBackend(object, libherbpath = "unknown") {
29
+ for (const expectedFunction of expectedFunctions) {
30
+ if (object[expectedFunction] === undefined) {
31
+ throw new Error(`Libherb at "${libherbpath}" doesn't expose function "${expectedFunction}".`);
32
+ }
33
+ if (typeof object[expectedFunction] !== "function") {
34
+ throw new Error(`Libherb at "${libherbpath}" has "${expectedFunction}" but it's not a function.`);
35
+ }
36
+ }
37
+ return true;
38
+ }
39
+ function ensureLibHerbBackend(object, libherbpath = "unknown") {
40
+ isLibHerbBackend(object, libherbpath);
41
+ return object;
42
+ }
43
+
44
+ class Position {
45
+ line;
46
+ column;
47
+ static from(position) {
48
+ return new Position(position.line, position.column);
49
+ }
50
+ constructor(line, column) {
51
+ this.line = line;
52
+ this.column = column;
53
+ }
54
+ toHash() {
55
+ return { line: this.line, column: this.column };
56
+ }
57
+ toJSON() {
58
+ return this.toHash();
59
+ }
60
+ treeInspect() {
61
+ return `(${this.line}:${this.column})`;
62
+ }
63
+ inspect() {
64
+ return `#<Herb::Position ${this.treeInspect()}>`;
65
+ }
66
+ toString() {
67
+ return this.inspect();
68
+ }
69
+ }
70
+
71
+ class Location {
72
+ start;
73
+ end;
74
+ static from(location) {
75
+ const start = Position.from(location.start);
76
+ const end = Position.from(location.end);
77
+ return new Location(start, end);
78
+ }
79
+ constructor(start, end) {
80
+ this.start = start;
81
+ this.end = end;
82
+ }
83
+ toHash() {
84
+ return {
85
+ start: this.start.toHash(),
86
+ end: this.end.toHash(),
87
+ };
88
+ }
89
+ toJSON() {
90
+ return this.toHash();
91
+ }
92
+ treeInspect() {
93
+ return `${this.start.treeInspect()}-${this.end.treeInspect()}`;
94
+ }
95
+ treeInspectWithLabel() {
96
+ return `(location: ${this.treeInspect()})`;
97
+ }
98
+ inspect() {
99
+ return `#<Herb::Location ${this.treeInspect()}>`;
100
+ }
101
+ toString() {
102
+ return this.inspect();
103
+ }
104
+ }
105
+
106
+ class Range {
107
+ start;
108
+ end;
109
+ static from(range) {
110
+ return new Range(range[0], range[1]);
111
+ }
112
+ constructor(start, end) {
113
+ this.start = start;
114
+ this.end = end;
115
+ }
116
+ toArray() {
117
+ return [this.start, this.end];
118
+ }
119
+ toJSON() {
120
+ return this.toArray();
121
+ }
122
+ treeInspect() {
123
+ return `[${this.start}, ${this.end}]`;
124
+ }
125
+ inspect() {
126
+ return `#<Herb::Range ${this.toArray()}>`;
127
+ }
128
+ toString() {
129
+ return this.inspect();
130
+ }
131
+ }
132
+
133
+ class Token {
134
+ value;
135
+ range;
136
+ location;
137
+ type;
138
+ static from(token) {
139
+ return new Token(token.value, Range.from(token.range), Location.from(token.location), token.type);
140
+ }
141
+ constructor(value, range, location, type) {
142
+ this.value = value;
143
+ this.range = range;
144
+ this.location = location;
145
+ this.type = type;
146
+ }
147
+ toHash() {
148
+ return {
149
+ value: this.value,
150
+ range: this.range?.toArray(),
151
+ location: this.location?.toHash(),
152
+ type: this.type,
153
+ };
154
+ }
155
+ toJSON() {
156
+ return this.toHash();
157
+ }
158
+ treeInspect() {
159
+ return `"${this.value}" ${this.location.treeInspectWithLabel()}`;
160
+ }
161
+ valueInspect() {
162
+ return this.type === "TOKEN_EOF"
163
+ ? JSON.stringify("<EOF>")
164
+ : JSON.stringify(this.value);
165
+ }
166
+ inspect() {
167
+ return `#<Herb::Token type="${this.type}" value=${this.valueInspect()} range=${this.range.treeInspect()} start=${this.location.start.treeInspect()} end=${this.location.end.treeInspect()}>`;
168
+ }
169
+ toString() {
170
+ return this.inspect();
171
+ }
172
+ }
173
+
174
+ class HerbError {
175
+ type;
176
+ message;
177
+ location;
178
+ static from(error) {
179
+ return fromSerializedError(error);
180
+ }
181
+ constructor(type, message, location) {
182
+ this.type = type;
183
+ this.message = message;
184
+ this.location = location;
185
+ }
186
+ toJSON() {
187
+ return {
188
+ type: this.type,
189
+ message: this.message,
190
+ location: this.location.toJSON(),
191
+ };
192
+ }
193
+ inspect() {
194
+ return this.treeInspect(0);
195
+ }
196
+ }
197
+
198
+ // NOTE: This file is generated by the templates/template.rb script and should not
199
+ // be modified manually. See /Users/marcoroth/Development/herb-release/templates/javascript/packages/core/src/errors.ts.erb
200
+ function fromSerializedError(error) {
201
+ switch (error.type) {
202
+ case "UNEXPECTED_ERROR": return UnexpectedError.from(error);
203
+ case "UNEXPECTED_TOKEN_ERROR": return UnexpectedTokenError.from(error);
204
+ case "MISSING_OPENING_TAG_ERROR": return MissingOpeningTagError.from(error);
205
+ case "MISSING_CLOSING_TAG_ERROR": return MissingClosingTagError.from(error);
206
+ case "TAG_NAMES_MISMATCH_ERROR": return TagNamesMismatchError.from(error);
207
+ case "QUOTES_MISMATCH_ERROR": return QuotesMismatchError.from(error);
208
+ case "VOID_ELEMENT_CLOSING_TAG_ERROR": return VoidElementClosingTagError.from(error);
209
+ case "UNCLOSED_ELEMENT_ERROR": return UnclosedElementError.from(error);
210
+ case "RUBY_PARSE_ERROR": return RubyParseError.from(error);
211
+ default:
212
+ throw new Error(`Unknown node type: ${error.type}`);
213
+ }
214
+ }
215
+ class UnexpectedError extends HerbError {
216
+ description;
217
+ expected;
218
+ found;
219
+ static from(data) {
220
+ return new UnexpectedError({
221
+ type: data.type,
222
+ message: data.message,
223
+ location: Location.from(data.location),
224
+ description: data.description,
225
+ expected: data.expected,
226
+ found: data.found,
227
+ });
228
+ }
229
+ constructor(props) {
230
+ super(props.type, props.message, props.location);
231
+ this.description = props.description;
232
+ this.expected = props.expected;
233
+ this.found = props.found;
234
+ }
235
+ toJSON() {
236
+ return {
237
+ ...super.toJSON(),
238
+ type: "UNEXPECTED_ERROR",
239
+ description: this.description,
240
+ expected: this.expected,
241
+ found: this.found,
242
+ };
243
+ }
244
+ toDiagnostics() {
245
+ const diagnostics = [
246
+ {
247
+ line: this.location.start.line,
248
+ column: this.location.start.column,
249
+ endLine: this.location.end.line,
250
+ endColumn: this.location.end.column,
251
+ message: this.message,
252
+ severity: 'error'
253
+ }
254
+ ];
255
+ // no-op for description
256
+ // no-op for expected
257
+ // no-op for found
258
+ return diagnostics;
259
+ }
260
+ treeInspect() {
261
+ let output = "";
262
+ output += `@ UnexpectedError ${this.location.treeInspectWithLabel()}\n`;
263
+ output += `├── message: "${this.message}"\n`;
264
+ output += `├── description: ${JSON.stringify(this.description)}\n`;
265
+ output += `├── expected: ${JSON.stringify(this.expected)}\n`;
266
+ output += `└── found: ${JSON.stringify(this.found)}\n`;
267
+ return output;
268
+ }
269
+ }
270
+ class UnexpectedTokenError extends HerbError {
271
+ expected_type;
272
+ found;
273
+ static from(data) {
274
+ return new UnexpectedTokenError({
275
+ type: data.type,
276
+ message: data.message,
277
+ location: Location.from(data.location),
278
+ expected_type: data.expected_type,
279
+ found: data.found ? Token.from(data.found) : null,
280
+ });
281
+ }
282
+ constructor(props) {
283
+ super(props.type, props.message, props.location);
284
+ this.expected_type = props.expected_type;
285
+ this.found = props.found;
286
+ }
287
+ toJSON() {
288
+ return {
289
+ ...super.toJSON(),
290
+ type: "UNEXPECTED_TOKEN_ERROR",
291
+ expected_type: this.expected_type,
292
+ found: this.found ? this.found.toJSON() : null,
293
+ };
294
+ }
295
+ toDiagnostics() {
296
+ const diagnostics = [
297
+ {
298
+ line: this.location.start.line,
299
+ column: this.location.start.column,
300
+ endLine: this.location.end.line,
301
+ endColumn: this.location.end.column,
302
+ message: this.message,
303
+ severity: 'error'
304
+ }
305
+ ];
306
+ // no-op for expected_type
307
+ if (this.found) {
308
+ diagnostics.push({
309
+ line: this.found.location.start.line,
310
+ column: this.found.location.start.column,
311
+ endLine: this.found.location.end.line,
312
+ endColumn: this.found.location.end.column,
313
+ message: `found "${(this.found.value)}" is here`,
314
+ severity: 'info'
315
+ });
316
+ }
317
+ return diagnostics;
318
+ }
319
+ treeInspect() {
320
+ let output = "";
321
+ output += `@ UnexpectedTokenError ${this.location.treeInspectWithLabel()}\n`;
322
+ output += `├── message: "${this.message}"\n`;
323
+ output += `├── expected_type: ${JSON.stringify(this.expected_type)}\n`;
324
+ output += `└── found: ${this.found ? this.found.treeInspect() : "∅"}\n`;
325
+ return output;
326
+ }
327
+ }
328
+ class MissingOpeningTagError extends HerbError {
329
+ closing_tag;
330
+ static from(data) {
331
+ return new MissingOpeningTagError({
332
+ type: data.type,
333
+ message: data.message,
334
+ location: Location.from(data.location),
335
+ closing_tag: data.closing_tag ? Token.from(data.closing_tag) : null,
336
+ });
337
+ }
338
+ constructor(props) {
339
+ super(props.type, props.message, props.location);
340
+ this.closing_tag = props.closing_tag;
341
+ }
342
+ toJSON() {
343
+ return {
344
+ ...super.toJSON(),
345
+ type: "MISSING_OPENING_TAG_ERROR",
346
+ closing_tag: this.closing_tag ? this.closing_tag.toJSON() : null,
347
+ };
348
+ }
349
+ toDiagnostics() {
350
+ const diagnostics = [
351
+ {
352
+ line: this.location.start.line,
353
+ column: this.location.start.column,
354
+ endLine: this.location.end.line,
355
+ endColumn: this.location.end.column,
356
+ message: this.message,
357
+ severity: 'error'
358
+ }
359
+ ];
360
+ if (this.closing_tag) {
361
+ diagnostics.push({
362
+ line: this.closing_tag.location.start.line,
363
+ column: this.closing_tag.location.start.column,
364
+ endLine: this.closing_tag.location.end.line,
365
+ endColumn: this.closing_tag.location.end.column,
366
+ message: `closing_tag "${(this.closing_tag.value)}" is here`,
367
+ severity: 'info'
368
+ });
369
+ }
370
+ return diagnostics;
371
+ }
372
+ treeInspect() {
373
+ let output = "";
374
+ output += `@ MissingOpeningTagError ${this.location.treeInspectWithLabel()}\n`;
375
+ output += `├── message: "${this.message}"\n`;
376
+ output += `└── closing_tag: ${this.closing_tag ? this.closing_tag.treeInspect() : "∅"}\n`;
377
+ return output;
378
+ }
379
+ }
380
+ class MissingClosingTagError extends HerbError {
381
+ opening_tag;
382
+ static from(data) {
383
+ return new MissingClosingTagError({
384
+ type: data.type,
385
+ message: data.message,
386
+ location: Location.from(data.location),
387
+ opening_tag: data.opening_tag ? Token.from(data.opening_tag) : null,
388
+ });
389
+ }
390
+ constructor(props) {
391
+ super(props.type, props.message, props.location);
392
+ this.opening_tag = props.opening_tag;
393
+ }
394
+ toJSON() {
395
+ return {
396
+ ...super.toJSON(),
397
+ type: "MISSING_CLOSING_TAG_ERROR",
398
+ opening_tag: this.opening_tag ? this.opening_tag.toJSON() : null,
399
+ };
400
+ }
401
+ toDiagnostics() {
402
+ const diagnostics = [
403
+ {
404
+ line: this.location.start.line,
405
+ column: this.location.start.column,
406
+ endLine: this.location.end.line,
407
+ endColumn: this.location.end.column,
408
+ message: this.message,
409
+ severity: 'error'
410
+ }
411
+ ];
412
+ if (this.opening_tag) {
413
+ diagnostics.push({
414
+ line: this.opening_tag.location.start.line,
415
+ column: this.opening_tag.location.start.column,
416
+ endLine: this.opening_tag.location.end.line,
417
+ endColumn: this.opening_tag.location.end.column,
418
+ message: `opening_tag "${(this.opening_tag.value)}" is here`,
419
+ severity: 'info'
420
+ });
421
+ }
422
+ return diagnostics;
423
+ }
424
+ treeInspect() {
425
+ let output = "";
426
+ output += `@ MissingClosingTagError ${this.location.treeInspectWithLabel()}\n`;
427
+ output += `├── message: "${this.message}"\n`;
428
+ output += `└── opening_tag: ${this.opening_tag ? this.opening_tag.treeInspect() : "∅"}\n`;
429
+ return output;
430
+ }
431
+ }
432
+ class TagNamesMismatchError extends HerbError {
433
+ opening_tag;
434
+ closing_tag;
435
+ static from(data) {
436
+ return new TagNamesMismatchError({
437
+ type: data.type,
438
+ message: data.message,
439
+ location: Location.from(data.location),
440
+ opening_tag: data.opening_tag ? Token.from(data.opening_tag) : null,
441
+ closing_tag: data.closing_tag ? Token.from(data.closing_tag) : null,
442
+ });
443
+ }
444
+ constructor(props) {
445
+ super(props.type, props.message, props.location);
446
+ this.opening_tag = props.opening_tag;
447
+ this.closing_tag = props.closing_tag;
448
+ }
449
+ toJSON() {
450
+ return {
451
+ ...super.toJSON(),
452
+ type: "TAG_NAMES_MISMATCH_ERROR",
453
+ opening_tag: this.opening_tag ? this.opening_tag.toJSON() : null,
454
+ closing_tag: this.closing_tag ? this.closing_tag.toJSON() : null,
455
+ };
456
+ }
457
+ toDiagnostics() {
458
+ const diagnostics = [
459
+ {
460
+ line: this.location.start.line,
461
+ column: this.location.start.column,
462
+ endLine: this.location.end.line,
463
+ endColumn: this.location.end.column,
464
+ message: this.message,
465
+ severity: 'error'
466
+ }
467
+ ];
468
+ if (this.opening_tag) {
469
+ diagnostics.push({
470
+ line: this.opening_tag.location.start.line,
471
+ column: this.opening_tag.location.start.column,
472
+ endLine: this.opening_tag.location.end.line,
473
+ endColumn: this.opening_tag.location.end.column,
474
+ message: `opening_tag "${(this.opening_tag.value)}" is here`,
475
+ severity: 'info'
476
+ });
477
+ }
478
+ if (this.closing_tag) {
479
+ diagnostics.push({
480
+ line: this.closing_tag.location.start.line,
481
+ column: this.closing_tag.location.start.column,
482
+ endLine: this.closing_tag.location.end.line,
483
+ endColumn: this.closing_tag.location.end.column,
484
+ message: `closing_tag "${(this.closing_tag.value)}" is here`,
485
+ severity: 'info'
486
+ });
487
+ }
488
+ return diagnostics;
489
+ }
490
+ treeInspect() {
491
+ let output = "";
492
+ output += `@ TagNamesMismatchError ${this.location.treeInspectWithLabel()}\n`;
493
+ output += `├── message: "${this.message}"\n`;
494
+ output += `├── opening_tag: ${this.opening_tag ? this.opening_tag.treeInspect() : "∅"}\n`;
495
+ output += `└── closing_tag: ${this.closing_tag ? this.closing_tag.treeInspect() : "∅"}\n`;
496
+ return output;
497
+ }
498
+ }
499
+ class QuotesMismatchError extends HerbError {
500
+ opening_quote;
501
+ closing_quote;
502
+ static from(data) {
503
+ return new QuotesMismatchError({
504
+ type: data.type,
505
+ message: data.message,
506
+ location: Location.from(data.location),
507
+ opening_quote: data.opening_quote ? Token.from(data.opening_quote) : null,
508
+ closing_quote: data.closing_quote ? Token.from(data.closing_quote) : null,
509
+ });
510
+ }
511
+ constructor(props) {
512
+ super(props.type, props.message, props.location);
513
+ this.opening_quote = props.opening_quote;
514
+ this.closing_quote = props.closing_quote;
515
+ }
516
+ toJSON() {
517
+ return {
518
+ ...super.toJSON(),
519
+ type: "QUOTES_MISMATCH_ERROR",
520
+ opening_quote: this.opening_quote ? this.opening_quote.toJSON() : null,
521
+ closing_quote: this.closing_quote ? this.closing_quote.toJSON() : null,
522
+ };
523
+ }
524
+ toDiagnostics() {
525
+ const diagnostics = [
526
+ {
527
+ line: this.location.start.line,
528
+ column: this.location.start.column,
529
+ endLine: this.location.end.line,
530
+ endColumn: this.location.end.column,
531
+ message: this.message,
532
+ severity: 'error'
533
+ }
534
+ ];
535
+ if (this.opening_quote) {
536
+ diagnostics.push({
537
+ line: this.opening_quote.location.start.line,
538
+ column: this.opening_quote.location.start.column,
539
+ endLine: this.opening_quote.location.end.line,
540
+ endColumn: this.opening_quote.location.end.column,
541
+ message: `opening_quote "${(this.opening_quote.value)}" is here`,
542
+ severity: 'info'
543
+ });
544
+ }
545
+ if (this.closing_quote) {
546
+ diagnostics.push({
547
+ line: this.closing_quote.location.start.line,
548
+ column: this.closing_quote.location.start.column,
549
+ endLine: this.closing_quote.location.end.line,
550
+ endColumn: this.closing_quote.location.end.column,
551
+ message: `closing_quote "${(this.closing_quote.value)}" is here`,
552
+ severity: 'info'
553
+ });
554
+ }
555
+ return diagnostics;
556
+ }
557
+ treeInspect() {
558
+ let output = "";
559
+ output += `@ QuotesMismatchError ${this.location.treeInspectWithLabel()}\n`;
560
+ output += `├── message: "${this.message}"\n`;
561
+ output += `├── opening_quote: ${this.opening_quote ? this.opening_quote.treeInspect() : "∅"}\n`;
562
+ output += `└── closing_quote: ${this.closing_quote ? this.closing_quote.treeInspect() : "∅"}\n`;
563
+ return output;
564
+ }
565
+ }
566
+ class VoidElementClosingTagError extends HerbError {
567
+ tag_name;
568
+ expected;
569
+ found;
570
+ static from(data) {
571
+ return new VoidElementClosingTagError({
572
+ type: data.type,
573
+ message: data.message,
574
+ location: Location.from(data.location),
575
+ tag_name: data.tag_name ? Token.from(data.tag_name) : null,
576
+ expected: data.expected,
577
+ found: data.found,
578
+ });
579
+ }
580
+ constructor(props) {
581
+ super(props.type, props.message, props.location);
582
+ this.tag_name = props.tag_name;
583
+ this.expected = props.expected;
584
+ this.found = props.found;
585
+ }
586
+ toJSON() {
587
+ return {
588
+ ...super.toJSON(),
589
+ type: "VOID_ELEMENT_CLOSING_TAG_ERROR",
590
+ tag_name: this.tag_name ? this.tag_name.toJSON() : null,
591
+ expected: this.expected,
592
+ found: this.found,
593
+ };
594
+ }
595
+ toDiagnostics() {
596
+ const diagnostics = [
597
+ {
598
+ line: this.location.start.line,
599
+ column: this.location.start.column,
600
+ endLine: this.location.end.line,
601
+ endColumn: this.location.end.column,
602
+ message: this.message,
603
+ severity: 'error'
604
+ }
605
+ ];
606
+ if (this.tag_name) {
607
+ diagnostics.push({
608
+ line: this.tag_name.location.start.line,
609
+ column: this.tag_name.location.start.column,
610
+ endLine: this.tag_name.location.end.line,
611
+ endColumn: this.tag_name.location.end.column,
612
+ message: `tag_name "${(this.tag_name.value)}" is here`,
613
+ severity: 'info'
614
+ });
615
+ }
616
+ // no-op for expected
617
+ // no-op for found
618
+ return diagnostics;
619
+ }
620
+ treeInspect() {
621
+ let output = "";
622
+ output += `@ VoidElementClosingTagError ${this.location.treeInspectWithLabel()}\n`;
623
+ output += `├── message: "${this.message}"\n`;
624
+ output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
625
+ output += `├── expected: ${JSON.stringify(this.expected)}\n`;
626
+ output += `└── found: ${JSON.stringify(this.found)}\n`;
627
+ return output;
628
+ }
629
+ }
630
+ class UnclosedElementError extends HerbError {
631
+ opening_tag;
632
+ static from(data) {
633
+ return new UnclosedElementError({
634
+ type: data.type,
635
+ message: data.message,
636
+ location: Location.from(data.location),
637
+ opening_tag: data.opening_tag ? Token.from(data.opening_tag) : null,
638
+ });
639
+ }
640
+ constructor(props) {
641
+ super(props.type, props.message, props.location);
642
+ this.opening_tag = props.opening_tag;
643
+ }
644
+ toJSON() {
645
+ return {
646
+ ...super.toJSON(),
647
+ type: "UNCLOSED_ELEMENT_ERROR",
648
+ opening_tag: this.opening_tag ? this.opening_tag.toJSON() : null,
649
+ };
650
+ }
651
+ toDiagnostics() {
652
+ const diagnostics = [
653
+ {
654
+ line: this.location.start.line,
655
+ column: this.location.start.column,
656
+ endLine: this.location.end.line,
657
+ endColumn: this.location.end.column,
658
+ message: this.message,
659
+ severity: 'error'
660
+ }
661
+ ];
662
+ if (this.opening_tag) {
663
+ diagnostics.push({
664
+ line: this.opening_tag.location.start.line,
665
+ column: this.opening_tag.location.start.column,
666
+ endLine: this.opening_tag.location.end.line,
667
+ endColumn: this.opening_tag.location.end.column,
668
+ message: `opening_tag "${(this.opening_tag.value)}" is here`,
669
+ severity: 'info'
670
+ });
671
+ }
672
+ return diagnostics;
673
+ }
674
+ treeInspect() {
675
+ let output = "";
676
+ output += `@ UnclosedElementError ${this.location.treeInspectWithLabel()}\n`;
677
+ output += `├── message: "${this.message}"\n`;
678
+ output += `└── opening_tag: ${this.opening_tag ? this.opening_tag.treeInspect() : "∅"}\n`;
679
+ return output;
680
+ }
681
+ }
682
+ class RubyParseError extends HerbError {
683
+ error_message;
684
+ diagnostic_id;
685
+ level;
686
+ static from(data) {
687
+ return new RubyParseError({
688
+ type: data.type,
689
+ message: data.message,
690
+ location: Location.from(data.location),
691
+ error_message: data.error_message,
692
+ diagnostic_id: data.diagnostic_id,
693
+ level: data.level,
694
+ });
695
+ }
696
+ constructor(props) {
697
+ super(props.type, props.message, props.location);
698
+ this.error_message = props.error_message;
699
+ this.diagnostic_id = props.diagnostic_id;
700
+ this.level = props.level;
701
+ }
702
+ toJSON() {
703
+ return {
704
+ ...super.toJSON(),
705
+ type: "RUBY_PARSE_ERROR",
706
+ error_message: this.error_message,
707
+ diagnostic_id: this.diagnostic_id,
708
+ level: this.level,
709
+ };
710
+ }
711
+ toDiagnostics() {
712
+ const diagnostics = [
713
+ {
714
+ line: this.location.start.line,
715
+ column: this.location.start.column,
716
+ endLine: this.location.end.line,
717
+ endColumn: this.location.end.column,
718
+ message: this.message,
719
+ severity: 'error'
720
+ }
721
+ ];
722
+ // no-op for error_message
723
+ // no-op for diagnostic_id
724
+ // no-op for level
725
+ return diagnostics;
726
+ }
727
+ treeInspect() {
728
+ let output = "";
729
+ output += `@ RubyParseError ${this.location.treeInspectWithLabel()}\n`;
730
+ output += `├── message: "${this.message}"\n`;
731
+ output += `├── error_message: ${JSON.stringify(this.error_message)}\n`;
732
+ output += `├── diagnostic_id: ${JSON.stringify(this.diagnostic_id)}\n`;
733
+ output += `└── level: ${JSON.stringify(this.level)}\n`;
734
+ return output;
735
+ }
736
+ }
737
+
738
+ var name = "@herb-tools/core";
739
+ var version = "0.1.0";
740
+ var packageJSON = {
741
+ name: name,
742
+ version: version};
743
+
744
+ function ensureString(object) {
745
+ if (typeof object === "string") {
746
+ return object;
747
+ }
748
+ throw new TypeError("Argument must be a string");
749
+ }
750
+ function convertToUTF8(string) {
751
+ const bytes = [];
752
+ for (let i = 0; i < string.length; i++) {
753
+ bytes.push(string.charCodeAt(i));
754
+ }
755
+ const decoder = new TextDecoder("utf-8");
756
+ return decoder.decode(new Uint8Array(bytes));
757
+ }
758
+
759
+ class Result {
760
+ source;
761
+ warnings;
762
+ errors;
763
+ constructor(source, warnings = [], errors = []) {
764
+ this.source = source;
765
+ this.warnings = warnings || [];
766
+ this.errors = errors || [];
767
+ }
768
+ success() {
769
+ return false;
770
+ }
771
+ failed() {
772
+ return true;
773
+ }
774
+ }
775
+
776
+ class TokenList {
777
+ list;
778
+ static from(list) {
779
+ return new TokenList(list.map((token) => Token.from(token)));
780
+ }
781
+ constructor(list) {
782
+ this.list = list;
783
+ }
784
+ get length() {
785
+ return this.list.length;
786
+ }
787
+ [Symbol.iterator]() {
788
+ return this.list[Symbol.iterator]();
789
+ }
790
+ at(index) {
791
+ return this.list.at(index);
792
+ }
793
+ forEach(callback) {
794
+ this.list.forEach(callback);
795
+ }
796
+ map(callback) {
797
+ return this.list.map(callback);
798
+ }
799
+ filter(predicate) {
800
+ return this.list.filter(predicate);
801
+ }
802
+ __getobj__() {
803
+ return this.list;
804
+ }
805
+ inspect() {
806
+ return this.list.map((token) => token.inspect()).join("\n") + "\n";
807
+ }
808
+ toString() {
809
+ return this.inspect();
810
+ }
811
+ }
812
+
813
+ /**
814
+ * Represents the result of a lexical analysis, extending the base `Result` class.
815
+ * It contains the token list, source code, warnings, and errors.
816
+ */
817
+ class LexResult extends Result {
818
+ /** The list of tokens generated from the source code. */
819
+ value;
820
+ /**
821
+ * Creates a `LexResult` instance from a serialized result.
822
+ * @param result - The serialized lexical result containing tokens, source, warnings, and errors.
823
+ * @returns A new `LexResult` instance.
824
+ */
825
+ static from(result) {
826
+ return new LexResult(TokenList.from(result.tokens || []), result.source, result.warnings, result.errors);
827
+ }
828
+ /**
829
+ * Constructs a new `LexResult`.
830
+ * @param value - The list of tokens.
831
+ * @param source - The source code that was lexed.
832
+ * @param warnings - An array of warnings encountered during lexing.
833
+ * @param errors - An array of errors encountered during lexing.
834
+ */
835
+ constructor(value, source, warnings = [], errors = []) {
836
+ super(source, warnings, errors);
837
+ this.value = value;
838
+ }
839
+ /**
840
+ * Determines if the lexing was successful.
841
+ * @returns `true` if there are no errors, otherwise `false`.
842
+ */
843
+ success() {
844
+ return this.errors.length === 0;
845
+ }
846
+ /**
847
+ * Determines if the lexing failed.
848
+ * @returns `true` if there are errors, otherwise `false`.
849
+ */
850
+ failed() {
851
+ return this.errors.length > 0;
852
+ }
853
+ /**
854
+ * Converts the `LexResult` to a JSON representation.
855
+ * @returns An object containing the token list, source, warnings, and errors.
856
+ */
857
+ toJSON() {
858
+ return {
859
+ value: this.value,
860
+ source: this.source,
861
+ warnings: this.warnings,
862
+ errors: this.errors,
863
+ };
864
+ }
865
+ }
866
+
867
+ class Node {
868
+ type;
869
+ location;
870
+ errors;
871
+ static from(node) {
872
+ return fromSerializedNode(node);
873
+ }
874
+ constructor(type, location, errors) {
875
+ this.type = type;
876
+ this.location = location;
877
+ this.errors = errors;
878
+ }
879
+ toJSON() {
880
+ return {
881
+ type: this.type,
882
+ location: this.location.toJSON(),
883
+ errors: this.errors,
884
+ };
885
+ }
886
+ inspect() {
887
+ return this.treeInspect(0);
888
+ }
889
+ inspectArray(array, prefix) {
890
+ if (!array)
891
+ return "∅\n";
892
+ if (array.length === 0)
893
+ return "[]\n";
894
+ let output = `(${array.length} item${array.length == 1 ? "" : "s"})\n`;
895
+ array.forEach((item, index) => {
896
+ const isLast = index === array.length - 1;
897
+ if (item instanceof Node || item instanceof HerbError) {
898
+ output += this.inspectNode(item, prefix, isLast ? " " : "│ ", isLast, false);
899
+ }
900
+ else {
901
+ const symbol = isLast ? "└── " : "├── ";
902
+ output += `${prefix}${symbol} ${item}\n`;
903
+ }
904
+ });
905
+ output += `${prefix}\n`;
906
+ return output;
907
+ }
908
+ inspectNode(node, prefix, prefix2 = " ", last = true, trailingNewline = true) {
909
+ if (!node)
910
+ return "∅\n";
911
+ let output = trailingNewline ? "\n" : "";
912
+ output += `${prefix}`;
913
+ output += last ? "└── " : "├── ";
914
+ output += node
915
+ .treeInspect()
916
+ .trimStart()
917
+ .split("\n")
918
+ .map((line, index) => index == 0 ? line.trimStart() : `${prefix}${prefix2}${line}`)
919
+ .join("\n")
920
+ .trimStart();
921
+ output += `\n`;
922
+ return output;
923
+ }
924
+ }
925
+
926
+ // NOTE: This file is generated by the templates/template.rb script and should not
927
+ // be modified manually. See /Users/marcoroth/Development/herb-release/templates/javascript/packages/core/src/nodes.ts.erb
928
+ function fromSerializedNode(node) {
929
+ switch (node.type) {
930
+ case "AST_DOCUMENT_NODE": return DocumentNode.from(node);
931
+ case "AST_LITERAL_NODE": return LiteralNode.from(node);
932
+ case "AST_HTML_OPEN_TAG_NODE": return HTMLOpenTagNode.from(node);
933
+ case "AST_HTML_CLOSE_TAG_NODE": return HTMLCloseTagNode.from(node);
934
+ case "AST_HTML_SELF_CLOSE_TAG_NODE": return HTMLSelfCloseTagNode.from(node);
935
+ case "AST_HTML_ELEMENT_NODE": return HTMLElementNode.from(node);
936
+ case "AST_HTML_ATTRIBUTE_VALUE_NODE": return HTMLAttributeValueNode.from(node);
937
+ case "AST_HTML_ATTRIBUTE_NAME_NODE": return HTMLAttributeNameNode.from(node);
938
+ case "AST_HTML_ATTRIBUTE_NODE": return HTMLAttributeNode.from(node);
939
+ case "AST_HTML_TEXT_NODE": return HTMLTextNode.from(node);
940
+ case "AST_HTML_COMMENT_NODE": return HTMLCommentNode.from(node);
941
+ case "AST_HTML_DOCTYPE_NODE": return HTMLDoctypeNode.from(node);
942
+ case "AST_WHITESPACE_NODE": return WhitespaceNode.from(node);
943
+ case "AST_ERB_CONTENT_NODE": return ERBContentNode.from(node);
944
+ case "AST_ERB_END_NODE": return ERBEndNode.from(node);
945
+ case "AST_ERB_ELSE_NODE": return ERBElseNode.from(node);
946
+ case "AST_ERB_IF_NODE": return ERBIfNode.from(node);
947
+ case "AST_ERB_BLOCK_NODE": return ERBBlockNode.from(node);
948
+ case "AST_ERB_WHEN_NODE": return ERBWhenNode.from(node);
949
+ case "AST_ERB_CASE_NODE": return ERBCaseNode.from(node);
950
+ case "AST_ERB_WHILE_NODE": return ERBWhileNode.from(node);
951
+ case "AST_ERB_UNTIL_NODE": return ERBUntilNode.from(node);
952
+ case "AST_ERB_FOR_NODE": return ERBForNode.from(node);
953
+ case "AST_ERB_RESCUE_NODE": return ERBRescueNode.from(node);
954
+ case "AST_ERB_ENSURE_NODE": return ERBEnsureNode.from(node);
955
+ case "AST_ERB_BEGIN_NODE": return ERBBeginNode.from(node);
956
+ case "AST_ERB_UNLESS_NODE": return ERBUnlessNode.from(node);
957
+ default:
958
+ throw new Error(`Unknown node type: ${node.type}`);
959
+ }
960
+ }
961
+ class DocumentNode extends Node {
962
+ children;
963
+ static from(data) {
964
+ return new DocumentNode({
965
+ type: data.type,
966
+ location: Location.from(data.location),
967
+ errors: (data.errors || []).map(error => HerbError.from(error)),
968
+ children: (data.children || []).map(node => fromSerializedNode(node)),
969
+ });
970
+ }
971
+ constructor(props) {
972
+ super(props.type, props.location, props.errors);
973
+ this.children = props.children;
974
+ }
975
+ childNodes() {
976
+ return [
977
+ ...this.children,
978
+ ].filter(node => node !== null && node !== undefined);
979
+ }
980
+ recursiveErrors() {
981
+ return [
982
+ ...this.errors,
983
+ ...this.children.map(node => node.recursiveErrors()),
984
+ ].flat();
985
+ }
986
+ toJSON() {
987
+ return {
988
+ ...super.toJSON(),
989
+ type: "AST_DOCUMENT_NODE",
990
+ children: this.children.map(node => node.toJSON()),
991
+ };
992
+ }
993
+ treeInspect() {
994
+ let output = "";
995
+ output += `@ DocumentNode ${this.location.treeInspectWithLabel()}\n`;
996
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
997
+ output += `└── children: ${this.inspectArray(this.children, " ")}`;
998
+ // output += "\n";
999
+ return output;
1000
+ }
1001
+ }
1002
+ class LiteralNode extends Node {
1003
+ content;
1004
+ static from(data) {
1005
+ return new LiteralNode({
1006
+ type: data.type,
1007
+ location: Location.from(data.location),
1008
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1009
+ content: data.content,
1010
+ });
1011
+ }
1012
+ constructor(props) {
1013
+ super(props.type, props.location, props.errors);
1014
+ this.content = convertToUTF8(props.content);
1015
+ }
1016
+ childNodes() {
1017
+ return [].filter(node => node !== null && node !== undefined);
1018
+ }
1019
+ recursiveErrors() {
1020
+ return [
1021
+ ...this.errors,
1022
+ ].flat();
1023
+ }
1024
+ toJSON() {
1025
+ return {
1026
+ ...super.toJSON(),
1027
+ type: "AST_LITERAL_NODE",
1028
+ content: this.content,
1029
+ };
1030
+ }
1031
+ treeInspect() {
1032
+ let output = "";
1033
+ output += `@ LiteralNode ${this.location.treeInspectWithLabel()}\n`;
1034
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1035
+ output += `└── content: ${this.content ? JSON.stringify(this.content) : "∅"}\n`;
1036
+ // output += "\n";
1037
+ return output;
1038
+ }
1039
+ }
1040
+ class HTMLOpenTagNode extends Node {
1041
+ tag_opening;
1042
+ tag_name;
1043
+ tag_closing;
1044
+ children;
1045
+ is_void;
1046
+ static from(data) {
1047
+ return new HTMLOpenTagNode({
1048
+ type: data.type,
1049
+ location: Location.from(data.location),
1050
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1051
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1052
+ tag_name: data.tag_name ? Token.from(data.tag_name) : null,
1053
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1054
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1055
+ is_void: data.is_void,
1056
+ });
1057
+ }
1058
+ constructor(props) {
1059
+ super(props.type, props.location, props.errors);
1060
+ this.tag_opening = props.tag_opening;
1061
+ this.tag_name = props.tag_name;
1062
+ this.tag_closing = props.tag_closing;
1063
+ this.children = props.children;
1064
+ this.is_void = props.is_void;
1065
+ }
1066
+ childNodes() {
1067
+ return [
1068
+ ...this.children,
1069
+ ].filter(node => node !== null && node !== undefined);
1070
+ }
1071
+ recursiveErrors() {
1072
+ return [
1073
+ ...this.errors,
1074
+ ...this.children.map(node => node.recursiveErrors()),
1075
+ ].flat();
1076
+ }
1077
+ toJSON() {
1078
+ return {
1079
+ ...super.toJSON(),
1080
+ type: "AST_HTML_OPEN_TAG_NODE",
1081
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1082
+ tag_name: this.tag_name ? this.tag_name.toJSON() : null,
1083
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1084
+ children: this.children.map(node => node.toJSON()),
1085
+ is_void: this.is_void,
1086
+ };
1087
+ }
1088
+ treeInspect() {
1089
+ let output = "";
1090
+ output += `@ HTMLOpenTagNode ${this.location.treeInspectWithLabel()}\n`;
1091
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1092
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1093
+ output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
1094
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1095
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1096
+ output += `└── is_void: ${typeof this.is_void === 'boolean' ? String(this.is_void) : "∅"}\n`;
1097
+ // output += "\n";
1098
+ return output;
1099
+ }
1100
+ }
1101
+ class HTMLCloseTagNode extends Node {
1102
+ tag_opening;
1103
+ tag_name;
1104
+ tag_closing;
1105
+ static from(data) {
1106
+ return new HTMLCloseTagNode({
1107
+ type: data.type,
1108
+ location: Location.from(data.location),
1109
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1110
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1111
+ tag_name: data.tag_name ? Token.from(data.tag_name) : null,
1112
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1113
+ });
1114
+ }
1115
+ constructor(props) {
1116
+ super(props.type, props.location, props.errors);
1117
+ this.tag_opening = props.tag_opening;
1118
+ this.tag_name = props.tag_name;
1119
+ this.tag_closing = props.tag_closing;
1120
+ }
1121
+ childNodes() {
1122
+ return [].filter(node => node !== null && node !== undefined);
1123
+ }
1124
+ recursiveErrors() {
1125
+ return [
1126
+ ...this.errors,
1127
+ ].flat();
1128
+ }
1129
+ toJSON() {
1130
+ return {
1131
+ ...super.toJSON(),
1132
+ type: "AST_HTML_CLOSE_TAG_NODE",
1133
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1134
+ tag_name: this.tag_name ? this.tag_name.toJSON() : null,
1135
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1136
+ };
1137
+ }
1138
+ treeInspect() {
1139
+ let output = "";
1140
+ output += `@ HTMLCloseTagNode ${this.location.treeInspectWithLabel()}\n`;
1141
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1142
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1143
+ output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
1144
+ output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1145
+ // output += "\n";
1146
+ return output;
1147
+ }
1148
+ }
1149
+ class HTMLSelfCloseTagNode extends Node {
1150
+ tag_opening;
1151
+ tag_name;
1152
+ attributes;
1153
+ tag_closing;
1154
+ is_void;
1155
+ static from(data) {
1156
+ return new HTMLSelfCloseTagNode({
1157
+ type: data.type,
1158
+ location: Location.from(data.location),
1159
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1160
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1161
+ tag_name: data.tag_name ? Token.from(data.tag_name) : null,
1162
+ attributes: (data.attributes || []).map(node => fromSerializedNode(node)),
1163
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1164
+ is_void: data.is_void,
1165
+ });
1166
+ }
1167
+ constructor(props) {
1168
+ super(props.type, props.location, props.errors);
1169
+ this.tag_opening = props.tag_opening;
1170
+ this.tag_name = props.tag_name;
1171
+ this.attributes = props.attributes;
1172
+ this.tag_closing = props.tag_closing;
1173
+ this.is_void = props.is_void;
1174
+ }
1175
+ childNodes() {
1176
+ return [
1177
+ ...this.attributes,
1178
+ ].filter(node => node !== null && node !== undefined);
1179
+ }
1180
+ recursiveErrors() {
1181
+ return [
1182
+ ...this.errors,
1183
+ ...this.attributes.map(node => node.recursiveErrors()),
1184
+ ].flat();
1185
+ }
1186
+ toJSON() {
1187
+ return {
1188
+ ...super.toJSON(),
1189
+ type: "AST_HTML_SELF_CLOSE_TAG_NODE",
1190
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1191
+ tag_name: this.tag_name ? this.tag_name.toJSON() : null,
1192
+ attributes: this.attributes.map(node => node.toJSON()),
1193
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1194
+ is_void: this.is_void,
1195
+ };
1196
+ }
1197
+ treeInspect() {
1198
+ let output = "";
1199
+ output += `@ HTMLSelfCloseTagNode ${this.location.treeInspectWithLabel()}\n`;
1200
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1201
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1202
+ output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
1203
+ output += `├── attributes: ${this.inspectArray(this.attributes, "│ ")}`;
1204
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1205
+ output += `└── is_void: ${typeof this.is_void === 'boolean' ? String(this.is_void) : "∅"}\n`;
1206
+ // output += "\n";
1207
+ return output;
1208
+ }
1209
+ }
1210
+ class HTMLElementNode extends Node {
1211
+ open_tag;
1212
+ tag_name;
1213
+ body;
1214
+ close_tag;
1215
+ is_void;
1216
+ static from(data) {
1217
+ return new HTMLElementNode({
1218
+ type: data.type,
1219
+ location: Location.from(data.location),
1220
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1221
+ open_tag: data.open_tag ? fromSerializedNode(data.open_tag) : null,
1222
+ tag_name: data.tag_name ? Token.from(data.tag_name) : null,
1223
+ body: (data.body || []).map(node => fromSerializedNode(node)),
1224
+ close_tag: data.close_tag ? fromSerializedNode(data.close_tag) : null,
1225
+ is_void: data.is_void,
1226
+ });
1227
+ }
1228
+ constructor(props) {
1229
+ super(props.type, props.location, props.errors);
1230
+ this.open_tag = props.open_tag;
1231
+ this.tag_name = props.tag_name;
1232
+ this.body = props.body;
1233
+ this.close_tag = props.close_tag;
1234
+ this.is_void = props.is_void;
1235
+ }
1236
+ childNodes() {
1237
+ return [
1238
+ this.open_tag,
1239
+ ...this.body,
1240
+ this.close_tag,
1241
+ ].filter(node => node !== null && node !== undefined);
1242
+ }
1243
+ recursiveErrors() {
1244
+ return [
1245
+ ...this.errors,
1246
+ this.open_tag ? this.open_tag.recursiveErrors() : [],
1247
+ ...this.body.map(node => node.recursiveErrors()),
1248
+ this.close_tag ? this.close_tag.recursiveErrors() : [],
1249
+ ].flat();
1250
+ }
1251
+ toJSON() {
1252
+ return {
1253
+ ...super.toJSON(),
1254
+ type: "AST_HTML_ELEMENT_NODE",
1255
+ open_tag: this.open_tag ? this.open_tag.toJSON() : null,
1256
+ tag_name: this.tag_name ? this.tag_name.toJSON() : null,
1257
+ body: this.body.map(node => node.toJSON()),
1258
+ close_tag: this.close_tag ? this.close_tag.toJSON() : null,
1259
+ is_void: this.is_void,
1260
+ };
1261
+ }
1262
+ treeInspect() {
1263
+ let output = "";
1264
+ output += `@ HTMLElementNode ${this.location.treeInspectWithLabel()}\n`;
1265
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1266
+ output += `├── open_tag: ${this.inspectNode(this.open_tag, "│ ")}`;
1267
+ output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
1268
+ output += `├── body: ${this.inspectArray(this.body, "│ ")}`;
1269
+ output += `├── close_tag: ${this.inspectNode(this.close_tag, "│ ")}`;
1270
+ output += `└── is_void: ${typeof this.is_void === 'boolean' ? String(this.is_void) : "∅"}\n`;
1271
+ // output += "\n";
1272
+ return output;
1273
+ }
1274
+ }
1275
+ class HTMLAttributeValueNode extends Node {
1276
+ open_quote;
1277
+ children;
1278
+ close_quote;
1279
+ quoted;
1280
+ static from(data) {
1281
+ return new HTMLAttributeValueNode({
1282
+ type: data.type,
1283
+ location: Location.from(data.location),
1284
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1285
+ open_quote: data.open_quote ? Token.from(data.open_quote) : null,
1286
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1287
+ close_quote: data.close_quote ? Token.from(data.close_quote) : null,
1288
+ quoted: data.quoted,
1289
+ });
1290
+ }
1291
+ constructor(props) {
1292
+ super(props.type, props.location, props.errors);
1293
+ this.open_quote = props.open_quote;
1294
+ this.children = props.children;
1295
+ this.close_quote = props.close_quote;
1296
+ this.quoted = props.quoted;
1297
+ }
1298
+ childNodes() {
1299
+ return [
1300
+ ...this.children,
1301
+ ].filter(node => node !== null && node !== undefined);
1302
+ }
1303
+ recursiveErrors() {
1304
+ return [
1305
+ ...this.errors,
1306
+ ...this.children.map(node => node.recursiveErrors()),
1307
+ ].flat();
1308
+ }
1309
+ toJSON() {
1310
+ return {
1311
+ ...super.toJSON(),
1312
+ type: "AST_HTML_ATTRIBUTE_VALUE_NODE",
1313
+ open_quote: this.open_quote ? this.open_quote.toJSON() : null,
1314
+ children: this.children.map(node => node.toJSON()),
1315
+ close_quote: this.close_quote ? this.close_quote.toJSON() : null,
1316
+ quoted: this.quoted,
1317
+ };
1318
+ }
1319
+ treeInspect() {
1320
+ let output = "";
1321
+ output += `@ HTMLAttributeValueNode ${this.location.treeInspectWithLabel()}\n`;
1322
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1323
+ output += `├── open_quote: ${this.open_quote ? this.open_quote.treeInspect() : "∅"}\n`;
1324
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1325
+ output += `├── close_quote: ${this.close_quote ? this.close_quote.treeInspect() : "∅"}\n`;
1326
+ output += `└── quoted: ${typeof this.quoted === 'boolean' ? String(this.quoted) : "∅"}\n`;
1327
+ // output += "\n";
1328
+ return output;
1329
+ }
1330
+ }
1331
+ class HTMLAttributeNameNode extends Node {
1332
+ name;
1333
+ static from(data) {
1334
+ return new HTMLAttributeNameNode({
1335
+ type: data.type,
1336
+ location: Location.from(data.location),
1337
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1338
+ name: data.name ? Token.from(data.name) : null,
1339
+ });
1340
+ }
1341
+ constructor(props) {
1342
+ super(props.type, props.location, props.errors);
1343
+ this.name = props.name;
1344
+ }
1345
+ childNodes() {
1346
+ return [].filter(node => node !== null && node !== undefined);
1347
+ }
1348
+ recursiveErrors() {
1349
+ return [
1350
+ ...this.errors,
1351
+ ].flat();
1352
+ }
1353
+ toJSON() {
1354
+ return {
1355
+ ...super.toJSON(),
1356
+ type: "AST_HTML_ATTRIBUTE_NAME_NODE",
1357
+ name: this.name ? this.name.toJSON() : null,
1358
+ };
1359
+ }
1360
+ treeInspect() {
1361
+ let output = "";
1362
+ output += `@ HTMLAttributeNameNode ${this.location.treeInspectWithLabel()}\n`;
1363
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1364
+ output += `└── name: ${this.name ? this.name.treeInspect() : "∅"}\n`;
1365
+ // output += "\n";
1366
+ return output;
1367
+ }
1368
+ }
1369
+ class HTMLAttributeNode extends Node {
1370
+ name;
1371
+ equals;
1372
+ value;
1373
+ static from(data) {
1374
+ return new HTMLAttributeNode({
1375
+ type: data.type,
1376
+ location: Location.from(data.location),
1377
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1378
+ name: data.name ? fromSerializedNode(data.name) : null,
1379
+ equals: data.equals ? Token.from(data.equals) : null,
1380
+ value: data.value ? fromSerializedNode(data.value) : null,
1381
+ });
1382
+ }
1383
+ constructor(props) {
1384
+ super(props.type, props.location, props.errors);
1385
+ this.name = props.name;
1386
+ this.equals = props.equals;
1387
+ this.value = props.value;
1388
+ }
1389
+ childNodes() {
1390
+ return [
1391
+ this.name,
1392
+ this.value,
1393
+ ].filter(node => node !== null && node !== undefined);
1394
+ }
1395
+ recursiveErrors() {
1396
+ return [
1397
+ ...this.errors,
1398
+ this.name ? this.name.recursiveErrors() : [],
1399
+ this.value ? this.value.recursiveErrors() : [],
1400
+ ].flat();
1401
+ }
1402
+ toJSON() {
1403
+ return {
1404
+ ...super.toJSON(),
1405
+ type: "AST_HTML_ATTRIBUTE_NODE",
1406
+ name: this.name ? this.name.toJSON() : null,
1407
+ equals: this.equals ? this.equals.toJSON() : null,
1408
+ value: this.value ? this.value.toJSON() : null,
1409
+ };
1410
+ }
1411
+ treeInspect() {
1412
+ let output = "";
1413
+ output += `@ HTMLAttributeNode ${this.location.treeInspectWithLabel()}\n`;
1414
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1415
+ output += `├── name: ${this.inspectNode(this.name, "│ ")}`;
1416
+ output += `├── equals: ${this.equals ? this.equals.treeInspect() : "∅"}\n`;
1417
+ output += `└── value: ${this.inspectNode(this.value, " ")}`;
1418
+ // output += "\n";
1419
+ return output;
1420
+ }
1421
+ }
1422
+ class HTMLTextNode extends Node {
1423
+ content;
1424
+ static from(data) {
1425
+ return new HTMLTextNode({
1426
+ type: data.type,
1427
+ location: Location.from(data.location),
1428
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1429
+ content: data.content,
1430
+ });
1431
+ }
1432
+ constructor(props) {
1433
+ super(props.type, props.location, props.errors);
1434
+ this.content = convertToUTF8(props.content);
1435
+ }
1436
+ childNodes() {
1437
+ return [].filter(node => node !== null && node !== undefined);
1438
+ }
1439
+ recursiveErrors() {
1440
+ return [
1441
+ ...this.errors,
1442
+ ].flat();
1443
+ }
1444
+ toJSON() {
1445
+ return {
1446
+ ...super.toJSON(),
1447
+ type: "AST_HTML_TEXT_NODE",
1448
+ content: this.content,
1449
+ };
1450
+ }
1451
+ treeInspect() {
1452
+ let output = "";
1453
+ output += `@ HTMLTextNode ${this.location.treeInspectWithLabel()}\n`;
1454
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1455
+ output += `└── content: ${this.content ? JSON.stringify(this.content) : "∅"}\n`;
1456
+ // output += "\n";
1457
+ return output;
1458
+ }
1459
+ }
1460
+ class HTMLCommentNode extends Node {
1461
+ comment_start;
1462
+ children;
1463
+ comment_end;
1464
+ static from(data) {
1465
+ return new HTMLCommentNode({
1466
+ type: data.type,
1467
+ location: Location.from(data.location),
1468
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1469
+ comment_start: data.comment_start ? Token.from(data.comment_start) : null,
1470
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1471
+ comment_end: data.comment_end ? Token.from(data.comment_end) : null,
1472
+ });
1473
+ }
1474
+ constructor(props) {
1475
+ super(props.type, props.location, props.errors);
1476
+ this.comment_start = props.comment_start;
1477
+ this.children = props.children;
1478
+ this.comment_end = props.comment_end;
1479
+ }
1480
+ childNodes() {
1481
+ return [
1482
+ ...this.children,
1483
+ ].filter(node => node !== null && node !== undefined);
1484
+ }
1485
+ recursiveErrors() {
1486
+ return [
1487
+ ...this.errors,
1488
+ ...this.children.map(node => node.recursiveErrors()),
1489
+ ].flat();
1490
+ }
1491
+ toJSON() {
1492
+ return {
1493
+ ...super.toJSON(),
1494
+ type: "AST_HTML_COMMENT_NODE",
1495
+ comment_start: this.comment_start ? this.comment_start.toJSON() : null,
1496
+ children: this.children.map(node => node.toJSON()),
1497
+ comment_end: this.comment_end ? this.comment_end.toJSON() : null,
1498
+ };
1499
+ }
1500
+ treeInspect() {
1501
+ let output = "";
1502
+ output += `@ HTMLCommentNode ${this.location.treeInspectWithLabel()}\n`;
1503
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1504
+ output += `├── comment_start: ${this.comment_start ? this.comment_start.treeInspect() : "∅"}\n`;
1505
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1506
+ output += `└── comment_end: ${this.comment_end ? this.comment_end.treeInspect() : "∅"}\n`;
1507
+ // output += "\n";
1508
+ return output;
1509
+ }
1510
+ }
1511
+ class HTMLDoctypeNode extends Node {
1512
+ tag_opening;
1513
+ children;
1514
+ tag_closing;
1515
+ static from(data) {
1516
+ return new HTMLDoctypeNode({
1517
+ type: data.type,
1518
+ location: Location.from(data.location),
1519
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1520
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1521
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1522
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1523
+ });
1524
+ }
1525
+ constructor(props) {
1526
+ super(props.type, props.location, props.errors);
1527
+ this.tag_opening = props.tag_opening;
1528
+ this.children = props.children;
1529
+ this.tag_closing = props.tag_closing;
1530
+ }
1531
+ childNodes() {
1532
+ return [
1533
+ ...this.children,
1534
+ ].filter(node => node !== null && node !== undefined);
1535
+ }
1536
+ recursiveErrors() {
1537
+ return [
1538
+ ...this.errors,
1539
+ ...this.children.map(node => node.recursiveErrors()),
1540
+ ].flat();
1541
+ }
1542
+ toJSON() {
1543
+ return {
1544
+ ...super.toJSON(),
1545
+ type: "AST_HTML_DOCTYPE_NODE",
1546
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1547
+ children: this.children.map(node => node.toJSON()),
1548
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1549
+ };
1550
+ }
1551
+ treeInspect() {
1552
+ let output = "";
1553
+ output += `@ HTMLDoctypeNode ${this.location.treeInspectWithLabel()}\n`;
1554
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1555
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1556
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
1557
+ output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1558
+ // output += "\n";
1559
+ return output;
1560
+ }
1561
+ }
1562
+ class WhitespaceNode extends Node {
1563
+ value;
1564
+ static from(data) {
1565
+ return new WhitespaceNode({
1566
+ type: data.type,
1567
+ location: Location.from(data.location),
1568
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1569
+ value: data.value ? Token.from(data.value) : null,
1570
+ });
1571
+ }
1572
+ constructor(props) {
1573
+ super(props.type, props.location, props.errors);
1574
+ this.value = props.value;
1575
+ }
1576
+ childNodes() {
1577
+ return [].filter(node => node !== null && node !== undefined);
1578
+ }
1579
+ recursiveErrors() {
1580
+ return [
1581
+ ...this.errors,
1582
+ ].flat();
1583
+ }
1584
+ toJSON() {
1585
+ return {
1586
+ ...super.toJSON(),
1587
+ type: "AST_WHITESPACE_NODE",
1588
+ value: this.value ? this.value.toJSON() : null,
1589
+ };
1590
+ }
1591
+ treeInspect() {
1592
+ let output = "";
1593
+ output += `@ WhitespaceNode ${this.location.treeInspectWithLabel()}\n`;
1594
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1595
+ output += `└── value: ${this.value ? this.value.treeInspect() : "∅"}\n`;
1596
+ // output += "\n";
1597
+ return output;
1598
+ }
1599
+ }
1600
+ class ERBContentNode extends Node {
1601
+ tag_opening;
1602
+ content;
1603
+ tag_closing;
1604
+ // no-op for analyzed_ruby
1605
+ parsed;
1606
+ valid;
1607
+ static from(data) {
1608
+ return new ERBContentNode({
1609
+ type: data.type,
1610
+ location: Location.from(data.location),
1611
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1612
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1613
+ content: data.content ? Token.from(data.content) : null,
1614
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1615
+ // no-op for analyzed_ruby
1616
+ parsed: data.parsed,
1617
+ valid: data.valid,
1618
+ });
1619
+ }
1620
+ constructor(props) {
1621
+ super(props.type, props.location, props.errors);
1622
+ this.tag_opening = props.tag_opening;
1623
+ this.content = props.content;
1624
+ this.tag_closing = props.tag_closing;
1625
+ // no-op for analyzed_ruby
1626
+ this.parsed = props.parsed;
1627
+ this.valid = props.valid;
1628
+ }
1629
+ childNodes() {
1630
+ return [].filter(node => node !== null && node !== undefined);
1631
+ }
1632
+ recursiveErrors() {
1633
+ return [
1634
+ ...this.errors,
1635
+ ].flat();
1636
+ }
1637
+ toJSON() {
1638
+ return {
1639
+ ...super.toJSON(),
1640
+ type: "AST_ERB_CONTENT_NODE",
1641
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1642
+ content: this.content ? this.content.toJSON() : null,
1643
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1644
+ // no-op for analyzed_ruby
1645
+ parsed: this.parsed,
1646
+ valid: this.valid,
1647
+ };
1648
+ }
1649
+ treeInspect() {
1650
+ let output = "";
1651
+ output += `@ ERBContentNode ${this.location.treeInspectWithLabel()}\n`;
1652
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1653
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1654
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1655
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1656
+ // no-op for analyzed_ruby
1657
+ output += `├── parsed: ${typeof this.parsed === 'boolean' ? String(this.parsed) : "∅"}\n`;
1658
+ output += `└── valid: ${typeof this.valid === 'boolean' ? String(this.valid) : "∅"}\n`;
1659
+ // output += "\n";
1660
+ return output;
1661
+ }
1662
+ }
1663
+ class ERBEndNode extends Node {
1664
+ tag_opening;
1665
+ content;
1666
+ tag_closing;
1667
+ static from(data) {
1668
+ return new ERBEndNode({
1669
+ type: data.type,
1670
+ location: Location.from(data.location),
1671
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1672
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1673
+ content: data.content ? Token.from(data.content) : null,
1674
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1675
+ });
1676
+ }
1677
+ constructor(props) {
1678
+ super(props.type, props.location, props.errors);
1679
+ this.tag_opening = props.tag_opening;
1680
+ this.content = props.content;
1681
+ this.tag_closing = props.tag_closing;
1682
+ }
1683
+ childNodes() {
1684
+ return [].filter(node => node !== null && node !== undefined);
1685
+ }
1686
+ recursiveErrors() {
1687
+ return [
1688
+ ...this.errors,
1689
+ ].flat();
1690
+ }
1691
+ toJSON() {
1692
+ return {
1693
+ ...super.toJSON(),
1694
+ type: "AST_ERB_END_NODE",
1695
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1696
+ content: this.content ? this.content.toJSON() : null,
1697
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1698
+ };
1699
+ }
1700
+ treeInspect() {
1701
+ let output = "";
1702
+ output += `@ ERBEndNode ${this.location.treeInspectWithLabel()}\n`;
1703
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1704
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1705
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1706
+ output += `└── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1707
+ // output += "\n";
1708
+ return output;
1709
+ }
1710
+ }
1711
+ class ERBElseNode extends Node {
1712
+ tag_opening;
1713
+ content;
1714
+ tag_closing;
1715
+ statements;
1716
+ static from(data) {
1717
+ return new ERBElseNode({
1718
+ type: data.type,
1719
+ location: Location.from(data.location),
1720
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1721
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1722
+ content: data.content ? Token.from(data.content) : null,
1723
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1724
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
1725
+ });
1726
+ }
1727
+ constructor(props) {
1728
+ super(props.type, props.location, props.errors);
1729
+ this.tag_opening = props.tag_opening;
1730
+ this.content = props.content;
1731
+ this.tag_closing = props.tag_closing;
1732
+ this.statements = props.statements;
1733
+ }
1734
+ childNodes() {
1735
+ return [
1736
+ ...this.statements,
1737
+ ].filter(node => node !== null && node !== undefined);
1738
+ }
1739
+ recursiveErrors() {
1740
+ return [
1741
+ ...this.errors,
1742
+ ...this.statements.map(node => node.recursiveErrors()),
1743
+ ].flat();
1744
+ }
1745
+ toJSON() {
1746
+ return {
1747
+ ...super.toJSON(),
1748
+ type: "AST_ERB_ELSE_NODE",
1749
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1750
+ content: this.content ? this.content.toJSON() : null,
1751
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1752
+ statements: this.statements.map(node => node.toJSON()),
1753
+ };
1754
+ }
1755
+ treeInspect() {
1756
+ let output = "";
1757
+ output += `@ ERBElseNode ${this.location.treeInspectWithLabel()}\n`;
1758
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1759
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1760
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1761
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1762
+ output += `└── statements: ${this.inspectArray(this.statements, " ")}`;
1763
+ // output += "\n";
1764
+ return output;
1765
+ }
1766
+ }
1767
+ class ERBIfNode extends Node {
1768
+ tag_opening;
1769
+ content;
1770
+ tag_closing;
1771
+ statements;
1772
+ subsequent;
1773
+ end_node;
1774
+ static from(data) {
1775
+ return new ERBIfNode({
1776
+ type: data.type,
1777
+ location: Location.from(data.location),
1778
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1779
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1780
+ content: data.content ? Token.from(data.content) : null,
1781
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1782
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
1783
+ subsequent: data.subsequent ? fromSerializedNode(data.subsequent) : null,
1784
+ end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
1785
+ });
1786
+ }
1787
+ constructor(props) {
1788
+ super(props.type, props.location, props.errors);
1789
+ this.tag_opening = props.tag_opening;
1790
+ this.content = props.content;
1791
+ this.tag_closing = props.tag_closing;
1792
+ this.statements = props.statements;
1793
+ this.subsequent = props.subsequent;
1794
+ this.end_node = props.end_node;
1795
+ }
1796
+ childNodes() {
1797
+ return [
1798
+ ...this.statements,
1799
+ this.subsequent,
1800
+ this.end_node,
1801
+ ].filter(node => node !== null && node !== undefined);
1802
+ }
1803
+ recursiveErrors() {
1804
+ return [
1805
+ ...this.errors,
1806
+ ...this.statements.map(node => node.recursiveErrors()),
1807
+ this.subsequent ? this.subsequent.recursiveErrors() : [],
1808
+ this.end_node ? this.end_node.recursiveErrors() : [],
1809
+ ].flat();
1810
+ }
1811
+ toJSON() {
1812
+ return {
1813
+ ...super.toJSON(),
1814
+ type: "AST_ERB_IF_NODE",
1815
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1816
+ content: this.content ? this.content.toJSON() : null,
1817
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1818
+ statements: this.statements.map(node => node.toJSON()),
1819
+ subsequent: this.subsequent ? this.subsequent.toJSON() : null,
1820
+ end_node: this.end_node ? this.end_node.toJSON() : null,
1821
+ };
1822
+ }
1823
+ treeInspect() {
1824
+ let output = "";
1825
+ output += `@ ERBIfNode ${this.location.treeInspectWithLabel()}\n`;
1826
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1827
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1828
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1829
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1830
+ output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
1831
+ output += `├── subsequent: ${this.inspectNode(this.subsequent, "│ ")}`;
1832
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
1833
+ // output += "\n";
1834
+ return output;
1835
+ }
1836
+ }
1837
+ class ERBBlockNode extends Node {
1838
+ tag_opening;
1839
+ content;
1840
+ tag_closing;
1841
+ body;
1842
+ end_node;
1843
+ static from(data) {
1844
+ return new ERBBlockNode({
1845
+ type: data.type,
1846
+ location: Location.from(data.location),
1847
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1848
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1849
+ content: data.content ? Token.from(data.content) : null,
1850
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1851
+ body: (data.body || []).map(node => fromSerializedNode(node)),
1852
+ end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
1853
+ });
1854
+ }
1855
+ constructor(props) {
1856
+ super(props.type, props.location, props.errors);
1857
+ this.tag_opening = props.tag_opening;
1858
+ this.content = props.content;
1859
+ this.tag_closing = props.tag_closing;
1860
+ this.body = props.body;
1861
+ this.end_node = props.end_node;
1862
+ }
1863
+ childNodes() {
1864
+ return [
1865
+ ...this.body,
1866
+ this.end_node,
1867
+ ].filter(node => node !== null && node !== undefined);
1868
+ }
1869
+ recursiveErrors() {
1870
+ return [
1871
+ ...this.errors,
1872
+ ...this.body.map(node => node.recursiveErrors()),
1873
+ this.end_node ? this.end_node.recursiveErrors() : [],
1874
+ ].flat();
1875
+ }
1876
+ toJSON() {
1877
+ return {
1878
+ ...super.toJSON(),
1879
+ type: "AST_ERB_BLOCK_NODE",
1880
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1881
+ content: this.content ? this.content.toJSON() : null,
1882
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1883
+ body: this.body.map(node => node.toJSON()),
1884
+ end_node: this.end_node ? this.end_node.toJSON() : null,
1885
+ };
1886
+ }
1887
+ treeInspect() {
1888
+ let output = "";
1889
+ output += `@ ERBBlockNode ${this.location.treeInspectWithLabel()}\n`;
1890
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1891
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1892
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1893
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1894
+ output += `├── body: ${this.inspectArray(this.body, "│ ")}`;
1895
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
1896
+ // output += "\n";
1897
+ return output;
1898
+ }
1899
+ }
1900
+ class ERBWhenNode extends Node {
1901
+ tag_opening;
1902
+ content;
1903
+ tag_closing;
1904
+ statements;
1905
+ static from(data) {
1906
+ return new ERBWhenNode({
1907
+ type: data.type,
1908
+ location: Location.from(data.location),
1909
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1910
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1911
+ content: data.content ? Token.from(data.content) : null,
1912
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1913
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
1914
+ });
1915
+ }
1916
+ constructor(props) {
1917
+ super(props.type, props.location, props.errors);
1918
+ this.tag_opening = props.tag_opening;
1919
+ this.content = props.content;
1920
+ this.tag_closing = props.tag_closing;
1921
+ this.statements = props.statements;
1922
+ }
1923
+ childNodes() {
1924
+ return [
1925
+ ...this.statements,
1926
+ ].filter(node => node !== null && node !== undefined);
1927
+ }
1928
+ recursiveErrors() {
1929
+ return [
1930
+ ...this.errors,
1931
+ ...this.statements.map(node => node.recursiveErrors()),
1932
+ ].flat();
1933
+ }
1934
+ toJSON() {
1935
+ return {
1936
+ ...super.toJSON(),
1937
+ type: "AST_ERB_WHEN_NODE",
1938
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
1939
+ content: this.content ? this.content.toJSON() : null,
1940
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
1941
+ statements: this.statements.map(node => node.toJSON()),
1942
+ };
1943
+ }
1944
+ treeInspect() {
1945
+ let output = "";
1946
+ output += `@ ERBWhenNode ${this.location.treeInspectWithLabel()}\n`;
1947
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
1948
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
1949
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
1950
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
1951
+ output += `└── statements: ${this.inspectArray(this.statements, " ")}`;
1952
+ // output += "\n";
1953
+ return output;
1954
+ }
1955
+ }
1956
+ class ERBCaseNode extends Node {
1957
+ tag_opening;
1958
+ content;
1959
+ tag_closing;
1960
+ children;
1961
+ conditions;
1962
+ else_clause;
1963
+ end_node;
1964
+ static from(data) {
1965
+ return new ERBCaseNode({
1966
+ type: data.type,
1967
+ location: Location.from(data.location),
1968
+ errors: (data.errors || []).map(error => HerbError.from(error)),
1969
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
1970
+ content: data.content ? Token.from(data.content) : null,
1971
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
1972
+ children: (data.children || []).map(node => fromSerializedNode(node)),
1973
+ conditions: (data.conditions || []).map(node => fromSerializedNode(node)),
1974
+ else_clause: data.else_clause ? fromSerializedNode(data.else_clause) : null,
1975
+ end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
1976
+ });
1977
+ }
1978
+ constructor(props) {
1979
+ super(props.type, props.location, props.errors);
1980
+ this.tag_opening = props.tag_opening;
1981
+ this.content = props.content;
1982
+ this.tag_closing = props.tag_closing;
1983
+ this.children = props.children;
1984
+ this.conditions = props.conditions;
1985
+ this.else_clause = props.else_clause;
1986
+ this.end_node = props.end_node;
1987
+ }
1988
+ childNodes() {
1989
+ return [
1990
+ ...this.children,
1991
+ ...this.conditions,
1992
+ this.else_clause,
1993
+ this.end_node,
1994
+ ].filter(node => node !== null && node !== undefined);
1995
+ }
1996
+ recursiveErrors() {
1997
+ return [
1998
+ ...this.errors,
1999
+ ...this.children.map(node => node.recursiveErrors()),
2000
+ ...this.conditions.map(node => node.recursiveErrors()),
2001
+ this.else_clause ? this.else_clause.recursiveErrors() : [],
2002
+ this.end_node ? this.end_node.recursiveErrors() : [],
2003
+ ].flat();
2004
+ }
2005
+ toJSON() {
2006
+ return {
2007
+ ...super.toJSON(),
2008
+ type: "AST_ERB_CASE_NODE",
2009
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2010
+ content: this.content ? this.content.toJSON() : null,
2011
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2012
+ children: this.children.map(node => node.toJSON()),
2013
+ conditions: this.conditions.map(node => node.toJSON()),
2014
+ else_clause: this.else_clause ? this.else_clause.toJSON() : null,
2015
+ end_node: this.end_node ? this.end_node.toJSON() : null,
2016
+ };
2017
+ }
2018
+ treeInspect() {
2019
+ let output = "";
2020
+ output += `@ ERBCaseNode ${this.location.treeInspectWithLabel()}\n`;
2021
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2022
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2023
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2024
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2025
+ output += `├── children: ${this.inspectArray(this.children, "│ ")}`;
2026
+ output += `├── conditions: ${this.inspectArray(this.conditions, "│ ")}`;
2027
+ output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
2028
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2029
+ // output += "\n";
2030
+ return output;
2031
+ }
2032
+ }
2033
+ class ERBWhileNode extends Node {
2034
+ tag_opening;
2035
+ content;
2036
+ tag_closing;
2037
+ statements;
2038
+ end_node;
2039
+ static from(data) {
2040
+ return new ERBWhileNode({
2041
+ type: data.type,
2042
+ location: Location.from(data.location),
2043
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2044
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2045
+ content: data.content ? Token.from(data.content) : null,
2046
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2047
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
2048
+ end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2049
+ });
2050
+ }
2051
+ constructor(props) {
2052
+ super(props.type, props.location, props.errors);
2053
+ this.tag_opening = props.tag_opening;
2054
+ this.content = props.content;
2055
+ this.tag_closing = props.tag_closing;
2056
+ this.statements = props.statements;
2057
+ this.end_node = props.end_node;
2058
+ }
2059
+ childNodes() {
2060
+ return [
2061
+ ...this.statements,
2062
+ this.end_node,
2063
+ ].filter(node => node !== null && node !== undefined);
2064
+ }
2065
+ recursiveErrors() {
2066
+ return [
2067
+ ...this.errors,
2068
+ ...this.statements.map(node => node.recursiveErrors()),
2069
+ this.end_node ? this.end_node.recursiveErrors() : [],
2070
+ ].flat();
2071
+ }
2072
+ toJSON() {
2073
+ return {
2074
+ ...super.toJSON(),
2075
+ type: "AST_ERB_WHILE_NODE",
2076
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2077
+ content: this.content ? this.content.toJSON() : null,
2078
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2079
+ statements: this.statements.map(node => node.toJSON()),
2080
+ end_node: this.end_node ? this.end_node.toJSON() : null,
2081
+ };
2082
+ }
2083
+ treeInspect() {
2084
+ let output = "";
2085
+ output += `@ ERBWhileNode ${this.location.treeInspectWithLabel()}\n`;
2086
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2087
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2088
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2089
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2090
+ output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2091
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2092
+ // output += "\n";
2093
+ return output;
2094
+ }
2095
+ }
2096
+ class ERBUntilNode extends Node {
2097
+ tag_opening;
2098
+ content;
2099
+ tag_closing;
2100
+ statements;
2101
+ end_node;
2102
+ static from(data) {
2103
+ return new ERBUntilNode({
2104
+ type: data.type,
2105
+ location: Location.from(data.location),
2106
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2107
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2108
+ content: data.content ? Token.from(data.content) : null,
2109
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2110
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
2111
+ end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2112
+ });
2113
+ }
2114
+ constructor(props) {
2115
+ super(props.type, props.location, props.errors);
2116
+ this.tag_opening = props.tag_opening;
2117
+ this.content = props.content;
2118
+ this.tag_closing = props.tag_closing;
2119
+ this.statements = props.statements;
2120
+ this.end_node = props.end_node;
2121
+ }
2122
+ childNodes() {
2123
+ return [
2124
+ ...this.statements,
2125
+ this.end_node,
2126
+ ].filter(node => node !== null && node !== undefined);
2127
+ }
2128
+ recursiveErrors() {
2129
+ return [
2130
+ ...this.errors,
2131
+ ...this.statements.map(node => node.recursiveErrors()),
2132
+ this.end_node ? this.end_node.recursiveErrors() : [],
2133
+ ].flat();
2134
+ }
2135
+ toJSON() {
2136
+ return {
2137
+ ...super.toJSON(),
2138
+ type: "AST_ERB_UNTIL_NODE",
2139
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2140
+ content: this.content ? this.content.toJSON() : null,
2141
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2142
+ statements: this.statements.map(node => node.toJSON()),
2143
+ end_node: this.end_node ? this.end_node.toJSON() : null,
2144
+ };
2145
+ }
2146
+ treeInspect() {
2147
+ let output = "";
2148
+ output += `@ ERBUntilNode ${this.location.treeInspectWithLabel()}\n`;
2149
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2150
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2151
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2152
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2153
+ output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2154
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2155
+ // output += "\n";
2156
+ return output;
2157
+ }
2158
+ }
2159
+ class ERBForNode extends Node {
2160
+ tag_opening;
2161
+ content;
2162
+ tag_closing;
2163
+ statements;
2164
+ end_node;
2165
+ static from(data) {
2166
+ return new ERBForNode({
2167
+ type: data.type,
2168
+ location: Location.from(data.location),
2169
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2170
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2171
+ content: data.content ? Token.from(data.content) : null,
2172
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2173
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
2174
+ end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2175
+ });
2176
+ }
2177
+ constructor(props) {
2178
+ super(props.type, props.location, props.errors);
2179
+ this.tag_opening = props.tag_opening;
2180
+ this.content = props.content;
2181
+ this.tag_closing = props.tag_closing;
2182
+ this.statements = props.statements;
2183
+ this.end_node = props.end_node;
2184
+ }
2185
+ childNodes() {
2186
+ return [
2187
+ ...this.statements,
2188
+ this.end_node,
2189
+ ].filter(node => node !== null && node !== undefined);
2190
+ }
2191
+ recursiveErrors() {
2192
+ return [
2193
+ ...this.errors,
2194
+ ...this.statements.map(node => node.recursiveErrors()),
2195
+ this.end_node ? this.end_node.recursiveErrors() : [],
2196
+ ].flat();
2197
+ }
2198
+ toJSON() {
2199
+ return {
2200
+ ...super.toJSON(),
2201
+ type: "AST_ERB_FOR_NODE",
2202
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2203
+ content: this.content ? this.content.toJSON() : null,
2204
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2205
+ statements: this.statements.map(node => node.toJSON()),
2206
+ end_node: this.end_node ? this.end_node.toJSON() : null,
2207
+ };
2208
+ }
2209
+ treeInspect() {
2210
+ let output = "";
2211
+ output += `@ ERBForNode ${this.location.treeInspectWithLabel()}\n`;
2212
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2213
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2214
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2215
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2216
+ output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2217
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2218
+ // output += "\n";
2219
+ return output;
2220
+ }
2221
+ }
2222
+ class ERBRescueNode extends Node {
2223
+ tag_opening;
2224
+ content;
2225
+ tag_closing;
2226
+ statements;
2227
+ subsequent;
2228
+ static from(data) {
2229
+ return new ERBRescueNode({
2230
+ type: data.type,
2231
+ location: Location.from(data.location),
2232
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2233
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2234
+ content: data.content ? Token.from(data.content) : null,
2235
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2236
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
2237
+ subsequent: data.subsequent ? fromSerializedNode(data.subsequent) : null,
2238
+ });
2239
+ }
2240
+ constructor(props) {
2241
+ super(props.type, props.location, props.errors);
2242
+ this.tag_opening = props.tag_opening;
2243
+ this.content = props.content;
2244
+ this.tag_closing = props.tag_closing;
2245
+ this.statements = props.statements;
2246
+ this.subsequent = props.subsequent;
2247
+ }
2248
+ childNodes() {
2249
+ return [
2250
+ ...this.statements,
2251
+ this.subsequent,
2252
+ ].filter(node => node !== null && node !== undefined);
2253
+ }
2254
+ recursiveErrors() {
2255
+ return [
2256
+ ...this.errors,
2257
+ ...this.statements.map(node => node.recursiveErrors()),
2258
+ this.subsequent ? this.subsequent.recursiveErrors() : [],
2259
+ ].flat();
2260
+ }
2261
+ toJSON() {
2262
+ return {
2263
+ ...super.toJSON(),
2264
+ type: "AST_ERB_RESCUE_NODE",
2265
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2266
+ content: this.content ? this.content.toJSON() : null,
2267
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2268
+ statements: this.statements.map(node => node.toJSON()),
2269
+ subsequent: this.subsequent ? this.subsequent.toJSON() : null,
2270
+ };
2271
+ }
2272
+ treeInspect() {
2273
+ let output = "";
2274
+ output += `@ ERBRescueNode ${this.location.treeInspectWithLabel()}\n`;
2275
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2276
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2277
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2278
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2279
+ output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2280
+ output += `└── subsequent: ${this.inspectNode(this.subsequent, " ")}`;
2281
+ // output += "\n";
2282
+ return output;
2283
+ }
2284
+ }
2285
+ class ERBEnsureNode extends Node {
2286
+ tag_opening;
2287
+ content;
2288
+ tag_closing;
2289
+ statements;
2290
+ static from(data) {
2291
+ return new ERBEnsureNode({
2292
+ type: data.type,
2293
+ location: Location.from(data.location),
2294
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2295
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2296
+ content: data.content ? Token.from(data.content) : null,
2297
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2298
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
2299
+ });
2300
+ }
2301
+ constructor(props) {
2302
+ super(props.type, props.location, props.errors);
2303
+ this.tag_opening = props.tag_opening;
2304
+ this.content = props.content;
2305
+ this.tag_closing = props.tag_closing;
2306
+ this.statements = props.statements;
2307
+ }
2308
+ childNodes() {
2309
+ return [
2310
+ ...this.statements,
2311
+ ].filter(node => node !== null && node !== undefined);
2312
+ }
2313
+ recursiveErrors() {
2314
+ return [
2315
+ ...this.errors,
2316
+ ...this.statements.map(node => node.recursiveErrors()),
2317
+ ].flat();
2318
+ }
2319
+ toJSON() {
2320
+ return {
2321
+ ...super.toJSON(),
2322
+ type: "AST_ERB_ENSURE_NODE",
2323
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2324
+ content: this.content ? this.content.toJSON() : null,
2325
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2326
+ statements: this.statements.map(node => node.toJSON()),
2327
+ };
2328
+ }
2329
+ treeInspect() {
2330
+ let output = "";
2331
+ output += `@ ERBEnsureNode ${this.location.treeInspectWithLabel()}\n`;
2332
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2333
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2334
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2335
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2336
+ output += `└── statements: ${this.inspectArray(this.statements, " ")}`;
2337
+ // output += "\n";
2338
+ return output;
2339
+ }
2340
+ }
2341
+ class ERBBeginNode extends Node {
2342
+ tag_opening;
2343
+ content;
2344
+ tag_closing;
2345
+ statements;
2346
+ rescue_clause;
2347
+ else_clause;
2348
+ ensure_clause;
2349
+ end_node;
2350
+ static from(data) {
2351
+ return new ERBBeginNode({
2352
+ type: data.type,
2353
+ location: Location.from(data.location),
2354
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2355
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2356
+ content: data.content ? Token.from(data.content) : null,
2357
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2358
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
2359
+ rescue_clause: data.rescue_clause ? fromSerializedNode(data.rescue_clause) : null,
2360
+ else_clause: data.else_clause ? fromSerializedNode(data.else_clause) : null,
2361
+ ensure_clause: data.ensure_clause ? fromSerializedNode(data.ensure_clause) : null,
2362
+ end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2363
+ });
2364
+ }
2365
+ constructor(props) {
2366
+ super(props.type, props.location, props.errors);
2367
+ this.tag_opening = props.tag_opening;
2368
+ this.content = props.content;
2369
+ this.tag_closing = props.tag_closing;
2370
+ this.statements = props.statements;
2371
+ this.rescue_clause = props.rescue_clause;
2372
+ this.else_clause = props.else_clause;
2373
+ this.ensure_clause = props.ensure_clause;
2374
+ this.end_node = props.end_node;
2375
+ }
2376
+ childNodes() {
2377
+ return [
2378
+ ...this.statements,
2379
+ this.rescue_clause,
2380
+ this.else_clause,
2381
+ this.ensure_clause,
2382
+ this.end_node,
2383
+ ].filter(node => node !== null && node !== undefined);
2384
+ }
2385
+ recursiveErrors() {
2386
+ return [
2387
+ ...this.errors,
2388
+ ...this.statements.map(node => node.recursiveErrors()),
2389
+ this.rescue_clause ? this.rescue_clause.recursiveErrors() : [],
2390
+ this.else_clause ? this.else_clause.recursiveErrors() : [],
2391
+ this.ensure_clause ? this.ensure_clause.recursiveErrors() : [],
2392
+ this.end_node ? this.end_node.recursiveErrors() : [],
2393
+ ].flat();
2394
+ }
2395
+ toJSON() {
2396
+ return {
2397
+ ...super.toJSON(),
2398
+ type: "AST_ERB_BEGIN_NODE",
2399
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2400
+ content: this.content ? this.content.toJSON() : null,
2401
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2402
+ statements: this.statements.map(node => node.toJSON()),
2403
+ rescue_clause: this.rescue_clause ? this.rescue_clause.toJSON() : null,
2404
+ else_clause: this.else_clause ? this.else_clause.toJSON() : null,
2405
+ ensure_clause: this.ensure_clause ? this.ensure_clause.toJSON() : null,
2406
+ end_node: this.end_node ? this.end_node.toJSON() : null,
2407
+ };
2408
+ }
2409
+ treeInspect() {
2410
+ let output = "";
2411
+ output += `@ ERBBeginNode ${this.location.treeInspectWithLabel()}\n`;
2412
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2413
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2414
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2415
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2416
+ output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2417
+ output += `├── rescue_clause: ${this.inspectNode(this.rescue_clause, "│ ")}`;
2418
+ output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
2419
+ output += `├── ensure_clause: ${this.inspectNode(this.ensure_clause, "│ ")}`;
2420
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2421
+ // output += "\n";
2422
+ return output;
2423
+ }
2424
+ }
2425
+ class ERBUnlessNode extends Node {
2426
+ tag_opening;
2427
+ content;
2428
+ tag_closing;
2429
+ statements;
2430
+ else_clause;
2431
+ end_node;
2432
+ static from(data) {
2433
+ return new ERBUnlessNode({
2434
+ type: data.type,
2435
+ location: Location.from(data.location),
2436
+ errors: (data.errors || []).map(error => HerbError.from(error)),
2437
+ tag_opening: data.tag_opening ? Token.from(data.tag_opening) : null,
2438
+ content: data.content ? Token.from(data.content) : null,
2439
+ tag_closing: data.tag_closing ? Token.from(data.tag_closing) : null,
2440
+ statements: (data.statements || []).map(node => fromSerializedNode(node)),
2441
+ else_clause: data.else_clause ? fromSerializedNode(data.else_clause) : null,
2442
+ end_node: data.end_node ? fromSerializedNode(data.end_node) : null,
2443
+ });
2444
+ }
2445
+ constructor(props) {
2446
+ super(props.type, props.location, props.errors);
2447
+ this.tag_opening = props.tag_opening;
2448
+ this.content = props.content;
2449
+ this.tag_closing = props.tag_closing;
2450
+ this.statements = props.statements;
2451
+ this.else_clause = props.else_clause;
2452
+ this.end_node = props.end_node;
2453
+ }
2454
+ childNodes() {
2455
+ return [
2456
+ ...this.statements,
2457
+ this.else_clause,
2458
+ this.end_node,
2459
+ ].filter(node => node !== null && node !== undefined);
2460
+ }
2461
+ recursiveErrors() {
2462
+ return [
2463
+ ...this.errors,
2464
+ ...this.statements.map(node => node.recursiveErrors()),
2465
+ this.else_clause ? this.else_clause.recursiveErrors() : [],
2466
+ this.end_node ? this.end_node.recursiveErrors() : [],
2467
+ ].flat();
2468
+ }
2469
+ toJSON() {
2470
+ return {
2471
+ ...super.toJSON(),
2472
+ type: "AST_ERB_UNLESS_NODE",
2473
+ tag_opening: this.tag_opening ? this.tag_opening.toJSON() : null,
2474
+ content: this.content ? this.content.toJSON() : null,
2475
+ tag_closing: this.tag_closing ? this.tag_closing.toJSON() : null,
2476
+ statements: this.statements.map(node => node.toJSON()),
2477
+ else_clause: this.else_clause ? this.else_clause.toJSON() : null,
2478
+ end_node: this.end_node ? this.end_node.toJSON() : null,
2479
+ };
2480
+ }
2481
+ treeInspect() {
2482
+ let output = "";
2483
+ output += `@ ERBUnlessNode ${this.location.treeInspectWithLabel()}\n`;
2484
+ output += `├── errors: ${this.inspectArray(this.errors, "│ ")}`;
2485
+ output += `├── tag_opening: ${this.tag_opening ? this.tag_opening.treeInspect() : "∅"}\n`;
2486
+ output += `├── content: ${this.content ? this.content.treeInspect() : "∅"}\n`;
2487
+ output += `├── tag_closing: ${this.tag_closing ? this.tag_closing.treeInspect() : "∅"}\n`;
2488
+ output += `├── statements: ${this.inspectArray(this.statements, "│ ")}`;
2489
+ output += `├── else_clause: ${this.inspectNode(this.else_clause, "│ ")}`;
2490
+ output += `└── end_node: ${this.inspectNode(this.end_node, " ")}`;
2491
+ // output += "\n";
2492
+ return output;
2493
+ }
2494
+ }
2495
+
2496
+ class HerbWarning {
2497
+ message;
2498
+ location;
2499
+ static from(warning) {
2500
+ return new HerbWarning(warning.message, Location.from(warning.location));
2501
+ }
2502
+ constructor(message, location) {
2503
+ this.message = message;
2504
+ this.location = location;
2505
+ }
2506
+ }
2507
+
2508
+ /**
2509
+ * Represents the result of a parsing operation, extending the base `Result` class.
2510
+ * It contains the parsed document node, source code, warnings, and errors.
2511
+ */
2512
+ class ParseResult extends Result {
2513
+ /** The document node generated from the source code. */
2514
+ value;
2515
+ /**
2516
+ * Creates a `ParseResult` instance from a serialized result.
2517
+ * @param result - The serialized parse result containing the value and source.
2518
+ * @returns A new `ParseResult` instance.
2519
+ */
2520
+ static from(result) {
2521
+ return new ParseResult(DocumentNode.from(result.value), result.source, result.warnings.map((warning) => HerbWarning.from(warning)), result.errors.map((error) => HerbError.from(error)));
2522
+ }
2523
+ /**
2524
+ * Constructs a new `ParseResult`.
2525
+ * @param value - The document node.
2526
+ * @param source - The source code that was parsed.
2527
+ * @param warnings - An array of warnings encountered during parsing.
2528
+ * @param errors - An array of errors encountered during parsing.
2529
+ */
2530
+ constructor(value, source, warnings = [], errors = []) {
2531
+ super(source, warnings, errors);
2532
+ this.value = value;
2533
+ }
2534
+ /**
2535
+ * Determines if the parsing failed.
2536
+ * @returns `true` if there are errors, otherwise `false`.
2537
+ */
2538
+ failed() {
2539
+ // TODO: this should probably be recursive as noted in the Ruby version
2540
+ return this.errors.length > 0 || this.value.errors.length > 0;
2541
+ }
2542
+ /**
2543
+ * Determines if the parsing was successful.
2544
+ * @returns `true` if there are no errors, otherwise `false`.
2545
+ */
2546
+ success() {
2547
+ return !this.failed();
2548
+ }
2549
+ /**
2550
+ * Returns a pretty-printed JSON string of the errors.
2551
+ * @returns A string representation of the errors.
2552
+ */
2553
+ prettyErrors() {
2554
+ return JSON.stringify([...this.errors, ...this.value.errors], null, 2);
2555
+ }
2556
+ recursiveErrors() {
2557
+ return [...this.errors, ...this.value.recursiveErrors()];
2558
+ }
2559
+ /**
2560
+ * Returns a pretty-printed string of the parse result.
2561
+ * @returns A string representation of the parse result.
2562
+ */
2563
+ inspect() {
2564
+ return this.value.inspect();
2565
+ }
2566
+ /**
2567
+ * Accepts a visitor to traverse the document node.
2568
+ * @param visitor - The visitor instance.
2569
+ */
2570
+ visit(visitor) {
2571
+ visitor.visit(this.value);
2572
+ }
2573
+ }
2574
+
2575
+ /**
2576
+ * The main Herb parser interface, providing methods to lex and parse input.
2577
+ */
2578
+ class HerbBackend {
2579
+ /** The backend instance handling lexing and parsing. */
2580
+ backend = undefined;
2581
+ backendPromise;
2582
+ /**
2583
+ * Creates a new Herb instance.
2584
+ * @param backendPromise - A promise resolving to a `LibHerbBackend` implementation for lexing and parsing.
2585
+ * @throws Error if no valid backend is provided.
2586
+ */
2587
+ constructor(backendPromise) {
2588
+ if (!backendPromise) {
2589
+ throw new Error("No LibHerb backend provided");
2590
+ }
2591
+ this.backendPromise = backendPromise;
2592
+ }
2593
+ /**
2594
+ * Loads the backend by resolving the backend promise.
2595
+ * @returns A promise containing the resolved `HerbBackend` instance after loading it.
2596
+ */
2597
+ async load() {
2598
+ const backend = await this.backendPromise();
2599
+ this.backend = backend;
2600
+ return this;
2601
+ }
2602
+ /**
2603
+ * Lexes the given source string into a `LexResult`.
2604
+ * @param source - The source code to lex.
2605
+ * @returns A `LexResult` instance.
2606
+ * @throws Error if the backend is not loaded.
2607
+ */
2608
+ lex(source) {
2609
+ this.ensureBackend();
2610
+ return LexResult.from(this.backend.lex(ensureString(source)));
2611
+ }
2612
+ /**
2613
+ * Lexes a file.
2614
+ * @param path - The file path to lex.
2615
+ * @returns A `LexResult` instance.
2616
+ * @throws Error if the backend is not loaded.
2617
+ */
2618
+ lexFile(path) {
2619
+ this.ensureBackend();
2620
+ return LexResult.from(this.backend.lexFile(ensureString(path)));
2621
+ }
2622
+ /**
2623
+ * Parses the given source string into a `ParseResult`.
2624
+ * @param source - The source code to parse.
2625
+ * @returns A `ParseResult` instance.
2626
+ * @throws Error if the backend is not loaded.
2627
+ */
2628
+ parse(source) {
2629
+ this.ensureBackend();
2630
+ return ParseResult.from(this.backend.parse(ensureString(source)));
2631
+ }
2632
+ /**
2633
+ * Parses a file.
2634
+ * @param path - The file path to parse.
2635
+ * @returns A `ParseResult` instance.
2636
+ * @throws Error if the backend is not loaded.
2637
+ */
2638
+ parseFile(path) {
2639
+ this.ensureBackend();
2640
+ return ParseResult.from(this.backend.parseFile(ensureString(path)));
2641
+ }
2642
+ /**
2643
+ * Extracts embedded Ruby code from the given source.
2644
+ * @param source - The source code to extract Ruby from.
2645
+ * @returns The extracted Ruby code as a string.
2646
+ * @throws Error if the backend is not loaded.
2647
+ */
2648
+ extractRuby(source) {
2649
+ this.ensureBackend();
2650
+ return this.backend.extractRuby(ensureString(source));
2651
+ }
2652
+ /**
2653
+ * Extracts HTML from the given source.
2654
+ * @param source - The source code to extract HTML from.
2655
+ * @returns The extracted HTML as a string.
2656
+ * @throws Error if the backend is not loaded.
2657
+ */
2658
+ extractHTML(source) {
2659
+ this.ensureBackend();
2660
+ return this.backend.extractHTML(ensureString(source));
2661
+ }
2662
+ /**
2663
+ * Gets the Herb version information, including the core and backend versions.
2664
+ * @returns A version string containing backend, core, and libherb versions.
2665
+ * @throws Error if the backend is not loaded.
2666
+ */
2667
+ get version() {
2668
+ this.ensureBackend();
2669
+ const backend = this.backendVersion();
2670
+ const core = `${packageJSON.name}@${packageJSON.version}`;
2671
+ const libherb = this.backend.version();
2672
+ return `${backend}, ${core}, ${libherb}`;
2673
+ }
2674
+ /**
2675
+ * Ensures that the backend is loaded.
2676
+ * @throws Error if the backend is not loaded.
2677
+ */
2678
+ ensureBackend() {
2679
+ if (!this.isLoaded) {
2680
+ throw new Error("Herb backend is not loaded. Call `await Herb.load()` first.");
2681
+ }
2682
+ }
2683
+ /**
2684
+ * Checks if the backend is loaded.
2685
+ * @returns True if the backend is loaded, false otherwise.
2686
+ */
2687
+ get isLoaded() {
2688
+ return this.backend !== undefined;
2689
+ }
2690
+ }
2691
+
2692
+ /**
2693
+ * Represents a visitor that can traverse nodes.
2694
+ */
2695
+ class Visitor {
2696
+ /**
2697
+ * Visits a node and performs an action.
2698
+ * @param node - The node to visit.
2699
+ */
2700
+ visit(node) {
2701
+ console.log("Node", node); // TODO: implement
2702
+ }
2703
+ }
2704
+
2705
+ exports.ASTNode = ASTNode;
2706
+ exports.DocumentNode = DocumentNode;
2707
+ exports.ERBBeginNode = ERBBeginNode;
2708
+ exports.ERBBlockNode = ERBBlockNode;
2709
+ exports.ERBCaseNode = ERBCaseNode;
2710
+ exports.ERBContentNode = ERBContentNode;
2711
+ exports.ERBElseNode = ERBElseNode;
2712
+ exports.ERBEndNode = ERBEndNode;
2713
+ exports.ERBEnsureNode = ERBEnsureNode;
2714
+ exports.ERBForNode = ERBForNode;
2715
+ exports.ERBIfNode = ERBIfNode;
2716
+ exports.ERBRescueNode = ERBRescueNode;
2717
+ exports.ERBUnlessNode = ERBUnlessNode;
2718
+ exports.ERBUntilNode = ERBUntilNode;
2719
+ exports.ERBWhenNode = ERBWhenNode;
2720
+ exports.ERBWhileNode = ERBWhileNode;
2721
+ exports.HTMLAttributeNameNode = HTMLAttributeNameNode;
2722
+ exports.HTMLAttributeNode = HTMLAttributeNode;
2723
+ exports.HTMLAttributeValueNode = HTMLAttributeValueNode;
2724
+ exports.HTMLCloseTagNode = HTMLCloseTagNode;
2725
+ exports.HTMLCommentNode = HTMLCommentNode;
2726
+ exports.HTMLDoctypeNode = HTMLDoctypeNode;
2727
+ exports.HTMLElementNode = HTMLElementNode;
2728
+ exports.HTMLOpenTagNode = HTMLOpenTagNode;
2729
+ exports.HTMLSelfCloseTagNode = HTMLSelfCloseTagNode;
2730
+ exports.HTMLTextNode = HTMLTextNode;
2731
+ exports.HerbBackend = HerbBackend;
2732
+ exports.LexResult = LexResult;
2733
+ exports.LiteralNode = LiteralNode;
2734
+ exports.Location = Location;
2735
+ exports.MissingClosingTagError = MissingClosingTagError;
2736
+ exports.MissingOpeningTagError = MissingOpeningTagError;
2737
+ exports.ParseResult = ParseResult;
2738
+ exports.Position = Position;
2739
+ exports.QuotesMismatchError = QuotesMismatchError;
2740
+ exports.Range = Range;
2741
+ exports.Result = Result;
2742
+ exports.RubyParseError = RubyParseError;
2743
+ exports.TagNamesMismatchError = TagNamesMismatchError;
2744
+ exports.Token = Token;
2745
+ exports.TokenList = TokenList;
2746
+ exports.UnclosedElementError = UnclosedElementError;
2747
+ exports.UnexpectedError = UnexpectedError;
2748
+ exports.UnexpectedTokenError = UnexpectedTokenError;
2749
+ exports.Visitor = Visitor;
2750
+ exports.VoidElementClosingTagError = VoidElementClosingTagError;
2751
+ exports.WhitespaceNode = WhitespaceNode;
2752
+ exports._TYPECHECK = _TYPECHECK;
2753
+ exports.convertToUTF8 = convertToUTF8;
2754
+ exports.ensureLibHerbBackend = ensureLibHerbBackend;
2755
+ exports.ensureString = ensureString;
2756
+ exports.fromSerializedError = fromSerializedError;
2757
+ exports.fromSerializedNode = fromSerializedNode;
2758
+ exports.isLibHerbBackend = isLibHerbBackend;
2759
+ //# sourceMappingURL=herb-core.cjs.map