@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.
@@ -1,5 +1,6 @@
1
- import { HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode } from "./nodes.js";
2
- import { Node, ERBContentNode, HTMLAttributeNameNode } from "./nodes.js";
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<string, (node: Node) => boolean>;
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
  /**
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herb-tools/core",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Core module exporting shared interfaces, AST node definitions, and common utilities for Herb",
5
5
  "type": "module",
6
6
  "license": "MIT",
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 { Node, ERBContentNode, HTMLAttributeNameNode } from "./nodes.js"
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
- return isNode(node, ERBContentNode) && ["<%=", "<%=="].includes((node as ERBContentNode).tag_opening?.value!)
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 | HTMLCloseTagNode): string {
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.6.0/templates/javascript/packages/core/src/errors.ts.erb
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"