@herb-tools/core 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,15 @@
1
1
  import { Result } from "./result.js";
2
- import { TokenList, SerializedTokenList } from "./token-list.js";
2
+ import { TokenList } from "./token-list.js";
3
+ import { HerbError } from "./errors.js";
4
+ import { HerbWarning } from "./warning.js";
5
+ import type { SerializedHerbError } from "./errors.js";
6
+ import type { SerializedHerbWarning } from "./warning.js";
7
+ import type { SerializedTokenList } from "./token-list.js";
3
8
  export type SerializedLexResult = {
4
9
  tokens: SerializedTokenList;
5
10
  source: string;
6
- warnings: any[];
7
- errors: any[];
11
+ warnings: SerializedHerbWarning[];
12
+ errors: SerializedHerbError[];
8
13
  };
9
14
  /**
10
15
  * Represents the result of a lexical analysis, extending the base `Result` class.
@@ -26,17 +31,17 @@ export declare class LexResult extends Result {
26
31
  * @param warnings - An array of warnings encountered during lexing.
27
32
  * @param errors - An array of errors encountered during lexing.
28
33
  */
29
- constructor(value: TokenList, source: string, warnings?: any[], errors?: any[]);
34
+ constructor(value: TokenList, source: string, warnings?: HerbWarning[], errors?: HerbError[]);
30
35
  /**
31
36
  * Determines if the lexing was successful.
32
37
  * @returns `true` if there are no errors, otherwise `false`.
33
38
  */
34
- success(): boolean;
39
+ get successful(): boolean;
35
40
  /**
36
41
  * Determines if the lexing failed.
37
42
  * @returns `true` if there are errors, otherwise `false`.
38
43
  */
39
- failed(): boolean;
44
+ get failed(): boolean;
40
45
  /**
41
46
  * Converts the `LexResult` to a JSON representation.
42
47
  * @returns An object containing the token list, source, warnings, and errors.
@@ -44,7 +49,7 @@ export declare class LexResult extends Result {
44
49
  toJSON(): {
45
50
  value: TokenList;
46
51
  source: string;
47
- warnings: import("./warning.js").HerbWarning[];
48
- errors: import("./error.js").HerbError[];
52
+ warnings: HerbWarning[];
53
+ errors: HerbError[];
49
54
  };
50
55
  }
@@ -1,11 +1,38 @@
1
- import { Node } from "./node.js";
1
+ import { Location } from "./location.js";
2
2
  import { Token, SerializedToken } from "./token.js";
3
- import { HerbError } from "./error.js";
3
+ import { HerbError } from "./errors.js";
4
+ import type { SerializedLocation } from "./location.js";
5
+ import type { SerializedHerbError } from "./errors.js";
4
6
  import type { Visitor } from "./visitor.js";
5
- import type { SerializedNode, BaseNodeProps } from "./node.js";
6
- export declare function fromSerializedNode(node: SerializedNode): Node;
7
7
  export type SerializedNodeType = string;
8
+ export interface SerializedNode {
9
+ type: SerializedNodeType;
10
+ location: SerializedLocation;
11
+ errors: SerializedHerbError[];
12
+ }
13
+ export interface BaseNodeProps {
14
+ type: NodeType;
15
+ location: Location;
16
+ errors: HerbError[];
17
+ }
8
18
  export type NodeType = "AST_DOCUMENT_NODE" | "AST_LITERAL_NODE" | "AST_HTML_OPEN_TAG_NODE" | "AST_HTML_CLOSE_TAG_NODE" | "AST_HTML_SELF_CLOSE_TAG_NODE" | "AST_HTML_ELEMENT_NODE" | "AST_HTML_ATTRIBUTE_VALUE_NODE" | "AST_HTML_ATTRIBUTE_NAME_NODE" | "AST_HTML_ATTRIBUTE_NODE" | "AST_HTML_TEXT_NODE" | "AST_HTML_COMMENT_NODE" | "AST_HTML_DOCTYPE_NODE" | "AST_WHITESPACE_NODE" | "AST_ERB_CONTENT_NODE" | "AST_ERB_END_NODE" | "AST_ERB_ELSE_NODE" | "AST_ERB_IF_NODE" | "AST_ERB_BLOCK_NODE" | "AST_ERB_WHEN_NODE" | "AST_ERB_CASE_NODE" | "AST_ERB_CASE_MATCH_NODE" | "AST_ERB_WHILE_NODE" | "AST_ERB_UNTIL_NODE" | "AST_ERB_FOR_NODE" | "AST_ERB_RESCUE_NODE" | "AST_ERB_ENSURE_NODE" | "AST_ERB_BEGIN_NODE" | "AST_ERB_UNLESS_NODE" | "AST_ERB_YIELD_NODE" | "AST_ERB_IN_NODE";
19
+ export declare abstract class Node implements BaseNodeProps {
20
+ readonly type: NodeType;
21
+ readonly location: Location;
22
+ readonly errors: HerbError[];
23
+ static from(node: SerializedNode): Node;
24
+ constructor(type: NodeType, location: Location, errors: HerbError[]);
25
+ toJSON(): SerializedNode;
26
+ inspect(): string;
27
+ get isSingleLine(): boolean;
28
+ abstract treeInspect(indent?: number): string;
29
+ abstract recursiveErrors(): HerbError[];
30
+ abstract accept(visitor: Visitor): void;
31
+ abstract childNodes(): (Node | null | undefined)[];
32
+ abstract compactChildNodes(): Node[];
33
+ protected inspectArray(array: (Node | HerbError)[] | null | undefined, prefix: string): string;
34
+ protected inspectNode(node: Node | HerbError | undefined | null, prefix: string, prefix2?: string, last?: boolean, trailingNewline?: boolean): string;
35
+ }
9
36
  export interface SerializedDocumentNode extends SerializedNode {
10
37
  type: "AST_DOCUMENT_NODE";
11
38
  children: SerializedNode[];
@@ -822,3 +849,4 @@ export declare class ERBInNode extends Node {
822
849
  toJSON(): SerializedERBInNode;
823
850
  treeInspect(): string;
824
851
  }
852
+ export declare function fromSerializedNode(node: SerializedNode): Node;
@@ -1,8 +1,8 @@
1
1
  import { Result } from "./result.js";
2
2
  import { DocumentNode } from "./nodes.js";
3
- import { HerbError } from "./error.js";
3
+ import { HerbError } from "./errors.js";
4
4
  import { HerbWarning } from "./warning.js";
5
- import type { SerializedHerbError } from "./error.js";
5
+ import type { SerializedHerbError } from "./errors.js";
6
6
  import type { SerializedHerbWarning } from "./warning.js";
7
7
  import type { SerializedDocumentNode } from "./nodes.js";
8
8
  import type { Visitor } from "./visitor.js";
@@ -37,12 +37,12 @@ export declare class ParseResult extends Result {
37
37
  * Determines if the parsing failed.
38
38
  * @returns `true` if there are errors, otherwise `false`.
39
39
  */
40
- failed(): boolean;
40
+ get failed(): boolean;
41
41
  /**
42
42
  * Determines if the parsing was successful.
43
43
  * @returns `true` if there are no errors, otherwise `false`.
44
44
  */
45
- success(): boolean;
45
+ get successful(): boolean;
46
46
  /**
47
47
  * Returns a pretty-printed JSON string of the errors.
48
48
  * @returns A string representation of the errors.
@@ -1,10 +1,18 @@
1
- import { HerbError } from "./error.js";
1
+ import { HerbError } from "./errors.js";
2
2
  import { HerbWarning } from "./warning.js";
3
- export declare class Result {
3
+ export declare abstract class Result {
4
4
  readonly source: string;
5
5
  readonly warnings: HerbWarning[];
6
6
  readonly errors: HerbError[];
7
7
  constructor(source: string, warnings?: HerbWarning[], errors?: HerbError[]);
8
- success(): boolean;
9
- failed(): boolean;
8
+ /**
9
+ * Determines if the parsing was successful.
10
+ * @returns `true` if there are no errors, otherwise `false`.
11
+ */
12
+ get successful(): boolean;
13
+ /**
14
+ * Determines if the parsing failed.
15
+ * @returns `true` if there are errors, otherwise `false`.
16
+ */
17
+ get failed(): boolean;
10
18
  }
@@ -1,5 +1,4 @@
1
- import { Node } from "./node";
2
- import { DocumentNode, LiteralNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLSelfCloseTagNode, HTMLElementNode, HTMLAttributeValueNode, HTMLAttributeNameNode, HTMLAttributeNode, HTMLTextNode, HTMLCommentNode, HTMLDoctypeNode, WhitespaceNode, ERBContentNode, ERBEndNode, ERBElseNode, ERBIfNode, ERBBlockNode, ERBWhenNode, ERBCaseNode, ERBCaseMatchNode, ERBWhileNode, ERBUntilNode, ERBForNode, ERBRescueNode, ERBEnsureNode, ERBBeginNode, ERBUnlessNode, ERBYieldNode, ERBInNode } from "./nodes.js";
1
+ import { Node, DocumentNode, LiteralNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLSelfCloseTagNode, HTMLElementNode, HTMLAttributeValueNode, HTMLAttributeNameNode, HTMLAttributeNode, HTMLTextNode, HTMLCommentNode, HTMLDoctypeNode, WhitespaceNode, ERBContentNode, ERBEndNode, ERBElseNode, ERBIfNode, ERBBlockNode, ERBWhenNode, ERBCaseNode, ERBCaseMatchNode, ERBWhileNode, ERBUntilNode, ERBForNode, ERBRescueNode, ERBEnsureNode, ERBBeginNode, ERBUnlessNode, ERBYieldNode, ERBInNode } from "./nodes.js";
3
2
  export declare class Visitor {
4
3
  visit(node: Node | null | undefined): void;
5
4
  visitAll(nodes: (Node | null | undefined)[]): void;
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@herb-tools/core",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
+ "description": "Core module exporting shared interfaces, AST node definitions, and common utilities for Herb",
4
5
  "type": "module",
5
6
  "license": "MIT",
6
7
  "homepage": "https://herb-tools.dev",
package/src/errors.ts CHANGED
@@ -3,7 +3,6 @@
3
3
 
4
4
  import { Location, SerializedLocation } from "./location.js"
5
5
  import { Token, SerializedToken } from "./token.js"
6
- import { HerbError, SerializedHerbError } from "./error.js"
7
6
 
8
7
  type HerbDiagnostic = {
9
8
  line: number
@@ -27,21 +26,40 @@ export type HerbErrorType =
27
26
 
28
27
  export type SerializedErrorType = string
29
28
 
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);
29
+ export interface SerializedHerbError {
30
+ type: string
31
+ message: string
32
+ location: SerializedLocation
33
+ }
41
34
 
42
- default:
43
- throw new Error(`Unknown node type: ${error.type}`);
35
+ export abstract class HerbError {
36
+ readonly type: string
37
+ readonly message: string
38
+ readonly location: Location
39
+
40
+ static from(error: SerializedHerbError): HerbError {
41
+ return fromSerializedError(error)
42
+ }
43
+
44
+ constructor(type: string, message: string, location: Location) {
45
+ this.type = type
46
+ this.message = message
47
+ this.location = location
48
+ }
49
+
50
+ toJSON(): SerializedHerbError {
51
+ return {
52
+ type: this.type,
53
+ message: this.message,
54
+ location: this.location.toJSON(),
55
+ }
56
+ }
57
+
58
+ inspect(): string {
59
+ return this.treeInspect(0)
44
60
  }
61
+
62
+ abstract treeInspect(indent?: number): string
45
63
  }
46
64
 
47
65
  export interface SerializedUnexpectedError {
@@ -818,3 +836,20 @@ export class RubyParseError extends HerbError {
818
836
  }
819
837
  }
820
838
 
839
+
840
+ export function fromSerializedError(error: SerializedHerbError): HerbError {
841
+ switch (error.type) {
842
+ case "UNEXPECTED_ERROR": return UnexpectedError.from(error as SerializedUnexpectedError);
843
+ case "UNEXPECTED_TOKEN_ERROR": return UnexpectedTokenError.from(error as SerializedUnexpectedTokenError);
844
+ case "MISSING_OPENING_TAG_ERROR": return MissingOpeningTagError.from(error as SerializedMissingOpeningTagError);
845
+ case "MISSING_CLOSING_TAG_ERROR": return MissingClosingTagError.from(error as SerializedMissingClosingTagError);
846
+ case "TAG_NAMES_MISMATCH_ERROR": return TagNamesMismatchError.from(error as SerializedTagNamesMismatchError);
847
+ case "QUOTES_MISMATCH_ERROR": return QuotesMismatchError.from(error as SerializedQuotesMismatchError);
848
+ case "VOID_ELEMENT_CLOSING_TAG_ERROR": return VoidElementClosingTagError.from(error as SerializedVoidElementClosingTagError);
849
+ case "UNCLOSED_ELEMENT_ERROR": return UnclosedElementError.from(error as SerializedUnclosedElementError);
850
+ case "RUBY_PARSE_ERROR": return RubyParseError.from(error as SerializedRubyParseError);
851
+
852
+ default:
853
+ throw new Error(`Unknown node type: ${error.type}`);
854
+ }
855
+ }
package/src/index.ts CHANGED
@@ -3,7 +3,6 @@ export * from "./errors.js"
3
3
  export * from "./herb-backend.js"
4
4
  export * from "./lex-result.js"
5
5
  export * from "./location.js"
6
- export * from "./node.js"
7
6
  export * from "./nodes.js"
8
7
  export * from "./parse-result.js"
9
8
  export * from "./position.js"
@@ -13,3 +12,4 @@ export * from "./token-list.js"
13
12
  export * from "./token.js"
14
13
  export * from "./util.js"
15
14
  export * from "./visitor.js"
15
+ export * from "./warning.js"
package/src/lex-result.ts CHANGED
@@ -1,11 +1,17 @@
1
1
  import { Result } from "./result.js"
2
- import { TokenList, SerializedTokenList } from "./token-list.js"
2
+ import { TokenList } from "./token-list.js"
3
+ import { HerbError } from "./errors.js"
4
+ import { HerbWarning } from "./warning.js"
5
+
6
+ import type { SerializedHerbError } from "./errors.js"
7
+ import type { SerializedHerbWarning } from "./warning.js"
8
+ import type { SerializedTokenList } from "./token-list.js"
3
9
 
4
10
  export type SerializedLexResult = {
5
11
  tokens: SerializedTokenList
6
12
  source: string
7
- warnings: any[]
8
- errors: any[]
13
+ warnings: SerializedHerbWarning[]
14
+ errors: SerializedHerbError[]
9
15
  }
10
16
 
11
17
  /**
@@ -25,8 +31,8 @@ export class LexResult extends Result {
25
31
  return new LexResult(
26
32
  TokenList.from(result.tokens || []),
27
33
  result.source,
28
- result.warnings,
29
- result.errors,
34
+ result.warnings.map((warning) => HerbWarning.from(warning)),
35
+ result.errors.map((error) => HerbError.from(error)),
30
36
  )
31
37
  }
32
38
 
@@ -40,8 +46,8 @@ export class LexResult extends Result {
40
46
  constructor(
41
47
  value: TokenList,
42
48
  source: string,
43
- warnings: any[] = [],
44
- errors: any[] = [],
49
+ warnings: HerbWarning[] = [],
50
+ errors: HerbError[] = [],
45
51
  ) {
46
52
  super(source, warnings, errors)
47
53
  this.value = value
@@ -51,7 +57,7 @@ export class LexResult extends Result {
51
57
  * Determines if the lexing was successful.
52
58
  * @returns `true` if there are no errors, otherwise `false`.
53
59
  */
54
- override success(): boolean {
60
+ get successful(): boolean {
55
61
  return this.errors.length === 0
56
62
  }
57
63
 
@@ -59,7 +65,7 @@ export class LexResult extends Result {
59
65
  * Determines if the lexing failed.
60
66
  * @returns `true` if there are errors, otherwise `false`.
61
67
  */
62
- override failed(): boolean {
68
+ get failed(): boolean {
63
69
  return this.errors.length > 0
64
70
  }
65
71
 
package/src/nodes.ts CHANGED
@@ -1,53 +1,28 @@
1
1
  // NOTE: This file is generated by the templates/template.rb script and should not
2
2
  // be modified manually. See /Users/marcoroth/Development/herb-release/templates/javascript/packages/core/src/nodes.ts.erb
3
3
 
4
- import { Node } from "./node.js"
5
4
  import { Location } from "./location.js"
6
5
  import { Token, SerializedToken } from "./token.js"
7
- import { HerbError } from "./error.js"
6
+ import { HerbError } from "./errors.js"
8
7
  import { convertToUTF8 } from "./util.js"
9
8
 
9
+ import type { SerializedLocation } from "./location.js"
10
+ import type { SerializedHerbError } from "./errors.js"
10
11
  import type { Visitor } from "./visitor.js"
11
- import type { SerializedNode, BaseNodeProps } from "./node.js"
12
12
 
13
- export function fromSerializedNode(node: SerializedNode): Node {
14
- switch (node.type) {
15
- case "AST_DOCUMENT_NODE": return DocumentNode.from(node as SerializedDocumentNode);
16
- case "AST_LITERAL_NODE": return LiteralNode.from(node as SerializedLiteralNode);
17
- case "AST_HTML_OPEN_TAG_NODE": return HTMLOpenTagNode.from(node as SerializedHTMLOpenTagNode);
18
- case "AST_HTML_CLOSE_TAG_NODE": return HTMLCloseTagNode.from(node as SerializedHTMLCloseTagNode);
19
- case "AST_HTML_SELF_CLOSE_TAG_NODE": return HTMLSelfCloseTagNode.from(node as SerializedHTMLSelfCloseTagNode);
20
- case "AST_HTML_ELEMENT_NODE": return HTMLElementNode.from(node as SerializedHTMLElementNode);
21
- case "AST_HTML_ATTRIBUTE_VALUE_NODE": return HTMLAttributeValueNode.from(node as SerializedHTMLAttributeValueNode);
22
- case "AST_HTML_ATTRIBUTE_NAME_NODE": return HTMLAttributeNameNode.from(node as SerializedHTMLAttributeNameNode);
23
- case "AST_HTML_ATTRIBUTE_NODE": return HTMLAttributeNode.from(node as SerializedHTMLAttributeNode);
24
- case "AST_HTML_TEXT_NODE": return HTMLTextNode.from(node as SerializedHTMLTextNode);
25
- case "AST_HTML_COMMENT_NODE": return HTMLCommentNode.from(node as SerializedHTMLCommentNode);
26
- case "AST_HTML_DOCTYPE_NODE": return HTMLDoctypeNode.from(node as SerializedHTMLDoctypeNode);
27
- case "AST_WHITESPACE_NODE": return WhitespaceNode.from(node as SerializedWhitespaceNode);
28
- case "AST_ERB_CONTENT_NODE": return ERBContentNode.from(node as SerializedERBContentNode);
29
- case "AST_ERB_END_NODE": return ERBEndNode.from(node as SerializedERBEndNode);
30
- case "AST_ERB_ELSE_NODE": return ERBElseNode.from(node as SerializedERBElseNode);
31
- case "AST_ERB_IF_NODE": return ERBIfNode.from(node as SerializedERBIfNode);
32
- case "AST_ERB_BLOCK_NODE": return ERBBlockNode.from(node as SerializedERBBlockNode);
33
- case "AST_ERB_WHEN_NODE": return ERBWhenNode.from(node as SerializedERBWhenNode);
34
- case "AST_ERB_CASE_NODE": return ERBCaseNode.from(node as SerializedERBCaseNode);
35
- case "AST_ERB_CASE_MATCH_NODE": return ERBCaseMatchNode.from(node as SerializedERBCaseMatchNode);
36
- case "AST_ERB_WHILE_NODE": return ERBWhileNode.from(node as SerializedERBWhileNode);
37
- case "AST_ERB_UNTIL_NODE": return ERBUntilNode.from(node as SerializedERBUntilNode);
38
- case "AST_ERB_FOR_NODE": return ERBForNode.from(node as SerializedERBForNode);
39
- case "AST_ERB_RESCUE_NODE": return ERBRescueNode.from(node as SerializedERBRescueNode);
40
- case "AST_ERB_ENSURE_NODE": return ERBEnsureNode.from(node as SerializedERBEnsureNode);
41
- case "AST_ERB_BEGIN_NODE": return ERBBeginNode.from(node as SerializedERBBeginNode);
42
- case "AST_ERB_UNLESS_NODE": return ERBUnlessNode.from(node as SerializedERBUnlessNode);
43
- case "AST_ERB_YIELD_NODE": return ERBYieldNode.from(node as SerializedERBYieldNode);
44
- case "AST_ERB_IN_NODE": return ERBInNode.from(node as SerializedERBInNode);
13
+ export type SerializedNodeType = string
45
14
 
46
- default:
47
- throw new Error(`Unknown node type: ${node.type}`);
48
- }
15
+ export interface SerializedNode {
16
+ type: SerializedNodeType
17
+ location: SerializedLocation
18
+ errors: SerializedHerbError[]
19
+ }
20
+
21
+ export interface BaseNodeProps {
22
+ type: NodeType
23
+ location: Location
24
+ errors: HerbError[]
49
25
  }
50
- export type SerializedNodeType = string
51
26
 
52
27
  export type NodeType =
53
28
  | "AST_DOCUMENT_NODE"
@@ -81,6 +56,103 @@ export type NodeType =
81
56
  | "AST_ERB_YIELD_NODE"
82
57
  | "AST_ERB_IN_NODE"
83
58
 
59
+ export abstract class Node implements BaseNodeProps {
60
+ readonly type: NodeType
61
+ readonly location: Location
62
+ readonly errors: HerbError[]
63
+
64
+ static from(node: SerializedNode): Node {
65
+ return fromSerializedNode(node)
66
+ }
67
+
68
+ constructor(type: NodeType, location: Location, errors: HerbError[]) {
69
+ this.type = type
70
+ this.location = location
71
+ this.errors = errors
72
+ }
73
+
74
+ toJSON(): SerializedNode {
75
+ return {
76
+ type: this.type,
77
+ location: this.location.toJSON(),
78
+ errors: this.errors,
79
+ }
80
+ }
81
+
82
+ inspect(): string {
83
+ return this.treeInspect(0)
84
+ }
85
+
86
+ get isSingleLine(): boolean {
87
+ return this.location.start.line === this.location.end.line
88
+ }
89
+
90
+ abstract treeInspect(indent?: number): string
91
+ abstract recursiveErrors(): HerbError[]
92
+ abstract accept(visitor: Visitor): void
93
+ abstract childNodes(): (Node | null | undefined)[]
94
+ abstract compactChildNodes(): Node[]
95
+
96
+ protected inspectArray(
97
+ array: (Node | HerbError)[] | null | undefined,
98
+ prefix: string,
99
+ ): string {
100
+ if (!array) return "∅\n"
101
+ if (array.length === 0) return "[]\n"
102
+
103
+ let output = `(${array.length} item${array.length == 1 ? "" : "s"})\n`
104
+
105
+ array.forEach((item, index) => {
106
+ const isLast = index === array.length - 1
107
+
108
+ if (item instanceof Node || item instanceof HerbError) {
109
+ output += this.inspectNode(
110
+ item,
111
+ prefix,
112
+ isLast ? " " : "│ ",
113
+ isLast,
114
+ false,
115
+ )
116
+ } else {
117
+ const symbol = isLast ? "└── " : "├── "
118
+ output += `${prefix}${symbol} ${item}\n`
119
+ }
120
+ })
121
+
122
+ output += `${prefix}\n`
123
+
124
+ return output
125
+ }
126
+
127
+ protected inspectNode(
128
+ node: Node | HerbError | undefined | null,
129
+ prefix: string,
130
+ prefix2: string = " ",
131
+ last: boolean = true,
132
+ trailingNewline: boolean = true,
133
+ ): string {
134
+ if (!node) return "∅\n"
135
+
136
+ let output = trailingNewline ? "\n" : ""
137
+ output += `${prefix}`
138
+
139
+ output += last ? "└── " : "├── "
140
+ output += node
141
+ .treeInspect()
142
+ .trimStart()
143
+ .split("\n")
144
+ .map((line, index) =>
145
+ index == 0 ? line.trimStart() : `${prefix}${prefix2}${line}`,
146
+ )
147
+ .join("\n")
148
+ .trimStart()
149
+
150
+ output += `\n`
151
+
152
+ return output
153
+ }
154
+ }
155
+
84
156
  export interface SerializedDocumentNode extends SerializedNode {
85
157
  type: "AST_DOCUMENT_NODE";
86
158
  children: SerializedNode[];
@@ -2800,3 +2872,41 @@ export class ERBInNode extends Node {
2800
2872
  }
2801
2873
  }
2802
2874
 
2875
+
2876
+ export function fromSerializedNode(node: SerializedNode): Node {
2877
+ switch (node.type) {
2878
+ case "AST_DOCUMENT_NODE": return DocumentNode.from(node as SerializedDocumentNode);
2879
+ case "AST_LITERAL_NODE": return LiteralNode.from(node as SerializedLiteralNode);
2880
+ case "AST_HTML_OPEN_TAG_NODE": return HTMLOpenTagNode.from(node as SerializedHTMLOpenTagNode);
2881
+ case "AST_HTML_CLOSE_TAG_NODE": return HTMLCloseTagNode.from(node as SerializedHTMLCloseTagNode);
2882
+ case "AST_HTML_SELF_CLOSE_TAG_NODE": return HTMLSelfCloseTagNode.from(node as SerializedHTMLSelfCloseTagNode);
2883
+ case "AST_HTML_ELEMENT_NODE": return HTMLElementNode.from(node as SerializedHTMLElementNode);
2884
+ case "AST_HTML_ATTRIBUTE_VALUE_NODE": return HTMLAttributeValueNode.from(node as SerializedHTMLAttributeValueNode);
2885
+ case "AST_HTML_ATTRIBUTE_NAME_NODE": return HTMLAttributeNameNode.from(node as SerializedHTMLAttributeNameNode);
2886
+ case "AST_HTML_ATTRIBUTE_NODE": return HTMLAttributeNode.from(node as SerializedHTMLAttributeNode);
2887
+ case "AST_HTML_TEXT_NODE": return HTMLTextNode.from(node as SerializedHTMLTextNode);
2888
+ case "AST_HTML_COMMENT_NODE": return HTMLCommentNode.from(node as SerializedHTMLCommentNode);
2889
+ case "AST_HTML_DOCTYPE_NODE": return HTMLDoctypeNode.from(node as SerializedHTMLDoctypeNode);
2890
+ case "AST_WHITESPACE_NODE": return WhitespaceNode.from(node as SerializedWhitespaceNode);
2891
+ case "AST_ERB_CONTENT_NODE": return ERBContentNode.from(node as SerializedERBContentNode);
2892
+ case "AST_ERB_END_NODE": return ERBEndNode.from(node as SerializedERBEndNode);
2893
+ case "AST_ERB_ELSE_NODE": return ERBElseNode.from(node as SerializedERBElseNode);
2894
+ case "AST_ERB_IF_NODE": return ERBIfNode.from(node as SerializedERBIfNode);
2895
+ case "AST_ERB_BLOCK_NODE": return ERBBlockNode.from(node as SerializedERBBlockNode);
2896
+ case "AST_ERB_WHEN_NODE": return ERBWhenNode.from(node as SerializedERBWhenNode);
2897
+ case "AST_ERB_CASE_NODE": return ERBCaseNode.from(node as SerializedERBCaseNode);
2898
+ case "AST_ERB_CASE_MATCH_NODE": return ERBCaseMatchNode.from(node as SerializedERBCaseMatchNode);
2899
+ case "AST_ERB_WHILE_NODE": return ERBWhileNode.from(node as SerializedERBWhileNode);
2900
+ case "AST_ERB_UNTIL_NODE": return ERBUntilNode.from(node as SerializedERBUntilNode);
2901
+ case "AST_ERB_FOR_NODE": return ERBForNode.from(node as SerializedERBForNode);
2902
+ case "AST_ERB_RESCUE_NODE": return ERBRescueNode.from(node as SerializedERBRescueNode);
2903
+ case "AST_ERB_ENSURE_NODE": return ERBEnsureNode.from(node as SerializedERBEnsureNode);
2904
+ case "AST_ERB_BEGIN_NODE": return ERBBeginNode.from(node as SerializedERBBeginNode);
2905
+ case "AST_ERB_UNLESS_NODE": return ERBUnlessNode.from(node as SerializedERBUnlessNode);
2906
+ case "AST_ERB_YIELD_NODE": return ERBYieldNode.from(node as SerializedERBYieldNode);
2907
+ case "AST_ERB_IN_NODE": return ERBInNode.from(node as SerializedERBInNode);
2908
+
2909
+ default:
2910
+ throw new Error(`Unknown node type: ${node.type}`);
2911
+ }
2912
+ }
@@ -1,11 +1,13 @@
1
1
  import { Result } from "./result.js"
2
+
2
3
  import { DocumentNode } from "./nodes.js"
3
- import { HerbError } from "./error.js"
4
+ import { HerbError } from "./errors.js"
4
5
  import { HerbWarning } from "./warning.js"
5
6
 
6
- import type { SerializedHerbError } from "./error.js"
7
+ import type { SerializedHerbError } from "./errors.js"
7
8
  import type { SerializedHerbWarning } from "./warning.js"
8
9
  import type { SerializedDocumentNode } from "./nodes.js"
10
+
9
11
  import type { Visitor } from "./visitor.js"
10
12
 
11
13
  export type SerializedParseResult = {
@@ -58,7 +60,7 @@ export class ParseResult extends Result {
58
60
  * Determines if the parsing failed.
59
61
  * @returns `true` if there are errors, otherwise `false`.
60
62
  */
61
- failed(): boolean {
63
+ get failed(): boolean {
62
64
  // TODO: this should probably be recursive as noted in the Ruby version
63
65
  return this.errors.length > 0 || this.value.errors.length > 0
64
66
  }
@@ -67,8 +69,8 @@ export class ParseResult extends Result {
67
69
  * Determines if the parsing was successful.
68
70
  * @returns `true` if there are no errors, otherwise `false`.
69
71
  */
70
- success(): boolean {
71
- return !this.failed()
72
+ get successful(): boolean {
73
+ return this.errors.length === 0
72
74
  }
73
75
 
74
76
  /**
package/src/result.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { HerbError } from "./error.js"
1
+ import { HerbError } from "./errors.js"
2
2
  import { HerbWarning } from "./warning.js"
3
3
 
4
- export class Result {
4
+ export abstract class Result {
5
5
  readonly source: string
6
6
  readonly warnings: HerbWarning[]
7
7
  readonly errors: HerbError[]
@@ -16,11 +16,19 @@ export class Result {
16
16
  this.errors = errors || []
17
17
  }
18
18
 
19
- success(): boolean {
20
- return false
19
+ /**
20
+ * Determines if the parsing was successful.
21
+ * @returns `true` if there are no errors, otherwise `false`.
22
+ */
23
+ get successful(): boolean {
24
+ return this.errors.length === 0
21
25
  }
22
26
 
23
- failed(): boolean {
24
- return true
27
+ /**
28
+ * Determines if the parsing failed.
29
+ * @returns `true` if there are errors, otherwise `false`.
30
+ */
31
+ get failed(): boolean {
32
+ return this.errors.length > 0
25
33
  }
26
34
  }
package/src/visitor.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  // NOTE: This file is generated by the templates/template.rb script and should not
2
2
  // be modified manually. See /Users/marcoroth/Development/herb-release/templates/javascript/packages/core/src/visitor.ts.erb
3
3
 
4
- import { Node } from "./node"
5
-
6
4
  import {
5
+ Node,
7
6
  DocumentNode,
8
7
  LiteralNode,
9
8
  HTMLOpenTagNode,
@@ -1,16 +0,0 @@
1
- import { Location, SerializedLocation } from "./location.js";
2
- export interface SerializedHerbError {
3
- type: string;
4
- message: string;
5
- location: SerializedLocation;
6
- }
7
- export declare abstract class HerbError {
8
- readonly type: string;
9
- readonly message: string;
10
- readonly location: Location;
11
- static from(error: SerializedHerbError): HerbError;
12
- constructor(type: string, message: string, location: Location);
13
- toJSON(): SerializedHerbError;
14
- inspect(): string;
15
- abstract treeInspect(indent?: number): string;
16
- }
@@ -1,30 +0,0 @@
1
- import { Location, SerializedLocation } from "./location.js";
2
- import { HerbError, SerializedHerbError } from "./error.js";
3
- import { NodeType, SerializedNodeType } from "./nodes.js";
4
- import type { Visitor } from "./visitor.js";
5
- export interface SerializedNode {
6
- type: SerializedNodeType;
7
- location: SerializedLocation;
8
- errors: SerializedHerbError[];
9
- }
10
- export interface BaseNodeProps {
11
- type: NodeType;
12
- location: Location;
13
- errors: HerbError[];
14
- }
15
- export declare abstract class Node implements BaseNodeProps {
16
- readonly type: NodeType;
17
- readonly location: Location;
18
- readonly errors: HerbError[];
19
- static from(node: SerializedNode): Node;
20
- constructor(type: NodeType, location: Location, errors: HerbError[]);
21
- toJSON(): SerializedNode;
22
- inspect(): string;
23
- abstract treeInspect(indent?: number): string;
24
- abstract recursiveErrors(): HerbError[];
25
- abstract accept(visitor: Visitor): void;
26
- abstract childNodes(): (Node | null | undefined)[];
27
- abstract compactChildNodes(): Node[];
28
- protected inspectArray(array: (Node | HerbError)[] | null | undefined, prefix: string): string;
29
- protected inspectNode(node: Node | HerbError | undefined | null, prefix: string, prefix2?: string, last?: boolean, trailingNewline?: boolean): string;
30
- }