@ai-matrx/rich-content 0.0.0 → 0.2.2
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/CHANGELOG.md +72 -0
- package/LICENSE +1 -1
- package/README.md +58 -3
- package/dist/display/blocks/csv/CsvBlock.d.ts +10 -0
- package/dist/display/blocks/csv/CsvBlock.js +245 -0
- package/dist/display/blocks/table/parseMarkdownTable.d.ts +20 -0
- package/dist/display/blocks/table/parseMarkdownTable.js +35 -0
- package/dist/display/chat-markdown/citations/remarkMatrxCite.d.ts +33 -0
- package/dist/display/chat-markdown/citations/remarkMatrxCite.js +71 -0
- package/dist/display/chat-markdown/matrx-variables/remarkMatrxVariable.d.ts +29 -0
- package/dist/display/chat-markdown/matrx-variables/remarkMatrxVariable.js +71 -0
- package/dist/display/chat-markdown/page-break/remarkMatrxPageBreak.d.ts +55 -0
- package/dist/display/chat-markdown/page-break/remarkMatrxPageBreak.js +108 -0
- package/dist/display/chat-markdown/rehypeSafeRawHtml.d.ts +59 -0
- package/dist/display/chat-markdown/rehypeSafeRawHtml.js +140 -0
- package/dist/display/markdown-classification/processors/bock-processors/parse-markdown-table.d.ts +14 -0
- package/dist/display/markdown-classification/processors/bock-processors/parse-markdown-table.js +171 -0
- package/dist/display/markdown-classification/processors/types.d.ts +120 -0
- package/dist/display/markdown-classification/processors/types.js +10 -0
- package/dist/display/markdown-classification/processors/utils/client-blocks.d.ts +169 -0
- package/dist/display/markdown-classification/processors/utils/client-blocks.js +0 -0
- package/dist/display/markdown-classification/processors/utils/content-splitter-core.d.ts +223 -0
- package/dist/display/markdown-classification/processors/utils/content-splitter-core.js +1791 -0
- package/dist/display/markdown-classification/processors/utils/content-splitter-v2.d.ts +15 -0
- package/dist/display/markdown-classification/processors/utils/content-splitter-v2.js +19 -0
- package/dist/display/markdown-classification/processors/utils/expand-text-blocks.d.ts +9 -0
- package/dist/display/markdown-classification/processors/utils/expand-text-blocks.js +36 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-lines.d.ts +5 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-lines.js +40 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-vector-inputs.d.ts +16 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-vector-inputs.js +385 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-vectors.d.ts +43 -0
- package/dist/display/markdown-classification/processors/utils/gfm-table-vectors.js +33 -0
- package/dist/display/markdown-classification/processors/utils/table-data-parser.d.ts +9 -0
- package/dist/display/markdown-classification/processors/utils/table-data-parser.js +30 -0
- package/dist/display/markdown-classification/processors/utils/thinking-parser.d.ts +7 -0
- package/dist/display/markdown-classification/processors/utils/thinking-parser.js +70 -0
- package/dist/display/render-block.d.ts +23 -0
- package/dist/display/render-block.js +0 -0
- package/dist/display/themes.d.ts +1023 -0
- package/dist/display/themes.js +1105 -0
- package/dist/display/types.d.ts +32 -0
- package/dist/display/types.js +0 -0
- package/dist/host/ContentIrHostBoundary.d.ts +8 -0
- package/dist/host/ContentIrHostBoundary.js +15 -0
- package/dist/host/ErrorActions.d.ts +4 -0
- package/dist/host/ErrorActions.js +11 -0
- package/dist/host/NestedContent.d.ts +3 -0
- package/dist/host/NestedContent.js +12 -0
- package/dist/host/ResourcePeek.d.ts +6 -0
- package/dist/host/ResourcePeek.js +14 -0
- package/dist/host/component-registry.d.ts +2 -0
- package/dist/host/component-registry.js +25 -0
- package/dist/host/diagnostics.d.ts +2 -0
- package/dist/host/diagnostics.js +15 -0
- package/dist/host/index.d.ts +3 -0
- package/dist/host/index.js +18 -0
- package/dist/host/kind-incident.d.ts +3 -0
- package/dist/host/kind-incident.js +12 -0
- package/dist/host/kind-registry.d.ts +2 -0
- package/dist/host/kind-registry.js +35 -0
- package/dist/host/people.d.ts +3 -0
- package/dist/host/people.js +12 -0
- package/dist/host/registry.d.ts +27 -0
- package/dist/host/registry.js +55 -0
- package/dist/host/splitter-envelopes.d.ts +2 -0
- package/dist/host/splitter-envelopes.js +7 -0
- package/dist/host/tables.d.ts +6 -0
- package/dist/host/tables.js +8 -0
- package/dist/host/toast.d.ts +2 -0
- package/dist/host/toast.js +57 -0
- package/dist/host/types.d.ts +157 -0
- package/dist/host/types.js +0 -0
- package/dist/host/wikilinks.d.ts +15 -0
- package/dist/host/wikilinks.js +23 -0
- package/dist/kinds/host/route-env.d.ts +33 -0
- package/dist/kinds/host/route-env.js +16 -0
- package/dist/kinds/react/KindEscapedNotice.d.ts +14 -0
- package/dist/kinds/react/KindEscapedNotice.js +72 -0
- package/dist/kinds/react/ProvisionalKindBoundary.d.ts +19 -0
- package/dist/kinds/react/ProvisionalKindBoundary.js +17 -0
- package/dist/kinds/react/ensure-kind-renderable.d.ts +14 -0
- package/dist/kinds/react/ensure-kind-renderable.js +45 -0
- package/dist/kinds/react/kind-problems.d.ts +62 -0
- package/dist/kinds/react/kind-problems.js +134 -0
- package/dist/kinds/react/kind-route.d.ts +23 -0
- package/dist/kinds/react/kind-route.js +24 -0
- package/dist/kinds/react/loading/infer-loading-slug.d.ts +58 -0
- package/dist/kinds/react/loading/infer-loading-slug.js +100 -0
- package/dist/kinds/react/loading/kind-loading-components.d.ts +48 -0
- package/dist/kinds/react/loading/kind-loading-components.js +447 -0
- package/dist/kinds/react/loading/kind-loading-registry.d.ts +21 -0
- package/dist/kinds/react/loading/kind-loading-registry.js +62 -0
- package/dist/kinds/react/loading/kind-loading-slugs.d.ts +18 -0
- package/dist/kinds/react/loading/kind-loading-slugs.js +34 -0
- package/dist/kinds/react/loading/kind-loading.types.d.ts +79 -0
- package/dist/kinds/react/loading/kind-loading.types.js +31 -0
- package/dist/kinds/react/loading/resolve-loading-slug.d.ts +29 -0
- package/dist/kinds/react/loading/resolve-loading-slug.js +51 -0
- package/dist/kinds/react/partial-kind-route.d.ts +32 -0
- package/dist/kinds/react/partial-kind-route.js +27 -0
- package/dist/kinds/react/registry-versioned.d.ts +54 -0
- package/dist/kinds/react/registry-versioned.js +18 -0
- package/dist/kinds/react/route-at-version.d.ts +38 -0
- package/dist/kinds/react/route-at-version.js +78 -0
- package/dist/kinds/react/slot/KindSlot.d.ts +87 -0
- package/dist/kinds/react/slot/KindSlot.js +65 -0
- package/dist/kinds/react/use-registry-repaint.d.ts +6 -0
- package/dist/kinds/react/use-registry-repaint.js +36 -0
- package/dist/kinds/react/useIrNode.d.ts +9 -0
- package/dist/kinds/react/useIrNode.js +46 -0
- package/dist/kinds/react/useLiveJsonRegion.d.ts +15 -0
- package/dist/kinds/react/useLiveJsonRegion.js +84 -0
- package/dist/kinds/redux/render-block-envelope.d.ts +14 -0
- package/dist/kinds/redux/render-block-envelope.js +26 -0
- package/dist/kinds/registry/kind-correctors.d.ts +63 -0
- package/dist/kinds/registry/kind-correctors.js +94 -0
- package/dist/kinds/registry/legacy-quiz-envelope.d.ts +1 -0
- package/dist/kinds/registry/legacy-quiz-envelope.js +1 -0
- package/dist/kinds/registry/region-envelope-memo.d.ts +45 -0
- package/dist/kinds/registry/region-envelope-memo.js +94 -0
- package/dist/kinds/registry/registry-debug.d.ts +38 -0
- package/dist/kinds/registry/registry-debug.js +39 -0
- package/dist/markdown-core/MarkdownCore.d.ts +6 -0
- package/dist/markdown-core/MarkdownCore.js +32 -0
- package/dist/markdown-core/MarkdownCoreImpl.d.ts +3 -0
- package/dist/markdown-core/MarkdownCoreImpl.js +27 -0
- package/dist/markdown-core/MarkdownCoreServer.d.ts +4 -0
- package/dist/markdown-core/MarkdownCoreServer.js +26 -0
- package/dist/markdown-core/heading-anchors-context.d.ts +2 -0
- package/dist/markdown-core/heading-anchors-context.js +11 -0
- package/dist/markdown-core/heading-anchors-props.d.ts +2 -0
- package/dist/markdown-core/heading-anchors-props.js +6 -0
- package/dist/markdown-core/markdown-core-html.d.ts +3 -0
- package/dist/markdown-core/markdown-core-html.js +33 -0
- package/dist/markdown-core/markdown-core-presets.d.ts +22 -0
- package/dist/markdown-core/markdown-core-presets.js +118 -0
- package/dist/markdown-core/markdown-core-types.d.ts +43 -0
- package/dist/markdown-core/markdown-core-types.js +0 -0
- package/dist/markdown-core/math/vendor/micromark-math-math-flow.d.ts +15 -0
- package/dist/markdown-core/math/vendor/micromark-math-math-flow.js +143 -0
- package/dist/markdown-core/math/vendor/micromark-math-math-text.d.ts +24 -0
- package/dist/markdown-core/math/vendor/micromark-math-math-text.js +127 -0
- package/dist/markdown-core/math/vendor/micromark-math-syntax.d.ts +30 -0
- package/dist/markdown-core/math/vendor/micromark-math-syntax.js +15 -0
- package/dist/markdown-core/math/vendor/rehype-katex.d.ts +15 -0
- package/dist/markdown-core/math/vendor/rehype-katex.js +83 -0
- package/dist/markdown-core/math/vendor/remark-math.d.ts +9 -0
- package/dist/markdown-core/math/vendor/remark-math.js +20 -0
- package/dist/markdown-core/math-normalizer.d.ts +57 -0
- package/dist/markdown-core/math-normalizer.js +315 -0
- package/dist/markdown-core/plain-title.d.ts +2 -0
- package/dist/markdown-core/plain-title.js +1 -0
- package/dist/markdown-core/stream-heal.d.ts +2 -0
- package/dist/markdown-core/stream-heal.js +184 -0
- package/dist/markdown-core/streaming-context.d.ts +2 -0
- package/dist/markdown-core/streaming-context.js +11 -0
- package/dist/markdown-core/syntax/callout-types.d.ts +9 -0
- package/dist/markdown-core/syntax/callout-types.js +101 -0
- package/dist/markdown-core/syntax/containers.d.ts +17 -0
- package/dist/markdown-core/syntax/containers.js +353 -0
- package/dist/markdown-core/syntax/document-numbering.d.ts +52 -0
- package/dist/markdown-core/syntax/document-numbering.js +184 -0
- package/dist/markdown-core/syntax/elements/CalloutIcon.d.ts +3 -0
- package/dist/markdown-core/syntax/elements/CalloutIcon.js +41 -0
- package/dist/markdown-core/syntax/elements/CrossRef.d.ts +12 -0
- package/dist/markdown-core/syntax/elements/CrossRef.js +57 -0
- package/dist/markdown-core/syntax/elements/CsvFence.d.ts +4 -0
- package/dist/markdown-core/syntax/elements/CsvFence.js +18 -0
- package/dist/markdown-core/syntax/elements/DetailsElements.d.ts +12 -0
- package/dist/markdown-core/syntax/elements/DetailsElements.js +38 -0
- package/dist/markdown-core/syntax/elements/DocumentNumbering.d.ts +20 -0
- package/dist/markdown-core/syntax/elements/DocumentNumbering.js +37 -0
- package/dist/markdown-core/syntax/elements/DocumentPropertiesPanel.d.ts +4 -0
- package/dist/markdown-core/syntax/elements/DocumentPropertiesPanel.js +46 -0
- package/dist/markdown-core/syntax/elements/InDocAnchor.d.ts +11 -0
- package/dist/markdown-core/syntax/elements/InDocAnchor.js +87 -0
- package/dist/markdown-core/syntax/elements/MarkdownSourceEdit.d.ts +24 -0
- package/dist/markdown-core/syntax/elements/MarkdownSourceEdit.js +28 -0
- package/dist/markdown-core/syntax/elements/MatrxTabs.d.ts +10 -0
- package/dist/markdown-core/syntax/elements/MatrxTabs.js +59 -0
- package/dist/markdown-core/syntax/elements/MentionChip.d.ts +7 -0
- package/dist/markdown-core/syntax/elements/MentionChip.js +69 -0
- package/dist/markdown-core/syntax/elements/NestedBody.d.ts +3 -0
- package/dist/markdown-core/syntax/elements/NestedBody.js +13 -0
- package/dist/markdown-core/syntax/elements/TableOfContents.d.ts +5 -0
- package/dist/markdown-core/syntax/elements/TableOfContents.js +44 -0
- package/dist/markdown-core/syntax/elements/TaskCheckbox.d.ts +7 -0
- package/dist/markdown-core/syntax/elements/TaskCheckbox.js +63 -0
- package/dist/markdown-core/syntax/elements/WikiEmbed.d.ts +7 -0
- package/dist/markdown-core/syntax/elements/WikiEmbed.js +68 -0
- package/dist/markdown-core/syntax/elements/WikiLink.d.ts +10 -0
- package/dist/markdown-core/syntax/elements/WikiLink.js +114 -0
- package/dist/markdown-core/syntax/elements/core-syntax-elements.d.ts +22 -0
- package/dist/markdown-core/syntax/elements/core-syntax-elements.js +70 -0
- package/dist/markdown-core/syntax/elements/find-in-document.d.ts +3 -0
- package/dist/markdown-core/syntax/elements/find-in-document.js +20 -0
- package/dist/markdown-core/syntax/elements/wiki-target.d.ts +5 -0
- package/dist/markdown-core/syntax/elements/wiki-target.js +8 -0
- package/dist/markdown-core/syntax/frontmatter.d.ts +26 -0
- package/dist/markdown-core/syntax/frontmatter.js +72 -0
- package/dist/markdown-core/syntax/gfm-cell-pipes.d.ts +11 -0
- package/dist/markdown-core/syntax/gfm-cell-pipes.js +4 -0
- package/dist/markdown-core/syntax/inline-syntax.d.ts +26 -0
- package/dist/markdown-core/syntax/inline-syntax.js +163 -0
- package/dist/markdown-core/syntax/linear-scan.d.ts +46 -0
- package/dist/markdown-core/syntax/linear-scan.js +129 -0
- package/dist/markdown-core/syntax/mdast-helpers.d.ts +48 -0
- package/dist/markdown-core/syntax/mdast-helpers.js +48 -0
- package/dist/markdown-core/syntax/mentions.d.ts +2 -0
- package/dist/markdown-core/syntax/mentions.js +42 -0
- package/dist/markdown-core/syntax/names.d.ts +6 -0
- package/dist/markdown-core/syntax/names.js +18 -0
- package/dist/markdown-core/syntax/prepare-syntax-source.d.ts +1 -0
- package/dist/markdown-core/syntax/prepare-syntax-source.js +78 -0
- package/dist/markdown-core/syntax/rehype-matrx-syntax.d.ts +9 -0
- package/dist/markdown-core/syntax/rehype-matrx-syntax.js +180 -0
- package/dist/markdown-core/syntax/remark-inline-only.d.ts +23 -0
- package/dist/markdown-core/syntax/remark-inline-only.js +25 -0
- package/dist/markdown-core/syntax/remark-matrx-syntax.d.ts +7 -0
- package/dist/markdown-core/syntax/remark-matrx-syntax.js +351 -0
- package/dist/markdown-core/syntax/remark-table-code-pipes.d.ts +7 -0
- package/dist/markdown-core/syntax/remark-table-code-pipes.js +23 -0
- package/dist/markdown-core/syntax/stream-heal-syntax.d.ts +2 -0
- package/dist/markdown-core/syntax/stream-heal-syntax.js +108 -0
- package/dist/markdown-core/syntax/task-source.d.ts +10 -0
- package/dist/markdown-core/syntax/task-source.js +34 -0
- package/dist/markdown-core/syntax/useDocumentProperties.d.ts +3 -0
- package/dist/markdown-core/syntax/useDocumentProperties.js +8 -0
- package/dist/styles.css +0 -0
- package/dist/utils/addressWithoutNavigating.d.ts +68 -0
- package/dist/utils/addressWithoutNavigating.js +60 -0
- package/dist/utils/client-lazy.d.ts +13 -0
- package/dist/utils/client-lazy.js +24 -0
- package/dist/utils/decision-options.d.ts +21 -0
- package/dist/utils/decision-options.js +32 -0
- package/dist/utils/gfm-lexer.d.ts +5 -0
- package/dist/utils/gfm-lexer.js +10 -0
- package/dist/utils/json.d.ts +63 -0
- package/dist/utils/json.js +22 -0
- package/dist/utils/plain-title.d.ts +25 -0
- package/dist/utils/plain-title.js +51 -0
- package/dist/utils/table-source.d.ts +62 -0
- package/dist/utils/table-source.js +191 -0
- package/dist/utils/youtube.d.ts +52 -0
- package/dist/utils/youtube.js +137 -0
- package/package.json +132 -5
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { fromHtmlIsomorphic } from "hast-util-from-html-isomorphic";
|
|
2
|
+
import { toText } from "hast-util-to-text";
|
|
3
|
+
import katex from "katex";
|
|
4
|
+
import { SKIP, visitParents } from "unist-util-visit-parents";
|
|
5
|
+
const emptyOptions = {};
|
|
6
|
+
const emptyClasses = [];
|
|
7
|
+
function rehypeKatex(options) {
|
|
8
|
+
const settings = options || emptyOptions;
|
|
9
|
+
return function(tree, file) {
|
|
10
|
+
visitParents(tree, "element", function(element, parents) {
|
|
11
|
+
const classes = Array.isArray(element.properties.className) ? element.properties.className : emptyClasses;
|
|
12
|
+
const languageMath = classes.includes("language-math");
|
|
13
|
+
const mathDisplay = classes.includes("math-display");
|
|
14
|
+
const mathInline = classes.includes("math-inline");
|
|
15
|
+
let displayMode = mathDisplay;
|
|
16
|
+
if (!languageMath && !mathDisplay && !mathInline) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
let parent = parents[parents.length - 1];
|
|
20
|
+
let scope = element;
|
|
21
|
+
if (element.tagName === "code" && languageMath && parent && parent.type === "element" && parent.tagName === "pre") {
|
|
22
|
+
scope = parent;
|
|
23
|
+
parent = parents[parents.length - 2];
|
|
24
|
+
displayMode = true;
|
|
25
|
+
}
|
|
26
|
+
if (!parent) return;
|
|
27
|
+
const value = toText(scope, { whitespace: "pre" });
|
|
28
|
+
let result;
|
|
29
|
+
try {
|
|
30
|
+
result = katex.renderToString(value, {
|
|
31
|
+
...settings,
|
|
32
|
+
displayMode,
|
|
33
|
+
throwOnError: true
|
|
34
|
+
});
|
|
35
|
+
} catch (error) {
|
|
36
|
+
const cause = (
|
|
37
|
+
/** @type {Error} */
|
|
38
|
+
error
|
|
39
|
+
);
|
|
40
|
+
const ruleId = cause.name.toLowerCase();
|
|
41
|
+
file.message("Could not render math with KaTeX", {
|
|
42
|
+
ancestors: [...parents, element],
|
|
43
|
+
cause,
|
|
44
|
+
place: element.position,
|
|
45
|
+
ruleId,
|
|
46
|
+
source: "rehype-katex"
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
result = katex.renderToString(value, {
|
|
50
|
+
...settings,
|
|
51
|
+
displayMode,
|
|
52
|
+
strict: "ignore",
|
|
53
|
+
throwOnError: false
|
|
54
|
+
});
|
|
55
|
+
} catch {
|
|
56
|
+
result = [
|
|
57
|
+
{
|
|
58
|
+
type: "element",
|
|
59
|
+
tagName: "span",
|
|
60
|
+
properties: {
|
|
61
|
+
className: ["katex-error"],
|
|
62
|
+
style: "color:" + (settings.errorColor || "#cc0000"),
|
|
63
|
+
title: String(error)
|
|
64
|
+
},
|
|
65
|
+
children: [{ type: "text", value }]
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (typeof result === "string") {
|
|
71
|
+
const root = fromHtmlIsomorphic(result, { fragment: true });
|
|
72
|
+
result = /** @type {Array<ElementContent>} */
|
|
73
|
+
root.children;
|
|
74
|
+
}
|
|
75
|
+
const index = parent.children.indexOf(scope);
|
|
76
|
+
parent.children.splice(index, 1, ...result);
|
|
77
|
+
return SKIP;
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
rehypeKatex as default
|
|
83
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { mathFromMarkdown, mathToMarkdown } from "mdast-util-math";
|
|
2
|
+
import { math } from "./micromark-math-syntax.js";
|
|
3
|
+
const emptyOptions = {};
|
|
4
|
+
function remarkMath(options) {
|
|
5
|
+
const self = (
|
|
6
|
+
/** @type {Processor} */
|
|
7
|
+
this
|
|
8
|
+
);
|
|
9
|
+
const settings = options || emptyOptions;
|
|
10
|
+
const data = self.data();
|
|
11
|
+
const micromarkExtensions = data.micromarkExtensions || (data.micromarkExtensions = []);
|
|
12
|
+
const fromMarkdownExtensions = data.fromMarkdownExtensions || (data.fromMarkdownExtensions = []);
|
|
13
|
+
const toMarkdownExtensions = data.toMarkdownExtensions || (data.toMarkdownExtensions = []);
|
|
14
|
+
micromarkExtensions.push(math(settings));
|
|
15
|
+
fromMarkdownExtensions.push(mathFromMarkdown());
|
|
16
|
+
toMarkdownExtensions.push(mathToMarkdown(settings));
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
remarkMath as default
|
|
20
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** remark-math options for EVERY math-capable renderer. */
|
|
2
|
+
export declare const REMARK_MATH_OPTIONS: {
|
|
3
|
+
readonly singleDollarTextMath: false;
|
|
4
|
+
};
|
|
5
|
+
/** rehype-katex options for EVERY math-capable renderer. */
|
|
6
|
+
export declare const REHYPE_KATEX_OPTIONS: {
|
|
7
|
+
readonly strict: "ignore";
|
|
8
|
+
/** No command (`\href`, `\url`, `\includegraphics`, `\htmlClass`…) is trusted. */
|
|
9
|
+
readonly trust: false;
|
|
10
|
+
/** Largest size any user-given length may take, in em (`\rule{1000em}` → 10em). */
|
|
11
|
+
readonly maxSize: 10;
|
|
12
|
+
/** Macro expansions per formula before KaTeX stops (a `\def` loop ends here). */
|
|
13
|
+
readonly maxExpand: 500;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Exactly `text.replace(/OPEN((?:(?!\n[ \t]*\n)[\s\S])*?)CLOSE/g, fn)` for a
|
|
17
|
+
* two-character `open`/`close` (`\[`/`\]`, `\(`/`\)`), in linear time — the
|
|
18
|
+
* regex re-scanned to the next blank line from every unclosed opener (round
|
|
19
|
+
* 11, F1). A span never crosses a blank line (a line of only spaces/tabs).
|
|
20
|
+
*/
|
|
21
|
+
export declare function replaceDelimitedWithinParagraph(text: string, open: string, close: string, fn: (match: string, inner: string, offset: number) => string): string;
|
|
22
|
+
/**
|
|
23
|
+
* THE escaped-bracket rule: a closed `\[ … \]` is display math only when its
|
|
24
|
+
* content is real TeX and the `\[` does not index an identifier. Everything
|
|
25
|
+
* else — citations `\[1\]`, dates, task boxes `- \[x\]`, `arr\[i\]`,
|
|
26
|
+
* `\[bracket\]` — is CommonMark's escaped brackets, literal text
|
|
27
|
+
* (verify-RC-B4 R3-2). The rule's home is `@ai-matrx/content-ir`
|
|
28
|
+
* `isEscapedBracketMath` (aidream 094594d3a1, shared vectors
|
|
29
|
+
* `escaped-bracket-vectors.json`); this is its exact copy until that release
|
|
30
|
+
* is installed here — then import it and delete this.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isEscapedBracketMath(content: string, before: string | undefined): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Normalize every LLM/author math delimiter to the one form remark-math
|
|
35
|
+
* (with `REMARK_MATH_OPTIONS`) parses. Idempotent on already-normalized text.
|
|
36
|
+
*/
|
|
37
|
+
export declare function normalizeMathDelimiters(markdown: string): string;
|
|
38
|
+
/** Markdown source that renders `tex` as one display-math block. */
|
|
39
|
+
export declare function displayMathSource(tex: string): string;
|
|
40
|
+
/** One piece of normalized markdown: prose, code (fence or span), or math. */
|
|
41
|
+
export interface MathSpanPiece {
|
|
42
|
+
kind: "text" | "code" | "math";
|
|
43
|
+
/** The source bytes of this piece (for math, including the `$$` delimiters). */
|
|
44
|
+
text: string;
|
|
45
|
+
/** Math only: the TeX between the delimiters. */
|
|
46
|
+
tex?: string;
|
|
47
|
+
/** Math only: a display block (`$$` on their own lines) vs inline. */
|
|
48
|
+
display?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Split markdown into prose / code / math pieces AFTER normalizing it to the
|
|
52
|
+
* one dialect — the same boundaries every renderer uses, so a consumer that
|
|
53
|
+
* must turn math into something else (a document exporter drawing formulas)
|
|
54
|
+
* never re-derives them. Concatenating every `text` reproduces the normalized
|
|
55
|
+
* source.
|
|
56
|
+
*/
|
|
57
|
+
export declare function splitMathSpans(markdown: string): MathSpanPiece[];
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { fenceLineKinds, findCodeRanges, isSingleDollarMath, singleDollarAfter } from "@ai-matrx/content-ir/source";
|
|
2
|
+
const REMARK_MATH_OPTIONS = { singleDollarTextMath: false };
|
|
3
|
+
const REHYPE_KATEX_OPTIONS = {
|
|
4
|
+
strict: "ignore",
|
|
5
|
+
// SAFETY LIMITS — math is rendered from anyone's text (shared notes,
|
|
6
|
+
// public pages), so it must not be able to inflate or script the page
|
|
7
|
+
// (verifier F3, 2026-09-25; guard __tests__/katex-limits.test.tsx):
|
|
8
|
+
/** No command (`\href`, `\url`, `\includegraphics`, `\htmlClass`…) is trusted. */
|
|
9
|
+
trust: false,
|
|
10
|
+
/** Largest size any user-given length may take, in em (`\rule{1000em}` → 10em). */
|
|
11
|
+
maxSize: 10,
|
|
12
|
+
/** Macro expansions per formula before KaTeX stops (a `\def` loop ends here). */
|
|
13
|
+
maxExpand: 500
|
|
14
|
+
};
|
|
15
|
+
function segment(md) {
|
|
16
|
+
const out = [];
|
|
17
|
+
let buf = "";
|
|
18
|
+
const flushText = () => {
|
|
19
|
+
if (buf) out.push({ text: buf, protected: false });
|
|
20
|
+
buf = "";
|
|
21
|
+
};
|
|
22
|
+
const pushProtected = (text) => {
|
|
23
|
+
flushText();
|
|
24
|
+
out.push({ text, protected: true });
|
|
25
|
+
};
|
|
26
|
+
const lines = md.split(/(?<=\n)/);
|
|
27
|
+
const kinds = fenceLineKinds(md);
|
|
28
|
+
let i = 0;
|
|
29
|
+
const blocks = [];
|
|
30
|
+
let textRun = "";
|
|
31
|
+
while (i < lines.length) {
|
|
32
|
+
const line = lines[i];
|
|
33
|
+
if (kinds[i] === "open") {
|
|
34
|
+
let fence = line;
|
|
35
|
+
i += 1;
|
|
36
|
+
while (i < lines.length && (kinds[i] === "body" || kinds[i] === "close")) {
|
|
37
|
+
const closes = kinds[i] === "close";
|
|
38
|
+
fence += lines[i];
|
|
39
|
+
i += 1;
|
|
40
|
+
if (closes) break;
|
|
41
|
+
}
|
|
42
|
+
if (textRun) blocks.push({ text: textRun, protected: false });
|
|
43
|
+
textRun = "";
|
|
44
|
+
blocks.push({ text: fence, protected: true });
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
textRun += line;
|
|
48
|
+
i += 1;
|
|
49
|
+
}
|
|
50
|
+
if (textRun) blocks.push({ text: textRun, protected: false });
|
|
51
|
+
for (const block of blocks) {
|
|
52
|
+
if (block.protected) {
|
|
53
|
+
pushProtected(block.text);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const s = block.text;
|
|
57
|
+
const spans = findCodeRanges(s).filter((r) => r.kind === "span");
|
|
58
|
+
let nextSpan = 0;
|
|
59
|
+
let j = 0;
|
|
60
|
+
while (j < s.length) {
|
|
61
|
+
while (nextSpan < spans.length && spans[nextSpan].start < j) nextSpan += 1;
|
|
62
|
+
const span = spans[nextSpan];
|
|
63
|
+
if (span && span.start === j) {
|
|
64
|
+
pushProtected(s.slice(span.start, span.end));
|
|
65
|
+
j = span.end;
|
|
66
|
+
nextSpan += 1;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const ch = s[j];
|
|
70
|
+
if (ch === "\\" && j + 1 < s.length) {
|
|
71
|
+
buf += ch + s[j + 1];
|
|
72
|
+
j += 2;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (ch === "`") {
|
|
76
|
+
let n = 0;
|
|
77
|
+
while (s[j + n] === "`") n += 1;
|
|
78
|
+
buf += s.slice(j, j + n);
|
|
79
|
+
j += n;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (ch === "$" && s[j + 1] === "$") {
|
|
83
|
+
const close = s.indexOf("$$", j + 2);
|
|
84
|
+
if (close === -1) {
|
|
85
|
+
buf += "$$";
|
|
86
|
+
j += 2;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
flushText();
|
|
90
|
+
out.push({ text: s.slice(j, close + 2), protected: true, math: true });
|
|
91
|
+
j = close + 2;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
buf += ch;
|
|
95
|
+
j += 1;
|
|
96
|
+
}
|
|
97
|
+
flushText();
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
function convertSingleDollar(text) {
|
|
102
|
+
let out = "";
|
|
103
|
+
let i = 0;
|
|
104
|
+
while (i < text.length) {
|
|
105
|
+
const ch = text[i];
|
|
106
|
+
if (ch === "\\" && i + 1 < text.length) {
|
|
107
|
+
out += ch + text[i + 1];
|
|
108
|
+
i += 2;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (ch === "$" && text[i + 1] === "$") {
|
|
112
|
+
const close = text.indexOf("$$", i + 2);
|
|
113
|
+
const end = close === -1 ? i + 2 : close + 2;
|
|
114
|
+
out += text.slice(i, end);
|
|
115
|
+
i = end;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (ch === "$") {
|
|
119
|
+
let close = -1;
|
|
120
|
+
for (let k = i + 1; k < text.length; k += 1) {
|
|
121
|
+
const c = text[k];
|
|
122
|
+
if (c === "\n") break;
|
|
123
|
+
if (c === "\\") {
|
|
124
|
+
k += 1;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (c === "$") {
|
|
128
|
+
close = k;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (close !== -1 && text[close + 1] !== "$") {
|
|
133
|
+
const content = text.slice(i + 1, close);
|
|
134
|
+
if (isSingleDollarMath(content, singleDollarAfter(text, close))) {
|
|
135
|
+
out += `$$${content}$$`;
|
|
136
|
+
i = close + 1;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
out += ch;
|
|
141
|
+
i += 1;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
out += ch;
|
|
145
|
+
i += 1;
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
function outsideMath(text, fn) {
|
|
150
|
+
let out = "";
|
|
151
|
+
let i = 0;
|
|
152
|
+
while (i < text.length) {
|
|
153
|
+
const open = text.indexOf("$$", i);
|
|
154
|
+
if (open === -1) break;
|
|
155
|
+
const close = text.indexOf("$$", open + 2);
|
|
156
|
+
if (close === -1) break;
|
|
157
|
+
out += fn(text.slice(i, open)) + text.slice(open, close + 2);
|
|
158
|
+
i = close + 2;
|
|
159
|
+
}
|
|
160
|
+
return out + fn(text.slice(i));
|
|
161
|
+
}
|
|
162
|
+
function convertBracketDisplay(text) {
|
|
163
|
+
return outsideMath(text, convertBracketDisplayInProse);
|
|
164
|
+
}
|
|
165
|
+
function convertBracketDisplayInProse(text) {
|
|
166
|
+
return replaceBracketSpans(text, (match, content) => {
|
|
167
|
+
const trimmed = content.trim();
|
|
168
|
+
if (content.includes("$") || /[A-Za-z]:\\/.test(content)) return match;
|
|
169
|
+
if (/\\[A-Za-z]/.test(content) && (content.includes("\n") || content.length >= 3)) {
|
|
170
|
+
return `
|
|
171
|
+
|
|
172
|
+
$$
|
|
173
|
+
${trimmed}
|
|
174
|
+
$$
|
|
175
|
+
|
|
176
|
+
`;
|
|
177
|
+
}
|
|
178
|
+
const multiline = match.startsWith("[\n") || match.startsWith("[ \n");
|
|
179
|
+
if (multiline && trimmed.length >= 3) {
|
|
180
|
+
const hasMathOperators = /[+\-=×÷*/]/.test(trimmed);
|
|
181
|
+
const hasProseWords = /\b(note|step|example|optional|the|is|are|was|were|for|with|this|that)\b/i.test(
|
|
182
|
+
trimmed
|
|
183
|
+
);
|
|
184
|
+
const mathLikeRatio = (trimmed.match(/[0-9+\-=×÷*/()xy\s]/g) || []).length / trimmed.length;
|
|
185
|
+
if (hasMathOperators && !hasProseWords && mathLikeRatio > 0.6) {
|
|
186
|
+
return `
|
|
187
|
+
|
|
188
|
+
$$
|
|
189
|
+
${trimmed}
|
|
190
|
+
$$
|
|
191
|
+
|
|
192
|
+
`;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return match;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function forwardFinder(find) {
|
|
199
|
+
let askedFrom = -1;
|
|
200
|
+
let answer = -1;
|
|
201
|
+
return (from) => {
|
|
202
|
+
if (askedFrom >= 0 && from >= askedFrom && (answer === -1 || answer >= from)) return answer;
|
|
203
|
+
askedFrom = from;
|
|
204
|
+
answer = find(from);
|
|
205
|
+
return answer;
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const isRegexWhitespace = (ch) => /\s/.test(ch);
|
|
209
|
+
function replaceBracketSpans(text, fn) {
|
|
210
|
+
if (!text.includes("[")) return text;
|
|
211
|
+
const nextClose = forwardFinder((from) => {
|
|
212
|
+
for (let at = text.indexOf("]", from); at !== -1; at = text.indexOf("]", at + 1)) {
|
|
213
|
+
const after = text[at + 1];
|
|
214
|
+
if (after !== "(" && after !== "[" && after !== ":") return at;
|
|
215
|
+
}
|
|
216
|
+
return -1;
|
|
217
|
+
});
|
|
218
|
+
let out = "";
|
|
219
|
+
let copied = 0;
|
|
220
|
+
for (let open = text.indexOf("["); open !== -1; ) {
|
|
221
|
+
const close = nextClose(open + 1);
|
|
222
|
+
if (close === -1) break;
|
|
223
|
+
let a = open + 1;
|
|
224
|
+
while (a < close && isRegexWhitespace(text[a])) a++;
|
|
225
|
+
let b = close;
|
|
226
|
+
while (b > a && isRegexWhitespace(text[b - 1])) b--;
|
|
227
|
+
out += text.slice(copied, open) + fn(text.slice(open, close + 1), text.slice(a, b));
|
|
228
|
+
copied = close + 1;
|
|
229
|
+
open = text.indexOf("[", copied);
|
|
230
|
+
}
|
|
231
|
+
return copied === 0 ? text : out + text.slice(copied);
|
|
232
|
+
}
|
|
233
|
+
function replaceDelimitedWithinParagraph(text, open, close, fn) {
|
|
234
|
+
if (!text.includes(open)) return text;
|
|
235
|
+
const nextClose = forwardFinder((from) => text.indexOf(close, from));
|
|
236
|
+
const blank = /\n[ \t]*\n/g;
|
|
237
|
+
const nextBlank = forwardFinder((from) => {
|
|
238
|
+
blank.lastIndex = from;
|
|
239
|
+
const m = blank.exec(text);
|
|
240
|
+
return m ? m.index : -1;
|
|
241
|
+
});
|
|
242
|
+
let out = "";
|
|
243
|
+
let copied = 0;
|
|
244
|
+
for (let at = text.indexOf(open); at !== -1; ) {
|
|
245
|
+
const start = at + open.length;
|
|
246
|
+
const end = nextClose(start);
|
|
247
|
+
if (end === -1) break;
|
|
248
|
+
const gap = nextBlank(start);
|
|
249
|
+
if (gap !== -1 && gap < end) {
|
|
250
|
+
at = text.indexOf(open, at + 1);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
out += text.slice(copied, at) + fn(text.slice(at, end + close.length), text.slice(start, end), at);
|
|
254
|
+
copied = end + close.length;
|
|
255
|
+
at = text.indexOf(open, copied);
|
|
256
|
+
}
|
|
257
|
+
return copied === 0 ? text : out + text.slice(copied);
|
|
258
|
+
}
|
|
259
|
+
const BRACKET_TEX_SIGNAL = /\\[A-Za-z]+|[\^{}=<>+]|_\{|(?:^|[^A-Za-z0-9])[A-Za-z]_[A-Za-z0-9](?![A-Za-z0-9])/;
|
|
260
|
+
function isEscapedBracketMath(content, before) {
|
|
261
|
+
if (!content.trim()) return false;
|
|
262
|
+
if (before !== void 0 && /[A-Za-z0-9_)\]]/.test(before)) return false;
|
|
263
|
+
return BRACKET_TEX_SIGNAL.test(content);
|
|
264
|
+
}
|
|
265
|
+
function normalizeText(text) {
|
|
266
|
+
let t = text;
|
|
267
|
+
const whole = t;
|
|
268
|
+
t = replaceDelimitedWithinParagraph(
|
|
269
|
+
t,
|
|
270
|
+
"\\[",
|
|
271
|
+
"\\]",
|
|
272
|
+
(match, tex, offset) => isEscapedBracketMath(tex, offset > 0 ? whole[offset - 1] : void 0) ? `
|
|
273
|
+
|
|
274
|
+
$$
|
|
275
|
+
${tex.trim()}
|
|
276
|
+
$$
|
|
277
|
+
|
|
278
|
+
` : match
|
|
279
|
+
);
|
|
280
|
+
t = replaceDelimitedWithinParagraph(t, "\\(", "\\)", (_m, tex) => `$$${tex.trim()}$$`);
|
|
281
|
+
t = convertSingleDollar(t);
|
|
282
|
+
t = convertBracketDisplay(t);
|
|
283
|
+
return t;
|
|
284
|
+
}
|
|
285
|
+
function normalizeMathDelimiters(markdown) {
|
|
286
|
+
if (!markdown || !/[\\$[]/.test(markdown)) return markdown;
|
|
287
|
+
return segment(markdown).map((s) => s.protected ? s.text : normalizeText(s.text)).join("");
|
|
288
|
+
}
|
|
289
|
+
function displayMathSource(tex) {
|
|
290
|
+
return `$$
|
|
291
|
+
${tex.trim()}
|
|
292
|
+
$$`;
|
|
293
|
+
}
|
|
294
|
+
function splitMathSpans(markdown) {
|
|
295
|
+
return segment(normalizeMathDelimiters(markdown)).map((seg) => {
|
|
296
|
+
if (!seg.protected) return { kind: "text", text: seg.text };
|
|
297
|
+
if (!seg.math) return { kind: "code", text: seg.text };
|
|
298
|
+
const inner = seg.text.slice(2, -2);
|
|
299
|
+
return {
|
|
300
|
+
kind: "math",
|
|
301
|
+
text: seg.text,
|
|
302
|
+
tex: inner.trim(),
|
|
303
|
+
display: /^[ \t]*\n/.test(inner)
|
|
304
|
+
};
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
export {
|
|
308
|
+
REHYPE_KATEX_OPTIONS,
|
|
309
|
+
REMARK_MATH_OPTIONS,
|
|
310
|
+
displayMathSource,
|
|
311
|
+
isEscapedBracketMath,
|
|
312
|
+
normalizeMathDelimiters,
|
|
313
|
+
replaceDelimitedWithinParagraph,
|
|
314
|
+
splitMathSpans
|
|
315
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../utils/plain-title.js";
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import remend, {
|
|
2
|
+
isWithinCodeBlock,
|
|
3
|
+
isWithinMathBlock
|
|
4
|
+
} from "remend";
|
|
5
|
+
import { looksLikeOpenInlineMath, singleDollarMathEnd } from "@ai-matrx/content-ir/source";
|
|
6
|
+
import { SYNTAX_STREAM_HANDLERS } from "./syntax/stream-heal-syntax.js";
|
|
7
|
+
import { replaceReferenceUses, trailingBracketedTail, trimTrailingSpaceTab } from "./syntax/linear-scan.js";
|
|
8
|
+
import {
|
|
9
|
+
isGfmDelimiterRow,
|
|
10
|
+
rowCells,
|
|
11
|
+
startsLikeTableRow,
|
|
12
|
+
trailingTableStart
|
|
13
|
+
} from "../display/markdown-classification/processors/utils/gfm-table-lines.js";
|
|
14
|
+
const TRAILING_REFERENCE_DEFINITION = /(^|\n) {0,3}\[[^\]\n]+\]:[^\n]*$/;
|
|
15
|
+
const pendingReferenceDefinition = {
|
|
16
|
+
name: "matrx-pending-reference-definition",
|
|
17
|
+
priority: 5,
|
|
18
|
+
handle: (text) => {
|
|
19
|
+
const match = TRAILING_REFERENCE_DEFINITION.exec(text);
|
|
20
|
+
if (!match) return text;
|
|
21
|
+
const lineStart = match.index + match[1].length;
|
|
22
|
+
if (isWithinCodeBlock(text, lineStart)) return text;
|
|
23
|
+
return text.slice(0, lineStart);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const DEFINITION_LABEL = /^ {0,3}\[([^\]\n]+)\]:/gm;
|
|
27
|
+
const pendingReferenceUses = {
|
|
28
|
+
name: "matrx-pending-reference-uses",
|
|
29
|
+
priority: 6,
|
|
30
|
+
handle: (text) => {
|
|
31
|
+
const defined = /* @__PURE__ */ new Set();
|
|
32
|
+
for (const m of text.matchAll(DEFINITION_LABEL)) {
|
|
33
|
+
if (!isWithinCodeBlock(text, m.index)) defined.add(normalizeLabel(m[1]));
|
|
34
|
+
}
|
|
35
|
+
return replaceReferenceUses(
|
|
36
|
+
text,
|
|
37
|
+
(whole, bang, label, id, offset) => {
|
|
38
|
+
if (defined.has(normalizeLabel(id))) return whole;
|
|
39
|
+
if (isWithinCodeBlock(text, offset) || isInsideInlineCode(text, offset)) {
|
|
40
|
+
return whole;
|
|
41
|
+
}
|
|
42
|
+
return bang ? "" : label;
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
function normalizeLabel(label) {
|
|
48
|
+
return label.trim().replace(/\s+/g, " ").toLowerCase();
|
|
49
|
+
}
|
|
50
|
+
function isInsideInlineCode(text, offset) {
|
|
51
|
+
const lineStart = text.lastIndexOf("\n", offset - 1) + 1;
|
|
52
|
+
const before = text.slice(lineStart, offset);
|
|
53
|
+
return (before.match(/`/g)?.length ?? 0) % 2 === 1;
|
|
54
|
+
}
|
|
55
|
+
const pendingBracketedTail = {
|
|
56
|
+
name: "matrx-pending-bracketed-tail",
|
|
57
|
+
priority: 1,
|
|
58
|
+
handle: (text) => {
|
|
59
|
+
const match = trailingBracketedTail(text);
|
|
60
|
+
if (!match) return text;
|
|
61
|
+
const { whole, bang, label, reference: referencePart } = match;
|
|
62
|
+
if (isWithinCodeBlock(text, match.index)) return text;
|
|
63
|
+
if (isInsideInlineCode(text, match.index)) return text;
|
|
64
|
+
return text.slice(0, text.length - whole.length) + (bang ? "" : label);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const TRAILING_EMPTY_EMPHASIS = /(^|\s)[*_~`]+$/;
|
|
68
|
+
const pendingEmptyEmphasis = {
|
|
69
|
+
name: "matrx-pending-empty-emphasis",
|
|
70
|
+
priority: 200,
|
|
71
|
+
handle: (text) => {
|
|
72
|
+
const match = TRAILING_EMPTY_EMPHASIS.exec(text);
|
|
73
|
+
if (!match) return text;
|
|
74
|
+
if (isWithinCodeBlock(text, match.index)) return text;
|
|
75
|
+
return text.slice(0, match.index + match[1].length);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const pendingInlineMath = {
|
|
79
|
+
name: "matrx-pending-inline-math",
|
|
80
|
+
priority: 2,
|
|
81
|
+
handle: (text) => {
|
|
82
|
+
const lineStart = text.lastIndexOf("\n") + 1;
|
|
83
|
+
let i = lineStart;
|
|
84
|
+
while (i < text.length) {
|
|
85
|
+
const ch = text[i];
|
|
86
|
+
if (ch === "\\") {
|
|
87
|
+
i += 2;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (ch === "`") {
|
|
91
|
+
const close = text.indexOf("`", i + 1);
|
|
92
|
+
if (close === -1) return text;
|
|
93
|
+
i = close + 1;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (ch !== "$") {
|
|
97
|
+
i += 1;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (text[i + 1] === "$") {
|
|
101
|
+
const close = text.indexOf("$$", i + 2);
|
|
102
|
+
if (close === -1) return text;
|
|
103
|
+
i = close + 2;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const end = singleDollarMathEnd(text, i);
|
|
107
|
+
if (end !== -1) {
|
|
108
|
+
i = end;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const partial = text.slice(i + 1);
|
|
112
|
+
const opensMath = partial === "" || !/^\s/.test(partial) && looksLikeOpenInlineMath(partial.trimEnd());
|
|
113
|
+
if (opensMath && !isWithinCodeBlock(text, i) && !isWithinMathBlock(text, i)) {
|
|
114
|
+
return text.slice(0, i);
|
|
115
|
+
}
|
|
116
|
+
i += 1;
|
|
117
|
+
}
|
|
118
|
+
return text;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const tableCells = rowCells;
|
|
122
|
+
const pendingTable = {
|
|
123
|
+
name: "matrx-pending-table",
|
|
124
|
+
priority: 3,
|
|
125
|
+
handle: (text) => {
|
|
126
|
+
const lines = text.split("\n");
|
|
127
|
+
const start = trailingTableStart(lines);
|
|
128
|
+
if (start === lines.length) return text;
|
|
129
|
+
const offset = lines.slice(0, start).join("\n").length + (start > 0 ? 1 : 0);
|
|
130
|
+
if (isWithinCodeBlock(text, offset)) return text;
|
|
131
|
+
const rows = lines.slice(start);
|
|
132
|
+
const pipeLed = startsLikeTableRow(rows[0]);
|
|
133
|
+
const headerCells = tableCells(rows[0]).length;
|
|
134
|
+
const delimiter = rows[1];
|
|
135
|
+
const delimiterWhole = delimiter !== void 0 && isGfmDelimiterRow(delimiter) && tableCells(delimiter).length === headerCells && (rows.length > 2 || delimiter.trimEnd().endsWith("|") || !pipeLed);
|
|
136
|
+
if (!delimiterWhole) return text.slice(0, offset).replace(/\n$/, "\n");
|
|
137
|
+
const last = rows[rows.length - 1];
|
|
138
|
+
if (rows.length > 2 && pipeLed && !last.trimEnd().endsWith("|")) {
|
|
139
|
+
return lines.slice(0, lines.length - 1).join("\n");
|
|
140
|
+
}
|
|
141
|
+
return text;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const REASONING_OPEN = /(?:<|<)(thinking|think|reasoning)(?:>|>)/g;
|
|
145
|
+
const pendingReasoningSpan = {
|
|
146
|
+
name: "matrx-pending-reasoning-span",
|
|
147
|
+
priority: 1,
|
|
148
|
+
handle: (text) => {
|
|
149
|
+
let cut = -1;
|
|
150
|
+
for (const match of text.matchAll(REASONING_OPEN)) {
|
|
151
|
+
const at = match.index ?? 0;
|
|
152
|
+
const tag = match[1];
|
|
153
|
+
const rest = text.slice(at + match[0].length);
|
|
154
|
+
if (new RegExp(`(?:<|<)/${tag}(?:>|>)`).test(rest)) continue;
|
|
155
|
+
if (isWithinCodeBlock(text, at)) continue;
|
|
156
|
+
const lineStart = text.lastIndexOf("\n", at - 1) + 1;
|
|
157
|
+
if (((text.slice(lineStart, at).match(/`/g) ?? []).length & 1) === 1) continue;
|
|
158
|
+
cut = at;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
return cut === -1 ? text : trimTrailingSpaceTab(text.slice(0, cut));
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
const REMEND_OPTIONS = {
|
|
165
|
+
linkMode: "text-only",
|
|
166
|
+
handlers: [
|
|
167
|
+
pendingReasoningSpan,
|
|
168
|
+
pendingBracketedTail,
|
|
169
|
+
pendingInlineMath,
|
|
170
|
+
pendingTable,
|
|
171
|
+
pendingReferenceDefinition,
|
|
172
|
+
pendingReferenceUses,
|
|
173
|
+
pendingEmptyEmphasis,
|
|
174
|
+
// Extended syntax (front matter, directives, callouts, wikilinks, …).
|
|
175
|
+
...SYNTAX_STREAM_HANDLERS
|
|
176
|
+
]
|
|
177
|
+
};
|
|
178
|
+
function healStreamingMarkdown(source) {
|
|
179
|
+
if (!source) return source;
|
|
180
|
+
return remend(source, REMEND_OPTIONS);
|
|
181
|
+
}
|
|
182
|
+
export {
|
|
183
|
+
healStreamingMarkdown
|
|
184
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
const MarkdownStreamingContext = createContext(false);
|
|
4
|
+
const MarkdownStreamingProvider = MarkdownStreamingContext.Provider;
|
|
5
|
+
function useMarkdownStreaming() {
|
|
6
|
+
return useContext(MarkdownStreamingContext);
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
MarkdownStreamingProvider,
|
|
10
|
+
useMarkdownStreaming
|
|
11
|
+
};
|