@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/store.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(store_exports, {
|
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(store_exports);
|
|
28
28
|
var import_core2 = require("@stream-mdx/core");
|
|
29
|
+
var import_patch_batching = require("@stream-mdx/core/perf/patch-batching");
|
|
29
30
|
|
|
30
31
|
// src/renderer/list-utils.ts
|
|
31
32
|
function updateNodeDepth(node, depth) {
|
|
@@ -124,12 +125,28 @@ function snapshotToBlock(node) {
|
|
|
124
125
|
}
|
|
125
126
|
return null;
|
|
126
127
|
}
|
|
127
|
-
var
|
|
128
|
-
var
|
|
128
|
+
var nodeSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
129
|
+
var childrenSnapshotCacheByMap = /* @__PURE__ */ new WeakMap();
|
|
129
130
|
var NODE_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
130
131
|
var CHILDREN_SNAPSHOT_CACHE_LIMIT = 5e4;
|
|
131
132
|
var NODE_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(NODE_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
132
133
|
var CHILDREN_SNAPSHOT_CACHE_BUFFER = Math.max(200, Math.floor(CHILDREN_SNAPSHOT_CACHE_LIMIT * 0.1));
|
|
134
|
+
function getNodeSnapshotCacheForMap(map) {
|
|
135
|
+
let cache = nodeSnapshotCacheByMap.get(map);
|
|
136
|
+
if (!cache) {
|
|
137
|
+
cache = /* @__PURE__ */ new Map();
|
|
138
|
+
nodeSnapshotCacheByMap.set(map, cache);
|
|
139
|
+
}
|
|
140
|
+
return cache;
|
|
141
|
+
}
|
|
142
|
+
function getChildrenSnapshotCacheForMap(map) {
|
|
143
|
+
let cache = childrenSnapshotCacheByMap.get(map);
|
|
144
|
+
if (!cache) {
|
|
145
|
+
cache = /* @__PURE__ */ new Map();
|
|
146
|
+
childrenSnapshotCacheByMap.set(map, cache);
|
|
147
|
+
}
|
|
148
|
+
return cache;
|
|
149
|
+
}
|
|
133
150
|
function pruneCache(cache, max, buffer) {
|
|
134
151
|
if (cache.size <= max + buffer) return;
|
|
135
152
|
let remaining = cache.size - max;
|
|
@@ -139,6 +156,14 @@ function pruneCache(cache, max, buffer) {
|
|
|
139
156
|
if (remaining <= 0) break;
|
|
140
157
|
}
|
|
141
158
|
}
|
|
159
|
+
function deleteSnapshotCacheEntry(map, id) {
|
|
160
|
+
getNodeSnapshotCacheForMap(map).delete(id);
|
|
161
|
+
getChildrenSnapshotCacheForMap(map).delete(id);
|
|
162
|
+
}
|
|
163
|
+
function clearSnapshotCaches(map) {
|
|
164
|
+
getNodeSnapshotCacheForMap(map).clear();
|
|
165
|
+
getChildrenSnapshotCacheForMap(map).clear();
|
|
166
|
+
}
|
|
142
167
|
var EMPTY_CHILDREN = Object.freeze([]);
|
|
143
168
|
var EMPTY_NODE_SNAPSHOT = Object.freeze({ version: -1, node: void 0 });
|
|
144
169
|
var EMPTY_CHILDREN_SNAPSHOT = Object.freeze({
|
|
@@ -306,9 +331,57 @@ function createRootRecord() {
|
|
|
306
331
|
parentId: null,
|
|
307
332
|
children: [],
|
|
308
333
|
props: {},
|
|
309
|
-
version: 0
|
|
334
|
+
version: 0,
|
|
335
|
+
blockEpoch: 0
|
|
310
336
|
};
|
|
311
337
|
}
|
|
338
|
+
function readNumericEpoch(value) {
|
|
339
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
340
|
+
return void 0;
|
|
341
|
+
}
|
|
342
|
+
return value;
|
|
343
|
+
}
|
|
344
|
+
function readSnapshotBlockEpoch(snapshot) {
|
|
345
|
+
return readNumericEpoch(snapshot.meta?.blockEpoch);
|
|
346
|
+
}
|
|
347
|
+
function readPatchBlockEpoch(patch) {
|
|
348
|
+
if (patch.op === "setHTML") {
|
|
349
|
+
return readNumericEpoch(patch.patchMeta?.blockEpoch);
|
|
350
|
+
}
|
|
351
|
+
return readNumericEpoch(patch.meta?.blockEpoch);
|
|
352
|
+
}
|
|
353
|
+
function readPatchParseEpoch(patch) {
|
|
354
|
+
if (patch.op === "setHTML") {
|
|
355
|
+
return readNumericEpoch(patch.patchMeta?.parseEpoch);
|
|
356
|
+
}
|
|
357
|
+
return readNumericEpoch(patch.meta?.parseEpoch);
|
|
358
|
+
}
|
|
359
|
+
function readPatchTx(patch) {
|
|
360
|
+
if (patch.op === "setHTML") {
|
|
361
|
+
return readNumericEpoch(patch.patchMeta?.tx);
|
|
362
|
+
}
|
|
363
|
+
return readNumericEpoch(patch.meta?.tx);
|
|
364
|
+
}
|
|
365
|
+
function assignSubtreeBlockEpoch(map, rootId, blockEpoch, touched) {
|
|
366
|
+
const root = map.get(rootId);
|
|
367
|
+
if (!root) return;
|
|
368
|
+
const stack = [root];
|
|
369
|
+
while (stack.length > 0) {
|
|
370
|
+
const node = stack.pop();
|
|
371
|
+
if (!node) continue;
|
|
372
|
+
if (node.blockEpoch !== blockEpoch) {
|
|
373
|
+
node.blockEpoch = blockEpoch;
|
|
374
|
+
node.version += 1;
|
|
375
|
+
touched?.add(node.id);
|
|
376
|
+
}
|
|
377
|
+
for (const childId of node.children) {
|
|
378
|
+
const child = map.get(childId);
|
|
379
|
+
if (child) {
|
|
380
|
+
stack.push(child);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
312
385
|
function ensureArray(value) {
|
|
313
386
|
return Array.isArray(value) ? value : [];
|
|
314
387
|
}
|
|
@@ -368,7 +441,7 @@ function escapeHtml(value) {
|
|
|
368
441
|
}
|
|
369
442
|
function stripOuterLineSpan(html) {
|
|
370
443
|
if (!html) return null;
|
|
371
|
-
const openTagMatch = html.match(/<span[^>]*>/i);
|
|
444
|
+
const openTagMatch = html.match(/<span[^>]*class="[^"]*\bline\b[^"]*"[^>]*>/i);
|
|
372
445
|
if (!openTagMatch) {
|
|
373
446
|
return null;
|
|
374
447
|
}
|
|
@@ -417,8 +490,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
417
490
|
if (node.type !== "code-line") {
|
|
418
491
|
anomalies.push(`type-mismatch:${node.id}:${node.type}`);
|
|
419
492
|
nodes.delete(node.id);
|
|
420
|
-
|
|
421
|
-
childrenSnapshotCache.delete(node.id);
|
|
493
|
+
deleteSnapshotCacheEntry(nodes, node.id);
|
|
422
494
|
touched.add(node.id);
|
|
423
495
|
continue;
|
|
424
496
|
}
|
|
@@ -462,16 +534,14 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
462
534
|
const existing = nodes.get(desiredId);
|
|
463
535
|
if (existing && existing !== node) {
|
|
464
536
|
nodes.delete(desiredId);
|
|
465
|
-
|
|
466
|
-
childrenSnapshotCache.delete(desiredId);
|
|
537
|
+
deleteSnapshotCacheEntry(nodes, desiredId);
|
|
467
538
|
touched.add(desiredId);
|
|
468
539
|
mutated = true;
|
|
469
540
|
}
|
|
470
541
|
if (node.id !== desiredId) {
|
|
471
542
|
const previousId = node.id;
|
|
472
543
|
nodes.delete(node.id);
|
|
473
|
-
|
|
474
|
-
childrenSnapshotCache.delete(previousId);
|
|
544
|
+
deleteSnapshotCacheEntry(nodes, previousId);
|
|
475
545
|
node.id = desiredId;
|
|
476
546
|
nodes.set(desiredId, node);
|
|
477
547
|
touched.add(desiredId);
|
|
@@ -502,8 +572,7 @@ function normalizeCodeBlockChildren(nodes, parent, touched) {
|
|
|
502
572
|
for (const [id, record] of nodes) {
|
|
503
573
|
if (record.parentId === parent.id && record.type === "code-line" && !allowed.has(id)) {
|
|
504
574
|
nodes.delete(id);
|
|
505
|
-
|
|
506
|
-
childrenSnapshotCache.delete(id);
|
|
575
|
+
deleteSnapshotCacheEntry(nodes, id);
|
|
507
576
|
touched.add(id);
|
|
508
577
|
mutated = true;
|
|
509
578
|
}
|
|
@@ -587,8 +656,10 @@ function normalizeCodeLineProps(incoming, previous) {
|
|
|
587
656
|
}
|
|
588
657
|
function createCodeLineProps(index, text, highlight, tokens) {
|
|
589
658
|
const safeText = typeof text === "string" ? text : "";
|
|
590
|
-
const
|
|
591
|
-
const
|
|
659
|
+
const hasIncomingHighlight = typeof highlight === "string" && highlight.trim().length > 0;
|
|
660
|
+
const sanitized = hasIncomingHighlight ? sanitizeLineInnerHtml(highlight, safeText) : null;
|
|
661
|
+
const hasRenderableTokens = tokens !== void 0 && tokens !== null;
|
|
662
|
+
const html = sanitized && sanitized.length >= safeText.length ? sanitized : hasRenderableTokens ? null : escapeHtml(safeText);
|
|
592
663
|
const props = {
|
|
593
664
|
index,
|
|
594
665
|
text: safeText,
|
|
@@ -699,6 +770,18 @@ function validateCodeBlockChildren(nodes, parent) {
|
|
|
699
770
|
issues.push({ kind: "dangling-node", id });
|
|
700
771
|
}
|
|
701
772
|
}
|
|
773
|
+
if (parent.block?.isFinalized) {
|
|
774
|
+
const snapshot = (0, import_core2.createBlockSnapshot)((0, import_core2.cloneBlock)(parent.block));
|
|
775
|
+
const expectedChildren = ensureArray(snapshot.children).filter((child) => child.type === "code-line");
|
|
776
|
+
if (expectedChildren.length !== parent.children.length) {
|
|
777
|
+
issues.push({
|
|
778
|
+
kind: "line-count-mismatch",
|
|
779
|
+
id: parent.id,
|
|
780
|
+
expected: expectedChildren.length,
|
|
781
|
+
actual: parent.children.length
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
}
|
|
702
785
|
return { ok: issues.length === 0, issues };
|
|
703
786
|
}
|
|
704
787
|
function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
@@ -715,7 +798,7 @@ function rebuildCodeBlockFromSnapshot(nodes, parent, touched, issues) {
|
|
|
715
798
|
}
|
|
716
799
|
const snapshot = (0, import_core2.createBlockSnapshot)((0, import_core2.cloneBlock)(parent.block));
|
|
717
800
|
removeSubtree(nodes, parent.id, touched);
|
|
718
|
-
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot);
|
|
801
|
+
const inserted = insertSnapshotAt(nodes, ancestor, index, snapshot, touched, parent.blockEpoch);
|
|
719
802
|
if (!inserted) {
|
|
720
803
|
return false;
|
|
721
804
|
}
|
|
@@ -738,7 +821,55 @@ function arraysEqual(a, b) {
|
|
|
738
821
|
}
|
|
739
822
|
return true;
|
|
740
823
|
}
|
|
741
|
-
function
|
|
824
|
+
function expectedCodeLineId(parentId, index) {
|
|
825
|
+
return `${parentId}::line:${index}`;
|
|
826
|
+
}
|
|
827
|
+
function collectStoreInvariantViolations(nodes) {
|
|
828
|
+
const violations = [];
|
|
829
|
+
for (const [id, node] of nodes) {
|
|
830
|
+
if (node.type === "__root__") continue;
|
|
831
|
+
if (node.children.length > 1) {
|
|
832
|
+
const seen = /* @__PURE__ */ new Set();
|
|
833
|
+
for (const childId of node.children) {
|
|
834
|
+
if (seen.has(childId)) {
|
|
835
|
+
violations.push(`duplicate child id:${id}:${childId}`);
|
|
836
|
+
} else {
|
|
837
|
+
seen.add(childId);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
if (node.type === "list") {
|
|
842
|
+
const parent = node.parentId ? nodes.get(node.parentId) : void 0;
|
|
843
|
+
if (parent?.type === "list-item" && node.children.length === 0) {
|
|
844
|
+
violations.push(`empty nested list:${id}`);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
if (node.type === "code") {
|
|
848
|
+
for (let index = 0; index < node.children.length; index += 1) {
|
|
849
|
+
const childId = node.children[index];
|
|
850
|
+
const child = nodes.get(childId);
|
|
851
|
+
if (!child) {
|
|
852
|
+
violations.push(`missing code-line node:${node.id}:${childId}`);
|
|
853
|
+
continue;
|
|
854
|
+
}
|
|
855
|
+
if (child.type !== "code-line") {
|
|
856
|
+
violations.push(`non-code child in code block:${node.id}:${child.id}:${child.type}`);
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
const expectedId = expectedCodeLineId(node.id, index);
|
|
860
|
+
if (child.id !== expectedId) {
|
|
861
|
+
violations.push(`code-line id mismatch:${node.id}:${child.id}:${expectedId}`);
|
|
862
|
+
}
|
|
863
|
+
const indexProp = typeof child.props?.index === "number" ? child.props.index : null;
|
|
864
|
+
if (indexProp !== index) {
|
|
865
|
+
violations.push(`code-line index mismatch:${node.id}:${child.id}:${indexProp}:${index}`);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
return violations;
|
|
871
|
+
}
|
|
872
|
+
function buildNodeFromSnapshot(map, snapshot, parentId, blockEpoch) {
|
|
742
873
|
const record = {
|
|
743
874
|
id: snapshot.id,
|
|
744
875
|
type: snapshot.type,
|
|
@@ -748,6 +879,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
748
879
|
meta: snapshot.meta ? { ...snapshot.meta } : void 0,
|
|
749
880
|
range: snapshot.range ? { ...snapshot.range } : void 0,
|
|
750
881
|
version: 0,
|
|
882
|
+
blockEpoch,
|
|
751
883
|
block: snapshotToBlock(snapshot) ?? void 0
|
|
752
884
|
};
|
|
753
885
|
if (record.type === "code") {
|
|
@@ -756,7 +888,7 @@ function buildNodeFromSnapshot(map, snapshot, parentId) {
|
|
|
756
888
|
map.set(record.id, record);
|
|
757
889
|
const childSnapshots = ensureArray(snapshot.children);
|
|
758
890
|
for (const child of childSnapshots) {
|
|
759
|
-
const childRecord = buildNodeFromSnapshot(map, child, record.id);
|
|
891
|
+
const childRecord = buildNodeFromSnapshot(map, child, record.id, blockEpoch);
|
|
760
892
|
record.children.push(childRecord.id);
|
|
761
893
|
}
|
|
762
894
|
return record;
|
|
@@ -784,8 +916,7 @@ function removeSubtree(map, id, touched) {
|
|
|
784
916
|
}
|
|
785
917
|
}
|
|
786
918
|
map.delete(node.id);
|
|
787
|
-
|
|
788
|
-
childrenSnapshotCache.delete(node.id);
|
|
919
|
+
deleteSnapshotCacheEntry(map, node.id);
|
|
789
920
|
touched.add(node.id);
|
|
790
921
|
for (const childId of node.children) {
|
|
791
922
|
const child = map.get(childId);
|
|
@@ -817,13 +948,13 @@ function resolveParent(map, path) {
|
|
|
817
948
|
}
|
|
818
949
|
return map.get(path.blockId);
|
|
819
950
|
}
|
|
820
|
-
function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
951
|
+
function insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
821
952
|
if (!parent) return null;
|
|
822
953
|
const existingIndex = parent.children.indexOf(snapshot.id);
|
|
823
954
|
if (existingIndex !== -1) {
|
|
824
955
|
removeSubtree(map, parent.children[existingIndex], touched ?? /* @__PURE__ */ new Set());
|
|
825
956
|
}
|
|
826
|
-
const record = buildNodeFromSnapshot(map, snapshot, parent.id);
|
|
957
|
+
const record = buildNodeFromSnapshot(map, snapshot, parent.id, blockEpoch ?? readSnapshotBlockEpoch(snapshot) ?? parent.blockEpoch);
|
|
827
958
|
const insertedIds = [];
|
|
828
959
|
const queue = [record];
|
|
829
960
|
while (queue.length > 0) {
|
|
@@ -841,13 +972,13 @@ function insertSnapshotAt(map, parent, index, snapshot, touched) {
|
|
|
841
972
|
ensureUniqueChildren(parent, touched);
|
|
842
973
|
return { record, insertedIds };
|
|
843
974
|
}
|
|
844
|
-
function replaceSnapshotAt(map, parent, index, snapshot, touched) {
|
|
975
|
+
function replaceSnapshotAt(map, parent, index, snapshot, touched, blockEpoch) {
|
|
845
976
|
if (!parent) return;
|
|
846
977
|
if (index < 0 || index >= parent.children.length) return;
|
|
847
978
|
const targetId = parent.children[index];
|
|
848
979
|
parent.children.splice(index, 1);
|
|
849
980
|
removeSubtree(map, targetId, touched);
|
|
850
|
-
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched);
|
|
981
|
+
const inserted = insertSnapshotAt(map, parent, index, snapshot, touched, blockEpoch);
|
|
851
982
|
if (inserted) {
|
|
852
983
|
for (const id of inserted.insertedIds) {
|
|
853
984
|
touched.add(id);
|
|
@@ -867,6 +998,24 @@ function createRendererStore(initialBlocks = []) {
|
|
|
867
998
|
const listeners = /* @__PURE__ */ new Set();
|
|
868
999
|
let notifyScheduled = false;
|
|
869
1000
|
let lastCoalescingMetrics = null;
|
|
1001
|
+
let invariantViolations = [];
|
|
1002
|
+
let transientDiagnostics = [];
|
|
1003
|
+
let nextBlockEpoch = 1;
|
|
1004
|
+
const debugCounters = {
|
|
1005
|
+
appendLineGuardRejected: 0,
|
|
1006
|
+
staleEpochRejected: 0,
|
|
1007
|
+
storeInvariantViolationCount: 0
|
|
1008
|
+
};
|
|
1009
|
+
const allocateBlockEpoch = (preferred) => {
|
|
1010
|
+
const resolved = readNumericEpoch(preferred);
|
|
1011
|
+
if (resolved !== void 0) {
|
|
1012
|
+
nextBlockEpoch = Math.max(nextBlockEpoch, resolved + 1);
|
|
1013
|
+
return resolved;
|
|
1014
|
+
}
|
|
1015
|
+
const epoch = nextBlockEpoch;
|
|
1016
|
+
nextBlockEpoch += 1;
|
|
1017
|
+
return epoch;
|
|
1018
|
+
};
|
|
870
1019
|
const getRaf = () => {
|
|
871
1020
|
if (typeof globalThis !== "undefined" && typeof globalThis.requestAnimationFrame === "function") {
|
|
872
1021
|
return globalThis.requestAnimationFrame;
|
|
@@ -898,9 +1047,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
898
1047
|
}
|
|
899
1048
|
}
|
|
900
1049
|
}
|
|
1050
|
+
function appendDiagnostic(message) {
|
|
1051
|
+
transientDiagnostics = [...transientDiagnostics, message];
|
|
1052
|
+
invariantViolations = [...invariantViolations, message];
|
|
1053
|
+
}
|
|
901
1054
|
function rebuildFromBlocks(blocks) {
|
|
902
|
-
|
|
903
|
-
childrenSnapshotCache.clear();
|
|
1055
|
+
clearSnapshotCaches(nodes);
|
|
904
1056
|
nodes = /* @__PURE__ */ new Map();
|
|
905
1057
|
const root = createRootRecord();
|
|
906
1058
|
nodes.set(root.id, root);
|
|
@@ -909,9 +1061,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
909
1061
|
for (let i = 0; i < blocks.length; i++) {
|
|
910
1062
|
const block = (0, import_core2.cloneBlock)(blocks[i]);
|
|
911
1063
|
const snapshot = (0, import_core2.createBlockSnapshot)(block);
|
|
912
|
-
insertSnapshotAt(nodes, root, root.children.length, snapshot);
|
|
1064
|
+
insertSnapshotAt(nodes, root, root.children.length, snapshot, void 0, allocateBlockEpoch(readSnapshotBlockEpoch(snapshot)));
|
|
913
1065
|
}
|
|
914
1066
|
normalizeAllListDepths(nodes, /* @__PURE__ */ new Set(), import_core2.PATCH_ROOT_ID);
|
|
1067
|
+
transientDiagnostics = [];
|
|
1068
|
+
invariantViolations = collectStoreInvariantViolations(nodes);
|
|
1069
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
915
1070
|
version++;
|
|
916
1071
|
blocksDirty = true;
|
|
917
1072
|
scheduleNotify();
|
|
@@ -976,11 +1131,57 @@ function createRendererStore(initialBlocks = []) {
|
|
|
976
1131
|
listDepthDirty = true;
|
|
977
1132
|
}
|
|
978
1133
|
};
|
|
979
|
-
const
|
|
1134
|
+
const semanticTxEpochs = /* @__PURE__ */ new Map();
|
|
1135
|
+
const resolveBlockEpochTarget = (patch, at) => {
|
|
1136
|
+
if ((patch.op === "insertChild" || patch.op === "replaceChild") && at.blockId === import_core2.PATCH_ROOT_ID) {
|
|
1137
|
+
const nodeId = patch.node?.id;
|
|
1138
|
+
return nodeId ? nodes.get(nodeId) : void 0;
|
|
1139
|
+
}
|
|
1140
|
+
return nodes.get(at.blockId) ?? (at.nodeId ? nodes.get(at.nodeId) : void 0);
|
|
1141
|
+
};
|
|
1142
|
+
const rejectStaleEpochPatch = (patch, at) => {
|
|
1143
|
+
const expectedBlockEpoch = readPatchBlockEpoch(patch);
|
|
1144
|
+
const patchTx = readPatchTx(patch);
|
|
1145
|
+
if (expectedBlockEpoch === void 0) {
|
|
1146
|
+
return false;
|
|
1147
|
+
}
|
|
1148
|
+
if ((0, import_patch_batching.getPatchKind)(patch) !== "semantic" || !at) {
|
|
1149
|
+
return false;
|
|
1150
|
+
}
|
|
1151
|
+
const target = resolveBlockEpochTarget(patch, at);
|
|
1152
|
+
if (!target || target.blockEpoch === expectedBlockEpoch) {
|
|
1153
|
+
return false;
|
|
1154
|
+
}
|
|
1155
|
+
const txEpoch = at.blockId && patchTx !== void 0 ? semanticTxEpochs.get(at.blockId) : void 0;
|
|
1156
|
+
if (txEpoch && txEpoch.tx === patchTx && txEpoch.blockEpoch === target.blockEpoch) {
|
|
1157
|
+
return false;
|
|
1158
|
+
}
|
|
1159
|
+
debugCounters.staleEpochRejected += 1;
|
|
1160
|
+
appendDiagnostic(
|
|
1161
|
+
`stale epoch rejected:${patch.op}:${target.id}:expected=${expectedBlockEpoch}:actual=${target.blockEpoch}`
|
|
1162
|
+
);
|
|
1163
|
+
return true;
|
|
1164
|
+
};
|
|
1165
|
+
const advanceBlockEpoch = (blockId, touchedSet, preferredEpoch, tx) => {
|
|
1166
|
+
if (!blockId || blockId === import_core2.PATCH_ROOT_ID) {
|
|
1167
|
+
return null;
|
|
1168
|
+
}
|
|
1169
|
+
const blockRoot = nodes.get(blockId);
|
|
1170
|
+
if (!blockRoot) {
|
|
1171
|
+
return null;
|
|
1172
|
+
}
|
|
1173
|
+
const nextEpoch = allocateBlockEpoch(preferredEpoch);
|
|
1174
|
+
assignSubtreeBlockEpoch(nodes, blockRoot.id, nextEpoch, touchedSet);
|
|
1175
|
+
if (tx !== void 0) {
|
|
1176
|
+
semanticTxEpochs.set(blockRoot.id, { tx, blockEpoch: nextEpoch });
|
|
1177
|
+
}
|
|
1178
|
+
return nextEpoch;
|
|
1179
|
+
};
|
|
1180
|
+
const applyPropsUpdate = (at, props, preferredEpoch, tx, semanticUpdate = false) => {
|
|
980
1181
|
const perfStartLocal = perfEnabled ? getPerfNow() : 0;
|
|
981
1182
|
const targetId = at.nodeId ?? at.blockId;
|
|
982
1183
|
if (!targetId) return;
|
|
983
|
-
|
|
1184
|
+
let target = nodes.get(targetId);
|
|
984
1185
|
if (!target) return;
|
|
985
1186
|
const parentType = target.parentId ? nodes.get(target.parentId)?.type : void 0;
|
|
986
1187
|
if (debugListPatches && (isListRelated(target.type) || isListRelated(parentType))) {
|
|
@@ -1007,6 +1208,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1007
1208
|
propsChanged = true;
|
|
1008
1209
|
}
|
|
1009
1210
|
if (propsChanged) {
|
|
1211
|
+
if (semanticUpdate) {
|
|
1212
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
1213
|
+
}
|
|
1010
1214
|
target.version++;
|
|
1011
1215
|
touched.add(target.id);
|
|
1012
1216
|
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
@@ -1070,16 +1274,56 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1070
1274
|
}
|
|
1071
1275
|
}
|
|
1072
1276
|
let blockChanged = false;
|
|
1277
|
+
let typeChanged = false;
|
|
1278
|
+
let rebuiltFromFinalizedBlock = false;
|
|
1279
|
+
let blockEpochAdvanced = false;
|
|
1073
1280
|
const incomingBlock = props?.block;
|
|
1074
1281
|
if (incomingBlock && typeof incomingBlock === "object") {
|
|
1075
1282
|
target.block = (0, import_core2.cloneBlock)(incomingBlock);
|
|
1283
|
+
const previousType = target.type;
|
|
1284
|
+
const incomingType = typeof target.block.type === "string" ? target.block.type : target.type;
|
|
1285
|
+
if (incomingType !== target.type) {
|
|
1286
|
+
target.type = incomingType;
|
|
1287
|
+
typeChanged = true;
|
|
1288
|
+
if (isListRelated(previousType) || isListRelated(target.type)) {
|
|
1289
|
+
markListDepthDirty(target.id);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1076
1292
|
if (target.type === "code") {
|
|
1077
1293
|
applyCodeBlockMetadata(target);
|
|
1078
1294
|
}
|
|
1295
|
+
if (semanticUpdate) {
|
|
1296
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
1297
|
+
blockEpochAdvanced = true;
|
|
1298
|
+
}
|
|
1299
|
+
const shouldRebuildFinalizedTree = !at.nodeId && target.id === at.blockId && Boolean(target.block?.isFinalized) && target.type !== "code" && Boolean(target.parentId);
|
|
1300
|
+
if (shouldRebuildFinalizedTree) {
|
|
1301
|
+
const parent = target.parentId ? nodes.get(target.parentId) : void 0;
|
|
1302
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
1303
|
+
if (parent && index !== -1) {
|
|
1304
|
+
const snapshot = (0, import_core2.createBlockSnapshot)((0, import_core2.cloneBlock)(target.block));
|
|
1305
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
1306
|
+
mutatedBlocks = true;
|
|
1307
|
+
blockChanged = true;
|
|
1308
|
+
rebuiltFromFinalizedBlock = true;
|
|
1309
|
+
const rebuilt = nodes.get(target.id);
|
|
1310
|
+
if (isListRelated(previousType) || isListRelated(rebuilt?.type)) {
|
|
1311
|
+
markListDepthDirty(target.id);
|
|
1312
|
+
}
|
|
1313
|
+
target = rebuilt ?? target;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1079
1316
|
mutatedBlocks = true;
|
|
1080
1317
|
blockChanged = true;
|
|
1081
1318
|
}
|
|
1082
|
-
if (
|
|
1319
|
+
if (rebuiltFromFinalizedBlock) {
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
if (propsChanged || blockChanged || typeChanged) {
|
|
1323
|
+
if (semanticUpdate && !blockEpochAdvanced) {
|
|
1324
|
+
advanceBlockEpoch(at.blockId, touched, preferredEpoch, tx);
|
|
1325
|
+
blockEpochAdvanced = true;
|
|
1326
|
+
}
|
|
1083
1327
|
target.version++;
|
|
1084
1328
|
touched.add(target.id);
|
|
1085
1329
|
let parentForNormalization;
|
|
@@ -1122,13 +1366,22 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1122
1366
|
const applyPatch = (patch) => {
|
|
1123
1367
|
switch (patch.op) {
|
|
1124
1368
|
case "insertChild": {
|
|
1369
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
1125
1370
|
const parent = resolveParent(nodes, patch.at);
|
|
1126
|
-
const inserted = insertSnapshotAt(
|
|
1371
|
+
const inserted = insertSnapshotAt(
|
|
1372
|
+
nodes,
|
|
1373
|
+
parent,
|
|
1374
|
+
patch.index,
|
|
1375
|
+
patch.node,
|
|
1376
|
+
touched,
|
|
1377
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
1378
|
+
);
|
|
1127
1379
|
if (inserted) {
|
|
1128
1380
|
for (const id of inserted.insertedIds) {
|
|
1129
1381
|
touched.add(id);
|
|
1130
1382
|
}
|
|
1131
1383
|
mutatedBlocks = true;
|
|
1384
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
1132
1385
|
if (isListRelated(inserted.record.type) || isListRelated(parent?.type)) {
|
|
1133
1386
|
markListDepthDirty(inserted.record.id);
|
|
1134
1387
|
if (parent) {
|
|
@@ -1148,6 +1401,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1148
1401
|
break;
|
|
1149
1402
|
}
|
|
1150
1403
|
case "deleteChild": {
|
|
1404
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
1151
1405
|
const parent = resolveParent(nodes, patch.at);
|
|
1152
1406
|
if (!parent) break;
|
|
1153
1407
|
if (patch.index < 0 || patch.index >= parent.children.length) break;
|
|
@@ -1159,6 +1413,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1159
1413
|
touched.add(parent.id);
|
|
1160
1414
|
ensureUniqueChildren(parent, touched);
|
|
1161
1415
|
mutatedBlocks = true;
|
|
1416
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
1162
1417
|
if (isListRelated(parent.type) || isListRelated(removedNode?.type)) {
|
|
1163
1418
|
markListDepthDirty(parent.id);
|
|
1164
1419
|
}
|
|
@@ -1175,11 +1430,20 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1175
1430
|
break;
|
|
1176
1431
|
}
|
|
1177
1432
|
case "replaceChild": {
|
|
1433
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
1178
1434
|
const parent = resolveParent(nodes, patch.at);
|
|
1179
1435
|
if (!parent) break;
|
|
1180
|
-
replaceSnapshotAt(
|
|
1436
|
+
replaceSnapshotAt(
|
|
1437
|
+
nodes,
|
|
1438
|
+
parent,
|
|
1439
|
+
patch.index,
|
|
1440
|
+
patch.node,
|
|
1441
|
+
touched,
|
|
1442
|
+
allocateBlockEpoch(readPatchParseEpoch(patch) ?? readSnapshotBlockEpoch(patch.node))
|
|
1443
|
+
);
|
|
1181
1444
|
touched.add(parent.id);
|
|
1182
1445
|
mutatedBlocks = true;
|
|
1446
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
1183
1447
|
if (isListRelated(parent.type)) {
|
|
1184
1448
|
markListDepthDirty(parent.id);
|
|
1185
1449
|
}
|
|
@@ -1193,18 +1457,33 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1193
1457
|
break;
|
|
1194
1458
|
}
|
|
1195
1459
|
case "setProps": {
|
|
1196
|
-
|
|
1460
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
1461
|
+
applyPropsUpdate(patch.at, patch.props, readPatchParseEpoch(patch), readPatchTx(patch), (0, import_patch_batching.getPatchKind)(patch) === "semantic");
|
|
1197
1462
|
break;
|
|
1198
1463
|
}
|
|
1199
1464
|
case "setPropsBatch": {
|
|
1200
1465
|
const entries = Array.isArray(patch.entries) ? patch.entries : [];
|
|
1201
1466
|
for (const entry of entries) {
|
|
1202
1467
|
if (!entry || !entry.at) continue;
|
|
1203
|
-
|
|
1468
|
+
const entryPatch = {
|
|
1469
|
+
op: "setProps",
|
|
1470
|
+
at: entry.at,
|
|
1471
|
+
props: entry.props,
|
|
1472
|
+
meta: entry.meta ?? patch.meta
|
|
1473
|
+
};
|
|
1474
|
+
if (rejectStaleEpochPatch(entryPatch, entry.at)) continue;
|
|
1475
|
+
applyPropsUpdate(
|
|
1476
|
+
entry.at,
|
|
1477
|
+
entry.props,
|
|
1478
|
+
readPatchParseEpoch(entryPatch),
|
|
1479
|
+
readPatchTx(entryPatch),
|
|
1480
|
+
(0, import_patch_batching.getPatchKind)(entryPatch) === "semantic"
|
|
1481
|
+
);
|
|
1204
1482
|
}
|
|
1205
1483
|
break;
|
|
1206
1484
|
}
|
|
1207
1485
|
case "finalize": {
|
|
1486
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
1208
1487
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
1209
1488
|
if (!target || !target.block) break;
|
|
1210
1489
|
if (!target.block.isFinalized) {
|
|
@@ -1213,6 +1492,17 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1213
1492
|
target.version++;
|
|
1214
1493
|
touched.add(target.id);
|
|
1215
1494
|
mutatedBlocks = true;
|
|
1495
|
+
if (!patch.at.nodeId && target.id === patch.at.blockId && target.type !== "code" && target.parentId) {
|
|
1496
|
+
const parent = nodes.get(target.parentId);
|
|
1497
|
+
const index = parent ? parent.children.indexOf(target.id) : -1;
|
|
1498
|
+
if (parent && index !== -1) {
|
|
1499
|
+
const snapshot = (0, import_core2.createBlockSnapshot)((0, import_core2.cloneBlock)(target.block));
|
|
1500
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, target.blockEpoch);
|
|
1501
|
+
if (isListRelated(target.type) || isListRelated(snapshot.type)) {
|
|
1502
|
+
markListDepthDirty(target.id);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1216
1506
|
}
|
|
1217
1507
|
if (isListRelated(target.type)) {
|
|
1218
1508
|
markListDepthDirty(target.id);
|
|
@@ -1226,6 +1516,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1226
1516
|
break;
|
|
1227
1517
|
}
|
|
1228
1518
|
case "reorder": {
|
|
1519
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
1229
1520
|
const parent = resolveParent(nodes, patch.at);
|
|
1230
1521
|
if (!parent) break;
|
|
1231
1522
|
const length = parent.children.length;
|
|
@@ -1240,6 +1531,9 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1240
1531
|
parent.children.splice(to, 0, ...moved);
|
|
1241
1532
|
parent.version++;
|
|
1242
1533
|
touched.add(parent.id);
|
|
1534
|
+
if ((0, import_patch_batching.getPatchKind)(patch) === "semantic") {
|
|
1535
|
+
advanceBlockEpoch(patch.at.blockId, touched, readPatchParseEpoch(patch), readPatchTx(patch));
|
|
1536
|
+
}
|
|
1243
1537
|
if (isListRelated(parent.type)) {
|
|
1244
1538
|
markListDepthDirty(parent.id);
|
|
1245
1539
|
}
|
|
@@ -1255,15 +1549,31 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1255
1549
|
break;
|
|
1256
1550
|
}
|
|
1257
1551
|
case "appendLines": {
|
|
1552
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
1258
1553
|
const parent = resolveParent(nodes, patch.at);
|
|
1259
1554
|
if (!parent) break;
|
|
1260
|
-
|
|
1555
|
+
if (parent.type !== "code") {
|
|
1556
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
1557
|
+
appendDiagnostic(`appendLines target not code:${parent.id}:${parent.type}`);
|
|
1558
|
+
break;
|
|
1559
|
+
}
|
|
1560
|
+
const requestedStartIndex = Math.max(0, patch.startIndex);
|
|
1561
|
+
const startIndex = Math.max(0, Math.min(requestedStartIndex, parent.children.length));
|
|
1261
1562
|
const lineCount = patch.lines?.length ?? 0;
|
|
1262
1563
|
if (lineCount === 0) break;
|
|
1564
|
+
const prefixMatches = parent.children.every((childId, index) => childId === expectedCodeLineId(parent.id, index));
|
|
1565
|
+
const isStrictTailAppend = requestedStartIndex === parent.children.length;
|
|
1566
|
+
if (!isStrictTailAppend || !prefixMatches) {
|
|
1567
|
+
debugCounters.appendLineGuardRejected += 1;
|
|
1568
|
+
appendDiagnostic(
|
|
1569
|
+
`appendLines guard rejected:${parent.id}:requestedStart=${requestedStartIndex}:childCount=${parent.children.length}:prefixMatches=${prefixMatches}`
|
|
1570
|
+
);
|
|
1571
|
+
break;
|
|
1572
|
+
}
|
|
1263
1573
|
const originalChildren = parent.children.slice();
|
|
1264
1574
|
const insertedIds = [];
|
|
1265
1575
|
const insertedSet = /* @__PURE__ */ new Set();
|
|
1266
|
-
const isTrailingAppend =
|
|
1576
|
+
const isTrailingAppend = true;
|
|
1267
1577
|
let parentChildrenChanged = false;
|
|
1268
1578
|
let codeLinesMutated = false;
|
|
1269
1579
|
for (let offset = 0; offset < lineCount; offset++) {
|
|
@@ -1305,7 +1615,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1305
1615
|
parentId: parent.id,
|
|
1306
1616
|
children: [],
|
|
1307
1617
|
props: nextLineProps,
|
|
1308
|
-
version: 0
|
|
1618
|
+
version: 0,
|
|
1619
|
+
blockEpoch: parent.blockEpoch
|
|
1309
1620
|
};
|
|
1310
1621
|
nodes.set(lineId, record);
|
|
1311
1622
|
touched.add(lineId);
|
|
@@ -1355,6 +1666,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1355
1666
|
break;
|
|
1356
1667
|
}
|
|
1357
1668
|
case "setHTML": {
|
|
1669
|
+
if (rejectStaleEpochPatch(patch, patch.at)) break;
|
|
1358
1670
|
const target = nodes.get(patch.at.nodeId ?? patch.at.blockId);
|
|
1359
1671
|
if (!target) break;
|
|
1360
1672
|
const sanitized = patch.sanitized ? patch.html : (0, import_core2.sanitizeHTML)(patch.html);
|
|
@@ -1397,6 +1709,30 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1397
1709
|
applyPatch(patch);
|
|
1398
1710
|
}
|
|
1399
1711
|
}
|
|
1712
|
+
const finalizedTableRoots = /* @__PURE__ */ new Set();
|
|
1713
|
+
for (const touchedId of touched) {
|
|
1714
|
+
let cursor = nodes.get(touchedId);
|
|
1715
|
+
while (cursor && cursor.id !== import_core2.PATCH_ROOT_ID) {
|
|
1716
|
+
if (cursor.type === "table" && cursor.block?.isFinalized && cursor.parentId) {
|
|
1717
|
+
finalizedTableRoots.add(cursor.id);
|
|
1718
|
+
break;
|
|
1719
|
+
}
|
|
1720
|
+
cursor = cursor.parentId ? nodes.get(cursor.parentId) : void 0;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
if (finalizedTableRoots.size > 0) {
|
|
1724
|
+
for (const tableId of finalizedTableRoots) {
|
|
1725
|
+
const tableNode = nodes.get(tableId);
|
|
1726
|
+
if (!tableNode || !tableNode.block || !tableNode.parentId) continue;
|
|
1727
|
+
const parent = nodes.get(tableNode.parentId);
|
|
1728
|
+
if (!parent) continue;
|
|
1729
|
+
const index = parent.children.indexOf(tableNode.id);
|
|
1730
|
+
if (index === -1) continue;
|
|
1731
|
+
const snapshot = (0, import_core2.createBlockSnapshot)((0, import_core2.cloneBlock)(tableNode.block));
|
|
1732
|
+
replaceSnapshotAt(nodes, parent, index, snapshot, touched, tableNode.blockEpoch);
|
|
1733
|
+
mutatedBlocks = true;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1400
1736
|
if (mutatedBlocks) {
|
|
1401
1737
|
blocksDirty = true;
|
|
1402
1738
|
}
|
|
@@ -1417,6 +1753,8 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1417
1753
|
normalizeListDepthsForIds(nodes, touched, listDepthDirtyNodes, import_core2.PATCH_ROOT_ID);
|
|
1418
1754
|
}
|
|
1419
1755
|
}
|
|
1756
|
+
invariantViolations = [...collectStoreInvariantViolations(nodes), ...transientDiagnostics];
|
|
1757
|
+
debugCounters.storeInvariantViolationCount += invariantViolations.length;
|
|
1420
1758
|
if (touched.size > 0 || mutatedBlocks) {
|
|
1421
1759
|
version++;
|
|
1422
1760
|
scheduleNotify();
|
|
@@ -1465,6 +1803,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1465
1803
|
if (!record) {
|
|
1466
1804
|
return EMPTY_NODE_SNAPSHOT;
|
|
1467
1805
|
}
|
|
1806
|
+
const nodeSnapshotCache = getNodeSnapshotCacheForMap(nodes);
|
|
1468
1807
|
const cached = nodeSnapshotCache.get(id);
|
|
1469
1808
|
if (cached && cached.version === record.version && cached.node === record) {
|
|
1470
1809
|
return cached;
|
|
@@ -1484,6 +1823,7 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1484
1823
|
if (!record) {
|
|
1485
1824
|
return EMPTY_CHILDREN_SNAPSHOT;
|
|
1486
1825
|
}
|
|
1826
|
+
const childrenSnapshotCache = getChildrenSnapshotCacheForMap(nodes);
|
|
1487
1827
|
const cached = childrenSnapshotCache.get(id);
|
|
1488
1828
|
if (cached && cached.version === record.version) {
|
|
1489
1829
|
return cached;
|
|
@@ -1493,6 +1833,12 @@ function createRendererStore(initialBlocks = []) {
|
|
|
1493
1833
|
pruneCache(childrenSnapshotCache, CHILDREN_SNAPSHOT_CACHE_LIMIT, CHILDREN_SNAPSHOT_CACHE_BUFFER);
|
|
1494
1834
|
return snapshot;
|
|
1495
1835
|
},
|
|
1836
|
+
getInvariantViolations() {
|
|
1837
|
+
return invariantViolations.slice();
|
|
1838
|
+
},
|
|
1839
|
+
getDebugCounters() {
|
|
1840
|
+
return { ...debugCounters };
|
|
1841
|
+
},
|
|
1496
1842
|
getLastCoalescingMetrics() {
|
|
1497
1843
|
return lastCoalescingMetrics;
|
|
1498
1844
|
},
|