@loro-extended/change 1.0.1 → 1.1.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 +40 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +92 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/change.test.ts +251 -0
- package/src/index.ts +2 -0
- package/src/shape.ts +136 -35
package/README.md
CHANGED
|
@@ -497,6 +497,46 @@ const schema = Shape.doc({
|
|
|
497
497
|
- `Shape.plain.union(shapes)` - Union of value types (e.g., `string | null`)
|
|
498
498
|
- `Shape.plain.discriminatedUnion(key, variants)` - Tagged union types with a discriminant key
|
|
499
499
|
|
|
500
|
+
#### Nullable Values
|
|
501
|
+
|
|
502
|
+
Use `.nullable()` on value types to create nullable fields with `null` as the default placeholder:
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
const schema = Shape.doc({
|
|
506
|
+
profile: Shape.struct({
|
|
507
|
+
name: Shape.plain.string().placeholder("Anonymous"),
|
|
508
|
+
email: Shape.plain.string().nullable(), // string | null, defaults to null
|
|
509
|
+
age: Shape.plain.number().nullable(), // number | null, defaults to null
|
|
510
|
+
verified: Shape.plain.boolean().nullable(), // boolean | null, defaults to null
|
|
511
|
+
tags: Shape.plain.array(Shape.plain.string()).nullable(), // string[] | null
|
|
512
|
+
metadata: Shape.plain.record(Shape.plain.string()).nullable(), // Record<string, string> | null
|
|
513
|
+
location: Shape.plain.struct({ // { lat: number, lng: number } | null
|
|
514
|
+
lat: Shape.plain.number(),
|
|
515
|
+
lng: Shape.plain.number(),
|
|
516
|
+
}).nullable(),
|
|
517
|
+
}),
|
|
518
|
+
});
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
You can chain `.placeholder()` after `.nullable()` to customize the default value:
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
const schema = Shape.doc({
|
|
525
|
+
settings: Shape.struct({
|
|
526
|
+
// Nullable string with custom default
|
|
527
|
+
nickname: Shape.plain.string().nullable().placeholder("Guest"),
|
|
528
|
+
}),
|
|
529
|
+
});
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
This is syntactic sugar for the more verbose union pattern:
|
|
533
|
+
|
|
534
|
+
```typescript
|
|
535
|
+
// These are equivalent:
|
|
536
|
+
email: Shape.plain.string().nullable()
|
|
537
|
+
email: Shape.plain.union([Shape.plain.null(), Shape.plain.string()]).placeholder(null)
|
|
538
|
+
```
|
|
539
|
+
|
|
500
540
|
### TypedDoc API
|
|
501
541
|
|
|
502
542
|
With the proxy-based API, schema properties are accessed directly on the doc object, and meta-operations are accessed via the `$` namespace.
|
package/dist/index.d.ts
CHANGED
|
@@ -229,6 +229,13 @@ declare class TextRef extends TypedRef<TextContainerShape> {
|
|
|
229
229
|
type WithPlaceholder<S extends Shape<any, any, any>> = S & {
|
|
230
230
|
placeholder(value: S["_placeholder"]): S;
|
|
231
231
|
};
|
|
232
|
+
/**
|
|
233
|
+
* Type for value shapes that support the .nullable() method.
|
|
234
|
+
* Returns a union of null and the original shape with null as the default placeholder.
|
|
235
|
+
*/
|
|
236
|
+
type WithNullable<S extends ValueShape> = {
|
|
237
|
+
nullable(): WithPlaceholder<UnionValueShape<[NullValueShape, S]>>;
|
|
238
|
+
};
|
|
232
239
|
interface DocShape<NestedShapes extends Record<string, ContainerShape> = Record<string, ContainerShape>> extends Shape<{
|
|
233
240
|
[K in keyof NestedShapes]: NestedShapes[K]["_plain"];
|
|
234
241
|
}, {
|
|
@@ -404,9 +411,9 @@ declare const Shape: {
|
|
|
404
411
|
text: () => WithPlaceholder<TextContainerShape>;
|
|
405
412
|
tree: <T extends MapContainerShape | StructContainerShape>(shape: T) => TreeContainerShape;
|
|
406
413
|
plain: {
|
|
407
|
-
string: <T extends string = string>(...options: T[]) => WithPlaceholder<StringValueShape<T>>;
|
|
408
|
-
number: () => WithPlaceholder<NumberValueShape>;
|
|
409
|
-
boolean: () => WithPlaceholder<BooleanValueShape>;
|
|
414
|
+
string: <T extends string = string>(...options: T[]) => WithPlaceholder<StringValueShape<T>> & WithNullable<StringValueShape<T>>;
|
|
415
|
+
number: () => WithPlaceholder<NumberValueShape> & WithNullable<NumberValueShape>;
|
|
416
|
+
boolean: () => WithPlaceholder<BooleanValueShape> & WithNullable<BooleanValueShape>;
|
|
410
417
|
null: () => NullValueShape;
|
|
411
418
|
undefined: () => UndefinedValueShape;
|
|
412
419
|
uint8Array: () => Uint8ArrayValueShape;
|
|
@@ -422,13 +429,13 @@ declare const Shape: {
|
|
|
422
429
|
* })
|
|
423
430
|
* ```
|
|
424
431
|
*/
|
|
425
|
-
struct: <T extends Record<string, ValueShape>>(shape: T) => StructValueShape<T
|
|
432
|
+
struct: <T extends Record<string, ValueShape>>(shape: T) => StructValueShape<T> & WithNullable<StructValueShape<T>>;
|
|
426
433
|
/**
|
|
427
434
|
* @deprecated Use `Shape.plain.struct` instead. `Shape.plain.struct` will be removed in a future version.
|
|
428
435
|
*/
|
|
429
|
-
object: <T extends Record<string, ValueShape>>(shape: T) => StructValueShape<T
|
|
430
|
-
record: <T extends ValueShape>(shape: T) => RecordValueShape<T
|
|
431
|
-
array: <T extends ValueShape>(shape: T) => ArrayValueShape<T
|
|
436
|
+
object: <T extends Record<string, ValueShape>>(shape: T) => StructValueShape<T> & WithNullable<StructValueShape<T>>;
|
|
437
|
+
record: <T extends ValueShape>(shape: T) => RecordValueShape<T> & WithNullable<RecordValueShape<T>>;
|
|
438
|
+
array: <T extends ValueShape>(shape: T) => ArrayValueShape<T> & WithNullable<ArrayValueShape<T>>;
|
|
432
439
|
union: <T extends ValueShape[]>(shapes: T) => WithPlaceholder<UnionValueShape<T>>;
|
|
433
440
|
/**
|
|
434
441
|
* Creates a discriminated union shape for type-safe tagged unions.
|
|
@@ -816,4 +823,4 @@ declare class TypedPresence<S extends ContainerShape | ValueShape> {
|
|
|
816
823
|
*/
|
|
817
824
|
declare function validatePlaceholder<T extends DocShape>(placeholder: unknown, schema: T): Infer<T>;
|
|
818
825
|
|
|
819
|
-
export { type ArrayValueShape, type ContainerOrValueShape, type ContainerShape, type CounterContainerShape, type DiscriminatedUnionValueShape, type DocShape, type Infer, type InferMutableType, type InferPlaceholderType, type ListContainerShape, type MapContainerShape, type MovableListContainerShape, type Mutable, type ObjectValue, type ObjectValueShape, type PresenceInterface, type RecordContainerShape, type RecordValueShape, type ContainerType as RootContainerType, Shape, type StructContainerShape, type StructValueShape, type TextContainerShape, type TreeContainerShape, type TypedDoc, TypedPresence, type UnionValueShape, type ValueShape, type WithPlaceholder, change, createPlaceholderProxy, createTypedDoc, derivePlaceholder, deriveShapePlaceholder, getLoroDoc, mergeValue, overlayPlaceholder, validatePlaceholder };
|
|
826
|
+
export { type ArrayValueShape, type ContainerOrValueShape, type ContainerShape, type CounterContainerShape, type DiscriminatedUnionValueShape, type DocShape, type Infer, type InferMutableType, type InferPlaceholderType, type ListContainerShape, type MapContainerShape, type MovableListContainerShape, type Mutable, type ObjectValue, type ObjectValueShape, type PresenceInterface, type RecordContainerShape, type RecordValueShape, type ContainerType as RootContainerType, Shape, type StructContainerShape, type StructValueShape, type TextContainerShape, type TreeContainerShape, type TypedDoc, TypedPresence, type UnionValueShape, type ValueShape, type WithNullable, type WithPlaceholder, change, createPlaceholderProxy, createTypedDoc, derivePlaceholder, deriveShapePlaceholder, getLoroDoc, mergeValue, overlayPlaceholder, validatePlaceholder };
|
package/dist/index.js
CHANGED
|
@@ -270,6 +270,29 @@ function createPlaceholderProxy(target) {
|
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
// src/shape.ts
|
|
273
|
+
function makeNullable(shape) {
|
|
274
|
+
const nullShape = {
|
|
275
|
+
_type: "value",
|
|
276
|
+
valueType: "null",
|
|
277
|
+
_plain: null,
|
|
278
|
+
_mutable: null,
|
|
279
|
+
_placeholder: null
|
|
280
|
+
};
|
|
281
|
+
const base = {
|
|
282
|
+
_type: "value",
|
|
283
|
+
valueType: "union",
|
|
284
|
+
shapes: [nullShape, shape],
|
|
285
|
+
_plain: null,
|
|
286
|
+
_mutable: null,
|
|
287
|
+
_placeholder: null
|
|
288
|
+
// Default placeholder is null
|
|
289
|
+
};
|
|
290
|
+
return Object.assign(base, {
|
|
291
|
+
placeholder(value) {
|
|
292
|
+
return { ...base, _placeholder: value };
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
273
296
|
var Shape = {
|
|
274
297
|
doc: (shape) => ({
|
|
275
298
|
_type: "doc",
|
|
@@ -382,6 +405,9 @@ var Shape = {
|
|
|
382
405
|
return Object.assign(base, {
|
|
383
406
|
placeholder(value) {
|
|
384
407
|
return { ...base, _placeholder: value };
|
|
408
|
+
},
|
|
409
|
+
nullable() {
|
|
410
|
+
return makeNullable(base);
|
|
385
411
|
}
|
|
386
412
|
});
|
|
387
413
|
},
|
|
@@ -396,6 +422,9 @@ var Shape = {
|
|
|
396
422
|
return Object.assign(base, {
|
|
397
423
|
placeholder(value) {
|
|
398
424
|
return { ...base, _placeholder: value };
|
|
425
|
+
},
|
|
426
|
+
nullable() {
|
|
427
|
+
return makeNullable(base);
|
|
399
428
|
}
|
|
400
429
|
});
|
|
401
430
|
},
|
|
@@ -410,6 +439,9 @@ var Shape = {
|
|
|
410
439
|
return Object.assign(base, {
|
|
411
440
|
placeholder(value) {
|
|
412
441
|
return { ...base, _placeholder: value };
|
|
442
|
+
},
|
|
443
|
+
nullable() {
|
|
444
|
+
return makeNullable(base);
|
|
413
445
|
}
|
|
414
446
|
});
|
|
415
447
|
},
|
|
@@ -446,41 +478,69 @@ var Shape = {
|
|
|
446
478
|
* })
|
|
447
479
|
* ```
|
|
448
480
|
*/
|
|
449
|
-
struct: (shape) =>
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
481
|
+
struct: (shape) => {
|
|
482
|
+
const base = {
|
|
483
|
+
_type: "value",
|
|
484
|
+
valueType: "struct",
|
|
485
|
+
shape,
|
|
486
|
+
_plain: {},
|
|
487
|
+
_mutable: {},
|
|
488
|
+
_placeholder: {}
|
|
489
|
+
};
|
|
490
|
+
return Object.assign(base, {
|
|
491
|
+
nullable() {
|
|
492
|
+
return makeNullable(base);
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
},
|
|
457
496
|
/**
|
|
458
497
|
* @deprecated Use `Shape.plain.struct` instead. `Shape.plain.struct` will be removed in a future version.
|
|
459
498
|
*/
|
|
460
|
-
object: (shape) =>
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
499
|
+
object: (shape) => {
|
|
500
|
+
const base = {
|
|
501
|
+
_type: "value",
|
|
502
|
+
valueType: "struct",
|
|
503
|
+
shape,
|
|
504
|
+
_plain: {},
|
|
505
|
+
_mutable: {},
|
|
506
|
+
_placeholder: {}
|
|
507
|
+
};
|
|
508
|
+
return Object.assign(base, {
|
|
509
|
+
nullable() {
|
|
510
|
+
return makeNullable(base);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
},
|
|
514
|
+
record: (shape) => {
|
|
515
|
+
const base = {
|
|
516
|
+
_type: "value",
|
|
517
|
+
valueType: "record",
|
|
518
|
+
shape,
|
|
519
|
+
_plain: {},
|
|
520
|
+
_mutable: {},
|
|
521
|
+
_placeholder: {}
|
|
522
|
+
};
|
|
523
|
+
return Object.assign(base, {
|
|
524
|
+
nullable() {
|
|
525
|
+
return makeNullable(base);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
},
|
|
529
|
+
array: (shape) => {
|
|
530
|
+
const base = {
|
|
531
|
+
_type: "value",
|
|
532
|
+
valueType: "array",
|
|
533
|
+
shape,
|
|
534
|
+
_plain: [],
|
|
535
|
+
_mutable: [],
|
|
536
|
+
_placeholder: []
|
|
537
|
+
};
|
|
538
|
+
return Object.assign(base, {
|
|
539
|
+
nullable() {
|
|
540
|
+
return makeNullable(base);
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
},
|
|
484
544
|
// Special value type that helps make things like `string | null` representable
|
|
485
545
|
// TODO(duane): should this be a more general type for containers too?
|
|
486
546
|
union: (shapes) => {
|