@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
|
@@ -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;
|
|
@@ -1200,7 +1200,11 @@ var defaultInlineComponents = {
|
|
|
1200
1200
|
const n = number ?? "?";
|
|
1201
1201
|
const href = number ? `#fn:${n}` : void 0;
|
|
1202
1202
|
const id = number ? `fnref:${n}` : void 0;
|
|
1203
|
-
return import_react5.default.createElement(
|
|
1203
|
+
return import_react5.default.createElement(
|
|
1204
|
+
"sup",
|
|
1205
|
+
{ className: "footnote-ref" },
|
|
1206
|
+
import_react5.default.createElement("a", { href, id, "data-label": label, style: { color: "var(--foreground)", textDecoration: "underline" } }, String(n))
|
|
1207
|
+
);
|
|
1204
1208
|
}
|
|
1205
1209
|
};
|
|
1206
1210
|
var defaultBlockComponents = {
|
|
@@ -1343,7 +1347,7 @@ var defaultBlockComponents = {
|
|
|
1343
1347
|
dangerouslySetInnerHTML: { __html: htmlString }
|
|
1344
1348
|
});
|
|
1345
1349
|
},
|
|
1346
|
-
mdx: ({ compiledRef, compiledModule, status, errorMessage
|
|
1350
|
+
mdx: ({ compiledRef, compiledModule, status, errorMessage }) => {
|
|
1347
1351
|
const [Comp, setComp] = import_react5.default.useState(null);
|
|
1348
1352
|
const [internalError, setInternalError] = import_react5.default.useState(null);
|
|
1349
1353
|
const [renderError, setRenderError] = import_react5.default.useState(null);
|
|
@@ -1444,7 +1448,6 @@ var defaultBlockComponents = {
|
|
|
1444
1448
|
const waitingForVisibility = deferHydration && !shouldHydrate && Boolean(resolvedId);
|
|
1445
1449
|
const pendingLabel = waitingForVisibility ? "MDX ready (hydrate on view)\u2026" : compileMode === "worker" ? "Compiling MDX (client)\u2026" : "Compiling MDX (server)\u2026";
|
|
1446
1450
|
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.");
|
|
1447
|
-
const rawFallback = typeof raw === "string" && raw.trim().length > 0 ? import_react5.default.createElement("pre", { className: "markdown-mdx-fallback" }, raw) : null;
|
|
1448
1451
|
const allowRetry = Boolean(internalError || renderError);
|
|
1449
1452
|
const retryButton = allowRetry ? import_react5.default.createElement(
|
|
1450
1453
|
"button",
|
|
@@ -1456,9 +1459,10 @@ var defaultBlockComponents = {
|
|
|
1456
1459
|
"Retry hydration"
|
|
1457
1460
|
) : null;
|
|
1458
1461
|
const errorPanel = import_react5.default.createElement(
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
import_react5.default.createElement(
|
|
1462
|
+
import_react5.default.Fragment,
|
|
1463
|
+
null,
|
|
1464
|
+
import_react5.default.createElement("strong", null, "MDX failed"),
|
|
1465
|
+
import_react5.default.createElement("div", null, message)
|
|
1462
1466
|
);
|
|
1463
1467
|
if (Comp && !failureMessage) {
|
|
1464
1468
|
return import_react5.default.createElement(
|
|
@@ -1481,14 +1485,13 @@ var defaultBlockComponents = {
|
|
|
1481
1485
|
return import_react5.default.createElement(
|
|
1482
1486
|
"div",
|
|
1483
1487
|
{
|
|
1484
|
-
className: "markdown-mdx",
|
|
1488
|
+
className: "markdown-mdx error",
|
|
1485
1489
|
ref: containerRef,
|
|
1486
1490
|
"data-mdx-ref": pendingId,
|
|
1487
1491
|
"data-mdx-status": "error",
|
|
1488
1492
|
"data-mdx-mode": compileMode
|
|
1489
1493
|
},
|
|
1490
1494
|
errorPanel,
|
|
1491
|
-
rawFallback,
|
|
1492
1495
|
retryButton
|
|
1493
1496
|
);
|
|
1494
1497
|
}
|
|
@@ -1515,7 +1518,16 @@ var defaultBlockComponents = {
|
|
|
1515
1518
|
{ key: item.number, id: `fn:${item.number}` },
|
|
1516
1519
|
renderInlineNodes(item.inlines, defaultInlineComponents),
|
|
1517
1520
|
" ",
|
|
1518
|
-
import_react5.default.createElement(
|
|
1521
|
+
import_react5.default.createElement(
|
|
1522
|
+
"a",
|
|
1523
|
+
{
|
|
1524
|
+
href: `#fnref:${item.number}`,
|
|
1525
|
+
className: "footnote-backref",
|
|
1526
|
+
"aria-label": "Back to content",
|
|
1527
|
+
style: { color: "var(--foreground)", textDecoration: "underline" }
|
|
1528
|
+
},
|
|
1529
|
+
"\u21A9"
|
|
1530
|
+
)
|
|
1519
1531
|
)
|
|
1520
1532
|
);
|
|
1521
1533
|
return import_react5.default.createElement("section", { className: "footnotes" }, import_react5.default.createElement("hr", {}), import_react5.default.createElement("ol", {}, listItems));
|
|
@@ -2063,6 +2075,9 @@ function useCodeHighlightRequester() {
|
|
|
2063
2075
|
// src/renderer/patch-batching.ts
|
|
2064
2076
|
var import_patch_batching = require("@stream-mdx/core/perf/patch-batching");
|
|
2065
2077
|
|
|
2078
|
+
// src/renderer/patch-commit-scheduler.ts
|
|
2079
|
+
var import_patch_batching2 = require("@stream-mdx/core/perf/patch-batching");
|
|
2080
|
+
|
|
2066
2081
|
// src/renderer/patch-coalescing.ts
|
|
2067
2082
|
var import_core3 = require("@stream-mdx/core");
|
|
2068
2083
|
|
|
@@ -2073,6 +2088,9 @@ var COALESCING_DURATION_ACTIVATE_MS = 6;
|
|
|
2073
2088
|
var COALESCING_DURATION_DEACTIVATE_MS = 4;
|
|
2074
2089
|
var RETAIN_TOUCHED_IN_HISTORY = typeof process !== "undefined" && process.env ? process.env.NODE_ENV !== "production" : true;
|
|
2075
2090
|
var EMPTY_TOUCHED_SET = /* @__PURE__ */ new Set();
|
|
2091
|
+
function shouldSkipCoalescing(patches) {
|
|
2092
|
+
return patches.length <= 1;
|
|
2093
|
+
}
|
|
2076
2094
|
function getDefaultNow() {
|
|
2077
2095
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
2078
2096
|
return () => performance.now();
|
|
@@ -2099,8 +2117,9 @@ function getDefaultCancelRaf() {
|
|
|
2099
2117
|
}
|
|
2100
2118
|
var PatchCommitScheduler = class {
|
|
2101
2119
|
constructor(params) {
|
|
2102
|
-
this.
|
|
2103
|
-
this.
|
|
2120
|
+
this.semanticQueue = [];
|
|
2121
|
+
this.enrichmentHighQueue = [];
|
|
2122
|
+
this.enrichmentLowQueue = [];
|
|
2104
2123
|
this.scheduled = false;
|
|
2105
2124
|
this.flushing = false;
|
|
2106
2125
|
this.scheduledHandle = null;
|
|
@@ -2112,6 +2131,7 @@ var PatchCommitScheduler = class {
|
|
|
2112
2131
|
this.scheduleToken = 0;
|
|
2113
2132
|
this.coalescingDurationSamples = [];
|
|
2114
2133
|
this.adaptiveBudgetActive = false;
|
|
2134
|
+
this.flushCount = 0;
|
|
2115
2135
|
this.store = params.store;
|
|
2116
2136
|
this.onFlush = params.onFlush;
|
|
2117
2137
|
this.frameBudgetMs = Math.max(1, params.options?.frameBudgetMs ?? 10);
|
|
@@ -2127,6 +2147,8 @@ var PatchCommitScheduler = class {
|
|
|
2127
2147
|
this.maxLowPriorityBatchesPerFlush = params.options?.maxLowPriorityBatchesPerFlush ?? 2;
|
|
2128
2148
|
this.urgentQueueThreshold = Math.max(1, params.options?.urgentQueueThreshold ?? 4);
|
|
2129
2149
|
this.historyLimit = Math.max(1, params.options?.historyLimit ?? 200);
|
|
2150
|
+
this.startupMicrotaskFlushes = Math.max(0, Math.floor(params.options?.startupMicrotaskFlushes ?? 0));
|
|
2151
|
+
this.adaptiveBudgeting = params.options?.adaptiveBudgeting ?? true;
|
|
2130
2152
|
const requestedBatch = params.options?.batch;
|
|
2131
2153
|
if (requestedBatch === "microtask") {
|
|
2132
2154
|
this.batchStrategy = "microtask";
|
|
@@ -2153,19 +2175,23 @@ var PatchCommitScheduler = class {
|
|
|
2153
2175
|
patches: input.patches,
|
|
2154
2176
|
meta: input.meta ?? {},
|
|
2155
2177
|
receivedAt: input.meta?.receivedAt ?? this.now(),
|
|
2178
|
+
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",
|
|
2156
2179
|
priority: input.meta?.priority === "low" ? "low" : "high"
|
|
2157
2180
|
};
|
|
2158
|
-
if (batch.
|
|
2159
|
-
|
|
2181
|
+
if (batch.kind === "semantic") {
|
|
2182
|
+
batch.priority = "high";
|
|
2183
|
+
this.semanticQueue.push(batch);
|
|
2184
|
+
} else if (batch.priority === "low") {
|
|
2185
|
+
this.enrichmentLowQueue.push(batch);
|
|
2160
2186
|
} else {
|
|
2161
|
-
this.
|
|
2187
|
+
this.enrichmentHighQueue.push(batch);
|
|
2162
2188
|
}
|
|
2163
2189
|
if (!this.paused) {
|
|
2164
2190
|
this.schedule();
|
|
2165
2191
|
}
|
|
2166
2192
|
}
|
|
2167
2193
|
flushAll() {
|
|
2168
|
-
if (this.
|
|
2194
|
+
if (this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0 && !this.flushing) {
|
|
2169
2195
|
return null;
|
|
2170
2196
|
}
|
|
2171
2197
|
this.cancelScheduled();
|
|
@@ -2175,9 +2201,11 @@ var PatchCommitScheduler = class {
|
|
|
2175
2201
|
}
|
|
2176
2202
|
clear() {
|
|
2177
2203
|
this.cancelScheduled();
|
|
2178
|
-
this.
|
|
2179
|
-
this.
|
|
2204
|
+
this.semanticQueue = [];
|
|
2205
|
+
this.enrichmentHighQueue = [];
|
|
2206
|
+
this.enrichmentLowQueue = [];
|
|
2180
2207
|
this.flushing = false;
|
|
2208
|
+
this.flushCount = 0;
|
|
2181
2209
|
this.coalescingDurationSamples = [];
|
|
2182
2210
|
this.adaptiveBudgetActive = false;
|
|
2183
2211
|
this.adaptiveHighBatchCap = void 0;
|
|
@@ -2185,10 +2213,10 @@ var PatchCommitScheduler = class {
|
|
|
2185
2213
|
this.maybeResolveIdle();
|
|
2186
2214
|
}
|
|
2187
2215
|
getPendingCount() {
|
|
2188
|
-
return this.
|
|
2216
|
+
return this.semanticQueue.length + this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2189
2217
|
}
|
|
2190
2218
|
isIdle() {
|
|
2191
|
-
return !this.flushing && !this.scheduled && this.
|
|
2219
|
+
return !this.flushing && !this.scheduled && this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0;
|
|
2192
2220
|
}
|
|
2193
2221
|
awaitIdle() {
|
|
2194
2222
|
if (this.isIdle()) {
|
|
@@ -2228,7 +2256,8 @@ var PatchCommitScheduler = class {
|
|
|
2228
2256
|
this.runFlush(this.frameBudgetMs, false);
|
|
2229
2257
|
this.maybeResolveIdle();
|
|
2230
2258
|
};
|
|
2231
|
-
|
|
2259
|
+
const useStartupMicrotask = this.batchStrategy !== "microtask" && this.startupMicrotaskFlushes > 0 && this.flushCount < this.startupMicrotaskFlushes && typeof queueMicrotask === "function";
|
|
2260
|
+
if ((this.batchStrategy === "microtask" || useStartupMicrotask) && typeof queueMicrotask === "function") {
|
|
2232
2261
|
this.scheduledViaRaf = false;
|
|
2233
2262
|
this.scheduledHandle = token;
|
|
2234
2263
|
queueMicrotask(execute);
|
|
@@ -2258,12 +2287,14 @@ var PatchCommitScheduler = class {
|
|
|
2258
2287
|
if (this.paused && !manual) {
|
|
2259
2288
|
return null;
|
|
2260
2289
|
}
|
|
2261
|
-
if (this.
|
|
2290
|
+
if (this.semanticQueue.length === 0 && this.enrichmentHighQueue.length === 0 && this.enrichmentLowQueue.length === 0) {
|
|
2262
2291
|
return null;
|
|
2263
2292
|
}
|
|
2264
2293
|
this.flushing = true;
|
|
2265
2294
|
const startedAt = this.now();
|
|
2266
|
-
const
|
|
2295
|
+
const initialSemanticQueueSize = this.semanticQueue.length;
|
|
2296
|
+
const initialEnrichmentQueueSize = this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2297
|
+
const initialQueueSize = initialSemanticQueueSize + initialEnrichmentQueueSize;
|
|
2267
2298
|
const batches = [];
|
|
2268
2299
|
let totalInputPatches = 0;
|
|
2269
2300
|
let totalAppliedPatches = 0;
|
|
@@ -2278,7 +2309,15 @@ var PatchCommitScheduler = class {
|
|
|
2278
2309
|
consumed += 1;
|
|
2279
2310
|
const applyStart = this.now();
|
|
2280
2311
|
const queueDelayMs = Math.max(0, applyStart - next.receivedAt);
|
|
2281
|
-
|
|
2312
|
+
let coalesced;
|
|
2313
|
+
let coalescingMetrics;
|
|
2314
|
+
if (shouldSkipCoalescing(next.patches)) {
|
|
2315
|
+
coalesced = next.patches;
|
|
2316
|
+
} else {
|
|
2317
|
+
const result = (0, import_core3.coalescePatchesWithMetrics)(next.patches, import_core3.DEFAULT_COALESCE_CONFIG);
|
|
2318
|
+
coalesced = result.patches;
|
|
2319
|
+
coalescingMetrics = result.metrics;
|
|
2320
|
+
}
|
|
2282
2321
|
const touched = this.store.applyPatches(coalesced, {
|
|
2283
2322
|
coalesced: true,
|
|
2284
2323
|
metrics: coalescingMetrics
|
|
@@ -2298,6 +2337,7 @@ var PatchCommitScheduler = class {
|
|
|
2298
2337
|
receivedAt: next.receivedAt,
|
|
2299
2338
|
appliedAt: applyStart,
|
|
2300
2339
|
priority: next.priority,
|
|
2340
|
+
kind: next.kind,
|
|
2301
2341
|
coalescing: coalescingMetrics
|
|
2302
2342
|
});
|
|
2303
2343
|
if (maxBatches && batches.length - startingBatchCount >= maxBatches) {
|
|
@@ -2314,27 +2354,32 @@ var PatchCommitScheduler = class {
|
|
|
2314
2354
|
queue.splice(0, consumed);
|
|
2315
2355
|
}
|
|
2316
2356
|
};
|
|
2317
|
-
|
|
2357
|
+
processQueue(this.semanticQueue, void 0, Number.POSITIVE_INFINITY);
|
|
2358
|
+
const initialHighQueueSize = this.enrichmentHighQueue.length;
|
|
2318
2359
|
const configuredHighLimit = manual || !this.maxBatchesPerFlush ? void 0 : initialHighQueueSize > this.maxBatchesPerFlush ? void 0 : this.maxBatchesPerFlush;
|
|
2319
|
-
const highBatchLimit = this.adaptiveHighBatchCap ?? configuredHighLimit;
|
|
2320
|
-
processQueue(this.
|
|
2360
|
+
const highBatchLimit = this.adaptiveBudgeting ? this.adaptiveHighBatchCap ?? configuredHighLimit : configuredHighLimit;
|
|
2361
|
+
processQueue(this.enrichmentHighQueue, highBatchLimit, budgetMs);
|
|
2321
2362
|
if (manual) {
|
|
2322
|
-
processQueue(this.
|
|
2323
|
-
} else if (this.
|
|
2363
|
+
processQueue(this.enrichmentLowQueue, void 0, Number.POSITIVE_INFINITY);
|
|
2364
|
+
} else if (this.enrichmentLowQueue.length > 0) {
|
|
2324
2365
|
elapsed = this.now() - startedAt;
|
|
2325
2366
|
const budgetForLow = Math.max(0, this.lowPriorityFrameBudgetMs - elapsed);
|
|
2326
|
-
|
|
2327
|
-
|
|
2367
|
+
const processedHigherPriorityWork = batches.length > 0;
|
|
2368
|
+
if (budgetForLow > 0 || !processedHigherPriorityWork) {
|
|
2369
|
+
const initialLowQueueSize = this.enrichmentLowQueue.length;
|
|
2328
2370
|
const configuredLowLimit = manual || !this.maxLowPriorityBatchesPerFlush ? void 0 : initialLowQueueSize > this.maxLowPriorityBatchesPerFlush ? void 0 : this.maxLowPriorityBatchesPerFlush;
|
|
2329
|
-
const lowBatchLimit = this.adaptiveLowBatchCap ?? configuredLowLimit;
|
|
2330
|
-
processQueue(this.
|
|
2371
|
+
const lowBatchLimit = this.adaptiveBudgeting ? this.adaptiveLowBatchCap ?? configuredLowLimit : configuredLowLimit;
|
|
2372
|
+
processQueue(this.enrichmentLowQueue, lowBatchLimit, budgetForLow);
|
|
2331
2373
|
}
|
|
2332
2374
|
}
|
|
2333
2375
|
this.flushing = false;
|
|
2334
2376
|
const completedAt = this.now();
|
|
2335
2377
|
const totalDurationMs = completedAt - startedAt;
|
|
2336
|
-
const
|
|
2378
|
+
const remainingSemantic = this.semanticQueue.length;
|
|
2379
|
+
const remainingEnrichment = this.enrichmentHighQueue.length + this.enrichmentLowQueue.length;
|
|
2380
|
+
const remaining = remainingSemantic + remainingEnrichment;
|
|
2337
2381
|
if (batches.length > 0) {
|
|
2382
|
+
this.flushCount += 1;
|
|
2338
2383
|
try {
|
|
2339
2384
|
this.onFlush({
|
|
2340
2385
|
batches,
|
|
@@ -2342,7 +2387,11 @@ var PatchCommitScheduler = class {
|
|
|
2342
2387
|
totalAppliedPatches,
|
|
2343
2388
|
totalDurationMs,
|
|
2344
2389
|
remainingQueueSize: remaining,
|
|
2390
|
+
remainingSemanticQueueSize: remainingSemantic,
|
|
2391
|
+
remainingEnrichmentQueueSize: remainingEnrichment,
|
|
2345
2392
|
queueDepthBefore: initialQueueSize,
|
|
2393
|
+
semanticQueueDepthBefore: initialSemanticQueueSize,
|
|
2394
|
+
enrichmentQueueDepthBefore: initialEnrichmentQueueSize,
|
|
2346
2395
|
flushStartedAt: startedAt,
|
|
2347
2396
|
flushCompletedAt: completedAt
|
|
2348
2397
|
});
|
|
@@ -2353,21 +2402,27 @@ var PatchCommitScheduler = class {
|
|
|
2353
2402
|
if (remaining > 0 && !this.paused) {
|
|
2354
2403
|
this.schedule();
|
|
2355
2404
|
}
|
|
2356
|
-
const coalescingStats = this.computeCoalescingDurationStats();
|
|
2357
|
-
this.
|
|
2358
|
-
|
|
2405
|
+
const coalescingStats = this.adaptiveBudgeting ? this.computeCoalescingDurationStats() : { sampleCount: this.coalescingDurationSamples.length, p95: null };
|
|
2406
|
+
if (this.adaptiveBudgeting) {
|
|
2407
|
+
this.updateAdaptiveBudget(coalescingStats.p95);
|
|
2408
|
+
}
|
|
2409
|
+
const adaptiveState = this.adaptiveBudgeting ? this.snapshotAdaptiveBudget(coalescingStats.p95 ?? null) : void 0;
|
|
2359
2410
|
const flushResult = batches.length > 0 ? {
|
|
2360
2411
|
batches,
|
|
2361
2412
|
totalPatches: totalInputPatches,
|
|
2362
2413
|
totalAppliedPatches,
|
|
2363
2414
|
totalDurationMs,
|
|
2364
2415
|
remainingQueueSize: remaining,
|
|
2416
|
+
remainingSemanticQueueSize: remainingSemantic,
|
|
2417
|
+
remainingEnrichmentQueueSize: remainingEnrichment,
|
|
2365
2418
|
queueDepthBefore: initialQueueSize,
|
|
2419
|
+
semanticQueueDepthBefore: initialSemanticQueueSize,
|
|
2420
|
+
enrichmentQueueDepthBefore: initialEnrichmentQueueSize,
|
|
2366
2421
|
flushStartedAt: startedAt,
|
|
2367
2422
|
flushCompletedAt: completedAt,
|
|
2368
2423
|
coalescingDurationP95: coalescingStats.p95 ?? void 0,
|
|
2369
2424
|
coalescingDurationSampleCount: coalescingStats.sampleCount,
|
|
2370
|
-
adaptiveBudgetActive: adaptiveState
|
|
2425
|
+
adaptiveBudgetActive: adaptiveState?.active,
|
|
2371
2426
|
adaptiveBudgetState: adaptiveState
|
|
2372
2427
|
} : null;
|
|
2373
2428
|
if (flushResult) {
|
|
@@ -2403,6 +2458,9 @@ var PatchCommitScheduler = class {
|
|
|
2403
2458
|
};
|
|
2404
2459
|
}
|
|
2405
2460
|
updateAdaptiveBudget(p95) {
|
|
2461
|
+
if (!this.adaptiveBudgeting) {
|
|
2462
|
+
return;
|
|
2463
|
+
}
|
|
2406
2464
|
if (p95 !== null && p95 > COALESCING_DURATION_ACTIVATE_MS) {
|
|
2407
2465
|
if (!this.adaptiveBudgetActive) {
|
|
2408
2466
|
this.adaptiveBudgetActive = true;
|
|
@@ -2476,11 +2534,13 @@ var PatchCommitScheduler = class {
|
|
|
2476
2534
|
}
|
|
2477
2535
|
restart() {
|
|
2478
2536
|
this.cancelScheduled();
|
|
2479
|
-
this.
|
|
2480
|
-
this.
|
|
2537
|
+
this.semanticQueue = [];
|
|
2538
|
+
this.enrichmentHighQueue = [];
|
|
2539
|
+
this.enrichmentLowQueue = [];
|
|
2481
2540
|
this.flushing = false;
|
|
2482
2541
|
this.sequence = 0;
|
|
2483
2542
|
this.history = [];
|
|
2543
|
+
this.flushCount = 0;
|
|
2484
2544
|
this.scheduleToken++;
|
|
2485
2545
|
this.paused = false;
|
|
2486
2546
|
this.coalescingDurationSamples = [];
|
|
@@ -2527,6 +2587,12 @@ var PatchCommitScheduler = class {
|
|
|
2527
2587
|
if (typeof options.historyLimit !== "undefined") {
|
|
2528
2588
|
this.setHistoryLimit(options.historyLimit);
|
|
2529
2589
|
}
|
|
2590
|
+
if (typeof options.startupMicrotaskFlushes !== "undefined") {
|
|
2591
|
+
this.startupMicrotaskFlushes = Math.max(0, Math.floor(options.startupMicrotaskFlushes));
|
|
2592
|
+
}
|
|
2593
|
+
if (typeof options.adaptiveBudgeting !== "undefined") {
|
|
2594
|
+
this.adaptiveBudgeting = options.adaptiveBudgeting;
|
|
2595
|
+
}
|
|
2530
2596
|
if (typeof options.batch !== "undefined") {
|
|
2531
2597
|
const requestedBatch = options.batch;
|
|
2532
2598
|
if (requestedBatch === "microtask") {
|
|
@@ -2553,6 +2619,7 @@ var PatchCommitScheduler = class {
|
|
|
2553
2619
|
|
|
2554
2620
|
// src/renderer/store.ts
|
|
2555
2621
|
var import_core4 = require("@stream-mdx/core");
|
|
2622
|
+
var import_patch_batching3 = require("@stream-mdx/core/perf/patch-batching");
|
|
2556
2623
|
|
|
2557
2624
|
// src/renderer/list-utils.ts
|
|
2558
2625
|
function updateNodeDepth(node, depth) {
|
|
@@ -2648,12 +2715,28 @@ function snapshotToBlock(node) {
|
|
|
2648
2715
|
}
|
|
2649
2716
|
return null;
|
|
2650
2717
|
}
|
|
2651
|
-
var
|
|
2652
|
-
var
|
|
2718
|
+
var nodeSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
2719
|
+
var childrenSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
2653
2720
|
var NODE_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
2654
2721
|
var CHILDREN_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
2655
2722
|
var NODE_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(NODE_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
2656
2723
|
var CHILDREN_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(CHILDREN_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
2724
|
+
function getNodeSnapshotCacheForMap(map) {
|
|
2725
|
+
let cache = nodeSnapshotCacheByMap.get(map);
|
|
2726
|
+
if (!cache) {
|
|
2727
|
+
cache = /* @__PURE__ */ new Map();
|
|
2728
|
+
nodeSnapshotCacheByMap.set(map, cache);
|
|
2729
|
+
}
|
|
2730
|
+
return cache;
|
|
2731
|
+
}
|
|
2732
|
+
function getChildrenSnapshotCacheForMap(map) {
|
|
2733
|
+
let cache = childrenSnapshotCacheByMap.get(map);
|
|
2734
|
+
if (!cache) {
|
|
2735
|
+
cache = /* @__PURE__ */ new Map();
|
|
2736
|
+
childrenSnapshotCacheByMap.set(map, cache);
|
|
2737
|
+
}
|
|
2738
|
+
return cache;
|
|
2739
|
+
}
|
|
2657
2740
|
function pruneCache(cache, max, buffer) {
|
|
2658
2741
|
if (cache.size <= max + buffer) return;
|
|
2659
2742
|
let remaining = cache.size - max;
|
|
@@ -2663,6 +2746,14 @@ function pruneCache(cache, max, buffer) {
|
|
|
2663
2746
|
if (remaining <= 0) break;
|
|
2664
2747
|
}
|
|
2665
2748
|
}
|
|
2749
|
+
function deleteSnapshotCacheEntry(map, id) {
|
|
2750
|
+
getNodeSnapshotCacheForMap(map).delete(id);
|
|
2751
|
+
getChildrenSnapshotCacheForMap(map).delete(id);
|
|
2752
|
+
}
|
|
2753
|
+
function clearSnapshotCaches(map) {
|
|
2754
|
+
getNodeSnapshotCacheForMap(map).clear();
|
|
2755
|
+
getChildrenSnapshotCacheForMap(map).clear();
|
|
2756
|
+
}
|
|
2666
2757
|
var EMPTY_CHILDREN = Object.freeze([]);
|
|
2667
2758
|
var EMPTY_NODE_SNAPSHOT = Object.freeze({ version: -1, node: void 0 });
|
|
2668
2759
|
var EMPTY_CHILDREN_SNAPSHOT = Object.freeze({
|
|
@@ -2830,9 +2921,57 @@ function createRootRecord() {
|
|
|
2830
2921
|
parentId: null,
|
|
2831
2922
|
children: [],
|
|
2832
2923
|
props: {},
|
|
2833
|
-
version: 0
|
|
2924
|
+
version: 0,
|
|
2925
|
+
blockEpoch: 0
|
|
2834
2926
|
};
|
|
2835
2927
|
}
|
|
2928
|
+
function readNumericEpoch(value) {
|
|
2929
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
2930
|
+
return void 0;
|
|
2931
|
+
}
|
|
2932
|
+
return value;
|
|
2933
|
+
}
|
|
2934
|
+
function readSnapshotBlockEpoch(snapshot) {
|
|
2935
|
+
return readNumericEpoch(snapshot.meta?.blockEpoch);
|
|
2936
|
+
}
|
|
2937
|
+
function readPatchBlockEpoch(patch) {
|
|
2938
|
+
if (patch.op === "setHTML") {
|
|
2939
|
+
return readNumericEpoch(patch.patchMeta?.blockEpoch);
|
|
2940
|
+
}
|
|
2941
|
+
return readNumericEpoch(patch.meta?.blockEpoch);
|
|
2942
|
+
}
|
|
2943
|
+
function readPatchParseEpoch(patch) {
|
|
2944
|
+
if (patch.op === "setHTML") {
|
|
2945
|
+
return readNumericEpoch(patch.patchMeta?.parseEpoch);
|
|
2946
|
+
}
|
|
2947
|
+
return readNumericEpoch(patch.meta?.parseEpoch);
|
|
2948
|
+
}
|
|
2949
|
+
function readPatchTx(patch) {
|
|
2950
|
+
if (patch.op === "setHTML") {
|
|
2951
|
+
return readNumericEpoch(patch.patchMeta?.tx);
|
|
2952
|
+
}
|
|
2953
|
+
return readNumericEpoch(patch.meta?.tx);
|
|
2954
|
+
}
|
|
2955
|
+
function assignSubtreeBlockEpoch(map, rootId, blockEpoch, touched) {
|
|
2956
|
+
const root = map.get(rootId);
|
|
2957
|
+
if (!root) return;
|
|
2958
|
+
const stack = [root];
|
|
2959
|
+
while (stack.length > 0) {
|
|
2960
|
+
const node = stack.pop();
|
|
2961
|
+
if (!node) continue;
|
|
2962
|
+
if (node.blockEpoch !== blockEpoch) {
|
|
2963
|
+
node.blockEpoch = blockEpoch;
|
|
2964
|
+
node.version += 1;
|
|
2965
|
+
touched?.add(node.id);
|
|
2966
|
+
}
|
|
2967
|
+
for (const childId of node.children) {
|
|
2968
|
+
const child = map.get(childId);
|
|
2969
|
+
if (child) {
|
|
2970
|
+
stack.push(child);
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2836
2975
|
function ensureArray(value) {
|
|
2837
2976
|
return Array.isArray(value) ? value : [];
|
|
2838
2977
|
}
|
|
@@ -2892,7 +3031,7 @@ function escapeHtml2(value) {
|
|
|
2892
3031
|
}
|
|
2893
3032
|
function stripOuterLineSpan(html) {
|
|
2894
3033
|
if (!html) return null;
|
|
2895
|
-
const openTagMatch = html.match(/<span[^>]*>/i);
|
|
3034
|
+
const openTagMatch = html.match(/<span[^>]*class="[^"]*\bline\b[^"]*"[^>]*>/i);
|
|
2896
3035
|
if (!openTagMatch) {
|
|
2897
3036
|
return null;
|
|
2898
3037
|
}
|
|
@@ -2941,8 +3080,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
2941
3080
|
if (node.type !== "code-line") {
|
|
2942
3081
|
anomalies.push(`type-mismatch:${node.id}:${node.type}`);
|
|
2943
3082
|
nodes.delete(node.id);
|
|
2944
|
-
|
|
2945
|
-
childrenSnapshotCache.delete(node.id);
|
|
3083
|
+
deleteSnapshotCacheEntry(nodes, node.id);
|
|
2946
3084
|
touched.add(node.id);
|
|
2947
3085
|
continue;
|
|
2948
3086
|
}
|
|
@@ -2986,16 +3124,14 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
2986
3124
|
const existing = nodes.get(desiredId);
|
|
2987
3125
|
if (existing && existing !== node) {
|
|
2988
3126
|
nodes.delete(desiredId);
|
|
2989
|
-
|
|
2990
|
-
childrenSnapshotCache.delete(desiredId);
|
|
3127
|
+
deleteSnapshotCacheEntry(nodes, desiredId);
|
|
2991
3128
|
touched.add(desiredId);
|
|
2992
3129
|
mutated = true;
|
|
2993
3130
|
}
|
|
2994
3131
|
if (node.id !== desiredId) {
|
|
2995
3132
|
const previousId = node.id;
|
|
2996
3133
|
nodes.delete(node.id);
|
|
2997
|
-
|
|
2998
|
-
childrenSnapshotCache.delete(previousId);
|
|
3134
|
+
deleteSnapshotCacheEntry(nodes, previousId);
|
|
2999
3135
|
node.id = desiredId;
|
|
3000
3136
|
nodes.set(desiredId, node);
|
|
3001
3137
|
touched.add(desiredId);
|
|
@@ -3026,8 +3162,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
3026
3162
|
for (const [id, record] of nodes) {
|
|
3027
3163
|
if (record.parentId === parent.id && record.type === "code-line" && !allowed.has(id)) {
|
|
3028
3164
|
nodes.delete(id);
|
|
3029
|
-
|
|
3030
|
-
childrenSnapshotCache.delete(id);
|
|
3165
|
+
deleteSnapshotCacheEntry(nodes, id);
|
|
3031
3166
|
touched.add(id);
|
|
3032
3167
|
mutated = true;
|
|
3033
3168
|
}
|
|
@@ -3111,8 +3246,10 @@ function normalizeCodeLineProps(incoming, previous) {
|
|
|
3111
3246
|
}
|
|
3112
3247
|
function createCodeLineProps(index, text, highlight, tokens) {
|
|
3113
3248
|
const safeText = typeof text === "string" ? text : "";
|
|
3114
|
-
const
|
|
3115
|
-
const
|
|
3249
|
+
const hasIncomingHighlight = typeof highlight === "string" && highlight.trim().length > 0;
|
|
3250
|
+
const sanitized = hasIncomingHighlight ? sanitizeLineInnerHtml(highlight, safeText) : null;
|
|
3251
|
+
const hasRenderableTokens = tokens !== void 0 && tokens !== null;
|
|
3252
|
+
const html = sanitized && sanitized.length >= safeText.length ? sanitized : hasRenderableTokens ? null : escapeHtml2(safeText);
|
|
3116
3253
|
const props = {
|
|
3117
3254
|
index,
|
|
3118
3255
|
text: safeText,
|
|
@@ -3223,6 +3360,18 @@ function validateCodeBlockChildren(nodes, parent) {
|
|
|
3223
3360
|
issues.push({ kind: "dangling-node", id });
|
|
3224
3361
|
}
|
|
3225
3362
|
}
|
|
3363
|
+
if (parent.block?.isFinalized) {
|
|
3364
|
+
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(parent.block));
|
|
3365
|
+
const expectedChildren = ensureArray(snapshot.children).filter((child) => child.type === "code-line");
|
|
3366
|
+
if (expectedChildren.length !== parent.children.length) {
|
|
3367
|
+
issues.push({
|
|
3368
|
+
kind: "line-count-mismatch",
|
|
3369
|
+
id: parent.id,
|
|
3370
|
+
expected: expectedChildren.length,
|
|
3371
|
+
actual: parent.children.length
|
|
3372
|
+
});
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3226
3375
|
return { ok: issues.length === 0, issues };
|
|
3227
3376
|
}
|
|
3228
3377
|
function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
@@ -3239,7 +3388,7 @@ function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
|
3239
3388
|
}
|
|
3240
3389
|
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(parent.block));
|
|
3241
3390
|
removeSubtree(nodes, parent.id, touched);
|
|
3242
|
-
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot);
|
|
3391
|
+
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot, touched, parent.blockEpoch);
|
|
3243
3392
|
if (!inserted) {
|
|
3244
3393
|
return false;
|
|
3245
3394
|
}
|
|
@@ -3262,7 +3411,55 @@ function arraysEqual(a, b) {
|
|
|
3262
3411
|
}
|
|
3263
3412
|
return true;
|
|
3264
3413
|
}
|
|
3265
|
-
function
|
|
3414
|
+
function expectedCodeLineId(parentId, index) {
|
|
3415
|
+
return `${parentId}::line:${index}`;
|
|
3416
|
+
}
|
|
3417
|
+
function collectStoreInvariantViolations(nodes) {
|
|
3418
|
+
const violations = [];
|
|
3419
|
+
for (const [id, node] of nodes) {
|
|
3420
|
+
if (node.type === "__root__") continue;
|
|
3421
|
+
if (node.children.length > 1) {
|
|
3422
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3423
|
+
for (const childId of node.children) {
|
|
3424
|
+
if (seen.has(childId)) {
|
|
3425
|
+
violations.push(`duplicate child id:${id}:${childId}`);
|
|
3426
|
+
} else {
|
|
3427
|
+
seen.add(childId);
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
if (node.type === "list") {
|
|
3432
|
+
const parent = node.parentId ? nodes.get(node.parentId) : void 0;
|
|
3433
|
+
if (parent?.type === "list-item" && node.children.length === 0) {
|
|
3434
|
+
violations.push(`empty nested list:${id}`);
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
if (node.type === "code") {
|
|
3438
|
+
for (let index = 0; index < node.children.length; index += 1) {
|
|
3439
|
+
const childId = node.children[index];
|
|
3440
|
+
const child = nodes.get(childId);
|
|
3441
|
+
if (!child) {
|
|
3442
|
+
violations.push(`missing code-line node:${node.id}:${childId}`);
|
|
3443
|
+
continue;
|
|
3444
|
+
}
|
|
3445
|
+
if (child.type !== "code-line") {
|
|
3446
|
+
violations.push(`non-code child in code block:${node.id}:${child.id}:${child.type}`);
|
|
3447
|
+
continue;
|
|
3448
|
+
}
|
|
3449
|
+
const expectedId = expectedCodeLineId(node.id, index);
|
|
3450
|
+
if (child.id !== expectedId) {
|
|
3451
|
+
violations.push(`code-line id mismatch:${node.id}:${child.id}:${expectedId}`);
|
|
3452
|
+
}
|
|
3453
|
+
const indexProp = typeof child.props?.index === "number" ? child.props.index : null;
|
|
3454
|
+
if (indexProp !== index) {
|
|
3455
|
+
violations.push(`code-line index mismatch:${node.id}:${child.id}:${indexProp}:${index}`);
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
return violations;
|
|
3461
|
+
}
|
|
3462
|
+
function buildNodeFromSnapshot(map, snapshot, parentId, blockEpoch) {
|
|
3266
3463
|
const record = {
|
|
3267
3464
|
id: snapshot.id,
|
|
3268
3465
|
type: snapshot.type,
|
|
@@ -3272,6 +3469,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
3272
3469
|
meta: snapshot.meta ? { ...snapshot.meta } : void 0,
|
|
3273
3470
|
range: snapshot.range ? { ...snapshot.range } : void 0,
|
|
3274
3471
|
version: 0,
|
|
3472
|
+
blockEpoch,
|
|
3275
3473
|
block: snapshotToBlock(snapshot) ?? void 0
|
|
3276
3474
|
};
|
|
3277
3475
|
if (record.type === "code") {
|
|
@@ -3280,7 +3478,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
3280
3478
|
map.set(record.id, record);
|
|
3281
3479
|
const childSnapshots = ensureArray(snapshot.children);
|
|
3282
3480
|
for (const child of childSnapshots) {
|
|
3283
|
-
const childRecord = buildNodeFromSnapshot(map, child, record.id);
|
|
3481
|
+
const childRecord = buildNodeFromSnapshot(map, child, record.id, blockEpoch);
|
|
3284
3482
|
record.children.push(childRecord.id);
|
|
3285
3483
|
}
|
|
3286
3484
|
return record;
|
|
@@ -3308,8 +3506,7 @@ function removeSubtree(map, id, touched) {
|
|
|
3308
3506
|
}
|
|
3309
3507
|
}
|
|
3310
3508
|
map.delete(node.id);
|
|
3311
|
-
|
|
3312
|
-
childrenSnapshotCache.delete(node.id);
|
|
3509
|
+
deleteSnapshotCacheEntry(map, node.id);
|
|
3313
3510
|
touched.add(node.id);
|
|
3314
3511
|
for (const childId of node.children) {
|
|
3315
3512
|
const child = map.get(childId);
|
|
@@ -3341,13 +3538,13 @@ function resolveParent(map, path) {
|
|
|
3341
3538
|
}
|
|
3342
3539
|
return map.get(path.blockId);
|
|
3343
3540
|
}
|
|
3344
|
-
function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
3541
|
+
function insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
3345
3542
|
if (!parent) return null;
|
|
3346
3543
|
const existingIndex = parent.children.indexOf(snapshot.id);
|
|
3347
3544
|
if (existingIndex !== -1) {
|
|
3348
3545
|
removeSubtree(map, parent.children[existingIndex], touched ?? /* @__PURE__ */ new Set());
|
|
3349
3546
|
}
|
|
3350
|
-
const record = buildNodeFromSnapshot(map, snapshot, parent.id);
|
|
3547
|
+
const record = buildNodeFromSnapshot(map, snapshot, parent.id, blockEpoch ?? readSnapshotBlockEpoch(snapshot) ?? parent.blockEpoch);
|
|
3351
3548
|
const insertedIds = [];
|
|
3352
3549
|
const queue = [record];
|
|
3353
3550
|
while (queue.length > 0) {
|
|
@@ -3365,13 +3562,13 @@ function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
|
3365
3562
|
ensureUniqueChildren(parent, touched);
|
|
3366
3563
|
return { record, insertedIds };
|
|
3367
3564
|
}
|
|
3368
|
-
function replaceSnapshotAt(map, parent, index, snapshot, touched) {
|
|
3565
|
+
function replaceSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
3369
3566
|
if (!parent) return;
|
|
3370
3567
|
if (index < 0 || index >= parent.children.length) return;
|
|
3371
3568
|
const targetId = parent.children[index];
|
|
3372
3569
|
parent.children.splice(index, 1);
|
|
3373
3570
|
removeSubtree(map, targetId, touched);
|
|
3374
|
-
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched);
|
|
3571
|
+
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch);
|
|
3375
3572
|
if (inserted) {
|
|
3376
3573
|
for (const id of inserted.insertedIds) {
|
|
3377
3574
|
touched.add(id);
|
|
@@ -3391,6 +3588,24 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3391
3588
|
const listeners = /* @__PURE__ */ new Set();
|
|
3392
3589
|
let notifyScheduled = false;
|
|
3393
3590
|
let lastCoalescingMetrics = null;
|
|
3591
|
+
let invariantViolations = [];
|
|
3592
|
+
let transientDiagnostics = [];
|
|
3593
|
+
let nextBlockEpoch = 1;
|
|
3594
|
+
const debugCounters = {
|
|
3595
|
+
appendLineGuardRejected: 0,
|
|
3596
|
+
staleEpochRejected: 0,
|
|
3597
|
+
storeInvariantViolationCount: 0
|
|
3598
|
+
};
|
|
3599
|
+
const allocateBlockEpoch = (preferred) => {
|
|
3600
|
+
const resolved = readNumericEpoch(preferred);
|
|
3601
|
+
if (resolved !== void 0) {
|
|
3602
|
+
nextBlockEpoch = Math.max(nextBlockEpoch, resolved + 1);
|
|
3603
|
+
return resolved;
|
|
3604
|
+
}
|
|
3605
|
+
const epoch = nextBlockEpoch;
|
|
3606
|
+
nextBlockEpoch += 1;
|
|
3607
|
+
return epoch;
|
|
3608
|
+
};
|
|
3394
3609
|
const getRaf = () => {
|
|
3395
3610
|
if (typeof globalThis !== "undefined" && typeof globalThis.requestAnimationFrame === "function") {
|
|
3396
3611
|
return globalThis.requestAnimationFrame;
|
|
@@ -3422,9 +3637,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3422
3637
|
}
|
|
3423
3638
|
}
|
|
3424
3639
|
}
|
|
3640
|
+
function appendDiagnostic(message) {
|
|
3641
|
+
transientDiagnostics = [...transientDiagnostics, message];
|
|
3642
|
+
invariantViolations = [...invariantViolations, message];
|
|
3643
|
+
}
|
|
3425
3644
|
function rebuildFromBlocks(blocks) {
|
|
3426
|
-
|
|
3427
|
-
childrenSnapshotCache.clear();
|
|
3645
|
+
clearSnapshotCaches(nodes);
|
|
3428
3646
|
nodes = /* @__PURE__ */ new Map();
|
|
3429
3647
|
const root = createRootRecord();
|
|
3430
3648
|
nodes.set(root.id, root);
|
|
@@ -3433,9 +3651,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3433
3651
|
for (let i = 0; i < blocks.length; i++) {
|
|
3434
3652
|
const block = (0, import_core4.cloneBlock)(blocks[i]);
|
|
3435
3653
|
const snapshot = (0, import_core4.createBlockSnapshot)(block);
|
|
3436
|
-
insertSnapshotAt(nodes, root, root.children.length, snapshot);
|
|
3654
|
+
insertSnapshotAt(nodes, root, root.children.length, snapshot, void 0, allocateBlockEpoch(readSnapshotBlockEpoch(snapshot)));
|
|
3437
3655
|
}
|
|
3438
3656
|
normalizeAllListDepths(nodes, /* @__PURE__ */ new Set(), import_core4.PATCH_ROOT_ID);
|
|
3657
|
+
transientDiagnostics = [];
|
|
3658
|
+
invariantViolations = collectStoreInvariantViolations(nodes);
|
|
3659
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
3439
3660
|
version++;
|
|
3440
3661
|
blocksDirty = true;
|
|
3441
3662
|
scheduleNotify();
|
|
@@ -3500,11 +3721,57 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3500
3721
|
listDepthDirty = true;
|
|
3501
3722
|
}
|
|
3502
3723
|
};
|
|
3503
|
-
const
|
|
3724
|
+
const semanticTxEpochs = /* @__PURE__ */ new Map();
|
|
3725
|
+
const resolveBlockEpochTarget = (patch, at) => {
|
|
3726
|
+
if ((patch.op === "insertChild" || patch.op === "replaceChild") && at.blockId === import_core4.PATCH_ROOT_ID) {
|
|
3727
|
+
const nodeId = patch.node?.id;
|
|
3728
|
+
return nodeId ? nodes.get(nodeId) : void 0;
|
|
3729
|
+
}
|
|
3730
|
+
return nodes.get(at.blockId) ?? (at.nodeId ? nodes.get(at.nodeId) : void 0);
|
|
3731
|
+
};
|
|
3732
|
+
const rejectStaleEpochPatch = (patch, at) => {
|
|
3733
|
+
const expectedBlockEpoch = readPatchBlockEpoch(patch);
|
|
3734
|
+
const patchTx = readPatchTx(patch);
|
|
3735
|
+
if (expectedBlockEpoch === void 0) {
|
|
3736
|
+
return false;
|
|
3737
|
+
}
|
|
3738
|
+
if ((0, import_patch_batching3.getPatchKind)(patch) !== "semantic" || !at) {
|
|
3739
|
+
return false;
|
|
3740
|
+
}
|
|
3741
|
+
const target = resolveBlockEpochTarget(patch, at);
|
|
3742
|
+
if (!target || target.blockEpoch === expectedBlockEpoch) {
|
|
3743
|
+
return false;
|
|
3744
|
+
}
|
|
3745
|
+
const txEpoch = at.blockId && patchTx !== void 0 ? semanticTxEpochs.get(at.blockId) : void 0;
|
|
3746
|
+
if (txEpoch && txEpoch.tx === patchTx && txEpoch.blockEpoch === target.blockEpoch) {
|
|
3747
|
+
return false;
|
|
3748
|
+
}
|
|
3749
|
+
debugCounters.staleEpochRejected += 1;
|
|
3750
|
+
appendDiagnostic(
|
|
3751
|
+
`stale epoch rejected:${patch.op}:${target.id}:expected=${expectedBlockEpoch}:actual=${target.blockEpoch}`
|
|
3752
|
+
);
|
|
3753
|
+
return true;
|
|
3754
|
+
};
|
|
3755
|
+
const advanceBlockEpoch = (blockId, touchedSet, preferredEpoch, tx) => {
|
|
3756
|
+
if (!blockId || blockId === import_core4.PATCH_ROOT_ID) {
|
|
3757
|
+
return null;
|
|
3758
|
+
}
|
|
3759
|
+
const blockRoot = nodes.get(blockId);
|
|
3760
|
+
if (!blockRoot) {
|
|
3761
|
+
return null;
|
|
3762
|
+
}
|
|
3763
|
+
const nextEpoch = allocateBlockEpoch(preferredEpoch);
|
|
3764
|
+
assignSubtreeBlockEpoch(nodes, blockRoot.id, nextEpoch, touchedSet);
|
|
3765
|
+
if (tx !== void 0) {
|
|
3766
|
+
semanticTxEpochs.set(blockRoot.id, { tx, blockEpoch: nextEpoch });
|
|
3767
|
+
}
|
|
3768
|
+
return nextEpoch;
|
|
3769
|
+
};
|
|
3770
|
+
const applyPropsUpdate = (at, props, preferredEpoch, tx, semanticUpdate = false) => {
|
|
3504
3771
|
const perfStartLocal = perfEnabled ? getPerfNow() : 0;
|
|
3505
3772
|
const targetId = at.nodeId ?? at.blockId;
|
|
3506
3773
|
if (!targetId) return;
|
|
3507
|
-
|
|
3774
|
+
let target = nodes.get(targetId);
|
|
3508
3775
|
if (!target) return;
|
|
3509
3776
|
const parentType = target.parentId ? nodes.get(target.parentId)?.type : void 0;
|
|
3510
3777
|
if (debugListPatches && (isListRelated(target.type) || isListRelated(parentType))) {
|
|
@@ -3531,6 +3798,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3531
3798
|
propsChanged = true;
|
|
3532
3799
|
}
|
|
3533
3800
|
if (propsChanged) {
|
|
3801
|
+
if (semanticUpdate) {
|
|
3802
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3803
|
+
}
|
|
3534
3804
|
target.version++;
|
|
3535
3805
|
touched.add(target.id);
|
|
3536
3806
|
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
@@ -3594,16 +3864,56 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3594
3864
|
}
|
|
3595
3865
|
}
|
|
3596
3866
|
let blockChanged = false;
|
|
3867
|
+
let typeChanged = false;
|
|
3868
|
+
let rebuiltFromFinalizedBlock = false;
|
|
3869
|
+
let blockEpochAdvanced = false;
|
|
3597
3870
|
const incomingBlock = props?.block;
|
|
3598
3871
|
if (incomingBlock && typeof incomingBlock === "object") {
|
|
3599
3872
|
target.block = (0, import_core4.cloneBlock)(incomingBlock);
|
|
3873
|
+
const previousType = target.type;
|
|
3874
|
+
const incomingType = typeof target.block.type === "string" ? target.block.type : target.type;
|
|
3875
|
+
if (incomingType !== target.type) {
|
|
3876
|
+
target.type = incomingType;
|
|
3877
|
+
typeChanged = true;
|
|
3878
|
+
if (isListRelated(previousType) || isListRelated(target.type)) {
|
|
3879
|
+
markListDepthDirty(target.id);
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
3600
3882
|
if (target.type === "code") {
|
|
3601
3883
|
applyCodeBlockMetadata(target);
|
|
3602
3884
|
}
|
|
3885
|
+
if (semanticUpdate) {
|
|
3886
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3887
|
+
blockEpochAdvanced = true;
|
|
3888
|
+
}
|
|
3889
|
+
const shouldRebuildFinalizedTree = !at.nodeId && target.id === at.blockId && Boolean(target.block?.isFinalized) && target.type !== "code" && Boolean(target.parentId);
|
|
3890
|
+
if (shouldRebuildFinalizedTree) {
|
|
3891
|
+
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
3892
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
3893
|
+
if (parent && index !== -1) {
|
|
3894
|
+
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(target.block));
|
|
3895
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
3896
|
+
mutatedBlocks = true;
|
|
3897
|
+
blockChanged = true;
|
|
3898
|
+
rebuiltFromFinalizedBlock = true;
|
|
3899
|
+
const rebuilt = nodes.get(target.id);
|
|
3900
|
+
if (isListRelated(previousType) || isListRelated(rebuilt?.type)) {
|
|
3901
|
+
markListDepthDirty(target.id);
|
|
3902
|
+
}
|
|
3903
|
+
target = rebuilt ?? target;
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3603
3906
|
mutatedBlocks = true;
|
|
3604
3907
|
blockChanged = true;
|
|
3605
3908
|
}
|
|
3606
|
-
if (
|
|
3909
|
+
if (rebuiltFromFinalizedBlock) {
|
|
3910
|
+
return;
|
|
3911
|
+
}
|
|
3912
|
+
if (propsChanged || blockChanged || typeChanged) {
|
|
3913
|
+
if (semanticUpdate && !blockEpochAdvanced) {
|
|
3914
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
3915
|
+
blockEpochAdvanced = true;
|
|
3916
|
+
}
|
|
3607
3917
|
target.version++;
|
|
3608
3918
|
touched.add(target.id);
|
|
3609
3919
|
let parentForNormalization;
|
|
@@ -3646,13 +3956,22 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3646
3956
|
const applyPatch = (patch) => {
|
|
3647
3957
|
switch (patch.op) {
|
|
3648
3958
|
case "insertChild": {
|
|
3959
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3649
3960
|
const parent = resolveParent(nodes, patch.at);
|
|
3650
|
-
const inserted = insertSnapshotAt(
|
|
3961
|
+
const inserted = insertSnapshotAt(
|
|
3962
|
+
nodes,
|
|
3963
|
+
parent,
|
|
3964
|
+
patch.index,
|
|
3965
|
+
patch.node,
|
|
3966
|
+
touched,
|
|
3967
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
3968
|
+
);
|
|
3651
3969
|
if (inserted) {
|
|
3652
3970
|
for (const id of inserted.insertedIds) {
|
|
3653
3971
|
touched.add(id);
|
|
3654
3972
|
}
|
|
3655
3973
|
mutatedBlocks = true;
|
|
3974
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3656
3975
|
if (isListRelated(inserted.record.type) || isListRelated(parent?.type)) {
|
|
3657
3976
|
markListDepthDirty(inserted.record.id);
|
|
3658
3977
|
if (parent) {
|
|
@@ -3672,6 +3991,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3672
3991
|
break;
|
|
3673
3992
|
}
|
|
3674
3993
|
case "deleteChild": {
|
|
3994
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3675
3995
|
const parent = resolveParent(nodes, patch.at);
|
|
3676
3996
|
if (!parent) break;
|
|
3677
3997
|
if (patch.index < 0 || patch.index >= parent.children.length) break;
|
|
@@ -3683,6 +4003,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3683
4003
|
touched.add(parent.id);
|
|
3684
4004
|
ensureUniqueChildren(parent, touched);
|
|
3685
4005
|
mutatedBlocks = true;
|
|
4006
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3686
4007
|
if (isListRelated(parent.type) || isListRelated(removedNode?.type)) {
|
|
3687
4008
|
markListDepthDirty(parent.id);
|
|
3688
4009
|
}
|
|
@@ -3699,11 +4020,20 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3699
4020
|
break;
|
|
3700
4021
|
}
|
|
3701
4022
|
case "replaceChild": {
|
|
4023
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3702
4024
|
const parent = resolveParent(nodes, patch.at);
|
|
3703
4025
|
if (!parent) break;
|
|
3704
|
-
replaceSnapshotAt(
|
|
4026
|
+
replaceSnapshotAt(
|
|
4027
|
+
nodes,
|
|
4028
|
+
parent,
|
|
4029
|
+
patch.index,
|
|
4030
|
+
patch.node,
|
|
4031
|
+
touched,
|
|
4032
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
4033
|
+
);
|
|
3705
4034
|
touched.add(parent.id);
|
|
3706
4035
|
mutatedBlocks = true;
|
|
4036
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
3707
4037
|
if (isListRelated(parent.type)) {
|
|
3708
4038
|
markListDepthDirty(parent.id);
|
|
3709
4039
|
}
|
|
@@ -3717,18 +4047,33 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3717
4047
|
break;
|
|
3718
4048
|
}
|
|
3719
4049
|
case "setProps": {
|
|
3720
|
-
|
|
4050
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
4051
|
+
applyPropsUpdate(patch.at, patch.props, readPatchParseEpoch(patch), readPatchTx(patch), (0, import_patch_batching3.getPatchKind)(patch) === "semantic");
|
|
3721
4052
|
break;
|
|
3722
4053
|
}
|
|
3723
4054
|
case "setPropsBatch": {
|
|
3724
4055
|
const entries2 = Array.isArray(patch.entries) ? patch.entries : [];
|
|
3725
4056
|
for (const entry of entries2) {
|
|
3726
4057
|
if (!entry || !entry.at) continue;
|
|
3727
|
-
|
|
4058
|
+
const entryPatch = {
|
|
4059
|
+
op: "setProps",
|
|
4060
|
+
at: entry.at,
|
|
4061
|
+
props: entry.props,
|
|
4062
|
+
meta: entry.meta ?? patch.meta
|
|
4063
|
+
};
|
|
4064
|
+
if (rejectStaleEpochPatch(entryPatch, entry.at)) continue;
|
|
4065
|
+
applyPropsUpdate(
|
|
4066
|
+
entry.at,
|
|
4067
|
+
entry.props,
|
|
4068
|
+
readPatchParseEpoch(entryPatch),
|
|
4069
|
+
readPatchTx(entryPatch),
|
|
4070
|
+
(0, import_patch_batching3.getPatchKind)(entryPatch) === "semantic"
|
|
4071
|
+
);
|
|
3728
4072
|
}
|
|
3729
4073
|
break;
|
|
3730
4074
|
}
|
|
3731
4075
|
case "finalize": {
|
|
4076
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3732
4077
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
3733
4078
|
if (!target || !target.block) break;
|
|
3734
4079
|
if (!target.block.isFinalized) {
|
|
@@ -3737,6 +4082,17 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3737
4082
|
target.version++;
|
|
3738
4083
|
touched.add(target.id);
|
|
3739
4084
|
mutatedBlocks = true;
|
|
4085
|
+
if (!patch.at.nodeId && target.id === patch.at.blockId && target.type !== "code" && target.parentId) {
|
|
4086
|
+
const parent = nodes.get(target.parentId);
|
|
4087
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
4088
|
+
if (parent && index !== -1) {
|
|
4089
|
+
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(target.block));
|
|
4090
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
4091
|
+
if (isListRelated(target.type) || isListRelated(snapshot.type)) {
|
|
4092
|
+
markListDepthDirty(target.id);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
3740
4096
|
}
|
|
3741
4097
|
if (isListRelated(target.type)) {
|
|
3742
4098
|
markListDepthDirty(target.id);
|
|
@@ -3750,6 +4106,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3750
4106
|
break;
|
|
3751
4107
|
}
|
|
3752
4108
|
case "reorder": {
|
|
4109
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3753
4110
|
const parent = resolveParent(nodes, patch.at);
|
|
3754
4111
|
if (!parent) break;
|
|
3755
4112
|
const length = parent.children.length;
|
|
@@ -3764,6 +4121,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3764
4121
|
parent.children.splice(to, 0, ...moved);
|
|
3765
4122
|
parent.version++;
|
|
3766
4123
|
touched.add(parent.id);
|
|
4124
|
+
if ((0, import_patch_batching3.getPatchKind)(patch) === "semantic") {
|
|
4125
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
4126
|
+
}
|
|
3767
4127
|
if (isListRelated(parent.type)) {
|
|
3768
4128
|
markListDepthDirty(parent.id);
|
|
3769
4129
|
}
|
|
@@ -3779,15 +4139,31 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3779
4139
|
break;
|
|
3780
4140
|
}
|
|
3781
4141
|
case "appendLines": {
|
|
4142
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3782
4143
|
const parent = resolveParent(nodes, patch.at);
|
|
3783
4144
|
if (!parent) break;
|
|
3784
|
-
|
|
4145
|
+
if (parent.type !== "code") {
|
|
4146
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
4147
|
+
appendDiagnostic(`appendLines target not code:${parent.id}:${parent.type}`);
|
|
4148
|
+
break;
|
|
4149
|
+
}
|
|
4150
|
+
const requestedStartIndex = Math.max(0, patch.startIndex);
|
|
4151
|
+
const startIndex = Math.max(0, Math.min(requestedStartIndex, parent.children.length));
|
|
3785
4152
|
const lineCount = patch.lines?.length ?? 0;
|
|
3786
4153
|
if (lineCount === 0) break;
|
|
4154
|
+
const prefixMatches = parent.children.every((childId, index) => childId === expectedCodeLineId(parent.id, index));
|
|
4155
|
+
const isStrictTailAppend = requestedStartIndex === parent.children.length;
|
|
4156
|
+
if (!isStrictTailAppend || !prefixMatches) {
|
|
4157
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
4158
|
+
appendDiagnostic(
|
|
4159
|
+
`appendLines guard rejected:${parent.id}:requestedStart=${requestedStartIndex}:childCount=${parent.children.length}:prefixMatches=${prefixMatches}`
|
|
4160
|
+
);
|
|
4161
|
+
break;
|
|
4162
|
+
}
|
|
3787
4163
|
const originalChildren = parent.children.slice();
|
|
3788
4164
|
const insertedIds = [];
|
|
3789
4165
|
const insertedSet = /* @__PURE__ */ new Set();
|
|
3790
|
-
const isTrailingAppend =
|
|
4166
|
+
const isTrailingAppend = true;
|
|
3791
4167
|
let parentChildrenChanged = false;
|
|
3792
4168
|
let codeLinesMutated = false;
|
|
3793
4169
|
for (let offset = 0; offset < lineCount; offset++) {
|
|
@@ -3829,7 +4205,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3829
4205
|
parentId: parent.id,
|
|
3830
4206
|
children: [],
|
|
3831
4207
|
props: nextLineProps,
|
|
3832
|
-
version: 0
|
|
4208
|
+
version: 0,
|
|
4209
|
+
blockEpoch: parent.blockEpoch
|
|
3833
4210
|
};
|
|
3834
4211
|
nodes.set(lineId, record);
|
|
3835
4212
|
touched.add(lineId);
|
|
@@ -3879,6 +4256,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3879
4256
|
break;
|
|
3880
4257
|
}
|
|
3881
4258
|
case "setHTML": {
|
|
4259
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
3882
4260
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
3883
4261
|
if (!target) break;
|
|
3884
4262
|
const sanitized = patch.sanitized ? patch.html : (0, import_core4.sanitizeHTML)(patch.html);
|
|
@@ -3921,6 +4299,30 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3921
4299
|
applyPatch(patch);
|
|
3922
4300
|
}
|
|
3923
4301
|
}
|
|
4302
|
+
const finalizedTableRoots = /* @__PURE__ */ new Set();
|
|
4303
|
+
for (const touchedId of touched) {
|
|
4304
|
+
let cursor = nodes.get(touchedId);
|
|
4305
|
+
while (cursor && cursor.id !== import_core4.PATCH_ROOT_ID) {
|
|
4306
|
+
if (cursor.type === "table" && cursor.block?.isFinalized && cursor.parentId) {
|
|
4307
|
+
finalizedTableRoots.add(cursor.id);
|
|
4308
|
+
break;
|
|
4309
|
+
}
|
|
4310
|
+
cursor = cursor.parentId ? nodes.get(cursor.parentId) : void 0;
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4313
|
+
if (finalizedTableRoots.size > 0) {
|
|
4314
|
+
for (const tableId of finalizedTableRoots) {
|
|
4315
|
+
const tableNode = nodes.get(tableId);
|
|
4316
|
+
if (!tableNode || !tableNode.block || !tableNode.parentId) continue;
|
|
4317
|
+
const parent = nodes.get(tableNode.parentId);
|
|
4318
|
+
if (!parent) continue;
|
|
4319
|
+
const index = parent.children.indexOf(tableNode.id);
|
|
4320
|
+
if (index === -1) continue;
|
|
4321
|
+
const snapshot = (0, import_core4.createBlockSnapshot)((0, import_core4.cloneBlock)(tableNode.block));
|
|
4322
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, tableNode.blockEpoch);
|
|
4323
|
+
mutatedBlocks = true;
|
|
4324
|
+
}
|
|
4325
|
+
}
|
|
3924
4326
|
if (mutatedBlocks) {
|
|
3925
4327
|
blocksDirty = true;
|
|
3926
4328
|
}
|
|
@@ -3941,6 +4343,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3941
4343
|
normalizeListDepthsForIds(nodes, touched, listDepthDirtyNodes, import_core4.PATCH_ROOT_ID);
|
|
3942
4344
|
}
|
|
3943
4345
|
}
|
|
4346
|
+
invariantViolations = [...collectStoreInvariantViolations(nodes), ...transientDiagnostics];
|
|
4347
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
3944
4348
|
if (touched.size > 0 || mutatedBlocks) {
|
|
3945
4349
|
version++;
|
|
3946
4350
|
scheduleNotify();
|
|
@@ -3989,6 +4393,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
3989
4393
|
if (!record) {
|
|
3990
4394
|
return EMPTY_NODE_SNAPSHOT;
|
|
3991
4395
|
}
|
|
4396
|
+
const nodeSnapshotCache = getNodeSnapshotCacheForMap(nodes);
|
|
3992
4397
|
const cached = nodeSnapshotCache.get(id);
|
|
3993
4398
|
if (cached && cached.version === record.version && cached.node === record) {
|
|
3994
4399
|
return cached;
|
|
@@ -4008,6 +4413,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4008
4413
|
if (!record) {
|
|
4009
4414
|
return EMPTY_CHILDREN_SNAPSHOT;
|
|
4010
4415
|
}
|
|
4416
|
+
const childrenSnapshotCache = getChildrenSnapshotCacheForMap(nodes);
|
|
4011
4417
|
const cached = childrenSnapshotCache.get(id);
|
|
4012
4418
|
if (cached && cached.version === record.version) {
|
|
4013
4419
|
return cached;
|
|
@@ -4017,6 +4423,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
4017
4423
|
pruneCache(childrenSnapshotCache, CHILDREN_SNAPSHOT_CACHE_LIMIT, CHILDREN_SNAPSHOT_CACHE_BUFFER);
|
|
4018
4424
|
return snapshot;
|
|
4019
4425
|
},
|
|
4426
|
+
getInvariantViolations() {
|
|
4427
|
+
return invariantViolations.slice();
|
|
4428
|
+
},
|
|
4429
|
+
getDebugCounters() {
|
|
4430
|
+
return { ...debugCounters };
|
|
4431
|
+
},
|
|
4020
4432
|
getLastCoalescingMetrics() {
|
|
4021
4433
|
return lastCoalescingMetrics;
|
|
4022
4434
|
},
|
|
@@ -4501,8 +4913,10 @@ var ListBlockView = import_react10.default.memo(
|
|
|
4501
4913
|
isFinalized: block?.isFinalized ?? false
|
|
4502
4914
|
});
|
|
4503
4915
|
}, [listDebugEnabled, blockId, depth, ordered, childIds, listItemIds, store, block?.isFinalized]);
|
|
4504
|
-
const listStyle = import_react10.default.useMemo(() => {
|
|
4505
|
-
if (!ordered || listItemIds.length === 0)
|
|
4916
|
+
const { listStyle, markerDigits } = import_react10.default.useMemo(() => {
|
|
4917
|
+
if (!ordered || listItemIds.length === 0) {
|
|
4918
|
+
return { listStyle: void 0, markerDigits: 1 };
|
|
4919
|
+
}
|
|
4506
4920
|
let maxDigits = 1;
|
|
4507
4921
|
listItemIds.forEach((childId, index) => {
|
|
4508
4922
|
const childNode = store.getNode(childId);
|
|
@@ -4514,9 +4928,14 @@ var ListBlockView = import_react10.default.memo(
|
|
|
4514
4928
|
const digits = digitMatch ? digitMatch.length : text.length;
|
|
4515
4929
|
if (digits > maxDigits) maxDigits = digits;
|
|
4516
4930
|
});
|
|
4517
|
-
const baseIndent = depth === 0 ? "
|
|
4931
|
+
const baseIndent = depth === 0 ? "2rem" : depth === 1 ? "1.75rem" : "1.5rem";
|
|
4932
|
+
const extraDigits = Math.max(0, maxDigits - 1);
|
|
4518
4933
|
return {
|
|
4519
|
-
|
|
4934
|
+
markerDigits: maxDigits,
|
|
4935
|
+
listStyle: {
|
|
4936
|
+
["--list-indent"]: extraDigits > 0 ? `calc(${baseIndent} + ${extraDigits}ch)` : baseIndent,
|
|
4937
|
+
["--list-marker-digits"]: String(maxDigits)
|
|
4938
|
+
}
|
|
4520
4939
|
};
|
|
4521
4940
|
}, [ordered, listItemIds, store, depth]);
|
|
4522
4941
|
if (listItemIds.length === 0) return null;
|
|
@@ -4525,6 +4944,7 @@ var ListBlockView = import_react10.default.memo(
|
|
|
4525
4944
|
{
|
|
4526
4945
|
className: `markdown-list ${ordered ? "ordered" : "unordered"}`,
|
|
4527
4946
|
"data-list-depth": depth,
|
|
4947
|
+
"data-marker-digits": ordered ? markerDigits : void 0,
|
|
4528
4948
|
"data-list-id": listDebugEnabled ? blockId : void 0,
|
|
4529
4949
|
style: listStyle,
|
|
4530
4950
|
children: listItemIds.map((childId, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -4706,6 +5126,7 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4706
5126
|
deferredConfig ? { ...deferredConfig, enabled: true } : { enabled: false }
|
|
4707
5127
|
);
|
|
4708
5128
|
if (!node || !node.block) return null;
|
|
5129
|
+
const blockIsFinalized = node.block.isFinalized;
|
|
4709
5130
|
const nodeVersion = node.version;
|
|
4710
5131
|
const lines = import_react10.default.useMemo(() => {
|
|
4711
5132
|
const seenIds = /* @__PURE__ */ new Set();
|
|
@@ -4736,13 +5157,25 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4736
5157
|
const lang = typeof node.props?.lang === "string" ? node.props?.lang : node.block.payload.meta?.lang;
|
|
4737
5158
|
const preAttrs = node.props?.preAttrs ?? void 0;
|
|
4738
5159
|
const codeAttrs = node.props?.codeAttrs ?? void 0;
|
|
5160
|
+
const blockMeta = node.block.payload.meta ?? void 0;
|
|
5161
|
+
const lazyEnabled = Boolean(blockMeta?.lazyTokenization);
|
|
5162
|
+
const lazyTokenizedUntil = typeof blockMeta?.lazyTokenizedUntil === "number" ? blockMeta.lazyTokenizedUntil : 0;
|
|
5163
|
+
const lazyHighlightedLines = Array.isArray(blockMeta?.highlightedLines) ? blockMeta.highlightedLines.length : 0;
|
|
5164
|
+
const lazyTokenLines = Array.isArray(blockMeta?.tokenLines) ? blockMeta.tokenLines.length : 0;
|
|
5165
|
+
const lazySourceTextLineCount = import_react10.default.useMemo(() => {
|
|
5166
|
+
const raw = typeof node.block?.payload.raw === "string" ? node.block.payload.raw : "";
|
|
5167
|
+
const metaCode = typeof blockMeta?.code === "string" ? blockMeta.code : null;
|
|
5168
|
+
const sourceText = resolveCodeSourceText(raw, metaCode);
|
|
5169
|
+
if (sourceText.length === 0) return 0;
|
|
5170
|
+
return sourceText.split("\n").length;
|
|
5171
|
+
}, [blockMeta, node.block?.payload.raw]);
|
|
5172
|
+
const totalLazyLineCount = Math.max(lines.length, lazyHighlightedLines, lazyTokenLines, lazySourceTextLineCount);
|
|
4739
5173
|
const virtualizationConfig = DEFAULT_VIRTUALIZED_CODE_CONFIG;
|
|
4740
5174
|
const virtualizationDisabled = typeof process !== "undefined" && typeof process.env === "object" && process.env.STREAM_MDX_DISABLE_VIRTUALIZED_CODE === "true";
|
|
4741
|
-
const
|
|
5175
|
+
const canVirtualize = node.block.isFinalized && !lazyEnabled;
|
|
5176
|
+
const shouldVirtualize = canVirtualize && !virtualizationDisabled && virtualizationConfig.enabled && lines.length >= virtualizationConfig.virtualizeThreshold;
|
|
4742
5177
|
const virtualization = useVirtualizedCode(lines, shouldVirtualize ? virtualizationConfig : { ...virtualizationConfig, enabled: false });
|
|
4743
5178
|
const highlightRequester = useCodeHighlightRequester();
|
|
4744
|
-
const lazyEnabled = Boolean(node.block.payload.meta?.lazyTokenization);
|
|
4745
|
-
const lazyTokenizedUntil = typeof node.block.payload.meta?.lazyTokenizedUntil === "number" ? node.block.payload.meta.lazyTokenizedUntil : 0;
|
|
4746
5179
|
const lastRangeRef = import_react10.default.useRef(null);
|
|
4747
5180
|
const rafRef = import_react10.default.useRef(null);
|
|
4748
5181
|
const idleRef = import_react10.default.useRef(null);
|
|
@@ -4823,29 +5256,111 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4823
5256
|
virtualization.window.startIndex,
|
|
4824
5257
|
virtualization.window.endIndex
|
|
4825
5258
|
]);
|
|
4826
|
-
|
|
4827
|
-
if (
|
|
4828
|
-
|
|
5259
|
+
import_react10.default.useEffect(() => {
|
|
5260
|
+
if (shouldVirtualize || !blockIsFinalized || !lazyEnabled || !highlightRequester) return;
|
|
5261
|
+
if (totalLazyLineCount <= 0 || lazyTokenizedUntil >= totalLazyLineCount) return;
|
|
5262
|
+
const nextRange = {
|
|
5263
|
+
visibleStart: 0,
|
|
5264
|
+
visibleEnd: totalLazyLineCount,
|
|
5265
|
+
prefetchStart: 0,
|
|
5266
|
+
prefetchEnd: totalLazyLineCount,
|
|
5267
|
+
tokenizedUntil: lazyTokenizedUntil
|
|
5268
|
+
};
|
|
5269
|
+
const last = lastRangeRef.current;
|
|
5270
|
+
if (last && last.visibleStart === nextRange.visibleStart && last.visibleEnd === nextRange.visibleEnd && last.prefetchStart === nextRange.prefetchStart && last.prefetchEnd === nextRange.prefetchEnd && last.tokenizedUntil === nextRange.tokenizedUntil) {
|
|
5271
|
+
return;
|
|
5272
|
+
}
|
|
5273
|
+
lastRangeRef.current = nextRange;
|
|
5274
|
+
if (rafRef.current !== null && typeof cancelAnimationFrame === "function") {
|
|
5275
|
+
cancelAnimationFrame(rafRef.current);
|
|
5276
|
+
}
|
|
5277
|
+
const requestFullHighlight = () => {
|
|
5278
|
+
highlightRequester({
|
|
5279
|
+
blockId,
|
|
5280
|
+
startLine: 0,
|
|
5281
|
+
endLine: totalLazyLineCount,
|
|
5282
|
+
priority: "visible",
|
|
5283
|
+
reason: "finalize-full"
|
|
5284
|
+
});
|
|
5285
|
+
rafRef.current = null;
|
|
5286
|
+
};
|
|
5287
|
+
if (typeof requestAnimationFrame === "function") {
|
|
5288
|
+
rafRef.current = requestAnimationFrame(requestFullHighlight);
|
|
5289
|
+
} else {
|
|
5290
|
+
requestFullHighlight();
|
|
4829
5291
|
}
|
|
5292
|
+
}, [blockId, blockIsFinalized, highlightRequester, lazyEnabled, lazyTokenizedUntil, shouldVirtualize, totalLazyLineCount]);
|
|
5293
|
+
const highlightedHtml = import_react10.default.useMemo(() => {
|
|
5294
|
+
const blockHtml = node.block?.payload.highlightedHtml ?? "";
|
|
5295
|
+
const raw = typeof node.block?.payload.raw === "string" ? node.block.payload.raw : "";
|
|
5296
|
+
const metaCode = typeof node.block?.payload.meta?.code === "string" ? (node.block?.payload.meta).code : null;
|
|
5297
|
+
const sourceText = resolveCodeSourceText(raw, metaCode);
|
|
5298
|
+
const sourceEndsWithNewline = sourceText.endsWith("\n");
|
|
5299
|
+
const sourceLines = sourceText.length > 0 ? sourceText.split("\n") : [];
|
|
5300
|
+
const rawFallbackLines = buildCodeFallbackLines(raw);
|
|
5301
|
+
const deterministicWrapperAttrs = (0, import_core5.getDefaultCodeWrapperAttributes)(lang);
|
|
5302
|
+
const composedPreAttrs = deterministicWrapperAttrs.preAttrs;
|
|
5303
|
+
const composedCodeAttrs = deterministicWrapperAttrs.codeAttrs;
|
|
5304
|
+
const shouldAppendTerminalNewline = (renderedLines) => {
|
|
5305
|
+
if (!sourceEndsWithNewline || renderedLines.length === 0 || lines.length === 0) {
|
|
5306
|
+
return false;
|
|
5307
|
+
}
|
|
5308
|
+
const lastRendered = renderedLines[renderedLines.length - 1];
|
|
5309
|
+
const lastKnown = lines[lines.length - 1];
|
|
5310
|
+
if (!lastRendered || !lastKnown || lastRendered.index !== lastKnown.index || lastRendered.text === "") {
|
|
5311
|
+
return false;
|
|
5312
|
+
}
|
|
5313
|
+
const expectedRenderedLineCount = Math.max(0, sourceLines.length - 1);
|
|
5314
|
+
const expectedLastRenderedLine = sourceLines.length >= 2 ? sourceLines[sourceLines.length - 2] ?? "" : "";
|
|
5315
|
+
return renderedLines.length === expectedRenderedLineCount && lastRendered.text === expectedLastRenderedLine;
|
|
5316
|
+
};
|
|
4830
5317
|
if (lines.length > 0) {
|
|
4831
5318
|
const hasLineHtml = lines.some((line) => typeof line.html === "string" && line.html.length > 0);
|
|
4832
|
-
if (!hasLineHtml &&
|
|
4833
|
-
return
|
|
5319
|
+
if (!hasLineHtml && blockHtml) {
|
|
5320
|
+
return blockHtml;
|
|
4834
5321
|
}
|
|
4835
5322
|
if (shouldVirtualize) {
|
|
4836
|
-
return composeHighlightedHtml(
|
|
5323
|
+
return composeHighlightedHtml(
|
|
5324
|
+
virtualization.window.visibleLines,
|
|
5325
|
+
composedPreAttrs,
|
|
5326
|
+
composedCodeAttrs,
|
|
5327
|
+
shouldAppendTerminalNewline(virtualization.window.visibleLines)
|
|
5328
|
+
);
|
|
4837
5329
|
}
|
|
4838
|
-
return composeHighlightedHtml(lines,
|
|
5330
|
+
return composeHighlightedHtml(lines, composedPreAttrs, composedCodeAttrs, shouldAppendTerminalNewline(lines));
|
|
5331
|
+
}
|
|
5332
|
+
if (!shouldVirtualize && blockHtml) {
|
|
5333
|
+
const hasHighlightedLines = blockHtml.includes('class="line"');
|
|
5334
|
+
if (!hasHighlightedLines && rawFallbackLines.length > 0) {
|
|
5335
|
+
return composeHighlightedHtml(
|
|
5336
|
+
rawFallbackLines,
|
|
5337
|
+
composedPreAttrs,
|
|
5338
|
+
composedCodeAttrs,
|
|
5339
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5340
|
+
);
|
|
5341
|
+
}
|
|
5342
|
+
return blockHtml;
|
|
4839
5343
|
}
|
|
4840
|
-
const blockHtml = node.block?.payload.highlightedHtml ?? "";
|
|
4841
5344
|
if (blockHtml?.trim().match(/^```[\w-]*\s*$/)) {
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
5345
|
+
if (rawFallbackLines.length > 0) {
|
|
5346
|
+
return composeHighlightedHtml(
|
|
5347
|
+
rawFallbackLines,
|
|
5348
|
+
composedPreAttrs,
|
|
5349
|
+
composedCodeAttrs,
|
|
5350
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5351
|
+
);
|
|
4845
5352
|
}
|
|
4846
5353
|
}
|
|
5354
|
+
if (!blockHtml && rawFallbackLines.length > 0) {
|
|
5355
|
+
return composeHighlightedHtml(
|
|
5356
|
+
rawFallbackLines,
|
|
5357
|
+
composedPreAttrs,
|
|
5358
|
+
composedCodeAttrs,
|
|
5359
|
+
sourceEndsWithNewline && rawFallbackLines[rawFallbackLines.length - 1]?.text !== ""
|
|
5360
|
+
);
|
|
5361
|
+
}
|
|
4847
5362
|
return blockHtml;
|
|
4848
|
-
}, [shouldVirtualize, node.block?.payload.highlightedHtml,
|
|
5363
|
+
}, [blockIsFinalized, shouldVirtualize, node.block?.payload.highlightedHtml, node.block?.payload.meta, lines, lang, virtualization.window.visibleLines, node.block?.payload.raw]);
|
|
4849
5364
|
const rendered = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4850
5365
|
CodeComponent,
|
|
4851
5366
|
{
|
|
@@ -4857,13 +5372,19 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4857
5372
|
codeAttrs
|
|
4858
5373
|
}
|
|
4859
5374
|
);
|
|
5375
|
+
const effectiveLineCount = import_react10.default.useMemo(() => {
|
|
5376
|
+
if (lines.length > 0) {
|
|
5377
|
+
return lines.length;
|
|
5378
|
+
}
|
|
5379
|
+
return 1;
|
|
5380
|
+
}, [lines.length]);
|
|
4860
5381
|
const codeFrameClass = "not-prose flex flex-col rounded-lg border border-input pt-1 font-mono text-sm";
|
|
4861
5382
|
const codeMetricsAttrs = {
|
|
4862
5383
|
"data-code-block": "true",
|
|
4863
5384
|
"data-block-id": blockId,
|
|
4864
5385
|
"data-code-virtualized": shouldVirtualize ? "true" : "false",
|
|
4865
|
-
"data-code-total-lines": String(
|
|
4866
|
-
"data-code-mounted-lines": String(shouldVirtualize ? virtualization.window.mountedLines :
|
|
5386
|
+
"data-code-total-lines": String(effectiveLineCount),
|
|
5387
|
+
"data-code-mounted-lines": String(shouldVirtualize ? virtualization.window.mountedLines : effectiveLineCount),
|
|
4867
5388
|
"data-code-window-size": String(virtualization.config.windowSize)
|
|
4868
5389
|
};
|
|
4869
5390
|
const codeView = shouldVirtualize ? (() => {
|
|
@@ -4909,21 +5430,152 @@ var CodeBlockView = import_react10.default.memo(({ store, blockId, registry }) =
|
|
|
4909
5430
|
return codeView;
|
|
4910
5431
|
});
|
|
4911
5432
|
CodeBlockView.displayName = "CodeBlockView";
|
|
4912
|
-
function composeHighlightedHtml(lines, preAttrs, codeAttrs) {
|
|
5433
|
+
function composeHighlightedHtml(lines, preAttrs, codeAttrs, appendTerminalNewline = false) {
|
|
4913
5434
|
const lineMarkup = lines.map((line) => {
|
|
4914
|
-
const content = line.html ?? escapeHtml3(line.text);
|
|
5435
|
+
const content = line.html ?? renderTokenLineHtml(line.tokens) ?? escapeHtml3(line.text);
|
|
4915
5436
|
const dataLine = Number.isFinite(line.index) ? ` data-line="${line.index + 1}"` : "";
|
|
4916
5437
|
return `<span class="line"${dataLine}>${content}</span>`;
|
|
4917
5438
|
}).join("\n");
|
|
4918
5439
|
const preAttr = attrsToString(preAttrs);
|
|
4919
5440
|
const codeAttr = attrsToString(codeAttrs);
|
|
4920
|
-
return `<pre${preAttr}><code${codeAttr}>${lineMarkup}
|
|
4921
|
-
|
|
5441
|
+
return `<pre${preAttr}><code${codeAttr}>${lineMarkup}${appendTerminalNewline ? "\n" : ""}</code></pre>`;
|
|
5442
|
+
}
|
|
5443
|
+
var TOKEN_FONT_STYLE_ITALIC = 1;
|
|
5444
|
+
var TOKEN_FONT_STYLE_BOLD = 2;
|
|
5445
|
+
var TOKEN_FONT_STYLE_UNDERLINE = 4;
|
|
5446
|
+
var TOKEN_FONT_STYLE_STRIKETHROUGH = 8;
|
|
5447
|
+
function renderTokenLineHtml(tokens) {
|
|
5448
|
+
if (!tokens || !Array.isArray(tokens.spans)) {
|
|
5449
|
+
return null;
|
|
5450
|
+
}
|
|
5451
|
+
return mergeRenderableTokenSpans(tokens.spans).map((span) => renderTokenSpanHtml(span)).join("");
|
|
5452
|
+
}
|
|
5453
|
+
function renderTokenSpanHtml(span) {
|
|
5454
|
+
const dark = span.v?.dark;
|
|
5455
|
+
const light = span.v?.light;
|
|
5456
|
+
const single = span.s;
|
|
5457
|
+
const styles = [];
|
|
5458
|
+
if (dark?.fg) {
|
|
5459
|
+
styles.push(`--shiki-dark:${dark.fg}`);
|
|
5460
|
+
}
|
|
5461
|
+
if (light?.fg) {
|
|
5462
|
+
styles.push(`--shiki-light:${light.fg}`);
|
|
5463
|
+
}
|
|
5464
|
+
if (!light?.fg && !dark?.fg && single?.fg) {
|
|
5465
|
+
styles.push(`color:${single.fg}`);
|
|
5466
|
+
}
|
|
5467
|
+
const fontStyle = light?.fs ?? dark?.fs ?? single?.fs;
|
|
5468
|
+
if (typeof fontStyle === "number" && fontStyle > 0) {
|
|
5469
|
+
if (fontStyle & TOKEN_FONT_STYLE_ITALIC) {
|
|
5470
|
+
styles.push("font-style: italic");
|
|
5471
|
+
}
|
|
5472
|
+
if (fontStyle & TOKEN_FONT_STYLE_BOLD) {
|
|
5473
|
+
styles.push("font-weight: bold");
|
|
5474
|
+
}
|
|
5475
|
+
const decorations = [];
|
|
5476
|
+
if (fontStyle & TOKEN_FONT_STYLE_UNDERLINE) {
|
|
5477
|
+
decorations.push("underline");
|
|
5478
|
+
}
|
|
5479
|
+
if (fontStyle & TOKEN_FONT_STYLE_STRIKETHROUGH) {
|
|
5480
|
+
decorations.push("line-through");
|
|
5481
|
+
}
|
|
5482
|
+
if (decorations.length > 0) {
|
|
5483
|
+
styles.push(`text-decoration: ${decorations.join(" ")}`);
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
const content = escapeHtml3(span.t ?? "");
|
|
5487
|
+
if (styles.length === 0) {
|
|
5488
|
+
return content;
|
|
5489
|
+
}
|
|
5490
|
+
return `<span style="${styles.join(";")}">${content}</span>`;
|
|
5491
|
+
}
|
|
5492
|
+
function mergeRenderableTokenSpans(spans) {
|
|
5493
|
+
if (spans.length <= 1) {
|
|
5494
|
+
return spans.slice();
|
|
5495
|
+
}
|
|
5496
|
+
const merged = [];
|
|
5497
|
+
let pendingWhitespace = "";
|
|
5498
|
+
for (const span of spans) {
|
|
5499
|
+
const text = typeof span.t === "string" ? span.t : "";
|
|
5500
|
+
if (/^[\t ]+$/.test(text)) {
|
|
5501
|
+
pendingWhitespace += text;
|
|
5502
|
+
continue;
|
|
5503
|
+
}
|
|
5504
|
+
const nextSpan = pendingWhitespace ? { ...span, t: `${pendingWhitespace}${text}` } : span;
|
|
5505
|
+
pendingWhitespace = "";
|
|
5506
|
+
const previous = merged[merged.length - 1];
|
|
5507
|
+
if (previous && sameTokenSpanStyle(previous, nextSpan)) {
|
|
5508
|
+
previous.t += nextSpan.t;
|
|
5509
|
+
} else {
|
|
5510
|
+
merged.push({ ...nextSpan });
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
if (pendingWhitespace) {
|
|
5514
|
+
const previous = merged[merged.length - 1];
|
|
5515
|
+
if (previous) {
|
|
5516
|
+
previous.t += pendingWhitespace;
|
|
5517
|
+
} else {
|
|
5518
|
+
merged.push({ t: pendingWhitespace });
|
|
5519
|
+
}
|
|
5520
|
+
}
|
|
5521
|
+
return merged;
|
|
5522
|
+
}
|
|
5523
|
+
function sameTokenSpanStyle(a, b) {
|
|
5524
|
+
const variantKeys = /* @__PURE__ */ new Set([
|
|
5525
|
+
...Object.keys(a.v ?? {}),
|
|
5526
|
+
...Object.keys(b.v ?? {})
|
|
5527
|
+
]);
|
|
5528
|
+
for (const key of variantKeys) {
|
|
5529
|
+
const aStyle = a.v?.[key];
|
|
5530
|
+
const bStyle = b.v?.[key];
|
|
5531
|
+
if ((aStyle?.fg ?? null) !== (bStyle?.fg ?? null)) return false;
|
|
5532
|
+
if ((aStyle?.bg ?? null) !== (bStyle?.bg ?? null)) return false;
|
|
5533
|
+
if ((aStyle?.fs ?? null) !== (bStyle?.fs ?? null)) return false;
|
|
5534
|
+
}
|
|
5535
|
+
if ((a.s?.fg ?? null) !== (b.s?.fg ?? null)) return false;
|
|
5536
|
+
if ((a.s?.bg ?? null) !== (b.s?.bg ?? null)) return false;
|
|
5537
|
+
if ((a.s?.fs ?? null) !== (b.s?.fs ?? null)) return false;
|
|
5538
|
+
return true;
|
|
5539
|
+
}
|
|
5540
|
+
function resolveCodeSourceText(raw, metaCode) {
|
|
5541
|
+
if (metaCode !== null) {
|
|
5542
|
+
return metaCode.replace(/\r\n?/g, "\n");
|
|
5543
|
+
}
|
|
5544
|
+
if (!raw) return "";
|
|
5545
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
5546
|
+
const fenced = (0, import_core5.stripCodeFence)(normalized);
|
|
5547
|
+
return fenced.hadFence ? fenced.code : normalized;
|
|
4922
5548
|
}
|
|
4923
5549
|
function attrsToString(attrs) {
|
|
4924
5550
|
if (!attrs) return "";
|
|
4925
5551
|
return Object.entries(attrs).map(([key, value]) => ` ${key}="${escapeAttribute(value)}"`).join("");
|
|
4926
5552
|
}
|
|
5553
|
+
function buildCodeFallbackLines(raw) {
|
|
5554
|
+
const normalized = normalizeCodeFallbackRaw(raw);
|
|
5555
|
+
if (normalized.length === 0) {
|
|
5556
|
+
if (/^\s*```[^\n]*\n?\s*$/.test(raw)) {
|
|
5557
|
+
return [{ id: "temp-0", index: 0, text: "", html: null }];
|
|
5558
|
+
}
|
|
5559
|
+
return [];
|
|
5560
|
+
}
|
|
5561
|
+
return normalized.split("\n").map((line, index) => ({
|
|
5562
|
+
id: `temp-${index}`,
|
|
5563
|
+
index,
|
|
5564
|
+
text: line,
|
|
5565
|
+
html: null
|
|
5566
|
+
}));
|
|
5567
|
+
}
|
|
5568
|
+
function normalizeCodeFallbackRaw(raw) {
|
|
5569
|
+
if (!raw) return "";
|
|
5570
|
+
const normalized = raw.replace(/\r\n?/g, "\n");
|
|
5571
|
+
const fenced = (0, import_core5.stripCodeFence)(normalized);
|
|
5572
|
+
if (!fenced.hadFence) {
|
|
5573
|
+
return normalized.replace(/\n+$/, "");
|
|
5574
|
+
}
|
|
5575
|
+
let code = fenced.code;
|
|
5576
|
+
code = code.replace(/\n+$/, "");
|
|
5577
|
+
return code;
|
|
5578
|
+
}
|
|
4927
5579
|
function escapeHtml3(value) {
|
|
4928
5580
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4929
5581
|
}
|
|
@@ -5047,7 +5699,9 @@ var MarkdownRenderer = class {
|
|
|
5047
5699
|
lowPriorityFrameBudgetMs: this.config.performance?.lowPriorityFrameBudgetMs,
|
|
5048
5700
|
urgentQueueThreshold: this.config.performance?.urgentQueueThreshold,
|
|
5049
5701
|
batch: this.config.performance?.batch,
|
|
5050
|
-
historyLimit: this.config.performance?.historyLimit
|
|
5702
|
+
historyLimit: this.config.performance?.historyLimit,
|
|
5703
|
+
startupMicrotaskFlushes: this.config.performance?.startupMicrotaskFlushes,
|
|
5704
|
+
adaptiveBudgeting: this.config.performance?.adaptiveBudgeting
|
|
5051
5705
|
}
|
|
5052
5706
|
});
|
|
5053
5707
|
}
|
|
@@ -5241,18 +5895,8 @@ var MarkdownRenderer = class {
|
|
|
5241
5895
|
const receivedAt = typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
5242
5896
|
const batches = (0, import_patch_batching.splitPatchBatch)(message.patches);
|
|
5243
5897
|
batches.forEach((batch, index) => {
|
|
5244
|
-
const
|
|
5245
|
-
|
|
5246
|
-
case "insertChild":
|
|
5247
|
-
case "replaceChild":
|
|
5248
|
-
case "deleteChild":
|
|
5249
|
-
case "reorder":
|
|
5250
|
-
return true;
|
|
5251
|
-
default:
|
|
5252
|
-
return false;
|
|
5253
|
-
}
|
|
5254
|
-
});
|
|
5255
|
-
const priority = hasStructural ? "high" : batch.some(import_patch_batching.isHeavyPatch) ? "low" : "high";
|
|
5898
|
+
const hasSemantic = batch.some((patch) => (0, import_patch_batching.getPatchKind)(patch) === "semantic");
|
|
5899
|
+
const priority = hasSemantic ? "high" : batch.some(import_patch_batching.isHeavyPatch) ? "low" : "high";
|
|
5256
5900
|
this.patchScheduler.enqueue({
|
|
5257
5901
|
patches: batch,
|
|
5258
5902
|
meta: {
|
|
@@ -5397,13 +6041,14 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
5397
6041
|
const mode = options?.mode ?? "server";
|
|
5398
6042
|
const [compiledMap, setCompiledMap] = (0, import_react13.useState)(/* @__PURE__ */ new Map());
|
|
5399
6043
|
const blockSignatureRef = (0, import_react13.useRef)(/* @__PURE__ */ new Map());
|
|
6044
|
+
const failedSignatureRef = (0, import_react13.useRef)(/* @__PURE__ */ new Map());
|
|
5400
6045
|
const applyCompiledRef = (0, import_react13.useCallback)(
|
|
5401
6046
|
(block, compiledId) => {
|
|
5402
6047
|
if (mode === "worker") {
|
|
5403
6048
|
return;
|
|
5404
6049
|
}
|
|
5405
6050
|
if (options?.workerClient) {
|
|
5406
|
-
options.workerClient.setMdxCompiled(block.id, compiledId);
|
|
6051
|
+
options.workerClient.setMdxCompiled(block.id, compiledId, block.payload.raw ?? "");
|
|
5407
6052
|
return;
|
|
5408
6053
|
}
|
|
5409
6054
|
const store = options?.store;
|
|
@@ -5414,6 +6059,9 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
5414
6059
|
const index = currentBlocks.findIndex((candidate) => candidate.id === block.id);
|
|
5415
6060
|
if (index === -1) return;
|
|
5416
6061
|
const current = currentBlocks[index];
|
|
6062
|
+
if ((current.payload.raw ?? "") !== (block.payload.raw ?? "")) {
|
|
6063
|
+
return;
|
|
6064
|
+
}
|
|
5417
6065
|
if (current.payload.compiledMdxRef?.id === compiledId) {
|
|
5418
6066
|
return;
|
|
5419
6067
|
}
|
|
@@ -5443,7 +6091,13 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
5443
6091
|
if (mode === "worker") {
|
|
5444
6092
|
return;
|
|
5445
6093
|
}
|
|
5446
|
-
const targets = blocks.filter((b) =>
|
|
6094
|
+
const targets = blocks.filter((b) => {
|
|
6095
|
+
if (b.type !== "mdx" || !b.isFinalized || b.payload.compiledMdxRef || compiledMap.has(b.id)) {
|
|
6096
|
+
return false;
|
|
6097
|
+
}
|
|
6098
|
+
const raw = b.payload.raw ?? "";
|
|
6099
|
+
return failedSignatureRef.current.get(b.id) !== raw;
|
|
6100
|
+
});
|
|
5447
6101
|
if (targets.length === 0) return;
|
|
5448
6102
|
let cancelled = false;
|
|
5449
6103
|
(async () => {
|
|
@@ -5462,22 +6116,29 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
5462
6116
|
next.set(block.id, compiled.id);
|
|
5463
6117
|
return next;
|
|
5464
6118
|
});
|
|
6119
|
+
failedSignatureRef.current.delete(block.id);
|
|
5465
6120
|
applyCompiledRef(block, compiled.id);
|
|
5466
6121
|
} catch (e) {
|
|
5467
6122
|
console.warn("MDX compile failed for block", block.id, e);
|
|
6123
|
+
failedSignatureRef.current.set(block.id, block.payload.raw ?? "");
|
|
5468
6124
|
if (options?.workerClient) {
|
|
5469
|
-
options.workerClient.setMdxError(block.id, e instanceof Error ? e.message : String(e));
|
|
6125
|
+
options.workerClient.setMdxError(block.id, e instanceof Error ? e.message : String(e), block.payload.raw ?? "");
|
|
5470
6126
|
} else if (options?.store) {
|
|
6127
|
+
const currentBlocks = options.store.getBlocks();
|
|
6128
|
+
const current = currentBlocks.find((candidate) => candidate.id === block.id);
|
|
6129
|
+
if (!current || (current.payload.raw ?? "") !== (block.payload.raw ?? "")) {
|
|
6130
|
+
continue;
|
|
6131
|
+
}
|
|
5471
6132
|
options.store.applyPatches([
|
|
5472
6133
|
{
|
|
5473
6134
|
op: "setProps",
|
|
5474
6135
|
at: { blockId: block.id, nodeId: block.id },
|
|
5475
6136
|
props: {
|
|
5476
6137
|
block: {
|
|
5477
|
-
...
|
|
6138
|
+
...current,
|
|
5478
6139
|
payload: {
|
|
5479
|
-
...
|
|
5480
|
-
meta: { ...
|
|
6140
|
+
...current.payload,
|
|
6141
|
+
meta: { ...current.payload.meta ?? {}, mdxStatus: "error", mdxError: e instanceof Error ? e.message : String(e) }
|
|
5481
6142
|
}
|
|
5482
6143
|
}
|
|
5483
6144
|
}
|
|
@@ -5510,6 +6171,7 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
5510
6171
|
const currentSignature = candidate.payload.raw ?? "";
|
|
5511
6172
|
if (previousSignature !== void 0 && previousSignature !== currentSignature) {
|
|
5512
6173
|
next.delete(blockId);
|
|
6174
|
+
failedSignatureRef.current.delete(blockId);
|
|
5513
6175
|
mutated = true;
|
|
5514
6176
|
}
|
|
5515
6177
|
}
|
|
@@ -5519,6 +6181,9 @@ function useMdxCoordinator(blocks, compileEndpoint, options) {
|
|
|
5519
6181
|
for (const block of blocks) {
|
|
5520
6182
|
if (block.type === "mdx") {
|
|
5521
6183
|
signatureMap.set(block.id, block.payload.raw ?? "");
|
|
6184
|
+
if (!block.isFinalized || block.payload.compiledMdxRef) {
|
|
6185
|
+
failedSignatureRef.current.delete(block.id);
|
|
6186
|
+
}
|
|
5522
6187
|
}
|
|
5523
6188
|
}
|
|
5524
6189
|
blockSignatureRef.current = signatureMap;
|
|
@@ -5876,7 +6541,9 @@ function StreamingMarkdownComponent({
|
|
|
5876
6541
|
lowPriorityFrameBudgetMs: effectiveScheduling.lowPriorityFrameBudgetMs,
|
|
5877
6542
|
urgentQueueThreshold: effectiveScheduling.urgentQueueThreshold,
|
|
5878
6543
|
batch: effectiveScheduling.batch,
|
|
5879
|
-
historyLimit
|
|
6544
|
+
historyLimit,
|
|
6545
|
+
startupMicrotaskFlushes: effectiveScheduling.startupMicrotaskFlushes,
|
|
6546
|
+
adaptiveBudgeting: effectiveScheduling.adaptiveBudgeting
|
|
5880
6547
|
},
|
|
5881
6548
|
mdx: mdxConfig
|
|
5882
6549
|
};
|