@leadertechie/md2html 0.1.0-alpha.17 → 0.1.0-alpha.19
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/README.md +152 -2
- package/dist/index.d.ts +283 -29
- package/dist/index.js +484 -436
- package/dist/index.js.map +1 -1
- package/dist/index2.js +4 -325
- package/dist/index2.js.map +1 -1
- package/dist/lit-renderer-Bp1Q6wYL.js +790 -0
- package/dist/lit-renderer-Bp1Q6wYL.js.map +1 -0
- package/dist/lit-renderer.d.ts +46 -2
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,41 +1,6 @@
|
|
|
1
|
+
import { d as defaultAllowedHTMLTags, H as HTMLRenderer } from "./lit-renderer-Bp1Q6wYL.js";
|
|
2
|
+
import { L, a, b, c, e, f, g, h, i, j, k, l, m, n, R, o } from "./lit-renderer-Bp1Q6wYL.js";
|
|
1
3
|
import { marked } from "marked";
|
|
2
|
-
const defaultAllowedHTMLTags = [
|
|
3
|
-
"img",
|
|
4
|
-
"style",
|
|
5
|
-
"div",
|
|
6
|
-
"span",
|
|
7
|
-
"section",
|
|
8
|
-
"article",
|
|
9
|
-
"aside",
|
|
10
|
-
"header",
|
|
11
|
-
"footer",
|
|
12
|
-
"nav",
|
|
13
|
-
"main",
|
|
14
|
-
"figure",
|
|
15
|
-
"figcaption",
|
|
16
|
-
"details",
|
|
17
|
-
"summary",
|
|
18
|
-
"mark",
|
|
19
|
-
"time",
|
|
20
|
-
"video",
|
|
21
|
-
"audio",
|
|
22
|
-
"source",
|
|
23
|
-
"iframe",
|
|
24
|
-
"embed"
|
|
25
|
-
];
|
|
26
|
-
const nodeTypeToScope = {
|
|
27
|
-
"text": "root",
|
|
28
|
-
"heading": "heading",
|
|
29
|
-
"paragraph": "paragraph",
|
|
30
|
-
"list": "list",
|
|
31
|
-
"list-item": "list-item",
|
|
32
|
-
"image": "image",
|
|
33
|
-
"code": "code",
|
|
34
|
-
"container": "container",
|
|
35
|
-
"strong": "strong",
|
|
36
|
-
"emphasis": "emphasis",
|
|
37
|
-
"link": "link"
|
|
38
|
-
};
|
|
39
4
|
class HeadingHandler {
|
|
40
5
|
constructor() {
|
|
41
6
|
this.type = "heading";
|
|
@@ -55,8 +20,9 @@ class ParagraphHandler {
|
|
|
55
20
|
handle(token, ctx) {
|
|
56
21
|
const tokens = token.tokens || [];
|
|
57
22
|
const hasInlineImage = tokens.some((t) => t.type === "image");
|
|
23
|
+
const hasInlineLink = tokens.some((t) => t.type === "link");
|
|
58
24
|
const hasInlineHTML = tokens.some((t) => t.type === "html");
|
|
59
|
-
if (hasInlineImage || ctx.preserveRawHTML && hasInlineHTML) {
|
|
25
|
+
if (hasInlineImage || hasInlineLink || ctx.preserveRawHTML && hasInlineHTML) {
|
|
60
26
|
const children = tokens.map((t) => {
|
|
61
27
|
if (t.type === "image") {
|
|
62
28
|
return {
|
|
@@ -65,6 +31,16 @@ class ParagraphHandler {
|
|
|
65
31
|
alt: t.text || ""
|
|
66
32
|
};
|
|
67
33
|
}
|
|
34
|
+
if (t.type === "link") {
|
|
35
|
+
return {
|
|
36
|
+
type: "link",
|
|
37
|
+
content: ctx.processSlots(ctx.processInlineFormatting(t.text || "")),
|
|
38
|
+
attributes: {
|
|
39
|
+
href: t.href || "",
|
|
40
|
+
...t.title ? { title: t.title } : {}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
68
44
|
if (t.type === "html" && ctx.preserveRawHTML) {
|
|
69
45
|
const processed = ctx.processRawHTML(t.raw);
|
|
70
46
|
if (processed.trim()) {
|
|
@@ -161,6 +137,24 @@ class HtmlHandler {
|
|
|
161
137
|
return { type: "container", content: token.raw };
|
|
162
138
|
}
|
|
163
139
|
}
|
|
140
|
+
class LinkHandler {
|
|
141
|
+
constructor() {
|
|
142
|
+
this.type = "link";
|
|
143
|
+
}
|
|
144
|
+
handle(token, ctx) {
|
|
145
|
+
const text = token.text || "";
|
|
146
|
+
const href = token.href || "";
|
|
147
|
+
const title = token.title || "";
|
|
148
|
+
return {
|
|
149
|
+
type: "link",
|
|
150
|
+
content: ctx.processSlots(ctx.processInlineFormatting(text)),
|
|
151
|
+
attributes: {
|
|
152
|
+
href,
|
|
153
|
+
...title ? { title } : {}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
164
158
|
class CatchAllHandler {
|
|
165
159
|
constructor() {
|
|
166
160
|
this.type = "*";
|
|
@@ -239,7 +233,7 @@ class ContainerBlockHandler {
|
|
|
239
233
|
const classMatches = [...specifier.matchAll(/\.([\w-]+)/g)];
|
|
240
234
|
const tag = tagMatch?.[1] || "div";
|
|
241
235
|
const id = idMatch?.[1] || "";
|
|
242
|
-
const classes = classMatches.map((
|
|
236
|
+
const classes = classMatches.map((m2) => m2[1]);
|
|
243
237
|
const children = ctx.parseTokens(childTokens, 0);
|
|
244
238
|
return {
|
|
245
239
|
type: "container",
|
|
@@ -265,6 +259,7 @@ class TokenHandlerRegistry {
|
|
|
265
259
|
this.register(new HtmlHandler());
|
|
266
260
|
this.register(new FrontmatterHandler());
|
|
267
261
|
this.register(new ContainerBlockHandler());
|
|
262
|
+
this.register(new LinkHandler());
|
|
268
263
|
this.catchAll = new CatchAllHandler();
|
|
269
264
|
}
|
|
270
265
|
/** Register a handler. Overrides any existing handler for the same token type. */
|
|
@@ -299,6 +294,392 @@ class TokenHandlerRegistry {
|
|
|
299
294
|
return this.catchAll;
|
|
300
295
|
}
|
|
301
296
|
}
|
|
297
|
+
var h2 = /* @__PURE__ */ ((t) => (t[t.DEBUG = 1] = "DEBUG", t[t.INFO = 9] = "INFO", t[t.WARN = 13] = "WARN", t[t.ERROR = 17] = "ERROR", t))(h2 || {});
|
|
298
|
+
const S = {
|
|
299
|
+
1: "DEBUG",
|
|
300
|
+
9: "INFO",
|
|
301
|
+
13: "WARN",
|
|
302
|
+
17: "ERROR"
|
|
303
|
+
}, E = [
|
|
304
|
+
"/telemetry/src/logger.ts",
|
|
305
|
+
"/telemetry/src/caller.ts",
|
|
306
|
+
"/telemetry/src/index.ts"
|
|
307
|
+
];
|
|
308
|
+
function N() {
|
|
309
|
+
const e2 = new Error().stack;
|
|
310
|
+
if (!e2) return;
|
|
311
|
+
const s = e2.split(`
|
|
312
|
+
`);
|
|
313
|
+
for (let r = 1; r < s.length; r++) {
|
|
314
|
+
const o2 = s[r].trim(), n2 = $(o2);
|
|
315
|
+
if (!n2) continue;
|
|
316
|
+
const { file: l2 } = n2;
|
|
317
|
+
if (!(l2 && E.some((m2) => l2.includes(m2))) && !(l2 && l2.includes("/node_modules/")) && l2)
|
|
318
|
+
return n2;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function $(t) {
|
|
322
|
+
const e2 = t.match(
|
|
323
|
+
/at\s+(?:(?:async\s+)?(?:(.+?)\s+\()?)?(?:(.+?):(\d+):(\d+)\)?)$/
|
|
324
|
+
);
|
|
325
|
+
if (!e2) return null;
|
|
326
|
+
const s = e2[1] || "<anonymous>", r = e2[2], o2 = parseInt(e2[3], 10), n2 = parseInt(e2[4], 10);
|
|
327
|
+
return r ? { file: r, line: o2, column: n2, functionName: s } : null;
|
|
328
|
+
}
|
|
329
|
+
class g2 {
|
|
330
|
+
constructor(e2 = [], s, r = {}) {
|
|
331
|
+
this.processors = [...e2], this.resource = s ?? { serviceName: "unknown" }, this.baseAttributes = { ...r };
|
|
332
|
+
}
|
|
333
|
+
// ── Public API ───────────────────────────────────────────────────────────
|
|
334
|
+
debug(e2, s) {
|
|
335
|
+
this.emit(h2.DEBUG, e2, void 0, s);
|
|
336
|
+
}
|
|
337
|
+
info(e2, s) {
|
|
338
|
+
this.emit(h2.INFO, e2, void 0, s);
|
|
339
|
+
}
|
|
340
|
+
warn(e2, s) {
|
|
341
|
+
this.emit(h2.WARN, e2, void 0, s);
|
|
342
|
+
}
|
|
343
|
+
error(e2, s, r) {
|
|
344
|
+
this.emit(h2.ERROR, e2, s, r);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Create a child logger with merged base attributes.
|
|
348
|
+
* Returns a NEW Logger — original is immutable.
|
|
349
|
+
*/
|
|
350
|
+
withContext(e2) {
|
|
351
|
+
return new g2(this.processors, this.resource, {
|
|
352
|
+
...this.baseAttributes,
|
|
353
|
+
...e2
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Append a processor to the pipeline.
|
|
358
|
+
* Returns a NEW Logger — original is immutable.
|
|
359
|
+
*/
|
|
360
|
+
withProcessor(e2) {
|
|
361
|
+
return new g2(
|
|
362
|
+
[...this.processors, e2],
|
|
363
|
+
this.resource,
|
|
364
|
+
this.baseAttributes
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Force-flush all pending records in all processors.
|
|
369
|
+
* Await before the end of a CF Worker request (inside ctx.waitUntil).
|
|
370
|
+
*/
|
|
371
|
+
async flush() {
|
|
372
|
+
await Promise.all(this.processors.map((e2) => e2.forceFlush()));
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Shutdown: flush + release resources. No logging after shutdown.
|
|
376
|
+
*/
|
|
377
|
+
async shutdown() {
|
|
378
|
+
await this.flush(), await Promise.all(this.processors.map((e2) => e2.shutdown()));
|
|
379
|
+
}
|
|
380
|
+
// ── Internal ────────────────────────────────────────────────────────────
|
|
381
|
+
emit(e2, s, r, o2) {
|
|
382
|
+
if (this.processors.length === 0) return;
|
|
383
|
+
const n2 = (/* @__PURE__ */ new Date()).toISOString(), l2 = {
|
|
384
|
+
severityNumber: e2,
|
|
385
|
+
severityText: S[e2],
|
|
386
|
+
body: s,
|
|
387
|
+
timestamp: n2,
|
|
388
|
+
observedTimestamp: n2,
|
|
389
|
+
attributes: { ...this.baseAttributes, ...o2 },
|
|
390
|
+
caller: N(),
|
|
391
|
+
...r ? { error: r } : {},
|
|
392
|
+
resource: { ...this.resource }
|
|
393
|
+
};
|
|
394
|
+
for (const m2 of this.processors)
|
|
395
|
+
try {
|
|
396
|
+
m2.onEmit(l2);
|
|
397
|
+
} catch (f2) {
|
|
398
|
+
console.error(
|
|
399
|
+
"[telemetry] Processor threw in onEmit:",
|
|
400
|
+
f2
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
class T {
|
|
406
|
+
constructor(e2) {
|
|
407
|
+
this.shutdownFlag = false, this.pendingExport = Promise.resolve(), this.adapter = e2;
|
|
408
|
+
}
|
|
409
|
+
onEmit(e2) {
|
|
410
|
+
this.shutdownFlag || (this.pendingExport = this.pendingExport.then(() => this.adapter.export([e2])).catch((s) => {
|
|
411
|
+
console.error(
|
|
412
|
+
`[telemetry] SimpleLogProcessor: adapter "${this.adapter.name}" export failed:`,
|
|
413
|
+
s
|
|
414
|
+
);
|
|
415
|
+
}));
|
|
416
|
+
}
|
|
417
|
+
async forceFlush() {
|
|
418
|
+
await this.pendingExport;
|
|
419
|
+
}
|
|
420
|
+
async shutdown() {
|
|
421
|
+
this.shutdownFlag = true, await this.forceFlush(), await this.adapter.shutdown?.();
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
class M {
|
|
425
|
+
constructor(e2) {
|
|
426
|
+
this.processors = [], this.resource = {
|
|
427
|
+
serviceName: e2?.serviceName ?? "unknown",
|
|
428
|
+
environment: e2?.environment,
|
|
429
|
+
version: e2?.version,
|
|
430
|
+
processName: e2?.processName
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Register an adapter via a SimpleLogProcessor (immediate export).
|
|
435
|
+
* For batching, use addProcessor(new BatchLogProcessor(adapter, opts)).
|
|
436
|
+
*/
|
|
437
|
+
addAdapter(e2) {
|
|
438
|
+
return this.addProcessor(new T(e2));
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Register a custom processor (SimpleLogProcessor, BatchLogProcessor,
|
|
442
|
+
* or your own implementation).
|
|
443
|
+
*/
|
|
444
|
+
addProcessor(e2) {
|
|
445
|
+
return this.processors.push(e2), this;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Get a named Logger instance.
|
|
449
|
+
* The logger inherits the provider's resource and processors.
|
|
450
|
+
* Optionally provide initial context attributes.
|
|
451
|
+
*/
|
|
452
|
+
getLogger(e2, s) {
|
|
453
|
+
const r = {
|
|
454
|
+
...this.resource,
|
|
455
|
+
...e2 ? { processName: e2 } : {}
|
|
456
|
+
};
|
|
457
|
+
return new g2(this.processors, r, s);
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Force-flush all registered processors.
|
|
461
|
+
*/
|
|
462
|
+
async flush() {
|
|
463
|
+
await Promise.all(this.processors.map((e2) => e2.forceFlush()));
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Shutdown: flush + release all processor resources.
|
|
467
|
+
*/
|
|
468
|
+
async shutdown() {
|
|
469
|
+
await this.flush(), await Promise.all(this.processors.map((e2) => e2.shutdown()));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
function U(t) {
|
|
473
|
+
const e2 = t?.level ?? h2.DEBUG, s = t?.json ?? false;
|
|
474
|
+
return {
|
|
475
|
+
name: "console",
|
|
476
|
+
async export(r) {
|
|
477
|
+
for (const o2 of r)
|
|
478
|
+
o2.severityNumber < e2 || (s ? I(o2) : R2(o2));
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
function R2(t) {
|
|
483
|
+
const e2 = F(t.severityNumber), s = t.timestamp, r = t.severityText, o2 = t.caller ? ` (${t.caller.file}:${t.caller.line})` : "", n2 = Object.keys(t.attributes).length > 0;
|
|
484
|
+
!!t.error ? e2(
|
|
485
|
+
`[${s}] [${r}]${o2} ${t.body}`,
|
|
486
|
+
t.attributes,
|
|
487
|
+
t.error
|
|
488
|
+
) : n2 ? e2(`[${s}] [${r}]${o2} ${t.body}`, t.attributes) : e2(`[${s}] [${r}]${o2} ${t.body}`);
|
|
489
|
+
}
|
|
490
|
+
function I(t) {
|
|
491
|
+
const e2 = {
|
|
492
|
+
timestamp: t.timestamp,
|
|
493
|
+
level: t.severityText,
|
|
494
|
+
message: t.body,
|
|
495
|
+
service: t.resource.serviceName,
|
|
496
|
+
environment: t.resource.environment,
|
|
497
|
+
attributes: t.attributes,
|
|
498
|
+
caller: t.caller
|
|
499
|
+
};
|
|
500
|
+
t.error && (e2.error = {
|
|
501
|
+
name: t.error.name,
|
|
502
|
+
message: t.error.message,
|
|
503
|
+
stack: t.error.stack
|
|
504
|
+
}), console.log(JSON.stringify(e2));
|
|
505
|
+
}
|
|
506
|
+
function F(t) {
|
|
507
|
+
switch (t) {
|
|
508
|
+
case h2.ERROR:
|
|
509
|
+
return console.error.bind(console);
|
|
510
|
+
case h2.WARN:
|
|
511
|
+
return console.warn.bind(console);
|
|
512
|
+
case h2.INFO:
|
|
513
|
+
return console.log.bind(console);
|
|
514
|
+
case h2.DEBUG:
|
|
515
|
+
default:
|
|
516
|
+
return console.debug.bind(console);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const defaultLoggers = /* @__PURE__ */ new Map();
|
|
520
|
+
function getDefaultLogger(serviceName) {
|
|
521
|
+
let log = defaultLoggers.get(serviceName);
|
|
522
|
+
if (!log) {
|
|
523
|
+
const provider = new M({ serviceName });
|
|
524
|
+
provider.addAdapter(U({ level: h2.WARN }));
|
|
525
|
+
log = provider.getLogger();
|
|
526
|
+
defaultLoggers.set(serviceName, log);
|
|
527
|
+
}
|
|
528
|
+
return log;
|
|
529
|
+
}
|
|
530
|
+
function createParseContext(services) {
|
|
531
|
+
const metadata = {};
|
|
532
|
+
return {
|
|
533
|
+
get preserveRawHTML() {
|
|
534
|
+
return services.preserveRawHTML;
|
|
535
|
+
},
|
|
536
|
+
get errorRecovery() {
|
|
537
|
+
return services.errorRecovery;
|
|
538
|
+
},
|
|
539
|
+
get maxRecursionDepth() {
|
|
540
|
+
return services.maxRecursionDepth;
|
|
541
|
+
},
|
|
542
|
+
processImagePath: (src) => services.processImagePath(src),
|
|
543
|
+
processInlineFormatting: (text) => services.processInlineFormatting(text),
|
|
544
|
+
processSlots: (text) => services.processSlots(text),
|
|
545
|
+
processRawHTML: (html) => services.processRawHTML(html),
|
|
546
|
+
parseTokens: (tokens, depth) => services.parseTokens(tokens, depth),
|
|
547
|
+
reportUnhandled: (type, token) => {
|
|
548
|
+
services.onUnhandledToken?.(type, token);
|
|
549
|
+
},
|
|
550
|
+
metadata
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
class ContainerBlockPreprocessor {
|
|
554
|
+
constructor() {
|
|
555
|
+
this.name = "container-blocks";
|
|
556
|
+
}
|
|
557
|
+
process(markdown) {
|
|
558
|
+
return markdown.replace(/^:::(?:(\w+(?:[.#][\w-]+)*)\s*)?$/gm, (_match, specifier) => {
|
|
559
|
+
if (!specifier) {
|
|
560
|
+
return "<!-- /md-container -->";
|
|
561
|
+
}
|
|
562
|
+
const normalized = specifier.match(/^\w/) ? specifier : `div${specifier}`;
|
|
563
|
+
return `<!-- md-container:${normalized} -->`;
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
class CompositePreprocessor {
|
|
568
|
+
constructor(processors) {
|
|
569
|
+
this.name = "composite";
|
|
570
|
+
this.processors = [];
|
|
571
|
+
if (processors) {
|
|
572
|
+
this.processors = [...processors];
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
/** Add a preprocessor to the chain. Returns `this` for fluent API. */
|
|
576
|
+
add(processor) {
|
|
577
|
+
this.processors.push(processor);
|
|
578
|
+
return this;
|
|
579
|
+
}
|
|
580
|
+
/** Remove a preprocessor by name. */
|
|
581
|
+
remove(name) {
|
|
582
|
+
this.processors = this.processors.filter((p) => p.name !== name);
|
|
583
|
+
}
|
|
584
|
+
/** Get the list of registered preprocessors. */
|
|
585
|
+
getProcessors() {
|
|
586
|
+
return [...this.processors];
|
|
587
|
+
}
|
|
588
|
+
process(markdown) {
|
|
589
|
+
let result = markdown;
|
|
590
|
+
for (const processor of this.processors) {
|
|
591
|
+
result = processor.process(result);
|
|
592
|
+
}
|
|
593
|
+
return result;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
function createDefaultPreprocessor() {
|
|
597
|
+
return new CompositePreprocessor([
|
|
598
|
+
new ContainerBlockPreprocessor()
|
|
599
|
+
]);
|
|
600
|
+
}
|
|
601
|
+
class ContainerBlockPostprocessor {
|
|
602
|
+
constructor() {
|
|
603
|
+
this.name = "container-blocks";
|
|
604
|
+
}
|
|
605
|
+
process(tokens) {
|
|
606
|
+
const result = [];
|
|
607
|
+
const stack = [];
|
|
608
|
+
for (const token of tokens) {
|
|
609
|
+
const t = token;
|
|
610
|
+
if (t.type === "html") {
|
|
611
|
+
const raw = t.raw.trim();
|
|
612
|
+
const openMatch = raw.match(/^<!--\s*md-container:\s*(\S+)\s*-->$/);
|
|
613
|
+
const closeMatch = raw.match(/^<!--\s*\/md-container\s*-->$/);
|
|
614
|
+
if (openMatch) {
|
|
615
|
+
stack.push({
|
|
616
|
+
specifier: openMatch[1],
|
|
617
|
+
tokens: []
|
|
618
|
+
});
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
if (closeMatch) {
|
|
622
|
+
if (stack.length === 0) {
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
const container = stack.pop();
|
|
626
|
+
const processedInner = this.process(container.tokens);
|
|
627
|
+
const containerToken = {
|
|
628
|
+
type: "containerBlock",
|
|
629
|
+
specifier: container.specifier,
|
|
630
|
+
tokens: processedInner
|
|
631
|
+
};
|
|
632
|
+
if (stack.length > 0) {
|
|
633
|
+
stack[stack.length - 1].tokens.push(containerToken);
|
|
634
|
+
} else {
|
|
635
|
+
result.push(containerToken);
|
|
636
|
+
}
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (stack.length > 0) {
|
|
641
|
+
stack[stack.length - 1].tokens.push(token);
|
|
642
|
+
} else {
|
|
643
|
+
result.push(token);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return result;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
class CompositeTokenPostprocessor {
|
|
650
|
+
constructor(processors) {
|
|
651
|
+
this.name = "composite";
|
|
652
|
+
this.processors = [];
|
|
653
|
+
if (processors) {
|
|
654
|
+
this.processors = [...processors];
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
/** Add a postprocessor to the chain. Returns `this` for fluent API. */
|
|
658
|
+
add(processor) {
|
|
659
|
+
this.processors.push(processor);
|
|
660
|
+
return this;
|
|
661
|
+
}
|
|
662
|
+
/** Remove a postprocessor by name. */
|
|
663
|
+
remove(name) {
|
|
664
|
+
this.processors = this.processors.filter((p) => p.name !== name);
|
|
665
|
+
}
|
|
666
|
+
/** Get the list of registered postprocessors. */
|
|
667
|
+
getProcessors() {
|
|
668
|
+
return [...this.processors];
|
|
669
|
+
}
|
|
670
|
+
process(tokens) {
|
|
671
|
+
let result = tokens;
|
|
672
|
+
for (const processor of this.processors) {
|
|
673
|
+
result = processor.process(result);
|
|
674
|
+
}
|
|
675
|
+
return result;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
function createDefaultPostprocessor() {
|
|
679
|
+
return new CompositeTokenPostprocessor([
|
|
680
|
+
new ContainerBlockPostprocessor()
|
|
681
|
+
]);
|
|
682
|
+
}
|
|
302
683
|
const DEFAULT_SLOT_PATTERN = /\[\[(.*?)\]\]/g;
|
|
303
684
|
class MarkdownParser {
|
|
304
685
|
constructor(options) {
|
|
@@ -307,6 +688,7 @@ class MarkdownParser {
|
|
|
307
688
|
this.preserveRawHTML = options?.preserveRawHTML ?? false;
|
|
308
689
|
this.slotPattern = options?.slotPattern ?? DEFAULT_SLOT_PATTERN;
|
|
309
690
|
this.onSlot = options?.onSlot;
|
|
691
|
+
this.log = options?.logger ?? getDefaultLogger("md2html");
|
|
310
692
|
this.errorRecovery = options?.errorRecovery ?? "throw";
|
|
311
693
|
this.maxRecursionDepth = options?.maxRecursionDepth ?? 100;
|
|
312
694
|
this.allowedHTMLTags = /* @__PURE__ */ new Set([
|
|
@@ -316,11 +698,21 @@ class MarkdownParser {
|
|
|
316
698
|
this.allowedAttributes = options?.allowedAttributes ?? {};
|
|
317
699
|
this.handlerRegistry = new TokenHandlerRegistry();
|
|
318
700
|
this.onUnhandledToken = options?.onUnhandledToken;
|
|
701
|
+
this.preprocessor = createDefaultPreprocessor();
|
|
702
|
+
this.postprocessor = createDefaultPostprocessor();
|
|
319
703
|
}
|
|
320
704
|
/** Access the handler registry for customization. */
|
|
321
705
|
get handlers() {
|
|
322
706
|
return this.handlerRegistry;
|
|
323
707
|
}
|
|
708
|
+
/** Access the preprocessor chain for customization. */
|
|
709
|
+
get preprocessors() {
|
|
710
|
+
return this.preprocessor;
|
|
711
|
+
}
|
|
712
|
+
/** Access the token postprocessor chain for customization. */
|
|
713
|
+
get postprocessors() {
|
|
714
|
+
return this.postprocessor;
|
|
715
|
+
}
|
|
324
716
|
processImagePath(src) {
|
|
325
717
|
if (src.startsWith("http") || src.startsWith("/")) {
|
|
326
718
|
return src;
|
|
@@ -415,31 +807,20 @@ class MarkdownParser {
|
|
|
415
807
|
return html;
|
|
416
808
|
}
|
|
417
809
|
/**
|
|
418
|
-
* Build
|
|
419
|
-
*
|
|
810
|
+
* Build a ParserServices object that bridges the parser's private methods
|
|
811
|
+
* to the ParseContext factory. This keeps context creation decoupled.
|
|
420
812
|
*/
|
|
421
|
-
|
|
422
|
-
const self = this;
|
|
423
|
-
const metadata = {};
|
|
813
|
+
buildServices() {
|
|
424
814
|
return {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
processImagePath: (src) => self.processImagePath(src),
|
|
435
|
-
processInlineFormatting: (text) => self.processInlineFormatting(text),
|
|
436
|
-
processSlots: (text) => self.processSlots(text),
|
|
437
|
-
processRawHTML: (html) => self.processRawHTML(html),
|
|
438
|
-
parseTokens: (tokens, depth) => self.parseTokens(tokens, depth),
|
|
439
|
-
reportUnhandled: (type, token) => {
|
|
440
|
-
self.onUnhandledToken?.(type, token);
|
|
441
|
-
},
|
|
442
|
-
metadata
|
|
815
|
+
preserveRawHTML: this.preserveRawHTML,
|
|
816
|
+
errorRecovery: this.errorRecovery,
|
|
817
|
+
maxRecursionDepth: this.maxRecursionDepth,
|
|
818
|
+
processImagePath: (src) => this.processImagePath(src),
|
|
819
|
+
processInlineFormatting: (text) => this.processInlineFormatting(text),
|
|
820
|
+
processSlots: (text) => this.processSlots(text),
|
|
821
|
+
processRawHTML: (html) => this.processRawHTML(html),
|
|
822
|
+
parseTokens: (tokens, depth) => this.parseTokens(tokens, depth),
|
|
823
|
+
onUnhandledToken: this.onUnhandledToken
|
|
443
824
|
};
|
|
444
825
|
}
|
|
445
826
|
/**
|
|
@@ -451,12 +832,12 @@ class MarkdownParser {
|
|
|
451
832
|
if (depth > this.maxRecursionDepth) {
|
|
452
833
|
const msg = `[md2html] Max recursion depth (${this.maxRecursionDepth}) exceeded, truncating`;
|
|
453
834
|
if (this.errorRecovery === "warn") {
|
|
454
|
-
|
|
835
|
+
this.log.warn(msg);
|
|
455
836
|
}
|
|
456
837
|
return [];
|
|
457
838
|
}
|
|
458
839
|
const nodes = [];
|
|
459
|
-
const ctx = sharedCtx || this.
|
|
840
|
+
const ctx = sharedCtx || createParseContext(this.buildServices());
|
|
460
841
|
for (const token of tokens) {
|
|
461
842
|
const typedToken = token;
|
|
462
843
|
const handler = this.handlerRegistry.get(typedToken.type);
|
|
@@ -467,82 +848,6 @@ class MarkdownParser {
|
|
|
467
848
|
}
|
|
468
849
|
return nodes;
|
|
469
850
|
}
|
|
470
|
-
/**
|
|
471
|
-
* Pre-process markdown: convert `:::tag#id.class` container syntax
|
|
472
|
-
* into HTML comment markers that marked will preserve as html tokens,
|
|
473
|
-
* but won't affect markdown parsing of the inner content.
|
|
474
|
-
*
|
|
475
|
-
* Example:
|
|
476
|
-
* :::section#header
|
|
477
|
-
* # Heading inside container
|
|
478
|
-
* Some text
|
|
479
|
-
* :::
|
|
480
|
-
*
|
|
481
|
-
* Becomes:
|
|
482
|
-
* <!-- md-container:section#header -->
|
|
483
|
-
* # Heading inside container
|
|
484
|
-
* Some text
|
|
485
|
-
* <!-- /md-container -->
|
|
486
|
-
*/
|
|
487
|
-
preprocessContainerBlocks(markdown) {
|
|
488
|
-
return markdown.replace(/^:::(?:(\w+(?:[.#][\w-]+)*)\s*)?$/gm, (match, specifier) => {
|
|
489
|
-
if (!specifier) {
|
|
490
|
-
return "<!-- /md-container -->";
|
|
491
|
-
}
|
|
492
|
-
const normalized = specifier.match(/^\w/) ? specifier : `div${specifier}`;
|
|
493
|
-
return `<!-- md-container:${normalized} -->`;
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
/**
|
|
497
|
-
* Post-process marked tokens to collapse container block markers
|
|
498
|
-
* into structured containerBlock tokens with proper nesting.
|
|
499
|
-
*
|
|
500
|
-
* This handles nesting depth up to maxRecursionDepth.
|
|
501
|
-
*/
|
|
502
|
-
postprocessTokens(tokens) {
|
|
503
|
-
const result = [];
|
|
504
|
-
const stack = [];
|
|
505
|
-
for (const token of tokens) {
|
|
506
|
-
const t = token;
|
|
507
|
-
if (t.type === "html") {
|
|
508
|
-
const raw = t.raw.trim();
|
|
509
|
-
const openMatch = raw.match(/^<!--\s*md-container:\s*(\S+)\s*-->$/);
|
|
510
|
-
const closeMatch = raw.match(/^<!--\s*\/md-container\s*-->$/);
|
|
511
|
-
if (openMatch) {
|
|
512
|
-
const newContainer = {
|
|
513
|
-
specifier: openMatch[1],
|
|
514
|
-
tokens: []
|
|
515
|
-
};
|
|
516
|
-
stack.push(newContainer);
|
|
517
|
-
continue;
|
|
518
|
-
}
|
|
519
|
-
if (closeMatch) {
|
|
520
|
-
if (stack.length === 0) {
|
|
521
|
-
continue;
|
|
522
|
-
}
|
|
523
|
-
const container = stack.pop();
|
|
524
|
-
const processedInner = this.postprocessTokens(container.tokens);
|
|
525
|
-
const containerToken = {
|
|
526
|
-
type: "containerBlock",
|
|
527
|
-
specifier: container.specifier,
|
|
528
|
-
tokens: processedInner
|
|
529
|
-
};
|
|
530
|
-
if (stack.length > 0) {
|
|
531
|
-
stack[stack.length - 1].tokens.push(containerToken);
|
|
532
|
-
} else {
|
|
533
|
-
result.push(containerToken);
|
|
534
|
-
}
|
|
535
|
-
continue;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
if (stack.length > 0) {
|
|
539
|
-
stack[stack.length - 1].tokens.push(token);
|
|
540
|
-
} else {
|
|
541
|
-
result.push(token);
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
return result;
|
|
545
|
-
}
|
|
546
851
|
parse(markdown, options) {
|
|
547
852
|
const parseOptions = {
|
|
548
853
|
gfm: options?.gfm ?? true,
|
|
@@ -550,10 +855,10 @@ class MarkdownParser {
|
|
|
550
855
|
pedantic: options?.pedantic ?? false
|
|
551
856
|
};
|
|
552
857
|
try {
|
|
553
|
-
const processed = this.
|
|
858
|
+
const processed = this.preprocessor.process(markdown);
|
|
554
859
|
const rawTokens = marked.lexer(processed, parseOptions);
|
|
555
|
-
const tokens = this.
|
|
556
|
-
const ctx = this.
|
|
860
|
+
const tokens = this.postprocessor.process(rawTokens);
|
|
861
|
+
const ctx = createParseContext(this.buildServices());
|
|
557
862
|
const content = this.parseTokens(tokens, 0, ctx);
|
|
558
863
|
return {
|
|
559
864
|
title: "",
|
|
@@ -564,7 +869,7 @@ class MarkdownParser {
|
|
|
564
869
|
if (this.errorRecovery === "throw") throw err;
|
|
565
870
|
const msg = `[md2html] Parse error: ${err instanceof Error ? err.message : String(err)}`;
|
|
566
871
|
if (this.errorRecovery === "warn") {
|
|
567
|
-
|
|
872
|
+
this.log.warn(msg);
|
|
568
873
|
}
|
|
569
874
|
return {
|
|
570
875
|
title: "",
|
|
@@ -576,296 +881,9 @@ class MarkdownParser {
|
|
|
576
881
|
return this.parse(markdown, options).content;
|
|
577
882
|
}
|
|
578
883
|
}
|
|
579
|
-
class HeadingRendererStrategy {
|
|
580
|
-
constructor() {
|
|
581
|
-
this.type = "heading";
|
|
582
|
-
}
|
|
583
|
-
render(node, _renderChild, ctx) {
|
|
584
|
-
const level = node.attributes?.level || "2";
|
|
585
|
-
const headingId = ctx.addHeadingIds ? ` id="${ctx.generateHeadingId(node.content)}"` : "";
|
|
586
|
-
const scopeAttr = ctx.getScopeAttr(node);
|
|
587
|
-
if (!ctx.hasClassConfig()) {
|
|
588
|
-
return `<h${level}${headingId}${scopeAttr}>${node.content || ""}</h${level}>`;
|
|
589
|
-
}
|
|
590
|
-
const prefix = ctx.classPrefix;
|
|
591
|
-
const levelClass = level === "1" ? "h1" : level === "2" ? "h2" : level === "3" ? "h3" : level === "4" ? "h4" : level === "5" ? "h5" : "h6";
|
|
592
|
-
const headingClass = prefix ? `${prefix}${levelClass}` : levelClass;
|
|
593
|
-
return `<h${level}${headingId}${scopeAttr} class="${headingClass}">${node.content || ""}</h${level}>`;
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
class ParagraphRendererStrategy {
|
|
597
|
-
constructor() {
|
|
598
|
-
this.type = "paragraph";
|
|
599
|
-
}
|
|
600
|
-
render(node, renderChild, ctx) {
|
|
601
|
-
const scopeAttr = ctx.getScopeAttr(node);
|
|
602
|
-
if (node.children) {
|
|
603
|
-
const childrenHtml = node.children.map(renderChild).join("");
|
|
604
|
-
return ctx.hasClassConfig() && ctx.classPrefix ? `<p class="${ctx.classPrefix}paragraph"${scopeAttr}>${childrenHtml}</p>` : `<p${scopeAttr}>${childrenHtml}</p>`;
|
|
605
|
-
}
|
|
606
|
-
return ctx.hasClassConfig() && ctx.classPrefix ? `<p class="${ctx.classPrefix}paragraph"${scopeAttr}>${node.content || ""}</p>` : `<p${scopeAttr}>${node.content || ""}</p>`;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
class ListRendererStrategy {
|
|
610
|
-
constructor() {
|
|
611
|
-
this.type = "list";
|
|
612
|
-
}
|
|
613
|
-
render(node, renderChild, ctx) {
|
|
614
|
-
const tag = node.ordered ? "ol" : "ul";
|
|
615
|
-
const items = node.children?.map(renderChild).join("") || "";
|
|
616
|
-
const scopeAttr = ctx.getScopeAttr(node);
|
|
617
|
-
return ctx.hasClassConfig() && ctx.classPrefix ? `<${tag} class="${ctx.classPrefix}list"${scopeAttr}>${items}</${tag}>` : `<${tag}${scopeAttr}>${items}</${tag}>`;
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
class ListItemRendererStrategy {
|
|
621
|
-
constructor() {
|
|
622
|
-
this.type = "list-item";
|
|
623
|
-
}
|
|
624
|
-
render(node, _renderChild, ctx) {
|
|
625
|
-
const scopeAttr = ctx.getScopeAttr(node);
|
|
626
|
-
return ctx.hasClassConfig() && ctx.classPrefix ? `<li class="${ctx.classPrefix}list-item"${scopeAttr}>${node.content || ""}</li>` : `<li${scopeAttr}>${node.content || ""}</li>`;
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
class ImageRendererStrategy {
|
|
630
|
-
constructor() {
|
|
631
|
-
this.type = "image";
|
|
632
|
-
}
|
|
633
|
-
render(node, _renderChild, ctx) {
|
|
634
|
-
const src = node.src || node.attributes?.src || "";
|
|
635
|
-
const alt = node.alt || node.attributes?.alt || "";
|
|
636
|
-
const scopeAttr = ctx.getScopeAttr(node);
|
|
637
|
-
let classStr = "";
|
|
638
|
-
if (ctx.hasClassConfig()) {
|
|
639
|
-
const prefix = ctx.classPrefix;
|
|
640
|
-
classStr = prefix ? `${prefix}image` : "image";
|
|
641
|
-
if (node.className) classStr += ` ${node.className}`;
|
|
642
|
-
return `<img src="${src}" alt="${alt}" class="${classStr}"${scopeAttr}>`;
|
|
643
|
-
}
|
|
644
|
-
if (node.className) {
|
|
645
|
-
return `<img src="${src}" alt="${alt}" class="${node.className}"${scopeAttr}>`;
|
|
646
|
-
}
|
|
647
|
-
return `<img src="${src}" alt="${alt}"${scopeAttr}>`;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
class CodeRendererStrategy {
|
|
651
|
-
constructor() {
|
|
652
|
-
this.type = "code";
|
|
653
|
-
}
|
|
654
|
-
render(node, _renderChild, ctx) {
|
|
655
|
-
const scopeAttr = ctx.getScopeAttr(node);
|
|
656
|
-
const lang = node.attributes?.lang || "";
|
|
657
|
-
if (ctx.hasClassConfig()) {
|
|
658
|
-
const prefix = ctx.classPrefix;
|
|
659
|
-
const codeClass = prefix ? `${prefix}code` : "code";
|
|
660
|
-
return `<pre${scopeAttr}><code class="${codeClass} language-${lang}">${node.content || ""}</code></pre>`;
|
|
661
|
-
}
|
|
662
|
-
return `<pre${scopeAttr}><code class="language-${lang}">${node.content || ""}</code></pre>`;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
class ContainerRendererStrategy {
|
|
666
|
-
constructor() {
|
|
667
|
-
this.type = "container";
|
|
668
|
-
}
|
|
669
|
-
render(node, renderChild, ctx) {
|
|
670
|
-
if (node.rawHTML) {
|
|
671
|
-
return node.rawHTML;
|
|
672
|
-
}
|
|
673
|
-
const tag = node.attributes?.tag || "div";
|
|
674
|
-
const children = node.children?.map(renderChild).join("") || "";
|
|
675
|
-
const id = node.attributes?.id;
|
|
676
|
-
const idAttr = id ? ` id="${id}"` : "";
|
|
677
|
-
const scopeAttr = ctx.getScopeAttr(node);
|
|
678
|
-
if (tag === "hr") return "<hr>";
|
|
679
|
-
if (ctx.hasClassConfig()) {
|
|
680
|
-
const containerClass = ctx.getContainerClass(tag);
|
|
681
|
-
const prefix = ctx.classPrefix;
|
|
682
|
-
if (prefix) {
|
|
683
|
-
const classes2 = [prefix + (containerClass || "container")];
|
|
684
|
-
if (node.className) classes2.push(node.className);
|
|
685
|
-
return `<${tag} class="${classes2.join(" ")}"${idAttr}${scopeAttr}>${children}</${tag}>`;
|
|
686
|
-
}
|
|
687
|
-
const classes = [containerClass || "container"];
|
|
688
|
-
if (node.className) classes.push(node.className);
|
|
689
|
-
return `<${tag} class="${classes.join(" ")}"${idAttr}${scopeAttr}>${children}</${tag}>`;
|
|
690
|
-
}
|
|
691
|
-
if (node.className) {
|
|
692
|
-
return `<${tag} class="${node.className}"${idAttr}${scopeAttr}>${children}</${tag}>`;
|
|
693
|
-
}
|
|
694
|
-
return `<${tag}${idAttr}${scopeAttr}>${children}</${tag}>`;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
class StrongRendererStrategy {
|
|
698
|
-
constructor() {
|
|
699
|
-
this.type = "strong";
|
|
700
|
-
}
|
|
701
|
-
render(node, _renderChild, ctx) {
|
|
702
|
-
return `<strong${ctx.getScopeAttr(node)}>${node.content || ""}</strong>`;
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
class EmphasisRendererStrategy {
|
|
706
|
-
constructor() {
|
|
707
|
-
this.type = "emphasis";
|
|
708
|
-
}
|
|
709
|
-
render(node, _renderChild, ctx) {
|
|
710
|
-
return `<em${ctx.getScopeAttr(node)}>${node.content || ""}</em>`;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
class LinkRendererStrategy {
|
|
714
|
-
constructor() {
|
|
715
|
-
this.type = "link";
|
|
716
|
-
}
|
|
717
|
-
render(node, _renderChild, ctx) {
|
|
718
|
-
const href = node.attributes?.href || "";
|
|
719
|
-
return `<a href="${href}"${ctx.getScopeAttr(node)}>${node.content || ""}</a>`;
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
class TextRendererStrategy {
|
|
723
|
-
constructor() {
|
|
724
|
-
this.type = "text";
|
|
725
|
-
}
|
|
726
|
-
render(node, _renderChild, _ctx) {
|
|
727
|
-
return node.content || "";
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
class RendererStrategyRegistry {
|
|
731
|
-
constructor() {
|
|
732
|
-
this.strategies = /* @__PURE__ */ new Map();
|
|
733
|
-
this.register(new HeadingRendererStrategy());
|
|
734
|
-
this.register(new ParagraphRendererStrategy());
|
|
735
|
-
this.register(new ListRendererStrategy());
|
|
736
|
-
this.register(new ListItemRendererStrategy());
|
|
737
|
-
this.register(new ImageRendererStrategy());
|
|
738
|
-
this.register(new CodeRendererStrategy());
|
|
739
|
-
this.register(new ContainerRendererStrategy());
|
|
740
|
-
this.register(new StrongRendererStrategy());
|
|
741
|
-
this.register(new EmphasisRendererStrategy());
|
|
742
|
-
this.register(new LinkRendererStrategy());
|
|
743
|
-
this.register(new TextRendererStrategy());
|
|
744
|
-
this.fallback = new TextRendererStrategy();
|
|
745
|
-
}
|
|
746
|
-
/** Register a strategy for a node type. Overrides any existing strategy. */
|
|
747
|
-
register(strategy) {
|
|
748
|
-
this.strategies.set(strategy.type, strategy);
|
|
749
|
-
}
|
|
750
|
-
/** Unregister a strategy by node type. */
|
|
751
|
-
unregister(type) {
|
|
752
|
-
this.strategies.delete(type);
|
|
753
|
-
}
|
|
754
|
-
/** Get a strategy for the given node type, falling back to catch-all. */
|
|
755
|
-
get(type) {
|
|
756
|
-
return this.strategies.get(type) ?? this.fallback;
|
|
757
|
-
}
|
|
758
|
-
/** Check if a dedicated strategy exists for the given node type. */
|
|
759
|
-
has(type) {
|
|
760
|
-
return this.strategies.has(type);
|
|
761
|
-
}
|
|
762
|
-
/** Get all registered dedicated strategy types. */
|
|
763
|
-
get types() {
|
|
764
|
-
return Array.from(this.strategies.keys());
|
|
765
|
-
}
|
|
766
|
-
/** Replace the fallback strategy. */
|
|
767
|
-
setFallback(strategy) {
|
|
768
|
-
this.fallback = strategy;
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
class HTMLRenderer {
|
|
772
|
-
constructor(config = {}) {
|
|
773
|
-
this.config = {
|
|
774
|
-
classPrefix: config.classPrefix || "",
|
|
775
|
-
customCSS: config.customCSS || "",
|
|
776
|
-
addHeadingIds: config.addHeadingIds ?? false,
|
|
777
|
-
emitScopeAnchors: config.emitScopeAnchors ?? false
|
|
778
|
-
};
|
|
779
|
-
this.strategyRegistry = new RendererStrategyRegistry();
|
|
780
|
-
}
|
|
781
|
-
/** Access the strategy registry for customization. */
|
|
782
|
-
get strategies() {
|
|
783
|
-
return this.strategyRegistry;
|
|
784
|
-
}
|
|
785
|
-
hasClassConfig() {
|
|
786
|
-
return this.config.classPrefix !== "" || this.config.addHeadingIds;
|
|
787
|
-
}
|
|
788
|
-
getClass(baseClass, nodeClass) {
|
|
789
|
-
if (!this.hasClassConfig()) {
|
|
790
|
-
return nodeClass || "";
|
|
791
|
-
}
|
|
792
|
-
const prefix = this.config.classPrefix;
|
|
793
|
-
const classes = [prefix ? `${prefix}${baseClass}` : baseClass];
|
|
794
|
-
if (nodeClass) classes.push(nodeClass);
|
|
795
|
-
return classes.join(" ");
|
|
796
|
-
}
|
|
797
|
-
generateHeadingId(content) {
|
|
798
|
-
if (!content) return "";
|
|
799
|
-
return content.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
800
|
-
}
|
|
801
|
-
/**
|
|
802
|
-
* Get the scope attribute string for a node type.
|
|
803
|
-
* Returns empty string if emitScopeAnchors is disabled.
|
|
804
|
-
*/
|
|
805
|
-
getScopeAttr(node) {
|
|
806
|
-
if (!this.config.emitScopeAnchors) return "";
|
|
807
|
-
const scopeValue = node.scope || nodeTypeToScope[node.type] || "container";
|
|
808
|
-
return ` data-md-scope="${scopeValue}"`;
|
|
809
|
-
}
|
|
810
|
-
/**
|
|
811
|
-
* Get the CSS class for a container's tag-based rendering.
|
|
812
|
-
* Returns just the tag name since renderWithClass applies the prefix.
|
|
813
|
-
*/
|
|
814
|
-
getContainerClass(tag) {
|
|
815
|
-
if (!this.hasClassConfig()) return "";
|
|
816
|
-
return tag;
|
|
817
|
-
}
|
|
818
|
-
buildRenderContext() {
|
|
819
|
-
const self = this;
|
|
820
|
-
return {
|
|
821
|
-
get classPrefix() {
|
|
822
|
-
return self.config.classPrefix;
|
|
823
|
-
},
|
|
824
|
-
get addHeadingIds() {
|
|
825
|
-
return self.config.addHeadingIds;
|
|
826
|
-
},
|
|
827
|
-
get emitScopeAnchors() {
|
|
828
|
-
return self.config.emitScopeAnchors;
|
|
829
|
-
},
|
|
830
|
-
get customCSS() {
|
|
831
|
-
return self.config.customCSS;
|
|
832
|
-
},
|
|
833
|
-
hasClassConfig: () => self.hasClassConfig(),
|
|
834
|
-
getClass: (baseClass, nodeClass) => self.getClass(baseClass, nodeClass),
|
|
835
|
-
getScopeAttr: (node) => self.getScopeAttr(node),
|
|
836
|
-
generateHeadingId: (content) => self.generateHeadingId(content),
|
|
837
|
-
getContainerClass: (tag) => self.getContainerClass(tag)
|
|
838
|
-
};
|
|
839
|
-
}
|
|
840
|
-
renderNode(node) {
|
|
841
|
-
const ctx = this.buildRenderContext();
|
|
842
|
-
const strategy = this.strategyRegistry.get(node.type);
|
|
843
|
-
return strategy.render(node, (child) => this.renderNode(child), ctx);
|
|
844
|
-
}
|
|
845
|
-
renderNodes(nodes) {
|
|
846
|
-
if (!nodes || nodes.length === 0) {
|
|
847
|
-
return "";
|
|
848
|
-
}
|
|
849
|
-
if (this.config.emitScopeAnchors) {
|
|
850
|
-
const inner = nodes.map((node) => this.renderNode(node)).join("\n");
|
|
851
|
-
return `<div data-md-scope="root">
|
|
852
|
-
${inner}
|
|
853
|
-
</div>`;
|
|
854
|
-
}
|
|
855
|
-
return nodes.map((node) => this.renderNode(node)).join("\n");
|
|
856
|
-
}
|
|
857
|
-
renderToHTMLString(nodes) {
|
|
858
|
-
return this.renderNodes(nodes);
|
|
859
|
-
}
|
|
860
|
-
render(markdown) {
|
|
861
|
-
return markdown;
|
|
862
|
-
}
|
|
863
|
-
getCustomCSS() {
|
|
864
|
-
return this.config.customCSS;
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
884
|
class MarkdownPipeline {
|
|
868
885
|
constructor(config = {}) {
|
|
886
|
+
this.log = config.logger ?? getDefaultLogger("md2html");
|
|
869
887
|
this.config = {
|
|
870
888
|
imagePathPrefix: config.imagePathPrefix || "",
|
|
871
889
|
imageBaseUrl: config.imageBaseUrl || "",
|
|
@@ -911,8 +929,16 @@ class MarkdownPipeline {
|
|
|
911
929
|
return this.renderer.renderNodes(nodes);
|
|
912
930
|
}
|
|
913
931
|
renderMarkdown(markdown) {
|
|
914
|
-
|
|
915
|
-
|
|
932
|
+
try {
|
|
933
|
+
const nodes = this.parse(markdown);
|
|
934
|
+
return this.render(nodes);
|
|
935
|
+
} catch (err) {
|
|
936
|
+
this.log.error("Markdown render failed", err, {
|
|
937
|
+
length: markdown.length,
|
|
938
|
+
recovery: this.config.errorRecovery
|
|
939
|
+
});
|
|
940
|
+
throw err;
|
|
941
|
+
}
|
|
916
942
|
}
|
|
917
943
|
renderPage(title, nodes, options) {
|
|
918
944
|
const html = this.render(nodes);
|
|
@@ -1057,26 +1083,48 @@ export {
|
|
|
1057
1083
|
BlockquoteHandler,
|
|
1058
1084
|
CatchAllHandler,
|
|
1059
1085
|
CodeHandler,
|
|
1086
|
+
CompositePreprocessor,
|
|
1087
|
+
CompositeTokenPostprocessor,
|
|
1060
1088
|
ContainerBlockHandler,
|
|
1089
|
+
ContainerBlockPostprocessor,
|
|
1090
|
+
ContainerBlockPreprocessor,
|
|
1061
1091
|
FrontmatterHandler,
|
|
1062
1092
|
HTMLRenderer,
|
|
1063
1093
|
HeadingHandler,
|
|
1064
1094
|
HrHandler,
|
|
1065
1095
|
HtmlHandler,
|
|
1066
1096
|
ImageHandler,
|
|
1097
|
+
LinkHandler,
|
|
1067
1098
|
ListHandler,
|
|
1099
|
+
L as LitCodeStrategy,
|
|
1100
|
+
a as LitContainerStrategy,
|
|
1101
|
+
b as LitEmphasisStrategy,
|
|
1102
|
+
c as LitFallbackStrategy,
|
|
1103
|
+
e as LitHeadingStrategy,
|
|
1104
|
+
f as LitImageStrategy,
|
|
1105
|
+
g as LitLinkStrategy,
|
|
1106
|
+
h as LitListItemStrategy,
|
|
1107
|
+
i as LitListStrategy,
|
|
1108
|
+
j as LitParagraphStrategy,
|
|
1109
|
+
k as LitRenderer,
|
|
1110
|
+
l as LitStrategyRegistry,
|
|
1111
|
+
m as LitStrongStrategy,
|
|
1112
|
+
n as LitTextStrategy,
|
|
1068
1113
|
MarkdownParser,
|
|
1069
1114
|
MarkdownPipeline,
|
|
1070
1115
|
NodeFactory,
|
|
1071
1116
|
ParagraphHandler,
|
|
1072
|
-
RendererStrategyRegistry,
|
|
1117
|
+
R as RendererStrategyRegistry,
|
|
1073
1118
|
TokenHandlerRegistry,
|
|
1074
1119
|
collectByType,
|
|
1075
1120
|
collectFromTree,
|
|
1076
1121
|
collectHeadings,
|
|
1077
1122
|
collectImages,
|
|
1123
|
+
createDefaultPostprocessor,
|
|
1124
|
+
createDefaultPreprocessor,
|
|
1125
|
+
createParseContext,
|
|
1078
1126
|
defaultAllowedHTMLTags,
|
|
1079
|
-
nodeTypeToScope,
|
|
1127
|
+
o as nodeTypeToScope,
|
|
1080
1128
|
walkTree
|
|
1081
1129
|
};
|
|
1082
1130
|
//# sourceMappingURL=index.js.map
|