@herb-tools/core 0.6.0 → 0.7.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.
- package/dist/herb-core.browser.js +235 -41
- package/dist/herb-core.browser.js.map +1 -1
- package/dist/herb-core.cjs +242 -40
- package/dist/herb-core.cjs.map +1 -1
- package/dist/herb-core.esm.js +235 -41
- package/dist/herb-core.esm.js.map +1 -1
- package/dist/herb-core.umd.js +242 -40
- package/dist/herb-core.umd.js.map +1 -1
- package/dist/types/ast-utils.d.ts +52 -2
- package/dist/types/node-type-guards.d.ts +3 -3
- package/dist/types/nodes.d.ts +41 -0
- package/package.json +1 -1
- package/src/ast-utils.ts +106 -3
- package/src/errors.ts +1 -1
- package/src/node-type-guards.ts +44 -42
- package/src/nodes.ts +147 -4
- package/src/visitor.ts +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode } from "./nodes.js";
|
|
2
|
-
import {
|
|
1
|
+
import { Node, ERBContentNode, HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLAttributeNameNode } from "./nodes.js";
|
|
2
|
+
import type { Location } from "./location.js";
|
|
3
|
+
import type { Position } from "./position.js";
|
|
3
4
|
/**
|
|
4
5
|
* Checks if a node is an ERB output node (generates content: <%= %> or <%== %>)
|
|
5
6
|
*/
|
|
@@ -72,3 +73,52 @@ export declare function getTagName(node: HTMLElementNode | HTMLOpenTagNode | HTM
|
|
|
72
73
|
* Check if a node is a comment (HTML comment or ERB comment)
|
|
73
74
|
*/
|
|
74
75
|
export declare function isCommentNode(node: Node): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Compares two positions to determine if they are equal
|
|
78
|
+
* Returns true if pos1 and pos2 are at the same location
|
|
79
|
+
*/
|
|
80
|
+
export declare function isPositionEqual(position1: Position, position2: Position): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Compares two positions to determine if the first comes after the second
|
|
83
|
+
* Returns true if pos1 comes after pos2 in source order
|
|
84
|
+
* @param inclusive - If true, returns true when positions are equal
|
|
85
|
+
*/
|
|
86
|
+
export declare function isPositionAfter(position1: Position, position2: Position, inclusive?: boolean): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Gets nodes that appear before the specified location in source order
|
|
89
|
+
* Uses line and column positions to determine ordering
|
|
90
|
+
*/
|
|
91
|
+
export declare function getNodesBeforeLocation<T extends Node>(nodes: T[], location: Location): T[];
|
|
92
|
+
/**
|
|
93
|
+
* Gets nodes that appear after the specified location in source order
|
|
94
|
+
* Uses line and column positions to determine ordering
|
|
95
|
+
*/
|
|
96
|
+
export declare function getNodesAfterLocation<T extends Node>(nodes: T[], location: Location): T[];
|
|
97
|
+
/**
|
|
98
|
+
* Splits nodes into before and after the specified location
|
|
99
|
+
* Returns an object with `before` and `after` arrays
|
|
100
|
+
*/
|
|
101
|
+
export declare function splitNodesAroundLocation<T extends Node>(nodes: T[], location: Location): {
|
|
102
|
+
before: T[];
|
|
103
|
+
after: T[];
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Splits nodes at a specific position
|
|
107
|
+
* Returns nodes that end before the position and nodes that start after the position
|
|
108
|
+
* More precise than splitNodesAroundLocation as it uses a single position point
|
|
109
|
+
* Uses the same defaults as the individual functions: before=exclusive, after=inclusive
|
|
110
|
+
*/
|
|
111
|
+
export declare function splitNodesAroundPosition<T extends Node>(nodes: T[], position: Position): {
|
|
112
|
+
before: T[];
|
|
113
|
+
after: T[];
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Gets nodes that end before the specified position
|
|
117
|
+
* @param inclusive - If true, includes nodes that end exactly at the position (default: false, matching half-open interval semantics)
|
|
118
|
+
*/
|
|
119
|
+
export declare function getNodesBeforePosition<T extends Node>(nodes: T[], position: Position, inclusive?: boolean): T[];
|
|
120
|
+
/**
|
|
121
|
+
* Gets nodes that start after the specified position
|
|
122
|
+
* @param inclusive - If true, includes nodes that start exactly at the position (default: true, matching typical boundary behavior)
|
|
123
|
+
*/
|
|
124
|
+
export declare function getNodesAfterPosition<T extends Node>(nodes: T[], position: Position, inclusive?: boolean): T[];
|
|
@@ -164,7 +164,7 @@ export declare const NODE_TYPE_GUARDS: Map<new (...args: any[]) => Node, (node:
|
|
|
164
164
|
* // node is HTMLTextNode
|
|
165
165
|
* }
|
|
166
166
|
*/
|
|
167
|
-
export declare const AST_TYPE_GUARDS: Map<
|
|
167
|
+
export declare const AST_TYPE_GUARDS: Map<NodeType, (node: Node) => boolean>;
|
|
168
168
|
type NodeTypeToClass = {
|
|
169
169
|
"AST_DOCUMENT_NODE": DocumentNode;
|
|
170
170
|
"AST_LITERAL_NODE": LiteralNode;
|
|
@@ -296,8 +296,8 @@ export declare function filterNodes(nodes: Node[] | undefined | null, ...types:
|
|
|
296
296
|
* // node is narrowed to HTMLTextNode
|
|
297
297
|
* }
|
|
298
298
|
*/
|
|
299
|
-
export declare function isNode<T extends NodeType>(node: Node, type: T): node is NodeTypeToClass[T];
|
|
300
|
-
export declare function isNode<T extends new (...args: any[]) => Node>(node: Node, type: T): node is ClassToInstance<T>;
|
|
299
|
+
export declare function isNode<T extends NodeType>(node: Node | null | undefined, type: T): node is NodeTypeToClass[T];
|
|
300
|
+
export declare function isNode<T extends new (...args: any[]) => Node>(node: Node | null | undefined, type: T): node is ClassToInstance<T>;
|
|
301
301
|
export declare function isToken(object: any): object is Token;
|
|
302
302
|
export declare function isParseResult(object: any): object is ParseResult;
|
|
303
303
|
/**
|
package/dist/types/nodes.d.ts
CHANGED
|
@@ -20,9 +20,16 @@ export declare abstract class Node implements BaseNodeProps {
|
|
|
20
20
|
readonly location: Location;
|
|
21
21
|
readonly errors: HerbError[];
|
|
22
22
|
static from(node: SerializedNode): Node;
|
|
23
|
+
static get type(): NodeType;
|
|
23
24
|
constructor(type: NodeType, location: Location, errors: HerbError[]);
|
|
24
25
|
toJSON(): SerializedNode;
|
|
25
26
|
inspect(): string;
|
|
27
|
+
is<T extends Node>(nodeClass: {
|
|
28
|
+
new (...args: any[]): T;
|
|
29
|
+
prototype: T;
|
|
30
|
+
type: NodeType;
|
|
31
|
+
}): this is T;
|
|
32
|
+
isOfType<T extends Node>(type: NodeType): this is T;
|
|
26
33
|
get isSingleLine(): boolean;
|
|
27
34
|
abstract treeInspect(indent?: number): string;
|
|
28
35
|
abstract recursiveErrors(): HerbError[];
|
|
@@ -41,6 +48,7 @@ export interface DocumentNodeProps extends BaseNodeProps {
|
|
|
41
48
|
}
|
|
42
49
|
export declare class DocumentNode extends Node {
|
|
43
50
|
readonly children: Node[];
|
|
51
|
+
static get type(): NodeType;
|
|
44
52
|
static from(data: SerializedDocumentNode): DocumentNode;
|
|
45
53
|
constructor(props: DocumentNodeProps);
|
|
46
54
|
accept(visitor: Visitor): void;
|
|
@@ -59,6 +67,7 @@ export interface LiteralNodeProps extends BaseNodeProps {
|
|
|
59
67
|
}
|
|
60
68
|
export declare class LiteralNode extends Node {
|
|
61
69
|
readonly content: string;
|
|
70
|
+
static get type(): NodeType;
|
|
62
71
|
static from(data: SerializedLiteralNode): LiteralNode;
|
|
63
72
|
constructor(props: LiteralNodeProps);
|
|
64
73
|
accept(visitor: Visitor): void;
|
|
@@ -89,6 +98,7 @@ export declare class HTMLOpenTagNode extends Node {
|
|
|
89
98
|
readonly tag_closing: Token | null;
|
|
90
99
|
readonly children: Node[];
|
|
91
100
|
readonly is_void: boolean;
|
|
101
|
+
static get type(): NodeType;
|
|
92
102
|
static from(data: SerializedHTMLOpenTagNode): HTMLOpenTagNode;
|
|
93
103
|
constructor(props: HTMLOpenTagNodeProps);
|
|
94
104
|
accept(visitor: Visitor): void;
|
|
@@ -116,6 +126,7 @@ export declare class HTMLCloseTagNode extends Node {
|
|
|
116
126
|
readonly tag_name: Token | null;
|
|
117
127
|
readonly children: Node[];
|
|
118
128
|
readonly tag_closing: Token | null;
|
|
129
|
+
static get type(): NodeType;
|
|
119
130
|
static from(data: SerializedHTMLCloseTagNode): HTMLCloseTagNode;
|
|
120
131
|
constructor(props: HTMLCloseTagNodeProps);
|
|
121
132
|
accept(visitor: Visitor): void;
|
|
@@ -132,6 +143,7 @@ export interface SerializedHTMLElementNode extends SerializedNode {
|
|
|
132
143
|
body: SerializedNode[];
|
|
133
144
|
close_tag: SerializedHTMLCloseTagNode | null;
|
|
134
145
|
is_void: boolean;
|
|
146
|
+
source: string;
|
|
135
147
|
}
|
|
136
148
|
export interface HTMLElementNodeProps extends BaseNodeProps {
|
|
137
149
|
open_tag: HTMLOpenTagNode | null;
|
|
@@ -139,6 +151,7 @@ export interface HTMLElementNodeProps extends BaseNodeProps {
|
|
|
139
151
|
body: Node[];
|
|
140
152
|
close_tag: HTMLCloseTagNode | null;
|
|
141
153
|
is_void: boolean;
|
|
154
|
+
source: string;
|
|
142
155
|
}
|
|
143
156
|
export declare class HTMLElementNode extends Node {
|
|
144
157
|
readonly open_tag: HTMLOpenTagNode | null;
|
|
@@ -146,6 +159,8 @@ export declare class HTMLElementNode extends Node {
|
|
|
146
159
|
readonly body: Node[];
|
|
147
160
|
readonly close_tag: HTMLCloseTagNode | null;
|
|
148
161
|
readonly is_void: boolean;
|
|
162
|
+
readonly source: string;
|
|
163
|
+
static get type(): NodeType;
|
|
149
164
|
static from(data: SerializedHTMLElementNode): HTMLElementNode;
|
|
150
165
|
constructor(props: HTMLElementNodeProps);
|
|
151
166
|
accept(visitor: Visitor): void;
|
|
@@ -173,6 +188,7 @@ export declare class HTMLAttributeValueNode extends Node {
|
|
|
173
188
|
readonly children: Node[];
|
|
174
189
|
readonly close_quote: Token | null;
|
|
175
190
|
readonly quoted: boolean;
|
|
191
|
+
static get type(): NodeType;
|
|
176
192
|
static from(data: SerializedHTMLAttributeValueNode): HTMLAttributeValueNode;
|
|
177
193
|
constructor(props: HTMLAttributeValueNodeProps);
|
|
178
194
|
accept(visitor: Visitor): void;
|
|
@@ -191,6 +207,7 @@ export interface HTMLAttributeNameNodeProps extends BaseNodeProps {
|
|
|
191
207
|
}
|
|
192
208
|
export declare class HTMLAttributeNameNode extends Node {
|
|
193
209
|
readonly children: Node[];
|
|
210
|
+
static get type(): NodeType;
|
|
194
211
|
static from(data: SerializedHTMLAttributeNameNode): HTMLAttributeNameNode;
|
|
195
212
|
constructor(props: HTMLAttributeNameNodeProps);
|
|
196
213
|
accept(visitor: Visitor): void;
|
|
@@ -215,6 +232,7 @@ export declare class HTMLAttributeNode extends Node {
|
|
|
215
232
|
readonly name: HTMLAttributeNameNode | null;
|
|
216
233
|
readonly equals: Token | null;
|
|
217
234
|
readonly value: HTMLAttributeValueNode | null;
|
|
235
|
+
static get type(): NodeType;
|
|
218
236
|
static from(data: SerializedHTMLAttributeNode): HTMLAttributeNode;
|
|
219
237
|
constructor(props: HTMLAttributeNodeProps);
|
|
220
238
|
accept(visitor: Visitor): void;
|
|
@@ -233,6 +251,7 @@ export interface HTMLTextNodeProps extends BaseNodeProps {
|
|
|
233
251
|
}
|
|
234
252
|
export declare class HTMLTextNode extends Node {
|
|
235
253
|
readonly content: string;
|
|
254
|
+
static get type(): NodeType;
|
|
236
255
|
static from(data: SerializedHTMLTextNode): HTMLTextNode;
|
|
237
256
|
constructor(props: HTMLTextNodeProps);
|
|
238
257
|
accept(visitor: Visitor): void;
|
|
@@ -257,6 +276,7 @@ export declare class HTMLCommentNode extends Node {
|
|
|
257
276
|
readonly comment_start: Token | null;
|
|
258
277
|
readonly children: Node[];
|
|
259
278
|
readonly comment_end: Token | null;
|
|
279
|
+
static get type(): NodeType;
|
|
260
280
|
static from(data: SerializedHTMLCommentNode): HTMLCommentNode;
|
|
261
281
|
constructor(props: HTMLCommentNodeProps);
|
|
262
282
|
accept(visitor: Visitor): void;
|
|
@@ -281,6 +301,7 @@ export declare class HTMLDoctypeNode extends Node {
|
|
|
281
301
|
readonly tag_opening: Token | null;
|
|
282
302
|
readonly children: Node[];
|
|
283
303
|
readonly tag_closing: Token | null;
|
|
304
|
+
static get type(): NodeType;
|
|
284
305
|
static from(data: SerializedHTMLDoctypeNode): HTMLDoctypeNode;
|
|
285
306
|
constructor(props: HTMLDoctypeNodeProps);
|
|
286
307
|
accept(visitor: Visitor): void;
|
|
@@ -305,6 +326,7 @@ export declare class XMLDeclarationNode extends Node {
|
|
|
305
326
|
readonly tag_opening: Token | null;
|
|
306
327
|
readonly children: Node[];
|
|
307
328
|
readonly tag_closing: Token | null;
|
|
329
|
+
static get type(): NodeType;
|
|
308
330
|
static from(data: SerializedXMLDeclarationNode): XMLDeclarationNode;
|
|
309
331
|
constructor(props: XMLDeclarationNodeProps);
|
|
310
332
|
accept(visitor: Visitor): void;
|
|
@@ -329,6 +351,7 @@ export declare class CDATANode extends Node {
|
|
|
329
351
|
readonly tag_opening: Token | null;
|
|
330
352
|
readonly children: Node[];
|
|
331
353
|
readonly tag_closing: Token | null;
|
|
354
|
+
static get type(): NodeType;
|
|
332
355
|
static from(data: SerializedCDATANode): CDATANode;
|
|
333
356
|
constructor(props: CDATANodeProps);
|
|
334
357
|
accept(visitor: Visitor): void;
|
|
@@ -347,6 +370,7 @@ export interface WhitespaceNodeProps extends BaseNodeProps {
|
|
|
347
370
|
}
|
|
348
371
|
export declare class WhitespaceNode extends Node {
|
|
349
372
|
readonly value: Token | null;
|
|
373
|
+
static get type(): NodeType;
|
|
350
374
|
static from(data: SerializedWhitespaceNode): WhitespaceNode;
|
|
351
375
|
constructor(props: WhitespaceNodeProps);
|
|
352
376
|
accept(visitor: Visitor): void;
|
|
@@ -377,6 +401,7 @@ export declare class ERBContentNode extends Node {
|
|
|
377
401
|
readonly tag_closing: Token | null;
|
|
378
402
|
readonly parsed: boolean;
|
|
379
403
|
readonly valid: boolean;
|
|
404
|
+
static get type(): NodeType;
|
|
380
405
|
static from(data: SerializedERBContentNode): ERBContentNode;
|
|
381
406
|
constructor(props: ERBContentNodeProps);
|
|
382
407
|
accept(visitor: Visitor): void;
|
|
@@ -401,6 +426,7 @@ export declare class ERBEndNode extends Node {
|
|
|
401
426
|
readonly tag_opening: Token | null;
|
|
402
427
|
readonly content: Token | null;
|
|
403
428
|
readonly tag_closing: Token | null;
|
|
429
|
+
static get type(): NodeType;
|
|
404
430
|
static from(data: SerializedERBEndNode): ERBEndNode;
|
|
405
431
|
constructor(props: ERBEndNodeProps);
|
|
406
432
|
accept(visitor: Visitor): void;
|
|
@@ -428,6 +454,7 @@ export declare class ERBElseNode extends Node {
|
|
|
428
454
|
readonly content: Token | null;
|
|
429
455
|
readonly tag_closing: Token | null;
|
|
430
456
|
readonly statements: Node[];
|
|
457
|
+
static get type(): NodeType;
|
|
431
458
|
static from(data: SerializedERBElseNode): ERBElseNode;
|
|
432
459
|
constructor(props: ERBElseNodeProps);
|
|
433
460
|
accept(visitor: Visitor): void;
|
|
@@ -461,6 +488,7 @@ export declare class ERBIfNode extends Node {
|
|
|
461
488
|
readonly statements: Node[];
|
|
462
489
|
readonly subsequent: Node | null;
|
|
463
490
|
readonly end_node: ERBEndNode | null;
|
|
491
|
+
static get type(): NodeType;
|
|
464
492
|
static from(data: SerializedERBIfNode): ERBIfNode;
|
|
465
493
|
constructor(props: ERBIfNodeProps);
|
|
466
494
|
accept(visitor: Visitor): void;
|
|
@@ -491,6 +519,7 @@ export declare class ERBBlockNode extends Node {
|
|
|
491
519
|
readonly tag_closing: Token | null;
|
|
492
520
|
readonly body: Node[];
|
|
493
521
|
readonly end_node: ERBEndNode | null;
|
|
522
|
+
static get type(): NodeType;
|
|
494
523
|
static from(data: SerializedERBBlockNode): ERBBlockNode;
|
|
495
524
|
constructor(props: ERBBlockNodeProps);
|
|
496
525
|
accept(visitor: Visitor): void;
|
|
@@ -518,6 +547,7 @@ export declare class ERBWhenNode extends Node {
|
|
|
518
547
|
readonly content: Token | null;
|
|
519
548
|
readonly tag_closing: Token | null;
|
|
520
549
|
readonly statements: Node[];
|
|
550
|
+
static get type(): NodeType;
|
|
521
551
|
static from(data: SerializedERBWhenNode): ERBWhenNode;
|
|
522
552
|
constructor(props: ERBWhenNodeProps);
|
|
523
553
|
accept(visitor: Visitor): void;
|
|
@@ -554,6 +584,7 @@ export declare class ERBCaseNode extends Node {
|
|
|
554
584
|
readonly conditions: Node[];
|
|
555
585
|
readonly else_clause: ERBElseNode | null;
|
|
556
586
|
readonly end_node: ERBEndNode | null;
|
|
587
|
+
static get type(): NodeType;
|
|
557
588
|
static from(data: SerializedERBCaseNode): ERBCaseNode;
|
|
558
589
|
constructor(props: ERBCaseNodeProps);
|
|
559
590
|
accept(visitor: Visitor): void;
|
|
@@ -590,6 +621,7 @@ export declare class ERBCaseMatchNode extends Node {
|
|
|
590
621
|
readonly conditions: Node[];
|
|
591
622
|
readonly else_clause: ERBElseNode | null;
|
|
592
623
|
readonly end_node: ERBEndNode | null;
|
|
624
|
+
static get type(): NodeType;
|
|
593
625
|
static from(data: SerializedERBCaseMatchNode): ERBCaseMatchNode;
|
|
594
626
|
constructor(props: ERBCaseMatchNodeProps);
|
|
595
627
|
accept(visitor: Visitor): void;
|
|
@@ -620,6 +652,7 @@ export declare class ERBWhileNode extends Node {
|
|
|
620
652
|
readonly tag_closing: Token | null;
|
|
621
653
|
readonly statements: Node[];
|
|
622
654
|
readonly end_node: ERBEndNode | null;
|
|
655
|
+
static get type(): NodeType;
|
|
623
656
|
static from(data: SerializedERBWhileNode): ERBWhileNode;
|
|
624
657
|
constructor(props: ERBWhileNodeProps);
|
|
625
658
|
accept(visitor: Visitor): void;
|
|
@@ -650,6 +683,7 @@ export declare class ERBUntilNode extends Node {
|
|
|
650
683
|
readonly tag_closing: Token | null;
|
|
651
684
|
readonly statements: Node[];
|
|
652
685
|
readonly end_node: ERBEndNode | null;
|
|
686
|
+
static get type(): NodeType;
|
|
653
687
|
static from(data: SerializedERBUntilNode): ERBUntilNode;
|
|
654
688
|
constructor(props: ERBUntilNodeProps);
|
|
655
689
|
accept(visitor: Visitor): void;
|
|
@@ -680,6 +714,7 @@ export declare class ERBForNode extends Node {
|
|
|
680
714
|
readonly tag_closing: Token | null;
|
|
681
715
|
readonly statements: Node[];
|
|
682
716
|
readonly end_node: ERBEndNode | null;
|
|
717
|
+
static get type(): NodeType;
|
|
683
718
|
static from(data: SerializedERBForNode): ERBForNode;
|
|
684
719
|
constructor(props: ERBForNodeProps);
|
|
685
720
|
accept(visitor: Visitor): void;
|
|
@@ -710,6 +745,7 @@ export declare class ERBRescueNode extends Node {
|
|
|
710
745
|
readonly tag_closing: Token | null;
|
|
711
746
|
readonly statements: Node[];
|
|
712
747
|
readonly subsequent: ERBRescueNode | null;
|
|
748
|
+
static get type(): NodeType;
|
|
713
749
|
static from(data: SerializedERBRescueNode): ERBRescueNode;
|
|
714
750
|
constructor(props: ERBRescueNodeProps);
|
|
715
751
|
accept(visitor: Visitor): void;
|
|
@@ -737,6 +773,7 @@ export declare class ERBEnsureNode extends Node {
|
|
|
737
773
|
readonly content: Token | null;
|
|
738
774
|
readonly tag_closing: Token | null;
|
|
739
775
|
readonly statements: Node[];
|
|
776
|
+
static get type(): NodeType;
|
|
740
777
|
static from(data: SerializedERBEnsureNode): ERBEnsureNode;
|
|
741
778
|
constructor(props: ERBEnsureNodeProps);
|
|
742
779
|
accept(visitor: Visitor): void;
|
|
@@ -776,6 +813,7 @@ export declare class ERBBeginNode extends Node {
|
|
|
776
813
|
readonly else_clause: ERBElseNode | null;
|
|
777
814
|
readonly ensure_clause: ERBEnsureNode | null;
|
|
778
815
|
readonly end_node: ERBEndNode | null;
|
|
816
|
+
static get type(): NodeType;
|
|
779
817
|
static from(data: SerializedERBBeginNode): ERBBeginNode;
|
|
780
818
|
constructor(props: ERBBeginNodeProps);
|
|
781
819
|
accept(visitor: Visitor): void;
|
|
@@ -809,6 +847,7 @@ export declare class ERBUnlessNode extends Node {
|
|
|
809
847
|
readonly statements: Node[];
|
|
810
848
|
readonly else_clause: ERBElseNode | null;
|
|
811
849
|
readonly end_node: ERBEndNode | null;
|
|
850
|
+
static get type(): NodeType;
|
|
812
851
|
static from(data: SerializedERBUnlessNode): ERBUnlessNode;
|
|
813
852
|
constructor(props: ERBUnlessNodeProps);
|
|
814
853
|
accept(visitor: Visitor): void;
|
|
@@ -833,6 +872,7 @@ export declare class ERBYieldNode extends Node {
|
|
|
833
872
|
readonly tag_opening: Token | null;
|
|
834
873
|
readonly content: Token | null;
|
|
835
874
|
readonly tag_closing: Token | null;
|
|
875
|
+
static get type(): NodeType;
|
|
836
876
|
static from(data: SerializedERBYieldNode): ERBYieldNode;
|
|
837
877
|
constructor(props: ERBYieldNodeProps);
|
|
838
878
|
accept(visitor: Visitor): void;
|
|
@@ -860,6 +900,7 @@ export declare class ERBInNode extends Node {
|
|
|
860
900
|
readonly content: Token | null;
|
|
861
901
|
readonly tag_closing: Token | null;
|
|
862
902
|
readonly statements: Node[];
|
|
903
|
+
static get type(): NodeType;
|
|
863
904
|
static from(data: SerializedERBInNode): ERBInNode;
|
|
864
905
|
constructor(props: ERBInNodeProps);
|
|
865
906
|
accept(visitor: Visitor): void;
|
package/package.json
CHANGED
package/src/ast-utils.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Node,
|
|
2
3
|
LiteralNode,
|
|
4
|
+
ERBContentNode,
|
|
3
5
|
ERBIfNode,
|
|
4
6
|
ERBUnlessNode,
|
|
5
7
|
ERBBlockNode,
|
|
@@ -11,6 +13,7 @@ import {
|
|
|
11
13
|
HTMLElementNode,
|
|
12
14
|
HTMLOpenTagNode,
|
|
13
15
|
HTMLCloseTagNode,
|
|
16
|
+
HTMLAttributeNameNode,
|
|
14
17
|
HTMLCommentNode
|
|
15
18
|
} from "./nodes.js"
|
|
16
19
|
|
|
@@ -24,13 +27,17 @@ import {
|
|
|
24
27
|
filterLiteralNodes
|
|
25
28
|
} from "./node-type-guards.js"
|
|
26
29
|
|
|
27
|
-
import {
|
|
30
|
+
import type { Location } from "./location.js"
|
|
31
|
+
import type { Position } from "./position.js"
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
34
|
* Checks if a node is an ERB output node (generates content: <%= %> or <%== %>)
|
|
31
35
|
*/
|
|
32
36
|
export function isERBOutputNode(node: Node): node is ERBContentNode {
|
|
33
|
-
|
|
37
|
+
if (!isNode(node, ERBContentNode)) return false
|
|
38
|
+
if (!node.tag_opening?.value) return false
|
|
39
|
+
|
|
40
|
+
return ["<%=", "<%=="].includes(node.tag_opening?.value)
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
/**
|
|
@@ -179,7 +186,7 @@ export function getCombinedAttributeName(attributeNameNode: HTMLAttributeNameNod
|
|
|
179
186
|
/**
|
|
180
187
|
* Gets the tag name of an HTML element node
|
|
181
188
|
*/
|
|
182
|
-
export function getTagName(node: HTMLElementNode | HTMLOpenTagNode |
|
|
189
|
+
export function getTagName(node: HTMLElementNode | HTMLOpenTagNode | HTMLCloseTagNode): string {
|
|
183
190
|
return node.tag_name?.value ?? ""
|
|
184
191
|
}
|
|
185
192
|
|
|
@@ -189,3 +196,99 @@ export function getTagName(node: HTMLElementNode | HTMLOpenTagNode | HTMLCloseT
|
|
|
189
196
|
export function isCommentNode(node: Node): boolean {
|
|
190
197
|
return isNode(node, HTMLCommentNode) || (isERBNode(node) && !isERBControlFlowNode(node))
|
|
191
198
|
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Compares two positions to determine if the first comes before the second
|
|
202
|
+
* Returns true if pos1 comes before pos2 in source order
|
|
203
|
+
* @param inclusive - If true, returns true when positions are equal
|
|
204
|
+
*/
|
|
205
|
+
function isPositionBefore(position1: Position, position2: Position, inclusive = false): boolean {
|
|
206
|
+
if (position1.line < position2.line) return true
|
|
207
|
+
if (position1.line > position2.line) return false
|
|
208
|
+
|
|
209
|
+
return inclusive ? position1.column <= position2.column : position1.column < position2.column
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Compares two positions to determine if they are equal
|
|
214
|
+
* Returns true if pos1 and pos2 are at the same location
|
|
215
|
+
*/
|
|
216
|
+
export function isPositionEqual(position1: Position, position2: Position): boolean {
|
|
217
|
+
return position1.line === position2.line && position1.column === position2.column
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Compares two positions to determine if the first comes after the second
|
|
222
|
+
* Returns true if pos1 comes after pos2 in source order
|
|
223
|
+
* @param inclusive - If true, returns true when positions are equal
|
|
224
|
+
*/
|
|
225
|
+
export function isPositionAfter(position1: Position, position2: Position, inclusive = false): boolean {
|
|
226
|
+
if (position1.line > position2.line) return true
|
|
227
|
+
if (position1.line < position2.line) return false
|
|
228
|
+
|
|
229
|
+
return inclusive ? position1.column >= position2.column : position1.column > position2.column
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Gets nodes that appear before the specified location in source order
|
|
234
|
+
* Uses line and column positions to determine ordering
|
|
235
|
+
*/
|
|
236
|
+
export function getNodesBeforeLocation<T extends Node>(nodes: T[], location: Location): T[] {
|
|
237
|
+
return nodes.filter(node =>
|
|
238
|
+
node.location && isPositionBefore(node.location.end, location.start)
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Gets nodes that appear after the specified location in source order
|
|
244
|
+
* Uses line and column positions to determine ordering
|
|
245
|
+
*/
|
|
246
|
+
export function getNodesAfterLocation<T extends Node>(nodes: T[], location: Location): T[] {
|
|
247
|
+
return nodes.filter(node =>
|
|
248
|
+
node.location && isPositionAfter(node.location.start, location.end)
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Splits nodes into before and after the specified location
|
|
254
|
+
* Returns an object with `before` and `after` arrays
|
|
255
|
+
*/
|
|
256
|
+
export function splitNodesAroundLocation<T extends Node>(nodes: T[], location: Location): { before: T[], after: T[] } {
|
|
257
|
+
return {
|
|
258
|
+
before: getNodesBeforeLocation(nodes, location),
|
|
259
|
+
after: getNodesAfterLocation(nodes, location)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Splits nodes at a specific position
|
|
265
|
+
* Returns nodes that end before the position and nodes that start after the position
|
|
266
|
+
* More precise than splitNodesAroundLocation as it uses a single position point
|
|
267
|
+
* Uses the same defaults as the individual functions: before=exclusive, after=inclusive
|
|
268
|
+
*/
|
|
269
|
+
export function splitNodesAroundPosition<T extends Node>(nodes: T[], position: Position): { before: T[], after: T[] } {
|
|
270
|
+
return {
|
|
271
|
+
before: getNodesBeforePosition(nodes, position), // uses default: inclusive = false
|
|
272
|
+
after: getNodesAfterPosition(nodes, position) // uses default: inclusive = true
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Gets nodes that end before the specified position
|
|
278
|
+
* @param inclusive - If true, includes nodes that end exactly at the position (default: false, matching half-open interval semantics)
|
|
279
|
+
*/
|
|
280
|
+
export function getNodesBeforePosition<T extends Node>(nodes: T[], position: Position, inclusive = false): T[] {
|
|
281
|
+
return nodes.filter(node =>
|
|
282
|
+
node.location && isPositionBefore(node.location.end, position, inclusive)
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Gets nodes that start after the specified position
|
|
288
|
+
* @param inclusive - If true, includes nodes that start exactly at the position (default: true, matching typical boundary behavior)
|
|
289
|
+
*/
|
|
290
|
+
export function getNodesAfterPosition<T extends Node>(nodes: T[], position: Position, inclusive = true): T[] {
|
|
291
|
+
return nodes.filter(node =>
|
|
292
|
+
node.location && isPositionAfter(node.location.start, position, inclusive)
|
|
293
|
+
)
|
|
294
|
+
}
|
package/src/errors.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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-0.
|
|
2
|
+
// be modified manually. See /Users/marcoroth/Development/herb-release-0.7.0/templates/javascript/packages/core/src/errors.ts.erb
|
|
3
3
|
|
|
4
4
|
import { Location, SerializedLocation } from "./location.js"
|
|
5
5
|
import { Token, SerializedToken } from "./token.js"
|