@herb-tools/core 0.8.9 → 0.9.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 { Node, ERBNode, ERBContentNode, HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLAttributeNameNode, HTMLCommentNode } from "./nodes.js";
2
- import type { Location } from "./location.js";
1
+ import { Node, LiteralNode, ERBNode, ERBContentNode, HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLAttributeNode, HTMLAttributeNameNode, HTMLAttributeValueNode, HTMLCommentNode, WhitespaceNode } from "./nodes.js";
2
+ import { Location } from "./location.js";
3
+ import { Token } from "./token.js";
3
4
  import type { Position } from "./position.js";
4
5
  export type ERBOutputNode = ERBNode & {
5
6
  tag_opening: {
@@ -80,13 +81,149 @@ export declare function getStaticAttributeName(attributeNameNode: HTMLAttributeN
80
81
  */
81
82
  export declare function getCombinedAttributeName(attributeNameNode: HTMLAttributeNameNode): string;
82
83
  /**
83
- * Gets the tag name of an HTML element node
84
+ * Gets the tag name of an HTML element, open tag, or close tag node.
85
+ * Returns null if the node is null/undefined.
84
86
  */
85
87
  export declare function getTagName(node: HTMLElementNode | HTMLOpenTagNode | HTMLCloseTagNode): string;
88
+ export declare function getTagName(node: HTMLElementNode | HTMLOpenTagNode | HTMLCloseTagNode | null | undefined): string | null;
89
+ /**
90
+ * Gets the lowercased tag name of an HTML element, open tag, or close tag node.
91
+ * Similar to `Element.localName` in the DOM API.
92
+ * Returns null if the node is null/undefined.
93
+ */
94
+ export declare function getTagLocalName(node: HTMLElementNode | HTMLOpenTagNode | HTMLCloseTagNode): string;
95
+ export declare function getTagLocalName(node: HTMLElementNode | HTMLOpenTagNode | HTMLCloseTagNode | null | undefined): string | null;
86
96
  /**
87
97
  * Check if a node is a comment (HTML comment or ERB comment)
88
98
  */
89
99
  export declare function isCommentNode(node: Node): node is HTMLCommentNode | ERBCommentNode;
100
+ /**
101
+ * Gets the open tag node from an HTMLElementNode, handling both regular and conditional open tags.
102
+ * For conditional open tags, returns null.
103
+ * If given an HTMLOpenTagNode directly, returns it as-is.
104
+ */
105
+ export declare function getOpenTag(node: HTMLElementNode | HTMLOpenTagNode | null | undefined): HTMLOpenTagNode | null;
106
+ /**
107
+ * Gets attributes from an HTMLElementNode or HTMLOpenTagNode
108
+ */
109
+ export declare function getAttributes(node: HTMLElementNode | HTMLOpenTagNode | null | undefined): HTMLAttributeNode[];
110
+ /**
111
+ * Gets the attribute name from an HTMLAttributeNode (lowercased)
112
+ * Returns null if the attribute name contains dynamic content (ERB)
113
+ */
114
+ export declare function getAttributeName(attributeNode: HTMLAttributeNode, lowercase?: boolean): string | null;
115
+ /**
116
+ * Checks if an attribute value contains only static content (no ERB).
117
+ * Accepts an HTMLAttributeNode directly, or an element/open tag + attribute name.
118
+ * Returns false for null/undefined input.
119
+ */
120
+ export declare function hasStaticAttributeValue(attributeNode: HTMLAttributeNode | null | undefined): boolean;
121
+ export declare function hasStaticAttributeValue(node: HTMLElementNode | HTMLOpenTagNode | null | undefined, attributeName: string): boolean;
122
+ /**
123
+ * Gets the static string value of an attribute (returns null if it contains ERB).
124
+ * Accepts an HTMLAttributeNode directly, or an element/open tag + attribute name.
125
+ * Returns null for null/undefined input.
126
+ */
127
+ export declare function getStaticAttributeValue(attributeNode: HTMLAttributeNode | null | undefined): string | null;
128
+ export declare function getStaticAttributeValue(node: HTMLElementNode | HTMLOpenTagNode | null | undefined, attributeName: string): string | null;
129
+ /**
130
+ * Attributes whose values are space-separated token lists.
131
+ */
132
+ export declare const TOKEN_LIST_ATTRIBUTES: Set<string>;
133
+ /**
134
+ * Splits a space-separated attribute value into individual tokens.
135
+ * Accepts a string, or an element/open tag + attribute name to look up.
136
+ * Returns an empty array for null/undefined/empty input.
137
+ */
138
+ export declare function getTokenList(value: string | null | undefined): string[];
139
+ export declare function getTokenList(node: HTMLElementNode | HTMLOpenTagNode | null | undefined, attributeName: string): string[];
140
+ /**
141
+ * Finds an attribute by name in a list of attribute nodes
142
+ */
143
+ export declare function findAttributeByName(attributes: Node[], attributeName: string): HTMLAttributeNode | null;
144
+ /**
145
+ * Gets a specific attribute from an HTMLElementNode or HTMLOpenTagNode by name
146
+ */
147
+ export declare function getAttribute(node: HTMLElementNode | HTMLOpenTagNode | null | undefined, attributeName: string): HTMLAttributeNode | null;
148
+ /**
149
+ * Checks if an element or open tag has a specific attribute
150
+ */
151
+ export declare function hasAttribute(node: HTMLElementNode | HTMLOpenTagNode | null | undefined, attributeName: string): boolean;
152
+ /**
153
+ * Checks if an attribute has a dynamic (ERB-containing) name.
154
+ * Accepts an HTMLAttributeNode (wraps the core HTMLAttributeNameNode-level check).
155
+ */
156
+ export declare function hasDynamicAttributeNameOnAttribute(attributeNode: HTMLAttributeNode): boolean;
157
+ /**
158
+ * Gets the combined string representation of an attribute name (including ERB syntax).
159
+ * Accepts an HTMLAttributeNode (wraps the core HTMLAttributeNameNode-level check).
160
+ */
161
+ export declare function getCombinedAttributeNameString(attributeNode: HTMLAttributeNode): string;
162
+ /**
163
+ * Checks if an attribute value contains dynamic content (ERB)
164
+ */
165
+ export declare function hasDynamicAttributeValue(attributeNode: HTMLAttributeNode): boolean;
166
+ /**
167
+ * Gets the value nodes array from an attribute for dynamic inspection
168
+ */
169
+ export declare function getAttributeValueNodes(attributeNode: HTMLAttributeNode): Node[];
170
+ /**
171
+ * Checks if an attribute value contains any static content (for validation purposes)
172
+ */
173
+ export declare function hasStaticAttributeValueContent(attributeNode: HTMLAttributeNode): boolean;
174
+ /**
175
+ * Gets the static content of an attribute value (all literal parts combined).
176
+ * Unlike getStaticAttributeValue, this extracts only the static portions from mixed content.
177
+ * Returns the concatenated literal content, or null if no literal nodes exist.
178
+ */
179
+ export declare function getStaticAttributeValueContent(attributeNode: HTMLAttributeNode): string | null;
180
+ /**
181
+ * Gets the combined attribute value including both static text and ERB tag syntax.
182
+ * For ERB nodes, includes the full tag syntax (e.g., "<%= foo %>").
183
+ * Returns null if the attribute has no value.
184
+ */
185
+ export declare function getAttributeValue(attributeNode: HTMLAttributeNode): string | null;
186
+ /**
187
+ * Checks if an attribute has a value node
188
+ */
189
+ export declare function hasAttributeValue(attributeNode: HTMLAttributeNode): boolean;
190
+ /**
191
+ * Gets the quote type used for an attribute value
192
+ */
193
+ export declare function getAttributeValueQuoteType(node: HTMLAttributeNode | HTMLAttributeValueNode): "single" | "double" | "none" | null;
194
+ /**
195
+ * Checks if an attribute value is quoted
196
+ */
197
+ export declare function isAttributeValueQuoted(attributeNode: HTMLAttributeNode): boolean;
198
+ /**
199
+ * Iterates over all attributes of an element or open tag node
200
+ */
201
+ export declare function forEachAttribute(node: HTMLElementNode | HTMLOpenTagNode, callback: (attributeNode: HTMLAttributeNode) => void): void;
202
+ /**
203
+ * Checks if a node is a whitespace-only literal or text node (no visible content)
204
+ */
205
+ export declare function isPureWhitespaceNode(node: Node): boolean;
206
+ /**
207
+ * Splits literal nodes at whitespace boundaries into separate nodes.
208
+ * Non-literal nodes are passed through unchanged.
209
+ *
210
+ * For example, a literal `"bg-blue-500 text-white"` becomes two literals:
211
+ * `"bg-blue-500"` and `" "` and `"text-white"`.
212
+ */
213
+ export declare function splitLiteralsAtWhitespace(nodes: Node[]): Node[];
214
+ /**
215
+ * Groups split nodes into "class groups" where each group represents a single
216
+ * class name (possibly spanning multiple nodes when ERB is interpolated).
217
+ *
218
+ * For example, `text-<%= color %>-500 bg-blue-500` produces two groups:
219
+ * - [`text-`, ERB, `-500`] (interpolated class)
220
+ * - [`bg-blue-500`] (static class)
221
+ *
222
+ * The key heuristic: a hyphen at a node boundary means the nodes are part of
223
+ * the same class name (e.g., `bg-` + ERB + `-500`), while whitespace means
224
+ * a new class name starts.
225
+ */
226
+ export declare function groupNodesByClass(nodes: Node[]): Node[][];
90
227
  /**
91
228
  * Compares two positions to determine if they are equal
92
229
  * Returns true if pos1 and pos2 are at the same location
@@ -136,3 +273,48 @@ export declare function getNodesBeforePosition<T extends Node>(nodes: T[], posit
136
273
  * @param inclusive - If true, includes nodes that start exactly at the position (default: true, matching typical boundary behavior)
137
274
  */
138
275
  export declare function getNodesAfterPosition<T extends Node>(nodes: T[], position: Position, inclusive?: boolean): T[];
276
+ /**
277
+ * Checks if two attributes are structurally equivalent (same name and value),
278
+ * ignoring positional data like location and range.
279
+ */
280
+ export declare function isEquivalentAttribute(first: HTMLAttributeNode, second: HTMLAttributeNode): boolean;
281
+ /**
282
+ * Checks if two open tags are structurally equivalent (same tag name and attributes),
283
+ * ignoring positional data like location and range.
284
+ */
285
+ export declare function isEquivalentOpenTag(first: HTMLOpenTagNode, second: HTMLOpenTagNode): boolean;
286
+ /**
287
+ * Checks if two elements have structurally equivalent open tags (same tag name and attributes),
288
+ * ignoring positional data like location and range. Does not compare body or close tag.
289
+ */
290
+ export declare function isEquivalentElement(first: HTMLElementNode, second: HTMLElementNode): boolean;
291
+ /**
292
+ * Finds the array containing a target node in the AST, along with its index.
293
+ * Traverses child arrays and linked node properties (e.g., `subsequent`, `else_clause`).
294
+ *
295
+ * Useful for autofix operations that need to splice nodes in/out of their parent array.
296
+ *
297
+ * @param root - The root node to search from
298
+ * @param target - The node to find
299
+ * @returns The containing array and the target's index, or null if not found
300
+ */
301
+ export declare function findParentArray(root: Node, target: Node): {
302
+ array: Node[];
303
+ index: number;
304
+ } | null;
305
+ /**
306
+ * Removes a node from an array, also removing an adjacent preceding
307
+ * whitespace-only literal if present.
308
+ */
309
+ export declare function removeNodeFromArray(array: Node[], node: Node): void;
310
+ /**
311
+ * Replaces an element in an array with its body (children), effectively unwrapping it.
312
+ */
313
+ export declare function replaceNodeWithBody(array: Node[], element: HTMLElementNode): void;
314
+ /**
315
+ * Creates a synthetic LiteralNode with the given content and zero location.
316
+ * Useful for inserting whitespace or newlines during AST mutations.
317
+ */
318
+ export declare function createLiteral(content: string): LiteralNode;
319
+ export declare function createSyntheticToken(value: string, type?: string): Token;
320
+ export declare function createWhitespaceNode(): WhitespaceNode;
@@ -1,17 +1,17 @@
1
1
  import type { SerializedParseResult } from "./parse-result.js";
2
2
  import type { SerializedLexResult } from "./lex-result.js";
3
- import type { ParserOptions } from "./parser-options.js";
3
+ import type { ParseOptions } from "./parser-options.js";
4
+ import type { ExtractRubyOptions } from "./extract-ruby-options.js";
4
5
  interface LibHerbBackendFunctions {
5
6
  lex: (source: string) => SerializedLexResult;
6
- lexFile: (path: string) => SerializedLexResult;
7
- parse: (source: string, options?: ParserOptions) => SerializedParseResult;
8
- parseFile: (path: string) => SerializedParseResult;
9
- extractRuby: (source: string) => string;
7
+ parse: (source: string, options?: ParseOptions) => SerializedParseResult;
8
+ extractRuby: (source: string, options?: ExtractRubyOptions) => string;
10
9
  extractHTML: (source: string) => string;
10
+ parseRuby: (source: string) => Uint8Array | null;
11
11
  version: () => string;
12
12
  }
13
13
  export type BackendPromise = () => Promise<LibHerbBackend>;
14
- declare const expectedFunctions: readonly ["parse", "lex", "parseFile", "lexFile", "extractRuby", "extractHTML", "version"];
14
+ declare const expectedFunctions: readonly ["parse", "lex", "extractRuby", "extractHTML", "parseRuby", "version"];
15
15
  type LibHerbBackendFunctionName = (typeof expectedFunctions)[number];
16
16
  export declare function _TYPECHECK(): {
17
17
  checkFunctionsExist: true;
@@ -1,7 +1,8 @@
1
1
  import { Location, SerializedLocation } from "./location.js";
2
+ import { Position, SerializedPosition } from "./position.js";
2
3
  import { Token, SerializedToken } from "./token.js";
3
4
  import { Diagnostic, MonacoDiagnostic } from "./diagnostic.js";
4
- export type HerbErrorType = "UNEXPECTED_ERROR" | "UNEXPECTED_TOKEN_ERROR" | "MISSING_OPENING_TAG_ERROR" | "MISSING_CLOSING_TAG_ERROR" | "TAG_NAMES_MISMATCH_ERROR" | "QUOTES_MISMATCH_ERROR" | "VOID_ELEMENT_CLOSING_TAG_ERROR" | "UNCLOSED_ELEMENT_ERROR" | "RUBY_PARSE_ERROR" | "ERB_CONTROL_FLOW_SCOPE_ERROR" | "MISSINGERB_END_TAG_ERROR" | "ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR";
5
+ export type HerbErrorType = "UNEXPECTED_ERROR" | "UNEXPECTED_TOKEN_ERROR" | "MISSING_OPENING_TAG_ERROR" | "MISSING_CLOSING_TAG_ERROR" | "TAG_NAMES_MISMATCH_ERROR" | "VOID_ELEMENT_CLOSING_TAG_ERROR" | "UNCLOSED_ELEMENT_ERROR" | "RUBY_PARSE_ERROR" | "ERB_CONTROL_FLOW_SCOPE_ERROR" | "MISSING_ERB_END_TAG_ERROR" | "ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR" | "ERB_CASE_WITH_CONDITIONS_ERROR" | "CONDITIONAL_ELEMENT_MULTIPLE_TAGS_ERROR" | "CONDITIONAL_ELEMENT_CONDITION_MISMATCH_ERROR" | "INVALID_COMMENT_CLOSING_TAG_ERROR" | "OMITTED_CLOSING_TAG_ERROR" | "UNCLOSED_OPEN_TAG_ERROR" | "UNCLOSED_CLOSE_TAG_ERROR" | "UNCLOSED_QUOTE_ERROR" | "MISSING_ATTRIBUTE_VALUE_ERROR" | "UNCLOSED_ERB_TAG_ERROR" | "STRAY_ERB_CLOSING_TAG_ERROR" | "NESTED_ERB_TAG_ERROR";
5
6
  export type SerializedErrorType = string;
6
7
  export interface SerializedHerbError {
7
8
  type: string;
@@ -133,29 +134,6 @@ export declare class TagNamesMismatchError extends HerbError {
133
134
  toMonacoDiagnostic(): MonacoDiagnostic;
134
135
  treeInspect(): string;
135
136
  }
136
- export interface SerializedQuotesMismatchError {
137
- type: "QUOTES_MISMATCH_ERROR";
138
- message: string;
139
- location: SerializedLocation;
140
- opening_quote: SerializedToken | null;
141
- closing_quote: SerializedToken | null;
142
- }
143
- export interface QuotesMismatchErrorProps {
144
- type: string;
145
- message: string;
146
- location: Location;
147
- opening_quote: Token | null;
148
- closing_quote: Token | null;
149
- }
150
- export declare class QuotesMismatchError extends HerbError {
151
- readonly opening_quote: Token | null;
152
- readonly closing_quote: Token | null;
153
- static from(data: SerializedQuotesMismatchError): QuotesMismatchError;
154
- constructor(props: QuotesMismatchErrorProps);
155
- toJSON(): SerializedQuotesMismatchError;
156
- toMonacoDiagnostic(): MonacoDiagnostic;
157
- treeInspect(): string;
158
- }
159
137
  export interface SerializedVoidElementClosingTagError {
160
138
  type: "VOID_ELEMENT_CLOSING_TAG_ERROR";
161
139
  message: string;
@@ -249,7 +227,7 @@ export declare class ERBControlFlowScopeError extends HerbError {
249
227
  treeInspect(): string;
250
228
  }
251
229
  export interface SerializedMissingERBEndTagError {
252
- type: "MISSINGERB_END_TAG_ERROR";
230
+ type: "MISSING_ERB_END_TAG_ERROR";
253
231
  message: string;
254
232
  location: SerializedLocation;
255
233
  keyword: string;
@@ -285,4 +263,268 @@ export declare class ERBMultipleBlocksInTagError extends HerbError {
285
263
  toMonacoDiagnostic(): MonacoDiagnostic;
286
264
  treeInspect(): string;
287
265
  }
266
+ export interface SerializedERBCaseWithConditionsError {
267
+ type: "ERB_CASE_WITH_CONDITIONS_ERROR";
268
+ message: string;
269
+ location: SerializedLocation;
270
+ }
271
+ export interface ERBCaseWithConditionsErrorProps {
272
+ type: string;
273
+ message: string;
274
+ location: Location;
275
+ }
276
+ export declare class ERBCaseWithConditionsError extends HerbError {
277
+ static from(data: SerializedERBCaseWithConditionsError): ERBCaseWithConditionsError;
278
+ constructor(props: ERBCaseWithConditionsErrorProps);
279
+ toJSON(): SerializedERBCaseWithConditionsError;
280
+ toMonacoDiagnostic(): MonacoDiagnostic;
281
+ treeInspect(): string;
282
+ }
283
+ export interface SerializedConditionalElementMultipleTagsError {
284
+ type: "CONDITIONAL_ELEMENT_MULTIPLE_TAGS_ERROR";
285
+ message: string;
286
+ location: SerializedLocation;
287
+ line: any;
288
+ column: any;
289
+ }
290
+ export interface ConditionalElementMultipleTagsErrorProps {
291
+ type: string;
292
+ message: string;
293
+ location: Location;
294
+ line: any;
295
+ column: any;
296
+ }
297
+ export declare class ConditionalElementMultipleTagsError extends HerbError {
298
+ readonly line: any;
299
+ readonly column: any;
300
+ static from(data: SerializedConditionalElementMultipleTagsError): ConditionalElementMultipleTagsError;
301
+ constructor(props: ConditionalElementMultipleTagsErrorProps);
302
+ toJSON(): SerializedConditionalElementMultipleTagsError;
303
+ toMonacoDiagnostic(): MonacoDiagnostic;
304
+ treeInspect(): string;
305
+ }
306
+ export interface SerializedConditionalElementConditionMismatchError {
307
+ type: "CONDITIONAL_ELEMENT_CONDITION_MISMATCH_ERROR";
308
+ message: string;
309
+ location: SerializedLocation;
310
+ tag_name: string;
311
+ open_condition: string;
312
+ open_line: any;
313
+ open_column: any;
314
+ close_condition: string;
315
+ close_line: any;
316
+ close_column: any;
317
+ }
318
+ export interface ConditionalElementConditionMismatchErrorProps {
319
+ type: string;
320
+ message: string;
321
+ location: Location;
322
+ tag_name: string;
323
+ open_condition: string;
324
+ open_line: any;
325
+ open_column: any;
326
+ close_condition: string;
327
+ close_line: any;
328
+ close_column: any;
329
+ }
330
+ export declare class ConditionalElementConditionMismatchError extends HerbError {
331
+ readonly tag_name: string;
332
+ readonly open_condition: string;
333
+ readonly open_line: any;
334
+ readonly open_column: any;
335
+ readonly close_condition: string;
336
+ readonly close_line: any;
337
+ readonly close_column: any;
338
+ static from(data: SerializedConditionalElementConditionMismatchError): ConditionalElementConditionMismatchError;
339
+ constructor(props: ConditionalElementConditionMismatchErrorProps);
340
+ toJSON(): SerializedConditionalElementConditionMismatchError;
341
+ toMonacoDiagnostic(): MonacoDiagnostic;
342
+ treeInspect(): string;
343
+ }
344
+ export interface SerializedInvalidCommentClosingTagError {
345
+ type: "INVALID_COMMENT_CLOSING_TAG_ERROR";
346
+ message: string;
347
+ location: SerializedLocation;
348
+ closing_tag: SerializedToken | null;
349
+ }
350
+ export interface InvalidCommentClosingTagErrorProps {
351
+ type: string;
352
+ message: string;
353
+ location: Location;
354
+ closing_tag: Token | null;
355
+ }
356
+ export declare class InvalidCommentClosingTagError extends HerbError {
357
+ readonly closing_tag: Token | null;
358
+ static from(data: SerializedInvalidCommentClosingTagError): InvalidCommentClosingTagError;
359
+ constructor(props: InvalidCommentClosingTagErrorProps);
360
+ toJSON(): SerializedInvalidCommentClosingTagError;
361
+ toMonacoDiagnostic(): MonacoDiagnostic;
362
+ treeInspect(): string;
363
+ }
364
+ export interface SerializedOmittedClosingTagError {
365
+ type: "OMITTED_CLOSING_TAG_ERROR";
366
+ message: string;
367
+ location: SerializedLocation;
368
+ opening_tag: SerializedToken | null;
369
+ insertion_point: SerializedPosition;
370
+ }
371
+ export interface OmittedClosingTagErrorProps {
372
+ type: string;
373
+ message: string;
374
+ location: Location;
375
+ opening_tag: Token | null;
376
+ insertion_point: Position;
377
+ }
378
+ export declare class OmittedClosingTagError extends HerbError {
379
+ readonly opening_tag: Token | null;
380
+ readonly insertion_point: Position;
381
+ static from(data: SerializedOmittedClosingTagError): OmittedClosingTagError;
382
+ constructor(props: OmittedClosingTagErrorProps);
383
+ toJSON(): SerializedOmittedClosingTagError;
384
+ toMonacoDiagnostic(): MonacoDiagnostic;
385
+ treeInspect(): string;
386
+ }
387
+ export interface SerializedUnclosedOpenTagError {
388
+ type: "UNCLOSED_OPEN_TAG_ERROR";
389
+ message: string;
390
+ location: SerializedLocation;
391
+ tag_name: SerializedToken | null;
392
+ }
393
+ export interface UnclosedOpenTagErrorProps {
394
+ type: string;
395
+ message: string;
396
+ location: Location;
397
+ tag_name: Token | null;
398
+ }
399
+ export declare class UnclosedOpenTagError extends HerbError {
400
+ readonly tag_name: Token | null;
401
+ static from(data: SerializedUnclosedOpenTagError): UnclosedOpenTagError;
402
+ constructor(props: UnclosedOpenTagErrorProps);
403
+ toJSON(): SerializedUnclosedOpenTagError;
404
+ toMonacoDiagnostic(): MonacoDiagnostic;
405
+ treeInspect(): string;
406
+ }
407
+ export interface SerializedUnclosedCloseTagError {
408
+ type: "UNCLOSED_CLOSE_TAG_ERROR";
409
+ message: string;
410
+ location: SerializedLocation;
411
+ tag_name: SerializedToken | null;
412
+ }
413
+ export interface UnclosedCloseTagErrorProps {
414
+ type: string;
415
+ message: string;
416
+ location: Location;
417
+ tag_name: Token | null;
418
+ }
419
+ export declare class UnclosedCloseTagError extends HerbError {
420
+ readonly tag_name: Token | null;
421
+ static from(data: SerializedUnclosedCloseTagError): UnclosedCloseTagError;
422
+ constructor(props: UnclosedCloseTagErrorProps);
423
+ toJSON(): SerializedUnclosedCloseTagError;
424
+ toMonacoDiagnostic(): MonacoDiagnostic;
425
+ treeInspect(): string;
426
+ }
427
+ export interface SerializedUnclosedQuoteError {
428
+ type: "UNCLOSED_QUOTE_ERROR";
429
+ message: string;
430
+ location: SerializedLocation;
431
+ opening_quote: SerializedToken | null;
432
+ }
433
+ export interface UnclosedQuoteErrorProps {
434
+ type: string;
435
+ message: string;
436
+ location: Location;
437
+ opening_quote: Token | null;
438
+ }
439
+ export declare class UnclosedQuoteError extends HerbError {
440
+ readonly opening_quote: Token | null;
441
+ static from(data: SerializedUnclosedQuoteError): UnclosedQuoteError;
442
+ constructor(props: UnclosedQuoteErrorProps);
443
+ toJSON(): SerializedUnclosedQuoteError;
444
+ toMonacoDiagnostic(): MonacoDiagnostic;
445
+ treeInspect(): string;
446
+ }
447
+ export interface SerializedMissingAttributeValueError {
448
+ type: "MISSING_ATTRIBUTE_VALUE_ERROR";
449
+ message: string;
450
+ location: SerializedLocation;
451
+ attribute_name: string;
452
+ }
453
+ export interface MissingAttributeValueErrorProps {
454
+ type: string;
455
+ message: string;
456
+ location: Location;
457
+ attribute_name: string;
458
+ }
459
+ export declare class MissingAttributeValueError extends HerbError {
460
+ readonly attribute_name: string;
461
+ static from(data: SerializedMissingAttributeValueError): MissingAttributeValueError;
462
+ constructor(props: MissingAttributeValueErrorProps);
463
+ toJSON(): SerializedMissingAttributeValueError;
464
+ toMonacoDiagnostic(): MonacoDiagnostic;
465
+ treeInspect(): string;
466
+ }
467
+ export interface SerializedUnclosedERBTagError {
468
+ type: "UNCLOSED_ERB_TAG_ERROR";
469
+ message: string;
470
+ location: SerializedLocation;
471
+ opening_tag: SerializedToken | null;
472
+ }
473
+ export interface UnclosedERBTagErrorProps {
474
+ type: string;
475
+ message: string;
476
+ location: Location;
477
+ opening_tag: Token | null;
478
+ }
479
+ export declare class UnclosedERBTagError extends HerbError {
480
+ readonly opening_tag: Token | null;
481
+ static from(data: SerializedUnclosedERBTagError): UnclosedERBTagError;
482
+ constructor(props: UnclosedERBTagErrorProps);
483
+ toJSON(): SerializedUnclosedERBTagError;
484
+ toMonacoDiagnostic(): MonacoDiagnostic;
485
+ treeInspect(): string;
486
+ }
487
+ export interface SerializedStrayERBClosingTagError {
488
+ type: "STRAY_ERB_CLOSING_TAG_ERROR";
489
+ message: string;
490
+ location: SerializedLocation;
491
+ }
492
+ export interface StrayERBClosingTagErrorProps {
493
+ type: string;
494
+ message: string;
495
+ location: Location;
496
+ }
497
+ export declare class StrayERBClosingTagError extends HerbError {
498
+ static from(data: SerializedStrayERBClosingTagError): StrayERBClosingTagError;
499
+ constructor(props: StrayERBClosingTagErrorProps);
500
+ toJSON(): SerializedStrayERBClosingTagError;
501
+ toMonacoDiagnostic(): MonacoDiagnostic;
502
+ treeInspect(): string;
503
+ }
504
+ export interface SerializedNestedERBTagError {
505
+ type: "NESTED_ERB_TAG_ERROR";
506
+ message: string;
507
+ location: SerializedLocation;
508
+ opening_tag: SerializedToken | null;
509
+ nested_tag_line: any;
510
+ nested_tag_column: any;
511
+ }
512
+ export interface NestedERBTagErrorProps {
513
+ type: string;
514
+ message: string;
515
+ location: Location;
516
+ opening_tag: Token | null;
517
+ nested_tag_line: any;
518
+ nested_tag_column: any;
519
+ }
520
+ export declare class NestedERBTagError extends HerbError {
521
+ readonly opening_tag: Token | null;
522
+ readonly nested_tag_line: any;
523
+ readonly nested_tag_column: any;
524
+ static from(data: SerializedNestedERBTagError): NestedERBTagError;
525
+ constructor(props: NestedERBTagErrorProps);
526
+ toJSON(): SerializedNestedERBTagError;
527
+ toMonacoDiagnostic(): MonacoDiagnostic;
528
+ treeInspect(): string;
529
+ }
288
530
  export declare function fromSerializedError(error: SerializedHerbError): HerbError;
@@ -0,0 +1,6 @@
1
+ export interface ExtractRubyOptions {
2
+ semicolons?: boolean;
3
+ comments?: boolean;
4
+ preserve_positions?: boolean;
5
+ }
6
+ export declare const DEFAULT_EXTRACT_RUBY_OPTIONS: ExtractRubyOptions;
@@ -1,7 +1,9 @@
1
1
  import { LexResult } from "./lex-result.js";
2
2
  import { ParseResult } from "./parse-result.js";
3
3
  import type { LibHerbBackend, BackendPromise } from "./backend.js";
4
- import type { ParserOptions } from "./parser-options.js";
4
+ import type { ParseOptions } from "./parser-options.js";
5
+ import type { ExtractRubyOptions } from "./extract-ruby-options.js";
6
+ import type { PrismParseResult } from "./prism/index.js";
5
7
  /**
6
8
  * The main Herb parser interface, providing methods to lex and parse input.
7
9
  */
@@ -31,9 +33,8 @@ export declare abstract class HerbBackend {
31
33
  * Lexes a file.
32
34
  * @param path - The file path to lex.
33
35
  * @returns A `LexResult` instance.
34
- * @throws Error if the backend is not loaded.
35
36
  */
36
- lexFile(path: string): LexResult;
37
+ abstract lexFile(path: string): LexResult;
37
38
  /**
38
39
  * Parses the given source string into a `ParseResult`.
39
40
  * @param source - The source code to parse.
@@ -41,21 +42,28 @@ export declare abstract class HerbBackend {
41
42
  * @returns A `ParseResult` instance.
42
43
  * @throws Error if the backend is not loaded.
43
44
  */
44
- parse(source: string, options?: ParserOptions): ParseResult;
45
+ parse(source: string, options?: ParseOptions): ParseResult;
45
46
  /**
46
47
  * Parses a file.
47
48
  * @param path - The file path to parse.
48
49
  * @returns A `ParseResult` instance.
49
- * @throws Error if the backend is not loaded.
50
50
  */
51
- parseFile(path: string): ParseResult;
51
+ abstract parseFile(path: string): ParseResult;
52
52
  /**
53
53
  * Extracts embedded Ruby code from the given source.
54
54
  * @param source - The source code to extract Ruby from.
55
+ * @param options - Optional extraction options.
55
56
  * @returns The extracted Ruby code as a string.
56
57
  * @throws Error if the backend is not loaded.
57
58
  */
58
- extractRuby(source: string): string;
59
+ extractRuby(source: string, options?: ExtractRubyOptions): string;
60
+ /**
61
+ * Parses a Ruby source string using Prism via the libherb backend.
62
+ * @param source - The Ruby source code to parse.
63
+ * @returns A Prism ParseResult containing the AST.
64
+ * @throws Error if the backend is not loaded.
65
+ */
66
+ parseRuby(source: string): PrismParseResult;
59
67
  /**
60
68
  * Extracts HTML from the given source.
61
69
  * @param source - The source code to extract HTML from.
@@ -3,6 +3,7 @@ export * from "./backend.js";
3
3
  export * from "./diagnostic.js";
4
4
  export * from "./didyoumean.js";
5
5
  export * from "./errors.js";
6
+ export * from "./extract-ruby-options.js";
6
7
  export * from "./herb-backend.js";
7
8
  export * from "./levenshtein.js";
8
9
  export * from "./lex-result.js";
@@ -19,3 +20,4 @@ export * from "./token.js";
19
20
  export * from "./util.js";
20
21
  export * from "./visitor.js";
21
22
  export * from "./warning.js";
23
+ export * from "./prism";