@@ -38,6 +38,7 @@ import {
38
38
isValueOfContainerType ,
39
39
schemaToContainerType ,
40
40
tryInferContainerType ,
41
+ getRootContainerByType ,
41
42
} from "./utils" ;
42
43
import { diffContainer } from "./diff" ;
43
44
@@ -264,7 +265,8 @@ export class Mirror<S extends SchemaType> {
264
265
if ( ! containerType ) {
265
266
continue ;
266
267
}
267
- const container = this . getRootContainerByType (
268
+ const container = getRootContainerByType (
269
+ this . doc ,
268
270
key ,
269
271
containerType ,
270
272
) ;
@@ -283,15 +285,28 @@ export class Mirror<S extends SchemaType> {
283
285
schemaType : ContainerSchemaType | undefined ,
284
286
) {
285
287
try {
286
- let container : Container ;
287
- container = this . doc . getContainerById ( containerID ) ! ;
288
+ const container = this . doc . getContainerById ( containerID ) ;
288
289
289
290
if ( ! container ) {
291
+ if ( this . options . debug ) {
292
+ console . warn (
293
+ `registerContainer: container not found for id ${ containerID } ` ,
294
+ ) ;
295
+ }
290
296
return ;
291
297
}
292
298
293
299
const containerId = container . id ;
294
300
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
+
295
310
this . registerContainerWithRegistry ( containerId , schemaType ) ;
296
311
297
312
// Register nested containers
@@ -310,89 +325,48 @@ export class Mirror<S extends SchemaType> {
310
325
* Register nested containers within a container
311
326
*/
312
327
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 ;
317
329
318
- let parentSchema = this . getContainerSchema ( container . id ) ;
330
+ const parentSchema = this . getContainerSchema ( container . id ) ;
319
331
320
332
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
-
332
333
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 ) ) {
345
338
let nestedSchema : ContainerSchemaType | undefined ;
346
-
347
339
if ( parentSchema && isLoroMapSchema ( parentSchema ) ) {
348
340
nestedSchema = parentSchema . definition [
349
341
key
350
342
] as ContainerSchemaType ;
351
343
}
352
-
353
- if ( nestedContainer ) {
354
- this . registerContainer (
355
- value as ContainerID ,
356
- nestedSchema ,
357
- ) ;
358
- }
344
+ this . registerContainer ( value . id , nestedSchema ) ;
359
345
}
360
346
}
361
347
} else if (
362
348
container . kind ( ) === "List" ||
363
349
container . kind ( ) === "MovableList"
364
350
) {
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 ) ) {
376
356
let nestedSchema : ContainerSchemaType | undefined ;
377
-
378
357
if (
379
358
parentSchema &&
380
359
( isLoroListSchema ( parentSchema ) ||
381
360
isLoroMovableListSchema ( parentSchema ) )
382
361
) {
383
- // For list items, we need to use the itemSchema, not the parent list schema
384
362
nestedSchema =
385
363
parentSchema . itemSchema as ContainerSchemaType ;
386
364
}
387
-
388
- if ( nestedContainer ) {
389
- this . registerContainer (
390
- value as ContainerID ,
391
- nestedSchema ,
392
- ) ;
365
+ if ( nestedSchema ) {
366
+ this . registerContainer ( value . id , nestedSchema ) ;
393
367
}
394
368
}
395
- } ) ;
369
+ }
396
370
}
397
371
} catch ( error ) {
398
372
if ( this . options . debug ) {
@@ -722,20 +696,15 @@ export class Mirror<S extends SchemaType> {
722
696
container . id ,
723
697
key ,
724
698
) ;
725
- const [ detachedContainer , containerType ] =
699
+ const [ detachedContainer , _containerType ] =
726
700
this . createContainerFromSchema ( schema , value ) ;
727
701
let newContainer = list . setContainer (
728
702
index ,
729
703
detachedContainer ,
730
704
) ;
731
705
732
706
this . registerContainer ( newContainer . id , schema ) ;
733
- this . initializeContainer (
734
- newContainer ,
735
- containerType ,
736
- schema ,
737
- value ,
738
- ) ;
707
+ this . initializeContainer ( newContainer , schema , value ) ;
739
708
} else {
740
709
throw new Error ( ) ;
741
710
}
@@ -1118,7 +1087,7 @@ export class Mirror<S extends SchemaType> {
1118
1087
key : string ,
1119
1088
value : unknown ,
1120
1089
) {
1121
- const [ detachedContainer , containerType ] =
1090
+ const [ detachedContainer , _containerType ] =
1122
1091
this . createContainerFromSchema ( schema , value ) ;
1123
1092
let insertedContainer = map . setContainer ( key , detachedContainer ) ;
1124
1093
@@ -1128,12 +1097,7 @@ export class Mirror<S extends SchemaType> {
1128
1097
1129
1098
this . registerContainer ( insertedContainer . id , schema ) ;
1130
1099
1131
- this . initializeContainer (
1132
- insertedContainer ,
1133
- containerType ,
1134
- schema ,
1135
- value ,
1136
- ) ;
1100
+ this . initializeContainer ( insertedContainer , schema , value ) ;
1137
1101
}
1138
1102
1139
1103
/**
@@ -1143,51 +1107,37 @@ export class Mirror<S extends SchemaType> {
1143
1107
*/
1144
1108
private initializeContainer (
1145
1109
container : Container ,
1146
- containerType : ContainerType ,
1147
1110
schema : ContainerSchemaType | undefined ,
1148
1111
value : unknown ,
1149
1112
) {
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 ;
1154
1116
if ( ! isObject ( value ) ) {
1155
- return map ;
1117
+ return ;
1156
1118
}
1157
-
1158
- // Populate the map with values
1159
1119
for ( const [ key , val ] of Object . entries ( value ) ) {
1160
1120
const fieldSchema = (
1161
1121
schema as
1162
1122
| LoroMapSchema < Record < string , SchemaType > >
1163
1123
| undefined
1164
1124
) ?. definition [ key ] ;
1165
1125
1166
- const isFieldContainer = isContainerSchema ( fieldSchema ) ;
1167
-
1168
- if ( isFieldContainer ) {
1126
+ if ( isContainerSchema ( fieldSchema ) ) {
1169
1127
const ct = schemaToContainerType ( fieldSchema ) ;
1170
1128
if ( ct && isValueOfContainerType ( ct , val ) ) {
1171
1129
this . insertContainerIntoMap ( map , fieldSchema , key , val ) ;
1172
1130
} else {
1173
- // Default to simple set
1174
1131
map . set ( key , val ) ;
1175
1132
}
1176
1133
} else {
1177
- // Default to simple set
1178
1134
map . set ( key , val ) ;
1179
1135
}
1180
1136
}
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 ;
1189
1139
if ( ! Array . isArray ( value ) ) {
1190
- return list ;
1140
+ return ;
1191
1141
}
1192
1142
1193
1143
const itemSchema = (
@@ -1204,28 +1154,19 @@ export class Mirror<S extends SchemaType> {
1204
1154
if ( ct && isValueOfContainerType ( ct , item ) ) {
1205
1155
this . insertContainerIntoList ( list , itemSchema , i , item ) ;
1206
1156
} else {
1207
- // Default to simple insert
1208
1157
list . insert ( i , item ) ;
1209
1158
}
1210
1159
} else {
1211
- // Default to simple insert
1212
1160
list . insert ( i , item ) ;
1213
1161
}
1214
1162
}
1215
-
1216
- return list ;
1217
- } else if ( containerType === "Text" ) {
1218
- // Generate a unique ID for the text
1163
+ } else if ( kind === "Text" ) {
1219
1164
const text = container as LoroText ;
1220
-
1221
- // Set the text content
1222
1165
if ( typeof value === "string" ) {
1223
1166
text . update ( value ) ;
1224
1167
}
1225
-
1226
- return text ;
1227
1168
} else {
1228
- throw new Error ( `Unknown schema type : ${ containerType } ` ) ;
1169
+ throw new Error ( `Unknown container kind : ${ kind } ` ) ;
1229
1170
}
1230
1171
}
1231
1172
@@ -1267,7 +1208,7 @@ export class Mirror<S extends SchemaType> {
1267
1208
index : number ,
1268
1209
value : unknown ,
1269
1210
) {
1270
- const [ detachedContainer , containerType ] =
1211
+ const [ detachedContainer , _containerType ] =
1271
1212
this . createContainerFromSchema ( schema , value ) ;
1272
1213
let insertedContainer : Container | undefined ;
1273
1214
@@ -1283,29 +1224,7 @@ export class Mirror<S extends SchemaType> {
1283
1224
1284
1225
this . registerContainer ( insertedContainer . id , schema ) ;
1285
1226
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 ) ;
1309
1228
}
1310
1229
1311
1230
/**
@@ -1353,18 +1272,11 @@ export class Mirror<S extends SchemaType> {
1353
1272
// Check if this field should be a container according to schema
1354
1273
if ( schema && schema . type === "loro-map" && schema . definition ) {
1355
1274
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 ) ) {
1367
1278
this . insertContainerIntoMap ( map , fieldSchema , key , value ) ;
1279
+ return ; // Avoid overwriting the inserted container
1368
1280
}
1369
1281
}
1370
1282
}
0 commit comments