Skip to content

Commit 5784d31

Browse files
committed
fix: a few potential errors
1 parent 54c296a commit 5784d31

File tree

4 files changed

+77
-175
lines changed

4 files changed

+77
-175
lines changed

packages/core/src/core/mirror.ts

Lines changed: 53 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
isValueOfContainerType,
3939
schemaToContainerType,
4040
tryInferContainerType,
41+
getRootContainerByType,
4142
} from "./utils";
4243
import { diffContainer } from "./diff";
4344

@@ -264,7 +265,8 @@ export class Mirror<S extends SchemaType> {
264265
if (!containerType) {
265266
continue;
266267
}
267-
const container = this.getRootContainerByType(
268+
const container = getRootContainerByType(
269+
this.doc,
268270
key,
269271
containerType,
270272
);
@@ -283,15 +285,28 @@ export class Mirror<S extends SchemaType> {
283285
schemaType: ContainerSchemaType | undefined,
284286
) {
285287
try {
286-
let container: Container;
287-
container = this.doc.getContainerById(containerID)!;
288+
const container = this.doc.getContainerById(containerID);
288289

289290
if (!container) {
291+
if (this.options.debug) {
292+
console.warn(
293+
`registerContainer: container not found for id ${containerID}`,
294+
);
295+
}
290296
return;
291297
}
292298

293299
const containerId = container.id;
294300

301+
// If already registered, optionally upgrade schema, then skip deep re-scan
302+
const existing = this.containerRegistry.get(containerId);
303+
if (existing) {
304+
if (!existing.schema && schemaType) {
305+
existing.schema = schemaType;
306+
}
307+
return;
308+
}
309+
295310
this.registerContainerWithRegistry(containerId, schemaType);
296311

297312
// Register nested containers
@@ -310,89 +325,48 @@ export class Mirror<S extends SchemaType> {
310325
* Register nested containers within a container
311326
*/
312327
private registerNestedContainers(container: Container) {
313-
// Skip if not attached or has no getShallowValue
314-
if (!container.isAttached || !("getShallowValue" in container)) {
315-
return;
316-
}
328+
if (!container.isAttached) return;
317329

318-
let parentSchema = this.getContainerSchema(container.id);
330+
const parentSchema = this.getContainerSchema(container.id);
319331

320332
try {
321-
const shallowValue = (
322-
container as Container & { getShallowValue: () => unknown }
323-
).getShallowValue();
324-
// Debug: shallow value of container structure
325-
if (this.options.debug) {
326-
console.log(
327-
"shallow value",
328-
JSON.stringify(shallowValue, null, 2),
329-
);
330-
}
331-
332333
if (container.kind() === "Map") {
333-
// For maps, check each value
334-
if (typeof shallowValue !== "object" || shallowValue === null) {
335-
return;
336-
}
337-
for (const [key, value] of Object.entries(
338-
shallowValue as Record<string, unknown>,
339-
)) {
340-
if (typeof value === "string" && value.startsWith("cid:")) {
341-
// This is a container reference
342-
const nestedContainer = this.doc.getContainerById(
343-
value as ContainerID,
344-
);
334+
const map = container as LoroMap;
335+
for (const key of map.keys()) {
336+
const value = map.get(key);
337+
if (isContainer(value)) {
345338
let nestedSchema: ContainerSchemaType | undefined;
346-
347339
if (parentSchema && isLoroMapSchema(parentSchema)) {
348340
nestedSchema = parentSchema.definition[
349341
key
350342
] as ContainerSchemaType;
351343
}
352-
353-
if (nestedContainer) {
354-
this.registerContainer(
355-
value as ContainerID,
356-
nestedSchema,
357-
);
358-
}
344+
this.registerContainer(value.id, nestedSchema);
359345
}
360346
}
361347
} else if (
362348
container.kind() === "List" ||
363349
container.kind() === "MovableList"
364350
) {
365-
// For lists, check each item
366-
if (!Array.isArray(shallowValue)) {
367-
return;
368-
}
369-
shallowValue.forEach((value: unknown) => {
370-
if (typeof value === "string" && value.startsWith("cid:")) {
371-
// This is a container reference
372-
const nestedContainer = this.doc.getContainerById(
373-
value as ContainerID,
374-
);
375-
351+
const list = container as LoroList | LoroMovableList;
352+
const len = list.length;
353+
for (let i = 0; i < len; i++) {
354+
const value = list.get(i);
355+
if (isContainer(value)) {
376356
let nestedSchema: ContainerSchemaType | undefined;
377-
378357
if (
379358
parentSchema &&
380359
(isLoroListSchema(parentSchema) ||
381360
isLoroMovableListSchema(parentSchema))
382361
) {
383-
// For list items, we need to use the itemSchema, not the parent list schema
384362
nestedSchema =
385363
parentSchema.itemSchema as ContainerSchemaType;
386364
}
387-
388-
if (nestedContainer) {
389-
this.registerContainer(
390-
value as ContainerID,
391-
nestedSchema,
392-
);
365+
if (nestedSchema) {
366+
this.registerContainer(value.id, nestedSchema);
393367
}
394368
}
395-
});
369+
}
396370
}
397371
} catch (error) {
398372
if (this.options.debug) {
@@ -722,20 +696,15 @@ export class Mirror<S extends SchemaType> {
722696
container.id,
723697
key,
724698
);
725-
const [detachedContainer, containerType] =
699+
const [detachedContainer, _containerType] =
726700
this.createContainerFromSchema(schema, value);
727701
let newContainer = list.setContainer(
728702
index,
729703
detachedContainer,
730704
);
731705

732706
this.registerContainer(newContainer.id, schema);
733-
this.initializeContainer(
734-
newContainer,
735-
containerType,
736-
schema,
737-
value,
738-
);
707+
this.initializeContainer(newContainer, schema, value);
739708
} else {
740709
throw new Error();
741710
}
@@ -1118,7 +1087,7 @@ export class Mirror<S extends SchemaType> {
11181087
key: string,
11191088
value: unknown,
11201089
) {
1121-
const [detachedContainer, containerType] =
1090+
const [detachedContainer, _containerType] =
11221091
this.createContainerFromSchema(schema, value);
11231092
let insertedContainer = map.setContainer(key, detachedContainer);
11241093

@@ -1128,12 +1097,7 @@ export class Mirror<S extends SchemaType> {
11281097

11291098
this.registerContainer(insertedContainer.id, schema);
11301099

1131-
this.initializeContainer(
1132-
insertedContainer,
1133-
containerType,
1134-
schema,
1135-
value,
1136-
);
1100+
this.initializeContainer(insertedContainer, schema, value);
11371101
}
11381102

11391103
/**
@@ -1143,51 +1107,37 @@ export class Mirror<S extends SchemaType> {
11431107
*/
11441108
private initializeContainer(
11451109
container: Container,
1146-
containerType: ContainerType,
11471110
schema: ContainerSchemaType | undefined,
11481111
value: unknown,
11491112
) {
1150-
if (containerType === "Map") {
1151-
let map = container as LoroMap;
1152-
1153-
// Map has no inner values
1113+
const kind = container.kind();
1114+
if (kind === "Map") {
1115+
const map = container as LoroMap;
11541116
if (!isObject(value)) {
1155-
return map;
1117+
return;
11561118
}
1157-
1158-
// Populate the map with values
11591119
for (const [key, val] of Object.entries(value)) {
11601120
const fieldSchema = (
11611121
schema as
11621122
| LoroMapSchema<Record<string, SchemaType>>
11631123
| undefined
11641124
)?.definition[key];
11651125

1166-
const isFieldContainer = isContainerSchema(fieldSchema);
1167-
1168-
if (isFieldContainer) {
1126+
if (isContainerSchema(fieldSchema)) {
11691127
const ct = schemaToContainerType(fieldSchema);
11701128
if (ct && isValueOfContainerType(ct, val)) {
11711129
this.insertContainerIntoMap(map, fieldSchema, key, val);
11721130
} else {
1173-
// Default to simple set
11741131
map.set(key, val);
11751132
}
11761133
} else {
1177-
// Default to simple set
11781134
map.set(key, val);
11791135
}
11801136
}
1181-
1182-
return map;
1183-
} else if (
1184-
containerType === "List" ||
1185-
containerType === "MovableList"
1186-
) {
1187-
// Generate a unique ID for the list
1188-
const list = container as LoroList;
1137+
} else if (kind === "List" || kind === "MovableList") {
1138+
const list = container as LoroList | LoroMovableList;
11891139
if (!Array.isArray(value)) {
1190-
return list;
1140+
return;
11911141
}
11921142

11931143
const itemSchema = (
@@ -1204,28 +1154,19 @@ export class Mirror<S extends SchemaType> {
12041154
if (ct && isValueOfContainerType(ct, item)) {
12051155
this.insertContainerIntoList(list, itemSchema, i, item);
12061156
} else {
1207-
// Default to simple insert
12081157
list.insert(i, item);
12091158
}
12101159
} else {
1211-
// Default to simple insert
12121160
list.insert(i, item);
12131161
}
12141162
}
1215-
1216-
return list;
1217-
} else if (containerType === "Text") {
1218-
// Generate a unique ID for the text
1163+
} else if (kind === "Text") {
12191164
const text = container as LoroText;
1220-
1221-
// Set the text content
12221165
if (typeof value === "string") {
12231166
text.update(value);
12241167
}
1225-
1226-
return text;
12271168
} else {
1228-
throw new Error(`Unknown schema type: ${containerType}`);
1169+
throw new Error(`Unknown container kind: ${kind}`);
12291170
}
12301171
}
12311172

@@ -1267,7 +1208,7 @@ export class Mirror<S extends SchemaType> {
12671208
index: number,
12681209
value: unknown,
12691210
) {
1270-
const [detachedContainer, containerType] =
1211+
const [detachedContainer, _containerType] =
12711212
this.createContainerFromSchema(schema, value);
12721213
let insertedContainer: Container | undefined;
12731214

@@ -1283,29 +1224,7 @@ export class Mirror<S extends SchemaType> {
12831224

12841225
this.registerContainer(insertedContainer.id, schema);
12851226

1286-
this.initializeContainer(
1287-
insertedContainer,
1288-
containerType,
1289-
schema,
1290-
value,
1291-
);
1292-
}
1293-
1294-
private getRootContainerByType(
1295-
key: string,
1296-
type: ContainerType,
1297-
): Container {
1298-
if (type === "Text") {
1299-
return this.doc.getText(key);
1300-
} else if (type === "List") {
1301-
return this.doc.getList(key);
1302-
} else if (type === "MovableList") {
1303-
return this.doc.getMovableList(key);
1304-
} else if (type === "Map") {
1305-
return this.doc.getMap(key);
1306-
} else {
1307-
throw new Error();
1308-
}
1227+
this.initializeContainer(insertedContainer, schema, value);
13091228
}
13101229

13111230
/**
@@ -1353,18 +1272,11 @@ export class Mirror<S extends SchemaType> {
13531272
// Check if this field should be a container according to schema
13541273
if (schema && schema.type === "loro-map" && schema.definition) {
13551274
const fieldSchema = schema.definition[key];
1356-
if (fieldSchema) {
1357-
const isContainer =
1358-
fieldSchema.type === "loro-map" ||
1359-
fieldSchema.type === "loro-list" ||
1360-
fieldSchema.type === "loro-text";
1361-
1362-
if (
1363-
isContainer &&
1364-
typeof value === "object" &&
1365-
value !== null
1366-
) {
1275+
if (fieldSchema && isContainerSchema(fieldSchema)) {
1276+
const ct = schemaToContainerType(fieldSchema);
1277+
if (ct && isValueOfContainerType(ct, value)) {
13671278
this.insertContainerIntoMap(map, fieldSchema, key, value);
1279+
return; // Avoid overwriting the inserted container
13681280
}
13691281
}
13701282
}

packages/core/src/core/utils.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -244,26 +244,7 @@ export function tryUpdateToContainer(
244244
}
245245

246246
change.kind = containerOp;
247-
switch (containerType) {
248-
case "Map":
249-
change.childContainerType = "Map";
250-
break;
251-
case "List":
252-
change.childContainerType = "List";
253-
break;
254-
case "Text":
255-
change.childContainerType = "Text";
256-
break;
257-
case "Counter":
258-
change.childContainerType = "Counter";
259-
break;
260-
case "Tree":
261-
change.childContainerType = "Tree";
262-
break;
263-
default:
264-
throw new Error();
265-
}
266-
247+
change.childContainerType = containerType;
267248
return change;
268249
}
269250

0 commit comments

Comments
 (0)