@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
package/src/errors.ts ADDED
@@ -0,0 +1,820 @@
1
+ // NOTE: This file is generated by the templates/template.rb script and should not
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release/templates/javascript/packages/core/src/errors.ts.erb
3
+
4
+ import { Location, SerializedLocation } from "./location.js"
5
+ import { Token, SerializedToken } from "./token.js"
6
+ import { HerbError, SerializedHerbError } from "./error.js"
7
+
8
+ type HerbDiagnostic = {
9
+ line: number
10
+ column: number
11
+ endLine: number
12
+ endColumn: number
13
+ message: string
14
+ severity: "error" | "warning" | "info"
15
+ }
16
+
17
+ export type HerbErrorType =
18
+ | "UNEXPECTED_ERROR"
19
+ | "UNEXPECTED_TOKEN_ERROR"
20
+ | "MISSING_OPENING_TAG_ERROR"
21
+ | "MISSING_CLOSING_TAG_ERROR"
22
+ | "TAG_NAMES_MISMATCH_ERROR"
23
+ | "QUOTES_MISMATCH_ERROR"
24
+ | "VOID_ELEMENT_CLOSING_TAG_ERROR"
25
+ | "UNCLOSED_ELEMENT_ERROR"
26
+ | "RUBY_PARSE_ERROR"
27
+
28
+ export type SerializedErrorType = string
29
+
30
+ export function fromSerializedError(error: SerializedHerbError): HerbError {
31
+ switch (error.type) {
32
+ case "UNEXPECTED_ERROR": return UnexpectedError.from(error as SerializedUnexpectedError);
33
+ case "UNEXPECTED_TOKEN_ERROR": return UnexpectedTokenError.from(error as SerializedUnexpectedTokenError);
34
+ case "MISSING_OPENING_TAG_ERROR": return MissingOpeningTagError.from(error as SerializedMissingOpeningTagError);
35
+ case "MISSING_CLOSING_TAG_ERROR": return MissingClosingTagError.from(error as SerializedMissingClosingTagError);
36
+ case "TAG_NAMES_MISMATCH_ERROR": return TagNamesMismatchError.from(error as SerializedTagNamesMismatchError);
37
+ case "QUOTES_MISMATCH_ERROR": return QuotesMismatchError.from(error as SerializedQuotesMismatchError);
38
+ case "VOID_ELEMENT_CLOSING_TAG_ERROR": return VoidElementClosingTagError.from(error as SerializedVoidElementClosingTagError);
39
+ case "UNCLOSED_ELEMENT_ERROR": return UnclosedElementError.from(error as SerializedUnclosedElementError);
40
+ case "RUBY_PARSE_ERROR": return RubyParseError.from(error as SerializedRubyParseError);
41
+
42
+ default:
43
+ throw new Error(`Unknown node type: ${error.type}`);
44
+ }
45
+ }
46
+
47
+ export interface SerializedUnexpectedError {
48
+ type: "UNEXPECTED_ERROR";
49
+ message: string;
50
+ location: SerializedLocation;
51
+ description: string;
52
+ expected: string;
53
+ found: string;
54
+ }
55
+
56
+ export interface UnexpectedErrorProps {
57
+ type: string;
58
+ message: string;
59
+ location: Location;
60
+ description: string;
61
+ expected: string;
62
+ found: string;
63
+ }
64
+
65
+ export class UnexpectedError extends HerbError {
66
+ readonly description: string;
67
+ readonly expected: string;
68
+ readonly found: string;
69
+
70
+ static from(data: SerializedUnexpectedError): UnexpectedError {
71
+ return new UnexpectedError({
72
+ type: data.type,
73
+ message: data.message,
74
+ location: Location.from(data.location),
75
+ description: data.description,
76
+ expected: data.expected,
77
+ found: data.found,
78
+ })
79
+ }
80
+
81
+ constructor(props: UnexpectedErrorProps) {
82
+ super(props.type, props.message, props.location);
83
+
84
+ this.description = props.description;
85
+ this.expected = props.expected;
86
+ this.found = props.found;
87
+ }
88
+
89
+ toJSON(): SerializedUnexpectedError {
90
+ return {
91
+ ...super.toJSON(),
92
+ type: "UNEXPECTED_ERROR",
93
+ description: this.description,
94
+ expected: this.expected,
95
+ found: this.found,
96
+ };
97
+ }
98
+
99
+ toDiagnostics(): HerbDiagnostic[] {
100
+ const diagnostics: HerbDiagnostic[] = [
101
+ {
102
+ line: this.location.start.line,
103
+ column: this.location.start.column,
104
+ endLine: this.location.end.line,
105
+ endColumn: this.location.end.column,
106
+ message: this.message,
107
+ severity: 'error'
108
+ }
109
+ ]
110
+
111
+ // no-op for description
112
+ // no-op for expected
113
+ // no-op for found
114
+
115
+ return diagnostics
116
+ }
117
+
118
+ treeInspect(): string {
119
+ let output = "";
120
+
121
+ output += `@ UnexpectedError ${this.location.treeInspectWithLabel()}\n`;
122
+ output += `├── message: "${this.message}"\n`;
123
+ output += `├── description: ${JSON.stringify(this.description)}\n`;
124
+ output += `├── expected: ${JSON.stringify(this.expected)}\n`;
125
+ output += `└── found: ${JSON.stringify(this.found)}\n`;
126
+
127
+ return output;
128
+ }
129
+ }
130
+
131
+ export interface SerializedUnexpectedTokenError {
132
+ type: "UNEXPECTED_TOKEN_ERROR";
133
+ message: string;
134
+ location: SerializedLocation;
135
+ expected_type: string | null;
136
+ found: SerializedToken | null;
137
+ }
138
+
139
+ export interface UnexpectedTokenErrorProps {
140
+ type: string;
141
+ message: string;
142
+ location: Location;
143
+ expected_type: string | null;
144
+ found: Token | null;
145
+ }
146
+
147
+ export class UnexpectedTokenError extends HerbError {
148
+ readonly expected_type: string | null;
149
+ readonly found: Token | null;
150
+
151
+ static from(data: SerializedUnexpectedTokenError): UnexpectedTokenError {
152
+ return new UnexpectedTokenError({
153
+ type: data.type,
154
+ message: data.message,
155
+ location: Location.from(data.location),
156
+ expected_type: data.expected_type,
157
+ found: data.found ? Token.from(data.found) : null,
158
+ })
159
+ }
160
+
161
+ constructor(props: UnexpectedTokenErrorProps) {
162
+ super(props.type, props.message, props.location);
163
+
164
+ this.expected_type = props.expected_type;
165
+ this.found = props.found;
166
+ }
167
+
168
+ toJSON(): SerializedUnexpectedTokenError {
169
+ return {
170
+ ...super.toJSON(),
171
+ type: "UNEXPECTED_TOKEN_ERROR",
172
+ expected_type: this.expected_type,
173
+ found: this.found ? this.found.toJSON() : null,
174
+ };
175
+ }
176
+
177
+ toDiagnostics(): HerbDiagnostic[] {
178
+ const diagnostics: HerbDiagnostic[] = [
179
+ {
180
+ line: this.location.start.line,
181
+ column: this.location.start.column,
182
+ endLine: this.location.end.line,
183
+ endColumn: this.location.end.column,
184
+ message: this.message,
185
+ severity: 'error'
186
+ }
187
+ ]
188
+
189
+ // no-op for expected_type
190
+ if (this.found) {
191
+ diagnostics.push({
192
+ line: this.found.location.start.line,
193
+ column: this.found.location.start.column,
194
+ endLine: this.found.location.end.line,
195
+ endColumn: this.found.location.end.column,
196
+ message: `found "${(this.found.value)}" is here`,
197
+ severity: 'info'
198
+ })
199
+ }
200
+
201
+
202
+ return diagnostics
203
+ }
204
+
205
+ treeInspect(): string {
206
+ let output = "";
207
+
208
+ output += `@ UnexpectedTokenError ${this.location.treeInspectWithLabel()}\n`;
209
+ output += `├── message: "${this.message}"\n`;
210
+ output += `├── expected_type: ${JSON.stringify(this.expected_type)}\n`;
211
+ output += `└── found: ${this.found ? this.found.treeInspect() : "∅"}\n`;
212
+
213
+ return output;
214
+ }
215
+ }
216
+
217
+ export interface SerializedMissingOpeningTagError {
218
+ type: "MISSING_OPENING_TAG_ERROR";
219
+ message: string;
220
+ location: SerializedLocation;
221
+ closing_tag: SerializedToken | null;
222
+ }
223
+
224
+ export interface MissingOpeningTagErrorProps {
225
+ type: string;
226
+ message: string;
227
+ location: Location;
228
+ closing_tag: Token | null;
229
+ }
230
+
231
+ export class MissingOpeningTagError extends HerbError {
232
+ readonly closing_tag: Token | null;
233
+
234
+ static from(data: SerializedMissingOpeningTagError): MissingOpeningTagError {
235
+ return new MissingOpeningTagError({
236
+ type: data.type,
237
+ message: data.message,
238
+ location: Location.from(data.location),
239
+ closing_tag: data.closing_tag ? Token.from(data.closing_tag) : null,
240
+ })
241
+ }
242
+
243
+ constructor(props: MissingOpeningTagErrorProps) {
244
+ super(props.type, props.message, props.location);
245
+
246
+ this.closing_tag = props.closing_tag;
247
+ }
248
+
249
+ toJSON(): SerializedMissingOpeningTagError {
250
+ return {
251
+ ...super.toJSON(),
252
+ type: "MISSING_OPENING_TAG_ERROR",
253
+ closing_tag: this.closing_tag ? this.closing_tag.toJSON() : null,
254
+ };
255
+ }
256
+
257
+ toDiagnostics(): HerbDiagnostic[] {
258
+ const diagnostics: HerbDiagnostic[] = [
259
+ {
260
+ line: this.location.start.line,
261
+ column: this.location.start.column,
262
+ endLine: this.location.end.line,
263
+ endColumn: this.location.end.column,
264
+ message: this.message,
265
+ severity: 'error'
266
+ }
267
+ ]
268
+
269
+ if (this.closing_tag) {
270
+ diagnostics.push({
271
+ line: this.closing_tag.location.start.line,
272
+ column: this.closing_tag.location.start.column,
273
+ endLine: this.closing_tag.location.end.line,
274
+ endColumn: this.closing_tag.location.end.column,
275
+ message: `closing_tag "${(this.closing_tag.value)}" is here`,
276
+ severity: 'info'
277
+ })
278
+ }
279
+
280
+
281
+ return diagnostics
282
+ }
283
+
284
+ treeInspect(): string {
285
+ let output = "";
286
+
287
+ output += `@ MissingOpeningTagError ${this.location.treeInspectWithLabel()}\n`;
288
+ output += `├── message: "${this.message}"\n`;
289
+ output += `└── closing_tag: ${this.closing_tag ? this.closing_tag.treeInspect() : "∅"}\n`;
290
+
291
+ return output;
292
+ }
293
+ }
294
+
295
+ export interface SerializedMissingClosingTagError {
296
+ type: "MISSING_CLOSING_TAG_ERROR";
297
+ message: string;
298
+ location: SerializedLocation;
299
+ opening_tag: SerializedToken | null;
300
+ }
301
+
302
+ export interface MissingClosingTagErrorProps {
303
+ type: string;
304
+ message: string;
305
+ location: Location;
306
+ opening_tag: Token | null;
307
+ }
308
+
309
+ export class MissingClosingTagError extends HerbError {
310
+ readonly opening_tag: Token | null;
311
+
312
+ static from(data: SerializedMissingClosingTagError): MissingClosingTagError {
313
+ return new MissingClosingTagError({
314
+ type: data.type,
315
+ message: data.message,
316
+ location: Location.from(data.location),
317
+ opening_tag: data.opening_tag ? Token.from(data.opening_tag) : null,
318
+ })
319
+ }
320
+
321
+ constructor(props: MissingClosingTagErrorProps) {
322
+ super(props.type, props.message, props.location);
323
+
324
+ this.opening_tag = props.opening_tag;
325
+ }
326
+
327
+ toJSON(): SerializedMissingClosingTagError {
328
+ return {
329
+ ...super.toJSON(),
330
+ type: "MISSING_CLOSING_TAG_ERROR",
331
+ opening_tag: this.opening_tag ? this.opening_tag.toJSON() : null,
332
+ };
333
+ }
334
+
335
+ toDiagnostics(): HerbDiagnostic[] {
336
+ const diagnostics: HerbDiagnostic[] = [
337
+ {
338
+ line: this.location.start.line,
339
+ column: this.location.start.column,
340
+ endLine: this.location.end.line,
341
+ endColumn: this.location.end.column,
342
+ message: this.message,
343
+ severity: 'error'
344
+ }
345
+ ]
346
+
347
+ if (this.opening_tag) {
348
+ diagnostics.push({
349
+ line: this.opening_tag.location.start.line,
350
+ column: this.opening_tag.location.start.column,
351
+ endLine: this.opening_tag.location.end.line,
352
+ endColumn: this.opening_tag.location.end.column,
353
+ message: `opening_tag "${(this.opening_tag.value)}" is here`,
354
+ severity: 'info'
355
+ })
356
+ }
357
+
358
+
359
+ return diagnostics
360
+ }
361
+
362
+ treeInspect(): string {
363
+ let output = "";
364
+
365
+ output += `@ MissingClosingTagError ${this.location.treeInspectWithLabel()}\n`;
366
+ output += `├── message: "${this.message}"\n`;
367
+ output += `└── opening_tag: ${this.opening_tag ? this.opening_tag.treeInspect() : "∅"}\n`;
368
+
369
+ return output;
370
+ }
371
+ }
372
+
373
+ export interface SerializedTagNamesMismatchError {
374
+ type: "TAG_NAMES_MISMATCH_ERROR";
375
+ message: string;
376
+ location: SerializedLocation;
377
+ opening_tag: SerializedToken | null;
378
+ closing_tag: SerializedToken | null;
379
+ }
380
+
381
+ export interface TagNamesMismatchErrorProps {
382
+ type: string;
383
+ message: string;
384
+ location: Location;
385
+ opening_tag: Token | null;
386
+ closing_tag: Token | null;
387
+ }
388
+
389
+ export class TagNamesMismatchError extends HerbError {
390
+ readonly opening_tag: Token | null;
391
+ readonly closing_tag: Token | null;
392
+
393
+ static from(data: SerializedTagNamesMismatchError): TagNamesMismatchError {
394
+ return new TagNamesMismatchError({
395
+ type: data.type,
396
+ message: data.message,
397
+ location: Location.from(data.location),
398
+ opening_tag: data.opening_tag ? Token.from(data.opening_tag) : null,
399
+ closing_tag: data.closing_tag ? Token.from(data.closing_tag) : null,
400
+ })
401
+ }
402
+
403
+ constructor(props: TagNamesMismatchErrorProps) {
404
+ super(props.type, props.message, props.location);
405
+
406
+ this.opening_tag = props.opening_tag;
407
+ this.closing_tag = props.closing_tag;
408
+ }
409
+
410
+ toJSON(): SerializedTagNamesMismatchError {
411
+ return {
412
+ ...super.toJSON(),
413
+ type: "TAG_NAMES_MISMATCH_ERROR",
414
+ opening_tag: this.opening_tag ? this.opening_tag.toJSON() : null,
415
+ closing_tag: this.closing_tag ? this.closing_tag.toJSON() : null,
416
+ };
417
+ }
418
+
419
+ toDiagnostics(): HerbDiagnostic[] {
420
+ const diagnostics: HerbDiagnostic[] = [
421
+ {
422
+ line: this.location.start.line,
423
+ column: this.location.start.column,
424
+ endLine: this.location.end.line,
425
+ endColumn: this.location.end.column,
426
+ message: this.message,
427
+ severity: 'error'
428
+ }
429
+ ]
430
+
431
+ if (this.opening_tag) {
432
+ diagnostics.push({
433
+ line: this.opening_tag.location.start.line,
434
+ column: this.opening_tag.location.start.column,
435
+ endLine: this.opening_tag.location.end.line,
436
+ endColumn: this.opening_tag.location.end.column,
437
+ message: `opening_tag "${(this.opening_tag.value)}" is here`,
438
+ severity: 'info'
439
+ })
440
+ }
441
+
442
+ if (this.closing_tag) {
443
+ diagnostics.push({
444
+ line: this.closing_tag.location.start.line,
445
+ column: this.closing_tag.location.start.column,
446
+ endLine: this.closing_tag.location.end.line,
447
+ endColumn: this.closing_tag.location.end.column,
448
+ message: `closing_tag "${(this.closing_tag.value)}" is here`,
449
+ severity: 'info'
450
+ })
451
+ }
452
+
453
+
454
+ return diagnostics
455
+ }
456
+
457
+ treeInspect(): string {
458
+ let output = "";
459
+
460
+ output += `@ TagNamesMismatchError ${this.location.treeInspectWithLabel()}\n`;
461
+ output += `├── message: "${this.message}"\n`;
462
+ output += `├── opening_tag: ${this.opening_tag ? this.opening_tag.treeInspect() : "∅"}\n`;
463
+ output += `└── closing_tag: ${this.closing_tag ? this.closing_tag.treeInspect() : "∅"}\n`;
464
+
465
+ return output;
466
+ }
467
+ }
468
+
469
+ export interface SerializedQuotesMismatchError {
470
+ type: "QUOTES_MISMATCH_ERROR";
471
+ message: string;
472
+ location: SerializedLocation;
473
+ opening_quote: SerializedToken | null;
474
+ closing_quote: SerializedToken | null;
475
+ }
476
+
477
+ export interface QuotesMismatchErrorProps {
478
+ type: string;
479
+ message: string;
480
+ location: Location;
481
+ opening_quote: Token | null;
482
+ closing_quote: Token | null;
483
+ }
484
+
485
+ export class QuotesMismatchError extends HerbError {
486
+ readonly opening_quote: Token | null;
487
+ readonly closing_quote: Token | null;
488
+
489
+ static from(data: SerializedQuotesMismatchError): QuotesMismatchError {
490
+ return new QuotesMismatchError({
491
+ type: data.type,
492
+ message: data.message,
493
+ location: Location.from(data.location),
494
+ opening_quote: data.opening_quote ? Token.from(data.opening_quote) : null,
495
+ closing_quote: data.closing_quote ? Token.from(data.closing_quote) : null,
496
+ })
497
+ }
498
+
499
+ constructor(props: QuotesMismatchErrorProps) {
500
+ super(props.type, props.message, props.location);
501
+
502
+ this.opening_quote = props.opening_quote;
503
+ this.closing_quote = props.closing_quote;
504
+ }
505
+
506
+ toJSON(): SerializedQuotesMismatchError {
507
+ return {
508
+ ...super.toJSON(),
509
+ type: "QUOTES_MISMATCH_ERROR",
510
+ opening_quote: this.opening_quote ? this.opening_quote.toJSON() : null,
511
+ closing_quote: this.closing_quote ? this.closing_quote.toJSON() : null,
512
+ };
513
+ }
514
+
515
+ toDiagnostics(): HerbDiagnostic[] {
516
+ const diagnostics: HerbDiagnostic[] = [
517
+ {
518
+ line: this.location.start.line,
519
+ column: this.location.start.column,
520
+ endLine: this.location.end.line,
521
+ endColumn: this.location.end.column,
522
+ message: this.message,
523
+ severity: 'error'
524
+ }
525
+ ]
526
+
527
+ if (this.opening_quote) {
528
+ diagnostics.push({
529
+ line: this.opening_quote.location.start.line,
530
+ column: this.opening_quote.location.start.column,
531
+ endLine: this.opening_quote.location.end.line,
532
+ endColumn: this.opening_quote.location.end.column,
533
+ message: `opening_quote "${(this.opening_quote.value)}" is here`,
534
+ severity: 'info'
535
+ })
536
+ }
537
+
538
+ if (this.closing_quote) {
539
+ diagnostics.push({
540
+ line: this.closing_quote.location.start.line,
541
+ column: this.closing_quote.location.start.column,
542
+ endLine: this.closing_quote.location.end.line,
543
+ endColumn: this.closing_quote.location.end.column,
544
+ message: `closing_quote "${(this.closing_quote.value)}" is here`,
545
+ severity: 'info'
546
+ })
547
+ }
548
+
549
+
550
+ return diagnostics
551
+ }
552
+
553
+ treeInspect(): string {
554
+ let output = "";
555
+
556
+ output += `@ QuotesMismatchError ${this.location.treeInspectWithLabel()}\n`;
557
+ output += `├── message: "${this.message}"\n`;
558
+ output += `├── opening_quote: ${this.opening_quote ? this.opening_quote.treeInspect() : "∅"}\n`;
559
+ output += `└── closing_quote: ${this.closing_quote ? this.closing_quote.treeInspect() : "∅"}\n`;
560
+
561
+ return output;
562
+ }
563
+ }
564
+
565
+ export interface SerializedVoidElementClosingTagError {
566
+ type: "VOID_ELEMENT_CLOSING_TAG_ERROR";
567
+ message: string;
568
+ location: SerializedLocation;
569
+ tag_name: SerializedToken | null;
570
+ expected: string;
571
+ found: string;
572
+ }
573
+
574
+ export interface VoidElementClosingTagErrorProps {
575
+ type: string;
576
+ message: string;
577
+ location: Location;
578
+ tag_name: Token | null;
579
+ expected: string;
580
+ found: string;
581
+ }
582
+
583
+ export class VoidElementClosingTagError extends HerbError {
584
+ readonly tag_name: Token | null;
585
+ readonly expected: string;
586
+ readonly found: string;
587
+
588
+ static from(data: SerializedVoidElementClosingTagError): VoidElementClosingTagError {
589
+ return new VoidElementClosingTagError({
590
+ type: data.type,
591
+ message: data.message,
592
+ location: Location.from(data.location),
593
+ tag_name: data.tag_name ? Token.from(data.tag_name) : null,
594
+ expected: data.expected,
595
+ found: data.found,
596
+ })
597
+ }
598
+
599
+ constructor(props: VoidElementClosingTagErrorProps) {
600
+ super(props.type, props.message, props.location);
601
+
602
+ this.tag_name = props.tag_name;
603
+ this.expected = props.expected;
604
+ this.found = props.found;
605
+ }
606
+
607
+ toJSON(): SerializedVoidElementClosingTagError {
608
+ return {
609
+ ...super.toJSON(),
610
+ type: "VOID_ELEMENT_CLOSING_TAG_ERROR",
611
+ tag_name: this.tag_name ? this.tag_name.toJSON() : null,
612
+ expected: this.expected,
613
+ found: this.found,
614
+ };
615
+ }
616
+
617
+ toDiagnostics(): HerbDiagnostic[] {
618
+ const diagnostics: HerbDiagnostic[] = [
619
+ {
620
+ line: this.location.start.line,
621
+ column: this.location.start.column,
622
+ endLine: this.location.end.line,
623
+ endColumn: this.location.end.column,
624
+ message: this.message,
625
+ severity: 'error'
626
+ }
627
+ ]
628
+
629
+ if (this.tag_name) {
630
+ diagnostics.push({
631
+ line: this.tag_name.location.start.line,
632
+ column: this.tag_name.location.start.column,
633
+ endLine: this.tag_name.location.end.line,
634
+ endColumn: this.tag_name.location.end.column,
635
+ message: `tag_name "${(this.tag_name.value)}" is here`,
636
+ severity: 'info'
637
+ })
638
+ }
639
+
640
+ // no-op for expected
641
+ // no-op for found
642
+
643
+ return diagnostics
644
+ }
645
+
646
+ treeInspect(): string {
647
+ let output = "";
648
+
649
+ output += `@ VoidElementClosingTagError ${this.location.treeInspectWithLabel()}\n`;
650
+ output += `├── message: "${this.message}"\n`;
651
+ output += `├── tag_name: ${this.tag_name ? this.tag_name.treeInspect() : "∅"}\n`;
652
+ output += `├── expected: ${JSON.stringify(this.expected)}\n`;
653
+ output += `└── found: ${JSON.stringify(this.found)}\n`;
654
+
655
+ return output;
656
+ }
657
+ }
658
+
659
+ export interface SerializedUnclosedElementError {
660
+ type: "UNCLOSED_ELEMENT_ERROR";
661
+ message: string;
662
+ location: SerializedLocation;
663
+ opening_tag: SerializedToken | null;
664
+ }
665
+
666
+ export interface UnclosedElementErrorProps {
667
+ type: string;
668
+ message: string;
669
+ location: Location;
670
+ opening_tag: Token | null;
671
+ }
672
+
673
+ export class UnclosedElementError extends HerbError {
674
+ readonly opening_tag: Token | null;
675
+
676
+ static from(data: SerializedUnclosedElementError): UnclosedElementError {
677
+ return new UnclosedElementError({
678
+ type: data.type,
679
+ message: data.message,
680
+ location: Location.from(data.location),
681
+ opening_tag: data.opening_tag ? Token.from(data.opening_tag) : null,
682
+ })
683
+ }
684
+
685
+ constructor(props: UnclosedElementErrorProps) {
686
+ super(props.type, props.message, props.location);
687
+
688
+ this.opening_tag = props.opening_tag;
689
+ }
690
+
691
+ toJSON(): SerializedUnclosedElementError {
692
+ return {
693
+ ...super.toJSON(),
694
+ type: "UNCLOSED_ELEMENT_ERROR",
695
+ opening_tag: this.opening_tag ? this.opening_tag.toJSON() : null,
696
+ };
697
+ }
698
+
699
+ toDiagnostics(): HerbDiagnostic[] {
700
+ const diagnostics: HerbDiagnostic[] = [
701
+ {
702
+ line: this.location.start.line,
703
+ column: this.location.start.column,
704
+ endLine: this.location.end.line,
705
+ endColumn: this.location.end.column,
706
+ message: this.message,
707
+ severity: 'error'
708
+ }
709
+ ]
710
+
711
+ if (this.opening_tag) {
712
+ diagnostics.push({
713
+ line: this.opening_tag.location.start.line,
714
+ column: this.opening_tag.location.start.column,
715
+ endLine: this.opening_tag.location.end.line,
716
+ endColumn: this.opening_tag.location.end.column,
717
+ message: `opening_tag "${(this.opening_tag.value)}" is here`,
718
+ severity: 'info'
719
+ })
720
+ }
721
+
722
+
723
+ return diagnostics
724
+ }
725
+
726
+ treeInspect(): string {
727
+ let output = "";
728
+
729
+ output += `@ UnclosedElementError ${this.location.treeInspectWithLabel()}\n`;
730
+ output += `├── message: "${this.message}"\n`;
731
+ output += `└── opening_tag: ${this.opening_tag ? this.opening_tag.treeInspect() : "∅"}\n`;
732
+
733
+ return output;
734
+ }
735
+ }
736
+
737
+ export interface SerializedRubyParseError {
738
+ type: "RUBY_PARSE_ERROR";
739
+ message: string;
740
+ location: SerializedLocation;
741
+ error_message: string;
742
+ diagnostic_id: string;
743
+ level: string;
744
+ }
745
+
746
+ export interface RubyParseErrorProps {
747
+ type: string;
748
+ message: string;
749
+ location: Location;
750
+ error_message: string;
751
+ diagnostic_id: string;
752
+ level: string;
753
+ }
754
+
755
+ export class RubyParseError extends HerbError {
756
+ readonly error_message: string;
757
+ readonly diagnostic_id: string;
758
+ readonly level: string;
759
+
760
+ static from(data: SerializedRubyParseError): RubyParseError {
761
+ return new RubyParseError({
762
+ type: data.type,
763
+ message: data.message,
764
+ location: Location.from(data.location),
765
+ error_message: data.error_message,
766
+ diagnostic_id: data.diagnostic_id,
767
+ level: data.level,
768
+ })
769
+ }
770
+
771
+ constructor(props: RubyParseErrorProps) {
772
+ super(props.type, props.message, props.location);
773
+
774
+ this.error_message = props.error_message;
775
+ this.diagnostic_id = props.diagnostic_id;
776
+ this.level = props.level;
777
+ }
778
+
779
+ toJSON(): SerializedRubyParseError {
780
+ return {
781
+ ...super.toJSON(),
782
+ type: "RUBY_PARSE_ERROR",
783
+ error_message: this.error_message,
784
+ diagnostic_id: this.diagnostic_id,
785
+ level: this.level,
786
+ };
787
+ }
788
+
789
+ toDiagnostics(): HerbDiagnostic[] {
790
+ const diagnostics: HerbDiagnostic[] = [
791
+ {
792
+ line: this.location.start.line,
793
+ column: this.location.start.column,
794
+ endLine: this.location.end.line,
795
+ endColumn: this.location.end.column,
796
+ message: this.message,
797
+ severity: 'error'
798
+ }
799
+ ]
800
+
801
+ // no-op for error_message
802
+ // no-op for diagnostic_id
803
+ // no-op for level
804
+
805
+ return diagnostics
806
+ }
807
+
808
+ treeInspect(): string {
809
+ let output = "";
810
+
811
+ output += `@ RubyParseError ${this.location.treeInspectWithLabel()}\n`;
812
+ output += `├── message: "${this.message}"\n`;
813
+ output += `├── error_message: ${JSON.stringify(this.error_message)}\n`;
814
+ output += `├── diagnostic_id: ${JSON.stringify(this.diagnostic_id)}\n`;
815
+ output += `└── level: ${JSON.stringify(this.level)}\n`;
816
+
817
+ return output;
818
+ }
819
+ }
820
+