@leadertechie/md2html 0.1.0-alpha.15 → 0.1.0-alpha.17
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 +249 -1
- package/dist/index.js +590 -68
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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;
|
|
@@ -169,6 +238,7 @@ export declare class MarkdownParser {
|
|
|
169
238
|
private errorRecovery;
|
|
170
239
|
private maxRecursionDepth;
|
|
171
240
|
private allowedHTMLTags;
|
|
241
|
+
private allowedAttributes;
|
|
172
242
|
private handlerRegistry;
|
|
173
243
|
private onUnhandledToken?;
|
|
174
244
|
constructor(options?: ParserOptions);
|
|
@@ -177,13 +247,57 @@ export declare class MarkdownParser {
|
|
|
177
247
|
private processImagePath;
|
|
178
248
|
private processInlineFormatting;
|
|
179
249
|
private processSlots;
|
|
250
|
+
/**
|
|
251
|
+
* Check if an attribute name is allowed for a given tag.
|
|
252
|
+
* Supports "data-*" wildcard prefix matching.
|
|
253
|
+
*/
|
|
254
|
+
private isAttributeAllowed;
|
|
255
|
+
/**
|
|
256
|
+
* Check if an attribute name matches a list of allowed patterns.
|
|
257
|
+
* Supports "data-*" wildcard prefix matching.
|
|
258
|
+
*/
|
|
259
|
+
private matchesAttributeList;
|
|
260
|
+
/**
|
|
261
|
+
* Filter attributes on an HTML tag, keeping only allowed ones.
|
|
262
|
+
*/
|
|
263
|
+
private filterTagAttributes;
|
|
180
264
|
private processRawHTML;
|
|
181
265
|
/**
|
|
182
266
|
* Build the ParseContext that is passed to every token handler.
|
|
183
267
|
* This is the bridge between the parser's private services and the handlers.
|
|
184
268
|
*/
|
|
185
269
|
private createContext;
|
|
270
|
+
/**
|
|
271
|
+
* Process an array of marked tokens into ContentNodes.
|
|
272
|
+
* When depth === 0 (root), creates a shared context that accumulates metadata.
|
|
273
|
+
* For recursive calls (depth > 0), creates a fresh context for each level.
|
|
274
|
+
*/
|
|
186
275
|
private parseTokens;
|
|
276
|
+
/**
|
|
277
|
+
* Pre-process markdown: convert `:::tag#id.class` container syntax
|
|
278
|
+
* into HTML comment markers that marked will preserve as html tokens,
|
|
279
|
+
* but won't affect markdown parsing of the inner content.
|
|
280
|
+
*
|
|
281
|
+
* Example:
|
|
282
|
+
* :::section#header
|
|
283
|
+
* # Heading inside container
|
|
284
|
+
* Some text
|
|
285
|
+
* :::
|
|
286
|
+
*
|
|
287
|
+
* Becomes:
|
|
288
|
+
* <!-- md-container:section#header -->
|
|
289
|
+
* # Heading inside container
|
|
290
|
+
* Some text
|
|
291
|
+
* <!-- /md-container -->
|
|
292
|
+
*/
|
|
293
|
+
private preprocessContainerBlocks;
|
|
294
|
+
/**
|
|
295
|
+
* Post-process marked tokens to collapse container block markers
|
|
296
|
+
* into structured containerBlock tokens with proper nesting.
|
|
297
|
+
*
|
|
298
|
+
* This handles nesting depth up to maxRecursionDepth.
|
|
299
|
+
*/
|
|
300
|
+
private postprocessTokens;
|
|
187
301
|
parse(markdown: string, options?: ParseOptions): MarkdownContent;
|
|
188
302
|
parseToNodes(markdown: string, options?: ParseOptions): ContentNode[];
|
|
189
303
|
}
|
|
@@ -205,9 +319,75 @@ export declare class MarkdownPipeline {
|
|
|
205
319
|
getCustomCSS(): string;
|
|
206
320
|
}
|
|
207
321
|
|
|
322
|
+
/**
|
|
323
|
+
* ContentNode factory — a builder API for creating ContentNode instances
|
|
324
|
+
* consistently across the codebase. Eliminates scattered object literals
|
|
325
|
+
* and provides type-safe construction with sensible defaults.
|
|
326
|
+
*
|
|
327
|
+
* Usage:
|
|
328
|
+
* NodeFactory.heading('Hello', { level: '1' })
|
|
329
|
+
* NodeFactory.paragraph('Some text')
|
|
330
|
+
* NodeFactory.container({ tag: 'section', id: 'main' }, [children...])
|
|
331
|
+
*/
|
|
332
|
+
export declare class NodeFactory {
|
|
333
|
+
static heading(content: string, attributes?: Record<string, unknown>): ContentNode;
|
|
334
|
+
static paragraph(contentOrChildren: string | ContentNode[], children?: ContentNode[]): ContentNode;
|
|
335
|
+
static list(items: ContentNode[], ordered?: boolean, attributes?: Record<string, unknown>): ContentNode;
|
|
336
|
+
static listItem(content: string): ContentNode;
|
|
337
|
+
static image(src: string, alt?: string, className?: string): ContentNode;
|
|
338
|
+
static code(content: string, lang?: string): ContentNode;
|
|
339
|
+
static container(children?: ContentNode[], config?: {
|
|
340
|
+
tag?: string;
|
|
341
|
+
id?: string;
|
|
342
|
+
className?: string;
|
|
343
|
+
rawHTML?: string;
|
|
344
|
+
scope?: string;
|
|
345
|
+
}): ContentNode;
|
|
346
|
+
static text(content: string): ContentNode;
|
|
347
|
+
static strong(content: string): ContentNode;
|
|
348
|
+
static emphasis(content: string): ContentNode;
|
|
349
|
+
static link(href: string, content: string): ContentNode;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Strategy interface for rendering a specific ContentNode type to HTML.
|
|
354
|
+
* This is the renderer-side equivalent of TokenHandler — each node type
|
|
355
|
+
* gets its own strategy, eliminating the large switch statement.
|
|
356
|
+
*
|
|
357
|
+
* To add support for a new node type:
|
|
358
|
+
* 1. Create a class implementing NodeRendererStrategy
|
|
359
|
+
* 2. Register it with the RendererStrategyRegistry
|
|
360
|
+
*/
|
|
361
|
+
export declare interface NodeRendererStrategy {
|
|
362
|
+
/** The node type this strategy handles */
|
|
363
|
+
readonly type: string;
|
|
364
|
+
/** Render a node of this type to an HTML string */
|
|
365
|
+
render(node: ContentNode, renderChild: (child: ContentNode) => string, ctx: RenderContext): string;
|
|
366
|
+
}
|
|
367
|
+
|
|
208
368
|
/** Maps ContentNodeType to ScopeValue */
|
|
209
369
|
export declare const nodeTypeToScope: Record<ContentNodeType, ScopeValue>;
|
|
210
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Visitor interface for traversing/walking a ContentNode AST.
|
|
373
|
+
*
|
|
374
|
+
* Implement this interface to inspect, collect, or transform nodes.
|
|
375
|
+
* Each method returns a ContentNode or null — returning null removes the node.
|
|
376
|
+
*
|
|
377
|
+
* Use cases:
|
|
378
|
+
* - Collect all images for preloading
|
|
379
|
+
* - Transform link URLs
|
|
380
|
+
* - Validate AST structure
|
|
381
|
+
* - Extract headings for ToC
|
|
382
|
+
* - Inject attributes
|
|
383
|
+
*/
|
|
384
|
+
export declare interface NodeVisitor {
|
|
385
|
+
/** Called when entering a node, before visiting its children. */
|
|
386
|
+
enter?(node: ContentNode, parent: ContentNode | null, depth: number): ContentNode | null;
|
|
387
|
+
/** Called after visiting all children of the node. */
|
|
388
|
+
exit?(node: ContentNode, parent: ContentNode | null, depth: number): ContentNode | null;
|
|
389
|
+
}
|
|
390
|
+
|
|
211
391
|
/**
|
|
212
392
|
* Handles 'paragraph' tokens, including inline images and raw HTML.
|
|
213
393
|
*/
|
|
@@ -238,6 +418,11 @@ export declare interface ParseContext {
|
|
|
238
418
|
maxRecursionDepth: number;
|
|
239
419
|
/** Report an unhandled token type so callers can be notified */
|
|
240
420
|
reportUnhandled(type: string, token: Record<string, unknown>): void;
|
|
421
|
+
/**
|
|
422
|
+
* Shared metadata store populated by token handlers (e.g. FrontmatterHandler).
|
|
423
|
+
* After parsing, this object contains all frontmatter key-value pairs.
|
|
424
|
+
*/
|
|
425
|
+
metadata: Record<string, unknown>;
|
|
241
426
|
}
|
|
242
427
|
|
|
243
428
|
export declare interface ParseOptions {
|
|
@@ -255,8 +440,15 @@ export declare interface ParserOptions {
|
|
|
255
440
|
errorRecovery?: 'throw' | 'warn' | 'silent';
|
|
256
441
|
maxRecursionDepth?: number;
|
|
257
442
|
allowedHTMLTags?: string[];
|
|
443
|
+
/**
|
|
444
|
+
* Allowed HTML attributes per tag for preserveRawHTML mode.
|
|
445
|
+
* Key "*" applies to all tags. Key "tag" applies to specific tags.
|
|
446
|
+
* Supports "data-*" wildcard prefix matching.
|
|
447
|
+
*/
|
|
448
|
+
allowedAttributes?: Record<string, string[]>;
|
|
258
449
|
/**
|
|
259
450
|
* Callback invoked when a token type has no dedicated handler.
|
|
451
|
+
|
|
260
452
|
* The catch-all handler will still produce a container node for the content,
|
|
261
453
|
* but this callback allows callers to log, warn, or track unhandled types.
|
|
262
454
|
*
|
|
@@ -290,6 +482,56 @@ export declare interface PipelineConfigV2 extends PipelineConfig {
|
|
|
290
482
|
maxRecursionDepth?: number;
|
|
291
483
|
/** Additional allowed HTML tags for preserveRawHTML mode */
|
|
292
484
|
allowedHTMLTags?: string[];
|
|
485
|
+
/**
|
|
486
|
+
* Allowed HTML attributes per tag for preserveRawHTML mode.
|
|
487
|
+
* Key "*" applies to all tags. Key "tag" applies to specific tags.
|
|
488
|
+
* Supports "data-*" wildcard prefix matching.
|
|
489
|
+
* Example: { "*": ["id", "class"], "script": ["type", "src"] }
|
|
490
|
+
*/
|
|
491
|
+
allowedAttributes?: Record<string, string[]>;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Context passed to every render strategy, providing access to
|
|
496
|
+
* shared rendering services and configuration.
|
|
497
|
+
*/
|
|
498
|
+
export declare interface RenderContext {
|
|
499
|
+
classPrefix: string;
|
|
500
|
+
addHeadingIds: boolean;
|
|
501
|
+
emitScopeAnchors: boolean;
|
|
502
|
+
customCSS: string;
|
|
503
|
+
getClass(baseClass: string, nodeClass?: string): string;
|
|
504
|
+
getScopeAttr(node: ContentNode): string;
|
|
505
|
+
generateHeadingId(content?: string): string;
|
|
506
|
+
getContainerClass(tag: string): string;
|
|
507
|
+
hasClassConfig(): boolean;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Registry of renderer strategies. Maps ContentNode types to their
|
|
512
|
+
* rendering strategy. This is the renderer-side equivalent of
|
|
513
|
+
* TokenHandlerRegistry.
|
|
514
|
+
*
|
|
515
|
+
* The registry uses a two-tier lookup:
|
|
516
|
+
* 1. Check for a dedicated strategy by node type
|
|
517
|
+
* 2. Fall back to the catch-all strategy (registered as '*')
|
|
518
|
+
*/
|
|
519
|
+
export declare class RendererStrategyRegistry {
|
|
520
|
+
private strategies;
|
|
521
|
+
private fallback;
|
|
522
|
+
constructor();
|
|
523
|
+
/** Register a strategy for a node type. Overrides any existing strategy. */
|
|
524
|
+
register(strategy: NodeRendererStrategy): void;
|
|
525
|
+
/** Unregister a strategy by node type. */
|
|
526
|
+
unregister(type: string): void;
|
|
527
|
+
/** Get a strategy for the given node type, falling back to catch-all. */
|
|
528
|
+
get(type: string): NodeRendererStrategy;
|
|
529
|
+
/** Check if a dedicated strategy exists for the given node type. */
|
|
530
|
+
has(type: string): boolean;
|
|
531
|
+
/** Get all registered dedicated strategy types. */
|
|
532
|
+
get types(): string[];
|
|
533
|
+
/** Replace the fallback strategy. */
|
|
534
|
+
setFallback(strategy: NodeRendererStrategy): void;
|
|
293
535
|
}
|
|
294
536
|
|
|
295
537
|
/** Scope hierarchy values for data-md-scope */
|
|
@@ -354,4 +596,10 @@ export declare class TokenHandlerRegistry {
|
|
|
354
596
|
getCatchAll(): TokenHandler;
|
|
355
597
|
}
|
|
356
598
|
|
|
599
|
+
/**
|
|
600
|
+
* Walk a ContentNode tree, applying a visitor at each node.
|
|
601
|
+
* Returns a new tree (immutable) — does not mutate the original.
|
|
602
|
+
*/
|
|
603
|
+
export declare function walkTree(root: ContentNode, visitor: NodeVisitor): ContentNode;
|
|
604
|
+
|
|
357
605
|
export { }
|