@godxjp/markdown 33.20.0 → 33.22.1

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.
@@ -0,0 +1,940 @@
1
+ "use client";
2
+ import {
3
+ CODE_TOKENS
4
+ } from "./chunk-ANYWBQJT.js";
5
+ import {
6
+ katexSchema
7
+ } from "./chunk-AKKOCR2Y.js";
8
+
9
+ // src/headings.ts
10
+ import GithubSlugger from "github-slugger";
11
+ import { visit } from "unist-util-visit";
12
+ var HEADING = /^h([1-6])$/;
13
+ function textOf(node) {
14
+ if (node.type === "text") return node.value;
15
+ if ("children" in node) return node.children.map(textOf).join("");
16
+ return "";
17
+ }
18
+ function rehypeHeadingIds(options = {}) {
19
+ return (tree) => {
20
+ const slugger = new GithubSlugger();
21
+ let index = 0;
22
+ visit(tree, "element", (node) => {
23
+ const match = HEADING.exec(node.tagName);
24
+ if (!match) return;
25
+ if (node.properties?.id != null) return;
26
+ const text = textOf(node);
27
+ const info = { depth: Number(match[1]), text, index: index++ };
28
+ const id = options.resolve ? options.resolve(info) : slugger.slug(text);
29
+ if (id) node.properties = { ...node.properties, id };
30
+ });
31
+ };
32
+ }
33
+
34
+ // src/mermaid.tsx
35
+ import * as React from "react";
36
+ import { jsx, jsxs } from "react/jsx-runtime";
37
+ var ALLOWED_ELEMENTS = /* @__PURE__ */ new Set([
38
+ "svg",
39
+ "g",
40
+ "path",
41
+ "rect",
42
+ "circle",
43
+ "ellipse",
44
+ "line",
45
+ "polyline",
46
+ "polygon",
47
+ "text",
48
+ "tspan",
49
+ "textpath",
50
+ "marker",
51
+ "defs",
52
+ "style",
53
+ "title",
54
+ "desc",
55
+ "lineargradient",
56
+ "radialgradient",
57
+ "stop",
58
+ "clippath",
59
+ "mask",
60
+ "pattern",
61
+ "symbol",
62
+ "use",
63
+ "filter",
64
+ "fegaussianblur",
65
+ "feoffset",
66
+ "feblend",
67
+ "feflood",
68
+ "fecomposite",
69
+ "femerge",
70
+ "femergenode",
71
+ "fedropshadow"
72
+ ]);
73
+ var URL_REF = /url\s*\(\s*(['"]?)([^'")]*)\1\s*\)/gi;
74
+ var CSS_HAZARD = /@import|expression\s*\(|javascript:|behavior\s*:|-moz-binding|<\//i;
75
+ function urlsAreLocal(value) {
76
+ for (const match of value.matchAll(URL_REF)) {
77
+ if (!match[2].trim().startsWith("#")) return false;
78
+ }
79
+ return true;
80
+ }
81
+ function checkMermaidSvg(svg) {
82
+ if (typeof DOMParser === "undefined") return { ok: false, reason: "no DOMParser" };
83
+ const doc = new DOMParser().parseFromString(svg, "image/svg+xml");
84
+ if (doc.getElementsByTagName("parsererror").length > 0) return { ok: false, reason: "parse" };
85
+ const root = doc.documentElement;
86
+ if (root.localName.toLowerCase() !== "svg") return { ok: false, reason: "root" };
87
+ const elements = [root, ...Array.from(root.getElementsByTagName("*"))];
88
+ for (const element2 of elements) {
89
+ const name = element2.localName.toLowerCase();
90
+ if (!ALLOWED_ELEMENTS.has(name)) return { ok: false, reason: `element ${name}` };
91
+ if (name === "style") {
92
+ const css = element2.textContent ?? "";
93
+ if (CSS_HAZARD.test(css) || !urlsAreLocal(css)) return { ok: false, reason: "style" };
94
+ }
95
+ for (const attribute of Array.from(element2.attributes)) {
96
+ const attr = attribute.localName.toLowerCase();
97
+ const value = attribute.value;
98
+ if (attr.startsWith("on")) return { ok: false, reason: `handler ${attr}` };
99
+ if ((attr === "href" || attr === "src") && !value.trim().startsWith("#")) {
100
+ return { ok: false, reason: `ref ${attr}` };
101
+ }
102
+ if (attr === "style" && CSS_HAZARD.test(value)) return { ok: false, reason: "style attr" };
103
+ if (!urlsAreLocal(value)) return { ok: false, reason: `url ${attr}` };
104
+ }
105
+ }
106
+ return { ok: true, svg: root };
107
+ }
108
+ var loading = null;
109
+ var initializedTheme = null;
110
+ async function loadMermaid() {
111
+ loading ??= import("mermaid").then((module) => module.default).catch(() => null);
112
+ const api = await loading;
113
+ const theme = document.documentElement.dataset.theme === "dark" ? "dark" : "default";
114
+ if (api && theme !== initializedTheme) {
115
+ api.initialize({
116
+ startOnLoad: false,
117
+ securityLevel: "strict",
118
+ // SVG text labels, not HTML in <foreignObject> — which the gate rejects outright.
119
+ htmlLabels: false,
120
+ flowchart: { htmlLabels: false },
121
+ // Journey wraps its labels in <switch><foreignObject> by default ("element switch" at the
122
+ // gate, so every journey fell back to code); tspan placement draws them as SVG text.
123
+ journey: { textPlacement: "tspan" },
124
+ theme
125
+ });
126
+ initializedTheme = theme;
127
+ }
128
+ return api;
129
+ }
130
+ function MermaidCode({ source }) {
131
+ return /* @__PURE__ */ jsx("pre", { "data-mermaid": "code", children: /* @__PURE__ */ jsx("code", { className: "language-mermaid", children: source }) });
132
+ }
133
+ function MermaidDiagram({ source, label }) {
134
+ const host = React.useRef(null);
135
+ const id = `godx-mermaid-${React.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
136
+ const [state, setState] = React.useState("code");
137
+ React.useEffect(() => {
138
+ let cancelled = false;
139
+ setState("code");
140
+ void (async () => {
141
+ const api = await loadMermaid();
142
+ if (!api || cancelled) return;
143
+ try {
144
+ const { svg } = await api.render(id, source);
145
+ const checked = checkMermaidSvg(svg);
146
+ if (cancelled || !checked.ok || !host.current) return;
147
+ host.current.replaceChildren(document.importNode(checked.svg, true));
148
+ setState("diagram");
149
+ } catch {
150
+ } finally {
151
+ document.getElementById(`d${id}`)?.remove();
152
+ }
153
+ })();
154
+ return () => {
155
+ cancelled = true;
156
+ };
157
+ }, [id, source]);
158
+ return /* @__PURE__ */ jsxs("figure", { "data-mermaid": state, "aria-label": state === "diagram" ? label : void 0, children: [
159
+ /* @__PURE__ */ jsx("div", { ref: host, hidden: state !== "diagram" }),
160
+ state === "code" ? /* @__PURE__ */ jsx(MermaidCode, { source }) : null
161
+ ] });
162
+ }
163
+
164
+ // src/schema.ts
165
+ import { defaultSchema } from "rehype-sanitize";
166
+ var markdownSchema = {
167
+ ...defaultSchema,
168
+ tagNames: [...defaultSchema.tagNames ?? [], ...katexSchema.tagNames],
169
+ clobberPrefix: "",
170
+ protocols: {
171
+ ...defaultSchema.protocols,
172
+ href: ["http", "https", "mailto"],
173
+ src: ["http", "https"],
174
+ cite: ["http", "https"]
175
+ },
176
+ attributes: {
177
+ ...defaultSchema.attributes,
178
+ ...katexSchema.attributes,
179
+ span: [...katexSchema.attributes.span, ["dataCodeToken", ...CODE_TOKENS]],
180
+ // Heading anchors (rehype-headings, below) and the code fence language.
181
+ h1: [...defaultSchema.attributes?.h1 ?? [], "id"],
182
+ h2: [...defaultSchema.attributes?.h2 ?? [], "id"],
183
+ h3: [...defaultSchema.attributes?.h3 ?? [], "id"],
184
+ h4: [...defaultSchema.attributes?.h4 ?? [], "id"],
185
+ h5: [...defaultSchema.attributes?.h5 ?? [], "id"],
186
+ h6: [...defaultSchema.attributes?.h6 ?? [], "id"],
187
+ // Grammar v1 (gh#1156): the renderer's own callout / toggle / column markup. Every value is
188
+ // pinned — a body cannot mint any other class, kind, role or inline style through these.
189
+ div: [
190
+ ...defaultSchema.attributes?.div ?? [],
191
+ [
192
+ "className",
193
+ "ui-prose-callout",
194
+ "ui-prose-columns",
195
+ "ui-prose-column",
196
+ "ui-prose-directive"
197
+ ],
198
+ ["dataKind", "note", "tip", "important", "warning", "caution"],
199
+ ["role", "note"],
200
+ ["style", /^--prose-column-grow:\d+(?:\.\d+)?$/]
201
+ ],
202
+ p: [...defaultSchema.attributes?.p ?? [], ["className", "ui-prose-callout-title"]],
203
+ details: [...defaultSchema.attributes?.details ?? [], ["className", "ui-prose-toggle"]],
204
+ summary: [
205
+ ...defaultSchema.attributes?.summary ?? [],
206
+ ["className", "ui-prose-toggle-summary"]
207
+ ]
208
+ }
209
+ };
210
+ var ruleName = (rule) => Array.isArray(rule) ? rule[0] : rule;
211
+ function extendSchema(extension = {}) {
212
+ const attributes = { ...markdownSchema.attributes };
213
+ for (const [tag, list] of Object.entries(extension.attributes ?? {})) {
214
+ const merged = [...attributes[tag] ?? []];
215
+ for (const rule of list) {
216
+ const name = ruleName(rule);
217
+ const at = merged.findIndex((existing2) => ruleName(existing2) === name);
218
+ if (at === -1) {
219
+ merged.push(rule);
220
+ continue;
221
+ }
222
+ const existing = merged[at];
223
+ if (!Array.isArray(existing)) continue;
224
+ merged[at] = Array.isArray(rule) ? [name, ...existing.slice(1), ...rule.slice(1)] : rule;
225
+ }
226
+ attributes[tag] = merged;
227
+ }
228
+ return {
229
+ ...markdownSchema,
230
+ tagNames: [...markdownSchema.tagNames ?? [], ...extension.tagNames ?? []],
231
+ attributes
232
+ };
233
+ }
234
+ var SAFE_HREF = /^(https?:|mailto:)/i;
235
+ var SAFE_SRC = /^https?:/i;
236
+ var SCHEME = /^[a-z][a-z0-9+.-]*:/i;
237
+ function safeUrl(url, key) {
238
+ const value = url.trim();
239
+ const probe = value.replace(/[\x00-\x20\x7f]/g, "");
240
+ if (!SCHEME.test(probe)) return value;
241
+ if (key === "src") return SAFE_SRC.test(probe) ? value : "";
242
+ return SAFE_HREF.test(probe) ? value : "";
243
+ }
244
+
245
+ // src/core.tsx
246
+ import * as React3 from "react";
247
+ import ReactMarkdown from "react-markdown";
248
+ import rehypeSanitize from "rehype-sanitize";
249
+ import remarkGfm from "remark-gfm";
250
+ import { visit as visit2 } from "unist-util-visit";
251
+
252
+ // src/table-scroll.tsx
253
+ import * as React2 from "react";
254
+ import { jsx as jsx2 } from "react/jsx-runtime";
255
+ function TableScroll({ children }) {
256
+ const ref = React2.useRef(null);
257
+ const [scrolls, setScrolls] = React2.useState(false);
258
+ React2.useLayoutEffect(() => {
259
+ const box = ref.current;
260
+ if (!box || typeof ResizeObserver === "undefined") return void 0;
261
+ const measure = () => setScrolls(box.scrollWidth > box.clientWidth + 1);
262
+ const observer = new ResizeObserver(measure);
263
+ observer.observe(box);
264
+ if (box.firstElementChild) observer.observe(box.firstElementChild);
265
+ measure();
266
+ return () => observer.disconnect();
267
+ }, []);
268
+ return /* @__PURE__ */ jsx2(
269
+ "div",
270
+ {
271
+ ref,
272
+ className: "ui-prose-table-scroll",
273
+ "data-slot": "prose-table-scroll",
274
+ tabIndex: scrolls ? 0 : void 0,
275
+ children
276
+ }
277
+ );
278
+ }
279
+
280
+ // src/codec/model.ts
281
+ var CALLOUT_KINDS = ["note", "tip", "important", "warning", "caution"];
282
+ var COLUMNS_MIN = 2;
283
+ var COLUMNS_MAX = 4;
284
+ var MODELLED_DIRECTIVES = ["toggle", "columns", "column"];
285
+
286
+ // src/codec/readers.ts
287
+ var CALLOUT = /^\[!([A-Za-z]+)\](?:[ \t]+([^\n]*))?$/;
288
+ function readCallout(node) {
289
+ const [first, ...rest] = node.children;
290
+ if (first?.type !== "paragraph") return null;
291
+ const [head, ...tail] = first.children;
292
+ if (head?.type !== "text") return null;
293
+ const newline = head.value.indexOf("\n");
294
+ if (newline === -1 && tail.length > 0) return null;
295
+ const line = newline === -1 ? head.value : head.value.slice(0, newline);
296
+ const match = CALLOUT.exec(line);
297
+ const kind = match?.[1]?.toLowerCase();
298
+ if (!match || !kind || !CALLOUT_KINDS.includes(kind)) return null;
299
+ const remainder = [
300
+ ...newline === -1 ? [] : [{ ...head, value: head.value.slice(newline + 1) }],
301
+ ...tail
302
+ ].filter((n) => !(n.type === "text" && n.value === ""));
303
+ return {
304
+ kind,
305
+ title: match[2]?.trim() || null,
306
+ body: [
307
+ ...remainder.length ? [{ type: "paragraph", children: remainder }] : [],
308
+ ...rest
309
+ ]
310
+ };
311
+ }
312
+ function labelOf(node) {
313
+ const first = node.children[0];
314
+ return first?.type === "paragraph" && first.data?.directiveLabel ? first : null;
315
+ }
316
+ function readToggle(node) {
317
+ if (node.name !== "toggle" || Object.keys(node.attributes ?? {}).length > 0) return null;
318
+ const label = labelOf(node);
319
+ return {
320
+ summary: label?.children ?? [],
321
+ body: label ? node.children.slice(1) : node.children
322
+ };
323
+ }
324
+ function readColumns(node, nested) {
325
+ if (node.name !== "columns" || nested || labelOf(node) || Object.keys(node.attributes ?? {}).length) {
326
+ return null;
327
+ }
328
+ const columns = node.children;
329
+ if (columns.length < COLUMNS_MIN || columns.length > COLUMNS_MAX) return null;
330
+ const parts = [];
331
+ for (const column of columns) {
332
+ if (column.type !== "containerDirective" || column.name !== "column" || labelOf(column))
333
+ return null;
334
+ const attributes = Object.entries(column.attributes ?? {});
335
+ if (attributes.length > 1) return null;
336
+ let width = null;
337
+ if (attributes.length === 1) {
338
+ const [key, value] = attributes[0];
339
+ if (key !== "width" || typeof value !== "string" || !/^(?:[1-9]\d?|100)$/.test(value))
340
+ return null;
341
+ width = Number(value);
342
+ }
343
+ parts.push({ width, body: column.children });
344
+ }
345
+ return parts;
346
+ }
347
+ function columnShares(columns) {
348
+ const explicit = columns.reduce((sum, c) => sum + (c.width ?? 0), 0);
349
+ const open = columns.filter((c) => c.width == null).length;
350
+ const each = open ? Math.max(1, (100 - explicit) / open) : 0;
351
+ return columns.map((c) => c.width ?? Math.round(each * 100) / 100);
352
+ }
353
+
354
+ // src/codec/syntax.ts
355
+ import { directive } from "micromark-extension-directive";
356
+ import { gfm } from "micromark-extension-gfm";
357
+ import { cjkFriendlyExtension } from "micromark-extension-cjk-friendly";
358
+ import { frontmatter } from "micromark-extension-frontmatter";
359
+ import { math } from "micromark-extension-math";
360
+ import { frontmatterFromMarkdown, frontmatterToMarkdown } from "mdast-util-frontmatter";
361
+ import { mathFromMarkdown, mathToMarkdown } from "mdast-util-math";
362
+ import { directiveFromMarkdown } from "mdast-util-directive";
363
+ import { gfmFromMarkdown, gfmToMarkdown } from "mdast-util-gfm";
364
+ function micromarkExtensions() {
365
+ const [container] = directive().flow[58];
366
+ const containerOnly = { flow: { 58: container } };
367
+ return [gfm(), cjkFriendlyExtension(), frontmatter(["yaml"]), dollarMath(), containerOnly];
368
+ }
369
+ var DOLLAR = 36;
370
+ var isSpace = (code) => code === null || code === void 0 || code < 0 || code === 32;
371
+ var isDigit = (code) => code != null && code >= 48 && code <= 57;
372
+ var BACKSLASH = 92;
373
+ function dollarMath() {
374
+ const extension = math();
375
+ const text = extension.text[DOLLAR];
376
+ const tokenize = function(effects, ok, nok) {
377
+ const codes = [];
378
+ let done = false;
379
+ const finish = (code) => {
380
+ done = true;
381
+ const single = codes[1] !== DOLLAR;
382
+ const after = codes[codes.length - 1];
383
+ const before = codes[codes.length - 3];
384
+ const refused = isSpace(codes[1]) || isSpace(before) || before === BACKSLASH || isDigit(after);
385
+ if (single && refused) return nok(code);
386
+ return ok(code);
387
+ };
388
+ const watch = (state) => (code) => {
389
+ if (done) return state(code);
390
+ codes.push(code);
391
+ const next = state(code);
392
+ return next && !done ? watch(next) : next;
393
+ };
394
+ return watch(
395
+ text.tokenize.call(this, effects, finish, (code) => {
396
+ done = true;
397
+ return nok(code);
398
+ })
399
+ );
400
+ };
401
+ return { ...extension, text: { [DOLLAR]: { ...text, tokenize } } };
402
+ }
403
+ function fromMarkdownExtensions() {
404
+ return [
405
+ gfmFromMarkdown(),
406
+ directiveFromMarkdown(),
407
+ frontmatterFromMarkdown(["yaml"]),
408
+ mathFromMarkdown()
409
+ ];
410
+ }
411
+
412
+ // src/directives.ts
413
+ var DEFAULT_CALLOUT_TITLES = {
414
+ note: "Note",
415
+ tip: "Tip",
416
+ important: "Important",
417
+ warning: "Warning",
418
+ caution: "Caution"
419
+ };
420
+ var element = (hName, hProperties = {}) => ({
421
+ hName,
422
+ hProperties
423
+ });
424
+ function remarkKitSyntax(options = {}) {
425
+ const titles = { ...DEFAULT_CALLOUT_TITLES, ...options.calloutTitles };
426
+ const registered = new Set(
427
+ (options.directives ?? []).filter((name) => !MODELLED_DIRECTIVES.includes(name))
428
+ );
429
+ return function() {
430
+ const data = this.data();
431
+ (data.micromarkExtensions ??= []).push(...micromarkExtensions().slice(1));
432
+ (data.fromMarkdownExtensions ??= []).push(...fromMarkdownExtensions().slice(1));
433
+ let text = "";
434
+ const walk = (node, inColumn) => {
435
+ if (node.type === "blockquote") callout(node, titles);
436
+ else if (node.type === "containerDirective") directive2(node, inColumn, registered, text);
437
+ if (!("children" in node)) return;
438
+ const isColumn = node.type === "containerDirective" && node.name === "column";
439
+ for (const child of node.children) walk(child, inColumn || isColumn);
440
+ };
441
+ return (tree, file) => {
442
+ text = typeof file?.value === "string" ? file.value : "";
443
+ tree.children = tree.children.filter((node) => node.type !== "yaml");
444
+ walk(tree, false);
445
+ };
446
+ };
447
+ }
448
+ function callout(node, titles) {
449
+ const parts = readCallout(node);
450
+ if (!parts) return;
451
+ const title = {
452
+ type: "paragraph",
453
+ data: element("p", { className: ["ui-prose-callout-title"] }),
454
+ children: [{ type: "text", value: parts.title ?? titles[parts.kind] }]
455
+ };
456
+ node.data = element("div", {
457
+ className: ["ui-prose-callout"],
458
+ dataKind: parts.kind,
459
+ role: "note"
460
+ });
461
+ node.children = [title, ...parts.body];
462
+ }
463
+ function unprefix(line, prefix) {
464
+ if (!prefix) return line;
465
+ if (line.startsWith(prefix)) return line.slice(prefix.length);
466
+ const bare = prefix.trimEnd();
467
+ return bare && line.startsWith(bare) ? line.slice(bare.length) : line;
468
+ }
469
+ function directiveSlices(node, text) {
470
+ const attributes = {};
471
+ for (const [key, value] of Object.entries(node.attributes ?? {})) attributes[key] = value ?? "";
472
+ const at = (position) => position && position.start.offset != null && position.end.offset != null ? { from: position.start.offset, to: position.end.offset } : null;
473
+ const whole = at(node.position);
474
+ if (!whole) return { label: null, attributes, source: "", body: "" };
475
+ const prefix = text.slice(text.lastIndexOf("\n", whole.from - 1) + 1, whole.from);
476
+ const slice = (from, to) => text.slice(from, to).split("\n").map((line, i) => i === 0 ? line : unprefix(line, prefix)).join("\n");
477
+ const [first, ...rest] = node.children;
478
+ const hasLabel = first?.type === "paragraph" && Boolean(first.data?.directiveLabel);
479
+ const label = hasLabel ? at(first.position) : null;
480
+ const body = (hasLabel ? rest : node.children).map((child) => at(child.position));
481
+ const start = body[0];
482
+ const end = body[body.length - 1];
483
+ return {
484
+ label: label ? slice(label.from + 1, label.to - 1) : hasLabel ? "" : null,
485
+ attributes,
486
+ source: slice(whole.from, whole.to),
487
+ body: start && end ? slice(start.from, end.to) : ""
488
+ };
489
+ }
490
+ function directive2(node, nested, registered, text) {
491
+ const toggle = readToggle(node);
492
+ if (toggle) {
493
+ const summary = {
494
+ type: "paragraph",
495
+ data: element("summary", { className: ["ui-prose-toggle-summary"] }),
496
+ children: toggle.summary
497
+ };
498
+ node.data = element("details", { className: ["ui-prose-toggle"] });
499
+ node.children = [summary, ...toggle.body];
500
+ return;
501
+ }
502
+ const columns = readColumns(node, nested);
503
+ if (columns) {
504
+ const shares = columnShares(columns);
505
+ node.data = element("div", { className: ["ui-prose-columns"] });
506
+ node.children = columns.map((column, i) => ({
507
+ type: "containerDirective",
508
+ name: "column",
509
+ attributes: {},
510
+ data: element("div", {
511
+ className: ["ui-prose-column"],
512
+ style: `--prose-column-grow:${shares[i]}`
513
+ }),
514
+ children: column.body
515
+ }));
516
+ return;
517
+ }
518
+ if (registered.has(node.name)) {
519
+ node.data = element("div", {
520
+ className: ["ui-prose-directive"],
521
+ dataDirective: node.name,
522
+ dataDirectiveBlock: JSON.stringify(directiveSlices(node, text))
523
+ });
524
+ return;
525
+ }
526
+ if (!node.data?.hName) node.data = element("div", { className: ["ui-prose-directive"] });
527
+ }
528
+
529
+ // src/core.tsx
530
+ import { Fragment, jsx as jsx3 } from "react/jsx-runtime";
531
+ var MARKDOWN_FORMAT = "md";
532
+ var RENDERER_VERSION = 6;
533
+ var URL_ATTRIBUTES = {
534
+ a: "href",
535
+ img: "src",
536
+ blockquote: "cite",
537
+ q: "cite"
538
+ };
539
+ function rehypeResolveUrls(options) {
540
+ return (tree) => {
541
+ if (!options.resolve) return;
542
+ visit2(tree, "element", (node) => {
543
+ const key = URL_ATTRIBUTES[node.tagName];
544
+ const value = key ? node.properties?.[key] : void 0;
545
+ if (typeof value !== "string") return;
546
+ const resolved = options.resolve(value, key);
547
+ if (resolved !== void 0) node.properties = { ...node.properties, [key]: resolved };
548
+ });
549
+ };
550
+ }
551
+ var graphemes = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : void 0;
552
+ function textOf2(node) {
553
+ let text = "";
554
+ let hasImage = false;
555
+ visit2(node, (child) => {
556
+ if (child.type === "text") text += child.value;
557
+ else if (child.type === "element" && child.tagName === "img") hasImage = true;
558
+ });
559
+ return { text, hasImage };
560
+ }
561
+ function rehypeShortCells(options) {
562
+ return (tree) => {
563
+ const { max } = options;
564
+ if (max === false || max <= 0) return;
565
+ visit2(tree, "element", (node) => {
566
+ if (node.tagName !== "td" && node.tagName !== "th") return;
567
+ const { text, hasImage } = textOf2(node);
568
+ const token = text.trim();
569
+ if (hasImage || token === "" || /\s/.test(token)) return;
570
+ const length = graphemes ? [...graphemes.segment(token)].length : [...token].length;
571
+ if (length <= max) node.properties = { ...node.properties, dataShort: "" };
572
+ });
573
+ };
574
+ }
575
+ function rehypeExternalLinks(options) {
576
+ return (tree) => {
577
+ if (options.policy !== "new-tab") return;
578
+ const origin = options.origin ?? globalThis.location?.origin;
579
+ visit2(tree, "element", (node) => {
580
+ if (node.tagName !== "a") return;
581
+ const href = node.properties?.href;
582
+ if (typeof href !== "string" || !/^https?:\/\//i.test(href)) return;
583
+ let target;
584
+ try {
585
+ target = new URL(href);
586
+ } catch {
587
+ return;
588
+ }
589
+ if (origin && target.origin === origin) return;
590
+ node.properties = { ...node.properties, target: "_blank", rel: ["noopener", "noreferrer"] };
591
+ });
592
+ };
593
+ }
594
+ function omitNode(props) {
595
+ const { node: _node, ...rest } = props;
596
+ return rest;
597
+ }
598
+ function fenceOf(node) {
599
+ const code = node?.children?.[0];
600
+ if (!code || code.type !== "element" || code.tagName !== "code") return void 0;
601
+ const classes = code.properties?.className ?? [];
602
+ const language = classes.find((name) => name.startsWith("language-"))?.slice(9);
603
+ const text = code.children.map((child) => child.type === "text" ? child.value : "").join("");
604
+ return { language, text };
605
+ }
606
+ var DIRECTIVE_SCHEMA = {
607
+ attributes: { div: ["dataDirective", "dataDirectiveBlock"] }
608
+ };
609
+ function withoutLabel(node, children) {
610
+ const at = node?.children.findIndex((child) => child.type === "element") ?? -1;
611
+ if (at === -1) return children;
612
+ if (!Array.isArray(children)) return at === 0 ? null : children;
613
+ return children.filter((_, index) => index !== at);
614
+ }
615
+ function MarkdownCore({
616
+ children,
617
+ remarkPlugins = [],
618
+ rehypePlugins = [],
619
+ schema,
620
+ components,
621
+ resolveUrl,
622
+ headingId,
623
+ mermaid = true,
624
+ highlight = true,
625
+ allowedElements,
626
+ disallowedElements,
627
+ allowElement,
628
+ unwrapDisallowed,
629
+ shortCellLength = 24,
630
+ calloutTitles,
631
+ externalLinks = "same-tab",
632
+ origin,
633
+ directives,
634
+ runtime
635
+ }) {
636
+ const directiveNames = React3.useMemo(
637
+ () => Object.keys(directives ?? {}).sort().join(" "),
638
+ [directives]
639
+ );
640
+ const sanitizeSchema = React3.useMemo(() => {
641
+ if (!directiveNames) return extendSchema(schema);
642
+ return extendSchema({
643
+ tagNames: schema?.tagNames,
644
+ attributes: {
645
+ ...schema?.attributes,
646
+ div: [...schema?.attributes?.div ?? [], ...DIRECTIVE_SCHEMA.attributes.div]
647
+ }
648
+ });
649
+ }, [schema, directiveNames]);
650
+ const kitSyntax = React3.useMemo(
651
+ () => remarkKitSyntax({
652
+ calloutTitles,
653
+ directives: directiveNames ? directiveNames.split(" ") : []
654
+ }),
655
+ [calloutTitles, directiveNames]
656
+ );
657
+ const live = React3.useRef(directives);
658
+ live.current = directives;
659
+ const merged = React3.useMemo(() => {
660
+ const HostTable = components?.table;
661
+ const table = (props) => /* @__PURE__ */ jsx3(TableScroll, { children: HostTable ? typeof HostTable === "string" ? React3.createElement(HostTable, props) : /* @__PURE__ */ jsx3(HostTable, { ...props }) : /* @__PURE__ */ jsx3("table", { ...omitNode(props) }) });
662
+ const out = { ...components, table };
663
+ if (directiveNames) {
664
+ const HostDiv = components?.div;
665
+ out.div = (props) => {
666
+ const {
667
+ "data-directive": name,
668
+ "data-directive-block": block,
669
+ ...rest
670
+ } = props;
671
+ const registry = live.current;
672
+ const render = typeof name === "string" && registry && Object.hasOwn(registry, name) ? registry[name] : void 0;
673
+ if (render && typeof block === "string") {
674
+ const parts = JSON.parse(block);
675
+ const drawn = render({
676
+ name,
677
+ ...parts,
678
+ children: parts.label === null ? props.children : withoutLabel(props.node, props.children)
679
+ });
680
+ if (drawn !== void 0) return /* @__PURE__ */ jsx3(Fragment, { children: drawn });
681
+ }
682
+ if (HostDiv)
683
+ return typeof HostDiv === "string" ? React3.createElement(HostDiv, rest) : /* @__PURE__ */ jsx3(HostDiv, { ...rest });
684
+ return /* @__PURE__ */ jsx3("div", { ...omitNode(rest) });
685
+ };
686
+ }
687
+ if (!mermaid) return out;
688
+ const HostPre = components?.pre;
689
+ const pre = (props) => {
690
+ const fence = fenceOf(props.node);
691
+ if (fence?.language === "mermaid") return /* @__PURE__ */ jsx3(MermaidDiagram, { source: fence.text });
692
+ if (HostPre)
693
+ return typeof HostPre === "string" ? React3.createElement(HostPre, props) : /* @__PURE__ */ jsx3(HostPre, { ...props });
694
+ const { node: _node, children: inner, ...rest } = props;
695
+ return /* @__PURE__ */ jsx3("pre", { ...rest, children: inner });
696
+ };
697
+ return { ...out, pre };
698
+ }, [components, mermaid, directiveNames]);
699
+ return /* @__PURE__ */ jsx3(
700
+ ReactMarkdown,
701
+ {
702
+ remarkPlugins: [
703
+ remarkGfm,
704
+ kitSyntax,
705
+ ...remarkPlugins,
706
+ ...runtime.probe ? [runtime.probe] : []
707
+ ],
708
+ rehypePlugins: [
709
+ [rehypeResolveUrls, { resolve: resolveUrl }],
710
+ [rehypeHeadingIds, { resolve: headingId }],
711
+ // Both BEFORE the sanitiser, which judges their output (schema.ts).
712
+ ...runtime.math ? [runtime.math] : [],
713
+ ...highlight && runtime.highlight ? [runtime.highlight] : [],
714
+ [rehypeSanitize, sanitizeSchema],
715
+ [rehypeShortCells, { max: shortCellLength }],
716
+ [rehypeExternalLinks, { policy: externalLinks, origin }],
717
+ ...rehypePlugins
718
+ ],
719
+ urlTransform: safeUrl,
720
+ components: merged,
721
+ allowedElements,
722
+ disallowedElements,
723
+ allowElement,
724
+ unwrapDisallowed,
725
+ children
726
+ }
727
+ );
728
+ }
729
+
730
+ // src/fixtures.ts
731
+ var MARKDOWN_FIXTURES = [
732
+ {
733
+ name: "headings get GitHub anchors, de-duplicated",
734
+ markdown: "# \u6982\u8981\n\n## Setup\n\n## Setup",
735
+ html: '<h1 id="\u6982\u8981">\u6982\u8981</h1>\n<h2 id="setup">Setup</h2>\n<h2 id="setup-1">Setup</h2>'
736
+ },
737
+ {
738
+ name: "emphasis, strong, strikethrough, inline code",
739
+ markdown: "*em* **strong** ~~gone~~ `code`",
740
+ html: "<p><em>em</em> <strong>strong</strong> <del>gone</del> <code>code</code></p>"
741
+ },
742
+ {
743
+ name: "GFM table with alignment, in its scroll box",
744
+ markdown: "| a | b |\n|:--|--:|\n| 1 | 2 |",
745
+ // Every table sits in its own scroll box (gh#1131, renderer v2); a single short token per
746
+ // cell carries `data-short` (gh#1150, renderer v3).
747
+ html: '<div class="ui-prose-table-scroll" data-slot="prose-table-scroll"><table><thead><tr><th data-short="" style="text-align:left">a</th><th data-short="" style="text-align:right">b</th></tr></thead><tbody><tr><td data-short="" style="text-align:left">1</td><td data-short="" style="text-align:right">2</td></tr></tbody></table></div>'
748
+ },
749
+ {
750
+ name: "task list stays read-only",
751
+ markdown: "- [x] done\n- [ ] todo",
752
+ html: '<ul class="contains-task-list">\n<li class="task-list-item"><input type="checkbox" disabled="" checked=""/> done</li>\n<li class="task-list-item"><input type="checkbox" disabled=""/> todo</li>\n</ul>'
753
+ },
754
+ {
755
+ name: "fenced code keeps its language class, tokenised (renderer v6)",
756
+ markdown: "```ts\nconst a = 1;\n```",
757
+ html: '<pre><code class="language-ts"><span data-code-token="keyword">const</span> a = <span data-code-token="constant">1</span>;\n</code></pre>'
758
+ },
759
+ {
760
+ name: "links and autolinks",
761
+ markdown: "[docs](https://example.com/a) <https://example.com> mail@example.com",
762
+ html: '<p><a href="https://example.com/a">docs</a> <a href="https://example.com">https://example.com</a> <a href="mailto:mail@example.com">mail@example.com</a></p>'
763
+ },
764
+ {
765
+ name: "relative and fragment links pass",
766
+ markdown: "[a](/wiki/Page) [b](#setup) [c](other)",
767
+ html: '<p><a href="/wiki/Page">a</a> <a href="#setup">b</a> <a href="other">c</a></p>'
768
+ },
769
+ {
770
+ name: "image by URL",
771
+ markdown: "![chart](https://cdn.example.com/c.png)",
772
+ html: '<p><img src="https://cdn.example.com/c.png" alt="chart"/></p>'
773
+ },
774
+ {
775
+ name: "footnote link and its target agree",
776
+ markdown: "Text[^1]\n\n[^1]: Note.",
777
+ html: '<p>Text<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup></p>\n<section data-footnotes="true" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>\n<ol>\n<li id="user-content-fn-1">\n<p>Note. <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">\u21A9</a></p>\n</li>\n</ol>\n</section>'
778
+ },
779
+ {
780
+ name: "mermaid fence before the diagram has rendered",
781
+ markdown: "```mermaid\ngraph TD; A-->B\n```",
782
+ html: '<figure data-mermaid="code"><div hidden=""></div><pre data-mermaid="code"><code class="language-mermaid">graph TD; A--&gt;B\n</code></pre></figure>'
783
+ },
784
+ {
785
+ name: "raw HTML blocks are dropped, never parsed",
786
+ hostile: true,
787
+ markdown: '<script>alert(1)</script>\n\n<img src=x onerror="alert(1)">\n\n<div id="app-sidebar">x</div>',
788
+ html: "\n\n",
789
+ forbidden: ["<script", "<img", "onerror", "app-sidebar"]
790
+ },
791
+ {
792
+ name: "inline raw HTML is dropped, its text kept",
793
+ hostile: true,
794
+ markdown: 'a <b onclick="alert(1)">bold</b> <iframe src="https://evil.example"></iframe> z',
795
+ html: "<p>a bold z</p>",
796
+ forbidden: ["<b", "onclick", "<iframe", "evil.example"]
797
+ },
798
+ {
799
+ name: "javascript: and data: links are dropped",
800
+ hostile: true,
801
+ markdown: "[a](javascript:alert(1)) [b](JAVASCRIPT:alert(1)) [c](data:text/html,<script>alert(1)</script>) [d](vbscript:x)",
802
+ html: "<p><a>a</a> <a>b</a> <a>c</a> <a>d</a></p>",
803
+ forbidden: ["javascript:", "JAVASCRIPT:", "data:", "vbscript:"]
804
+ },
805
+ {
806
+ name: "a scheme split by control characters is dropped",
807
+ hostile: true,
808
+ markdown: "[a](<java script:alert(1)>)",
809
+ html: "<p><a>a</a></p>",
810
+ forbidden: ["script:"]
811
+ },
812
+ {
813
+ name: "data: and javascript: images are dropped",
814
+ hostile: true,
815
+ markdown: "![x](data:image/svg+xml;base64,PHN2Zz4=) ![y](javascript:alert(1))",
816
+ html: '<p><img alt="x"/> <img alt="y"/></p>',
817
+ forbidden: ["data:", "javascript:"]
818
+ },
819
+ // Grammar v1 (gh#1156, renderer v4): the constructs the codec and @godxjp/block-editor model.
820
+ {
821
+ name: "CJK-friendly emphasis next to \u3001\u3002\u300C\u300D\uFF08\uFF09",
822
+ markdown: "\u306E**\u300C\u5F37\u8ABF\u300D**\u3067\u3059\u3002\uFF08*\u6CE8*\uFF09\u300C[\u30EA\u30F3\u30AF](https://example.com/)\u300D\u3001**\u592A\u5B57**\u3002",
823
+ html: '<p>\u306E<strong>\u300C\u5F37\u8ABF\u300D</strong>\u3067\u3059\u3002\uFF08<em>\u6CE8</em>\uFF09\u300C<a href="https://example.com/">\u30EA\u30F3\u30AF</a>\u300D\u3001<strong>\u592A\u5B57</strong>\u3002</p>'
824
+ },
825
+ {
826
+ name: "callout with a title, and one without",
827
+ markdown: "> [!WARNING] Careful\n> Body\n\n> [!tip]\n> No title",
828
+ html: '<div class="ui-prose-callout" data-kind="warning" role="note">\n<p class="ui-prose-callout-title">Careful</p>\n<p>Body</p>\n</div>\n<div class="ui-prose-callout" data-kind="tip" role="note">\n<p class="ui-prose-callout-title">Tip</p>\n<p>No title</p>\n</div>'
829
+ },
830
+ {
831
+ name: "a fold marker or unknown kind stays a quote",
832
+ markdown: "> [!NOTE]- folded\n\n> [!INFO] unknown",
833
+ html: "<blockquote>\n<p>[!NOTE]- folded</p>\n</blockquote>\n<blockquote>\n<p>[!INFO] unknown</p>\n</blockquote>"
834
+ },
835
+ {
836
+ name: "toggle with an inline summary",
837
+ markdown: ":::toggle[Read *more*]\nBody\n:::",
838
+ html: '<details class="ui-prose-toggle"><summary class="ui-prose-toggle-summary">Read <em>more</em></summary><p>Body</p></details>'
839
+ },
840
+ {
841
+ name: "columns with a width and an equal share",
842
+ markdown: "::::columns\n:::column{width=40}\nLeft\n:::\n\n:::column\nRight\n:::\n::::",
843
+ html: '<div class="ui-prose-columns"><div class="ui-prose-column" style="--prose-column-grow:40"><p>Left</p></div><div class="ui-prose-column" style="--prose-column-grow:60"><p>Right</p></div></div>'
844
+ },
845
+ {
846
+ name: "wikilinks, embeds and times stay text",
847
+ markdown: "See [[Page#Intro|intro]] at 10:30.\n\n![[Diagram]]",
848
+ html: "<p>See [[Page#Intro|intro]] at 10:30.</p>\n<p>![[Diagram]]</p>"
849
+ },
850
+ {
851
+ // Renderer v5 (gh#1163): YAML front matter is metadata, not body. Before v5 it rendered as an
852
+ // <hr> plus a setext <h2> holding the YAML text.
853
+ name: "YAML front matter renders nothing",
854
+ markdown: "---\ntitle: Spec\ntags: [a]\n---\n\n# Heading\n\nBody",
855
+ html: '<h1 id="heading">Heading</h1>\n<p>Body</p>',
856
+ forbidden: ["title: Spec", "<hr"]
857
+ },
858
+ // Renderer v6: math (KaTeX, before the sanitiser) and syntax colour (`data-code-token`).
859
+ {
860
+ name: "inline and display math are drawn by KaTeX; `\\,` keeps its backslash",
861
+ markdown: "Inline $a\\,b$ and display:\n\n$$\nx^2\n$$",
862
+ html: '<p>Inline <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mtext>\u2009</mtext><mi>b</mi></mrow><annotation encoding="application/x-tex">a\\,b</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">b</span></span></span></span> and display:</p>\n<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>x</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">x^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8641em"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span>'
863
+ },
864
+ {
865
+ name: "a ```math fence is display math",
866
+ markdown: "```math\n\\frac{1}{2}\n```",
867
+ html: '<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mfrac><mn>1</mn><mn>2</mn></mfrac></mrow><annotation encoding="application/x-tex">\\frac{1}{2}\n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.0074em;vertical-align:-0.686em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3214em"><span style="top:-2.314em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.677em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">\u200B</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span>'
868
+ },
869
+ {
870
+ name: "prices stay text: a single `$` follows Pandoc's rule",
871
+ markdown: "$5 and $10, $5-$10, \\$x\\$",
872
+ html: "<p>$5 and $10, $5-$10, $x$</p>",
873
+ forbidden: ["katex"]
874
+ },
875
+ {
876
+ name: "a formula that does not parse shows its source",
877
+ markdown: "$\\frac{1$",
878
+ html: '<p><span class="katex-error" title="ParseError: KaTeX parse error: Unexpected end of input in a macro argument, expected &#x27;}&#x27; at end of input: \\frac{1" style="color:#cc0000">\\frac{1</span></p>'
879
+ },
880
+ {
881
+ name: "KaTeX \\href, \\url and \\includegraphics stay text (trust: false)",
882
+ hostile: true,
883
+ markdown: "$\\href{javascript:alert(1)}{a}$ $\\url{https://evil.example}$ $\\includegraphics{https://evil.example/i.png}$",
884
+ html: '<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="#cc0000"><mtext>\\href</mtext></mstyle></mrow><annotation encoding="application/x-tex">\\href{javascript:alert(1)}{a}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text" style="color:#cc0000"><span class="mord" style="color:#cc0000">\\href</span></span></span></span></span> <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="#cc0000"><mtext>\\url</mtext></mstyle></mrow><annotation encoding="application/x-tex">\\url{https://evil.example}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text" style="color:#cc0000"><span class="mord" style="color:#cc0000">\\url</span></span></span></span></span> <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="#cc0000"><mtext>\\includegraphics</mtext></mstyle></mrow><annotation encoding="application/x-tex">\\includegraphics{https://evil.example/i.png}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text" style="color:#cc0000"><span class="mord" style="color:#cc0000">\\includegraphics</span></span></span></span></span></p>',
885
+ forbidden: ["<a ", "href=", "<img", "src="]
886
+ },
887
+ {
888
+ name: "KaTeX \\htmlClass, \\htmlId, \\htmlStyle and \\htmlData stay text",
889
+ hostile: true,
890
+ markdown: "$\\htmlClass{ui-pwn}{a}$ $\\htmlId{pwn}{b}$ $\\htmlStyle{background:url(https://evil.example)}{c}$ $\\htmlData{pwn=1}{d}$",
891
+ html: '<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="#cc0000"><mtext>\\htmlClass</mtext></mstyle></mrow><annotation encoding="application/x-tex">\\htmlClass{ui-pwn}{a}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text" style="color:#cc0000"><span class="mord" style="color:#cc0000">\\htmlClass</span></span></span></span></span> <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="#cc0000"><mtext>\\htmlId</mtext></mstyle></mrow><annotation encoding="application/x-tex">\\htmlId{pwn}{b}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text" style="color:#cc0000"><span class="mord" style="color:#cc0000">\\htmlId</span></span></span></span></span> <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="#cc0000"><mtext>\\htmlStyle</mtext></mstyle></mrow><annotation encoding="application/x-tex">\\htmlStyle{background:url(https://evil.example)}{c}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text" style="color:#cc0000"><span class="mord" style="color:#cc0000">\\htmlStyle</span></span></span></span></span> <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mstyle mathcolor="#cc0000"><mtext>\\htmlData</mtext></mstyle></mrow><annotation encoding="application/x-tex">\\htmlData{pwn=1}{d}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord text" style="color:#cc0000"><span class="mord" style="color:#cc0000">\\htmlData</span></span></span></span></span></p>',
892
+ forbidden: ['class="ui-pwn"', 'id="pwn"', "data-pwn", 'style="background']
893
+ },
894
+ {
895
+ name: "a user-sized KaTeX box is capped at 10em",
896
+ hostile: true,
897
+ markdown: "$\\rule{9999em}{9999em}$",
898
+ html: '<p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mpadded height="0em" voffset="0em"><mspace mathbackground="black" width="10em" height="10em"></mspace></mpadded></mrow><annotation encoding="application/x-tex">\\rule{9999em}{9999em}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:10em"></span><span class="mord rule" style="border-right-width:10em;border-top-width:10em;bottom:0em"></span></span></span></span></p>',
899
+ forbidden: ["width:9999em", 'width="9999em"']
900
+ },
901
+ {
902
+ name: "HTML in a highlighted fence stays text",
903
+ hostile: true,
904
+ markdown: "```html\n<script>alert(1)</script>\n```",
905
+ html: '<pre><code class="language-html"><span data-code-token="punctuation">&lt;<span data-code-token="keyword">script</span>&gt;</span>alert(1)<span data-code-token="punctuation">&lt;/<span data-code-token="keyword">script</span>&gt;</span>\n</code></pre>',
906
+ forbidden: ["<script"]
907
+ },
908
+ {
909
+ name: "a fence in an unknown language stays plain",
910
+ markdown: "```unknown\nlet a = 1\n```",
911
+ html: '<pre><code class="language-unknown">let a = 1\n</code></pre>'
912
+ },
913
+ // Directive blocks: a container directive the kit does not model renders its content (the
914
+ // label as a paragraph) until a host registers a renderer for its name (`<Markdown directives>`).
915
+ {
916
+ name: "an unregistered :::poll renders its label and body",
917
+ markdown: ":::poll[Which date works?]{id=launch-date type=single closes=2026-11-10}\n- 11\u670815\u65E5\n- 11\u670822\u65E5 {#d22}\n:::",
918
+ html: '<div class="ui-prose-directive"><p>Which date works?</p><ul>\n<li>11\u670815\u65E5</li>\n<li>11\u670822\u65E5 {#d22}</li>\n</ul></div>'
919
+ },
920
+ {
921
+ name: "an unregistered ::::form holding :::poll blocks nests",
922
+ markdown: "::::form[Survey]{id=f}\n:::poll[A?]{id=a}\n- x\n- y\n:::\n\n:::poll{type=ack id=b}\nI agree.\n:::\n::::",
923
+ html: '<div class="ui-prose-directive"><p>Survey</p><div class="ui-prose-directive"><p>A?</p><ul>\n<li>x</li>\n<li>y</li>\n</ul></div><div class="ui-prose-directive"><p>I agree.</p></div></div>'
924
+ }
925
+ ];
926
+
927
+ export {
928
+ rehypeHeadingIds,
929
+ checkMermaidSvg,
930
+ MermaidDiagram,
931
+ markdownSchema,
932
+ extendSchema,
933
+ safeUrl,
934
+ micromarkExtensions,
935
+ fromMarkdownExtensions,
936
+ MARKDOWN_FORMAT,
937
+ RENDERER_VERSION,
938
+ MarkdownCore,
939
+ MARKDOWN_FIXTURES
940
+ };