@loro-extended/change 0.7.0 → 0.8.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/README.md +26 -31
- package/dist/index.d.ts +86 -54
- package/dist/index.js +723 -400
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/change.test.ts +97 -403
- package/src/derive-placeholder.test.ts +245 -0
- package/src/derive-placeholder.ts +132 -0
- package/src/discriminated-union.test.ts +5 -9
- package/src/draft-nodes/base.ts +9 -4
- package/src/draft-nodes/counter.md +31 -0
- package/src/draft-nodes/counter.test.ts +53 -0
- package/src/draft-nodes/doc.ts +27 -6
- package/src/draft-nodes/list-base.ts +24 -3
- package/src/draft-nodes/list.test.ts +43 -0
- package/src/draft-nodes/list.ts +3 -0
- package/src/draft-nodes/map.ts +57 -16
- package/src/draft-nodes/movable-list.test.ts +27 -0
- package/src/draft-nodes/movable-list.ts +5 -0
- package/src/draft-nodes/proxy-handlers.ts +87 -0
- package/src/{record.test.ts → draft-nodes/record.test.ts} +98 -18
- package/src/draft-nodes/record.ts +42 -80
- package/src/draft-nodes/utils.ts +46 -5
- package/src/equality.test.ts +19 -0
- package/src/index.ts +12 -6
- package/src/json-patch.test.ts +33 -167
- package/src/overlay.ts +45 -44
- package/src/readonly.test.ts +92 -0
- package/src/shape.ts +132 -77
- package/src/{change.ts → typed-doc.ts} +50 -28
- package/src/types.test.ts +26 -7
- package/src/types.ts +7 -7
- package/src/validation.ts +12 -12
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ import { TypedDoc, Shape } from "@loro-extended/change";
|
|
|
32
32
|
|
|
33
33
|
// Define your document schema
|
|
34
34
|
const schema = Shape.doc({
|
|
35
|
-
title: Shape.text(),
|
|
35
|
+
title: Shape.text().placeholder("My Todo List"),
|
|
36
36
|
todos: Shape.list(
|
|
37
37
|
Shape.plain.object({
|
|
38
38
|
id: Shape.plain.string(),
|
|
@@ -42,14 +42,8 @@ const schema = Shape.doc({
|
|
|
42
42
|
),
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
// Define empty state (default values)
|
|
46
|
-
const emptyState = {
|
|
47
|
-
title: "My Todo List",
|
|
48
|
-
todos: [],
|
|
49
|
-
};
|
|
50
|
-
|
|
51
45
|
// Create a typed document
|
|
52
|
-
const doc = new TypedDoc(schema
|
|
46
|
+
const doc = new TypedDoc(schema);
|
|
53
47
|
|
|
54
48
|
// Make changes with natural syntax
|
|
55
49
|
const result = doc.change((draft) => {
|
|
@@ -109,19 +103,26 @@ const blogSchema = Shape.doc({
|
|
|
109
103
|
Empty state provides default values that are merged when CRDT containers are empty, keeping the whole document typesafe:
|
|
110
104
|
|
|
111
105
|
```typescript
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
106
|
+
// Use .placeholder() to set default values
|
|
107
|
+
const blogSchemaWithDefaults = Shape.doc({
|
|
108
|
+
title: Shape.text().placeholder("Untitled Document"),
|
|
109
|
+
viewCount: Shape.counter(), // defaults to 0
|
|
110
|
+
tags: Shape.list(Shape.plain.string()), // defaults to []
|
|
111
|
+
metadata: Shape.map({
|
|
112
|
+
author: Shape.plain.string().placeholder("Anonymous"),
|
|
113
|
+
publishedAt: Shape.plain.string(), // defaults to ""
|
|
114
|
+
featured: Shape.plain.boolean(), // defaults to false
|
|
115
|
+
}),
|
|
116
|
+
sections: Shape.movableList(
|
|
117
|
+
Shape.map({
|
|
118
|
+
heading: Shape.text(),
|
|
119
|
+
content: Shape.text(),
|
|
120
|
+
order: Shape.plain.number(),
|
|
121
|
+
})
|
|
122
|
+
),
|
|
123
|
+
});
|
|
123
124
|
|
|
124
|
-
const doc = new TypedDoc(
|
|
125
|
+
const doc = new TypedDoc(blogSchemaWithDefaults);
|
|
125
126
|
|
|
126
127
|
// Initially returns empty state
|
|
127
128
|
console.log(doc.value);
|
|
@@ -351,13 +352,13 @@ doc.change((draft) => {
|
|
|
351
352
|
|
|
352
353
|
### Core Functions
|
|
353
354
|
|
|
354
|
-
#### `new TypedDoc<T>(schema,
|
|
355
|
+
#### `new TypedDoc<T>(schema, existingDoc?)`
|
|
355
356
|
|
|
356
357
|
Creates a new typed Loro document.
|
|
357
358
|
|
|
358
359
|
```typescript
|
|
359
|
-
const doc = new TypedDoc(schema
|
|
360
|
-
const docFromExisting = new TypedDoc(schema,
|
|
360
|
+
const doc = new TypedDoc(schema);
|
|
361
|
+
const docFromExisting = new TypedDoc(schema, existingLoroDoc);
|
|
361
362
|
```
|
|
362
363
|
|
|
363
364
|
#### `doc.change(mutator)`
|
|
@@ -571,14 +572,8 @@ const todoSchema = Shape.doc({
|
|
|
571
572
|
),
|
|
572
573
|
});
|
|
573
574
|
|
|
574
|
-
// Define empty state that matches your interface
|
|
575
|
-
const emptyState: TodoDoc = {
|
|
576
|
-
title: "My Todos",
|
|
577
|
-
todos: [],
|
|
578
|
-
};
|
|
579
|
-
|
|
580
575
|
// TypeScript will ensure the schema produces the correct type
|
|
581
|
-
const doc = new TypedDoc(todoSchema
|
|
576
|
+
const doc = new TypedDoc(todoSchema);
|
|
582
577
|
|
|
583
578
|
// The result will be properly typed as TodoDoc
|
|
584
579
|
const result: TodoDoc = doc.change((draft) => {
|
|
@@ -610,7 +605,7 @@ import { LoroDoc } from "loro-crdt";
|
|
|
610
605
|
|
|
611
606
|
// Wrap existing LoroDoc
|
|
612
607
|
const existingDoc = new LoroDoc();
|
|
613
|
-
const typedDoc = new TypedDoc(schema,
|
|
608
|
+
const typedDoc = new TypedDoc(schema, existingDoc);
|
|
614
609
|
|
|
615
610
|
// Access underlying LoroDoc
|
|
616
611
|
const loroDoc = typedDoc.loroDoc;
|
package/dist/index.d.ts
CHANGED
|
@@ -30,21 +30,24 @@ import { LoroList, LoroMovableList, Container, LoroMap, Value, LoroText, LoroCou
|
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
32
|
type Infer<T> = T extends Shape<infer P, any, any> ? P : never;
|
|
33
|
-
type InferPlainType<T> = T extends Shape<infer P, any, any> ? P : never;
|
|
34
33
|
type InferDraftType<T> = T extends Shape<any, infer D, any> ? D : never;
|
|
35
34
|
/**
|
|
36
|
-
* Extracts the valid
|
|
35
|
+
* Extracts the valid placeholder type from a shape.
|
|
37
36
|
*
|
|
38
37
|
* For dynamic containers (list, record, etc.), this will be constrained to
|
|
39
38
|
* empty values ([] or {}) to prevent users from expecting per-entry merging.
|
|
40
39
|
*/
|
|
41
|
-
type
|
|
40
|
+
type InferPlaceholderType<T> = T extends Shape<any, any, infer P> ? P : never;
|
|
42
41
|
type Draft<T extends DocShape<Record<string, ContainerShape>>> = InferDraftType<T>;
|
|
42
|
+
type DeepReadonly<T> = {
|
|
43
|
+
readonly [P in keyof T]: DeepReadonly<T[P]>;
|
|
44
|
+
};
|
|
43
45
|
|
|
44
46
|
type DraftNodeParams<Shape extends DocShape | ContainerShape> = {
|
|
45
47
|
shape: Shape;
|
|
46
|
-
|
|
48
|
+
placeholder?: Infer<Shape>;
|
|
47
49
|
getContainer: () => ShapeToContainer<Shape>;
|
|
50
|
+
readonly?: boolean;
|
|
48
51
|
};
|
|
49
52
|
declare abstract class DraftNode<Shape extends DocShape | ContainerShape> {
|
|
50
53
|
protected _params: DraftNodeParams<Shape>;
|
|
@@ -52,7 +55,8 @@ declare abstract class DraftNode<Shape extends DocShape | ContainerShape> {
|
|
|
52
55
|
constructor(_params: DraftNodeParams<Shape>);
|
|
53
56
|
abstract absorbPlainValues(): void;
|
|
54
57
|
protected get shape(): Shape;
|
|
55
|
-
protected get
|
|
58
|
+
protected get placeholder(): Infer<Shape> | undefined;
|
|
59
|
+
protected get readonly(): boolean;
|
|
56
60
|
protected get container(): ShapeToContainer<Shape>;
|
|
57
61
|
}
|
|
58
62
|
|
|
@@ -73,7 +77,7 @@ declare abstract class ListDraftNodeBase<NestedShape extends ContainerOrValueSha
|
|
|
73
77
|
protected pushWithConversion(item: Item): void;
|
|
74
78
|
getDraftNodeParams(index: number, shape: ContainerShape): DraftNodeParams<ContainerShape>;
|
|
75
79
|
protected getPredicateItem(index: number): Item;
|
|
76
|
-
protected getDraftItem(index: number):
|
|
80
|
+
protected getDraftItem(index: number): any;
|
|
77
81
|
find(predicate: (item: Item, index: number) => boolean): DraftItem | undefined;
|
|
78
82
|
findIndex(predicate: (item: Item, index: number) => boolean): number;
|
|
79
83
|
map<ReturnType>(callback: (item: Item, index: number) => ReturnType): ReturnType[];
|
|
@@ -94,6 +98,7 @@ declare abstract class ListDraftNodeBase<NestedShape extends ContainerOrValueSha
|
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
declare class ListDraftNode<NestedShape extends ContainerOrValueShape> extends ListDraftNodeBase<NestedShape> {
|
|
101
|
+
[index: number]: Infer<NestedShape>;
|
|
97
102
|
protected get container(): LoroList;
|
|
98
103
|
protected absorbValueAtIndex(index: number, value: any): void;
|
|
99
104
|
}
|
|
@@ -105,7 +110,7 @@ declare class MapDraftNode<NestedShapes extends Record<string, ContainerOrValueS
|
|
|
105
110
|
protected get container(): LoroMap;
|
|
106
111
|
absorbPlainValues(): void;
|
|
107
112
|
getDraftNodeParams<S extends ContainerShape>(key: string, shape: S): DraftNodeParams<ContainerShape>;
|
|
108
|
-
getOrCreateNode<Shape extends ContainerShape | ValueShape>(key: string, shape: Shape):
|
|
113
|
+
getOrCreateNode<Shape extends ContainerShape | ValueShape>(key: string, shape: Shape): any;
|
|
109
114
|
private createLazyProperties;
|
|
110
115
|
get(key: string): any;
|
|
111
116
|
set(key: string, value: Value): void;
|
|
@@ -118,6 +123,7 @@ declare class MapDraftNode<NestedShapes extends Record<string, ContainerOrValueS
|
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
declare class MovableListDraftNode<NestedShape extends ContainerOrValueShape, Item = NestedShape["_plain"]> extends ListDraftNodeBase<NestedShape> {
|
|
126
|
+
[index: number]: Infer<NestedShape>;
|
|
121
127
|
protected get container(): LoroMovableList;
|
|
122
128
|
protected absorbValueAtIndex(index: number, value: any): void;
|
|
123
129
|
move(from: number, to: number): void;
|
|
@@ -125,13 +131,13 @@ declare class MovableListDraftNode<NestedShape extends ContainerOrValueShape, It
|
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
declare class RecordDraftNode<NestedShape extends ContainerOrValueShape> extends DraftNode<any> {
|
|
134
|
+
[key: string]: Infer<NestedShape> | any;
|
|
128
135
|
private nodeCache;
|
|
129
|
-
constructor(params: DraftNodeParams<RecordContainerShape<NestedShape>>);
|
|
130
136
|
protected get shape(): RecordContainerShape<NestedShape>;
|
|
131
137
|
protected get container(): LoroMap;
|
|
132
138
|
absorbPlainValues(): void;
|
|
133
139
|
getDraftNodeParams<S extends ContainerShape>(key: string, shape: S): DraftNodeParams<ContainerShape>;
|
|
134
|
-
getOrCreateNode(key: string):
|
|
140
|
+
getOrCreateNode(key: string): any;
|
|
135
141
|
get(key: string): InferDraftType<NestedShape>;
|
|
136
142
|
set(key: string, value: any): void;
|
|
137
143
|
setContainer<C extends Container>(key: string, container: C): C;
|
|
@@ -161,12 +167,15 @@ declare class TextDraftNode extends DraftNode<TextContainerShape> {
|
|
|
161
167
|
get length(): number;
|
|
162
168
|
}
|
|
163
169
|
|
|
170
|
+
type WithPlaceholder<S extends Shape<any, any, any>> = S & {
|
|
171
|
+
placeholder(value: S["_placeholder"]): S;
|
|
172
|
+
};
|
|
164
173
|
interface DocShape<NestedShapes extends Record<string, ContainerShape> = Record<string, ContainerShape>> extends Shape<{
|
|
165
174
|
[K in keyof NestedShapes]: NestedShapes[K]["_plain"];
|
|
166
175
|
}, {
|
|
167
176
|
[K in keyof NestedShapes]: NestedShapes[K]["_draft"];
|
|
168
177
|
}, {
|
|
169
|
-
[K in keyof NestedShapes]: NestedShapes[K]["
|
|
178
|
+
[K in keyof NestedShapes]: NestedShapes[K]["_placeholder"];
|
|
170
179
|
}> {
|
|
171
180
|
readonly _type: "doc";
|
|
172
181
|
readonly shapes: NestedShapes;
|
|
@@ -194,7 +203,7 @@ interface MapContainerShape<NestedShapes extends Record<string, ContainerOrValue
|
|
|
194
203
|
}, MapDraftNode<NestedShapes> & {
|
|
195
204
|
[K in keyof NestedShapes]: NestedShapes[K]["_draft"];
|
|
196
205
|
}, {
|
|
197
|
-
[K in keyof NestedShapes]: NestedShapes[K]["
|
|
206
|
+
[K in keyof NestedShapes]: NestedShapes[K]["_placeholder"];
|
|
198
207
|
}> {
|
|
199
208
|
readonly _type: "map";
|
|
200
209
|
readonly shapes: NestedShapes;
|
|
@@ -235,7 +244,7 @@ interface ObjectValueShape<T extends Record<string, ValueShape> = Record<string,
|
|
|
235
244
|
}, {
|
|
236
245
|
[K in keyof T]: T[K]["_draft"];
|
|
237
246
|
}, {
|
|
238
|
-
[K in keyof T]: T[K]["
|
|
247
|
+
[K in keyof T]: T[K]["_placeholder"];
|
|
239
248
|
}> {
|
|
240
249
|
readonly _type: "value";
|
|
241
250
|
readonly valueType: "object";
|
|
@@ -251,7 +260,7 @@ interface ArrayValueShape<T extends ValueShape = ValueShape> extends Shape<T["_p
|
|
|
251
260
|
readonly valueType: "array";
|
|
252
261
|
readonly shape: T;
|
|
253
262
|
}
|
|
254
|
-
interface UnionValueShape<T extends ValueShape[] = ValueShape[]> extends Shape<T[number]["_plain"], T[number]["_draft"], T[number]["
|
|
263
|
+
interface UnionValueShape<T extends ValueShape[] = ValueShape[]> extends Shape<T[number]["_plain"], T[number]["_draft"], T[number]["_placeholder"]> {
|
|
255
264
|
readonly _type: "value";
|
|
256
265
|
readonly valueType: "union";
|
|
257
266
|
readonly shapes: T;
|
|
@@ -269,19 +278,19 @@ interface UnionValueShape<T extends ValueShape[] = ValueShape[]> extends Shape<T
|
|
|
269
278
|
* @typeParam K - The discriminant key (e.g., "type")
|
|
270
279
|
* @typeParam T - A record mapping discriminant values to their object shapes
|
|
271
280
|
*/
|
|
272
|
-
interface DiscriminatedUnionValueShape<K extends string = string, T extends Record<string, ObjectValueShape> = Record<string, ObjectValueShape>> extends Shape<T[keyof T]["_plain"], T[keyof T]["_draft"], T[keyof T]["
|
|
281
|
+
interface DiscriminatedUnionValueShape<K extends string = string, T extends Record<string, ObjectValueShape> = Record<string, ObjectValueShape>> extends Shape<T[keyof T]["_plain"], T[keyof T]["_draft"], T[keyof T]["_placeholder"]> {
|
|
273
282
|
readonly _type: "value";
|
|
274
283
|
readonly valueType: "discriminatedUnion";
|
|
275
284
|
readonly discriminantKey: K;
|
|
276
285
|
readonly variants: T;
|
|
277
286
|
}
|
|
278
|
-
type ValueShape = StringValueShape | NumberValueShape | BooleanValueShape | NullValueShape | UndefinedValueShape | Uint8ArrayValueShape | ObjectValueShape | RecordValueShape | ArrayValueShape | UnionValueShape | DiscriminatedUnionValueShape
|
|
287
|
+
type ValueShape = StringValueShape | NumberValueShape | BooleanValueShape | NullValueShape | UndefinedValueShape | Uint8ArrayValueShape | ObjectValueShape | RecordValueShape | ArrayValueShape | UnionValueShape | DiscriminatedUnionValueShape;
|
|
279
288
|
type ContainerOrValueShape = ContainerShape | ValueShape;
|
|
280
|
-
interface Shape<Plain, Draft,
|
|
289
|
+
interface Shape<Plain, Draft, Placeholder = Plain> {
|
|
281
290
|
readonly _type: string;
|
|
282
291
|
readonly _plain: Plain;
|
|
283
292
|
readonly _draft: Draft;
|
|
284
|
-
readonly
|
|
293
|
+
readonly _placeholder: Placeholder;
|
|
285
294
|
}
|
|
286
295
|
/**
|
|
287
296
|
* The LoroShape factory object
|
|
@@ -292,24 +301,24 @@ interface Shape<Plain, Draft, EmptyState = Plain> {
|
|
|
292
301
|
*/
|
|
293
302
|
declare const Shape: {
|
|
294
303
|
doc: <T extends Record<string, ContainerShape>>(shape: T) => DocShape<T>;
|
|
295
|
-
counter: () => CounterContainerShape
|
|
304
|
+
counter: () => WithPlaceholder<CounterContainerShape>;
|
|
296
305
|
list: <T extends ContainerOrValueShape>(shape: T) => ListContainerShape<T>;
|
|
297
306
|
map: <T extends Record<string, ContainerOrValueShape>>(shape: T) => MapContainerShape<T>;
|
|
298
307
|
record: <T extends ContainerOrValueShape>(shape: T) => RecordContainerShape<T>;
|
|
299
308
|
movableList: <T extends ContainerOrValueShape>(shape: T) => MovableListContainerShape<T>;
|
|
300
|
-
text: () => TextContainerShape
|
|
309
|
+
text: () => WithPlaceholder<TextContainerShape>;
|
|
301
310
|
tree: <T extends MapContainerShape>(shape: T) => TreeContainerShape;
|
|
302
311
|
plain: {
|
|
303
|
-
string: <T extends string = string>(...options: T[]) => StringValueShape<T
|
|
304
|
-
number: () => NumberValueShape
|
|
305
|
-
boolean: () => BooleanValueShape
|
|
312
|
+
string: <T extends string = string>(...options: T[]) => WithPlaceholder<StringValueShape<T>>;
|
|
313
|
+
number: () => WithPlaceholder<NumberValueShape>;
|
|
314
|
+
boolean: () => WithPlaceholder<BooleanValueShape>;
|
|
306
315
|
null: () => NullValueShape;
|
|
307
316
|
undefined: () => UndefinedValueShape;
|
|
308
317
|
uint8Array: () => Uint8ArrayValueShape;
|
|
309
318
|
object: <T extends Record<string, ValueShape>>(shape: T) => ObjectValueShape<T>;
|
|
310
319
|
record: <T extends ValueShape>(shape: T) => RecordValueShape<T>;
|
|
311
320
|
array: <T extends ValueShape>(shape: T) => ArrayValueShape<T>;
|
|
312
|
-
union: <T extends ValueShape[]>(shapes: T) => UnionValueShape<T
|
|
321
|
+
union: <T extends ValueShape[]>(shapes: T) => WithPlaceholder<UnionValueShape<T>>;
|
|
313
322
|
/**
|
|
314
323
|
* Creates a discriminated union shape for type-safe tagged unions.
|
|
315
324
|
*
|
|
@@ -336,11 +345,41 @@ declare const Shape: {
|
|
|
336
345
|
* @param discriminantKey - The key used to discriminate between variants (e.g., "type")
|
|
337
346
|
* @param variants - A record mapping discriminant values to their object shapes
|
|
338
347
|
*/
|
|
339
|
-
discriminatedUnion: <K extends string, T extends Record<string, ObjectValueShape>>(discriminantKey: K, variants: T) => DiscriminatedUnionValueShape<K, T
|
|
348
|
+
discriminatedUnion: <K extends string, T extends Record<string, ObjectValueShape>>(discriminantKey: K, variants: T) => WithPlaceholder<DiscriminatedUnionValueShape<K, T>>;
|
|
340
349
|
};
|
|
341
350
|
};
|
|
342
351
|
type ShapeToContainer<T extends DocShape | ContainerShape> = T extends TextContainerShape ? LoroText : T extends CounterContainerShape ? LoroCounter : T extends ListContainerShape ? LoroList : T extends MovableListContainerShape ? LoroMovableList : T extends MapContainerShape | RecordContainerShape ? LoroMap : T extends TreeContainerShape ? LoroTree : never;
|
|
343
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Derives the placeholder state from a schema by composing placeholder values.
|
|
355
|
+
*
|
|
356
|
+
* For leaf nodes (text, counter, values): uses _placeholder directly
|
|
357
|
+
* For containers (map, list, record): recurses into nested shapes
|
|
358
|
+
*/
|
|
359
|
+
declare function derivePlaceholder<T extends DocShape>(schema: T): InferPlaceholderType<T>;
|
|
360
|
+
/**
|
|
361
|
+
* Derives placeholder for a single shape.
|
|
362
|
+
*
|
|
363
|
+
* Leaf nodes: return _placeholder directly
|
|
364
|
+
* Containers: recurse into nested shapes (ignore _placeholder on containers)
|
|
365
|
+
*/
|
|
366
|
+
declare function deriveShapePlaceholder(shape: ContainerOrValueShape): unknown;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Overlays CRDT state with placeholder defaults
|
|
370
|
+
*/
|
|
371
|
+
declare function overlayPlaceholder<Shape extends DocShape>(shape: Shape, crdtValue: {
|
|
372
|
+
[key: string]: Value;
|
|
373
|
+
}, placeholderValue: {
|
|
374
|
+
[key: string]: Value;
|
|
375
|
+
}): {
|
|
376
|
+
[key: string]: Value;
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* Merges individual CRDT values with placeholder defaults
|
|
380
|
+
*/
|
|
381
|
+
declare function mergeValue<Shape extends ContainerShape | ValueShape>(shape: Shape, crdtValue: Value, placeholderValue: Value): Value;
|
|
382
|
+
|
|
344
383
|
/** biome-ignore-all lint/suspicious/noExplicitAny: JSON Patch values can be any type */
|
|
345
384
|
|
|
346
385
|
type JsonPatchAddOperation = {
|
|
@@ -379,20 +418,28 @@ type JsonPatch = JsonPatchOperation[];
|
|
|
379
418
|
|
|
380
419
|
declare class TypedDoc<Shape extends DocShape> {
|
|
381
420
|
private shape;
|
|
382
|
-
private
|
|
421
|
+
private placeholder;
|
|
383
422
|
private doc;
|
|
384
423
|
/**
|
|
385
|
-
* Creates a new TypedDoc with the given schema
|
|
424
|
+
* Creates a new TypedDoc with the given schema.
|
|
425
|
+
* Placeholder state is automatically derived from the schema's placeholder values.
|
|
386
426
|
*
|
|
387
|
-
* @param shape - The document schema
|
|
388
|
-
* @param emptyState - Default values for the document. For dynamic containers
|
|
389
|
-
* (list, record, etc.), only empty values ([] or {}) are allowed. Use
|
|
390
|
-
* `.change()` to add initial data after construction.
|
|
427
|
+
* @param shape - The document schema (with optional .placeholder() values)
|
|
391
428
|
* @param doc - Optional existing LoroDoc to wrap
|
|
392
429
|
*/
|
|
393
|
-
constructor(shape: Shape,
|
|
394
|
-
|
|
395
|
-
|
|
430
|
+
constructor(shape: Shape, doc?: LoroDoc);
|
|
431
|
+
/**
|
|
432
|
+
* Returns a read-only, live view of the document.
|
|
433
|
+
* Accessing properties on this object will read directly from the underlying CRDT.
|
|
434
|
+
* This is efficient (O(1) per access) and always up-to-date.
|
|
435
|
+
*/
|
|
436
|
+
get value(): DeepReadonly<Infer<Shape>>;
|
|
437
|
+
/**
|
|
438
|
+
* Returns the full plain JavaScript object representation of the document.
|
|
439
|
+
* This is an expensive O(N) operation that serializes the entire document.
|
|
440
|
+
*/
|
|
441
|
+
toJSON(): Infer<Shape>;
|
|
442
|
+
change(fn: (draft: Draft<Shape>) => void): Infer<Shape>;
|
|
396
443
|
/**
|
|
397
444
|
* Apply JSON Patch operations to the document
|
|
398
445
|
*
|
|
@@ -408,32 +455,17 @@ declare class TypedDoc<Shape extends DocShape> {
|
|
|
408
455
|
* ])
|
|
409
456
|
* ```
|
|
410
457
|
*/
|
|
411
|
-
applyPatch(patch: JsonPatch, pathPrefix?: (string | number)[]):
|
|
458
|
+
applyPatch(patch: JsonPatch, pathPrefix?: (string | number)[]): Infer<Shape>;
|
|
412
459
|
get loroDoc(): LoroDoc;
|
|
413
460
|
get docShape(): Shape;
|
|
414
461
|
get rawValue(): any;
|
|
415
462
|
}
|
|
416
|
-
declare function createTypedDoc<Shape extends DocShape>(shape: Shape,
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Overlays CRDT state with empty state defaults
|
|
420
|
-
*/
|
|
421
|
-
declare function overlayEmptyState<Shape extends DocShape>(shape: Shape, crdtValue: {
|
|
422
|
-
[key: string]: Value;
|
|
423
|
-
}, emptyValue: {
|
|
424
|
-
[key: string]: Value;
|
|
425
|
-
}): {
|
|
426
|
-
[key: string]: Value;
|
|
427
|
-
};
|
|
428
|
-
/**
|
|
429
|
-
* Merges individual CRDT values with empty state defaults
|
|
430
|
-
*/
|
|
431
|
-
declare function mergeValue<Shape extends ContainerShape | ValueShape>(shape: Shape, crdtValue: Value, emptyValue: Value): Value;
|
|
463
|
+
declare function createTypedDoc<Shape extends DocShape>(shape: Shape, existingDoc?: LoroDoc): TypedDoc<Shape>;
|
|
432
464
|
|
|
433
465
|
/**
|
|
434
|
-
* Validates
|
|
435
|
-
* Combines the functionality of
|
|
466
|
+
* Validates placeholder against schema structure without using Zod
|
|
467
|
+
* Combines the functionality of createPlaceholderValidator and createValueValidator
|
|
436
468
|
*/
|
|
437
|
-
declare function
|
|
469
|
+
declare function validatePlaceholder<T extends DocShape>(placeholder: unknown, schema: T): Infer<T>;
|
|
438
470
|
|
|
439
|
-
export { type ArrayValueShape, type ContainerOrValueShape, type ContainerShape, type CounterContainerShape, type DiscriminatedUnionValueShape, type DocShape, type Draft, type Infer, type InferDraftType, type
|
|
471
|
+
export { type ArrayValueShape, type ContainerOrValueShape, type ContainerShape, type CounterContainerShape, type DeepReadonly, type DiscriminatedUnionValueShape, type DocShape, type Draft, type Infer, type InferDraftType, type InferPlaceholderType, type ListContainerShape, type MapContainerShape, type MovableListContainerShape, type ObjectValueShape, type RecordContainerShape, type RecordValueShape, type ContainerType as RootContainerType, Shape, type TextContainerShape, type TreeContainerShape, TypedDoc, type UnionValueShape, type ValueShape, type WithPlaceholder, createTypedDoc, derivePlaceholder, deriveShapePlaceholder, mergeValue, overlayPlaceholder, validatePlaceholder };
|