@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.cjs
CHANGED
|
@@ -103,7 +103,7 @@ var init_mdx_client = __esm({
|
|
|
103
103
|
if (block.type !== "mdx") {
|
|
104
104
|
throw new Error("Block is not MDX type");
|
|
105
105
|
}
|
|
106
|
-
const cacheKey = block.id
|
|
106
|
+
const cacheKey = `${block.id}\0${block.payload.raw ?? ""}`;
|
|
107
107
|
const cachedPromise = this.cache.get(cacheKey);
|
|
108
108
|
if (cachedPromise) {
|
|
109
109
|
return cachedPromise;
|
|
@@ -952,7 +952,11 @@ var defaultInlineComponents = {
|
|
|
952
952
|
const n = number ?? "?";
|
|
953
953
|
const href = number ? `#fn:${n}` : void 0;
|
|
954
954
|
const id = number ? `fnref:${n}` : void 0;
|
|
955
|
-
return import_react5.default.createElement(
|
|
955
|
+
return import_react5.default.createElement(
|
|
956
|
+
"sup",
|
|
957
|
+
{ className: "footnote-ref" },
|
|
958
|
+
import_react5.default.createElement("a", { href, id, "data-label": label, style: { color: "var(--foreground)", textDecoration: "underline" } }, String(n))
|
|
959
|
+
);
|
|
956
960
|
}
|
|
957
961
|
};
|
|
958
962
|
var defaultBlockComponents = {
|
|
@@ -1095,7 +1099,7 @@ var defaultBlockComponents = {
|
|
|
1095
1099
|
dangerouslySetInnerHTML: { __html: htmlString }
|
|
1096
1100
|
});
|
|
1097
1101
|
},
|
|
1098
|
-
mdx: ({ compiledRef, compiledModule, status, errorMessage
|
|
1102
|
+
mdx: ({ compiledRef, compiledModule, status, errorMessage }) => {
|
|
1099
1103
|
const [Comp, setComp] = import_react5.default.useState(null);
|
|
1100
1104
|
const [internalError, setInternalError] = import_react5.default.useState(null);
|
|
1101
1105
|
const [renderError, setRenderError] = import_react5.default.useState(null);
|
|
@@ -1196,7 +1200,6 @@ var defaultBlockComponents = {
|
|
|
1196
1200
|
const waitingForVisibility = deferHydration && !shouldHydrate && Boolean(resolvedId);
|
|
1197
1201
|
const pendingLabel = waitingForVisibility ? "MDX ready (hydrate on view)\u2026" : compileMode === "worker" ? "Compiling MDX (client)\u2026" : "Compiling MDX (server)\u2026";
|
|
1198
1202
|
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.");
|
|
1199
|
-
const rawFallback = typeof raw === "string" && raw.trim().length > 0 ? import_react5.default.createElement("pre", { className: "markdown-mdx-fallback" }, raw) : null;
|
|
1200
1203
|
const allowRetry = Boolean(internalError || renderError);
|
|
1201
1204
|
const retryButton = allowRetry ? import_react5.default.createElement(
|
|
1202
1205
|
"button",
|
|
@@ -1208,9 +1211,10 @@ var defaultBlockComponents = {
|
|
|
1208
1211
|
"Retry hydration"
|
|
1209
1212
|
) : null;
|
|
1210
1213
|
const errorPanel = import_react5.default.createElement(
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
import_react5.default.createElement(
|
|
1214
|
+
import_react5.default.Fragment,
|
|
1215
|
+
null,
|
|
1216
|
+
import_react5.default.createElement("strong", null, "MDX failed"),
|
|
1217
|
+
import_react5.default.createElement("div", null, message)
|
|
1214
1218
|
);
|
|
1215
1219
|
if (Comp && !failureMessage) {
|
|
1216
1220
|
return import_react5.default.createElement(
|
|
@@ -1233,14 +1237,13 @@ var defaultBlockComponents = {
|
|
|
1233
1237
|
return import_react5.default.createElement(
|
|
1234
1238
|
"div",
|
|
1235
1239
|
{
|
|
1236
|
-
className: "markdown-mdx",
|
|
1240
|
+
className: "markdown-mdx error",
|
|
1237
1241
|
ref: containerRef,
|
|
1238
1242
|
"data-mdx-ref": pendingId,
|
|
1239
1243
|
"data-mdx-status": "error",
|
|
1240
1244
|
"data-mdx-mode": compileMode
|
|
1241
1245
|
},
|
|
1242
1246
|
errorPanel,
|
|
1243
|
-
rawFallback,
|
|
1244
1247
|
retryButton
|
|
1245
1248
|
);
|
|
1246
1249
|
}
|
|
@@ -1267,7 +1270,16 @@ var defaultBlockComponents = {
|
|
|
1267
1270
|
{ key: item.number, id: `fn:${item.number}` },
|
|
1268
1271
|
renderInlineNodes(item.inlines, defaultInlineComponents),
|
|
1269
1272
|
" ",
|
|
1270
|
-
import_react5.default.createElement(
|
|
1273
|
+
import_react5.default.createElement(
|
|
1274
|
+
"a",
|
|
1275
|
+
{
|
|
1276
|
+
href: `#fnref:${item.number}`,
|
|
1277
|
+
className: "footnote-backref",
|
|
1278
|
+
"aria-label": "Back to content",
|
|
1279
|
+
style: { color: "var(--foreground)", textDecoration: "underline" }
|
|
1280
|
+
},
|
|
1281
|
+
"\u21A9"
|
|
1282
|
+
)
|
|
1271
1283
|
)
|
|
1272
1284
|
);
|
|
1273
1285
|
return import_react5.default.createElement("section", { className: "footnotes" }, import_react5.default.createElement("hr", {}), import_react5.default.createElement("ol", {}, listItems));
|
|
@@ -1815,6 +1827,9 @@ function useCodeHighlightRequester() {
|
|
|
1815
1827
|
// src/renderer/patch-batching.ts
|
|
1816
1828
|
var import_patch_batching = require("@stream-mdx/core/perf/patch-batching");
|
|
1817
1829
|
|
|
1830
|
+
// src/renderer/patch-commit-scheduler.ts
|
|
1831
|
+
var import_patch_batching2 = require("@stream-mdx/core/perf/patch-batching");
|
|
1832
|
+
|
|
1818
1833
|
// src/renderer/patch-coalescing.ts
|
|
1819
1834
|
var import_core3 = require("@stream-mdx/core");
|
|
1820
1835
|
|
|
@@ -1825,6 +1840,9 @@ var COALESCING_DURATION_ACTIVATE_MS = 6;
|
|
|
1825
1840
|
var COALESCING_DURATION_DEACTIVATE_MS = 4;
|
|
1826
1841
|
var RETAIN_TOUCHED_IN_HISTORY = typeof process !== "undefined" && process.env ? process.env.NODE_ENV !== "production" : true;
|
|
1827
1842
|
var EMPTY_TOUCHED_SET = /* @__PURE__ */ new Set();
|
|
1843
|
+
function shouldSkipCoalescing(patches) {
|
|
1844
|
+
return patches.length <= 1;
|
|
1845
|
+
}
|
|
1828
1846
|
function getDefaultNow() {
|
|
1829
1847
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
1830
1848
|
return () => performance.now();
|
|
@@ -1851,8 +1869,9 @@ function getDefaultCancelRaf() {
|
|
|
1851
1869
|
}
|
|
1852
1870
|
var PatchCommitScheduler = class {
|
|
1853
1871
|
constructor(params) {
|
|
1854
|
-
this.
|
|
1855
|
-
this.
|
|
1872
|
+
this.semanticQueue = [];
|
|
1873
|
+
this.enrichmentHighQueue = [];
|
|
1874
|
+
this.enrichmentLowQueue = [];
|
|
1856
1875
|
this.scheduled = false;
|
|
1857
1876
|
this.flushing = false;
|
|
1858
1877
|
this.scheduledHandle = null;
|
|
@@ -1864,6 +1883,7 @@ var PatchCommitScheduler = class {
|
|
|
1864
1883
|
this.scheduleToken = 0;
|
|
1865
1884
|
this.coalescingDurationSamples = [];
|
|
1866
1885
|
this.adaptiveBudgetActive = false;
|
|
1886
|
+
this.flushCount = 0;
|
|
1867
1887
|
this.store = params.store;
|
|
1868
1888
|
this.onFlush = params.onFlush;
|
|
1869
1889
|
this.frameBudgetMs = Math.max(1, params.options?.frameBudgetMs ?? 10);
|
|
@@ -1879,6 +1899,8 @@ var PatchCommitScheduler = class {
|
|
|
1879
1899
|
this.maxLowPriorityBatchesPerFlush = params.options?.maxLowPriorityBatchesPerFlush ?? 2;
|
|
1880
1900
|
this.urgentQueueThreshold = Math.max(1, params.options?.urgentQueueThreshold ?? 4);
|
|
1881
1901
|
this.historyLimit = Math.max(1, params.options?.historyLimit ?? 200);
|
|
1902
|
+
this.startupMicrotaskFlushes = Math.max(0, Math.floor(params.options?.startupMicrotaskFlushes ?? 0));
|
|
1903
|
+
this.adaptiveBudgeting = params.options?.adaptiveBudgeting ?? true;
|
|
1882
1904
|
const requestedBatch = params.options?.batch;
|
|
1883
1905
|
if (requestedBatch === "microtask") {
|
|
1884
1906
|
this.batchStrategy = "microtask";
|
|
@@ -1905,19 +1927,23 @@ var PatchCommitScheduler = class {
|
|
|
1905
1927
|
patches: input.patches,
|
|
1906
1928
|
meta: input.meta ?? {},
|
|
1907
1929
|
receivedAt: input.meta?.receivedAt ?? this.now(),
|
|
1930
|
+
kind: input.meta?.kind === "semantic" || input.meta?.kind === "enrichment" ? input.meta.kind : input.patches.some((patch) => (0, import_patch_batching2.getPatchKind)(patch) === "semantic") ? "semantic" : "enrichment",
|
|
1908
1931
|
priority: input.meta?.priority === "low" ? "low" : "high"
|
|
1909
1932
|
};
|
|
1910
|
-
if (batch.
|
|
1911
|
-
|
|
1933
|
+
if (batch.kind === "semantic") {
|
|
1934
|
+
batch.priority = "high";
|
|
1935
|
+
this.semanticQueue.push(batch);
|
|
1936
|
+
} else if (batch.priority === "low") {
|
|
1937
|
+
this.enrichmentLowQueue.push(batch);
|
|
1912
1938
|
} else {
|
|
1913
|
-
this.
|
|
1939
|
+
this.enrichmentHighQueue.push(batch);
|
|
1914
1940
|
}
|
|
1915
1941
|
if (!this.paused) {
|
|
1916
1942
|
this.schedule();
|
|
1917
1943
|
}
|
|
1918
1944
|
}
|
|
1919
1945
|
flushAll() {
|
|
1920
|
-
if (this.
|
|
1946
|
+
if (this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0 && !this.flushing) {
|
|
1921
1947
|
return null;
|
|
1922
1948
|
}
|
|
1923
1949
|
this.cancelScheduled();
|
|
@@ -1927,9 +1953,11 @@ var PatchCommitScheduler = class {
|
|
|
1927
1953
|
}
|
|
1928
1954
|
clear() {
|
|
1929
1955
|
this.cancelScheduled();
|
|
1930
|
-
this.
|
|
1931
|
-
this.
|
|
1956
|
+
this.semanticQueue = [];
|
|
1957
|
+
this.enrichmentHighQueue = [];
|
|
1958
|
+
this.enrichmentLowQueue = [];
|
|
1932
1959
|
this.flushing = false;
|
|
1960
|
+
this.flushCount = 0;
|
|
1933
1961
|
this.coalescingDurationSamples = [];
|
|
1934
1962
|
this.adaptiveBudgetActive = false;
|
|
1935
1963
|
this.adaptiveHighBatchCap = void 0;
|
|
@@ -1937,10 +1965,10 @@ var PatchCommitScheduler = class {
|
|
|
1937
1965
|
this.maybeResolveIdle();
|
|
1938
1966
|
}
|
|
1939
1967
|
getPendingCount() {
|
|
1940
|
-
return this.
|
|
1968
|
+
return this.semanticQueue.length + this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
1941
1969
|
}
|
|
1942
1970
|
isIdle() {
|
|
1943
|
-
return !this.flushing && !this.scheduled && this.
|
|
1971
|
+
return !this.flushing && !this.scheduled && this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0;
|
|
1944
1972
|
}
|
|
1945
1973
|
awaitIdle() {
|
|
1946
1974
|
if (this.isIdle()) {
|
|
@@ -1980,7 +2008,8 @@ var PatchCommitScheduler = class {
|
|
|
1980
2008
|
this.runFlush(this.frameBudgetMs, false);
|
|
1981
2009
|
this.maybeResolveIdle();
|
|
1982
2010
|
};
|
|
1983
|
-
|
|
2011
|
+
const useStartupMicrotask = this.batchStrategy !== "microtask" && this.startupMicrotaskFlushes > 0 && this.flushCount < this.startupMicrotaskFlushes && typeof queueMicrotask === "function";
|
|
2012
|
+
if ((this.batchStrategy === "microtask" || useStartupMicrotask) && typeof queueMicrotask === "function") {
|
|
1984
2013
|
this.scheduledViaRaf = false;
|
|
1985
2014
|
this.scheduledHandle = token;
|
|
1986
2015
|
queueMicrotask(execute);
|
|
@@ -2010,12 +2039,14 @@ var PatchCommitScheduler = class {
|
|
|
2010
2039
|
if (this.paused && !manual) {
|
|
2011
2040
|
return null;
|
|
2012
2041
|
}
|
|
2013
|
-
if (this.
|
|
2042
|
+
if (this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0) {
|
|
2014
2043
|
return null;
|
|
2015
2044
|
}
|
|
2016
2045
|
this.flushing = true;
|
|
2017
2046
|
const startedAt = this.now();
|
|
2018
|
-
const
|
|
2047
|
+
const initialSemanticQueueSize = this.semanticQueue.length;
|
|
2048
|
+
const initialEnrichmentQueueSize = this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2049
|
+
const initialQueueSize = initialSemanticQueueSize + initialEnrichmentQueueSize;
|
|
2019
2050
|
const batches = [];
|
|
2020
2051
|
let totalInputPatches = 0;
|
|
2021
2052
|
let totalAppliedPatches = 0;
|
|
@@ -2030,7 +2061,15 @@ var PatchCommitScheduler = class {
|
|
|
2030
2061
|
consumed += 1;
|
|
2031
2062
|
const applyStart = this.now();
|
|
2032
2063
|
const queueDelayMs = Math.max(0, applyStart - next.receivedAt);
|
|
2033
|
-
|
|
2064
|
+
let coalesced;
|
|
2065
|
+
let coalescingMetrics;
|
|
2066
|
+
if (shouldSkipCoalescing(next.patches)) {
|
|
2067
|
+
coalesced = next.patches;
|
|
2068
|
+
} else {
|
|
2069
|
+
const result = (0, import_core3.coalescePatchesWithMetrics)(next.patches, import_core3.DEFAULT_COALESCE_CONFIG);
|
|
2070
|
+
coalesced = result.patches;
|
|
2071
|
+
coalescingMetrics = result.metrics;
|
|
2072
|
+
}
|
|
2034
2073
|
const touched = this.store.applyPatches(coalesced, {
|
|
2035
2074
|
coalesced: true,
|
|
2036
2075
|
metrics: coalescingMetrics
|
|
@@ -2050,6 +2089,7 @@ var PatchCommitScheduler = class {
|
|
|
2050
2089
|
receivedAt: next.receivedAt,
|
|
2051
2090
|
appliedAt: applyStart,
|
|
2052
2091
|
priority: next.priority,
|
|
2092
|
+
kind: next.kind,
|
|
2053
2093
|
coalescing: coalescingMetrics
|
|
2054
2094
|
});
|
|
2055
2095
|
if (maxBatches && batches.length - startingBatchCount >= maxBatches) {
|
|
@@ -2066,27 +2106,32 @@ var PatchCommitScheduler = class {
|
|
|
2066
2106
|
queue.splice(0, consumed);
|
|
2067
2107
|
}
|
|
2068
2108
|
};
|
|
2069
|
-
|
|
2109
|
+
processQueue(this.semanticQueue, void 0, Number.POSITIVE_INFINITY);
|
|
2110
|
+
const initialHighQueueSize = this.enrichmentHighQueue.length;
|
|
2070
2111
|
const configuredHighLimit = manual || !this.maxBatchesPerFlush ? void 0 : initialHighQueueSize > this.maxBatchesPerFlush ? void 0 : this.maxBatchesPerFlush;
|
|
2071
|
-
const highBatchLimit = this.adaptiveHighBatchCap ?? configuredHighLimit;
|
|
2072
|
-
processQueue(this.
|
|
2112
|
+
const highBatchLimit = this.adaptiveBudgeting ? this.adaptiveHighBatchCap ?? configuredHighLimit : configuredHighLimit;
|
|
2113
|
+
processQueue(this.enrichmentHighQueue, highBatchLimit, budgetMs);
|
|
2073
2114
|
if (manual) {
|
|
2074
|
-
processQueue(this.
|
|
2075
|
-
} else if (this.
|
|
2115
|
+
processQueue(this.enrichmentLowQueue, void 0, Number.POSITIVE_INFINITY);
|
|
2116
|
+
} else if (this.enrichmentLowQueue.length > 0) {
|
|
2076
2117
|
elapsed = this.now() - startedAt;
|
|
2077
2118
|
const budgetForLow = Math.max(0, this.lowPriorityFrameBudgetMs - elapsed);
|
|
2078
|
-
|
|
2079
|
-
|
|
2119
|
+
const processedHigherPriorityWork = batches.length > 0;
|
|
2120
|
+
if (budgetForLow > 0 || !processedHigherPriorityWork) {
|
|
2121
|
+
const initialLowQueueSize = this.enrichmentLowQueue.length;
|
|
2080
2122
|
const configuredLowLimit = manual || !this.maxLowPriorityBatchesPerFlush ? void 0 : initialLowQueueSize > this.maxLowPriorityBatchesPerFlush ? void 0 : this.maxLowPriorityBatchesPerFlush;
|
|
2081
|
-
const lowBatchLimit = this.adaptiveLowBatchCap ?? configuredLowLimit;
|
|
2082
|
-
processQueue(this.
|
|
2123
|
+
const lowBatchLimit = this.adaptiveBudgeting ? this.adaptiveLowBatchCap ?? configuredLowLimit : configuredLowLimit;
|
|
2124
|
+
processQueue(this.enrichmentLowQueue, lowBatchLimit, budgetForLow);
|
|
2083
2125
|
}
|
|
2084
2126
|
}
|
|
2085
2127
|
this.flushing = false;
|
|
2086
2128
|
const completedAt = this.now();
|
|
2087
2129
|
const totalDurationMs = completedAt - startedAt;
|
|
2088
|
-
const
|
|
2130
|
+
const remainingSemantic = this.semanticQueue.length;
|
|
2131
|
+
const remainingEnrichment = this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2132
|
+
const remaining = remainingSemantic + remainingEnrichment;
|
|
2089
2133
|
if (batches.length > 0) {
|
|
2134
|
+
this.flushCount += 1;
|
|
2090
2135
|
try {
|
|
2091
2136
|
this.onFlush({
|
|
2092
2137
|
batches,
|
|
@@ -2094,7 +2139,11 @@ var PatchCommitScheduler = class {
|
|
|
2094
2139
|
totalAppliedPatches,
|
|
2095
2140
|
totalDurationMs,
|
|
2096
2141
|
remainingQueueSize: remaining,
|
|
2142
|
+
remainingSemanticQueueSize: remainingSemantic,
|
|
2143
|
+
remainingEnrichmentQueueSize: remainingEnrichment,
|
|
2097
2144
|
queueDepthBefore: initialQueueSize,
|
|
2145
|
+
semanticQueueDepthBefore: initialSemanticQueueSize,
|
|
2146
|
+
enrichmentQueueDepthBefore: initialEnrichmentQueueSize,
|
|
2098
2147
|
flushStartedAt: startedAt,
|
|
2099
2148
|
flushCompletedAt: completedAt
|
|
2100
2149
|
});
|
|
@@ -2105,21 +2154,27 @@ var PatchCommitScheduler = class {
|
|
|
2105
2154
|
if (remaining > 0 && !this.paused) {
|
|
2106
2155
|
this.schedule();
|
|
2107
2156
|
}
|
|
2108
|
-
const coalescingStats = this.computeCoalescingDurationStats();
|
|
2109
|
-
this.
|
|
2110
|
-
|
|
2157
|
+
const coalescingStats = this.adaptiveBudgeting ? this.computeCoalescingDurationStats() : { sampleCount: this.coalescingDurationSamples.length, p95: null };
|
|
2158
|
+
if (this.adaptiveBudgeting) {
|
|
2159
|
+
this.updateAdaptiveBudget(coalescingStats.p95);
|
|
2160
|
+
}
|
|
2161
|
+
const adaptiveState = this.adaptiveBudgeting ? this.snapshotAdaptiveBudget(coalescingStats.p95 ?? null) : void 0;
|
|
2111
2162
|
const flushResult = batches.length > 0 ? {
|
|
2112
2163
|
batches,
|
|
2113
2164
|
totalPatches: totalInputPatches,
|
|
2114
2165
|
totalAppliedPatches,
|
|
2115
2166
|
totalDurationMs,
|
|
2116
2167
|
remainingQueueSize: remaining,
|
|
2168
|
+
remainingSemanticQueueSize: remainingSemantic,
|
|
2169
|
+
remainingEnrichmentQueueSize: remainingEnrichment,
|
|
2117
2170
|
queueDepthBefore: initialQueueSize,
|
|
2171
|
+
semanticQueueDepthBefore: initialSemanticQueueSize,
|
|
2172
|
+
enrichmentQueueDepthBefore: initialEnrichmentQueueSize,
|
|
2118
2173
|
flushStartedAt: startedAt,
|
|
2119
2174
|
flushCompletedAt: completedAt,
|
|
2120
2175
|
coalescingDurationP95: coalescingStats.p95 ?? void 0,
|
|
2121
2176
|
coalescingDurationSampleCount: coalescingStats.sampleCount,
|
|
2122
|
-
adaptiveBudgetActive: adaptiveState
|
|
2177
|
+
adaptiveBudgetActive: adaptiveState?.active,
|
|
2123
2178
|
adaptiveBudgetState: adaptiveState
|
|
2124
2179
|
} : null;
|
|
2125
2180
|
if (flushResult) {
|
|
@@ -2155,6 +2210,9 @@ var PatchCommitScheduler = class {
|
|
|
2155
2210
|
};
|
|
2156
2211
|
}
|
|
2157
2212
|
updateAdaptiveBudget(p95) {
|
|
2213
|
+
if (!this.adaptiveBudgeting) {
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2158
2216
|
if (p95 !== null && p95 > COALESCING_DURATION_ACTIVATE_MS) {
|
|
2159
2217
|
if (!this.adaptiveBudgetActive) {
|
|
2160
2218
|
this.adaptiveBudgetActive = true;
|
|
@@ -2228,11 +2286,13 @@ var PatchCommitScheduler = class {
|
|
|
2228
2286
|
}
|
|
2229
2287
|
restart() {
|
|
2230
2288
|
this.cancelScheduled();
|
|
2231
|
-
this.
|
|
2232
|
-
this.
|
|
2289
|
+
this.semanticQueue = [];
|
|
2290
|
+
this.enrichmentHighQueue = [];
|
|
2291
|
+
this.enrichmentLowQueue = [];
|
|
2233
2292
|
this.flushing = false;
|
|
2234
2293
|
this.sequence = 0;
|
|
2235
2294
|
this.history = [];
|
|
2295
|
+
this.flushCount = 0;
|
|
2236
2296
|
this.scheduleToken++;
|
|
2237
2297
|
this.paused = false;
|
|
2238
2298
|
this.coalescingDurationSamples = [];
|
|
@@ -2279,6 +2339,12 @@ var PatchCommitScheduler = class {
|
|
|
2279
2339
|
if (typeof options.historyLimit !== "undefined") {
|
|
2280
2340
|
this.setHistoryLimit(options.historyLimit);
|
|
2281
2341
|
}
|
|
2342
|
+
if (typeof options.startupMicrotaskFlushes !== "undefined") {
|
|
2343
|
+
this.startupMicrotaskFlushes = Math.max(0, Math.floor(options.startupMicrotaskFlushes));
|
|
2344
|
+
}
|
|
2345
|
+
if (typeof options.adaptiveBudgeting !== "undefined") {
|
|
2346
|
+
this.adaptiveBudgeting = options.adaptiveBudgeting;
|
|
2347
|
+
}
|
|
2282
2348
|
if (typeof options.batch !== "undefined") {
|
|
2283
2349
|
const requestedBatch = options.batch;
|
|
2284
2350
|
if (requestedBatch === "microtask") {
|
|
@@ -2305,6 +2371,7 @@ var PatchCommitScheduler = class {
|
|
|
2305
2371
|
|
|
2306
2372
|
// src/renderer/store.ts
|
|
2307
2373
|
var import_core4 = require("@stream-mdx/core");
|
|
2374
|
+
var import_patch_batching3 = require("@stream-mdx/core/perf/patch-batching");
|
|
2308
2375
|
|
|
2309
2376
|
// src/renderer/list-utils.ts
|
|
2310
2377
|
function updateNodeDepth(node, depth) {
|
|
@@ -2400,12 +2467,28 @@ function snapshotToBlock(node) {
|
|
|
2400
2467
|
}
|
|
2401
2468
|
return null;
|
|
2402
2469
|
}
|
|
2403
|
-
var
|
|
2404
|
-
var
|
|
2470
|
+
var nodeSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
2471
|
+
var childrenSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
2405
2472
|
var NODE_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
2406
2473
|
var CHILDREN_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
2407
2474
|
var NODE_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(NODE_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
2408
2475
|
var CHILDREN_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(CHILDREN_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
2476
|
+
function getNodeSnapshotCacheForMap(map) {
|
|
2477
|
+
let cache = nodeSnapshotCacheByMap.get(map);
|
|
2478
|
+
if (!cache) {
|
|
2479
|
+
cache = /* @__PURE__ */ new Map();
|
|
2480
|
+
nodeSnapshotCacheByMap.set(map, cache);
|
|
2481
|
+
}
|
|
2482
|
+
return cache;
|
|
2483
|
+
}
|
|
2484
|
+
function getChildrenSnapshotCacheForMap(map) {
|
|
2485
|
+
let cache = childrenSnapshotCacheByMap.get(map);
|
|
2486
|
+
if (!cache) {
|
|
2487
|
+
cache = /* @__PURE__ */ new Map();
|
|
2488
|
+
childrenSnapshotCacheByMap.set(map, cache);
|
|
2489
|
+
}
|
|
2490
|
+
return cache;
|
|
2491
|
+
}
|
|
2409
2492
|
function pruneCache(cache, max, buffer) {
|
|
2410
2493
|
if (cache.size <= max + buffer) return;
|
|
2411
2494
|
let remaining = cache.size - max;
|
|
@@ -2415,6 +2498,14 @@ function pruneCache(cache, max, buffer) {
|
|
|
2415
2498
|
if (remaining <= 0) break;
|
|
2416
2499
|
}
|
|
2417
2500
|
}
|
|
2501
|
+
function deleteSnapshotCacheEntry(map, id) {
|
|
2502
|
+
getNodeSnapshotCacheForMap(map).delete(id);
|
|
2503
|
+
getChildrenSnapshotCacheForMap(map).delete(id);
|
|
2504
|
+
}
|
|
2505
|
+
function clearSnapshotCaches(map) {
|
|
2506
|
+
getNodeSnapshotCacheForMap(map).clear();
|
|
2507
|
+
getChildrenSnapshotCacheForMap(map).clear();
|
|
2508
|
+
}
|
|
2418
2509
|
var EMPTY_CHILDREN = Object.freeze([]);
|
|
2419
2510
|
var EMPTY_NODE_SNAPSHOT = Object.freeze({ version: -1, node: void 0 });
|
|
2420
2511
|
var EMPTY_CHILDREN_SNAPSHOT = Object.freeze({
|
|
@@ -2582,9 +2673,57 @@ function createRootRecord() {
|
|
|
2582
2673
|
parentId: null,
|
|
2583
2674
|
children: [],
|
|
2584
2675
|
props: {},
|
|
2585
|
-
version: 0
|
|
2676
|
+
version: 0,
|
|
2677
|
+
blockEpoch: 0
|
|
2586
2678
|
};
|
|
2587
2679
|
}
|
|
2680
|
+
function readNumericEpoch(value) {
|
|
2681
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
2682
|
+
return void 0;
|
|
2683
|
+
}
|
|
2684
|
+
return value;
|
|
2685
|
+
}
|
|
2686
|
+
function readSnapshotBlockEpoch(snapshot) {
|
|
2687
|
+
return readNumericEpoch(snapshot.meta?.blockEpoch);
|
|
2688
|
+
}
|
|
2689
|
+
function readPatchBlockEpoch(patch) {
|
|
2690
|
+
if (patch.op === "setHTML") {
|
|
2691
|
+
return readNumericEpoch(patch.patchMeta?.blockEpoch);
|
|
2692
|
+
}
|
|
2693
|
+
return readNumericEpoch(patch.meta?.blockEpoch);
|
|
2694
|
+
}
|
|
2695
|
+
function readPatchParseEpoch(patch) {
|
|
2696
|
+
if (patch.op === "setHTML") {
|
|
2697
|
+
return readNumericEpoch(patch.patchMeta?.parseEpoch);
|
|
2698
|
+
}
|
|
2699
|
+
return readNumericEpoch(patch.meta?.parseEpoch);
|
|
2700
|
+
}
|
|
2701
|
+
function readPatchTx(patch) {
|
|
2702
|
+
if (patch.op === "setHTML") {
|
|
2703
|
+
return readNumericEpoch(patch.patchMeta?.tx);
|
|
2704
|
+
}
|
|
2705
|
+
return readNumericEpoch(patch.meta?.tx);
|
|
2706
|
+
}
|
|
2707
|
+
function assignSubtreeBlockEpoch(map, rootId, blockEpoch, touched) {
|
|
2708
|
+
const root = map.get(rootId);
|
|
2709
|
+
if (!root) return;
|
|
2710
|
+
const stack = [root];
|
|
2711
|
+
while (stack.length > 0) {
|
|
2712
|
+
const node = stack.pop();
|
|
2713
|
+
if (!node) continue;
|
|
2714
|
+
if (node.blockEpoch !== blockEpoch) {
|
|
2715
|
+
node.blockEpoch = blockEpoch;
|
|
2716
|
+
node.version += 1;
|
|
2717
|
+
touched?.add(node.id);
|
|
2718
|
+
}
|
|
2719
|
+
for (const childId of node.children) {
|
|
2720
|
+
const child = map.get(childId);
|
|
2721
|
+
if (child) {
|
|
2722
|
+
stack.push(child);
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2588
2727
|
function ensureArray(value) {
|
|
2589
2728
|
return Array.isArray(value) ? value : [];
|
|
2590
2729
|
}
|
|
@@ -2644,7 +2783,7 @@ function escapeHtml2(value) {
|
|
|
2644
2783
|
}
|
|
2645
2784
|
function stripOuterLineSpan(html) {
|
|
2646
2785
|
if (!html) return null;
|
|
2647
|
-
const openTagMatch = html.match(/<span[^>]*>/i);
|
|
2786
|
+
const openTagMatch = html.match(/<span[^>]*class="[^"]*\bline\b[^"]*"[^>]*>/i);
|
|
2648
2787
|
if (!openTagMatch) {
|
|
2649
2788
|
return null;
|
|
2650
2789
|
}
|
|
@@ -2693,8 +2832,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
2693
2832
|
if (node.type !== "code-line") {
|
|
2694
2833
|
anomalies.push(`type-mismatch:${node.id}:${node.type}`);
|
|
2695
2834
|
nodes.delete(node.id);
|
|
2696
|
-
|
|
2697
|
-
childrenSnapshotCache.delete(node.id);
|
|
2835
|
+
deleteSnapshotCacheEntry(nodes, node.id);
|
|
2698
2836
|
touched.add(node.id);
|
|
2699
2837
|
continue;
|
|
2700
2838
|
}
|
|
@@ -2738,16 +2876,14 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
2738
2876
|
const existing = nodes.get(desiredId);
|
|
2739
2877
|
if (existing && existing !== node) {
|
|
2740
2878
|
nodes.delete(desiredId);
|
|
2741
|
-
|
|
2742
|
-
childrenSnapshotCache.delete(desiredId);
|
|
2879
|
+
deleteSnapshotCacheEntry(nodes, desiredId);
|
|
2743
2880
|
touched.add(desiredId);
|
|
2744
2881
|
mutated = true;
|
|
2745
2882
|
}
|
|
2746
2883
|
if (node.id !== desiredId) {
|
|
2747
2884
|
const previousId = node.id;
|
|
2748
2885
|
nodes.delete(node.id);
|
|
2749
|
-
|
|
2750
|
-
childrenSnapshotCache.delete(previousId);
|
|
2886
|
+
deleteSnapshotCacheEntry(nodes, previousId);
|
|
2751
2887
|
node.id = desiredId;
|
|
2752
2888
|
nodes.set(desiredId, node);
|
|
2753
2889
|
touched.add(desiredId);
|
|
@@ -2778,8 +2914,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
2778
2914
|
for (const [id, record] of nodes) {
|
|
2779
2915
|
if (record.parentId === parent.id && record.type === "code-line" && !allowed.has(id)) {
|
|
2780
2916
|
nodes.delete(id);
|
|
2781
|
-
|
|
2782
|
-
childrenSnapshotCache.delete(id);
|
|
2917
|
+
deleteSnapshotCacheEntry(nodes, id);
|
|
2783
2918
|
touched.add(id);
|
|
2784
2919
|
mutated = true;
|
|
2785
2920
|
}
|
|
@@ -2863,8 +2998,10 @@ function normalizeCodeLineProps(incoming, previous) {
|
|
|
2863
2998
|
}
|
|
2864
2999
|
function createCodeLineProps(index, text, highlight, tokens) {
|
|
2865
3000
|
const safeText = typeof text === "string" ? text : "";
|
|
2866
|
-
const
|
|
2867
|
-
const
|
|
3001
|
+
const hasIncomingHighlight = typeof highlight === "string" && highlight.trim().length > 0;
|
|
3002
|
+
const sanitized = hasIncomingHighlight ? sanitizeLineInnerHtml(highlight, safeText) : null;
|
|
3003
|
+
const hasRenderableTokens = tokens !== void 0 && tokens !== null;
|
|
3004
|
+
const html = sanitized && sanitized.length >= safeText.length ? sanitized : hasRenderableTokens ? null : escapeHtml2(safeText);
|
|
2868
3005
|
const props = {
|
|
2869
3006
|
index,
|
|
2870
3007
|
text: safeText,
|
|
@@ -2975,6 +3112,18 @@ function validateCodeBlockChildren(nodes, parent) {
|
|
|
2975
3112
|
issues.push({ kind: "dangling-node", id });
|
|
2976
3113
|
}
|
|
2977
3114
|
}
|
|
3115
|
+
if (parent.block?.isFinalized) {
|
|
3116
|
+
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(parent.block));
|
|
3117
|
+
const expectedChildren = ensureArray(snapshot.children).filter((child) => child.type === "code-line");
|
|
3118
|
+
if (expectedChildren.length !== parent.children.length) {
|
|
3119
|
+
issues.push({
|
|
3120
|
+
kind: "line-count-mismatch",
|
|
3121
|
+
id: parent.id,
|
|
3122
|
+
expected: expectedChildren.length,
|
|
3123
|
+
actual: parent.children.length
|
|
3124
|
+
});
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
2978
3127
|
return { ok: issues.length === 0, issues };
|
|
2979
3128
|
}
|
|
2980
3129
|
function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
@@ -2991,7 +3140,7 @@ function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
|
2991
3140
|
}
|
|
2992
3141
|
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(parent.block));
|
|
2993
3142
|
removeSubtree(nodes, parent.id, touched);
|
|
2994
|
-
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot);
|
|
3143
|
+
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot, touched, parent.blockEpoch);
|
|
2995
3144
|
if (!inserted) {
|
|
2996
3145
|
return false;
|
|
2997
3146
|
}
|
|
@@ -3014,7 +3163,55 @@ function arraysEqual(a, b) {
|
|
|
3014
3163
|
}
|
|
3015
3164
|
return true;
|
|
3016
3165
|
}
|
|
3017
|
-
function
|
|
3166
|
+
function expectedCodeLineId(parentId, index) {
|
|
3167
|
+
return `${parentId}::line:${index}`;
|
|
3168
|
+
}
|
|
3169
|
+
function collectStoreInvariantViolations(nodes) {
|
|
3170
|
+
const violations = [];
|
|
3171
|
+
for (const [id, node] of nodes) {
|
|
3172
|
+
if (node.type === "__root__") continue;
|
|
3173
|
+
if (node.children.length > 1) {
|
|
3174
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3175
|
+
for (const childId of node.children) {
|
|
3176
|
+
if (seen.has(childId)) {
|
|
3177
|
+
violations.push(`duplicate child id:${id}:${childId}`);
|
|
3178
|
+
} else {
|
|
3179
|
+
seen.add(childId);
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
if (node.type === "list") {
|
|
3184
|
+
const parent = node.parentId ? nodes.get(node.parentId) : void 0;
|
|
3185
|
+
if (parent?.type === "list-item" && node.children.length === 0) {
|
|
3186
|
+
violations.push(`empty nested list:${id}`);
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
if (node.type === "code") {
|
|
3190
|
+
for (let index = 0; index < node.children.length; index += 1) {
|
|
3191
|
+
const childId = node.children[index];
|
|
3192
|
+
const child = nodes.get(childId);
|
|
3193
|
+
if (!child) {
|
|
3194
|
+
violations.push(`missing code-line node:${node.id}:${childId}`);
|
|
3195
|
+
continue;
|
|
3196
|
+
}
|
|
3197
|
+
if (child.type !== "code-line") {
|
|
3198
|
+
violations.push(`non-code child in code block:${node.id}:${child.id}:${child.type}`);
|
|
3199
|
+
continue;
|
|
3200
|
+
}
|
|
3201
|
+
const expectedId = expectedCodeLineId(node.id, index);
|
|
3202
|
+
if (child.id !== expectedId) {
|
|
3203
|
+
violations.push(`code-line id mismatch:${node.id}:${child.id}:${expectedId}`);
|
|
3204
|
+
}
|
|
3205
|
+
const indexProp = typeof child.props?.index === "number" ? child.props.index : null;
|
|
3206
|
+
if (indexProp !== index) {
|
|
3207
|
+
violations.push(`code-line index mismatch:${node.id}:${child.id}:${indexProp}:${index}`);
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
return violations;
|
|
3213
|
+
}
|
|
3214
|
+
function buildNodeFromSnapshot(map, snapshot, parentId, blockEpoch) {
|
|
3018
3215
|
const record = {
|
|
3019
3216
|
id: snapshot.id,
|
|
3020
3217
|
type: snapshot.type,
|
|
@@ -3024,6 +3221,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
3024
3221
|
meta: snapshot.meta ? { ...snapshot.meta } : void 0,
|
|
3025
3222
|
range: snapshot.range ? { ...snapshot.range } : void 0,
|
|
3026
3223
|
version: 0,
|
|
3224
|
+
blockEpoch,
|
|
3027
3225
|
block: snapshotToBlock(snapshot) ?? void 0
|
|
3028
3226
|
};
|
|
3029
3227
|
if (record.type === "code") {
|
|
@@ -3032,7 +3230,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
3032
3230
|
map.set(record.id, record);
|
|
3033
3231
|
const childSnapshots = ensureArray(snapshot.children);
|
|
3034
3232
|
for (const child of childSnapshots) {
|
|
3035
|
-
const childRecord = buildNodeFromSnapshot(map, child, record.id);
|
|
3233
|
+
const childRecord = buildNodeFromSnapshot(map, child, record.id, blockEpoch);
|
|
3036
3234
|
record.children.push(childRecord.id);
|
|
3037
3235
|
}
|
|
3038
3236
|
return record;
|
|
@@ -3060,8 +3258,7 @@ function removeSubtree(map, id, touched) {
|
|
|
3060
3258
|
}
|
|
3061
3259
|
}
|
|
3062
3260
|
map.delete(node.id);
|
|
3063
|
-
|
|
3064
|
-
childrenSnapshotCache.delete(node.id);
|
|
3261
|
+
deleteSnapshotCacheEntry(map, node.id);
|
|
3065
3262
|
touched.add(node.id);
|
|
3066
3263
|
for (const childId of node.children) {
|
|
3067
3264
|
const child = map.get(childId);
|
|
@@ -3093,13 +3290,13 @@ function resolveParent(map, path) {
|
|
|
3093
3290
|
}
|
|
3094
3291
|
return map.get(path.blockId);
|
|
3095
3292
|
}
|
|
3096
|
-
function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
3293
|
+
function insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
3097
3294
|
if (!parent) return null;
|
|
3098
3295
|
const existingIndex = parent.children.indexOf(snapshot.id);
|
|
3099
3296
|
if (existingIndex !== -1) {
|
|
3100
3297
|
removeSubtree(map, parent.children[existingIndex], touched ?? /* @__PURE__ */ new Set());
|
|
3101
3298
|
}
|
|
3102
|
-
const record = buildNodeFromSnapshot(map, snapshot, parent.id);
|
|
3299
|
+
const record = buildNodeFromSnapshot(map, snapshot, parent.id, blockEpoch ?? readSnapshotBlockEpoch(snapshot) ?? parent.blockEpoch);
|
|
3103
3300
|
const insertedIds = [];
|
|
3104
3301
|
const queue = [record];
|
|
3105
3302
|
while (queue.length > 0) {
|
|
@@ -3117,13 +3314,13 @@ function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
|
3117
3314
|
ensureUniqueChildren(parent, touched);
|
|
3118
3315
|
return { record, insertedIds };
|
|
3119
3316
|
}
|
|
3120
|
-
function replaceSnapshotAt(map, parent, index, snapshot, touched) {
|
|
3317
|
+
function replaceSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
3121
3318
|
if (!parent) return;
|
|
3122
3319
|
if (index < 0 || index >= parent.children.length) return;
|
|
3123
3320
|
const targetId = parent.children[index];
|
|
3124
3321
|
parent.children.splice(index, 1);
|
|
3125
3322
|
removeSubtree(map, targetId, touched);
|
|
3126
|
-
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched);
|
|
3323
|
+
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch);
|
|
3127
3324
|
if (inserted) {
|
|
3128
3325
|
for (const id of inserted.insertedIds) {
|
|
3129
3326
|
touched.add(id);
|
|
@@ -3143,6 +3340,24 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3143
3340
|
const listeners = /* @__PURE__ */ new Set();
|
|
3144
3341
|
let notifyScheduled = false;
|
|
3145
3342
|
let lastCoalescingMetrics = null;
|
|
3343
|
+
let invariantViolations = [];
|
|
3344
|
+
let transientDiagnostics = [];
|
|
3345
|
+
let nextBlockEpoch = 1;
|
|
3346
|
+
const debugCounters = {
|
|
3347
|
+
appendLineGuardRejected: 0,
|
|
3348
|
+
staleEpochRejected: 0,
|
|
3349
|
+
storeInvariantViolationCount: 0
|
|
3350
|
+
};
|
|
3351
|
+
const allocateBlockEpoch = (preferred) => {
|
|
3352
|
+
const resolved = readNumericEpoch(preferred);
|
|
3353
|
+
if (resolved !== void 0) {
|
|
3354
|
+
nextBlockEpoch = Math.max(nextBlockEpoch, resolved + 1);
|
|
3355
|
+
return resolved;
|
|
3356
|
+
}
|
|
3357
|
+
const epoch = nextBlockEpoch;
|
|
3358
|
+
nextBlockEpoch += 1;
|
|
3359
|
+
return epoch;
|
|
3360
|
+
};
|
|
3146
3361
|
const getRaf = () => {
|
|
3147
3362
|
if (typeof globalThis !== "undefined" && typeof globalThis.requestAnimationFrame === "function") {
|
|
3148
3363
|
return globalThis.requestAnimationFrame;
|
|
@@ -3174,9 +3389,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3174
3389
|
}
|
|
3175
3390
|
}
|
|
3176
3391
|
}
|
|
3392
|
+
function appendDiagnostic(message) {
|
|
3393
|
+
transientDiagnostics = [...transientDiagnostics, message];
|
|
3394
|
+
invariantViolations = [...invariantViolations, message];
|
|
3395
|
+
}
|
|
3177
3396
|
function rebuildFromBlocks(blocks) {
|
|
3178
|
-
|
|
3179
|
-
childrenSnapshotCache.clear();
|
|
3397
|
+
clearSnapshotCaches(nodes);
|
|
3180
3398
|
nodes = /* @__PURE__ */ new Map();
|
|
3181
3399
|
const root = createRootRecord();
|
|
3182
3400
|
nodes.set(root.id, root);
|
|
@@ -3185,9 +3403,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3185
3403
|
for (let i = 0; i < blocks.length; i++) {
|
|
3186
3404
|
const block = (0, import_core4.cloneBlock)(blocks[i]);
|
|
3187
3405
|
const snapshot = (0, import_core4.createBlockSnapshot)(block);
|
|
3188
|
-
insertSnapshotAt(nodes, root, root.children.length, snapshot);
|
|
3406
|
+
insertSnapshotAt(nodes, root, root.children.length, snapshot, void 0, allocateBlockEpoch(readSnapshotBlockEpoch(snapshot)));
|
|
3189
3407
|
}
|
|
3190
3408
|
normalizeAllListDepths(nodes, /* @__PURE__ */ new Set(), import_core4.PATCH_ROOT_ID);
|
|
3409
|
+
transientDiagnostics = [];
|
|
3410
|
+
invariantViolations = collectStoreInvariantViolations(nodes);
|
|
3411
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
3191
3412
|
version++;
|
|
3192
3413
|
blocksDirty = true;
|
|
3193
3414
|
scheduleNotify();
|
|
@@ -3252,11 +3473,57 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3252
3473
|
listDepthDirty = true;
|
|
3253
3474
|
}
|
|
3254
3475
|
};
|
|
3255
|
-
const
|
|
3476
|
+
const semanticTxEpochs = /* @__PURE__ */ new Map();
|
|
3477
|
+
const resolveBlockEpochTarget = (patch, at) => {
|
|
3478
|
+
if ((patch.op === "insertChild" || patch.op === "replaceChild") && at.blockId === import_core4.PATCH_ROOT_ID) {
|
|
3479
|
+
const nodeId = patch.node?.id;
|
|
3480
|
+
return nodeId ? nodes.get(nodeId) : void 0;
|
|
3481
|
+
}
|
|
3482
|
+
return nodes.get(at.blockId) ?? (at.nodeId ? nodes.get(at.nodeId) : void 0);
|
|
3483
|
+
};
|
|
3484
|
+
const rejectStaleEpochPatch = (patch, at) => {
|
|
3485
|
+
const expectedBlockEpoch = readPatchBlockEpoch(patch);
|
|
3486
|
+
const patchTx = readPatchTx(patch);
|
|
3487
|
+
if (expectedBlockEpoch === void 0) {
|
|
3488
|
+
return false;
|
|
3489
|
+
}
|
|
3490
|
+
if ((0, import_patch_batching3.getPatchKind)(patch) !== "semantic" || !at) {
|
|
3491
|
+
return false;
|
|
3492
|
+
}
|
|
3493
|
+
const target = resolveBlockEpochTarget(patch, at);
|
|
3494
|
+
if (!target || target.blockEpoch === expectedBlockEpoch) {
|
|
3495
|
+
return false;
|
|
3496
|
+
}
|
|
3497
|
+
const txEpoch = at.blockId && patchTx !== void 0 ? semanticTxEpochs.get(at.blockId) : void 0;
|
|
3498
|
+
if (txEpoch && txEpoch.tx === patchTx && txEpoch.blockEpoch === target.blockEpoch) {
|
|
3499
|
+
return false;
|
|
3500
|
+
}
|
|
3501
|
+
debugCounters.staleEpochRejected += 1;
|
|
3502
|
+
appendDiagnostic(
|
|
3503
|
+
`stale epoch rejected:${patch.op}:${target.id}:expected=${expectedBlockEpoch}:actual=${target.blockEpoch}`
|
|
3504
|
+
);
|
|
3505
|
+
return true;
|
|
3506
|
+
};
|
|
3507
|
+
const advanceBlockEpoch = (blockId, touchedSet, preferredEpoch, tx) => {
|
|
3508
|
+
if (!blockId || blockId === import_core4.PATCH_ROOT_ID) {
|
|
3509
|
+
return null;
|
|
3510
|
+
}
|
|
3511
|
+
const blockRoot = nodes.get(blockId);
|
|
3512
|
+
if (!blockRoot) {
|
|
3513
|
+
return null;
|
|
3514
|
+
}
|
|
3515
|
+
const nextEpoch = allocateBlockEpoch(preferredEpoch);
|
|
3516
|
+
assignSubtreeBlockEpoch(nodes, blockRoot.id, nextEpoch, touchedSet);
|
|
3517
|
+
if (tx !== void 0) {
|
|
3518
|
+
semanticTxEpochs.set(blockRoot.id, { tx, blockEpoch: nextEpoch });
|
|
3519
|
+
}
|
|
3520
|
+
return nextEpoch;
|
|
3521
|
+
};
|
|
3522
|
+
const applyPropsUpdate = (at, props, preferredEpoch, tx, semanticUpdate = false) => {
|
|
3256
3523
|
const perfStartLocal = perfEnabled ? getPerfNow() : 0;
|
|
3257
3524
|
const targetId = at.nodeId ?? at.blockId;
|
|
3258
3525
|
if (!targetId) return;
|
|
3259
|
-
|
|
3526
|
+
let target = nodes.get(targetId);
|
|
3260
3527
|
if (!target) return;
|
|
3261
3528
|
const parentType = target.parentId ? nodes.get(target.parentId)?.type : void 0;
|
|
3262
3529
|
if (debugListPatches && (isListRelated(target.type) || isListRelated(parentType))) {
|
|
@@ -3283,6 +3550,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3283
3550
|
propsChanged = true;
|
|
3284
3551
|
}
|
|
3285
3552
|
if (propsChanged) {
|
|
3553
|
+
if (semanticUpdate) {
|
|
3554
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3555
|
+
}
|
|
3286
3556
|
target.version++;
|
|
3287
3557
|
touched.add(target.id);
|
|
3288
3558
|
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
@@ -3346,16 +3616,56 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3346
3616
|
}
|
|
3347
3617
|
}
|
|
3348
3618
|
let blockChanged = false;
|
|
3619
|
+
let typeChanged = false;
|
|
3620
|
+
let rebuiltFromFinalizedBlock = false;
|
|
3621
|
+
let blockEpochAdvanced = false;
|
|
3349
3622
|
const incomingBlock = props?.block;
|
|
3350
3623
|
if (incomingBlock && typeof incomingBlock === "object") {
|
|
3351
3624
|
target.block = (0, import_core4.cloneBlock)(incomingBlock);
|
|
3625
|
+
const previousType = target.type;
|
|
3626
|
+
const incomingType = typeof target.block.type === "string" ? target.block.type : target.type;
|
|
3627
|
+
if (incomingType !== target.type) {
|
|
3628
|
+
target.type = incomingType;
|
|
3629
|
+
typeChanged = true;
|
|
3630
|
+
if (isListRelated(previousType) || isListRelated(target.type)) {
|
|
3631
|
+
markListDepthDirty(target.id);
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3352
3634
|
if (target.type === "code") {
|
|
3353
3635
|
applyCodeBlockMetadata(target);
|
|
3354
3636
|
}
|
|
3637
|
+
if (semanticUpdate) {
|
|
3638
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3639
|
+
blockEpochAdvanced = true;
|
|
3640
|
+
}
|
|
3641
|
+
const shouldRebuildFinalizedTree = !at.nodeId && target.id === at.blockId && Boolean(target.block?.isFinalized) && target.type !== "code" && Boolean(target.parentId);
|
|
3642
|
+
if (shouldRebuildFinalizedTree) {
|
|
3643
|
+
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
3644
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
3645
|
+
if (parent && index !== -1) {
|
|
3646
|
+
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(target.block));
|
|
3647
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
3648
|
+
mutatedBlocks = true;
|
|
3649
|
+
blockChanged = true;
|
|
3650
|
+
rebuiltFromFinalizedBlock = true;
|
|
3651
|
+
const rebuilt = nodes.get(target.id);
|
|
3652
|
+
if (isListRelated(previousType) || isListRelated(rebuilt?.type)) {
|
|
3653
|
+
markListDepthDirty(target.id);
|
|
3654
|
+
}
|
|
3655
|
+
target = rebuilt ?? target;
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3355
3658
|
mutatedBlocks = true;
|
|
3356
3659
|
blockChanged = true;
|
|
3357
3660
|
}
|
|
3358
|
-
if (
|
|
3661
|
+
if (rebuiltFromFinalizedBlock) {
|
|
3662
|
+
return;
|
|
3663
|
+
}
|
|
3664
|
+
if (propsChanged || blockChanged || typeChanged) {
|
|
3665
|
+
if (semanticUpdate && !blockEpochAdvanced) {
|
|
3666
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3667
|
+
blockEpochAdvanced = true;
|
|
3668
|
+
}
|
|
3359
3669
|
target.version++;
|
|
3360
3670
|
touched.add(target.id);
|
|
3361
3671
|
let parentForNormalization;
|
|
@@ -3398,13 +3708,22 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3398
3708
|
const applyPatch = (patch) => {
|
|
3399
3709
|
switch (patch.op) {
|
|
3400
3710
|
case "insertChild": {
|
|
3711
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3401
3712
|
const parent = resolveParent(nodes, patch.at);
|
|
3402
|
-
const inserted = insertSnapshotAt(
|
|
3713
|
+
const inserted = insertSnapshotAt(
|
|
3714
|
+
nodes,
|
|
3715
|
+
parent,
|
|
3716
|
+
patch.index,
|
|
3717
|
+
patch.node,
|
|
3718
|
+
touched,
|
|
3719
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
3720
|
+
);
|
|
3403
3721
|
if (inserted) {
|
|
3404
3722
|
for (const id of inserted.insertedIds) {
|
|
3405
3723
|
touched.add(id);
|
|
3406
3724
|
}
|
|
3407
3725
|
mutatedBlocks = true;
|
|
3726
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3408
3727
|
if (isListRelated(inserted.record.type) || isListRelated(parent?.type)) {
|
|
3409
3728
|
markListDepthDirty(inserted.record.id);
|
|
3410
3729
|
if (parent) {
|
|
@@ -3424,6 +3743,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3424
3743
|
break;
|
|
3425
3744
|
}
|
|
3426
3745
|
case "deleteChild": {
|
|
3746
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3427
3747
|
const parent = resolveParent(nodes, patch.at);
|
|
3428
3748
|
if (!parent) break;
|
|
3429
3749
|
if (patch.index < 0 || patch.index >= parent.children.length) break;
|
|
@@ -3435,6 +3755,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3435
3755
|
touched.add(parent.id);
|
|
3436
3756
|
ensureUniqueChildren(parent, touched);
|
|
3437
3757
|
mutatedBlocks = true;
|
|
3758
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3438
3759
|
if (isListRelated(parent.type) || isListRelated(removedNode?.type)) {
|
|
3439
3760
|
markListDepthDirty(parent.id);
|
|
3440
3761
|
}
|
|
@@ -3451,11 +3772,20 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3451
3772
|
break;
|
|
3452
3773
|
}
|
|
3453
3774
|
case "replaceChild": {
|
|
3775
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3454
3776
|
const parent = resolveParent(nodes, patch.at);
|
|
3455
3777
|
if (!parent) break;
|
|
3456
|
-
replaceSnapshotAt(
|
|
3778
|
+
replaceSnapshotAt(
|
|
3779
|
+
nodes,
|
|
3780
|
+
parent,
|
|
3781
|
+
patch.index,
|
|
3782
|
+
patch.node,
|
|
3783
|
+
touched,
|
|
3784
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
3785
|
+
);
|
|
3457
3786
|
touched.add(parent.id);
|
|
3458
3787
|
mutatedBlocks = true;
|
|
3788
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3459
3789
|
if (isListRelated(parent.type)) {
|
|
3460
3790
|
markListDepthDirty(parent.id);
|
|
3461
3791
|
}
|
|
@@ -3469,18 +3799,33 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3469
3799
|
break;
|
|
3470
3800
|
}
|
|
3471
3801
|
case "setProps": {
|
|
3472
|
-
|
|
3802
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3803
|
+
applyPropsUpdate(patch.at, patch.props, readPatchParseEpoch(patch), readPatchTx(patch), (0, import_patch_batching3.getPatchKind)(patch) === "semantic");
|
|
3473
3804
|
break;
|
|
3474
3805
|
}
|
|
3475
3806
|
case "setPropsBatch": {
|
|
3476
3807
|
const entries2 = Array.isArray(patch.entries) ? patch.entries : [];
|
|
3477
3808
|
for (const entry of entries2) {
|
|
3478
3809
|
if (!entry || !entry.at) continue;
|
|
3479
|
-
|
|
3810
|
+
const entryPatch = {
|
|
3811
|
+
op: "setProps",
|
|
3812
|
+
at: entry.at,
|
|
3813
|
+
props: entry.props,
|
|
3814
|
+
meta: entry.meta ?? patch.meta
|
|
3815
|
+
};
|
|
3816
|
+
if (rejectStaleEpochPatch(entryPatch, entry.at)) continue;
|
|
3817
|
+
applyPropsUpdate(
|
|
3818
|
+
entry.at,
|
|
3819
|
+
entry.props,
|
|
3820
|
+
readPatchParseEpoch(entryPatch),
|
|
3821
|
+
readPatchTx(entryPatch),
|
|
3822
|
+
(0, import_patch_batching3.getPatchKind)(entryPatch) === "semantic"
|
|
3823
|
+
);
|
|
3480
3824
|
}
|
|
3481
3825
|
break;
|
|
3482
3826
|
}
|
|
3483
3827
|
case "finalize": {
|
|
3828
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3484
3829
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
3485
3830
|
if (!target || !target.block) break;
|
|
3486
3831
|
if (!target.block.isFinalized) {
|
|
@@ -3489,6 +3834,17 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3489
3834
|
target.version++;
|
|
3490
3835
|
touched.add(target.id);
|
|
3491
3836
|
mutatedBlocks = true;
|
|
3837
|
+
if (!patch.at.nodeId && target.id === patch.at.blockId && target.type !== "code" && target.parentId) {
|
|
3838
|
+
const parent = nodes.get(target.parentId);
|
|
3839
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
3840
|
+
if (parent && index !== -1) {
|
|
3841
|
+
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(target.block));
|
|
3842
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
3843
|
+
if (isListRelated(target.type) || isListRelated(snapshot.type)) {
|
|
3844
|
+
markListDepthDirty(target.id);
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3492
3848
|
}
|
|
3493
3849
|
if (isListRelated(target.type)) {
|
|
3494
3850
|
markListDepthDirty(target.id);
|
|
@@ -3502,6 +3858,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3502
3858
|
break;
|
|
3503
3859
|
}
|
|
3504
3860
|
case "reorder": {
|
|
3861
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3505
3862
|
const parent = resolveParent(nodes, patch.at);
|
|
3506
3863
|
if (!parent) break;
|
|
3507
3864
|
const length = parent.children.length;
|
|
@@ -3516,6 +3873,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3516
3873
|
parent.children.splice(to, 0, ...moved);
|
|
3517
3874
|
parent.version++;
|
|
3518
3875
|
touched.add(parent.id);
|
|
3876
|
+
if ((0, import_patch_batching3.getPatchKind)(patch) === "semantic") {
|
|
3877
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3878
|
+
}
|
|
3519
3879
|
if (isListRelated(parent.type)) {
|
|
3520
3880
|
markListDepthDirty(parent.id);
|
|
3521
3881
|
}
|
|
@@ -3531,15 +3891,31 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3531
3891
|
break;
|
|
3532
3892
|
}
|
|
3533
3893
|
case "appendLines": {
|
|
3894
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3534
3895
|
const parent = resolveParent(nodes, patch.at);
|
|
3535
3896
|
if (!parent) break;
|
|
3536
|
-
|
|
3897
|
+
if (parent.type !== "code") {
|
|
3898
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
3899
|
+
appendDiagnostic(`appendLines target not code:${parent.id}:${parent.type}`);
|
|
3900
|
+
break;
|
|
3901
|
+
}
|
|
3902
|
+
const requestedStartIndex = Math.max(0, patch.startIndex);
|
|
3903
|
+
const startIndex = Math.max(0, Math.min(requestedStartIndex, parent.children.length));
|
|
3537
3904
|
const lineCount = patch.lines?.length ?? 0;
|
|
3538
3905
|
if (lineCount === 0) break;
|
|
3906
|
+
const prefixMatches = parent.children.every((childId, index) => childId === expectedCodeLineId(parent.id, index));
|
|
3907
|
+
const isStrictTailAppend = requestedStartIndex === parent.children.length;
|
|
3908
|
+
if (!isStrictTailAppend || !prefixMatches) {
|
|
3909
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
3910
|
+
appendDiagnostic(
|
|
3911
|
+
`appendLines guard rejected:${parent.id}:requestedStart=${requestedStartIndex}:childCount=${parent.children.length}:prefixMatches=${prefixMatches}`
|
|
3912
|
+
);
|
|
3913
|
+
break;
|
|
3914
|
+
}
|
|
3539
3915
|
const originalChildren = parent.children.slice();
|
|
3540
3916
|
const insertedIds = [];
|
|
3541
3917
|
const insertedSet = /* @__PURE__ */ new Set();
|
|
3542
|
-
const isTrailingAppend =
|
|
3918
|
+
const isTrailingAppend = true;
|
|
3543
3919
|
let parentChildrenChanged = false;
|
|
3544
3920
|
let codeLinesMutated = false;
|
|
3545
3921
|
for (let offset = 0; offset < lineCount; offset++) {
|
|
@@ -3581,7 +3957,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3581
3957
|
parentId: parent.id,
|
|
3582
3958
|
children: [],
|
|
3583
3959
|
props: nextLineProps,
|
|
3584
|
-
version: 0
|
|
3960
|
+
version: 0,
|
|
3961
|
+
blockEpoch: parent.blockEpoch
|
|
3585
3962
|
};
|
|
3586
3963
|
nodes.set(lineId, record);
|
|
3587
3964
|
touched.add(lineId);
|
|
@@ -3631,6 +4008,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3631
4008
|
break;
|
|
3632
4009
|
}
|
|
3633
4010
|
case "setHTML": {
|
|
4011
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3634
4012
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
3635
4013
|
if (!target) break;
|
|
3636
4014
|
const sanitized = patch.sanitized ? patch.html : (0, import_core4.sanitizeHTML)(patch.html);
|
|
@@ -3673,6 +4051,30 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3673
4051
|
applyPatch(patch);
|
|
3674
4052
|
}
|
|
3675
4053
|
}
|
|
4054
|
+
const finalizedTableRoots = /* @__PURE__ */ new Set();
|
|
4055
|
+
for (const touchedId of touched) {
|
|
4056
|
+
let cursor = nodes.get(touchedId);
|
|
4057
|
+
while (cursor && cursor.id !== import_core4.PATCH_ROOT_ID) {
|
|
4058
|
+
if (cursor.type === "table" && cursor.block?.isFinalized && cursor.parentId) {
|
|
4059
|
+
finalizedTableRoots.add(cursor.id);
|
|
4060
|
+
break;
|
|
4061
|
+
}
|
|
4062
|
+
cursor = cursor.parentId ? nodes.get(cursor.parentId) : void 0;
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
if (finalizedTableRoots.size > 0) {
|
|
4066
|
+
for (const tableId of finalizedTableRoots) {
|
|
4067
|
+
const tableNode = nodes.get(tableId);
|
|
4068
|
+
if (!tableNode || !tableNode.block || !tableNode.parentId) continue;
|
|
4069
|
+
const parent = nodes.get(tableNode.parentId);
|
|
4070
|
+
if (!parent) continue;
|
|
4071
|
+
const index = parent.children.indexOf(tableNode.id);
|
|
4072
|
+
if (index === -1) continue;
|
|
4073
|
+
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(tableNode.block));
|
|
4074
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, tableNode.blockEpoch);
|
|
4075
|
+
mutatedBlocks = true;
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
3676
4078
|
if (mutatedBlocks) {
|
|
3677
4079
|
blocksDirty = true;
|
|
3678
4080
|
}
|
|
@@ -3693,6 +4095,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3693
4095
|
normalizeListDepthsForIds(nodes, touched, listDepthDirtyNodes, import_core4.PATCH_ROOT_ID);
|
|
3694
4096
|
}
|
|
3695
4097
|
}
|
|
4098
|
+
invariantViolations = [...collectStoreInvariantViolations(nodes), ...transientDiagnostics];
|
|
4099
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
3696
4100
|
if (touched.size > 0 || mutatedBlocks) {
|
|
3697
4101
|
version++;
|
|
3698
4102
|
scheduleNotify();
|
|
@@ -3741,6 +4145,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3741
4145
|
if (!record) {
|
|
3742
4146
|
return EMPTY_NODE_SNAPSHOT;
|
|
3743
4147
|
}
|
|
4148
|
+
const nodeSnapshotCache = getNodeSnapshotCacheForMap(nodes);
|
|
3744
4149
|
const cached = nodeSnapshotCache.get(id);
|
|
3745
4150
|
if (cached && cached.version === record.version && cached.node === record) {
|
|
3746
4151
|
return cached;
|
|
@@ -3760,6 +4165,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3760
4165
|
if (!record) {
|
|
3761
4166
|
return EMPTY_CHILDREN_SNAPSHOT;
|
|
3762
4167
|
}
|
|
4168
|
+
const childrenSnapshotCache = getChildrenSnapshotCacheForMap(nodes);
|
|
3763
4169
|
const cached = childrenSnapshotCache.get(id);
|
|
3764
4170
|
if (cached && cached.version === record.version) {
|
|
3765
4171
|
return cached;
|
|
@@ -3769,6 +4175,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3769
4175
|
pruneCache(childrenSnapshotCache, CHILDREN_SNAPSHOT_CACHE_LIMIT, CHILDREN_SNAPSHOT_CACHE_BUFFER);
|
|
3770
4176
|
return snapshot;
|
|
3771
4177
|
},
|
|
4178
|
+
getInvariantViolations() {
|
|
4179
|
+
return invariantViolations.slice();
|
|
4180
|
+
},
|
|
4181
|
+
getDebugCounters() {
|
|
4182
|
+
return { ...debugCounters };
|
|
4183
|
+
},
|
|
3772
4184
|
getLastCoalescingMetrics() {
|
|
3773
4185
|
return lastCoalescingMetrics;
|
|
3774
4186
|
},
|
|
@@ -4246,8 +4658,10 @@ var ListBlockView = import_react10.default.memo(
|
|
|
4246
4658
|
isFinalized: block?.isFinalized ?? false
|
|
4247
4659
|
});
|
|
4248
4660
|
}, [listDebugEnabled, blockId, depth, ordered, childIds, listItemIds, store, block?.isFinalized]);
|
|
4249
|
-
const listStyle = import_react10.default.useMemo(() => {
|
|
4250
|
-
if (!ordered || listItemIds.length === 0)
|
|
4661
|
+
const { listStyle, markerDigits } = import_react10.default.useMemo(() => {
|
|
4662
|
+
if (!ordered || listItemIds.length === 0) {
|
|
4663
|
+
return { listStyle: void 0, markerDigits: 1 };
|
|
4664
|
+
}
|
|
4251
4665
|
let maxDigits = 1;
|
|
4252
4666
|
listItemIds.forEach((childId, index) => {
|
|
4253
4667
|
const childNode = store.getNode(childId);
|
|
@@ -4259,9 +4673,14 @@ var ListBlockView = import_react10.default.memo(
|
|
|
4259
4673
|
const digits = digitMatch ? digitMatch.length : text.length;
|
|
4260
4674
|
if (digits > maxDigits) maxDigits = digits;
|
|
4261
4675
|
});
|
|
4262
|
-
const baseIndent = depth === 0 ? "
|
|
4676
|
+
const baseIndent = depth === 0 ? "2rem" : depth === 1 ? "1.75rem" : "1.5rem";
|
|
4677
|
+
const extraDigits = Math.max(0, maxDigits - 1);
|
|
4263
4678
|
return {
|
|
4264
|
-
|
|
4679
|
+
markerDigits: maxDigits,
|
|
4680
|
+
listStyle: {
|
|
4681
|
+
["--list-indent"]: extraDigits > 0 ? `calc(${baseIndent} + ${extraDigits}ch)` : baseIndent,
|
|
4682
|
+
["--list-marker-digits"]: String(maxDigits)
|
|
4683
|
+
}
|
|
4265
4684
|
};
|
|
4266
4685
|
}, [ordered, listItemIds, store, depth]);
|
|
4267
4686
|
if (listItemIds.length === 0) return null;
|
|
@@ -4270,6 +4689,7 @@ var ListBlockView = import_react10.default.memo(
|
|
|
4270
4689
|
{
|
|
4271
4690
|
className: `markdown-list ${ordered ? "ordered" : "unordered"}`,
|
|
4272
4691
|
"data-list-depth": depth,
|
|
4692
|
+
"data-marker-digits": ordered ? markerDigits : void 0,
|
|
4273
4693
|
"data-list-id": listDebugEnabled ? blockId : void 0,
|
|
4274
4694
|
style: listStyle,
|
|
4275
4695
|
children: listItemIds.map((childId, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -4451,6 +4871,7 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4451
4871
|
deferredConfig ? { ...deferredConfig, enabled: true } : { enabled: false }
|
|
4452
4872
|
);
|
|
4453
4873
|
if (!node || !node.block) return null;
|
|
4874
|
+
const blockIsFinalized = node.block.isFinalized;
|
|
4454
4875
|
const nodeVersion = node.version;
|
|
4455
4876
|
const lines = import_react10.default.useMemo(() => {
|
|
4456
4877
|
const seenIds = /* @__PURE__ */ new Set();
|
|
@@ -4481,13 +4902,25 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4481
4902
|
const lang = typeof node.props?.lang === "string" ? node.props?.lang : node.block.payload.meta?.lang;
|
|
4482
4903
|
const preAttrs = node.props?.preAttrs ?? void 0;
|
|
4483
4904
|
const codeAttrs = node.props?.codeAttrs ?? void 0;
|
|
4905
|
+
const blockMeta = node.block.payload.meta ?? void 0;
|
|
4906
|
+
const lazyEnabled = Boolean(blockMeta?.lazyTokenization);
|
|
4907
|
+
const lazyTokenizedUntil = typeof blockMeta?.lazyTokenizedUntil === "number" ? blockMeta.lazyTokenizedUntil : 0;
|
|
4908
|
+
const lazyHighlightedLines = Array.isArray(blockMeta?.highlightedLines) ? blockMeta.highlightedLines.length : 0;
|
|
4909
|
+
const lazyTokenLines = Array.isArray(blockMeta?.tokenLines) ? blockMeta.tokenLines.length : 0;
|
|
4910
|
+
const lazySourceTextLineCount = import_react10.default.useMemo(() => {
|
|
4911
|
+
const raw = typeof node.block?.payload.raw === "string" ? node.block.payload.raw : "";
|
|
4912
|
+
const metaCode = typeof blockMeta?.code === "string" ? blockMeta.code : null;
|
|
4913
|
+
const sourceText = resolveCodeSourceText(raw, metaCode);
|
|
4914
|
+
if (sourceText.length === 0) return 0;
|
|
4915
|
+
return sourceText.split("\n").length;
|
|
4916
|
+
}, [blockMeta, node.block?.payload.raw]);
|
|
4917
|
+
const totalLazyLineCount = Math.max(lines.length, lazyHighlightedLines, lazyTokenLines, lazySourceTextLineCount);
|
|
4484
4918
|
const virtualizationConfig = DEFAULT_VIRTUALIZED_CODE_CONFIG;
|
|
4485
4919
|
const virtualizationDisabled = typeof process !== "undefined" && typeof process.env === "object" && process.env.STREAM_MDX_DISABLE_VIRTUALIZED_CODE === "true";
|
|
4486
|
-
const
|
|
4920
|
+
const canVirtualize = node.block.isFinalized && !lazyEnabled;
|
|
4921
|
+
const shouldVirtualize = canVirtualize && !virtualizationDisabled && virtualizationConfig.enabled && lines.length >= virtualizationConfig.virtualizeThreshold;
|
|
4487
4922
|
const virtualization = useVirtualizedCode(lines, shouldVirtualize ? virtualizationConfig : { ...virtualizationConfig, enabled: false });
|
|
4488
4923
|
const highlightRequester = useCodeHighlightRequester();
|
|
4489
|
-
const lazyEnabled = Boolean(node.block.payload.meta?.lazyTokenization);
|
|
4490
|
-
const lazyTokenizedUntil = typeof node.block.payload.meta?.lazyTokenizedUntil === "number" ? node.block.payload.meta.lazyTokenizedUntil : 0;
|
|
4491
4924
|
const lastRangeRef = import_react10.default.useRef(null);
|
|
4492
4925
|
const rafRef = import_react10.default.useRef(null);
|
|
4493
4926
|
const idleRef = import_react10.default.useRef(null);
|
|
@@ -4568,29 +5001,111 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4568
5001
|
virtualization.window.startIndex,
|
|
4569
5002
|
virtualization.window.endIndex
|
|
4570
5003
|
]);
|
|
4571
|
-
|
|
4572
|
-
if (
|
|
4573
|
-
|
|
5004
|
+
import_react10.default.useEffect(() => {
|
|
5005
|
+
if (shouldVirtualize || !blockIsFinalized || !lazyEnabled || !highlightRequester) return;
|
|
5006
|
+
if (totalLazyLineCount <= 0 || lazyTokenizedUntil >= totalLazyLineCount) return;
|
|
5007
|
+
const nextRange = {
|
|
5008
|
+
visibleStart: 0,
|
|
5009
|
+
visibleEnd: totalLazyLineCount,
|
|
5010
|
+
prefetchStart: 0,
|
|
5011
|
+
prefetchEnd: totalLazyLineCount,
|
|
5012
|
+
tokenizedUntil: lazyTokenizedUntil
|
|
5013
|
+
};
|
|
5014
|
+
const last = lastRangeRef.current;
|
|
5015
|
+
if (last && last.visibleStart === nextRange.visibleStart && last.visibleEnd === nextRange.visibleEnd && last.prefetchStart === nextRange.prefetchStart && last.prefetchEnd === nextRange.prefetchEnd && last.tokenizedUntil === nextRange.tokenizedUntil) {
|
|
5016
|
+
return;
|
|
5017
|
+
}
|
|
5018
|
+
lastRangeRef.current = nextRange;
|
|
5019
|
+
if (rafRef.current !== null && typeof cancelAnimationFrame === "function") {
|
|
5020
|
+
cancelAnimationFrame(rafRef.current);
|
|
4574
5021
|
}
|
|
5022
|
+
const requestFullHighlight = () => {
|
|
5023
|
+
highlightRequester({
|
|
5024
|
+
blockId,
|
|
5025
|
+
startLine: 0,
|
|
5026
|
+
endLine: totalLazyLineCount,
|
|
5027
|
+
priority: "visible",
|
|
5028
|
+
reason: "finalize-full"
|
|
5029
|
+
});
|
|
5030
|
+
rafRef.current = null;
|
|
5031
|
+
};
|
|
5032
|
+
if (typeof requestAnimationFrame === "function") {
|
|
5033
|
+
rafRef.current = requestAnimationFrame(requestFullHighlight);
|
|
5034
|
+
} else {
|
|
5035
|
+
requestFullHighlight();
|
|
5036
|
+
}
|
|
5037
|
+
}, [blockId, blockIsFinalized, highlightRequester, lazyEnabled, lazyTokenizedUntil, shouldVirtualize, totalLazyLineCount]);
|
|
5038
|
+
const highlightedHtml = import_react10.default.useMemo(() => {
|
|
5039
|
+
const blockHtml = node.block?.payload.highlightedHtml ?? "";
|
|
5040
|
+
const raw = typeof node.block?.payload.raw === "string" ? node.block.payload.raw : "";
|
|
5041
|
+
const metaCode = typeof node.block?.payload.meta?.code === "string" ? (node.block?.payload.meta).code : null;
|
|
5042
|
+
const sourceText = resolveCodeSourceText(raw, metaCode);
|
|
5043
|
+
const sourceEndsWithNewline = sourceText.endsWith("\n");
|
|
5044
|
+
const sourceLines = sourceText.length > 0 ? sourceText.split("\n") : [];
|
|
5045
|
+
const rawFallbackLines = buildCodeFallbackLines(raw);
|
|
5046
|
+
const deterministicWrapperAttrs = (0, import_core5.getDefaultCodeWrapperAttributes)(lang);
|
|
5047
|
+
const composedPreAttrs = deterministicWrapperAttrs.preAttrs;
|
|
5048
|
+
const composedCodeAttrs = deterministicWrapperAttrs.codeAttrs;
|
|
5049
|
+
const shouldAppendTerminalNewline = (renderedLines) => {
|
|
5050
|
+
if (!sourceEndsWithNewline || renderedLines.length === 0 || lines.length === 0) {
|
|
5051
|
+
return false;
|
|
5052
|
+
}
|
|
5053
|
+
const lastRendered = renderedLines[renderedLines.length - 1];
|
|
5054
|
+
const lastKnown = lines[lines.length - 1];
|
|
5055
|
+
if (!lastRendered || !lastKnown || lastRendered.index !== lastKnown.index || lastRendered.text === "") {
|
|
5056
|
+
return false;
|
|
5057
|
+
}
|
|
5058
|
+
const expectedRenderedLineCount = Math.max(0, sourceLines.length - 1);
|
|
5059
|
+
const expectedLastRenderedLine = sourceLines.length >= 2 ? sourceLines[sourceLines.length - 2] ?? "" : "";
|
|
5060
|
+
return renderedLines.length === expectedRenderedLineCount && lastRendered.text === expectedLastRenderedLine;
|
|
5061
|
+
};
|
|
4575
5062
|
if (lines.length > 0) {
|
|
4576
5063
|
const hasLineHtml = lines.some((line) => typeof line.html === "string" && line.html.length > 0);
|
|
4577
|
-
if (!hasLineHtml &&
|
|
4578
|
-
return
|
|
5064
|
+
if (!hasLineHtml && blockHtml) {
|
|
5065
|
+
return blockHtml;
|
|
4579
5066
|
}
|
|
4580
5067
|
if (shouldVirtualize) {
|
|
4581
|
-
return composeHighlightedHtml(
|
|
5068
|
+
return composeHighlightedHtml(
|
|
5069
|
+
virtualization.window.visibleLines,
|
|
5070
|
+
composedPreAttrs,
|
|
5071
|
+
composedCodeAttrs,
|
|
5072
|
+
shouldAppendTerminalNewline(virtualization.window.visibleLines)
|
|
5073
|
+
);
|
|
5074
|
+
}
|
|
5075
|
+
return composeHighlightedHtml(lines, composedPreAttrs, composedCodeAttrs, shouldAppendTerminalNewline(lines));
|
|
5076
|
+
}
|
|
5077
|
+
if (!shouldVirtualize && blockHtml) {
|
|
5078
|
+
const hasHighlightedLines = blockHtml.includes('class="line"');
|
|
5079
|
+
if (!hasHighlightedLines && rawFallbackLines.length > 0) {
|
|
5080
|
+
return composeHighlightedHtml(
|
|
5081
|
+
rawFallbackLines,
|
|
5082
|
+
composedPreAttrs,
|
|
5083
|
+
composedCodeAttrs,
|
|
5084
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5085
|
+
);
|
|
4582
5086
|
}
|
|
4583
|
-
return
|
|
5087
|
+
return blockHtml;
|
|
4584
5088
|
}
|
|
4585
|
-
const blockHtml = node.block?.payload.highlightedHtml ?? "";
|
|
4586
5089
|
if (blockHtml?.trim().match(/^```[\w-]*\s*$/)) {
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
5090
|
+
if (rawFallbackLines.length > 0) {
|
|
5091
|
+
return composeHighlightedHtml(
|
|
5092
|
+
rawFallbackLines,
|
|
5093
|
+
composedPreAttrs,
|
|
5094
|
+
composedCodeAttrs,
|
|
5095
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5096
|
+
);
|
|
4590
5097
|
}
|
|
4591
5098
|
}
|
|
5099
|
+
if (!blockHtml && rawFallbackLines.length > 0) {
|
|
5100
|
+
return composeHighlightedHtml(
|
|
5101
|
+
rawFallbackLines,
|
|
5102
|
+
composedPreAttrs,
|
|
5103
|
+
composedCodeAttrs,
|
|
5104
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5105
|
+
);
|
|
5106
|
+
}
|
|
4592
5107
|
return blockHtml;
|
|
4593
|
-
}, [shouldVirtualize, node.block?.payload.highlightedHtml,
|
|
5108
|
+
}, [blockIsFinalized, shouldVirtualize, node.block?.payload.highlightedHtml, node.block?.payload.meta, lines, lang, virtualization.window.visibleLines, node.block?.payload.raw]);
|
|
4594
5109
|
const rendered = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
4595
5110
|
CodeComponent,
|
|
4596
5111
|
{
|
|
@@ -4602,13 +5117,19 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4602
5117
|
codeAttrs
|
|
4603
5118
|
}
|
|
4604
5119
|
);
|
|
5120
|
+
const effectiveLineCount = import_react10.default.useMemo(() => {
|
|
5121
|
+
if (lines.length > 0) {
|
|
5122
|
+
return lines.length;
|
|
5123
|
+
}
|
|
5124
|
+
return 1;
|
|
5125
|
+
}, [lines.length]);
|
|
4605
5126
|
const codeFrameClass = "not-prose flex flex-col rounded-lg border border-input pt-1 font-mono text-sm";
|
|
4606
5127
|
const codeMetricsAttrs = {
|
|
4607
5128
|
"data-code-block": "true",
|
|
4608
5129
|
"data-block-id": blockId,
|
|
4609
5130
|
"data-code-virtualized": shouldVirtualize ? "true" : "false",
|
|
4610
|
-
"data-code-total-lines": String(
|
|
4611
|
-
"data-code-mounted-lines": String(shouldVirtualize ? virtualization.window.mountedLines :
|
|
5131
|
+
"data-code-total-lines": String(effectiveLineCount),
|
|
5132
|
+
"data-code-mounted-lines": String(shouldVirtualize ? virtualization.window.mountedLines : effectiveLineCount),
|
|
4612
5133
|
"data-code-window-size": String(virtualization.config.windowSize)
|
|
4613
5134
|
};
|
|
4614
5135
|
const codeView = shouldVirtualize ? (() => {
|
|
@@ -4654,21 +5175,152 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4654
5175
|
return codeView;
|
|
4655
5176
|
});
|
|
4656
5177
|
CodeBlockView.displayName = "CodeBlockView";
|
|
4657
|
-
function composeHighlightedHtml(lines, preAttrs, codeAttrs) {
|
|
5178
|
+
function composeHighlightedHtml(lines, preAttrs, codeAttrs, appendTerminalNewline = false) {
|
|
4658
5179
|
const lineMarkup = lines.map((line) => {
|
|
4659
|
-
const content = line.html ?? escapeHtml3(line.text);
|
|
5180
|
+
const content = line.html ?? renderTokenLineHtml(line.tokens) ?? escapeHtml3(line.text);
|
|
4660
5181
|
const dataLine = Number.isFinite(line.index) ? ` data-line="${line.index + 1}"` : "";
|
|
4661
5182
|
return `<span class="line"${dataLine}>${content}</span>`;
|
|
4662
5183
|
}).join("\n");
|
|
4663
5184
|
const preAttr = attrsToString(preAttrs);
|
|
4664
5185
|
const codeAttr = attrsToString(codeAttrs);
|
|
4665
|
-
return `<pre${preAttr}><code${codeAttr}>${lineMarkup}
|
|
4666
|
-
|
|
5186
|
+
return `<pre${preAttr}><code${codeAttr}>${lineMarkup}${appendTerminalNewline ? "\n" : ""}</code></pre>`;
|
|
5187
|
+
}
|
|
5188
|
+
var TOKEN_FONT_STYLE_ITALIC = 1;
|
|
5189
|
+
var TOKEN_FONT_STYLE_BOLD = 2;
|
|
5190
|
+
var TOKEN_FONT_STYLE_UNDERLINE = 4;
|
|
5191
|
+
var TOKEN_FONT_STYLE_STRIKETHROUGH = 8;
|
|
5192
|
+
function renderTokenLineHtml(tokens) {
|
|
5193
|
+
if (!tokens || !Array.isArray(tokens.spans)) {
|
|
5194
|
+
return null;
|
|
5195
|
+
}
|
|
5196
|
+
return mergeRenderableTokenSpans(tokens.spans).map((span) => renderTokenSpanHtml(span)).join("");
|
|
5197
|
+
}
|
|
5198
|
+
function renderTokenSpanHtml(span) {
|
|
5199
|
+
const dark = span.v?.dark;
|
|
5200
|
+
const light = span.v?.light;
|
|
5201
|
+
const single = span.s;
|
|
5202
|
+
const styles = [];
|
|
5203
|
+
if (dark?.fg) {
|
|
5204
|
+
styles.push(`--shiki-dark:${dark.fg}`);
|
|
5205
|
+
}
|
|
5206
|
+
if (light?.fg) {
|
|
5207
|
+
styles.push(`--shiki-light:${light.fg}`);
|
|
5208
|
+
}
|
|
5209
|
+
if (!light?.fg && !dark?.fg && single?.fg) {
|
|
5210
|
+
styles.push(`color:${single.fg}`);
|
|
5211
|
+
}
|
|
5212
|
+
const fontStyle = light?.fs ?? dark?.fs ?? single?.fs;
|
|
5213
|
+
if (typeof fontStyle === "number" && fontStyle > 0) {
|
|
5214
|
+
if (fontStyle & TOKEN_FONT_STYLE_ITALIC) {
|
|
5215
|
+
styles.push("font-style: italic");
|
|
5216
|
+
}
|
|
5217
|
+
if (fontStyle & TOKEN_FONT_STYLE_BOLD) {
|
|
5218
|
+
styles.push("font-weight: bold");
|
|
5219
|
+
}
|
|
5220
|
+
const decorations = [];
|
|
5221
|
+
if (fontStyle & TOKEN_FONT_STYLE_UNDERLINE) {
|
|
5222
|
+
decorations.push("underline");
|
|
5223
|
+
}
|
|
5224
|
+
if (fontStyle & TOKEN_FONT_STYLE_STRIKETHROUGH) {
|
|
5225
|
+
decorations.push("line-through");
|
|
5226
|
+
}
|
|
5227
|
+
if (decorations.length > 0) {
|
|
5228
|
+
styles.push(`text-decoration: ${decorations.join(" ")}`);
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
const content = escapeHtml3(span.t ?? "");
|
|
5232
|
+
if (styles.length === 0) {
|
|
5233
|
+
return content;
|
|
5234
|
+
}
|
|
5235
|
+
return `<span style="${styles.join(";")}">${content}</span>`;
|
|
5236
|
+
}
|
|
5237
|
+
function mergeRenderableTokenSpans(spans) {
|
|
5238
|
+
if (spans.length <= 1) {
|
|
5239
|
+
return spans.slice();
|
|
5240
|
+
}
|
|
5241
|
+
const merged = [];
|
|
5242
|
+
let pendingWhitespace = "";
|
|
5243
|
+
for (const span of spans) {
|
|
5244
|
+
const text = typeof span.t === "string" ? span.t : "";
|
|
5245
|
+
if (/^[\t ]+$/.test(text)) {
|
|
5246
|
+
pendingWhitespace += text;
|
|
5247
|
+
continue;
|
|
5248
|
+
}
|
|
5249
|
+
const nextSpan = pendingWhitespace ? { ...span, t: `${pendingWhitespace}${text}` } : span;
|
|
5250
|
+
pendingWhitespace = "";
|
|
5251
|
+
const previous = merged[merged.length - 1];
|
|
5252
|
+
if (previous && sameTokenSpanStyle(previous, nextSpan)) {
|
|
5253
|
+
previous.t += nextSpan.t;
|
|
5254
|
+
} else {
|
|
5255
|
+
merged.push({ ...nextSpan });
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
if (pendingWhitespace) {
|
|
5259
|
+
const previous = merged[merged.length - 1];
|
|
5260
|
+
if (previous) {
|
|
5261
|
+
previous.t += pendingWhitespace;
|
|
5262
|
+
} else {
|
|
5263
|
+
merged.push({ t: pendingWhitespace });
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
return merged;
|
|
5267
|
+
}
|
|
5268
|
+
function sameTokenSpanStyle(a, b) {
|
|
5269
|
+
const variantKeys = /* @__PURE__ */ new Set([
|
|
5270
|
+
...Object.keys(a.v ?? {}),
|
|
5271
|
+
...Object.keys(b.v ?? {})
|
|
5272
|
+
]);
|
|
5273
|
+
for (const key of variantKeys) {
|
|
5274
|
+
const aStyle = a.v?.[key];
|
|
5275
|
+
const bStyle = b.v?.[key];
|
|
5276
|
+
if ((aStyle?.fg ?? null) !== (bStyle?.fg ?? null)) return false;
|
|
5277
|
+
if ((aStyle?.bg ?? null) !== (bStyle?.bg ?? null)) return false;
|
|
5278
|
+
if ((aStyle?.fs ?? null) !== (bStyle?.fs ?? null)) return false;
|
|
5279
|
+
}
|
|
5280
|
+
if ((a.s?.fg ?? null) !== (b.s?.fg ?? null)) return false;
|
|
5281
|
+
if ((a.s?.bg ?? null) !== (b.s?.bg ?? null)) return false;
|
|
5282
|
+
if ((a.s?.fs ?? null) !== (b.s?.fs ?? null)) return false;
|
|
5283
|
+
return true;
|
|
5284
|
+
}
|
|
5285
|
+
function resolveCodeSourceText(raw, metaCode) {
|
|
5286
|
+
if (metaCode !== null) {
|
|
5287
|
+
return metaCode.replace(/\r\n?/g, "\n");
|
|
5288
|
+
}
|
|
5289
|
+
if (!raw) return "";
|
|
5290
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
5291
|
+
const fenced = (0, import_core5.stripCodeFence)(normalized);
|
|
5292
|
+
return fenced.hadFence ? fenced.code : normalized;
|
|
4667
5293
|
}
|
|
4668
5294
|
function attrsToString(attrs) {
|
|
4669
5295
|
if (!attrs) return "";
|
|
4670
5296
|
return Object.entries(attrs).map(([key, value]) => ` ${key}="${escapeAttribute(value)}"`).join("");
|
|
4671
5297
|
}
|
|
5298
|
+
function buildCodeFallbackLines(raw) {
|
|
5299
|
+
const normalized = normalizeCodeFallbackRaw(raw);
|
|
5300
|
+
if (normalized.length === 0) {
|
|
5301
|
+
if (/^\s*```[^\n]*\n?\s*$/.test(raw)) {
|
|
5302
|
+
return [{ id: "temp-0", index: 0, text: "", html: null }];
|
|
5303
|
+
}
|
|
5304
|
+
return [];
|
|
5305
|
+
}
|
|
5306
|
+
return normalized.split("\n").map((line, index) => ({
|
|
5307
|
+
id: `temp-${index}`,
|
|
5308
|
+
index,
|
|
5309
|
+
text: line,
|
|
5310
|
+
html: null
|
|
5311
|
+
}));
|
|
5312
|
+
}
|
|
5313
|
+
function normalizeCodeFallbackRaw(raw) {
|
|
5314
|
+
if (!raw) return "";
|
|
5315
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
5316
|
+
const fenced = (0, import_core5.stripCodeFence)(normalized);
|
|
5317
|
+
if (!fenced.hadFence) {
|
|
5318
|
+
return normalized.replace(/\n+$/, "");
|
|
5319
|
+
}
|
|
5320
|
+
let code = fenced.code;
|
|
5321
|
+
code = code.replace(/\n+$/, "");
|
|
5322
|
+
return code;
|
|
5323
|
+
}
|
|
4672
5324
|
function escapeHtml3(value) {
|
|
4673
5325
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4674
5326
|
}
|
|
@@ -4792,7 +5444,9 @@ var MarkdownRenderer = class {
|
|
|
4792
5444
|
lowPriorityFrameBudgetMs: this.config.performance?.lowPriorityFrameBudgetMs,
|
|
4793
5445
|
urgentQueueThreshold: this.config.performance?.urgentQueueThreshold,
|
|
4794
5446
|
batch: this.config.performance?.batch,
|
|
4795
|
-
historyLimit: this.config.performance?.historyLimit
|
|
5447
|
+
historyLimit: this.config.performance?.historyLimit,
|
|
5448
|
+
startupMicrotaskFlushes: this.config.performance?.startupMicrotaskFlushes,
|
|
5449
|
+
adaptiveBudgeting: this.config.performance?.adaptiveBudgeting
|
|
4796
5450
|
}
|
|
4797
5451
|
});
|
|
4798
5452
|
}
|
|
@@ -4986,18 +5640,8 @@ var MarkdownRenderer = class {
|
|
|
4986
5640
|
const receivedAt = typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
4987
5641
|
const batches = (0, import_patch_batching.splitPatchBatch)(message.patches);
|
|
4988
5642
|
batches.forEach((batch, index) => {
|
|
4989
|
-
const
|
|
4990
|
-
|
|
4991
|
-
case "insertChild":
|
|
4992
|
-
case "replaceChild":
|
|
4993
|
-
case "deleteChild":
|
|
4994
|
-
case "reorder":
|
|
4995
|
-
return true;
|
|
4996
|
-
default:
|
|
4997
|
-
return false;
|
|
4998
|
-
}
|
|
4999
|
-
});
|
|
5000
|
-
const priority = hasStructural ? "high" : batch.some(import_patch_batching.isHeavyPatch) ? "low" : "high";
|
|
5643
|
+
const hasSemantic = batch.some((patch) => (0, import_patch_batching.getPatchKind)(patch) === "semantic");
|
|
5644
|
+
const priority = hasSemantic ? "high" : batch.some(import_patch_batching.isHeavyPatch) ? "low" : "high";
|
|
5001
5645
|
this.patchScheduler.enqueue({
|
|
5002
5646
|
patches: batch,
|
|
5003
5647
|
meta: {
|