@docfuse/plugins 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -0
  3. package/README.zh-CN.md +52 -0
  4. package/dist/client/kroki.js +221 -0
  5. package/dist/client/mermaid.js +366 -0
  6. package/dist/client/plantuml.js +221 -0
  7. package/dist/diagram.css +195 -0
  8. package/dist/external-links.d.ts +10 -0
  9. package/dist/external-links.js +49 -0
  10. package/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  11. package/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  12. package/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  13. package/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  14. package/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  15. package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  16. package/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  17. package/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  18. package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  19. package/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  20. package/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  21. package/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  22. package/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  23. package/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  24. package/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  25. package/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  26. package/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  27. package/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  28. package/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  29. package/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  30. package/dist/index.d.ts +9 -0
  31. package/dist/index.js +757 -0
  32. package/dist/kroki.d.ts +12 -0
  33. package/dist/kroki.js +293 -0
  34. package/dist/link-card.d.ts +9 -0
  35. package/dist/link-card.js +87 -0
  36. package/dist/math.css +3 -0
  37. package/dist/math.d.ts +19 -0
  38. package/dist/math.js +140 -0
  39. package/dist/mermaid.d.ts +10 -0
  40. package/dist/mermaid.js +290 -0
  41. package/dist/pagefind.d.ts +66 -0
  42. package/dist/pagefind.js +84 -0
  43. package/dist/plantuml.d.ts +10 -0
  44. package/dist/plantuml.js +297 -0
  45. package/dist/reading-time.d.ts +20 -0
  46. package/dist/reading-time.js +90 -0
  47. package/package.json +122 -0
@@ -0,0 +1,12 @@
1
+ import { MarkdownPlugin } from '@docfuse/markdown';
2
+
3
+ interface KrokiOptions {
4
+ server?: string;
5
+ /** Map Markdown fence labels to Kroki diagram types. */
6
+ languages?: Readonly<Record<string, string>>;
7
+ format?: 'svg' | 'png';
8
+ }
9
+ /** Render plugin-owned diagram fences through a Kroki-compatible server. */
10
+ declare function kroki(options?: KrokiOptions): MarkdownPlugin;
11
+
12
+ export { type KrokiOptions, kroki };
package/dist/kroki.js ADDED
@@ -0,0 +1,293 @@
1
+ // src/kroki/index.ts
2
+ import { defineMarkdownPlugin } from "@docfuse/markdown";
3
+ import { strToU8, zlibSync } from "fflate";
4
+
5
+ // src/shared/diagram.ts
6
+ import { visit } from "unist-util-visit";
7
+ function displayKind(kind) {
8
+ if (kind === "plantuml") return "PlantUML";
9
+ return kind.charAt(0).toUpperCase() + kind.slice(1);
10
+ }
11
+ var DIAGRAM_LABELS = {
12
+ en: {
13
+ copy: "Copy source",
14
+ source: "Show source",
15
+ preview: "Show preview",
16
+ expand: "Expand diagram",
17
+ close: "Close expanded diagram",
18
+ controls: "Diagram zoom controls",
19
+ zoomOut: "Zoom out",
20
+ zoomReset: "Reset zoom",
21
+ zoomIn: "Zoom in",
22
+ imageAlt: (kind) => `${displayKind(kind)} diagram`,
23
+ loadingPreview: "Diagram preview loads in the browser."
24
+ },
25
+ zh: {
26
+ copy: "\u590D\u5236\u56FE\u8868\u6E90\u7801",
27
+ source: "\u663E\u793A\u56FE\u8868\u6E90\u7801",
28
+ preview: "\u663E\u793A\u56FE\u8868\u9884\u89C8",
29
+ expand: "\u653E\u5927\u56FE\u8868",
30
+ close: "\u5173\u95ED\u56FE\u8868\u9884\u89C8",
31
+ controls: "\u56FE\u8868\u7F29\u653E\u63A7\u4EF6",
32
+ zoomOut: "\u7F29\u5C0F\u56FE\u8868",
33
+ zoomReset: "\u91CD\u7F6E\u56FE\u8868\u7F29\u653E",
34
+ zoomIn: "\u653E\u5927\u56FE\u8868",
35
+ imageAlt: (kind) => `${displayKind(kind)} \u56FE\u8868`,
36
+ loadingPreview: "\u56FE\u8868\u9884\u89C8\u5C06\u5728\u6D4F\u89C8\u5668\u4E2D\u52A0\u8F7D\u3002"
37
+ }
38
+ };
39
+ function labelsFromFile(file) {
40
+ if (!file || typeof file !== "object" || !("data" in file)) return DIAGRAM_LABELS.en;
41
+ const data = file.data;
42
+ if (!data || typeof data !== "object" || !("docfuseLocale" in data)) return DIAGRAM_LABELS.en;
43
+ const locale = typeof data.docfuseLocale === "string" ? data.docfuseLocale.toLowerCase() : "";
44
+ return locale === "zh" || locale.startsWith("zh-") ? DIAGRAM_LABELS.zh : DIAGRAM_LABELS.en;
45
+ }
46
+ function languageOf(node) {
47
+ const code = node.children.find(
48
+ (child) => child.type === "element" && child.tagName === "code"
49
+ );
50
+ if (!code) return void 0;
51
+ const classes = Array.isArray(code.properties.className) ? code.properties.className : [];
52
+ const language = classes.map(String).find((className) => className.startsWith("language-"))?.slice("language-".length).toLowerCase();
53
+ const source = code.children.filter((child) => child.type === "text").map((child) => child.value).join("");
54
+ return language ? { language, source } : void 0;
55
+ }
56
+ function action(name, label, properties = {}) {
57
+ return {
58
+ type: "element",
59
+ tagName: "button",
60
+ properties: { type: "button", dataDfDiagramAction: name, ariaLabel: label, ...properties },
61
+ children: [{ type: "text", value: label }]
62
+ };
63
+ }
64
+ function zoomControl(name, label) {
65
+ return {
66
+ type: "element",
67
+ tagName: "button",
68
+ properties: { type: "button", dataDfDiagramAction: name, ariaLabel: label, title: label },
69
+ children: [{ type: "text", value: label }]
70
+ };
71
+ }
72
+ function diagramFence(options) {
73
+ return () => (tree, file) => {
74
+ const labels = labelsFromFile(file);
75
+ visit(tree, "element", (node, index, parent) => {
76
+ if (!parent || index === void 0 || node.tagName !== "pre") return;
77
+ const fence = languageOf(node);
78
+ if (!fence || !options.languages.has(fence.language)) return;
79
+ const imageUrl = options.imageUrl?.(fence.source, fence.language);
80
+ const hasVisualPreview = Boolean(imageUrl || options.kind === "mermaid");
81
+ const preview = imageUrl ? {
82
+ type: "element",
83
+ tagName: "img",
84
+ properties: {
85
+ className: ["df-diagram-img"],
86
+ src: imageUrl,
87
+ alt: labels.imageAlt(options.kind),
88
+ loading: "lazy"
89
+ },
90
+ children: []
91
+ } : {
92
+ type: "element",
93
+ tagName: "div",
94
+ properties: { className: ["df-diagram-placeholder"] },
95
+ children: [{ type: "text", value: labels.loadingPreview }]
96
+ };
97
+ parent.children[index] = {
98
+ type: "element",
99
+ tagName: "figure",
100
+ properties: {
101
+ className: ["df-diagram-window"],
102
+ dataDfPluginDiagram: options.kind,
103
+ dataDfSource: fence.source,
104
+ ...options.moduleUrl ? { dataDfModuleUrl: options.moduleUrl } : {}
105
+ },
106
+ children: [
107
+ {
108
+ type: "element",
109
+ tagName: "figcaption",
110
+ properties: { className: ["df-diagram-toolbar"] },
111
+ children: [
112
+ {
113
+ type: "element",
114
+ tagName: "span",
115
+ properties: { className: ["df-diagram-title"] },
116
+ children: [{ type: "text", value: options.filename(fence.language) }]
117
+ },
118
+ {
119
+ type: "element",
120
+ tagName: "span",
121
+ properties: { className: ["df-diagram-actions"] },
122
+ children: [
123
+ action("copy", labels.copy),
124
+ action("source", labels.source, { dataDfDiagramPreviewLabel: labels.preview }),
125
+ action("expand", labels.expand, { dataDfDiagramCloseLabel: labels.close })
126
+ ]
127
+ }
128
+ ]
129
+ },
130
+ {
131
+ type: "element",
132
+ tagName: "div",
133
+ properties: { className: ["df-diagram-stage"] },
134
+ children: [
135
+ {
136
+ type: "element",
137
+ tagName: "div",
138
+ properties: { className: ["df-diagram-preview"] },
139
+ children: [preview]
140
+ },
141
+ {
142
+ type: "element",
143
+ tagName: "pre",
144
+ properties: { className: ["df-diagram-source"], hidden: true },
145
+ children: [
146
+ {
147
+ type: "element",
148
+ tagName: "code",
149
+ properties: {},
150
+ children: [{ type: "text", value: fence.source }]
151
+ }
152
+ ]
153
+ },
154
+ ...hasVisualPreview ? [
155
+ {
156
+ type: "element",
157
+ tagName: "div",
158
+ properties: {
159
+ className: ["df-diagram-zoom-controls"],
160
+ role: "group",
161
+ ariaLabel: labels.controls
162
+ },
163
+ children: [
164
+ zoomControl("zoom-out", labels.zoomOut),
165
+ zoomControl("zoom-reset", labels.zoomReset),
166
+ zoomControl("zoom-in", labels.zoomIn)
167
+ ]
168
+ }
169
+ ] : []
170
+ ]
171
+ }
172
+ ]
173
+ };
174
+ });
175
+ };
176
+ }
177
+
178
+ // src/shared/markdownSource.ts
179
+ function stripColumns(value, columns) {
180
+ let index = 0;
181
+ let consumed = 0;
182
+ while (index < value.length && consumed < columns) {
183
+ if (value[index] === " ") consumed += 1;
184
+ else if (value[index] === " ") consumed += 4 - consumed % 4;
185
+ else break;
186
+ index += 1;
187
+ }
188
+ return consumed >= columns ? value.slice(index) : void 0;
189
+ }
190
+ function containerContent(line, state) {
191
+ let value = line;
192
+ while (true) {
193
+ const quote = value.match(/^ {0,3}>[ \t]?/);
194
+ if (!quote) break;
195
+ value = value.slice(quote[0].length);
196
+ }
197
+ const continued = state.listIndent > 0 ? stripColumns(value, state.listIndent) : void 0;
198
+ const content = continued ?? value;
199
+ const item = content.match(/^ {0,3}(?:[-+*]|\d{1,9}[.)])([ \t]+)(.*)$/);
200
+ if (item) {
201
+ const body = item[2] ?? "";
202
+ state.listIndent = (continued === void 0 ? 0 : state.listIndent) + content.length - body.length;
203
+ return body;
204
+ }
205
+ if (continued !== void 0 || value.trim() === "") return content;
206
+ state.listIndent = 0;
207
+ return value;
208
+ }
209
+ function openingFence(line) {
210
+ const match = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
211
+ if (!match?.[1]) return void 0;
212
+ const marker = match[1][0];
213
+ const info = match[2]?.trim() ?? "";
214
+ if (marker === "`" && info.includes("`")) return void 0;
215
+ return {
216
+ marker,
217
+ size: match[1].length,
218
+ language: info.split(/\s+/, 1)[0]?.toLowerCase() ?? ""
219
+ };
220
+ }
221
+ function closesFence(line, fence) {
222
+ const match = line.match(/^ {0,3}(`+|~+)[ \t]*$/);
223
+ return Boolean(match?.[1]?.[0] === fence.marker && match[1].length >= fence.size);
224
+ }
225
+ function hasMarkdownFenceLanguage(source, languages) {
226
+ let open;
227
+ const container = { listIndent: 0 };
228
+ for (const line of source.split(/\r?\n/)) {
229
+ const content = containerContent(line, container);
230
+ if (open) {
231
+ if (closesFence(content, open)) open = void 0;
232
+ continue;
233
+ }
234
+ const fence = openingFence(content);
235
+ if (!fence) continue;
236
+ if (languages.has(fence.language)) return true;
237
+ open = fence;
238
+ }
239
+ return false;
240
+ }
241
+
242
+ // src/kroki/index.ts
243
+ var PLUGIN_VERSION = "3";
244
+ var DEFAULT_SERVER = "https://kroki.io";
245
+ var DEFAULT_LANGUAGES = {
246
+ graphviz: "graphviz",
247
+ dot: "graphviz",
248
+ gv: "graphviz",
249
+ d2: "d2"
250
+ };
251
+ function encodeKroki(source) {
252
+ let binary = "";
253
+ for (const byte of zlibSync(strToU8(source), { level: 9 })) binary += String.fromCharCode(byte);
254
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
255
+ }
256
+ function krokiUrl(server, type, format, source) {
257
+ return `${server}/${encodeURIComponent(type)}/${format}/${encodeKroki(source)}`;
258
+ }
259
+ function kroki(options = {}) {
260
+ const server = options.server?.replace(/\/+$/, "") || DEFAULT_SERVER;
261
+ const languages = { ...DEFAULT_LANGUAGES, ...options.languages };
262
+ const format = options.format === "png" ? "png" : "svg";
263
+ const languageMap = Object.fromEntries(
264
+ Object.entries(languages).map(([language, type]) => [language.trim().toLowerCase(), type.trim().toLowerCase()]).filter(([language, type]) => language && type)
265
+ );
266
+ return defineMarkdownPlugin({
267
+ name: "kroki",
268
+ version: PLUGIN_VERSION,
269
+ cacheKey: { server, languages: languageMap, format },
270
+ browserCompiler: {
271
+ module: "@docfuse/plugins/kroki",
272
+ exportName: "kroki",
273
+ options: { server, languages: languageMap, format }
274
+ },
275
+ fenceLanguages: Object.keys(languageMap),
276
+ appliesTo: ({ source }) => hasMarkdownFenceLanguage(source, new Set(Object.keys(languageMap))),
277
+ assets: {
278
+ clients: [{ id: "kroki", module: "@docfuse/plugins/client/kroki" }],
279
+ styles: [{ id: "diagrams", module: "@docfuse/plugins/diagram.css" }]
280
+ },
281
+ rehypePlugins: [
282
+ diagramFence({
283
+ languages: new Set(Object.keys(languageMap)),
284
+ kind: "kroki",
285
+ filename: (language) => `diagram.${languageMap[language] ?? language}`,
286
+ imageUrl: (source, language) => krokiUrl(server, languageMap[language] ?? language, format, source)
287
+ })
288
+ ]
289
+ });
290
+ }
291
+ export {
292
+ kroki
293
+ };
@@ -0,0 +1,9 @@
1
+ import { MarkdownPlugin } from '@docfuse/markdown';
2
+
3
+ interface LinkCardOptions {
4
+ internalHosts?: readonly string[];
5
+ includeRelative?: boolean;
6
+ }
7
+ declare function linkCard(options?: LinkCardOptions): MarkdownPlugin;
8
+
9
+ export { type LinkCardOptions, linkCard };
@@ -0,0 +1,87 @@
1
+ // src/link-card/index.ts
2
+ import { defineMarkdownPlugin } from "@docfuse/markdown";
3
+ import { SKIP, visit } from "unist-util-visit";
4
+
5
+ // src/shared/hast.ts
6
+ function element(tagName, properties = {}, children = []) {
7
+ return { type: "element", tagName, properties, children };
8
+ }
9
+
10
+ // src/shared/urls.ts
11
+ function hostnameOf(href) {
12
+ try {
13
+ return new URL(href).hostname.toLowerCase();
14
+ } catch {
15
+ return void 0;
16
+ }
17
+ }
18
+ function isInternalHost(host, internalHosts) {
19
+ return internalHosts.some((internal) => host === internal || host.endsWith(`.${internal}`));
20
+ }
21
+
22
+ // src/link-card/index.ts
23
+ var PLUGIN_VERSION = "1";
24
+ function isExternalHttpLink(href, internalHosts, includeRelative) {
25
+ if (!href) return false;
26
+ if (href.startsWith("/") || href.startsWith("#") || href.startsWith("mailto:"))
27
+ return includeRelative && href.startsWith("/");
28
+ if (!/^https?:\/\//i.test(href)) return false;
29
+ const host = hostnameOf(href);
30
+ return Boolean(host && !isInternalHost(host, internalHosts));
31
+ }
32
+ function textOf(node) {
33
+ if (node.type === "text") return node.value;
34
+ if ("children" in node) return node.children.map((child) => textOf(child)).join("");
35
+ return "";
36
+ }
37
+ function displayHost(href) {
38
+ try {
39
+ const url = new URL(href);
40
+ return url.hostname + (url.pathname === "/" ? "" : url.pathname);
41
+ } catch {
42
+ return href;
43
+ }
44
+ }
45
+ function linkCard(options = {}) {
46
+ const internalHosts = (options.internalHosts ?? []).map((host) => host.toLowerCase());
47
+ const includeRelative = options.includeRelative === true;
48
+ return defineMarkdownPlugin({
49
+ name: "link-card",
50
+ version: PLUGIN_VERSION,
51
+ cacheKey: { internalHosts, includeRelative },
52
+ browserCompiler: {
53
+ module: "@docfuse/plugins/link-card",
54
+ exportName: "linkCard",
55
+ options: { internalHosts, includeRelative }
56
+ },
57
+ rehypePlugins: [
58
+ () => (tree) => {
59
+ visit(tree, "element", (node, index, parent) => {
60
+ if (node.tagName !== "p" || !parent || index === void 0) return;
61
+ const meaningful = node.children.filter(
62
+ (child) => child.type !== "text" || child.value.trim() !== ""
63
+ );
64
+ const onlyChild = meaningful[0];
65
+ if (meaningful.length !== 1 || onlyChild?.type !== "element" || onlyChild.tagName !== "a") return;
66
+ const href = String(onlyChild.properties.href ?? "");
67
+ if (!isExternalHttpLink(href, internalHosts, includeRelative)) return;
68
+ if (onlyChild.properties.dataDfElement === "file-link") return;
69
+ const title = textOf(onlyChild).trim() || displayHost(href);
70
+ const meta = displayHost(href);
71
+ parent.children[index] = element(
72
+ "a",
73
+ { ...onlyChild.properties, className: ["df-link-card"], href, dataDfComponent: "link-card" },
74
+ [
75
+ element("strong", {}, [{ type: "text", value: title }]),
76
+ ...meta && meta !== title ? [element("span", {}, [{ type: "text", value: meta }])] : []
77
+ ]
78
+ );
79
+ return [SKIP, index];
80
+ });
81
+ }
82
+ ]
83
+ });
84
+ }
85
+ export {
86
+ linkCard
87
+ };
package/dist/math.css ADDED
@@ -0,0 +1,3 @@
1
+ /* KaTeX */
2
+ @font-face{font-display:block;font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url(fonts/KaTeX_AMS-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Fraktur-Bold.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Fraktur-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Main-Bold.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:700;src:url(fonts/KaTeX_Main-BoldItalic.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url(fonts/KaTeX_Main-Italic.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Main-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:700;src:url(fonts/KaTeX_Math-BoldItalic.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url(fonts/KaTeX_Math-Italic.woff2) format("woff2")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:normal;font-weight:700;src:url(fonts/KaTeX_SansSerif-Bold.woff2) format("woff2")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:italic;font-weight:400;src:url(fonts/KaTeX_SansSerif-Italic.woff2) format("woff2")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:normal;font-weight:400;src:url(fonts/KaTeX_SansSerif-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Script;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Script-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size1-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size2-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size3-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size4-Regular.woff2) format("woff2")}@font-face{font-display:block;font-family:KaTeX_Typewriter;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Typewriter-Regular.woff2) format("woff2")}.katex{font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;position:relative;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.17.0"}.katex .katex-mathml{border:0;-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:-webkit-min-content;width:-moz-min-content;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathboldfrak,.katex .textboldfrak{font-family:KaTeX_Fraktur;font-weight:700}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .mathsfit,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .hbox{width:100%}.katex .hbox,.katex .thinbox{display:inline-flex;flex-direction:row}.katex .thinbox{max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .smash{display:inline;line-height:0}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{border:0 solid;display:inline-block;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.root{margin-left:.2777777778em;margin-right:-.5555555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.1666666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.6666666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.4566666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.1466666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.7142857143em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.8571428571em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.1428571429em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.2857142857em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.4285714286em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.7142857143em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.0571428571em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.4685714286em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.9628571429em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.5542857143em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.7777777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.8888888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.1111111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.3044444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.7644444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.5833333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.7283333333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.0733333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.4861111111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.4402777778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.7277777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.2893518519em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.4050925926em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.462962963em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.5208333333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.2002314815em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.4398148148em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.2410800386em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.2892960463em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.337512054em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.3857280617em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.4339440694em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.4821600771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.5785920926em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.6943105111em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.8331726133em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.1996142719em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.2009646302em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.2411575563em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.2813504823em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.3215434084em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.3617363344em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.4019292605em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.4823151125em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.578778135em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.6945337621em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.8336012862em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex svg{fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}
3
+
package/dist/math.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { MarkdownPlugin } from '@docfuse/markdown';
2
+
3
+ interface MathOptions {
4
+ /** KaTeX should throw instead of rendering unsupported input. */
5
+ throwOnError?: boolean;
6
+ /** Color used by KaTeX when `throwOnError` is false. */
7
+ errorColor?: string;
8
+ /** Trust KaTeX commands that can emit URLs or HTML. Disabled by default. */
9
+ trust?: boolean;
10
+ /** KaTeX strictness policy. */
11
+ strict?: boolean | 'ignore' | 'warn' | 'error';
12
+ /** Macros passed to KaTeX. */
13
+ macros?: Readonly<Record<string, string>>;
14
+ }
15
+ /** Conservative opt-in detector; escaped dollar signs and code do not activate KaTeX. */
16
+ declare function hasMathSyntax(source: string): boolean;
17
+ declare function math(options?: MathOptions): MarkdownPlugin;
18
+
19
+ export { type MathOptions, hasMathSyntax, math };
package/dist/math.js ADDED
@@ -0,0 +1,140 @@
1
+ // src/math/index.ts
2
+ import { defineMarkdownPlugin } from "@docfuse/markdown";
3
+ import rehypeKatex from "rehype-katex";
4
+ import remarkMath from "remark-math";
5
+
6
+ // src/shared/markdownSource.ts
7
+ function stripColumns(value, columns) {
8
+ let index = 0;
9
+ let consumed = 0;
10
+ while (index < value.length && consumed < columns) {
11
+ if (value[index] === " ") consumed += 1;
12
+ else if (value[index] === " ") consumed += 4 - consumed % 4;
13
+ else break;
14
+ index += 1;
15
+ }
16
+ return consumed >= columns ? value.slice(index) : void 0;
17
+ }
18
+ function containerContent(line, state) {
19
+ let value = line;
20
+ while (true) {
21
+ const quote = value.match(/^ {0,3}>[ \t]?/);
22
+ if (!quote) break;
23
+ value = value.slice(quote[0].length);
24
+ }
25
+ const continued = state.listIndent > 0 ? stripColumns(value, state.listIndent) : void 0;
26
+ const content = continued ?? value;
27
+ const item = content.match(/^ {0,3}(?:[-+*]|\d{1,9}[.)])([ \t]+)(.*)$/);
28
+ if (item) {
29
+ const body = item[2] ?? "";
30
+ state.listIndent = (continued === void 0 ? 0 : state.listIndent) + content.length - body.length;
31
+ return body;
32
+ }
33
+ if (continued !== void 0 || value.trim() === "") return content;
34
+ state.listIndent = 0;
35
+ return value;
36
+ }
37
+ function openingFence(line) {
38
+ const match = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
39
+ if (!match?.[1]) return void 0;
40
+ const marker = match[1][0];
41
+ const info = match[2]?.trim() ?? "";
42
+ if (marker === "`" && info.includes("`")) return void 0;
43
+ return {
44
+ marker,
45
+ size: match[1].length,
46
+ language: info.split(/\s+/, 1)[0]?.toLowerCase() ?? ""
47
+ };
48
+ }
49
+ function closesFence(line, fence) {
50
+ const match = line.match(/^ {0,3}(`+|~+)[ \t]*$/);
51
+ return Boolean(match?.[1]?.[0] === fence.marker && match[1].length >= fence.size);
52
+ }
53
+ function hasMarkdownFenceLanguage(source, languages) {
54
+ let open;
55
+ const container = { listIndent: 0 };
56
+ for (const line of source.split(/\r?\n/)) {
57
+ const content = containerContent(line, container);
58
+ if (open) {
59
+ if (closesFence(content, open)) open = void 0;
60
+ continue;
61
+ }
62
+ const fence = openingFence(content);
63
+ if (!fence) continue;
64
+ if (languages.has(fence.language)) return true;
65
+ open = fence;
66
+ }
67
+ return false;
68
+ }
69
+ function removeInlineCode(line) {
70
+ let result = "";
71
+ let index = 0;
72
+ while (index < line.length) {
73
+ if (line[index] !== "`") {
74
+ result += line[index];
75
+ index += 1;
76
+ continue;
77
+ }
78
+ let endOfOpening = index + 1;
79
+ while (line[endOfOpening] === "`") endOfOpening += 1;
80
+ const delimiter = line.slice(index, endOfOpening);
81
+ const closing = line.indexOf(delimiter, endOfOpening);
82
+ if (closing === -1) {
83
+ result += delimiter;
84
+ index = endOfOpening;
85
+ continue;
86
+ }
87
+ result += " ".repeat(closing + delimiter.length - index);
88
+ index = closing + delimiter.length;
89
+ }
90
+ return result;
91
+ }
92
+ function markdownProse(source) {
93
+ let open;
94
+ const container = { listIndent: 0 };
95
+ return source.split(/\r?\n/).map((line) => {
96
+ const content = containerContent(line, container);
97
+ if (open) {
98
+ if (closesFence(content, open)) open = void 0;
99
+ return "";
100
+ }
101
+ const fence = openingFence(content);
102
+ if (fence) {
103
+ open = fence;
104
+ return "";
105
+ }
106
+ if (/^(?: {4}|\t)/.test(content)) return "";
107
+ return removeInlineCode(content);
108
+ }).join("\n");
109
+ }
110
+
111
+ // src/math/index.ts
112
+ var PLUGIN_VERSION = "3";
113
+ function hasMathSyntax(source) {
114
+ const prose = markdownProse(source);
115
+ return hasMarkdownFenceLanguage(source, /* @__PURE__ */ new Set(["math"])) || /(^|[^\\])\$\$[\s\S]+?\$\$/.test(prose) || /(^|[^\\$])\$(?!\s)(?:\\.|[^$\n])+?(?<!\s)\$/.test(prose);
116
+ }
117
+ function math(options = {}) {
118
+ const resolved = {
119
+ throwOnError: options.throwOnError ?? false,
120
+ errorColor: options.errorColor ?? "#b42318",
121
+ trust: options.trust ?? false,
122
+ strict: options.strict ?? "warn",
123
+ macros: { ...options.macros ?? {} }
124
+ };
125
+ return defineMarkdownPlugin({
126
+ name: "math",
127
+ version: PLUGIN_VERSION,
128
+ cacheKey: resolved,
129
+ browserCompiler: { module: "@docfuse/plugins/math", exportName: "math", options: resolved },
130
+ appliesTo: ({ source }) => hasMathSyntax(source),
131
+ fenceLanguages: ["math"],
132
+ assets: { math: true },
133
+ remarkPlugins: [remarkMath],
134
+ rehypePlugins: [[rehypeKatex, resolved]]
135
+ });
136
+ }
137
+ export {
138
+ hasMathSyntax,
139
+ math
140
+ };
@@ -0,0 +1,10 @@
1
+ import { MarkdownPlugin } from '@docfuse/markdown';
2
+
3
+ interface MermaidOptions {
4
+ /** Optional browser ESM module. The bundled Mermaid runtime is used by default. */
5
+ moduleUrl?: string;
6
+ }
7
+ /** Enable Mermaid fenced code blocks as an opt-in official plugin. */
8
+ declare function mermaid(options?: MermaidOptions): MarkdownPlugin;
9
+
10
+ export { type MermaidOptions, mermaid };