@stream-mdx/core 0.1.0 → 0.2.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.
- package/CHANGELOG.md +6 -0
- package/README.md +6 -0
- package/dist/code-highlighting.cjs +20 -0
- package/dist/code-highlighting.d.cts +9 -1
- package/dist/code-highlighting.d.ts +9 -1
- package/dist/code-highlighting.mjs +18 -0
- package/dist/index.cjs +354 -149
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +352 -149
- package/dist/mixed-content.cjs +14 -0
- package/dist/mixed-content.d.cts +3 -1
- package/dist/mixed-content.d.ts +3 -1
- package/dist/mixed-content.mjs +14 -0
- package/dist/perf/patch-coalescing.cjs +58 -1
- package/dist/perf/patch-coalescing.mjs +58 -1
- package/dist/types.d.cts +64 -1
- package/dist/types.d.ts +64 -1
- package/dist/utils.cjs +16 -6
- package/dist/utils.mjs +16 -6
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -67,12 +67,14 @@ __export(index_exports, {
|
|
|
67
67
|
findClosingHtmlTag: () => findClosingHtmlTag,
|
|
68
68
|
generateBlockId: () => generateBlockId,
|
|
69
69
|
getBlockKey: () => getBlockKey,
|
|
70
|
+
getDefaultCodeWrapperAttributes: () => getDefaultCodeWrapperAttributes,
|
|
70
71
|
initializeSecurity: () => initializeSecurity,
|
|
71
72
|
initializeTrustedTypesPolicy: () => initializeTrustedTypesPolicy,
|
|
72
73
|
inlineNodesToPlainText: () => inlineNodesToPlainText,
|
|
73
74
|
isLikelyMdxComponent: () => isLikelyMdxComponent,
|
|
74
75
|
normalizeBlockquoteText: () => normalizeBlockquoteText,
|
|
75
76
|
normalizeFormatAnticipation: () => normalizeFormatAnticipation,
|
|
77
|
+
normalizeHighlightedLines: () => normalizeHighlightedLines,
|
|
76
78
|
normalizeLang: () => normalizeLang,
|
|
77
79
|
parseCodeFenceInfo: () => parseCodeFenceInfo,
|
|
78
80
|
prepareInlineStreamingContent: () => prepareInlineStreamingContent,
|
|
@@ -230,6 +232,22 @@ function manualExtractHighlightedLines(html, fallbackLength) {
|
|
|
230
232
|
}
|
|
231
233
|
return normalizeHighlightedLines(lines, fallbackLength);
|
|
232
234
|
}
|
|
235
|
+
function getDefaultCodeWrapperAttributes(lang, themes = { dark: "github-dark", light: "github-light" }) {
|
|
236
|
+
const language = lang && typeof lang === "string" && lang.length > 0 ? lang : "text";
|
|
237
|
+
const themeLabel = `${themes.dark} ${themes.light}`;
|
|
238
|
+
return {
|
|
239
|
+
preAttrs: {
|
|
240
|
+
class: `shiki shiki-themes ${themeLabel}`,
|
|
241
|
+
"data-language": language,
|
|
242
|
+
style: "--shiki-dark-bg: transparent; --shiki-light-bg: transparent"
|
|
243
|
+
},
|
|
244
|
+
codeAttrs: {
|
|
245
|
+
"data-language": language,
|
|
246
|
+
"data-theme": themeLabel,
|
|
247
|
+
style: "display: grid;"
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
233
251
|
function dedentIndentedCode(raw) {
|
|
234
252
|
if (!raw) return "";
|
|
235
253
|
const normalized = normalizeNewlines(raw);
|
|
@@ -636,6 +654,130 @@ function splitTextByRegexWithPrecedence(text, regex, toNode) {
|
|
|
636
654
|
return result;
|
|
637
655
|
}
|
|
638
656
|
|
|
657
|
+
// src/streaming/inline-streaming.ts
|
|
658
|
+
var DEFAULT_FORMAT_ANTICIPATION = {
|
|
659
|
+
inline: false,
|
|
660
|
+
mathInline: false,
|
|
661
|
+
mathBlock: false,
|
|
662
|
+
html: false,
|
|
663
|
+
mdx: false,
|
|
664
|
+
regex: false
|
|
665
|
+
};
|
|
666
|
+
function normalizeFormatAnticipation(input) {
|
|
667
|
+
if (input === true) {
|
|
668
|
+
return { ...DEFAULT_FORMAT_ANTICIPATION, inline: true };
|
|
669
|
+
}
|
|
670
|
+
if (!input) {
|
|
671
|
+
return { ...DEFAULT_FORMAT_ANTICIPATION };
|
|
672
|
+
}
|
|
673
|
+
return {
|
|
674
|
+
inline: input.inline ?? false,
|
|
675
|
+
mathInline: input.mathInline ?? false,
|
|
676
|
+
mathBlock: input.mathBlock ?? false,
|
|
677
|
+
html: input.html ?? false,
|
|
678
|
+
mdx: input.mdx ?? false,
|
|
679
|
+
regex: input.regex ?? false
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function prepareInlineStreamingContent(content, options) {
|
|
683
|
+
const enableMath = options?.math !== false;
|
|
684
|
+
const anticipation = normalizeFormatAnticipation(options?.formatAnticipation);
|
|
685
|
+
const enableInlineAnticipation = anticipation.inline;
|
|
686
|
+
const enableMathInlineAnticipation = anticipation.mathInline;
|
|
687
|
+
const enableMathBlockAnticipation = anticipation.mathBlock;
|
|
688
|
+
const stack = [];
|
|
689
|
+
const toggleToken = (token) => {
|
|
690
|
+
const last = stack[stack.length - 1];
|
|
691
|
+
if (last === token) {
|
|
692
|
+
stack.pop();
|
|
693
|
+
} else {
|
|
694
|
+
stack.push(token);
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
let mathDisplayOpen = false;
|
|
698
|
+
let mathDisplayCrossedNewline = false;
|
|
699
|
+
for (let i = 0; i < content.length; i++) {
|
|
700
|
+
const code = content.charCodeAt(i);
|
|
701
|
+
if (code === 10 || code === 13) {
|
|
702
|
+
if (mathDisplayOpen) {
|
|
703
|
+
mathDisplayCrossedNewline = true;
|
|
704
|
+
}
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
if (code === 96) {
|
|
708
|
+
toggleToken("code");
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
if (code === 126 && i + 1 < content.length && content.charCodeAt(i + 1) === 126) {
|
|
712
|
+
toggleToken("strike");
|
|
713
|
+
i += 1;
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
if (code === 42) {
|
|
717
|
+
if (i + 1 < content.length && content.charCodeAt(i + 1) === 42) {
|
|
718
|
+
toggleToken("strong");
|
|
719
|
+
i += 1;
|
|
720
|
+
} else {
|
|
721
|
+
toggleToken("em");
|
|
722
|
+
}
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
if (enableMath && code === 36) {
|
|
726
|
+
if (i + 1 < content.length && content.charCodeAt(i + 1) === 36) {
|
|
727
|
+
toggleToken("math-display");
|
|
728
|
+
if (mathDisplayOpen) {
|
|
729
|
+
mathDisplayOpen = false;
|
|
730
|
+
mathDisplayCrossedNewline = false;
|
|
731
|
+
} else {
|
|
732
|
+
mathDisplayOpen = true;
|
|
733
|
+
mathDisplayCrossedNewline = false;
|
|
734
|
+
}
|
|
735
|
+
i += 1;
|
|
736
|
+
} else {
|
|
737
|
+
toggleToken("math-inline");
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const hasIncompleteFormatting = stack.some((token) => token === "code" || token === "strike" || token === "strong" || token === "em");
|
|
742
|
+
const hasIncompleteMathInline = stack.includes("math-inline");
|
|
743
|
+
const hasIncompleteMathDisplay = stack.includes("math-display");
|
|
744
|
+
const hasIncompleteMath = hasIncompleteMathInline || hasIncompleteMathDisplay;
|
|
745
|
+
if (enableMath && hasIncompleteMath) {
|
|
746
|
+
if (hasIncompleteMathInline && !enableMathInlineAnticipation) {
|
|
747
|
+
return { kind: "raw", status: "raw", reason: "incomplete-math" };
|
|
748
|
+
}
|
|
749
|
+
if (hasIncompleteMathDisplay && (!enableMathBlockAnticipation || mathDisplayCrossedNewline)) {
|
|
750
|
+
return { kind: "raw", status: "raw", reason: "incomplete-math" };
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
if (hasIncompleteFormatting && !enableInlineAnticipation) {
|
|
754
|
+
return { kind: "raw", status: "raw", reason: "incomplete-formatting" };
|
|
755
|
+
}
|
|
756
|
+
if (!hasIncompleteFormatting && !hasIncompleteMath) {
|
|
757
|
+
return { kind: "parse", status: "complete", content, appended: "" };
|
|
758
|
+
}
|
|
759
|
+
const appendForToken = (token) => {
|
|
760
|
+
switch (token) {
|
|
761
|
+
case "code":
|
|
762
|
+
return "`";
|
|
763
|
+
case "strike":
|
|
764
|
+
return "~~";
|
|
765
|
+
case "strong":
|
|
766
|
+
return "**";
|
|
767
|
+
case "em":
|
|
768
|
+
return "*";
|
|
769
|
+
case "math-inline":
|
|
770
|
+
return "$";
|
|
771
|
+
case "math-display":
|
|
772
|
+
return "$$";
|
|
773
|
+
default:
|
|
774
|
+
return "";
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
const appended = stack.slice().reverse().map((token) => appendForToken(token)).join("");
|
|
778
|
+
return { kind: "parse", status: "anticipated", content: content + appended, appended };
|
|
779
|
+
}
|
|
780
|
+
|
|
639
781
|
// src/worker-html-sanitizer.ts
|
|
640
782
|
var rehypeParse = __toESM(require("rehype-parse"), 1);
|
|
641
783
|
var rehypeSanitize = __toESM(require("rehype-sanitize"), 1);
|
|
@@ -817,6 +959,8 @@ function splitByTagSegments(source, baseOffset, parseInline, options) {
|
|
|
817
959
|
const mdxAutoClose = options?.mdx?.autoClose === true;
|
|
818
960
|
const mdxMaxNewlines = normalizeNewlineLimit(options?.mdx?.maxNewlines);
|
|
819
961
|
const mdxAllowlist = normalizeComponentAllowlist(options?.mdx?.componentAllowlist);
|
|
962
|
+
const protectedRanges = options?.protectedRanges ?? [];
|
|
963
|
+
const protectedKinds = protectedRanges.length ? new Set(options?.protectedRangeKinds ?? ["math-inline", "math-display", "code-inline", "code-block", "autolink"]) : null;
|
|
820
964
|
while (match !== null) {
|
|
821
965
|
const start = match.index;
|
|
822
966
|
const tagName = match[1];
|
|
@@ -831,6 +975,18 @@ function splitByTagSegments(source, baseOffset, parseInline, options) {
|
|
|
831
975
|
continue;
|
|
832
976
|
}
|
|
833
977
|
let end = tagPattern.lastIndex;
|
|
978
|
+
if (protectedKinds && protectedRanges.length > 0) {
|
|
979
|
+
const absoluteStart = baseIsFinite ? baseOffset + start : start;
|
|
980
|
+
const absoluteEnd = baseIsFinite ? baseOffset + end : end;
|
|
981
|
+
const covered = protectedRanges.some(
|
|
982
|
+
(range) => protectedKinds.has(range.kind) && typeof range.from === "number" && typeof range.to === "number" && range.from <= absoluteStart && range.to >= absoluteEnd
|
|
983
|
+
);
|
|
984
|
+
if (covered) {
|
|
985
|
+
tagPattern.lastIndex = start + 1;
|
|
986
|
+
match = tagPattern.exec(source);
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
834
990
|
if (!isSelfClosing && !mdxAllowed) {
|
|
835
991
|
const closingIndex = findClosingHtmlTag(lowerSource, tagName.toLowerCase(), end);
|
|
836
992
|
if (closingIndex === -1) {
|
|
@@ -1128,23 +1284,33 @@ function getBlockKey(block) {
|
|
|
1128
1284
|
}
|
|
1129
1285
|
function detectMDX(content, options) {
|
|
1130
1286
|
const inlineCodeRanges = collectInlineCodeRanges(content);
|
|
1287
|
+
const protectedRanges = options?.protectedRanges ?? [];
|
|
1288
|
+
const baseOffset = typeof options?.baseOffset === "number" ? options.baseOffset : 0;
|
|
1289
|
+
const protectedKinds = protectedRanges.length ? /* @__PURE__ */ new Set(["math-inline", "math-display", "code-inline", "code-block", "html-inline", "html-block", "autolink"]) : null;
|
|
1131
1290
|
const componentPattern = /<([A-Z][\w-]*)(\s|\/?>)/g;
|
|
1132
1291
|
let componentMatch = componentPattern.exec(content);
|
|
1133
1292
|
while (componentMatch !== null) {
|
|
1134
1293
|
const start = componentMatch.index;
|
|
1135
1294
|
const end = start + componentMatch[0].length;
|
|
1136
|
-
if (
|
|
1137
|
-
|
|
1295
|
+
if (isWithinRanges(start, end, inlineCodeRanges)) {
|
|
1296
|
+
componentMatch = componentPattern.exec(content);
|
|
1297
|
+
continue;
|
|
1298
|
+
}
|
|
1299
|
+
if (protectedKinds) {
|
|
1300
|
+
const absoluteStart = baseOffset + start;
|
|
1301
|
+
const absoluteEnd = baseOffset + end;
|
|
1302
|
+
const covered = protectedRanges.some((range) => protectedKinds.has(range.kind) && range.from <= absoluteStart && range.to >= absoluteEnd);
|
|
1303
|
+
if (covered) {
|
|
1304
|
+
componentMatch = componentPattern.exec(content);
|
|
1305
|
+
continue;
|
|
1306
|
+
}
|
|
1138
1307
|
}
|
|
1139
|
-
|
|
1308
|
+
return true;
|
|
1140
1309
|
}
|
|
1141
1310
|
if (/(^|\n)\s*(import|export)\s/.test(content)) {
|
|
1142
1311
|
return true;
|
|
1143
1312
|
}
|
|
1144
1313
|
const expressionPattern = /\{[^{}]+\}/g;
|
|
1145
|
-
const protectedRanges = options?.protectedRanges ?? [];
|
|
1146
|
-
const baseOffset = typeof options?.baseOffset === "number" ? options.baseOffset : 0;
|
|
1147
|
-
const protectedKinds = protectedRanges.length ? /* @__PURE__ */ new Set(["math-inline", "math-display", "code-inline", "code-block"]) : null;
|
|
1148
1314
|
for (let match = expressionPattern.exec(content); match !== null; match = expressionPattern.exec(content)) {
|
|
1149
1315
|
const index = match.index;
|
|
1150
1316
|
const prev = index > 0 ? content[index - 1] : "";
|
|
@@ -1392,7 +1558,12 @@ function buildListItemSnapshot(block, listItemNode, ordered, index, id, baseOffs
|
|
|
1392
1558
|
}
|
|
1393
1559
|
if (name === "Paragraph") {
|
|
1394
1560
|
const paragraphRaw = raw.slice(cursor.from, cursor.to);
|
|
1395
|
-
const
|
|
1561
|
+
const meta = block.payload.meta ?? {};
|
|
1562
|
+
const paragraphData = processListItemParagraph(paragraphRaw, {
|
|
1563
|
+
formatAnticipation: meta.formatAnticipation,
|
|
1564
|
+
math: meta.mathEnabled,
|
|
1565
|
+
streaming: !block.isFinalized
|
|
1566
|
+
});
|
|
1396
1567
|
const parsedInline = paragraphData.inline;
|
|
1397
1568
|
if (!paragraphHandled) {
|
|
1398
1569
|
inlineNodes = parsedInline;
|
|
@@ -1424,7 +1595,10 @@ function buildListItemSnapshot(block, listItemNode, ordered, index, id, baseOffs
|
|
|
1424
1595
|
} else if (name === "BulletList" || name === "OrderedList") {
|
|
1425
1596
|
const nestedId = `${id}::list:${subListIndex++}`;
|
|
1426
1597
|
const nestedOrdered = name === "OrderedList";
|
|
1427
|
-
|
|
1598
|
+
const nestedSnapshot = buildListNodeSnapshot(block, cursor.node, nestedOrdered, nestedId, baseOffset, raw);
|
|
1599
|
+
if (Array.isArray(nestedSnapshot.children) && nestedSnapshot.children.length > 0) {
|
|
1600
|
+
childSnapshots.push(nestedSnapshot);
|
|
1601
|
+
}
|
|
1428
1602
|
} else if (name === "Blockquote") {
|
|
1429
1603
|
const quoteId = `${id}::blockquote:${blockquoteIndex++}`;
|
|
1430
1604
|
childSnapshots.push(buildBlockquoteSnapshot(block, cursor.node, quoteId, baseOffset, raw));
|
|
@@ -1460,11 +1634,31 @@ function buildListItemSnapshot(block, listItemNode, ordered, index, id, baseOffs
|
|
|
1460
1634
|
};
|
|
1461
1635
|
return itemSnapshot;
|
|
1462
1636
|
}
|
|
1463
|
-
function
|
|
1637
|
+
function parseListInline(raw, options) {
|
|
1638
|
+
if (!options?.streaming || !options.formatAnticipation) {
|
|
1639
|
+
return listInlineParser.parse(raw);
|
|
1640
|
+
}
|
|
1641
|
+
const prepared = prepareInlineStreamingContent(raw, { formatAnticipation: options.formatAnticipation, math: options.math });
|
|
1642
|
+
if (prepared.kind === "raw") {
|
|
1643
|
+
return [{ kind: "text", text: raw }];
|
|
1644
|
+
}
|
|
1645
|
+
let preparedContent = prepared.content;
|
|
1646
|
+
let appended = prepared.appended;
|
|
1647
|
+
const normalized = normalizeFormatAnticipation(options.formatAnticipation);
|
|
1648
|
+
if (normalized.regex) {
|
|
1649
|
+
const regexAppend = listInlineParser.getRegexAnticipationAppend(raw);
|
|
1650
|
+
if (regexAppend) {
|
|
1651
|
+
preparedContent += regexAppend;
|
|
1652
|
+
appended += regexAppend;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
return listInlineParser.parse(preparedContent, { cache: false });
|
|
1656
|
+
}
|
|
1657
|
+
function processListItemParagraph(raw, options) {
|
|
1464
1658
|
const normalized = normalizeParagraphText(raw);
|
|
1465
1659
|
const { content, task } = stripTaskMarker(normalized);
|
|
1466
|
-
const inline =
|
|
1467
|
-
const segments = extractMixedContentSegments(content, void 0, (value) =>
|
|
1660
|
+
const inline = parseListInline(content, options);
|
|
1661
|
+
const segments = extractMixedContentSegments(content, void 0, (value) => parseListInline(value, options));
|
|
1468
1662
|
return {
|
|
1469
1663
|
inline,
|
|
1470
1664
|
segments,
|
|
@@ -1749,28 +1943,82 @@ function enrichTableSnapshot(block, snapshot) {
|
|
|
1749
1943
|
function enrichCodeSnapshot(block, snapshot) {
|
|
1750
1944
|
const source = typeof block.payload.meta?.code === "string" ? block.payload.meta?.code : block.payload.raw ?? "";
|
|
1751
1945
|
const lines = extractCodeLines(source);
|
|
1946
|
+
const meta = block.payload.meta;
|
|
1752
1947
|
const highlightedHtml = block.payload.highlightedHtml ?? "";
|
|
1753
|
-
const
|
|
1754
|
-
const
|
|
1755
|
-
const
|
|
1948
|
+
const hasBlockHighlight = typeof block.payload.highlightedHtml === "string" && block.payload.highlightedHtml.length > 0;
|
|
1949
|
+
const metaLines = Array.isArray(meta?.highlightedLines) ? meta?.highlightedLines : null;
|
|
1950
|
+
const includeLineHtml = metaLines ? true : !hasBlockHighlight || lines.length >= 200;
|
|
1951
|
+
const highlightedLines = metaLines ? normalizeHighlightedLines(metaLines, lines.length) : extractHighlightedLines(highlightedHtml, lines.length);
|
|
1952
|
+
const metaTokenLines = Array.isArray(meta?.tokenLines) ? meta?.tokenLines : null;
|
|
1953
|
+
const tokenLines = metaTokenLines ? normalizeTokenLines(metaTokenLines, lines.length) : null;
|
|
1954
|
+
const metaDiffKind = Array.isArray(meta?.diffKind) ? meta?.diffKind : null;
|
|
1955
|
+
const diffKindLines = metaDiffKind ? normalizeOptionalArray(metaDiffKind, lines.length) : null;
|
|
1956
|
+
const metaOldNo = Array.isArray(meta?.oldNo) ? meta?.oldNo : null;
|
|
1957
|
+
const oldNoLines = metaOldNo ? normalizeOptionalArray(metaOldNo, lines.length) : null;
|
|
1958
|
+
const metaNewNo = Array.isArray(meta?.newNo) ? meta?.newNo : null;
|
|
1959
|
+
const newNoLines = metaNewNo ? normalizeOptionalArray(metaNewNo, lines.length) : null;
|
|
1960
|
+
const lang = typeof meta?.lang === "string" ? String(meta.lang) : void 0;
|
|
1961
|
+
let { preAttrs, codeAttrs } = extractCodeWrapperAttributes(highlightedHtml);
|
|
1962
|
+
if (!preAttrs || !codeAttrs) {
|
|
1963
|
+
const defaults = getDefaultCodeWrapperAttributes(lang);
|
|
1964
|
+
preAttrs = preAttrs ?? defaults.preAttrs;
|
|
1965
|
+
codeAttrs = codeAttrs ?? defaults.codeAttrs;
|
|
1966
|
+
}
|
|
1756
1967
|
snapshot.props = {
|
|
1757
1968
|
...snapshot.props ?? {},
|
|
1758
1969
|
lang,
|
|
1759
1970
|
preAttrs,
|
|
1760
1971
|
codeAttrs
|
|
1761
1972
|
};
|
|
1762
|
-
snapshot.children = lines.map((line, index) =>
|
|
1763
|
-
|
|
1764
|
-
type: "code-line",
|
|
1765
|
-
props: {
|
|
1973
|
+
snapshot.children = lines.map((line, index) => {
|
|
1974
|
+
const props = {
|
|
1766
1975
|
index,
|
|
1767
1976
|
text: line,
|
|
1768
|
-
html: highlightedLines[index] ?? null
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
|
-
|
|
1977
|
+
html: includeLineHtml ? highlightedLines[index] ?? null : null
|
|
1978
|
+
};
|
|
1979
|
+
if (tokenLines) {
|
|
1980
|
+
props.tokens = tokenLines[index] ?? null;
|
|
1981
|
+
}
|
|
1982
|
+
if (diffKindLines) {
|
|
1983
|
+
props.diffKind = diffKindLines[index] ?? null;
|
|
1984
|
+
}
|
|
1985
|
+
if (oldNoLines) {
|
|
1986
|
+
props.oldNo = oldNoLines[index] ?? null;
|
|
1987
|
+
}
|
|
1988
|
+
if (newNoLines) {
|
|
1989
|
+
props.newNo = newNoLines[index] ?? null;
|
|
1990
|
+
}
|
|
1991
|
+
return {
|
|
1992
|
+
id: `${block.id}::line:${index}`,
|
|
1993
|
+
type: "code-line",
|
|
1994
|
+
props,
|
|
1995
|
+
children: []
|
|
1996
|
+
};
|
|
1997
|
+
});
|
|
1772
1998
|
return snapshot;
|
|
1773
1999
|
}
|
|
2000
|
+
function normalizeTokenLines(lines, fallbackLength) {
|
|
2001
|
+
if (!lines || lines.length === 0) {
|
|
2002
|
+
return new Array(Math.max(0, fallbackLength)).fill(null);
|
|
2003
|
+
}
|
|
2004
|
+
const length = Math.max(fallbackLength, lines.length);
|
|
2005
|
+
const result = new Array(length).fill(null);
|
|
2006
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2007
|
+
result[i] = lines[i] ?? null;
|
|
2008
|
+
}
|
|
2009
|
+
return result;
|
|
2010
|
+
}
|
|
2011
|
+
function normalizeOptionalArray(lines, fallbackLength) {
|
|
2012
|
+
if (!lines || lines.length === 0) {
|
|
2013
|
+
return new Array(Math.max(0, fallbackLength)).fill(null);
|
|
2014
|
+
}
|
|
2015
|
+
const length = Math.max(fallbackLength, lines.length);
|
|
2016
|
+
const result = new Array(length).fill(null);
|
|
2017
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2018
|
+
result[i] = lines[i] ?? null;
|
|
2019
|
+
}
|
|
2020
|
+
return result;
|
|
2021
|
+
}
|
|
1774
2022
|
function cloneInlineNodes(nodes) {
|
|
1775
2023
|
return nodes.map((node) => {
|
|
1776
2024
|
if ("children" in node && Array.isArray(node.children)) {
|
|
@@ -1939,7 +2187,17 @@ function applyPatchBatch(snapshot, patches) {
|
|
|
1939
2187
|
case "appendLines": {
|
|
1940
2188
|
const parent = resolveTargetNode(snapshot, patch.at);
|
|
1941
2189
|
if (!parent) break;
|
|
1942
|
-
appendLinesToCodeNode(
|
|
2190
|
+
appendLinesToCodeNode(
|
|
2191
|
+
snapshot,
|
|
2192
|
+
parent,
|
|
2193
|
+
patch.startIndex,
|
|
2194
|
+
patch.lines ?? [],
|
|
2195
|
+
patch.highlight ?? [],
|
|
2196
|
+
patch.tokens,
|
|
2197
|
+
patch.diffKind,
|
|
2198
|
+
patch.oldNo,
|
|
2199
|
+
patch.newNo
|
|
2200
|
+
);
|
|
1943
2201
|
break;
|
|
1944
2202
|
}
|
|
1945
2203
|
case "setHTML": {
|
|
@@ -2061,7 +2319,7 @@ function applyPropsToNode(node, props) {
|
|
|
2061
2319
|
}
|
|
2062
2320
|
node.props = next;
|
|
2063
2321
|
}
|
|
2064
|
-
function appendLinesToCodeNode(snapshot, parent, startIndex, lines, highlights) {
|
|
2322
|
+
function appendLinesToCodeNode(snapshot, parent, startIndex, lines, highlights, tokens, diffKind, oldNo, newNo) {
|
|
2065
2323
|
if (parent.type !== "code") return;
|
|
2066
2324
|
const insertionIndex = Math.max(0, Math.min(startIndex, parent.children.length));
|
|
2067
2325
|
let currentIndex = insertionIndex;
|
|
@@ -2079,6 +2337,18 @@ function appendLinesToCodeNode(snapshot, parent, startIndex, lines, highlights)
|
|
|
2079
2337
|
html: highlights[i] ?? null
|
|
2080
2338
|
}
|
|
2081
2339
|
};
|
|
2340
|
+
if (tokens && Object.prototype.hasOwnProperty.call(tokens, i)) {
|
|
2341
|
+
child.props.tokens = tokens[i] ?? null;
|
|
2342
|
+
}
|
|
2343
|
+
if (diffKind && Object.prototype.hasOwnProperty.call(diffKind, i)) {
|
|
2344
|
+
child.props.diffKind = diffKind[i] ?? null;
|
|
2345
|
+
}
|
|
2346
|
+
if (oldNo && Object.prototype.hasOwnProperty.call(oldNo, i)) {
|
|
2347
|
+
child.props.oldNo = oldNo[i] ?? null;
|
|
2348
|
+
}
|
|
2349
|
+
if (newNo && Object.prototype.hasOwnProperty.call(newNo, i)) {
|
|
2350
|
+
child.props.newNo = newNo[i] ?? null;
|
|
2351
|
+
}
|
|
2082
2352
|
snapshot.nodes.set(child.id, child);
|
|
2083
2353
|
parent.children.splice(currentIndex, 0, child.id);
|
|
2084
2354
|
currentIndex++;
|
|
@@ -2634,6 +2904,14 @@ function mergeAppendLines(window2, startIndex) {
|
|
|
2634
2904
|
}
|
|
2635
2905
|
const lines = [...base.lines ?? []];
|
|
2636
2906
|
const highlight = Array.isArray(base.highlight) ? [...base.highlight] : [];
|
|
2907
|
+
const tokens = Array.isArray(base.tokens) ? [...base.tokens] : [];
|
|
2908
|
+
const diffKind = Array.isArray(base.diffKind) ? [...base.diffKind] : [];
|
|
2909
|
+
const oldNo = Array.isArray(base.oldNo) ? [...base.oldNo] : [];
|
|
2910
|
+
const newNo = Array.isArray(base.newNo) ? [...base.newNo] : [];
|
|
2911
|
+
let includeTokens = Array.isArray(base.tokens);
|
|
2912
|
+
let includeDiffKind = Array.isArray(base.diffKind);
|
|
2913
|
+
let includeOldNo = Array.isArray(base.oldNo);
|
|
2914
|
+
let includeNewNo = Array.isArray(base.newNo);
|
|
2637
2915
|
const baseStart = base.startIndex;
|
|
2638
2916
|
let expectedStart = baseStart + lines.length;
|
|
2639
2917
|
let j = startIndex + 1;
|
|
@@ -2641,6 +2919,7 @@ function mergeAppendLines(window2, startIndex) {
|
|
|
2641
2919
|
while (j < window2.length && mergedCount < APPEND_MERGE_LIMIT) {
|
|
2642
2920
|
const next = window2[j];
|
|
2643
2921
|
if (next.op === "appendLines" && next.at.blockId === base.at.blockId && next.at.nodeId === base.at.nodeId && typeof next.startIndex === "number" && next.startIndex === expectedStart) {
|
|
2922
|
+
const priorLineCount = lines.length;
|
|
2644
2923
|
lines.push(...next.lines ?? []);
|
|
2645
2924
|
const nextHighlights = Array.isArray(next.highlight) ? next.highlight : [];
|
|
2646
2925
|
const appendedCount = next.lines?.length ?? 0;
|
|
@@ -2654,6 +2933,50 @@ function mergeAppendLines(window2, startIndex) {
|
|
|
2654
2933
|
highlight.push(null);
|
|
2655
2934
|
}
|
|
2656
2935
|
}
|
|
2936
|
+
if (Array.isArray(next.tokens)) {
|
|
2937
|
+
if (!includeTokens) {
|
|
2938
|
+
tokens.push(...new Array(priorLineCount).fill(null));
|
|
2939
|
+
includeTokens = true;
|
|
2940
|
+
}
|
|
2941
|
+
for (let idx = 0; idx < appendedCount; idx++) {
|
|
2942
|
+
tokens.push(idx < next.tokens.length ? next.tokens[idx] ?? null : null);
|
|
2943
|
+
}
|
|
2944
|
+
} else if (includeTokens) {
|
|
2945
|
+
tokens.push(...new Array(appendedCount).fill(null));
|
|
2946
|
+
}
|
|
2947
|
+
if (Array.isArray(next.diffKind)) {
|
|
2948
|
+
if (!includeDiffKind) {
|
|
2949
|
+
diffKind.push(...new Array(priorLineCount).fill(null));
|
|
2950
|
+
includeDiffKind = true;
|
|
2951
|
+
}
|
|
2952
|
+
for (let idx = 0; idx < appendedCount; idx++) {
|
|
2953
|
+
diffKind.push(idx < next.diffKind.length ? next.diffKind[idx] ?? null : null);
|
|
2954
|
+
}
|
|
2955
|
+
} else if (includeDiffKind) {
|
|
2956
|
+
diffKind.push(...new Array(appendedCount).fill(null));
|
|
2957
|
+
}
|
|
2958
|
+
if (Array.isArray(next.oldNo)) {
|
|
2959
|
+
if (!includeOldNo) {
|
|
2960
|
+
oldNo.push(...new Array(priorLineCount).fill(null));
|
|
2961
|
+
includeOldNo = true;
|
|
2962
|
+
}
|
|
2963
|
+
for (let idx = 0; idx < appendedCount; idx++) {
|
|
2964
|
+
oldNo.push(idx < next.oldNo.length ? next.oldNo[idx] ?? null : null);
|
|
2965
|
+
}
|
|
2966
|
+
} else if (includeOldNo) {
|
|
2967
|
+
oldNo.push(...new Array(appendedCount).fill(null));
|
|
2968
|
+
}
|
|
2969
|
+
if (Array.isArray(next.newNo)) {
|
|
2970
|
+
if (!includeNewNo) {
|
|
2971
|
+
newNo.push(...new Array(priorLineCount).fill(null));
|
|
2972
|
+
includeNewNo = true;
|
|
2973
|
+
}
|
|
2974
|
+
for (let idx = 0; idx < appendedCount; idx++) {
|
|
2975
|
+
newNo.push(idx < next.newNo.length ? next.newNo[idx] ?? null : null);
|
|
2976
|
+
}
|
|
2977
|
+
} else if (includeNewNo) {
|
|
2978
|
+
newNo.push(...new Array(appendedCount).fill(null));
|
|
2979
|
+
}
|
|
2657
2980
|
expectedStart = baseStart + lines.length;
|
|
2658
2981
|
mergedCount++;
|
|
2659
2982
|
j++;
|
|
@@ -2664,7 +2987,11 @@ function mergeAppendLines(window2, startIndex) {
|
|
|
2664
2987
|
const combined = {
|
|
2665
2988
|
...base,
|
|
2666
2989
|
lines,
|
|
2667
|
-
highlight: highlight.length > 0 ? highlight : void 0
|
|
2990
|
+
highlight: highlight.length > 0 ? highlight : void 0,
|
|
2991
|
+
tokens: includeTokens && tokens.length > 0 ? tokens : void 0,
|
|
2992
|
+
diffKind: includeDiffKind && diffKind.length > 0 ? diffKind : void 0,
|
|
2993
|
+
oldNo: includeOldNo && oldNo.length > 0 ? oldNo : void 0,
|
|
2994
|
+
newNo: includeNewNo && newNo.length > 0 ? newNo : void 0
|
|
2668
2995
|
};
|
|
2669
2996
|
return { patch: combined, nextIndex: j };
|
|
2670
2997
|
}
|
|
@@ -3004,130 +3331,6 @@ var CustomStreamingMatcher = class {
|
|
|
3004
3331
|
return false;
|
|
3005
3332
|
}
|
|
3006
3333
|
};
|
|
3007
|
-
|
|
3008
|
-
// src/streaming/inline-streaming.ts
|
|
3009
|
-
var DEFAULT_FORMAT_ANTICIPATION = {
|
|
3010
|
-
inline: false,
|
|
3011
|
-
mathInline: false,
|
|
3012
|
-
mathBlock: false,
|
|
3013
|
-
html: false,
|
|
3014
|
-
mdx: false,
|
|
3015
|
-
regex: false
|
|
3016
|
-
};
|
|
3017
|
-
function normalizeFormatAnticipation(input) {
|
|
3018
|
-
if (input === true) {
|
|
3019
|
-
return { ...DEFAULT_FORMAT_ANTICIPATION, inline: true };
|
|
3020
|
-
}
|
|
3021
|
-
if (!input) {
|
|
3022
|
-
return { ...DEFAULT_FORMAT_ANTICIPATION };
|
|
3023
|
-
}
|
|
3024
|
-
return {
|
|
3025
|
-
inline: input.inline ?? false,
|
|
3026
|
-
mathInline: input.mathInline ?? false,
|
|
3027
|
-
mathBlock: input.mathBlock ?? false,
|
|
3028
|
-
html: input.html ?? false,
|
|
3029
|
-
mdx: input.mdx ?? false,
|
|
3030
|
-
regex: input.regex ?? false
|
|
3031
|
-
};
|
|
3032
|
-
}
|
|
3033
|
-
function prepareInlineStreamingContent(content, options) {
|
|
3034
|
-
const enableMath = options?.math !== false;
|
|
3035
|
-
const anticipation = normalizeFormatAnticipation(options?.formatAnticipation);
|
|
3036
|
-
const enableInlineAnticipation = anticipation.inline;
|
|
3037
|
-
const enableMathInlineAnticipation = anticipation.mathInline;
|
|
3038
|
-
const enableMathBlockAnticipation = anticipation.mathBlock;
|
|
3039
|
-
const stack = [];
|
|
3040
|
-
const toggleToken = (token) => {
|
|
3041
|
-
const last = stack[stack.length - 1];
|
|
3042
|
-
if (last === token) {
|
|
3043
|
-
stack.pop();
|
|
3044
|
-
} else {
|
|
3045
|
-
stack.push(token);
|
|
3046
|
-
}
|
|
3047
|
-
};
|
|
3048
|
-
let mathDisplayOpen = false;
|
|
3049
|
-
let mathDisplayCrossedNewline = false;
|
|
3050
|
-
for (let i = 0; i < content.length; i++) {
|
|
3051
|
-
const code = content.charCodeAt(i);
|
|
3052
|
-
if (code === 10 || code === 13) {
|
|
3053
|
-
if (mathDisplayOpen) {
|
|
3054
|
-
mathDisplayCrossedNewline = true;
|
|
3055
|
-
}
|
|
3056
|
-
continue;
|
|
3057
|
-
}
|
|
3058
|
-
if (code === 96) {
|
|
3059
|
-
toggleToken("code");
|
|
3060
|
-
continue;
|
|
3061
|
-
}
|
|
3062
|
-
if (code === 126 && i + 1 < content.length && content.charCodeAt(i + 1) === 126) {
|
|
3063
|
-
toggleToken("strike");
|
|
3064
|
-
i += 1;
|
|
3065
|
-
continue;
|
|
3066
|
-
}
|
|
3067
|
-
if (code === 42) {
|
|
3068
|
-
if (i + 1 < content.length && content.charCodeAt(i + 1) === 42) {
|
|
3069
|
-
toggleToken("strong");
|
|
3070
|
-
i += 1;
|
|
3071
|
-
} else {
|
|
3072
|
-
toggleToken("em");
|
|
3073
|
-
}
|
|
3074
|
-
continue;
|
|
3075
|
-
}
|
|
3076
|
-
if (enableMath && code === 36) {
|
|
3077
|
-
if (i + 1 < content.length && content.charCodeAt(i + 1) === 36) {
|
|
3078
|
-
toggleToken("math-display");
|
|
3079
|
-
if (mathDisplayOpen) {
|
|
3080
|
-
mathDisplayOpen = false;
|
|
3081
|
-
mathDisplayCrossedNewline = false;
|
|
3082
|
-
} else {
|
|
3083
|
-
mathDisplayOpen = true;
|
|
3084
|
-
mathDisplayCrossedNewline = false;
|
|
3085
|
-
}
|
|
3086
|
-
i += 1;
|
|
3087
|
-
} else {
|
|
3088
|
-
toggleToken("math-inline");
|
|
3089
|
-
}
|
|
3090
|
-
}
|
|
3091
|
-
}
|
|
3092
|
-
const hasIncompleteFormatting = stack.some((token) => token === "code" || token === "strike" || token === "strong" || token === "em");
|
|
3093
|
-
const hasIncompleteMathInline = stack.includes("math-inline");
|
|
3094
|
-
const hasIncompleteMathDisplay = stack.includes("math-display");
|
|
3095
|
-
const hasIncompleteMath = hasIncompleteMathInline || hasIncompleteMathDisplay;
|
|
3096
|
-
if (enableMath && hasIncompleteMath) {
|
|
3097
|
-
if (hasIncompleteMathInline && !enableMathInlineAnticipation) {
|
|
3098
|
-
return { kind: "raw", status: "raw", reason: "incomplete-math" };
|
|
3099
|
-
}
|
|
3100
|
-
if (hasIncompleteMathDisplay && (!enableMathBlockAnticipation || mathDisplayCrossedNewline)) {
|
|
3101
|
-
return { kind: "raw", status: "raw", reason: "incomplete-math" };
|
|
3102
|
-
}
|
|
3103
|
-
}
|
|
3104
|
-
if (hasIncompleteFormatting && !enableInlineAnticipation) {
|
|
3105
|
-
return { kind: "raw", status: "raw", reason: "incomplete-formatting" };
|
|
3106
|
-
}
|
|
3107
|
-
if (!hasIncompleteFormatting && !hasIncompleteMath) {
|
|
3108
|
-
return { kind: "parse", status: "complete", content, appended: "" };
|
|
3109
|
-
}
|
|
3110
|
-
const appendForToken = (token) => {
|
|
3111
|
-
switch (token) {
|
|
3112
|
-
case "code":
|
|
3113
|
-
return "`";
|
|
3114
|
-
case "strike":
|
|
3115
|
-
return "~~";
|
|
3116
|
-
case "strong":
|
|
3117
|
-
return "**";
|
|
3118
|
-
case "em":
|
|
3119
|
-
return "*";
|
|
3120
|
-
case "math-inline":
|
|
3121
|
-
return "$";
|
|
3122
|
-
case "math-display":
|
|
3123
|
-
return "$$";
|
|
3124
|
-
default:
|
|
3125
|
-
return "";
|
|
3126
|
-
}
|
|
3127
|
-
};
|
|
3128
|
-
const appended = stack.slice().reverse().map((token) => appendForToken(token)).join("");
|
|
3129
|
-
return { kind: "parse", status: "anticipated", content: content + appended, appended };
|
|
3130
|
-
}
|
|
3131
3334
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3132
3335
|
0 && (module.exports = {
|
|
3133
3336
|
CSP_HEADERS,
|
|
@@ -3167,12 +3370,14 @@ function prepareInlineStreamingContent(content, options) {
|
|
|
3167
3370
|
findClosingHtmlTag,
|
|
3168
3371
|
generateBlockId,
|
|
3169
3372
|
getBlockKey,
|
|
3373
|
+
getDefaultCodeWrapperAttributes,
|
|
3170
3374
|
initializeSecurity,
|
|
3171
3375
|
initializeTrustedTypesPolicy,
|
|
3172
3376
|
inlineNodesToPlainText,
|
|
3173
3377
|
isLikelyMdxComponent,
|
|
3174
3378
|
normalizeBlockquoteText,
|
|
3175
3379
|
normalizeFormatAnticipation,
|
|
3380
|
+
normalizeHighlightedLines,
|
|
3176
3381
|
normalizeLang,
|
|
3177
3382
|
parseCodeFenceInfo,
|
|
3178
3383
|
prepareInlineStreamingContent,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Block, NodeSnapshot, InlineNode, Patch } from './types.cjs';
|
|
2
|
-
export { ASTInlinePlugin, CoalescingMetrics, CompiledMdxModule, FormatAnticipationConfig, InlineHtmlDescriptor, InlinePlugin, LANGUAGE_ALIASES, MixedContentSegment, NodePath, PATCH_ROOT_ID, PatchMetrics, PerformanceMetrics, ProtectedRange, ProtectedRangeKind, RegexAnticipationPattern, RegexInlinePlugin, SetPropsBatchEntry, WorkerErrorPayload, WorkerIn, WorkerOut, WorkerPhase } from './types.cjs';
|
|
3
|
-
export { HighlightedLine, dedentIndentedCode, extractCodeLines, extractCodeWrapperAttributes, extractHighlightedLines, stripCodeFence } from './code-highlighting.cjs';
|
|
2
|
+
export { ASTInlinePlugin, CoalescingMetrics, CodeHighlightOutputMode, CodeHighlightingMode, CompiledMdxModule, DiffKind, FormatAnticipationConfig, InlineHtmlDescriptor, InlinePlugin, LANGUAGE_ALIASES, LazyTokenizationPriority, MixedContentSegment, NodePath, PATCH_ROOT_ID, PatchMetrics, PerformanceMetrics, ProtectedRange, ProtectedRangeKind, RegexAnticipationPattern, RegexInlinePlugin, SetPropsBatchEntry, TokenLineV1, TokenSpan, TokenStyle, WorkerErrorPayload, WorkerIn, WorkerOut, WorkerPhase } from './types.cjs';
|
|
3
|
+
export { HighlightedLine, dedentIndentedCode, extractCodeLines, extractCodeWrapperAttributes, extractHighlightedLines, getDefaultCodeWrapperAttributes, normalizeHighlightedLines, stripCodeFence } from './code-highlighting.cjs';
|
|
4
4
|
export { PerformanceTimer, StringBuffer, applyUpdate, debounce, detectMDX, generateBlockId, getBlockKey, normalizeBlockquoteText, normalizeLang, parseCodeFenceInfo, removeHeadingMarkers } from './utils.cjs';
|
|
5
5
|
export { MixedContentAutoCloseHtmlOptions, MixedContentAutoCloseMdxOptions, MixedContentOptions, extractMixedContentSegments, findClosingHtmlTag, isLikelyMdxComponent } from './mixed-content.cjs';
|
|
6
6
|
export { CSP_HEADERS, SanitizationPolicy, createSanitizationConfig, createTrustedHTML, initializeSecurity, initializeTrustedTypesPolicy, sanitizeCodeHTML, sanitizeHTML, sanitizeMathHTML, sanitizeURL } from './security.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Block, NodeSnapshot, InlineNode, Patch } from './types.js';
|
|
2
|
-
export { ASTInlinePlugin, CoalescingMetrics, CompiledMdxModule, FormatAnticipationConfig, InlineHtmlDescriptor, InlinePlugin, LANGUAGE_ALIASES, MixedContentSegment, NodePath, PATCH_ROOT_ID, PatchMetrics, PerformanceMetrics, ProtectedRange, ProtectedRangeKind, RegexAnticipationPattern, RegexInlinePlugin, SetPropsBatchEntry, WorkerErrorPayload, WorkerIn, WorkerOut, WorkerPhase } from './types.js';
|
|
3
|
-
export { HighlightedLine, dedentIndentedCode, extractCodeLines, extractCodeWrapperAttributes, extractHighlightedLines, stripCodeFence } from './code-highlighting.js';
|
|
2
|
+
export { ASTInlinePlugin, CoalescingMetrics, CodeHighlightOutputMode, CodeHighlightingMode, CompiledMdxModule, DiffKind, FormatAnticipationConfig, InlineHtmlDescriptor, InlinePlugin, LANGUAGE_ALIASES, LazyTokenizationPriority, MixedContentSegment, NodePath, PATCH_ROOT_ID, PatchMetrics, PerformanceMetrics, ProtectedRange, ProtectedRangeKind, RegexAnticipationPattern, RegexInlinePlugin, SetPropsBatchEntry, TokenLineV1, TokenSpan, TokenStyle, WorkerErrorPayload, WorkerIn, WorkerOut, WorkerPhase } from './types.js';
|
|
3
|
+
export { HighlightedLine, dedentIndentedCode, extractCodeLines, extractCodeWrapperAttributes, extractHighlightedLines, getDefaultCodeWrapperAttributes, normalizeHighlightedLines, stripCodeFence } from './code-highlighting.js';
|
|
4
4
|
export { PerformanceTimer, StringBuffer, applyUpdate, debounce, detectMDX, generateBlockId, getBlockKey, normalizeBlockquoteText, normalizeLang, parseCodeFenceInfo, removeHeadingMarkers } from './utils.js';
|
|
5
5
|
export { MixedContentAutoCloseHtmlOptions, MixedContentAutoCloseMdxOptions, MixedContentOptions, extractMixedContentSegments, findClosingHtmlTag, isLikelyMdxComponent } from './mixed-content.js';
|
|
6
6
|
export { CSP_HEADERS, SanitizationPolicy, createSanitizationConfig, createTrustedHTML, initializeSecurity, initializeTrustedTypesPolicy, sanitizeCodeHTML, sanitizeHTML, sanitizeMathHTML, sanitizeURL } from './security.js';
|