@stream-mdx/react 0.4.0 → 0.5.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 +14 -4
- package/README.md +65 -15
- package/dist/components/bottom-stick-scroll-area.cjs +344 -0
- package/dist/components/bottom-stick-scroll-area.d.cts +36 -0
- package/dist/components/bottom-stick-scroll-area.d.ts +36 -0
- package/dist/components/bottom-stick-scroll-area.mjs +320 -0
- package/dist/components/index.cjs +503 -172
- package/dist/components/index.d.cts +3 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.mjs +350 -22
- package/dist/{index-D2MYusAM.d.cts → index-BVhp_pcF.d.ts} +3 -0
- package/dist/{index-D2MYusAM.d.ts → index-EaeouYp2.d.cts} +3 -0
- package/dist/index.cjs +1472 -486
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.mjs +1256 -272
- package/dist/mdx-client.cjs +1 -1
- package/dist/mdx-client.mjs +1 -1
- package/dist/mdx-coordinator.cjs +28 -7
- package/dist/mdx-coordinator.d.cts +2 -2
- package/dist/mdx-coordinator.d.ts +2 -2
- package/dist/mdx-coordinator.mjs +28 -7
- package/dist/renderer/node-views.cjs +271 -26
- package/dist/renderer/node-views.d.cts +3 -1
- package/dist/renderer/node-views.d.ts +3 -1
- package/dist/renderer/node-views.mjs +272 -27
- package/dist/renderer/patch-batching.cjs +2 -0
- package/dist/renderer/patch-batching.d.cts +1 -1
- package/dist/renderer/patch-batching.d.ts +1 -1
- package/dist/renderer/patch-batching.mjs +2 -1
- package/dist/renderer/patch-commit-scheduler.cjs +82 -30
- package/dist/renderer/patch-commit-scheduler.d.cts +15 -3
- package/dist/renderer/patch-commit-scheduler.d.ts +15 -3
- package/dist/renderer/patch-commit-scheduler.mjs +84 -30
- package/dist/renderer/store.cjs +382 -36
- package/dist/renderer/store.d.cts +3 -0
- package/dist/renderer/store.d.ts +3 -0
- package/dist/renderer/store.mjs +382 -36
- package/dist/renderer.cjs +758 -114
- package/dist/renderer.d.cts +3 -1
- package/dist/renderer.d.ts +3 -1
- package/dist/renderer.mjs +760 -116
- package/dist/server.cjs +669 -71
- package/dist/server.d.cts +5 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.mjs +670 -72
- package/dist/{streaming-markdown-DOc2uLiP.d.ts → streaming-markdown-CEI9eDZm.d.ts} +3 -1
- package/dist/{streaming-markdown-D-JcByd9.d.cts → streaming-markdown-DRisClXb.d.cts} +3 -1
- package/dist/streaming-markdown.cjs +788 -121
- package/dist/streaming-markdown.d.cts +4 -2
- package/dist/streaming-markdown.d.ts +4 -2
- package/dist/streaming-markdown.mjs +790 -123
- package/dist/utils/inline-html.d.cts +3 -1
- package/dist/utils/inline-html.d.ts +3 -1
- package/package.json +14 -3
- package/shadcn/README.md +28 -0
- package/shadcn/bottom-stick-scroll-area.tsx +358 -0
package/dist/renderer.mjs
CHANGED
|
@@ -81,7 +81,7 @@ var init_mdx_client = __esm({
|
|
|
81
81
|
if (block.type !== "mdx") {
|
|
82
82
|
throw new Error("Block is not MDX type");
|
|
83
83
|
}
|
|
84
|
-
const cacheKey = block.id
|
|
84
|
+
const cacheKey = `${block.id}\0${block.payload.raw ?? ""}`;
|
|
85
85
|
const cachedPromise = this.cache.get(cacheKey);
|
|
86
86
|
if (cachedPromise) {
|
|
87
87
|
return cachedPromise;
|
|
@@ -921,7 +921,11 @@ var defaultInlineComponents = {
|
|
|
921
921
|
const n = number ?? "?";
|
|
922
922
|
const href = number ? `#fn:${n}` : void 0;
|
|
923
923
|
const id = number ? `fnref:${n}` : void 0;
|
|
924
|
-
return React4.createElement(
|
|
924
|
+
return React4.createElement(
|
|
925
|
+
"sup",
|
|
926
|
+
{ className: "footnote-ref" },
|
|
927
|
+
React4.createElement("a", { href, id, "data-label": label, style: { color: "var(--foreground)", textDecoration: "underline" } }, String(n))
|
|
928
|
+
);
|
|
925
929
|
}
|
|
926
930
|
};
|
|
927
931
|
var defaultBlockComponents = {
|
|
@@ -1064,7 +1068,7 @@ var defaultBlockComponents = {
|
|
|
1064
1068
|
dangerouslySetInnerHTML: { __html: htmlString }
|
|
1065
1069
|
});
|
|
1066
1070
|
},
|
|
1067
|
-
mdx: ({ compiledRef, compiledModule, status, errorMessage
|
|
1071
|
+
mdx: ({ compiledRef, compiledModule, status, errorMessage }) => {
|
|
1068
1072
|
const [Comp, setComp] = React4.useState(null);
|
|
1069
1073
|
const [internalError, setInternalError] = React4.useState(null);
|
|
1070
1074
|
const [renderError, setRenderError] = React4.useState(null);
|
|
@@ -1165,7 +1169,6 @@ var defaultBlockComponents = {
|
|
|
1165
1169
|
const waitingForVisibility = deferHydration && !shouldHydrate && Boolean(resolvedId);
|
|
1166
1170
|
const pendingLabel = waitingForVisibility ? "MDX ready (hydrate on view)\u2026" : compileMode === "worker" ? "Compiling MDX (client)\u2026" : "Compiling MDX (server)\u2026";
|
|
1167
1171
|
const message = failureMessage ?? (compileMode === "worker" ? "MDX compilation failed in client mode. Try switching back to server rendering or restarting the stream." : "MDX compilation failed. Try restarting the stream.");
|
|
1168
|
-
const rawFallback = typeof raw === "string" && raw.trim().length > 0 ? React4.createElement("pre", { className: "markdown-mdx-fallback" }, raw) : null;
|
|
1169
1172
|
const allowRetry = Boolean(internalError || renderError);
|
|
1170
1173
|
const retryButton = allowRetry ? React4.createElement(
|
|
1171
1174
|
"button",
|
|
@@ -1177,9 +1180,10 @@ var defaultBlockComponents = {
|
|
|
1177
1180
|
"Retry hydration"
|
|
1178
1181
|
) : null;
|
|
1179
1182
|
const errorPanel = React4.createElement(
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
React4.createElement(
|
|
1183
|
+
React4.Fragment,
|
|
1184
|
+
null,
|
|
1185
|
+
React4.createElement("strong", null, "MDX failed"),
|
|
1186
|
+
React4.createElement("div", null, message)
|
|
1183
1187
|
);
|
|
1184
1188
|
if (Comp && !failureMessage) {
|
|
1185
1189
|
return React4.createElement(
|
|
@@ -1202,14 +1206,13 @@ var defaultBlockComponents = {
|
|
|
1202
1206
|
return React4.createElement(
|
|
1203
1207
|
"div",
|
|
1204
1208
|
{
|
|
1205
|
-
className: "markdown-mdx",
|
|
1209
|
+
className: "markdown-mdx error",
|
|
1206
1210
|
ref: containerRef,
|
|
1207
1211
|
"data-mdx-ref": pendingId,
|
|
1208
1212
|
"data-mdx-status": "error",
|
|
1209
1213
|
"data-mdx-mode": compileMode
|
|
1210
1214
|
},
|
|
1211
1215
|
errorPanel,
|
|
1212
|
-
rawFallback,
|
|
1213
1216
|
retryButton
|
|
1214
1217
|
);
|
|
1215
1218
|
}
|
|
@@ -1236,7 +1239,16 @@ var defaultBlockComponents = {
|
|
|
1236
1239
|
{ key: item.number, id: `fn:${item.number}` },
|
|
1237
1240
|
renderInlineNodes(item.inlines, defaultInlineComponents),
|
|
1238
1241
|
" ",
|
|
1239
|
-
React4.createElement(
|
|
1242
|
+
React4.createElement(
|
|
1243
|
+
"a",
|
|
1244
|
+
{
|
|
1245
|
+
href: `#fnref:${item.number}`,
|
|
1246
|
+
className: "footnote-backref",
|
|
1247
|
+
"aria-label": "Back to content",
|
|
1248
|
+
style: { color: "var(--foreground)", textDecoration: "underline" }
|
|
1249
|
+
},
|
|
1250
|
+
"\u21A9"
|
|
1251
|
+
)
|
|
1240
1252
|
)
|
|
1241
1253
|
);
|
|
1242
1254
|
return React4.createElement("section", { className: "footnotes" }, React4.createElement("hr", {}), React4.createElement("ol", {}, listItems));
|
|
@@ -1782,7 +1794,10 @@ function useCodeHighlightRequester() {
|
|
|
1782
1794
|
}
|
|
1783
1795
|
|
|
1784
1796
|
// src/renderer/patch-batching.ts
|
|
1785
|
-
import { isHeavyPatch, splitPatchBatch } from "@stream-mdx/core/perf/patch-batching";
|
|
1797
|
+
import { getPatchKind, isHeavyPatch, splitPatchBatch } from "@stream-mdx/core/perf/patch-batching";
|
|
1798
|
+
|
|
1799
|
+
// src/renderer/patch-commit-scheduler.ts
|
|
1800
|
+
import { getPatchKind as getPatchKind2 } from "@stream-mdx/core/perf/patch-batching";
|
|
1786
1801
|
|
|
1787
1802
|
// src/renderer/patch-coalescing.ts
|
|
1788
1803
|
import {
|
|
@@ -1800,6 +1815,9 @@ var COALESCING_DURATION_ACTIVATE_MS = 6;
|
|
|
1800
1815
|
var COALESCING_DURATION_DEACTIVATE_MS = 4;
|
|
1801
1816
|
var RETAIN_TOUCHED_IN_HISTORY = typeof process !== "undefined" && process.env ? process.env.NODE_ENV !== "production" : true;
|
|
1802
1817
|
var EMPTY_TOUCHED_SET = /* @__PURE__ */ new Set();
|
|
1818
|
+
function shouldSkipCoalescing(patches) {
|
|
1819
|
+
return patches.length <= 1;
|
|
1820
|
+
}
|
|
1803
1821
|
function getDefaultNow() {
|
|
1804
1822
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
1805
1823
|
return () => performance.now();
|
|
@@ -1826,8 +1844,9 @@ function getDefaultCancelRaf() {
|
|
|
1826
1844
|
}
|
|
1827
1845
|
var PatchCommitScheduler = class {
|
|
1828
1846
|
constructor(params) {
|
|
1829
|
-
this.
|
|
1830
|
-
this.
|
|
1847
|
+
this.semanticQueue = [];
|
|
1848
|
+
this.enrichmentHighQueue = [];
|
|
1849
|
+
this.enrichmentLowQueue = [];
|
|
1831
1850
|
this.scheduled = false;
|
|
1832
1851
|
this.flushing = false;
|
|
1833
1852
|
this.scheduledHandle = null;
|
|
@@ -1839,6 +1858,7 @@ var PatchCommitScheduler = class {
|
|
|
1839
1858
|
this.scheduleToken = 0;
|
|
1840
1859
|
this.coalescingDurationSamples = [];
|
|
1841
1860
|
this.adaptiveBudgetActive = false;
|
|
1861
|
+
this.flushCount = 0;
|
|
1842
1862
|
this.store = params.store;
|
|
1843
1863
|
this.onFlush = params.onFlush;
|
|
1844
1864
|
this.frameBudgetMs = Math.max(1, params.options?.frameBudgetMs ?? 10);
|
|
@@ -1854,6 +1874,8 @@ var PatchCommitScheduler = class {
|
|
|
1854
1874
|
this.maxLowPriorityBatchesPerFlush = params.options?.maxLowPriorityBatchesPerFlush ?? 2;
|
|
1855
1875
|
this.urgentQueueThreshold = Math.max(1, params.options?.urgentQueueThreshold ?? 4);
|
|
1856
1876
|
this.historyLimit = Math.max(1, params.options?.historyLimit ?? 200);
|
|
1877
|
+
this.startupMicrotaskFlushes = Math.max(0, Math.floor(params.options?.startupMicrotaskFlushes ?? 0));
|
|
1878
|
+
this.adaptiveBudgeting = params.options?.adaptiveBudgeting ?? true;
|
|
1857
1879
|
const requestedBatch = params.options?.batch;
|
|
1858
1880
|
if (requestedBatch === "microtask") {
|
|
1859
1881
|
this.batchStrategy = "microtask";
|
|
@@ -1880,19 +1902,23 @@ var PatchCommitScheduler = class {
|
|
|
1880
1902
|
patches: input.patches,
|
|
1881
1903
|
meta: input.meta ?? {},
|
|
1882
1904
|
receivedAt: input.meta?.receivedAt ?? this.now(),
|
|
1905
|
+
kind: input.meta?.kind === "semantic" || input.meta?.kind === "enrichment" ? input.meta.kind : input.patches.some((patch) => getPatchKind2(patch) === "semantic") ? "semantic" : "enrichment",
|
|
1883
1906
|
priority: input.meta?.priority === "low" ? "low" : "high"
|
|
1884
1907
|
};
|
|
1885
|
-
if (batch.
|
|
1886
|
-
|
|
1908
|
+
if (batch.kind === "semantic") {
|
|
1909
|
+
batch.priority = "high";
|
|
1910
|
+
this.semanticQueue.push(batch);
|
|
1911
|
+
} else if (batch.priority === "low") {
|
|
1912
|
+
this.enrichmentLowQueue.push(batch);
|
|
1887
1913
|
} else {
|
|
1888
|
-
this.
|
|
1914
|
+
this.enrichmentHighQueue.push(batch);
|
|
1889
1915
|
}
|
|
1890
1916
|
if (!this.paused) {
|
|
1891
1917
|
this.schedule();
|
|
1892
1918
|
}
|
|
1893
1919
|
}
|
|
1894
1920
|
flushAll() {
|
|
1895
|
-
if (this.
|
|
1921
|
+
if (this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0 && !this.flushing) {
|
|
1896
1922
|
return null;
|
|
1897
1923
|
}
|
|
1898
1924
|
this.cancelScheduled();
|
|
@@ -1902,9 +1928,11 @@ var PatchCommitScheduler = class {
|
|
|
1902
1928
|
}
|
|
1903
1929
|
clear() {
|
|
1904
1930
|
this.cancelScheduled();
|
|
1905
|
-
this.
|
|
1906
|
-
this.
|
|
1931
|
+
this.semanticQueue = [];
|
|
1932
|
+
this.enrichmentHighQueue = [];
|
|
1933
|
+
this.enrichmentLowQueue = [];
|
|
1907
1934
|
this.flushing = false;
|
|
1935
|
+
this.flushCount = 0;
|
|
1908
1936
|
this.coalescingDurationSamples = [];
|
|
1909
1937
|
this.adaptiveBudgetActive = false;
|
|
1910
1938
|
this.adaptiveHighBatchCap = void 0;
|
|
@@ -1912,10 +1940,10 @@ var PatchCommitScheduler = class {
|
|
|
1912
1940
|
this.maybeResolveIdle();
|
|
1913
1941
|
}
|
|
1914
1942
|
getPendingCount() {
|
|
1915
|
-
return this.
|
|
1943
|
+
return this.semanticQueue.length + this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
1916
1944
|
}
|
|
1917
1945
|
isIdle() {
|
|
1918
|
-
return !this.flushing && !this.scheduled && this.
|
|
1946
|
+
return !this.flushing && !this.scheduled && this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0;
|
|
1919
1947
|
}
|
|
1920
1948
|
awaitIdle() {
|
|
1921
1949
|
if (this.isIdle()) {
|
|
@@ -1955,7 +1983,8 @@ var PatchCommitScheduler = class {
|
|
|
1955
1983
|
this.runFlush(this.frameBudgetMs, false);
|
|
1956
1984
|
this.maybeResolveIdle();
|
|
1957
1985
|
};
|
|
1958
|
-
|
|
1986
|
+
const useStartupMicrotask = this.batchStrategy !== "microtask" && this.startupMicrotaskFlushes > 0 && this.flushCount < this.startupMicrotaskFlushes && typeof queueMicrotask === "function";
|
|
1987
|
+
if ((this.batchStrategy === "microtask" || useStartupMicrotask) && typeof queueMicrotask === "function") {
|
|
1959
1988
|
this.scheduledViaRaf = false;
|
|
1960
1989
|
this.scheduledHandle = token;
|
|
1961
1990
|
queueMicrotask(execute);
|
|
@@ -1985,12 +2014,14 @@ var PatchCommitScheduler = class {
|
|
|
1985
2014
|
if (this.paused && !manual) {
|
|
1986
2015
|
return null;
|
|
1987
2016
|
}
|
|
1988
|
-
if (this.
|
|
2017
|
+
if (this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0) {
|
|
1989
2018
|
return null;
|
|
1990
2019
|
}
|
|
1991
2020
|
this.flushing = true;
|
|
1992
2021
|
const startedAt = this.now();
|
|
1993
|
-
const
|
|
2022
|
+
const initialSemanticQueueSize = this.semanticQueue.length;
|
|
2023
|
+
const initialEnrichmentQueueSize = this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2024
|
+
const initialQueueSize = initialSemanticQueueSize + initialEnrichmentQueueSize;
|
|
1994
2025
|
const batches = [];
|
|
1995
2026
|
let totalInputPatches = 0;
|
|
1996
2027
|
let totalAppliedPatches = 0;
|
|
@@ -2005,7 +2036,15 @@ var PatchCommitScheduler = class {
|
|
|
2005
2036
|
consumed += 1;
|
|
2006
2037
|
const applyStart = this.now();
|
|
2007
2038
|
const queueDelayMs = Math.max(0, applyStart - next.receivedAt);
|
|
2008
|
-
|
|
2039
|
+
let coalesced;
|
|
2040
|
+
let coalescingMetrics;
|
|
2041
|
+
if (shouldSkipCoalescing(next.patches)) {
|
|
2042
|
+
coalesced = next.patches;
|
|
2043
|
+
} else {
|
|
2044
|
+
const result = coalescePatchesWithMetrics(next.patches, DEFAULT_COALESCE_CONFIG);
|
|
2045
|
+
coalesced = result.patches;
|
|
2046
|
+
coalescingMetrics = result.metrics;
|
|
2047
|
+
}
|
|
2009
2048
|
const touched = this.store.applyPatches(coalesced, {
|
|
2010
2049
|
coalesced: true,
|
|
2011
2050
|
metrics: coalescingMetrics
|
|
@@ -2025,6 +2064,7 @@ var PatchCommitScheduler = class {
|
|
|
2025
2064
|
receivedAt: next.receivedAt,
|
|
2026
2065
|
appliedAt: applyStart,
|
|
2027
2066
|
priority: next.priority,
|
|
2067
|
+
kind: next.kind,
|
|
2028
2068
|
coalescing: coalescingMetrics
|
|
2029
2069
|
});
|
|
2030
2070
|
if (maxBatches && batches.length - startingBatchCount >= maxBatches) {
|
|
@@ -2041,27 +2081,32 @@ var PatchCommitScheduler = class {
|
|
|
2041
2081
|
queue.splice(0, consumed);
|
|
2042
2082
|
}
|
|
2043
2083
|
};
|
|
2044
|
-
|
|
2084
|
+
processQueue(this.semanticQueue, void 0, Number.POSITIVE_INFINITY);
|
|
2085
|
+
const initialHighQueueSize = this.enrichmentHighQueue.length;
|
|
2045
2086
|
const configuredHighLimit = manual || !this.maxBatchesPerFlush ? void 0 : initialHighQueueSize > this.maxBatchesPerFlush ? void 0 : this.maxBatchesPerFlush;
|
|
2046
|
-
const highBatchLimit = this.adaptiveHighBatchCap ?? configuredHighLimit;
|
|
2047
|
-
processQueue(this.
|
|
2087
|
+
const highBatchLimit = this.adaptiveBudgeting ? this.adaptiveHighBatchCap ?? configuredHighLimit : configuredHighLimit;
|
|
2088
|
+
processQueue(this.enrichmentHighQueue, highBatchLimit, budgetMs);
|
|
2048
2089
|
if (manual) {
|
|
2049
|
-
processQueue(this.
|
|
2050
|
-
} else if (this.
|
|
2090
|
+
processQueue(this.enrichmentLowQueue, void 0, Number.POSITIVE_INFINITY);
|
|
2091
|
+
} else if (this.enrichmentLowQueue.length > 0) {
|
|
2051
2092
|
elapsed = this.now() - startedAt;
|
|
2052
2093
|
const budgetForLow = Math.max(0, this.lowPriorityFrameBudgetMs - elapsed);
|
|
2053
|
-
|
|
2054
|
-
|
|
2094
|
+
const processedHigherPriorityWork = batches.length > 0;
|
|
2095
|
+
if (budgetForLow > 0 || !processedHigherPriorityWork) {
|
|
2096
|
+
const initialLowQueueSize = this.enrichmentLowQueue.length;
|
|
2055
2097
|
const configuredLowLimit = manual || !this.maxLowPriorityBatchesPerFlush ? void 0 : initialLowQueueSize > this.maxLowPriorityBatchesPerFlush ? void 0 : this.maxLowPriorityBatchesPerFlush;
|
|
2056
|
-
const lowBatchLimit = this.adaptiveLowBatchCap ?? configuredLowLimit;
|
|
2057
|
-
processQueue(this.
|
|
2098
|
+
const lowBatchLimit = this.adaptiveBudgeting ? this.adaptiveLowBatchCap ?? configuredLowLimit : configuredLowLimit;
|
|
2099
|
+
processQueue(this.enrichmentLowQueue, lowBatchLimit, budgetForLow);
|
|
2058
2100
|
}
|
|
2059
2101
|
}
|
|
2060
2102
|
this.flushing = false;
|
|
2061
2103
|
const completedAt = this.now();
|
|
2062
2104
|
const totalDurationMs = completedAt - startedAt;
|
|
2063
|
-
const
|
|
2105
|
+
const remainingSemantic = this.semanticQueue.length;
|
|
2106
|
+
const remainingEnrichment = this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2107
|
+
const remaining = remainingSemantic + remainingEnrichment;
|
|
2064
2108
|
if (batches.length > 0) {
|
|
2109
|
+
this.flushCount += 1;
|
|
2065
2110
|
try {
|
|
2066
2111
|
this.onFlush({
|
|
2067
2112
|
batches,
|
|
@@ -2069,7 +2114,11 @@ var PatchCommitScheduler = class {
|
|
|
2069
2114
|
totalAppliedPatches,
|
|
2070
2115
|
totalDurationMs,
|
|
2071
2116
|
remainingQueueSize: remaining,
|
|
2117
|
+
remainingSemanticQueueSize: remainingSemantic,
|
|
2118
|
+
remainingEnrichmentQueueSize: remainingEnrichment,
|
|
2072
2119
|
queueDepthBefore: initialQueueSize,
|
|
2120
|
+
semanticQueueDepthBefore: initialSemanticQueueSize,
|
|
2121
|
+
enrichmentQueueDepthBefore: initialEnrichmentQueueSize,
|
|
2073
2122
|
flushStartedAt: startedAt,
|
|
2074
2123
|
flushCompletedAt: completedAt
|
|
2075
2124
|
});
|
|
@@ -2080,21 +2129,27 @@ var PatchCommitScheduler = class {
|
|
|
2080
2129
|
if (remaining > 0 && !this.paused) {
|
|
2081
2130
|
this.schedule();
|
|
2082
2131
|
}
|
|
2083
|
-
const coalescingStats = this.computeCoalescingDurationStats();
|
|
2084
|
-
this.
|
|
2085
|
-
|
|
2132
|
+
const coalescingStats = this.adaptiveBudgeting ? this.computeCoalescingDurationStats() : { sampleCount: this.coalescingDurationSamples.length, p95: null };
|
|
2133
|
+
if (this.adaptiveBudgeting) {
|
|
2134
|
+
this.updateAdaptiveBudget(coalescingStats.p95);
|
|
2135
|
+
}
|
|
2136
|
+
const adaptiveState = this.adaptiveBudgeting ? this.snapshotAdaptiveBudget(coalescingStats.p95 ?? null) : void 0;
|
|
2086
2137
|
const flushResult = batches.length > 0 ? {
|
|
2087
2138
|
batches,
|
|
2088
2139
|
totalPatches: totalInputPatches,
|
|
2089
2140
|
totalAppliedPatches,
|
|
2090
2141
|
totalDurationMs,
|
|
2091
2142
|
remainingQueueSize: remaining,
|
|
2143
|
+
remainingSemanticQueueSize: remainingSemantic,
|
|
2144
|
+
remainingEnrichmentQueueSize: remainingEnrichment,
|
|
2092
2145
|
queueDepthBefore: initialQueueSize,
|
|
2146
|
+
semanticQueueDepthBefore: initialSemanticQueueSize,
|
|
2147
|
+
enrichmentQueueDepthBefore: initialEnrichmentQueueSize,
|
|
2093
2148
|
flushStartedAt: startedAt,
|
|
2094
2149
|
flushCompletedAt: completedAt,
|
|
2095
2150
|
coalescingDurationP95: coalescingStats.p95 ?? void 0,
|
|
2096
2151
|
coalescingDurationSampleCount: coalescingStats.sampleCount,
|
|
2097
|
-
adaptiveBudgetActive: adaptiveState
|
|
2152
|
+
adaptiveBudgetActive: adaptiveState?.active,
|
|
2098
2153
|
adaptiveBudgetState: adaptiveState
|
|
2099
2154
|
} : null;
|
|
2100
2155
|
if (flushResult) {
|
|
@@ -2130,6 +2185,9 @@ var PatchCommitScheduler = class {
|
|
|
2130
2185
|
};
|
|
2131
2186
|
}
|
|
2132
2187
|
updateAdaptiveBudget(p95) {
|
|
2188
|
+
if (!this.adaptiveBudgeting) {
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2133
2191
|
if (p95 !== null && p95 > COALESCING_DURATION_ACTIVATE_MS) {
|
|
2134
2192
|
if (!this.adaptiveBudgetActive) {
|
|
2135
2193
|
this.adaptiveBudgetActive = true;
|
|
@@ -2203,11 +2261,13 @@ var PatchCommitScheduler = class {
|
|
|
2203
2261
|
}
|
|
2204
2262
|
restart() {
|
|
2205
2263
|
this.cancelScheduled();
|
|
2206
|
-
this.
|
|
2207
|
-
this.
|
|
2264
|
+
this.semanticQueue = [];
|
|
2265
|
+
this.enrichmentHighQueue = [];
|
|
2266
|
+
this.enrichmentLowQueue = [];
|
|
2208
2267
|
this.flushing = false;
|
|
2209
2268
|
this.sequence = 0;
|
|
2210
2269
|
this.history = [];
|
|
2270
|
+
this.flushCount = 0;
|
|
2211
2271
|
this.scheduleToken++;
|
|
2212
2272
|
this.paused = false;
|
|
2213
2273
|
this.coalescingDurationSamples = [];
|
|
@@ -2254,6 +2314,12 @@ var PatchCommitScheduler = class {
|
|
|
2254
2314
|
if (typeof options.historyLimit !== "undefined") {
|
|
2255
2315
|
this.setHistoryLimit(options.historyLimit);
|
|
2256
2316
|
}
|
|
2317
|
+
if (typeof options.startupMicrotaskFlushes !== "undefined") {
|
|
2318
|
+
this.startupMicrotaskFlushes = Math.max(0, Math.floor(options.startupMicrotaskFlushes));
|
|
2319
|
+
}
|
|
2320
|
+
if (typeof options.adaptiveBudgeting !== "undefined") {
|
|
2321
|
+
this.adaptiveBudgeting = options.adaptiveBudgeting;
|
|
2322
|
+
}
|
|
2257
2323
|
if (typeof options.batch !== "undefined") {
|
|
2258
2324
|
const requestedBatch = options.batch;
|
|
2259
2325
|
if (requestedBatch === "microtask") {
|
|
@@ -2288,6 +2354,7 @@ import {
|
|
|
2288
2354
|
sanitizeHTML as sanitizeHTML2,
|
|
2289
2355
|
PATCH_ROOT_ID
|
|
2290
2356
|
} from "@stream-mdx/core";
|
|
2357
|
+
import { getPatchKind as getPatchKind3 } from "@stream-mdx/core/perf/patch-batching";
|
|
2291
2358
|
|
|
2292
2359
|
// src/renderer/list-utils.ts
|
|
2293
2360
|
function updateNodeDepth(node, depth) {
|
|
@@ -2383,12 +2450,28 @@ function snapshotToBlock(node) {
|
|
|
2383
2450
|
}
|
|
2384
2451
|
return null;
|
|
2385
2452
|
}
|
|
2386
|
-
var
|
|
2387
|
-
var
|
|
2453
|
+
var nodeSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
2454
|
+
var childrenSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
2388
2455
|
var NODE_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
2389
2456
|
var CHILDREN_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
2390
2457
|
var NODE_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(NODE_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
2391
2458
|
var CHILDREN_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(CHILDREN_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
2459
|
+
function getNodeSnapshotCacheForMap(map) {
|
|
2460
|
+
let cache = nodeSnapshotCacheByMap.get(map);
|
|
2461
|
+
if (!cache) {
|
|
2462
|
+
cache = /* @__PURE__ */ new Map();
|
|
2463
|
+
nodeSnapshotCacheByMap.set(map, cache);
|
|
2464
|
+
}
|
|
2465
|
+
return cache;
|
|
2466
|
+
}
|
|
2467
|
+
function getChildrenSnapshotCacheForMap(map) {
|
|
2468
|
+
let cache = childrenSnapshotCacheByMap.get(map);
|
|
2469
|
+
if (!cache) {
|
|
2470
|
+
cache = /* @__PURE__ */ new Map();
|
|
2471
|
+
childrenSnapshotCacheByMap.set(map, cache);
|
|
2472
|
+
}
|
|
2473
|
+
return cache;
|
|
2474
|
+
}
|
|
2392
2475
|
function pruneCache(cache, max, buffer) {
|
|
2393
2476
|
if (cache.size <= max + buffer) return;
|
|
2394
2477
|
let remaining = cache.size - max;
|
|
@@ -2398,6 +2481,14 @@ function pruneCache(cache, max, buffer) {
|
|
|
2398
2481
|
if (remaining <= 0) break;
|
|
2399
2482
|
}
|
|
2400
2483
|
}
|
|
2484
|
+
function deleteSnapshotCacheEntry(map, id) {
|
|
2485
|
+
getNodeSnapshotCacheForMap(map).delete(id);
|
|
2486
|
+
getChildrenSnapshotCacheForMap(map).delete(id);
|
|
2487
|
+
}
|
|
2488
|
+
function clearSnapshotCaches(map) {
|
|
2489
|
+
getNodeSnapshotCacheForMap(map).clear();
|
|
2490
|
+
getChildrenSnapshotCacheForMap(map).clear();
|
|
2491
|
+
}
|
|
2401
2492
|
var EMPTY_CHILDREN = Object.freeze([]);
|
|
2402
2493
|
var EMPTY_NODE_SNAPSHOT = Object.freeze({ version: -1, node: void 0 });
|
|
2403
2494
|
var EMPTY_CHILDREN_SNAPSHOT = Object.freeze({
|
|
@@ -2565,9 +2656,57 @@ function createRootRecord() {
|
|
|
2565
2656
|
parentId: null,
|
|
2566
2657
|
children: [],
|
|
2567
2658
|
props: {},
|
|
2568
|
-
version: 0
|
|
2659
|
+
version: 0,
|
|
2660
|
+
blockEpoch: 0
|
|
2569
2661
|
};
|
|
2570
2662
|
}
|
|
2663
|
+
function readNumericEpoch(value) {
|
|
2664
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
2665
|
+
return void 0;
|
|
2666
|
+
}
|
|
2667
|
+
return value;
|
|
2668
|
+
}
|
|
2669
|
+
function readSnapshotBlockEpoch(snapshot) {
|
|
2670
|
+
return readNumericEpoch(snapshot.meta?.blockEpoch);
|
|
2671
|
+
}
|
|
2672
|
+
function readPatchBlockEpoch(patch) {
|
|
2673
|
+
if (patch.op === "setHTML") {
|
|
2674
|
+
return readNumericEpoch(patch.patchMeta?.blockEpoch);
|
|
2675
|
+
}
|
|
2676
|
+
return readNumericEpoch(patch.meta?.blockEpoch);
|
|
2677
|
+
}
|
|
2678
|
+
function readPatchParseEpoch(patch) {
|
|
2679
|
+
if (patch.op === "setHTML") {
|
|
2680
|
+
return readNumericEpoch(patch.patchMeta?.parseEpoch);
|
|
2681
|
+
}
|
|
2682
|
+
return readNumericEpoch(patch.meta?.parseEpoch);
|
|
2683
|
+
}
|
|
2684
|
+
function readPatchTx(patch) {
|
|
2685
|
+
if (patch.op === "setHTML") {
|
|
2686
|
+
return readNumericEpoch(patch.patchMeta?.tx);
|
|
2687
|
+
}
|
|
2688
|
+
return readNumericEpoch(patch.meta?.tx);
|
|
2689
|
+
}
|
|
2690
|
+
function assignSubtreeBlockEpoch(map, rootId, blockEpoch, touched) {
|
|
2691
|
+
const root = map.get(rootId);
|
|
2692
|
+
if (!root) return;
|
|
2693
|
+
const stack = [root];
|
|
2694
|
+
while (stack.length > 0) {
|
|
2695
|
+
const node = stack.pop();
|
|
2696
|
+
if (!node) continue;
|
|
2697
|
+
if (node.blockEpoch !== blockEpoch) {
|
|
2698
|
+
node.blockEpoch = blockEpoch;
|
|
2699
|
+
node.version += 1;
|
|
2700
|
+
touched?.add(node.id);
|
|
2701
|
+
}
|
|
2702
|
+
for (const childId of node.children) {
|
|
2703
|
+
const child = map.get(childId);
|
|
2704
|
+
if (child) {
|
|
2705
|
+
stack.push(child);
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2571
2710
|
function ensureArray(value) {
|
|
2572
2711
|
return Array.isArray(value) ? value : [];
|
|
2573
2712
|
}
|
|
@@ -2627,7 +2766,7 @@ function escapeHtml2(value) {
|
|
|
2627
2766
|
}
|
|
2628
2767
|
function stripOuterLineSpan(html) {
|
|
2629
2768
|
if (!html) return null;
|
|
2630
|
-
const openTagMatch = html.match(/<span[^>]*>/i);
|
|
2769
|
+
const openTagMatch = html.match(/<span[^>]*class="[^"]*\bline\b[^"]*"[^>]*>/i);
|
|
2631
2770
|
if (!openTagMatch) {
|
|
2632
2771
|
return null;
|
|
2633
2772
|
}
|
|
@@ -2676,8 +2815,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
2676
2815
|
if (node.type !== "code-line") {
|
|
2677
2816
|
anomalies.push(`type-mismatch:${node.id}:${node.type}`);
|
|
2678
2817
|
nodes.delete(node.id);
|
|
2679
|
-
|
|
2680
|
-
childrenSnapshotCache.delete(node.id);
|
|
2818
|
+
deleteSnapshotCacheEntry(nodes, node.id);
|
|
2681
2819
|
touched.add(node.id);
|
|
2682
2820
|
continue;
|
|
2683
2821
|
}
|
|
@@ -2721,16 +2859,14 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
2721
2859
|
const existing = nodes.get(desiredId);
|
|
2722
2860
|
if (existing && existing !== node) {
|
|
2723
2861
|
nodes.delete(desiredId);
|
|
2724
|
-
|
|
2725
|
-
childrenSnapshotCache.delete(desiredId);
|
|
2862
|
+
deleteSnapshotCacheEntry(nodes, desiredId);
|
|
2726
2863
|
touched.add(desiredId);
|
|
2727
2864
|
mutated = true;
|
|
2728
2865
|
}
|
|
2729
2866
|
if (node.id !== desiredId) {
|
|
2730
2867
|
const previousId = node.id;
|
|
2731
2868
|
nodes.delete(node.id);
|
|
2732
|
-
|
|
2733
|
-
childrenSnapshotCache.delete(previousId);
|
|
2869
|
+
deleteSnapshotCacheEntry(nodes, previousId);
|
|
2734
2870
|
node.id = desiredId;
|
|
2735
2871
|
nodes.set(desiredId, node);
|
|
2736
2872
|
touched.add(desiredId);
|
|
@@ -2761,8 +2897,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
2761
2897
|
for (const [id, record] of nodes) {
|
|
2762
2898
|
if (record.parentId === parent.id && record.type === "code-line" && !allowed.has(id)) {
|
|
2763
2899
|
nodes.delete(id);
|
|
2764
|
-
|
|
2765
|
-
childrenSnapshotCache.delete(id);
|
|
2900
|
+
deleteSnapshotCacheEntry(nodes, id);
|
|
2766
2901
|
touched.add(id);
|
|
2767
2902
|
mutated = true;
|
|
2768
2903
|
}
|
|
@@ -2846,8 +2981,10 @@ function normalizeCodeLineProps(incoming, previous) {
|
|
|
2846
2981
|
}
|
|
2847
2982
|
function createCodeLineProps(index, text, highlight, tokens) {
|
|
2848
2983
|
const safeText = typeof text === "string" ? text : "";
|
|
2849
|
-
const
|
|
2850
|
-
const
|
|
2984
|
+
const hasIncomingHighlight = typeof highlight === "string" && highlight.trim().length > 0;
|
|
2985
|
+
const sanitized = hasIncomingHighlight ? sanitizeLineInnerHtml(highlight, safeText) : null;
|
|
2986
|
+
const hasRenderableTokens = tokens !== void 0 && tokens !== null;
|
|
2987
|
+
const html = sanitized && sanitized.length >= safeText.length ? sanitized : hasRenderableTokens ? null : escapeHtml2(safeText);
|
|
2851
2988
|
const props = {
|
|
2852
2989
|
index,
|
|
2853
2990
|
text: safeText,
|
|
@@ -2958,6 +3095,18 @@ function validateCodeBlockChildren(nodes, parent) {
|
|
|
2958
3095
|
issues.push({ kind: "dangling-node", id });
|
|
2959
3096
|
}
|
|
2960
3097
|
}
|
|
3098
|
+
if (parent.block?.isFinalized) {
|
|
3099
|
+
const snapshot = createBlockSnapshot(cloneBlock(parent.block));
|
|
3100
|
+
const expectedChildren = ensureArray(snapshot.children).filter((child) => child.type === "code-line");
|
|
3101
|
+
if (expectedChildren.length !== parent.children.length) {
|
|
3102
|
+
issues.push({
|
|
3103
|
+
kind: "line-count-mismatch",
|
|
3104
|
+
id: parent.id,
|
|
3105
|
+
expected: expectedChildren.length,
|
|
3106
|
+
actual: parent.children.length
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
2961
3110
|
return { ok: issues.length === 0, issues };
|
|
2962
3111
|
}
|
|
2963
3112
|
function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
@@ -2974,7 +3123,7 @@ function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
|
2974
3123
|
}
|
|
2975
3124
|
const snapshot = createBlockSnapshot(cloneBlock(parent.block));
|
|
2976
3125
|
removeSubtree(nodes, parent.id, touched);
|
|
2977
|
-
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot);
|
|
3126
|
+
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot, touched, parent.blockEpoch);
|
|
2978
3127
|
if (!inserted) {
|
|
2979
3128
|
return false;
|
|
2980
3129
|
}
|
|
@@ -2997,7 +3146,55 @@ function arraysEqual(a, b) {
|
|
|
2997
3146
|
}
|
|
2998
3147
|
return true;
|
|
2999
3148
|
}
|
|
3000
|
-
function
|
|
3149
|
+
function expectedCodeLineId(parentId, index) {
|
|
3150
|
+
return `${parentId}::line:${index}`;
|
|
3151
|
+
}
|
|
3152
|
+
function collectStoreInvariantViolations(nodes) {
|
|
3153
|
+
const violations = [];
|
|
3154
|
+
for (const [id, node] of nodes) {
|
|
3155
|
+
if (node.type === "__root__") continue;
|
|
3156
|
+
if (node.children.length > 1) {
|
|
3157
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3158
|
+
for (const childId of node.children) {
|
|
3159
|
+
if (seen.has(childId)) {
|
|
3160
|
+
violations.push(`duplicate child id:${id}:${childId}`);
|
|
3161
|
+
} else {
|
|
3162
|
+
seen.add(childId);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
if (node.type === "list") {
|
|
3167
|
+
const parent = node.parentId ? nodes.get(node.parentId) : void 0;
|
|
3168
|
+
if (parent?.type === "list-item" && node.children.length === 0) {
|
|
3169
|
+
violations.push(`empty nested list:${id}`);
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
if (node.type === "code") {
|
|
3173
|
+
for (let index = 0; index < node.children.length; index += 1) {
|
|
3174
|
+
const childId = node.children[index];
|
|
3175
|
+
const child = nodes.get(childId);
|
|
3176
|
+
if (!child) {
|
|
3177
|
+
violations.push(`missing code-line node:${node.id}:${childId}`);
|
|
3178
|
+
continue;
|
|
3179
|
+
}
|
|
3180
|
+
if (child.type !== "code-line") {
|
|
3181
|
+
violations.push(`non-code child in code block:${node.id}:${child.id}:${child.type}`);
|
|
3182
|
+
continue;
|
|
3183
|
+
}
|
|
3184
|
+
const expectedId = expectedCodeLineId(node.id, index);
|
|
3185
|
+
if (child.id !== expectedId) {
|
|
3186
|
+
violations.push(`code-line id mismatch:${node.id}:${child.id}:${expectedId}`);
|
|
3187
|
+
}
|
|
3188
|
+
const indexProp = typeof child.props?.index === "number" ? child.props.index : null;
|
|
3189
|
+
if (indexProp !== index) {
|
|
3190
|
+
violations.push(`code-line index mismatch:${node.id}:${child.id}:${indexProp}:${index}`);
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
return violations;
|
|
3196
|
+
}
|
|
3197
|
+
function buildNodeFromSnapshot(map, snapshot, parentId, blockEpoch) {
|
|
3001
3198
|
const record = {
|
|
3002
3199
|
id: snapshot.id,
|
|
3003
3200
|
type: snapshot.type,
|
|
@@ -3007,6 +3204,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
3007
3204
|
meta: snapshot.meta ? { ...snapshot.meta } : void 0,
|
|
3008
3205
|
range: snapshot.range ? { ...snapshot.range } : void 0,
|
|
3009
3206
|
version: 0,
|
|
3207
|
+
blockEpoch,
|
|
3010
3208
|
block: snapshotToBlock(snapshot) ?? void 0
|
|
3011
3209
|
};
|
|
3012
3210
|
if (record.type === "code") {
|
|
@@ -3015,7 +3213,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
3015
3213
|
map.set(record.id, record);
|
|
3016
3214
|
const childSnapshots = ensureArray(snapshot.children);
|
|
3017
3215
|
for (const child of childSnapshots) {
|
|
3018
|
-
const childRecord = buildNodeFromSnapshot(map, child, record.id);
|
|
3216
|
+
const childRecord = buildNodeFromSnapshot(map, child, record.id, blockEpoch);
|
|
3019
3217
|
record.children.push(childRecord.id);
|
|
3020
3218
|
}
|
|
3021
3219
|
return record;
|
|
@@ -3043,8 +3241,7 @@ function removeSubtree(map, id, touched) {
|
|
|
3043
3241
|
}
|
|
3044
3242
|
}
|
|
3045
3243
|
map.delete(node.id);
|
|
3046
|
-
|
|
3047
|
-
childrenSnapshotCache.delete(node.id);
|
|
3244
|
+
deleteSnapshotCacheEntry(map, node.id);
|
|
3048
3245
|
touched.add(node.id);
|
|
3049
3246
|
for (const childId of node.children) {
|
|
3050
3247
|
const child = map.get(childId);
|
|
@@ -3076,13 +3273,13 @@ function resolveParent(map, path) {
|
|
|
3076
3273
|
}
|
|
3077
3274
|
return map.get(path.blockId);
|
|
3078
3275
|
}
|
|
3079
|
-
function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
3276
|
+
function insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
3080
3277
|
if (!parent) return null;
|
|
3081
3278
|
const existingIndex = parent.children.indexOf(snapshot.id);
|
|
3082
3279
|
if (existingIndex !== -1) {
|
|
3083
3280
|
removeSubtree(map, parent.children[existingIndex], touched ?? /* @__PURE__ */ new Set());
|
|
3084
3281
|
}
|
|
3085
|
-
const record = buildNodeFromSnapshot(map, snapshot, parent.id);
|
|
3282
|
+
const record = buildNodeFromSnapshot(map, snapshot, parent.id, blockEpoch ?? readSnapshotBlockEpoch(snapshot) ?? parent.blockEpoch);
|
|
3086
3283
|
const insertedIds = [];
|
|
3087
3284
|
const queue = [record];
|
|
3088
3285
|
while (queue.length > 0) {
|
|
@@ -3100,13 +3297,13 @@ function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
|
3100
3297
|
ensureUniqueChildren(parent, touched);
|
|
3101
3298
|
return { record, insertedIds };
|
|
3102
3299
|
}
|
|
3103
|
-
function replaceSnapshotAt(map, parent, index, snapshot, touched) {
|
|
3300
|
+
function replaceSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
3104
3301
|
if (!parent) return;
|
|
3105
3302
|
if (index < 0 || index >= parent.children.length) return;
|
|
3106
3303
|
const targetId = parent.children[index];
|
|
3107
3304
|
parent.children.splice(index, 1);
|
|
3108
3305
|
removeSubtree(map, targetId, touched);
|
|
3109
|
-
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched);
|
|
3306
|
+
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch);
|
|
3110
3307
|
if (inserted) {
|
|
3111
3308
|
for (const id of inserted.insertedIds) {
|
|
3112
3309
|
touched.add(id);
|
|
@@ -3126,6 +3323,24 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3126
3323
|
const listeners = /* @__PURE__ */ new Set();
|
|
3127
3324
|
let notifyScheduled = false;
|
|
3128
3325
|
let lastCoalescingMetrics = null;
|
|
3326
|
+
let invariantViolations = [];
|
|
3327
|
+
let transientDiagnostics = [];
|
|
3328
|
+
let nextBlockEpoch = 1;
|
|
3329
|
+
const debugCounters = {
|
|
3330
|
+
appendLineGuardRejected: 0,
|
|
3331
|
+
staleEpochRejected: 0,
|
|
3332
|
+
storeInvariantViolationCount: 0
|
|
3333
|
+
};
|
|
3334
|
+
const allocateBlockEpoch = (preferred) => {
|
|
3335
|
+
const resolved = readNumericEpoch(preferred);
|
|
3336
|
+
if (resolved !== void 0) {
|
|
3337
|
+
nextBlockEpoch = Math.max(nextBlockEpoch, resolved + 1);
|
|
3338
|
+
return resolved;
|
|
3339
|
+
}
|
|
3340
|
+
const epoch = nextBlockEpoch;
|
|
3341
|
+
nextBlockEpoch += 1;
|
|
3342
|
+
return epoch;
|
|
3343
|
+
};
|
|
3129
3344
|
const getRaf = () => {
|
|
3130
3345
|
if (typeof globalThis !== "undefined" && typeof globalThis.requestAnimationFrame === "function") {
|
|
3131
3346
|
return globalThis.requestAnimationFrame;
|
|
@@ -3157,9 +3372,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3157
3372
|
}
|
|
3158
3373
|
}
|
|
3159
3374
|
}
|
|
3375
|
+
function appendDiagnostic(message) {
|
|
3376
|
+
transientDiagnostics = [...transientDiagnostics, message];
|
|
3377
|
+
invariantViolations = [...invariantViolations, message];
|
|
3378
|
+
}
|
|
3160
3379
|
function rebuildFromBlocks(blocks) {
|
|
3161
|
-
|
|
3162
|
-
childrenSnapshotCache.clear();
|
|
3380
|
+
clearSnapshotCaches(nodes);
|
|
3163
3381
|
nodes = /* @__PURE__ */ new Map();
|
|
3164
3382
|
const root = createRootRecord();
|
|
3165
3383
|
nodes.set(root.id, root);
|
|
@@ -3168,9 +3386,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3168
3386
|
for (let i = 0; i < blocks.length; i++) {
|
|
3169
3387
|
const block = cloneBlock(blocks[i]);
|
|
3170
3388
|
const snapshot = createBlockSnapshot(block);
|
|
3171
|
-
insertSnapshotAt(nodes, root, root.children.length, snapshot);
|
|
3389
|
+
insertSnapshotAt(nodes, root, root.children.length, snapshot, void 0, allocateBlockEpoch(readSnapshotBlockEpoch(snapshot)));
|
|
3172
3390
|
}
|
|
3173
3391
|
normalizeAllListDepths(nodes, /* @__PURE__ */ new Set(), PATCH_ROOT_ID);
|
|
3392
|
+
transientDiagnostics = [];
|
|
3393
|
+
invariantViolations = collectStoreInvariantViolations(nodes);
|
|
3394
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
3174
3395
|
version++;
|
|
3175
3396
|
blocksDirty = true;
|
|
3176
3397
|
scheduleNotify();
|
|
@@ -3235,11 +3456,57 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3235
3456
|
listDepthDirty = true;
|
|
3236
3457
|
}
|
|
3237
3458
|
};
|
|
3238
|
-
const
|
|
3459
|
+
const semanticTxEpochs = /* @__PURE__ */ new Map();
|
|
3460
|
+
const resolveBlockEpochTarget = (patch, at) => {
|
|
3461
|
+
if ((patch.op === "insertChild" || patch.op === "replaceChild") && at.blockId === PATCH_ROOT_ID) {
|
|
3462
|
+
const nodeId = patch.node?.id;
|
|
3463
|
+
return nodeId ? nodes.get(nodeId) : void 0;
|
|
3464
|
+
}
|
|
3465
|
+
return nodes.get(at.blockId) ?? (at.nodeId ? nodes.get(at.nodeId) : void 0);
|
|
3466
|
+
};
|
|
3467
|
+
const rejectStaleEpochPatch = (patch, at) => {
|
|
3468
|
+
const expectedBlockEpoch = readPatchBlockEpoch(patch);
|
|
3469
|
+
const patchTx = readPatchTx(patch);
|
|
3470
|
+
if (expectedBlockEpoch === void 0) {
|
|
3471
|
+
return false;
|
|
3472
|
+
}
|
|
3473
|
+
if (getPatchKind3(patch) !== "semantic" || !at) {
|
|
3474
|
+
return false;
|
|
3475
|
+
}
|
|
3476
|
+
const target = resolveBlockEpochTarget(patch, at);
|
|
3477
|
+
if (!target || target.blockEpoch === expectedBlockEpoch) {
|
|
3478
|
+
return false;
|
|
3479
|
+
}
|
|
3480
|
+
const txEpoch = at.blockId && patchTx !== void 0 ? semanticTxEpochs.get(at.blockId) : void 0;
|
|
3481
|
+
if (txEpoch && txEpoch.tx === patchTx && txEpoch.blockEpoch === target.blockEpoch) {
|
|
3482
|
+
return false;
|
|
3483
|
+
}
|
|
3484
|
+
debugCounters.staleEpochRejected += 1;
|
|
3485
|
+
appendDiagnostic(
|
|
3486
|
+
`stale epoch rejected:${patch.op}:${target.id}:expected=${expectedBlockEpoch}:actual=${target.blockEpoch}`
|
|
3487
|
+
);
|
|
3488
|
+
return true;
|
|
3489
|
+
};
|
|
3490
|
+
const advanceBlockEpoch = (blockId, touchedSet, preferredEpoch, tx) => {
|
|
3491
|
+
if (!blockId || blockId === PATCH_ROOT_ID) {
|
|
3492
|
+
return null;
|
|
3493
|
+
}
|
|
3494
|
+
const blockRoot = nodes.get(blockId);
|
|
3495
|
+
if (!blockRoot) {
|
|
3496
|
+
return null;
|
|
3497
|
+
}
|
|
3498
|
+
const nextEpoch = allocateBlockEpoch(preferredEpoch);
|
|
3499
|
+
assignSubtreeBlockEpoch(nodes, blockRoot.id, nextEpoch, touchedSet);
|
|
3500
|
+
if (tx !== void 0) {
|
|
3501
|
+
semanticTxEpochs.set(blockRoot.id, { tx, blockEpoch: nextEpoch });
|
|
3502
|
+
}
|
|
3503
|
+
return nextEpoch;
|
|
3504
|
+
};
|
|
3505
|
+
const applyPropsUpdate = (at, props, preferredEpoch, tx, semanticUpdate = false) => {
|
|
3239
3506
|
const perfStartLocal = perfEnabled ? getPerfNow() : 0;
|
|
3240
3507
|
const targetId = at.nodeId ?? at.blockId;
|
|
3241
3508
|
if (!targetId) return;
|
|
3242
|
-
|
|
3509
|
+
let target = nodes.get(targetId);
|
|
3243
3510
|
if (!target) return;
|
|
3244
3511
|
const parentType = target.parentId ? nodes.get(target.parentId)?.type : void 0;
|
|
3245
3512
|
if (debugListPatches && (isListRelated(target.type) || isListRelated(parentType))) {
|
|
@@ -3266,6 +3533,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3266
3533
|
propsChanged = true;
|
|
3267
3534
|
}
|
|
3268
3535
|
if (propsChanged) {
|
|
3536
|
+
if (semanticUpdate) {
|
|
3537
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3538
|
+
}
|
|
3269
3539
|
target.version++;
|
|
3270
3540
|
touched.add(target.id);
|
|
3271
3541
|
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
@@ -3329,16 +3599,56 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3329
3599
|
}
|
|
3330
3600
|
}
|
|
3331
3601
|
let blockChanged = false;
|
|
3602
|
+
let typeChanged = false;
|
|
3603
|
+
let rebuiltFromFinalizedBlock = false;
|
|
3604
|
+
let blockEpochAdvanced = false;
|
|
3332
3605
|
const incomingBlock = props?.block;
|
|
3333
3606
|
if (incomingBlock && typeof incomingBlock === "object") {
|
|
3334
3607
|
target.block = cloneBlock(incomingBlock);
|
|
3608
|
+
const previousType = target.type;
|
|
3609
|
+
const incomingType = typeof target.block.type === "string" ? target.block.type : target.type;
|
|
3610
|
+
if (incomingType !== target.type) {
|
|
3611
|
+
target.type = incomingType;
|
|
3612
|
+
typeChanged = true;
|
|
3613
|
+
if (isListRelated(previousType) || isListRelated(target.type)) {
|
|
3614
|
+
markListDepthDirty(target.id);
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3335
3617
|
if (target.type === "code") {
|
|
3336
3618
|
applyCodeBlockMetadata(target);
|
|
3337
3619
|
}
|
|
3620
|
+
if (semanticUpdate) {
|
|
3621
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3622
|
+
blockEpochAdvanced = true;
|
|
3623
|
+
}
|
|
3624
|
+
const shouldRebuildFinalizedTree = !at.nodeId && target.id === at.blockId && Boolean(target.block?.isFinalized) && target.type !== "code" && Boolean(target.parentId);
|
|
3625
|
+
if (shouldRebuildFinalizedTree) {
|
|
3626
|
+
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
3627
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
3628
|
+
if (parent && index !== -1) {
|
|
3629
|
+
const snapshot = createBlockSnapshot(cloneBlock(target.block));
|
|
3630
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
3631
|
+
mutatedBlocks = true;
|
|
3632
|
+
blockChanged = true;
|
|
3633
|
+
rebuiltFromFinalizedBlock = true;
|
|
3634
|
+
const rebuilt = nodes.get(target.id);
|
|
3635
|
+
if (isListRelated(previousType) || isListRelated(rebuilt?.type)) {
|
|
3636
|
+
markListDepthDirty(target.id);
|
|
3637
|
+
}
|
|
3638
|
+
target = rebuilt ?? target;
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3338
3641
|
mutatedBlocks = true;
|
|
3339
3642
|
blockChanged = true;
|
|
3340
3643
|
}
|
|
3341
|
-
if (
|
|
3644
|
+
if (rebuiltFromFinalizedBlock) {
|
|
3645
|
+
return;
|
|
3646
|
+
}
|
|
3647
|
+
if (propsChanged || blockChanged || typeChanged) {
|
|
3648
|
+
if (semanticUpdate && !blockEpochAdvanced) {
|
|
3649
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3650
|
+
blockEpochAdvanced = true;
|
|
3651
|
+
}
|
|
3342
3652
|
target.version++;
|
|
3343
3653
|
touched.add(target.id);
|
|
3344
3654
|
let parentForNormalization;
|
|
@@ -3381,13 +3691,22 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3381
3691
|
const applyPatch = (patch) => {
|
|
3382
3692
|
switch (patch.op) {
|
|
3383
3693
|
case "insertChild": {
|
|
3694
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3384
3695
|
const parent = resolveParent(nodes, patch.at);
|
|
3385
|
-
const inserted = insertSnapshotAt(
|
|
3696
|
+
const inserted = insertSnapshotAt(
|
|
3697
|
+
nodes,
|
|
3698
|
+
parent,
|
|
3699
|
+
patch.index,
|
|
3700
|
+
patch.node,
|
|
3701
|
+
touched,
|
|
3702
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
3703
|
+
);
|
|
3386
3704
|
if (inserted) {
|
|
3387
3705
|
for (const id of inserted.insertedIds) {
|
|
3388
3706
|
touched.add(id);
|
|
3389
3707
|
}
|
|
3390
3708
|
mutatedBlocks = true;
|
|
3709
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3391
3710
|
if (isListRelated(inserted.record.type) || isListRelated(parent?.type)) {
|
|
3392
3711
|
markListDepthDirty(inserted.record.id);
|
|
3393
3712
|
if (parent) {
|
|
@@ -3407,6 +3726,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3407
3726
|
break;
|
|
3408
3727
|
}
|
|
3409
3728
|
case "deleteChild": {
|
|
3729
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3410
3730
|
const parent = resolveParent(nodes, patch.at);
|
|
3411
3731
|
if (!parent) break;
|
|
3412
3732
|
if (patch.index < 0 || patch.index >= parent.children.length) break;
|
|
@@ -3418,6 +3738,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3418
3738
|
touched.add(parent.id);
|
|
3419
3739
|
ensureUniqueChildren(parent, touched);
|
|
3420
3740
|
mutatedBlocks = true;
|
|
3741
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3421
3742
|
if (isListRelated(parent.type) || isListRelated(removedNode?.type)) {
|
|
3422
3743
|
markListDepthDirty(parent.id);
|
|
3423
3744
|
}
|
|
@@ -3434,11 +3755,20 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3434
3755
|
break;
|
|
3435
3756
|
}
|
|
3436
3757
|
case "replaceChild": {
|
|
3758
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3437
3759
|
const parent = resolveParent(nodes, patch.at);
|
|
3438
3760
|
if (!parent) break;
|
|
3439
|
-
replaceSnapshotAt(
|
|
3761
|
+
replaceSnapshotAt(
|
|
3762
|
+
nodes,
|
|
3763
|
+
parent,
|
|
3764
|
+
patch.index,
|
|
3765
|
+
patch.node,
|
|
3766
|
+
touched,
|
|
3767
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
3768
|
+
);
|
|
3440
3769
|
touched.add(parent.id);
|
|
3441
3770
|
mutatedBlocks = true;
|
|
3771
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3442
3772
|
if (isListRelated(parent.type)) {
|
|
3443
3773
|
markListDepthDirty(parent.id);
|
|
3444
3774
|
}
|
|
@@ -3452,18 +3782,33 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3452
3782
|
break;
|
|
3453
3783
|
}
|
|
3454
3784
|
case "setProps": {
|
|
3455
|
-
|
|
3785
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3786
|
+
applyPropsUpdate(patch.at, patch.props, readPatchParseEpoch(patch), readPatchTx(patch), getPatchKind3(patch) === "semantic");
|
|
3456
3787
|
break;
|
|
3457
3788
|
}
|
|
3458
3789
|
case "setPropsBatch": {
|
|
3459
3790
|
const entries2 = Array.isArray(patch.entries) ? patch.entries : [];
|
|
3460
3791
|
for (const entry of entries2) {
|
|
3461
3792
|
if (!entry || !entry.at) continue;
|
|
3462
|
-
|
|
3793
|
+
const entryPatch = {
|
|
3794
|
+
op: "setProps",
|
|
3795
|
+
at: entry.at,
|
|
3796
|
+
props: entry.props,
|
|
3797
|
+
meta: entry.meta ?? patch.meta
|
|
3798
|
+
};
|
|
3799
|
+
if (rejectStaleEpochPatch(entryPatch, entry.at)) continue;
|
|
3800
|
+
applyPropsUpdate(
|
|
3801
|
+
entry.at,
|
|
3802
|
+
entry.props,
|
|
3803
|
+
readPatchParseEpoch(entryPatch),
|
|
3804
|
+
readPatchTx(entryPatch),
|
|
3805
|
+
getPatchKind3(entryPatch) === "semantic"
|
|
3806
|
+
);
|
|
3463
3807
|
}
|
|
3464
3808
|
break;
|
|
3465
3809
|
}
|
|
3466
3810
|
case "finalize": {
|
|
3811
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3467
3812
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
3468
3813
|
if (!target || !target.block) break;
|
|
3469
3814
|
if (!target.block.isFinalized) {
|
|
@@ -3472,6 +3817,17 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3472
3817
|
target.version++;
|
|
3473
3818
|
touched.add(target.id);
|
|
3474
3819
|
mutatedBlocks = true;
|
|
3820
|
+
if (!patch.at.nodeId && target.id === patch.at.blockId && target.type !== "code" && target.parentId) {
|
|
3821
|
+
const parent = nodes.get(target.parentId);
|
|
3822
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
3823
|
+
if (parent && index !== -1) {
|
|
3824
|
+
const snapshot = createBlockSnapshot(cloneBlock(target.block));
|
|
3825
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
3826
|
+
if (isListRelated(target.type) || isListRelated(snapshot.type)) {
|
|
3827
|
+
markListDepthDirty(target.id);
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
}
|
|
3475
3831
|
}
|
|
3476
3832
|
if (isListRelated(target.type)) {
|
|
3477
3833
|
markListDepthDirty(target.id);
|
|
@@ -3485,6 +3841,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3485
3841
|
break;
|
|
3486
3842
|
}
|
|
3487
3843
|
case "reorder": {
|
|
3844
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3488
3845
|
const parent = resolveParent(nodes, patch.at);
|
|
3489
3846
|
if (!parent) break;
|
|
3490
3847
|
const length = parent.children.length;
|
|
@@ -3499,6 +3856,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3499
3856
|
parent.children.splice(to, 0, ...moved);
|
|
3500
3857
|
parent.version++;
|
|
3501
3858
|
touched.add(parent.id);
|
|
3859
|
+
if (getPatchKind3(patch) === "semantic") {
|
|
3860
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3861
|
+
}
|
|
3502
3862
|
if (isListRelated(parent.type)) {
|
|
3503
3863
|
markListDepthDirty(parent.id);
|
|
3504
3864
|
}
|
|
@@ -3514,15 +3874,31 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3514
3874
|
break;
|
|
3515
3875
|
}
|
|
3516
3876
|
case "appendLines": {
|
|
3877
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3517
3878
|
const parent = resolveParent(nodes, patch.at);
|
|
3518
3879
|
if (!parent) break;
|
|
3519
|
-
|
|
3880
|
+
if (parent.type !== "code") {
|
|
3881
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
3882
|
+
appendDiagnostic(`appendLines target not code:${parent.id}:${parent.type}`);
|
|
3883
|
+
break;
|
|
3884
|
+
}
|
|
3885
|
+
const requestedStartIndex = Math.max(0, patch.startIndex);
|
|
3886
|
+
const startIndex = Math.max(0, Math.min(requestedStartIndex, parent.children.length));
|
|
3520
3887
|
const lineCount = patch.lines?.length ?? 0;
|
|
3521
3888
|
if (lineCount === 0) break;
|
|
3889
|
+
const prefixMatches = parent.children.every((childId, index) => childId === expectedCodeLineId(parent.id, index));
|
|
3890
|
+
const isStrictTailAppend = requestedStartIndex === parent.children.length;
|
|
3891
|
+
if (!isStrictTailAppend || !prefixMatches) {
|
|
3892
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
3893
|
+
appendDiagnostic(
|
|
3894
|
+
`appendLines guard rejected:${parent.id}:requestedStart=${requestedStartIndex}:childCount=${parent.children.length}:prefixMatches=${prefixMatches}`
|
|
3895
|
+
);
|
|
3896
|
+
break;
|
|
3897
|
+
}
|
|
3522
3898
|
const originalChildren = parent.children.slice();
|
|
3523
3899
|
const insertedIds = [];
|
|
3524
3900
|
const insertedSet = /* @__PURE__ */ new Set();
|
|
3525
|
-
const isTrailingAppend =
|
|
3901
|
+
const isTrailingAppend = true;
|
|
3526
3902
|
let parentChildrenChanged = false;
|
|
3527
3903
|
let codeLinesMutated = false;
|
|
3528
3904
|
for (let offset = 0; offset < lineCount; offset++) {
|
|
@@ -3564,7 +3940,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3564
3940
|
parentId: parent.id,
|
|
3565
3941
|
children: [],
|
|
3566
3942
|
props: nextLineProps,
|
|
3567
|
-
version: 0
|
|
3943
|
+
version: 0,
|
|
3944
|
+
blockEpoch: parent.blockEpoch
|
|
3568
3945
|
};
|
|
3569
3946
|
nodes.set(lineId, record);
|
|
3570
3947
|
touched.add(lineId);
|
|
@@ -3614,6 +3991,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3614
3991
|
break;
|
|
3615
3992
|
}
|
|
3616
3993
|
case "setHTML": {
|
|
3994
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3617
3995
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
3618
3996
|
if (!target) break;
|
|
3619
3997
|
const sanitized = patch.sanitized ? patch.html : sanitizeHTML2(patch.html);
|
|
@@ -3656,6 +4034,30 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3656
4034
|
applyPatch(patch);
|
|
3657
4035
|
}
|
|
3658
4036
|
}
|
|
4037
|
+
const finalizedTableRoots = /* @__PURE__ */ new Set();
|
|
4038
|
+
for (const touchedId of touched) {
|
|
4039
|
+
let cursor = nodes.get(touchedId);
|
|
4040
|
+
while (cursor && cursor.id !== PATCH_ROOT_ID) {
|
|
4041
|
+
if (cursor.type === "table" && cursor.block?.isFinalized && cursor.parentId) {
|
|
4042
|
+
finalizedTableRoots.add(cursor.id);
|
|
4043
|
+
break;
|
|
4044
|
+
}
|
|
4045
|
+
cursor = cursor.parentId ? nodes.get(cursor.parentId) : void 0;
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
if (finalizedTableRoots.size > 0) {
|
|
4049
|
+
for (const tableId of finalizedTableRoots) {
|
|
4050
|
+
const tableNode = nodes.get(tableId);
|
|
4051
|
+
if (!tableNode || !tableNode.block || !tableNode.parentId) continue;
|
|
4052
|
+
const parent = nodes.get(tableNode.parentId);
|
|
4053
|
+
if (!parent) continue;
|
|
4054
|
+
const index = parent.children.indexOf(tableNode.id);
|
|
4055
|
+
if (index === -1) continue;
|
|
4056
|
+
const snapshot = createBlockSnapshot(cloneBlock(tableNode.block));
|
|
4057
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, tableNode.blockEpoch);
|
|
4058
|
+
mutatedBlocks = true;
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
3659
4061
|
if (mutatedBlocks) {
|
|
3660
4062
|
blocksDirty = true;
|
|
3661
4063
|
}
|
|
@@ -3676,6 +4078,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3676
4078
|
normalizeListDepthsForIds(nodes, touched, listDepthDirtyNodes, PATCH_ROOT_ID);
|
|
3677
4079
|
}
|
|
3678
4080
|
}
|
|
4081
|
+
invariantViolations = [...collectStoreInvariantViolations(nodes), ...transientDiagnostics];
|
|
4082
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
3679
4083
|
if (touched.size > 0 || mutatedBlocks) {
|
|
3680
4084
|
version++;
|
|
3681
4085
|
scheduleNotify();
|
|
@@ -3724,6 +4128,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3724
4128
|
if (!record) {
|
|
3725
4129
|
return EMPTY_NODE_SNAPSHOT;
|
|
3726
4130
|
}
|
|
4131
|
+
const nodeSnapshotCache = getNodeSnapshotCacheForMap(nodes);
|
|
3727
4132
|
const cached = nodeSnapshotCache.get(id);
|
|
3728
4133
|
if (cached && cached.version === record.version && cached.node === record) {
|
|
3729
4134
|
return cached;
|
|
@@ -3743,6 +4148,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3743
4148
|
if (!record) {
|
|
3744
4149
|
return EMPTY_CHILDREN_SNAPSHOT;
|
|
3745
4150
|
}
|
|
4151
|
+
const childrenSnapshotCache = getChildrenSnapshotCacheForMap(nodes);
|
|
3746
4152
|
const cached = childrenSnapshotCache.get(id);
|
|
3747
4153
|
if (cached && cached.version === record.version) {
|
|
3748
4154
|
return cached;
|
|
@@ -3752,6 +4158,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3752
4158
|
pruneCache(childrenSnapshotCache, CHILDREN_SNAPSHOT_CACHE_LIMIT, CHILDREN_SNAPSHOT_CACHE_BUFFER);
|
|
3753
4159
|
return snapshot;
|
|
3754
4160
|
},
|
|
4161
|
+
getInvariantViolations() {
|
|
4162
|
+
return invariantViolations.slice();
|
|
4163
|
+
},
|
|
4164
|
+
getDebugCounters() {
|
|
4165
|
+
return { ...debugCounters };
|
|
4166
|
+
},
|
|
3755
4167
|
getLastCoalescingMetrics() {
|
|
3756
4168
|
return lastCoalescingMetrics;
|
|
3757
4169
|
},
|
|
@@ -3787,7 +4199,7 @@ function useRendererChildren(store, id) {
|
|
|
3787
4199
|
}
|
|
3788
4200
|
|
|
3789
4201
|
// src/renderer/node-views.tsx
|
|
3790
|
-
import { stripCodeFence } from "@stream-mdx/core";
|
|
4202
|
+
import { getDefaultCodeWrapperAttributes as getDefaultCodeWrapperAttributes2, stripCodeFence } from "@stream-mdx/core";
|
|
3791
4203
|
import React7 from "react";
|
|
3792
4204
|
|
|
3793
4205
|
// src/renderer/deferred-render-context.tsx
|
|
@@ -4229,8 +4641,10 @@ var ListBlockView = React7.memo(
|
|
|
4229
4641
|
isFinalized: block?.isFinalized ?? false
|
|
4230
4642
|
});
|
|
4231
4643
|
}, [listDebugEnabled, blockId, depth, ordered, childIds, listItemIds, store, block?.isFinalized]);
|
|
4232
|
-
const listStyle = React7.useMemo(() => {
|
|
4233
|
-
if (!ordered || listItemIds.length === 0)
|
|
4644
|
+
const { listStyle, markerDigits } = React7.useMemo(() => {
|
|
4645
|
+
if (!ordered || listItemIds.length === 0) {
|
|
4646
|
+
return { listStyle: void 0, markerDigits: 1 };
|
|
4647
|
+
}
|
|
4234
4648
|
let maxDigits = 1;
|
|
4235
4649
|
listItemIds.forEach((childId, index) => {
|
|
4236
4650
|
const childNode = store.getNode(childId);
|
|
@@ -4242,9 +4656,14 @@ var ListBlockView = React7.memo(
|
|
|
4242
4656
|
const digits = digitMatch ? digitMatch.length : text.length;
|
|
4243
4657
|
if (digits > maxDigits) maxDigits = digits;
|
|
4244
4658
|
});
|
|
4245
|
-
const baseIndent = depth === 0 ? "
|
|
4659
|
+
const baseIndent = depth === 0 ? "2rem" : depth === 1 ? "1.75rem" : "1.5rem";
|
|
4660
|
+
const extraDigits = Math.max(0, maxDigits - 1);
|
|
4246
4661
|
return {
|
|
4247
|
-
|
|
4662
|
+
markerDigits: maxDigits,
|
|
4663
|
+
listStyle: {
|
|
4664
|
+
["--list-indent"]: extraDigits > 0 ? `calc(${baseIndent} + ${extraDigits}ch)` : baseIndent,
|
|
4665
|
+
["--list-marker-digits"]: String(maxDigits)
|
|
4666
|
+
}
|
|
4248
4667
|
};
|
|
4249
4668
|
}, [ordered, listItemIds, store, depth]);
|
|
4250
4669
|
if (listItemIds.length === 0) return null;
|
|
@@ -4253,6 +4672,7 @@ var ListBlockView = React7.memo(
|
|
|
4253
4672
|
{
|
|
4254
4673
|
className: `markdown-list ${ordered ? "ordered" : "unordered"}`,
|
|
4255
4674
|
"data-list-depth": depth,
|
|
4675
|
+
"data-marker-digits": ordered ? markerDigits : void 0,
|
|
4256
4676
|
"data-list-id": listDebugEnabled ? blockId : void 0,
|
|
4257
4677
|
style: listStyle,
|
|
4258
4678
|
children: listItemIds.map((childId, index) => /* @__PURE__ */ jsx(
|
|
@@ -4434,6 +4854,7 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4434
4854
|
deferredConfig ? { ...deferredConfig, enabled: true } : { enabled: false }
|
|
4435
4855
|
);
|
|
4436
4856
|
if (!node || !node.block) return null;
|
|
4857
|
+
const blockIsFinalized = node.block.isFinalized;
|
|
4437
4858
|
const nodeVersion = node.version;
|
|
4438
4859
|
const lines = React7.useMemo(() => {
|
|
4439
4860
|
const seenIds = /* @__PURE__ */ new Set();
|
|
@@ -4464,13 +4885,25 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4464
4885
|
const lang = typeof node.props?.lang === "string" ? node.props?.lang : node.block.payload.meta?.lang;
|
|
4465
4886
|
const preAttrs = node.props?.preAttrs ?? void 0;
|
|
4466
4887
|
const codeAttrs = node.props?.codeAttrs ?? void 0;
|
|
4888
|
+
const blockMeta = node.block.payload.meta ?? void 0;
|
|
4889
|
+
const lazyEnabled = Boolean(blockMeta?.lazyTokenization);
|
|
4890
|
+
const lazyTokenizedUntil = typeof blockMeta?.lazyTokenizedUntil === "number" ? blockMeta.lazyTokenizedUntil : 0;
|
|
4891
|
+
const lazyHighlightedLines = Array.isArray(blockMeta?.highlightedLines) ? blockMeta.highlightedLines.length : 0;
|
|
4892
|
+
const lazyTokenLines = Array.isArray(blockMeta?.tokenLines) ? blockMeta.tokenLines.length : 0;
|
|
4893
|
+
const lazySourceTextLineCount = React7.useMemo(() => {
|
|
4894
|
+
const raw = typeof node.block?.payload.raw === "string" ? node.block.payload.raw : "";
|
|
4895
|
+
const metaCode = typeof blockMeta?.code === "string" ? blockMeta.code : null;
|
|
4896
|
+
const sourceText = resolveCodeSourceText(raw, metaCode);
|
|
4897
|
+
if (sourceText.length === 0) return 0;
|
|
4898
|
+
return sourceText.split("\n").length;
|
|
4899
|
+
}, [blockMeta, node.block?.payload.raw]);
|
|
4900
|
+
const totalLazyLineCount = Math.max(lines.length, lazyHighlightedLines, lazyTokenLines, lazySourceTextLineCount);
|
|
4467
4901
|
const virtualizationConfig = DEFAULT_VIRTUALIZED_CODE_CONFIG;
|
|
4468
4902
|
const virtualizationDisabled = typeof process !== "undefined" && typeof process.env === "object" && process.env.STREAM_MDX_DISABLE_VIRTUALIZED_CODE === "true";
|
|
4469
|
-
const
|
|
4903
|
+
const canVirtualize = node.block.isFinalized && !lazyEnabled;
|
|
4904
|
+
const shouldVirtualize = canVirtualize && !virtualizationDisabled && virtualizationConfig.enabled && lines.length >= virtualizationConfig.virtualizeThreshold;
|
|
4470
4905
|
const virtualization = useVirtualizedCode(lines, shouldVirtualize ? virtualizationConfig : { ...virtualizationConfig, enabled: false });
|
|
4471
4906
|
const highlightRequester = useCodeHighlightRequester();
|
|
4472
|
-
const lazyEnabled = Boolean(node.block.payload.meta?.lazyTokenization);
|
|
4473
|
-
const lazyTokenizedUntil = typeof node.block.payload.meta?.lazyTokenizedUntil === "number" ? node.block.payload.meta.lazyTokenizedUntil : 0;
|
|
4474
4907
|
const lastRangeRef = React7.useRef(null);
|
|
4475
4908
|
const rafRef = React7.useRef(null);
|
|
4476
4909
|
const idleRef = React7.useRef(null);
|
|
@@ -4551,29 +4984,111 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4551
4984
|
virtualization.window.startIndex,
|
|
4552
4985
|
virtualization.window.endIndex
|
|
4553
4986
|
]);
|
|
4554
|
-
|
|
4555
|
-
if (
|
|
4556
|
-
|
|
4987
|
+
React7.useEffect(() => {
|
|
4988
|
+
if (shouldVirtualize || !blockIsFinalized || !lazyEnabled || !highlightRequester) return;
|
|
4989
|
+
if (totalLazyLineCount <= 0 || lazyTokenizedUntil >= totalLazyLineCount) return;
|
|
4990
|
+
const nextRange = {
|
|
4991
|
+
visibleStart: 0,
|
|
4992
|
+
visibleEnd: totalLazyLineCount,
|
|
4993
|
+
prefetchStart: 0,
|
|
4994
|
+
prefetchEnd: totalLazyLineCount,
|
|
4995
|
+
tokenizedUntil: lazyTokenizedUntil
|
|
4996
|
+
};
|
|
4997
|
+
const last = lastRangeRef.current;
|
|
4998
|
+
if (last && last.visibleStart === nextRange.visibleStart && last.visibleEnd === nextRange.visibleEnd && last.prefetchStart === nextRange.prefetchStart && last.prefetchEnd === nextRange.prefetchEnd && last.tokenizedUntil === nextRange.tokenizedUntil) {
|
|
4999
|
+
return;
|
|
5000
|
+
}
|
|
5001
|
+
lastRangeRef.current = nextRange;
|
|
5002
|
+
if (rafRef.current !== null && typeof cancelAnimationFrame === "function") {
|
|
5003
|
+
cancelAnimationFrame(rafRef.current);
|
|
4557
5004
|
}
|
|
5005
|
+
const requestFullHighlight = () => {
|
|
5006
|
+
highlightRequester({
|
|
5007
|
+
blockId,
|
|
5008
|
+
startLine: 0,
|
|
5009
|
+
endLine: totalLazyLineCount,
|
|
5010
|
+
priority: "visible",
|
|
5011
|
+
reason: "finalize-full"
|
|
5012
|
+
});
|
|
5013
|
+
rafRef.current = null;
|
|
5014
|
+
};
|
|
5015
|
+
if (typeof requestAnimationFrame === "function") {
|
|
5016
|
+
rafRef.current = requestAnimationFrame(requestFullHighlight);
|
|
5017
|
+
} else {
|
|
5018
|
+
requestFullHighlight();
|
|
5019
|
+
}
|
|
5020
|
+
}, [blockId, blockIsFinalized, highlightRequester, lazyEnabled, lazyTokenizedUntil, shouldVirtualize, totalLazyLineCount]);
|
|
5021
|
+
const highlightedHtml = React7.useMemo(() => {
|
|
5022
|
+
const blockHtml = node.block?.payload.highlightedHtml ?? "";
|
|
5023
|
+
const raw = typeof node.block?.payload.raw === "string" ? node.block.payload.raw : "";
|
|
5024
|
+
const metaCode = typeof node.block?.payload.meta?.code === "string" ? (node.block?.payload.meta).code : null;
|
|
5025
|
+
const sourceText = resolveCodeSourceText(raw, metaCode);
|
|
5026
|
+
const sourceEndsWithNewline = sourceText.endsWith("\n");
|
|
5027
|
+
const sourceLines = sourceText.length > 0 ? sourceText.split("\n") : [];
|
|
5028
|
+
const rawFallbackLines = buildCodeFallbackLines(raw);
|
|
5029
|
+
const deterministicWrapperAttrs = getDefaultCodeWrapperAttributes2(lang);
|
|
5030
|
+
const composedPreAttrs = deterministicWrapperAttrs.preAttrs;
|
|
5031
|
+
const composedCodeAttrs = deterministicWrapperAttrs.codeAttrs;
|
|
5032
|
+
const shouldAppendTerminalNewline = (renderedLines) => {
|
|
5033
|
+
if (!sourceEndsWithNewline || renderedLines.length === 0 || lines.length === 0) {
|
|
5034
|
+
return false;
|
|
5035
|
+
}
|
|
5036
|
+
const lastRendered = renderedLines[renderedLines.length - 1];
|
|
5037
|
+
const lastKnown = lines[lines.length - 1];
|
|
5038
|
+
if (!lastRendered || !lastKnown || lastRendered.index !== lastKnown.index || lastRendered.text === "") {
|
|
5039
|
+
return false;
|
|
5040
|
+
}
|
|
5041
|
+
const expectedRenderedLineCount = Math.max(0, sourceLines.length - 1);
|
|
5042
|
+
const expectedLastRenderedLine = sourceLines.length >= 2 ? sourceLines[sourceLines.length - 2] ?? "" : "";
|
|
5043
|
+
return renderedLines.length === expectedRenderedLineCount && lastRendered.text === expectedLastRenderedLine;
|
|
5044
|
+
};
|
|
4558
5045
|
if (lines.length > 0) {
|
|
4559
5046
|
const hasLineHtml = lines.some((line) => typeof line.html === "string" && line.html.length > 0);
|
|
4560
|
-
if (!hasLineHtml &&
|
|
4561
|
-
return
|
|
5047
|
+
if (!hasLineHtml && blockHtml) {
|
|
5048
|
+
return blockHtml;
|
|
4562
5049
|
}
|
|
4563
5050
|
if (shouldVirtualize) {
|
|
4564
|
-
return composeHighlightedHtml(
|
|
5051
|
+
return composeHighlightedHtml(
|
|
5052
|
+
virtualization.window.visibleLines,
|
|
5053
|
+
composedPreAttrs,
|
|
5054
|
+
composedCodeAttrs,
|
|
5055
|
+
shouldAppendTerminalNewline(virtualization.window.visibleLines)
|
|
5056
|
+
);
|
|
5057
|
+
}
|
|
5058
|
+
return composeHighlightedHtml(lines, composedPreAttrs, composedCodeAttrs, shouldAppendTerminalNewline(lines));
|
|
5059
|
+
}
|
|
5060
|
+
if (!shouldVirtualize && blockHtml) {
|
|
5061
|
+
const hasHighlightedLines = blockHtml.includes('class="line"');
|
|
5062
|
+
if (!hasHighlightedLines && rawFallbackLines.length > 0) {
|
|
5063
|
+
return composeHighlightedHtml(
|
|
5064
|
+
rawFallbackLines,
|
|
5065
|
+
composedPreAttrs,
|
|
5066
|
+
composedCodeAttrs,
|
|
5067
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5068
|
+
);
|
|
4565
5069
|
}
|
|
4566
|
-
return
|
|
5070
|
+
return blockHtml;
|
|
4567
5071
|
}
|
|
4568
|
-
const blockHtml = node.block?.payload.highlightedHtml ?? "";
|
|
4569
5072
|
if (blockHtml?.trim().match(/^```[\w-]*\s*$/)) {
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
5073
|
+
if (rawFallbackLines.length > 0) {
|
|
5074
|
+
return composeHighlightedHtml(
|
|
5075
|
+
rawFallbackLines,
|
|
5076
|
+
composedPreAttrs,
|
|
5077
|
+
composedCodeAttrs,
|
|
5078
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5079
|
+
);
|
|
4573
5080
|
}
|
|
4574
5081
|
}
|
|
5082
|
+
if (!blockHtml && rawFallbackLines.length > 0) {
|
|
5083
|
+
return composeHighlightedHtml(
|
|
5084
|
+
rawFallbackLines,
|
|
5085
|
+
composedPreAttrs,
|
|
5086
|
+
composedCodeAttrs,
|
|
5087
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5088
|
+
);
|
|
5089
|
+
}
|
|
4575
5090
|
return blockHtml;
|
|
4576
|
-
}, [shouldVirtualize, node.block?.payload.highlightedHtml,
|
|
5091
|
+
}, [blockIsFinalized, shouldVirtualize, node.block?.payload.highlightedHtml, node.block?.payload.meta, lines, lang, virtualization.window.visibleLines, node.block?.payload.raw]);
|
|
4577
5092
|
const rendered = /* @__PURE__ */ jsx(
|
|
4578
5093
|
CodeComponent,
|
|
4579
5094
|
{
|
|
@@ -4585,13 +5100,19 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4585
5100
|
codeAttrs
|
|
4586
5101
|
}
|
|
4587
5102
|
);
|
|
5103
|
+
const effectiveLineCount = React7.useMemo(() => {
|
|
5104
|
+
if (lines.length > 0) {
|
|
5105
|
+
return lines.length;
|
|
5106
|
+
}
|
|
5107
|
+
return 1;
|
|
5108
|
+
}, [lines.length]);
|
|
4588
5109
|
const codeFrameClass = "not-prose flex flex-col rounded-lg border border-input pt-1 font-mono text-sm";
|
|
4589
5110
|
const codeMetricsAttrs = {
|
|
4590
5111
|
"data-code-block": "true",
|
|
4591
5112
|
"data-block-id": blockId,
|
|
4592
5113
|
"data-code-virtualized": shouldVirtualize ? "true" : "false",
|
|
4593
|
-
"data-code-total-lines": String(
|
|
4594
|
-
"data-code-mounted-lines": String(shouldVirtualize ? virtualization.window.mountedLines :
|
|
5114
|
+
"data-code-total-lines": String(effectiveLineCount),
|
|
5115
|
+
"data-code-mounted-lines": String(shouldVirtualize ? virtualization.window.mountedLines : effectiveLineCount),
|
|
4595
5116
|
"data-code-window-size": String(virtualization.config.windowSize)
|
|
4596
5117
|
};
|
|
4597
5118
|
const codeView = shouldVirtualize ? (() => {
|
|
@@ -4637,21 +5158,152 @@ var CodeBlockView = React7.memo(({ store, blockId, registry }) => {
|
|
|
4637
5158
|
return codeView;
|
|
4638
5159
|
});
|
|
4639
5160
|
CodeBlockView.displayName = "CodeBlockView";
|
|
4640
|
-
function composeHighlightedHtml(lines, preAttrs, codeAttrs) {
|
|
5161
|
+
function composeHighlightedHtml(lines, preAttrs, codeAttrs, appendTerminalNewline = false) {
|
|
4641
5162
|
const lineMarkup = lines.map((line) => {
|
|
4642
|
-
const content = line.html ?? escapeHtml3(line.text);
|
|
5163
|
+
const content = line.html ?? renderTokenLineHtml(line.tokens) ?? escapeHtml3(line.text);
|
|
4643
5164
|
const dataLine = Number.isFinite(line.index) ? ` data-line="${line.index + 1}"` : "";
|
|
4644
5165
|
return `<span class="line"${dataLine}>${content}</span>`;
|
|
4645
5166
|
}).join("\n");
|
|
4646
5167
|
const preAttr = attrsToString(preAttrs);
|
|
4647
5168
|
const codeAttr = attrsToString(codeAttrs);
|
|
4648
|
-
return `<pre${preAttr}><code${codeAttr}>${lineMarkup}
|
|
4649
|
-
|
|
5169
|
+
return `<pre${preAttr}><code${codeAttr}>${lineMarkup}${appendTerminalNewline ? "\n" : ""}</code></pre>`;
|
|
5170
|
+
}
|
|
5171
|
+
var TOKEN_FONT_STYLE_ITALIC = 1;
|
|
5172
|
+
var TOKEN_FONT_STYLE_BOLD = 2;
|
|
5173
|
+
var TOKEN_FONT_STYLE_UNDERLINE = 4;
|
|
5174
|
+
var TOKEN_FONT_STYLE_STRIKETHROUGH = 8;
|
|
5175
|
+
function renderTokenLineHtml(tokens) {
|
|
5176
|
+
if (!tokens || !Array.isArray(tokens.spans)) {
|
|
5177
|
+
return null;
|
|
5178
|
+
}
|
|
5179
|
+
return mergeRenderableTokenSpans(tokens.spans).map((span) => renderTokenSpanHtml(span)).join("");
|
|
5180
|
+
}
|
|
5181
|
+
function renderTokenSpanHtml(span) {
|
|
5182
|
+
const dark = span.v?.dark;
|
|
5183
|
+
const light = span.v?.light;
|
|
5184
|
+
const single = span.s;
|
|
5185
|
+
const styles = [];
|
|
5186
|
+
if (dark?.fg) {
|
|
5187
|
+
styles.push(`--shiki-dark:${dark.fg}`);
|
|
5188
|
+
}
|
|
5189
|
+
if (light?.fg) {
|
|
5190
|
+
styles.push(`--shiki-light:${light.fg}`);
|
|
5191
|
+
}
|
|
5192
|
+
if (!light?.fg && !dark?.fg && single?.fg) {
|
|
5193
|
+
styles.push(`color:${single.fg}`);
|
|
5194
|
+
}
|
|
5195
|
+
const fontStyle = light?.fs ?? dark?.fs ?? single?.fs;
|
|
5196
|
+
if (typeof fontStyle === "number" && fontStyle > 0) {
|
|
5197
|
+
if (fontStyle & TOKEN_FONT_STYLE_ITALIC) {
|
|
5198
|
+
styles.push("font-style: italic");
|
|
5199
|
+
}
|
|
5200
|
+
if (fontStyle & TOKEN_FONT_STYLE_BOLD) {
|
|
5201
|
+
styles.push("font-weight: bold");
|
|
5202
|
+
}
|
|
5203
|
+
const decorations = [];
|
|
5204
|
+
if (fontStyle & TOKEN_FONT_STYLE_UNDERLINE) {
|
|
5205
|
+
decorations.push("underline");
|
|
5206
|
+
}
|
|
5207
|
+
if (fontStyle & TOKEN_FONT_STYLE_STRIKETHROUGH) {
|
|
5208
|
+
decorations.push("line-through");
|
|
5209
|
+
}
|
|
5210
|
+
if (decorations.length > 0) {
|
|
5211
|
+
styles.push(`text-decoration: ${decorations.join(" ")}`);
|
|
5212
|
+
}
|
|
5213
|
+
}
|
|
5214
|
+
const content = escapeHtml3(span.t ?? "");
|
|
5215
|
+
if (styles.length === 0) {
|
|
5216
|
+
return content;
|
|
5217
|
+
}
|
|
5218
|
+
return `<span style="${styles.join(";")}">${content}</span>`;
|
|
5219
|
+
}
|
|
5220
|
+
function mergeRenderableTokenSpans(spans) {
|
|
5221
|
+
if (spans.length <= 1) {
|
|
5222
|
+
return spans.slice();
|
|
5223
|
+
}
|
|
5224
|
+
const merged = [];
|
|
5225
|
+
let pendingWhitespace = "";
|
|
5226
|
+
for (const span of spans) {
|
|
5227
|
+
const text = typeof span.t === "string" ? span.t : "";
|
|
5228
|
+
if (/^[\t ]+$/.test(text)) {
|
|
5229
|
+
pendingWhitespace += text;
|
|
5230
|
+
continue;
|
|
5231
|
+
}
|
|
5232
|
+
const nextSpan = pendingWhitespace ? { ...span, t: `${pendingWhitespace}${text}` } : span;
|
|
5233
|
+
pendingWhitespace = "";
|
|
5234
|
+
const previous = merged[merged.length - 1];
|
|
5235
|
+
if (previous && sameTokenSpanStyle(previous, nextSpan)) {
|
|
5236
|
+
previous.t += nextSpan.t;
|
|
5237
|
+
} else {
|
|
5238
|
+
merged.push({ ...nextSpan });
|
|
5239
|
+
}
|
|
5240
|
+
}
|
|
5241
|
+
if (pendingWhitespace) {
|
|
5242
|
+
const previous = merged[merged.length - 1];
|
|
5243
|
+
if (previous) {
|
|
5244
|
+
previous.t += pendingWhitespace;
|
|
5245
|
+
} else {
|
|
5246
|
+
merged.push({ t: pendingWhitespace });
|
|
5247
|
+
}
|
|
5248
|
+
}
|
|
5249
|
+
return merged;
|
|
5250
|
+
}
|
|
5251
|
+
function sameTokenSpanStyle(a, b) {
|
|
5252
|
+
const variantKeys = /* @__PURE__ */ new Set([
|
|
5253
|
+
...Object.keys(a.v ?? {}),
|
|
5254
|
+
...Object.keys(b.v ?? {})
|
|
5255
|
+
]);
|
|
5256
|
+
for (const key of variantKeys) {
|
|
5257
|
+
const aStyle = a.v?.[key];
|
|
5258
|
+
const bStyle = b.v?.[key];
|
|
5259
|
+
if ((aStyle?.fg ?? null) !== (bStyle?.fg ?? null)) return false;
|
|
5260
|
+
if ((aStyle?.bg ?? null) !== (bStyle?.bg ?? null)) return false;
|
|
5261
|
+
if ((aStyle?.fs ?? null) !== (bStyle?.fs ?? null)) return false;
|
|
5262
|
+
}
|
|
5263
|
+
if ((a.s?.fg ?? null) !== (b.s?.fg ?? null)) return false;
|
|
5264
|
+
if ((a.s?.bg ?? null) !== (b.s?.bg ?? null)) return false;
|
|
5265
|
+
if ((a.s?.fs ?? null) !== (b.s?.fs ?? null)) return false;
|
|
5266
|
+
return true;
|
|
5267
|
+
}
|
|
5268
|
+
function resolveCodeSourceText(raw, metaCode) {
|
|
5269
|
+
if (metaCode !== null) {
|
|
5270
|
+
return metaCode.replace(/\r\n?/g, "\n");
|
|
5271
|
+
}
|
|
5272
|
+
if (!raw) return "";
|
|
5273
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
5274
|
+
const fenced = stripCodeFence(normalized);
|
|
5275
|
+
return fenced.hadFence ? fenced.code : normalized;
|
|
4650
5276
|
}
|
|
4651
5277
|
function attrsToString(attrs) {
|
|
4652
5278
|
if (!attrs) return "";
|
|
4653
5279
|
return Object.entries(attrs).map(([key, value]) => ` ${key}="${escapeAttribute(value)}"`).join("");
|
|
4654
5280
|
}
|
|
5281
|
+
function buildCodeFallbackLines(raw) {
|
|
5282
|
+
const normalized = normalizeCodeFallbackRaw(raw);
|
|
5283
|
+
if (normalized.length === 0) {
|
|
5284
|
+
if (/^\s*```[^\n]*\n?\s*$/.test(raw)) {
|
|
5285
|
+
return [{ id: "temp-0", index: 0, text: "", html: null }];
|
|
5286
|
+
}
|
|
5287
|
+
return [];
|
|
5288
|
+
}
|
|
5289
|
+
return normalized.split("\n").map((line, index) => ({
|
|
5290
|
+
id: `temp-${index}`,
|
|
5291
|
+
index,
|
|
5292
|
+
text: line,
|
|
5293
|
+
html: null
|
|
5294
|
+
}));
|
|
5295
|
+
}
|
|
5296
|
+
function normalizeCodeFallbackRaw(raw) {
|
|
5297
|
+
if (!raw) return "";
|
|
5298
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
5299
|
+
const fenced = stripCodeFence(normalized);
|
|
5300
|
+
if (!fenced.hadFence) {
|
|
5301
|
+
return normalized.replace(/\n+$/, "");
|
|
5302
|
+
}
|
|
5303
|
+
let code = fenced.code;
|
|
5304
|
+
code = code.replace(/\n+$/, "");
|
|
5305
|
+
return code;
|
|
5306
|
+
}
|
|
4655
5307
|
function escapeHtml3(value) {
|
|
4656
5308
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4657
5309
|
}
|
|
@@ -4775,7 +5427,9 @@ var MarkdownRenderer = class {
|
|
|
4775
5427
|
lowPriorityFrameBudgetMs: this.config.performance?.lowPriorityFrameBudgetMs,
|
|
4776
5428
|
urgentQueueThreshold: this.config.performance?.urgentQueueThreshold,
|
|
4777
5429
|
batch: this.config.performance?.batch,
|
|
4778
|
-
historyLimit: this.config.performance?.historyLimit
|
|
5430
|
+
historyLimit: this.config.performance?.historyLimit,
|
|
5431
|
+
startupMicrotaskFlushes: this.config.performance?.startupMicrotaskFlushes,
|
|
5432
|
+
adaptiveBudgeting: this.config.performance?.adaptiveBudgeting
|
|
4779
5433
|
}
|
|
4780
5434
|
});
|
|
4781
5435
|
}
|
|
@@ -4969,18 +5623,8 @@ var MarkdownRenderer = class {
|
|
|
4969
5623
|
const receivedAt = typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
4970
5624
|
const batches = splitPatchBatch(message.patches);
|
|
4971
5625
|
batches.forEach((batch, index) => {
|
|
4972
|
-
const
|
|
4973
|
-
|
|
4974
|
-
case "insertChild":
|
|
4975
|
-
case "replaceChild":
|
|
4976
|
-
case "deleteChild":
|
|
4977
|
-
case "reorder":
|
|
4978
|
-
return true;
|
|
4979
|
-
default:
|
|
4980
|
-
return false;
|
|
4981
|
-
}
|
|
4982
|
-
});
|
|
4983
|
-
const priority = hasStructural ? "high" : batch.some(isHeavyPatch) ? "low" : "high";
|
|
5626
|
+
const hasSemantic = batch.some((patch) => getPatchKind(patch) === "semantic");
|
|
5627
|
+
const priority = hasSemantic ? "high" : batch.some(isHeavyPatch) ? "low" : "high";
|
|
4984
5628
|
this.patchScheduler.enqueue({
|
|
4985
5629
|
patches: batch,
|
|
4986
5630
|
meta: {
|