@leadertechie/md2html 0.1.0-alpha.16 → 0.1.0-alpha.18

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/index.d.ts CHANGED
@@ -43,6 +43,51 @@ export declare class CodeHandler implements TokenHandler {
43
43
  };
44
44
  }
45
45
 
46
+ /**
47
+ * Built-in visitor: collect all nodes of a specific type.
48
+ */
49
+ export declare function collectByType(root: ContentNode, type: string): ContentNode[];
50
+
51
+ /**
52
+ * Walk a ContentNode tree and collect results from the visitor.
53
+ * The collector function is called for each node and returns a value or null.
54
+ */
55
+ export declare function collectFromTree<T>(root: ContentNode, collector: (node: ContentNode, parent: ContentNode | null, depth: number) => T | null): T[];
56
+
57
+ /**
58
+ * Built-in visitor: collect all headings with their levels.
59
+ */
60
+ export declare function collectHeadings(root: ContentNode): Array<{
61
+ level: string;
62
+ text: string;
63
+ id?: string;
64
+ }>;
65
+
66
+ /**
67
+ * Built-in visitor: collect all images with their src/alt.
68
+ */
69
+ export declare function collectImages(root: ContentNode): Array<{
70
+ src: string;
71
+ alt: string;
72
+ }>;
73
+
74
+ /**
75
+ * ContainerBlockHandler — handles custom :::tag#id.class container blocks.
76
+ *
77
+ * These are produced by the MarkdownParser's preprocessor which converts
78
+ * the ::: syntax into marked tokens before lexing, then reconstructs
79
+ * containerBlock tokens after lexing.
80
+ *
81
+ * The handler parses the specifier (e.g. "section#header.content") into
82
+ * tag name, id, and class(es), then recursively parses the inner tokens
83
+ * as normal markdown content, producing a container node with the
84
+ * specified HTML wrapper.
85
+ */
86
+ export declare class ContainerBlockHandler implements TokenHandler {
87
+ readonly type = "containerBlock";
88
+ handle(token: Record<string, unknown>, ctx: ParseContext): ContentNode | null;
89
+ }
90
+
46
91
  export declare interface ContentNode {
47
92
  type: ContentNodeType;
48
93
  content?: string;
@@ -63,6 +108,22 @@ export declare type ContentNodeType = 'text' | 'heading' | 'paragraph' | 'list'
63
108
  /** Default allowed HTML tags for preserveRawHTML mode */
64
109
  export declare const defaultAllowedHTMLTags: string[];
65
110
 
111
+ /**
112
+ * FrontmatterHandler — consumes YAML-ish frontmatter tokens produced by marked.lexer().
113
+ * Parses the raw YAML and stores key-value pairs onto ctx.metadata.
114
+ * Returns null so no HTML is emitted for frontmatter blocks.
115
+ *
116
+ * Handles both formats:
117
+ * key: value
118
+ * key:
119
+ * - item1
120
+ * - item2
121
+ */
122
+ export declare class FrontmatterHandler implements TokenHandler {
123
+ readonly type = "frontmatter";
124
+ handle(token: Record<string, unknown>, ctx: ParseContext): null;
125
+ }
126
+
66
127
  /**
67
128
  * Handles 'heading' tokens (h1-h6).
68
129
  */
@@ -110,7 +171,10 @@ export declare class HtmlHandler implements TokenHandler {
110
171
 
111
172
  export declare class HTMLRenderer {
112
173
  private config;
174
+ private strategyRegistry;
113
175
  constructor(config?: StyleConfigV2);
176
+ /** Access the strategy registry for customization. */
177
+ get strategies(): RendererStrategyRegistry;
114
178
  private hasClassConfig;
115
179
  private getClass;
116
180
  private generateHeadingId;
@@ -119,7 +183,12 @@ export declare class HTMLRenderer {
119
183
  * Returns empty string if emitScopeAnchors is disabled.
120
184
  */
121
185
  private getScopeAttr;
122
- private renderWithClass;
186
+ /**
187
+ * Get the CSS class for a container's tag-based rendering.
188
+ * Returns just the tag name since renderWithClass applies the prefix.
189
+ */
190
+ private getContainerClass;
191
+ private buildRenderContext;
123
192
  renderNode(node: ContentNode): string;
124
193
  renderNodes(nodes: ContentNode[]): string;
125
194
  renderToHTMLString(nodes: ContentNode[]): string;
@@ -139,6 +208,22 @@ export declare class ImageHandler implements TokenHandler {
139
208
  };
140
209
  }
141
210
 
211
+ /**
212
+ * Handles standalone 'link' tokens (e.g., reference-style links, or links
213
+ * that appear outside paragraphs in certain edge cases).
214
+ */
215
+ export declare class LinkHandler implements TokenHandler {
216
+ readonly type = "link";
217
+ handle(token: Record<string, unknown>, ctx: ParseContext): {
218
+ type: "link";
219
+ content: string;
220
+ attributes: {
221
+ title?: string | undefined;
222
+ href: string;
223
+ };
224
+ };
225
+ }
226
+
142
227
  /**
143
228
  * Handles 'list' tokens (ordered and unordered).
144
229
  */
@@ -198,7 +283,37 @@ export declare class MarkdownParser {
198
283
  * This is the bridge between the parser's private services and the handlers.
199
284
  */
200
285
  private createContext;
286
+ /**
287
+ * Process an array of marked tokens into ContentNodes.
288
+ * When depth === 0 (root), creates a shared context that accumulates metadata.
289
+ * For recursive calls (depth > 0), creates a fresh context for each level.
290
+ */
201
291
  private parseTokens;
292
+ /**
293
+ * Pre-process markdown: convert `:::tag#id.class` container syntax
294
+ * into HTML comment markers that marked will preserve as html tokens,
295
+ * but won't affect markdown parsing of the inner content.
296
+ *
297
+ * Example:
298
+ * :::section#header
299
+ * # Heading inside container
300
+ * Some text
301
+ * :::
302
+ *
303
+ * Becomes:
304
+ * <!-- md-container:section#header -->
305
+ * # Heading inside container
306
+ * Some text
307
+ * <!-- /md-container -->
308
+ */
309
+ private preprocessContainerBlocks;
310
+ /**
311
+ * Post-process marked tokens to collapse container block markers
312
+ * into structured containerBlock tokens with proper nesting.
313
+ *
314
+ * This handles nesting depth up to maxRecursionDepth.
315
+ */
316
+ private postprocessTokens;
202
317
  parse(markdown: string, options?: ParseOptions): MarkdownContent;
203
318
  parseToNodes(markdown: string, options?: ParseOptions): ContentNode[];
204
319
  }
@@ -220,11 +335,77 @@ export declare class MarkdownPipeline {
220
335
  getCustomCSS(): string;
221
336
  }
222
337
 
338
+ /**
339
+ * ContentNode factory — a builder API for creating ContentNode instances
340
+ * consistently across the codebase. Eliminates scattered object literals
341
+ * and provides type-safe construction with sensible defaults.
342
+ *
343
+ * Usage:
344
+ * NodeFactory.heading('Hello', { level: '1' })
345
+ * NodeFactory.paragraph('Some text')
346
+ * NodeFactory.container({ tag: 'section', id: 'main' }, [children...])
347
+ */
348
+ export declare class NodeFactory {
349
+ static heading(content: string, attributes?: Record<string, unknown>): ContentNode;
350
+ static paragraph(contentOrChildren: string | ContentNode[], children?: ContentNode[]): ContentNode;
351
+ static list(items: ContentNode[], ordered?: boolean, attributes?: Record<string, unknown>): ContentNode;
352
+ static listItem(content: string): ContentNode;
353
+ static image(src: string, alt?: string, className?: string): ContentNode;
354
+ static code(content: string, lang?: string): ContentNode;
355
+ static container(children?: ContentNode[], config?: {
356
+ tag?: string;
357
+ id?: string;
358
+ className?: string;
359
+ rawHTML?: string;
360
+ scope?: string;
361
+ }): ContentNode;
362
+ static text(content: string): ContentNode;
363
+ static strong(content: string): ContentNode;
364
+ static emphasis(content: string): ContentNode;
365
+ static link(href: string, content: string): ContentNode;
366
+ }
367
+
368
+ /**
369
+ * Strategy interface for rendering a specific ContentNode type to HTML.
370
+ * This is the renderer-side equivalent of TokenHandler — each node type
371
+ * gets its own strategy, eliminating the large switch statement.
372
+ *
373
+ * To add support for a new node type:
374
+ * 1. Create a class implementing NodeRendererStrategy
375
+ * 2. Register it with the RendererStrategyRegistry
376
+ */
377
+ export declare interface NodeRendererStrategy {
378
+ /** The node type this strategy handles */
379
+ readonly type: string;
380
+ /** Render a node of this type to an HTML string */
381
+ render(node: ContentNode, renderChild: (child: ContentNode) => string, ctx: RenderContext): string;
382
+ }
383
+
223
384
  /** Maps ContentNodeType to ScopeValue */
224
385
  export declare const nodeTypeToScope: Record<ContentNodeType, ScopeValue>;
225
386
 
226
387
  /**
227
- * Handles 'paragraph' tokens, including inline images and raw HTML.
388
+ * Visitor interface for traversing/walking a ContentNode AST.
389
+ *
390
+ * Implement this interface to inspect, collect, or transform nodes.
391
+ * Each method returns a ContentNode or null — returning null removes the node.
392
+ *
393
+ * Use cases:
394
+ * - Collect all images for preloading
395
+ * - Transform link URLs
396
+ * - Validate AST structure
397
+ * - Extract headings for ToC
398
+ * - Inject attributes
399
+ */
400
+ export declare interface NodeVisitor {
401
+ /** Called when entering a node, before visiting its children. */
402
+ enter?(node: ContentNode, parent: ContentNode | null, depth: number): ContentNode | null;
403
+ /** Called after visiting all children of the node. */
404
+ exit?(node: ContentNode, parent: ContentNode | null, depth: number): ContentNode | null;
405
+ }
406
+
407
+ /**
408
+ * Handles 'paragraph' tokens, including inline images, links, and raw HTML.
228
409
  */
229
410
  export declare class ParagraphHandler implements TokenHandler {
230
411
  readonly type = "paragraph";
@@ -253,6 +434,11 @@ export declare interface ParseContext {
253
434
  maxRecursionDepth: number;
254
435
  /** Report an unhandled token type so callers can be notified */
255
436
  reportUnhandled(type: string, token: Record<string, unknown>): void;
437
+ /**
438
+ * Shared metadata store populated by token handlers (e.g. FrontmatterHandler).
439
+ * After parsing, this object contains all frontmatter key-value pairs.
440
+ */
441
+ metadata: Record<string, unknown>;
256
442
  }
257
443
 
258
444
  export declare interface ParseOptions {
@@ -321,6 +507,49 @@ export declare interface PipelineConfigV2 extends PipelineConfig {
321
507
  allowedAttributes?: Record<string, string[]>;
322
508
  }
323
509
 
510
+ /**
511
+ * Context passed to every render strategy, providing access to
512
+ * shared rendering services and configuration.
513
+ */
514
+ export declare interface RenderContext {
515
+ classPrefix: string;
516
+ addHeadingIds: boolean;
517
+ emitScopeAnchors: boolean;
518
+ customCSS: string;
519
+ getClass(baseClass: string, nodeClass?: string): string;
520
+ getScopeAttr(node: ContentNode): string;
521
+ generateHeadingId(content?: string): string;
522
+ getContainerClass(tag: string): string;
523
+ hasClassConfig(): boolean;
524
+ }
525
+
526
+ /**
527
+ * Registry of renderer strategies. Maps ContentNode types to their
528
+ * rendering strategy. This is the renderer-side equivalent of
529
+ * TokenHandlerRegistry.
530
+ *
531
+ * The registry uses a two-tier lookup:
532
+ * 1. Check for a dedicated strategy by node type
533
+ * 2. Fall back to the catch-all strategy (registered as '*')
534
+ */
535
+ export declare class RendererStrategyRegistry {
536
+ private strategies;
537
+ private fallback;
538
+ constructor();
539
+ /** Register a strategy for a node type. Overrides any existing strategy. */
540
+ register(strategy: NodeRendererStrategy): void;
541
+ /** Unregister a strategy by node type. */
542
+ unregister(type: string): void;
543
+ /** Get a strategy for the given node type, falling back to catch-all. */
544
+ get(type: string): NodeRendererStrategy;
545
+ /** Check if a dedicated strategy exists for the given node type. */
546
+ has(type: string): boolean;
547
+ /** Get all registered dedicated strategy types. */
548
+ get types(): string[];
549
+ /** Replace the fallback strategy. */
550
+ setFallback(strategy: NodeRendererStrategy): void;
551
+ }
552
+
324
553
  /** Scope hierarchy values for data-md-scope */
325
554
  export declare type ScopeValue = 'root' | 'heading' | 'paragraph' | 'list' | 'list-item' | 'image' | 'code' | 'strong' | 'emphasis' | 'link' | 'container';
326
555
 
@@ -383,4 +612,10 @@ export declare class TokenHandlerRegistry {
383
612
  getCatchAll(): TokenHandler;
384
613
  }
385
614
 
615
+ /**
616
+ * Walk a ContentNode tree, applying a visitor at each node.
617
+ * Returns a new tree (immutable) — does not mutate the original.
618
+ */
619
+ export declare function walkTree(root: ContentNode, visitor: NodeVisitor): ContentNode;
620
+
386
621
  export { }