@pluv/crdt 0.0.0-canary-20261027014949
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/LICENSE +21 -0
- package/dist/index.d.mts +195 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +486 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Shoubhit Dash
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { CrdtDocFactory, CrdtDocFactory as CrdtDocFactory$1, CrdtDocLike, CrdtDocLike as CrdtDocLike$1, CrdtLibraryKind, CrdtLibraryType, DocApplyEncodedStateParams, DocApplyEncodedStateParams as DocApplyEncodedStateParams$1, DocBatchApplyEncodedStateParams, DocBatchApplyEncodedStateParams as DocBatchApplyEncodedStateParams$1, DocSubscribeCallbackParams, DocSubscribeCallbackParams as DocSubscribeCallbackParams$1, HasCrdtLibrary, HasStorage, Maybe } from "@pluv/types";
|
|
2
|
+
export declare abstract class AbstractCrdtDocFactory<TDoc extends any = any, TStorage extends Record<string, any> = Record<string, any>, TJson extends Record<string, any> = any, TSeed extends Record<string, any> = any> implements CrdtDocFactory$1<TDoc, TStorage, TJson, TSeed> {
|
|
3
|
+
abstract getEmpty(): CrdtDocLike$1<TDoc, TStorage, TJson>;
|
|
4
|
+
abstract getFactory(seed?: TSeed): AbstractCrdtDocFactory<TDoc, TStorage, TJson, TSeed>;
|
|
5
|
+
abstract getInitialized(seed?: TSeed): CrdtDocLike$1<TDoc, TStorage, TJson>;
|
|
6
|
+
isEmpty(initialState: Maybe<string>): boolean;
|
|
7
|
+
resolveEncodedState(updates: string | string[] | readonly string[]): string | null;
|
|
8
|
+
}
|
|
9
|
+
export declare class NoopCrdtDoc implements CrdtDocLike$1<any, {}, {}> {
|
|
10
|
+
value: any;
|
|
11
|
+
applyEncodedState(_params: DocApplyEncodedStateParams$1): this;
|
|
12
|
+
batchApplyEncodedState(_params: DocBatchApplyEncodedStateParams$1): this;
|
|
13
|
+
captureUpdate(fn: () => void): string | null;
|
|
14
|
+
canRedo(): boolean;
|
|
15
|
+
canUndo(): boolean;
|
|
16
|
+
destroy(): void;
|
|
17
|
+
get(key?: undefined): {};
|
|
18
|
+
get<TKey extends never>(key: TKey): {}[TKey];
|
|
19
|
+
encodeDiff(_stateVector: string): string;
|
|
20
|
+
getEncodedState(): string;
|
|
21
|
+
getStateVector(): string;
|
|
22
|
+
readStateVersion(_encoded: string): readonly (readonly [string, number])[];
|
|
23
|
+
readUpdateVersion(_update: string): readonly (readonly [string, number])[];
|
|
24
|
+
containsUpdate(_update: string): boolean;
|
|
25
|
+
hasPending(): boolean;
|
|
26
|
+
canDetectPending(): boolean;
|
|
27
|
+
isDirty(): boolean;
|
|
28
|
+
isEmpty(): boolean;
|
|
29
|
+
rebuildStorage(): this;
|
|
30
|
+
redo(): this;
|
|
31
|
+
subscribe(_listener: (params: DocSubscribeCallbackParams$1<any, {}, {}>) => void): () => void;
|
|
32
|
+
toJson(): any;
|
|
33
|
+
track(): this;
|
|
34
|
+
transact(fn: () => void, _origin?: string): this;
|
|
35
|
+
undo(): this;
|
|
36
|
+
}
|
|
37
|
+
export declare class NoopCrdtDocFactory extends AbstractCrdtDocFactory<any, {}, {}, {}> {
|
|
38
|
+
getEmpty(): NoopCrdtDoc;
|
|
39
|
+
getFactory(_seed?: {}): NoopCrdtDocFactory;
|
|
40
|
+
getInitialized(_seed?: {}): NoopCrdtDoc;
|
|
41
|
+
}
|
|
42
|
+
export declare const noop: {
|
|
43
|
+
doc: (args?: any) => NoopCrdtDocFactory;
|
|
44
|
+
kind: "noop";
|
|
45
|
+
};
|
|
46
|
+
export declare class CrdtSchemaError extends Error {
|
|
47
|
+
constructor(message: string);
|
|
48
|
+
}
|
|
49
|
+
declare const JSON_KINDS: readonly ["string", "number", "boolean", "null", "literal", "enum", "array", "object", "record", "union", "intersection", "discriminatedUnion", "optional"];
|
|
50
|
+
type JsonSchemaKind = (typeof JSON_KINDS)[number];
|
|
51
|
+
declare const YJS_CRDT_KINDS: readonly ["yArray", "yMap", "yText", "yXmlText", "yXmlElement", "yXmlFragment"];
|
|
52
|
+
type YjsCrdtKind = (typeof YJS_CRDT_KINDS)[number];
|
|
53
|
+
declare const LORO_CRDT_KINDS: readonly ["loroList", "loroMap", "loroText", "loroMovableList", "loroCounter", "loroTree"];
|
|
54
|
+
type LoroCrdtKind = (typeof LORO_CRDT_KINDS)[number];
|
|
55
|
+
declare const CRDT_KINDS: readonly ["yArray", "yMap", "yText", "yXmlText", "yXmlElement", "yXmlFragment", "loroList", "loroMap", "loroText", "loroMovableList", "loroCounter", "loroTree"];
|
|
56
|
+
type CrdtSchemaKind = (typeof CRDT_KINDS)[number];
|
|
57
|
+
export declare const isJsonKind: (kind: string) => kind is JsonSchemaKind;
|
|
58
|
+
export declare const isYjsCrdtKind: (kind: string) => kind is YjsCrdtKind;
|
|
59
|
+
export declare const isLoroCrdtKind: (kind: string) => kind is LoroCrdtKind;
|
|
60
|
+
export declare const isCrdtKind: (kind: string) => kind is CrdtSchemaKind;
|
|
61
|
+
export declare const isXmlKind: (kind: string) => boolean;
|
|
62
|
+
export declare const isUnseedableKind: (kind: string) => boolean;
|
|
63
|
+
declare const SchemaStorage: unique symbol;
|
|
64
|
+
declare const SchemaJson: unique symbol;
|
|
65
|
+
declare const SchemaSeed: unique symbol;
|
|
66
|
+
type SchemaAst = {
|
|
67
|
+
kind: string;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
};
|
|
70
|
+
interface SchemaNode<TKind extends string = string, TStorage = unknown, TJson = unknown, TSeed = unknown> {
|
|
71
|
+
readonly kind: TKind;
|
|
72
|
+
readonly [SchemaStorage]?: TStorage;
|
|
73
|
+
readonly [SchemaJson]?: TJson;
|
|
74
|
+
readonly [SchemaSeed]?: TSeed;
|
|
75
|
+
toJSON(): SchemaAst;
|
|
76
|
+
}
|
|
77
|
+
type InferNodeStorage<T> = T extends SchemaNode<string, infer TStorage, unknown, unknown> ? TStorage : never;
|
|
78
|
+
type InferNodeJson<T> = T extends SchemaNode<string, unknown, infer TJson, unknown> ? TJson : never;
|
|
79
|
+
type InferNodeSeed<T> = T extends SchemaNode<string, unknown, unknown, infer TSeed> ? TSeed : never;
|
|
80
|
+
type AnySchemaNode = SchemaNode<string, any, any, any>;
|
|
81
|
+
export declare const isSchemaNode: (value: unknown) => value is AnySchemaNode;
|
|
82
|
+
export declare const createSchemaNode: <TKind extends string, TStorage, TJson, TSeed, TExtras extends Record<string, unknown>>(kind: TKind, extras: TExtras) => SchemaNode<TKind, TStorage, TJson, TSeed> & TExtras;
|
|
83
|
+
export declare const isJsonSchema: (node: AnySchemaNode) => boolean;
|
|
84
|
+
export declare const isOptionalNode: (node: AnySchemaNode) => node is AnySchemaNode & {
|
|
85
|
+
kind: "optional";
|
|
86
|
+
inner: AnySchemaNode;
|
|
87
|
+
};
|
|
88
|
+
export declare const unwrapOptional: (node: AnySchemaNode) => AnySchemaNode;
|
|
89
|
+
export declare const assertJsonSchema: (node: AnySchemaNode, context: string) => void;
|
|
90
|
+
export declare const assertNotOptional: (node: AnySchemaNode, context: string) => void;
|
|
91
|
+
type OptionalKeys<T extends Record<string, AnySchemaNode>> = { [K in keyof T]: T[K] extends {
|
|
92
|
+
kind: "optional";
|
|
93
|
+
} ? K : never; }[keyof T];
|
|
94
|
+
type RequiredKeys<T extends Record<string, AnySchemaNode>> = Exclude<keyof T, OptionalKeys<T>>;
|
|
95
|
+
type InferOptionalInnerJson<T> = T extends {
|
|
96
|
+
kind: "optional";
|
|
97
|
+
inner: infer I;
|
|
98
|
+
} ? InferNodeJson<I> : InferNodeJson<T>;
|
|
99
|
+
type InferOptionalInnerSeed<T> = T extends {
|
|
100
|
+
kind: "optional";
|
|
101
|
+
inner: infer I;
|
|
102
|
+
} ? InferNodeSeed<I> : InferNodeSeed<T>;
|
|
103
|
+
type InferObjectJson<T extends Record<string, AnySchemaNode>> = { [K in RequiredKeys<T>]: InferNodeJson<T[K]>; } & { [K in OptionalKeys<T>]?: InferOptionalInnerJson<T[K]>; };
|
|
104
|
+
type InferObjectSeed<T extends Record<string, AnySchemaNode>> = { [K in RequiredKeys<T>]: InferNodeSeed<T[K]>; } & { [K in OptionalKeys<T>]?: InferOptionalInnerSeed<T[K]>; };
|
|
105
|
+
type InferObjectStorage<T extends Record<string, AnySchemaNode>> = InferObjectJson<T>;
|
|
106
|
+
type UnionStorage<T extends readonly AnySchemaNode[]> = InferNodeStorage<T[number]>;
|
|
107
|
+
type UnionJson<T extends readonly AnySchemaNode[]> = InferNodeJson<T[number]>;
|
|
108
|
+
type UnionSeed<T extends readonly AnySchemaNode[]> = InferNodeSeed<T[number]>;
|
|
109
|
+
type IntersectionJson<T extends readonly AnySchemaNode[]> = T extends readonly [infer TFirst extends AnySchemaNode, ...infer TRest extends readonly AnySchemaNode[]] ? InferNodeJson<TFirst> & IntersectionJson<TRest> : unknown;
|
|
110
|
+
type IntersectionSeed<T extends readonly AnySchemaNode[]> = T extends readonly [infer TFirst extends AnySchemaNode, ...infer TRest extends readonly AnySchemaNode[]] ? InferNodeSeed<TFirst> & IntersectionSeed<TRest> : unknown;
|
|
111
|
+
type LiteralNode<T extends string | number | boolean> = SchemaNode<"literal", T, T, T>;
|
|
112
|
+
type EnumNode<T extends string> = SchemaNode<"enum", T, T, T>;
|
|
113
|
+
type ArrayNode<TItem extends AnySchemaNode> = SchemaNode<"array", InferNodeJson<TItem>[], InferNodeJson<TItem>[], InferNodeSeed<TItem>[]>;
|
|
114
|
+
type ObjectNode<TShape extends Record<string, AnySchemaNode>> = SchemaNode<"object", InferObjectStorage<TShape>, InferObjectJson<TShape>, InferObjectSeed<TShape>> & {
|
|
115
|
+
readonly shape: TShape;
|
|
116
|
+
};
|
|
117
|
+
type RecordNode<TValue extends AnySchemaNode> = SchemaNode<"record", Record<string, InferNodeJson<TValue>>, Record<string, InferNodeJson<TValue>>, Record<string, InferNodeSeed<TValue>>>;
|
|
118
|
+
type UnionNode<TOptions extends readonly AnySchemaNode[]> = SchemaNode<"union", UnionStorage<TOptions>, UnionJson<TOptions>, UnionSeed<TOptions>> & {
|
|
119
|
+
readonly options: TOptions;
|
|
120
|
+
};
|
|
121
|
+
type IntersectionNode<TOptions extends readonly AnySchemaNode[]> = SchemaNode<"intersection", IntersectionJson<TOptions>, IntersectionJson<TOptions>, IntersectionSeed<TOptions>> & {
|
|
122
|
+
readonly options: TOptions;
|
|
123
|
+
};
|
|
124
|
+
type DiscriminatedUnionNode<TKey extends string, TOptions extends readonly AnySchemaNode[]> = SchemaNode<"discriminatedUnion", UnionStorage<TOptions>, UnionJson<TOptions>, UnionSeed<TOptions>> & {
|
|
125
|
+
readonly discriminator: TKey;
|
|
126
|
+
readonly options: TOptions;
|
|
127
|
+
};
|
|
128
|
+
type OptionalNode<TInner extends AnySchemaNode> = SchemaNode<"optional", InferNodeStorage<TInner> | undefined, InferNodeJson<TInner> | undefined, InferNodeSeed<TInner> | undefined> & {
|
|
129
|
+
readonly inner: TInner;
|
|
130
|
+
};
|
|
131
|
+
type SchemaShape = Record<string, AnySchemaNode>;
|
|
132
|
+
type InferShapeStorage<TShape extends SchemaShape> = { [K in keyof TShape]: InferNodeStorage<TShape[K]>; };
|
|
133
|
+
type InferShapeJson<TShape extends SchemaShape> = { [K in keyof TShape]: InferNodeJson<TShape[K]>; };
|
|
134
|
+
type InferShapeSeed<TShape extends SchemaShape> = { [K in keyof TShape as InferNodeSeed<TShape[K]> extends never ? never : K]?: InferNodeSeed<TShape[K]>; };
|
|
135
|
+
type InferStorage$1<T> = T extends {
|
|
136
|
+
readonly shape: infer TShape extends SchemaShape;
|
|
137
|
+
} ? InferShapeStorage<TShape> : T extends SchemaNode<string, infer TStorage, unknown, unknown> ? TStorage : never;
|
|
138
|
+
type InferJson$1<T> = T extends {
|
|
139
|
+
readonly shape: infer TShape extends SchemaShape;
|
|
140
|
+
} ? InferShapeJson<TShape> : T extends SchemaNode<string, unknown, infer TJson, unknown> ? TJson : never;
|
|
141
|
+
type InferSeed$1<T> = T extends {
|
|
142
|
+
readonly shape: infer TShape extends SchemaShape;
|
|
143
|
+
} ? InferShapeSeed<TShape> : T extends SchemaNode<string, unknown, unknown, infer TSeed> ? TSeed : never;
|
|
144
|
+
declare const string: () => SchemaNodeLike<"string", string>;
|
|
145
|
+
declare const number: () => SchemaNodeLike<"number", number>;
|
|
146
|
+
declare const boolean: () => SchemaNodeLike<"boolean", boolean>;
|
|
147
|
+
declare const nullType: () => SchemaNodeLike<"null", null>;
|
|
148
|
+
type SchemaNodeLike<TKind extends string, TValue> = SchemaNode<TKind, TValue, TValue, TValue>;
|
|
149
|
+
declare const literal: <T extends string | number | boolean>(value: T) => LiteralNode<T> & {
|
|
150
|
+
value: T;
|
|
151
|
+
};
|
|
152
|
+
declare const enumType: <const TValues extends readonly string[]>(values: TValues) => EnumNode<TValues[number]> & {
|
|
153
|
+
values: TValues;
|
|
154
|
+
};
|
|
155
|
+
declare const array: <TItem extends AnySchemaNode>(item: TItem) => ArrayNode<TItem> & {
|
|
156
|
+
item: TItem;
|
|
157
|
+
};
|
|
158
|
+
declare const object: <TShape extends Record<string, AnySchemaNode>>(shape: TShape) => ObjectNode<TShape>;
|
|
159
|
+
declare const record: <TValue extends AnySchemaNode>(value: TValue) => RecordNode<TValue> & {
|
|
160
|
+
value: TValue;
|
|
161
|
+
};
|
|
162
|
+
export declare const $union: <const TOptions extends readonly AnySchemaNode[]>(options: TOptions) => UnionNode<TOptions>;
|
|
163
|
+
export declare const $intersection: <const TOptions extends readonly AnySchemaNode[]>(options: TOptions) => IntersectionNode<TOptions>;
|
|
164
|
+
export declare const $discriminatedUnion: <TKey extends string, const TOptions extends readonly AnySchemaNode[]>(key: TKey, options: TOptions) => DiscriminatedUnionNode<TKey, TOptions>;
|
|
165
|
+
export declare const $nullable: <TInner extends AnySchemaNode>(inner: TInner) => UnionNode<readonly [TInner, SchemaNodeLike<"null", null>]>;
|
|
166
|
+
export declare const $optional: <TInner extends AnySchemaNode>(inner: TInner) => OptionalNode<TInner>;
|
|
167
|
+
export declare const s: {
|
|
168
|
+
string: typeof string;
|
|
169
|
+
number: typeof number;
|
|
170
|
+
boolean: typeof boolean;
|
|
171
|
+
null: typeof nullType;
|
|
172
|
+
literal: typeof literal;
|
|
173
|
+
enum: typeof enumType;
|
|
174
|
+
array: typeof array;
|
|
175
|
+
object: typeof object;
|
|
176
|
+
record: typeof record;
|
|
177
|
+
$union: typeof $union;
|
|
178
|
+
$discriminatedUnion: typeof $discriminatedUnion;
|
|
179
|
+
$intersection: typeof $intersection;
|
|
180
|
+
$nullable: typeof $nullable;
|
|
181
|
+
$optional: typeof $optional;
|
|
182
|
+
};
|
|
183
|
+
declare const fromJSONUnknown: (ast: SchemaAst) => AnySchemaNode;
|
|
184
|
+
export declare const fromJSON: typeof fromJSONUnknown;
|
|
185
|
+
export declare const flattenObjectShape: (node: AnySchemaNode) => Record<string, AnySchemaNode>;
|
|
186
|
+
export declare const assertJsonValue: (node: AnySchemaNode, value: unknown, context: string) => void;
|
|
187
|
+
export declare const pickUnionOption: (node: AnySchemaNode, value: unknown) => AnySchemaNode | null;
|
|
188
|
+
export declare const canHydrate: (node: AnySchemaNode, value: unknown) => boolean;
|
|
189
|
+
type InferDoc<TFactory extends AbstractCrdtDocFactory<any, any, any, any>> = InferDocLike<TFactory>["value"];
|
|
190
|
+
type InferDocLike<TFactory extends AbstractCrdtDocFactory<any, any, any, any>> = ReturnType<TFactory["getInitialized"]>;
|
|
191
|
+
type InferStorage<T> = T extends AbstractCrdtDocFactory<any, infer TStorage, any, any> ? TStorage : InferStorage$1<T>;
|
|
192
|
+
type InferJson<T> = T extends AbstractCrdtDocFactory<any, any, infer TJson, any> ? TJson : InferJson$1<T>;
|
|
193
|
+
type InferSeed<T> = T extends AbstractCrdtDocFactory<any, any, any, infer TSeed> ? TSeed : InferSeed$1<T>;
|
|
194
|
+
export type { AnySchemaNode, CrdtDocFactory, CrdtDocLike, CrdtLibraryKind, CrdtLibraryType, DocApplyEncodedStateParams, DocBatchApplyEncodedStateParams, DocSubscribeCallbackParams, HasCrdtLibrary, HasStorage, InferDoc, InferDocLike, InferJson, InferNodeJson, InferNodeSeed, InferNodeStorage, InferSeed, InferShapeJson, InferShapeSeed, InferShapeStorage, InferStorage, SchemaAst, SchemaNode };
|
|
195
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":["CrdtDocLike","CrdtDocFactory","DocApplyEncodedStateParams","DocBatchApplyEncodedStateParams","DocSubscribeCallbackParams","CrdtDocLike","InferStorage","InferJson","InferSeed","_$__node0.SchemaNode","InferSchemaStorage","InferSchemaJson","InferSchemaSeed"],"sources":["../src/AbstractCrdtDocFactory.ts","../src/NoopCrdtDoc.ts","../src/NoopCrdtDocFactory.ts","../src/noop.ts","../src/schema/error.ts","../src/schema/kinds.ts","../src/schema/node.ts","../src/schema/infer.ts","../src/schema/s.ts","../src/schema/validate.ts","../src/types.ts"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
// src/AbstractCrdtDocFactory.ts
|
|
2
|
+
var AbstractCrdtDocFactory = class {
|
|
3
|
+
isEmpty(initialState) {
|
|
4
|
+
const doc = this.getEmpty().applyEncodedState({ update: initialState });
|
|
5
|
+
const isEmpty = doc.isEmpty();
|
|
6
|
+
doc.destroy();
|
|
7
|
+
return isEmpty;
|
|
8
|
+
}
|
|
9
|
+
resolveEncodedState(updates) {
|
|
10
|
+
if (typeof updates === "string") return updates;
|
|
11
|
+
if (Array.isArray(updates) && !updates.length) return null;
|
|
12
|
+
const applied = this.getEmpty().batchApplyEncodedState({ updates });
|
|
13
|
+
if (applied.isEmpty()) {
|
|
14
|
+
applied.destroy();
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const encodedState = applied.getEncodedState();
|
|
18
|
+
applied.destroy();
|
|
19
|
+
return encodedState;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
// src/NoopCrdtDoc.ts
|
|
23
|
+
var NoopCrdtDoc = class {
|
|
24
|
+
value = null;
|
|
25
|
+
applyEncodedState(_params) {
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
batchApplyEncodedState(_params) {
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
captureUpdate(fn) {
|
|
32
|
+
fn();
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
canRedo() {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
canUndo() {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
destroy() {}
|
|
42
|
+
get(key) {
|
|
43
|
+
return typeof key === "string" ? void 0 : {};
|
|
44
|
+
}
|
|
45
|
+
encodeDiff(_stateVector) {
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
getEncodedState() {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
getStateVector() {
|
|
52
|
+
return "";
|
|
53
|
+
}
|
|
54
|
+
readStateVersion(_encoded) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
readUpdateVersion(_update) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
containsUpdate(_update) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
hasPending() {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
canDetectPending() {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
isDirty() {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
isEmpty() {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
rebuildStorage() {
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
redo() {
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
subscribe(_listener) {
|
|
82
|
+
return () => void 0;
|
|
83
|
+
}
|
|
84
|
+
toJson() {
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
track() {
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
transact(fn, _origin) {
|
|
91
|
+
fn();
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
undo() {
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
// src/NoopCrdtDocFactory.ts
|
|
99
|
+
var NoopCrdtDocFactory = class extends AbstractCrdtDocFactory {
|
|
100
|
+
getEmpty() {
|
|
101
|
+
return new NoopCrdtDoc();
|
|
102
|
+
}
|
|
103
|
+
getFactory(_seed) {
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
getInitialized(_seed) {
|
|
107
|
+
return new NoopCrdtDoc();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
// src/noop.ts
|
|
111
|
+
const noop = {
|
|
112
|
+
doc: (args) => new NoopCrdtDocFactory(),
|
|
113
|
+
kind: "noop"
|
|
114
|
+
};
|
|
115
|
+
// src/schema/error.ts
|
|
116
|
+
var CrdtSchemaError = class extends Error {
|
|
117
|
+
constructor(message) {
|
|
118
|
+
super(message);
|
|
119
|
+
this.name = "CrdtSchemaError";
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
// src/schema/kinds.ts
|
|
123
|
+
const JSON_KINDS = [
|
|
124
|
+
"string",
|
|
125
|
+
"number",
|
|
126
|
+
"boolean",
|
|
127
|
+
"null",
|
|
128
|
+
"literal",
|
|
129
|
+
"enum",
|
|
130
|
+
"array",
|
|
131
|
+
"object",
|
|
132
|
+
"record",
|
|
133
|
+
"union",
|
|
134
|
+
"intersection",
|
|
135
|
+
"discriminatedUnion",
|
|
136
|
+
"optional"
|
|
137
|
+
];
|
|
138
|
+
const YJS_CRDT_KINDS = [
|
|
139
|
+
"yArray",
|
|
140
|
+
"yMap",
|
|
141
|
+
"yText",
|
|
142
|
+
"yXmlText",
|
|
143
|
+
"yXmlElement",
|
|
144
|
+
"yXmlFragment"
|
|
145
|
+
];
|
|
146
|
+
const LORO_CRDT_KINDS = [
|
|
147
|
+
"loroList",
|
|
148
|
+
"loroMap",
|
|
149
|
+
"loroText",
|
|
150
|
+
"loroMovableList",
|
|
151
|
+
"loroCounter",
|
|
152
|
+
"loroTree"
|
|
153
|
+
];
|
|
154
|
+
const CRDT_KINDS = [...YJS_CRDT_KINDS, ...LORO_CRDT_KINDS];
|
|
155
|
+
const isJsonKind = (kind) => {
|
|
156
|
+
return JSON_KINDS.includes(kind);
|
|
157
|
+
};
|
|
158
|
+
const isYjsCrdtKind = (kind) => {
|
|
159
|
+
return YJS_CRDT_KINDS.includes(kind);
|
|
160
|
+
};
|
|
161
|
+
const isLoroCrdtKind = (kind) => {
|
|
162
|
+
return LORO_CRDT_KINDS.includes(kind);
|
|
163
|
+
};
|
|
164
|
+
const isCrdtKind = (kind) => {
|
|
165
|
+
return CRDT_KINDS.includes(kind);
|
|
166
|
+
};
|
|
167
|
+
const isXmlKind = (kind) => {
|
|
168
|
+
return kind === "yXmlText" || kind === "yXmlElement" || kind === "yXmlFragment";
|
|
169
|
+
};
|
|
170
|
+
const isUnseedableKind = (kind) => {
|
|
171
|
+
return isXmlKind(kind) || kind === "loroTree";
|
|
172
|
+
};
|
|
173
|
+
// src/schema/node.ts
|
|
174
|
+
const isRecord = (value) => {
|
|
175
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
176
|
+
};
|
|
177
|
+
const isSchemaNode = (value) => {
|
|
178
|
+
return isRecord(value) && typeof value.kind === "string" && typeof value.toJSON === "function";
|
|
179
|
+
};
|
|
180
|
+
const toAst = (value) => {
|
|
181
|
+
if (isSchemaNode(value)) return value.toJSON();
|
|
182
|
+
if (Array.isArray(value)) return value.map(toAst);
|
|
183
|
+
if (isRecord(value)) return Object.entries(value).reduce((acc, [key, nested]) => {
|
|
184
|
+
acc[key] = toAst(nested);
|
|
185
|
+
return acc;
|
|
186
|
+
}, {});
|
|
187
|
+
return value;
|
|
188
|
+
};
|
|
189
|
+
const createSchemaNode = (kind, extras) => {
|
|
190
|
+
return {
|
|
191
|
+
kind,
|
|
192
|
+
...extras,
|
|
193
|
+
toJSON() {
|
|
194
|
+
const json = { kind };
|
|
195
|
+
Object.entries(extras).forEach(([key, value]) => {
|
|
196
|
+
json[key] = toAst(value);
|
|
197
|
+
});
|
|
198
|
+
return json;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
const isJsonSchema = (node) => {
|
|
203
|
+
if (node.kind === "optional") {
|
|
204
|
+
const inner = node.inner;
|
|
205
|
+
return isJsonSchema(inner);
|
|
206
|
+
}
|
|
207
|
+
if (node.kind === "union" || node.kind === "intersection" || node.kind === "discriminatedUnion") return node.options.every(isJsonSchema);
|
|
208
|
+
if (node.kind === "array") return isJsonSchema(node.item);
|
|
209
|
+
if (node.kind === "record") return isJsonSchema(node.value);
|
|
210
|
+
if (node.kind === "object") {
|
|
211
|
+
const shape = node.shape;
|
|
212
|
+
return Object.values(shape).every(isJsonSchema);
|
|
213
|
+
}
|
|
214
|
+
return isJsonKind(node.kind) && !isCrdtKind(node.kind);
|
|
215
|
+
};
|
|
216
|
+
const isOptionalNode = (node) => {
|
|
217
|
+
return node.kind === "optional";
|
|
218
|
+
};
|
|
219
|
+
const unwrapOptional = (node) => {
|
|
220
|
+
return isOptionalNode(node) ? node.inner : node;
|
|
221
|
+
};
|
|
222
|
+
const assertJsonSchema = (node, context) => {
|
|
223
|
+
if (!isJsonSchema(node)) throw new CrdtSchemaError(`${context} must be a JSON schema`);
|
|
224
|
+
};
|
|
225
|
+
const assertNotOptional = (node, context) => {
|
|
226
|
+
if (isOptionalNode(node)) throw new CrdtSchemaError(`${context} cannot be optional; s.$optional is only valid on s.object fields`);
|
|
227
|
+
};
|
|
228
|
+
// src/schema/s.ts
|
|
229
|
+
const flattenObjectShape$1 = (node, context) => {
|
|
230
|
+
if (node.kind === "object") return node.shape;
|
|
231
|
+
if (node.kind === "intersection") return node.options.reduce((acc, option) => {
|
|
232
|
+
const shape = flattenObjectShape$1(option, context);
|
|
233
|
+
Object.entries(shape).forEach(([key, field]) => {
|
|
234
|
+
if (key in acc && JSON.stringify(acc[key].toJSON()) !== JSON.stringify(field.toJSON())) throw new CrdtSchemaError(`${context} has conflicting types for key "${key}"`);
|
|
235
|
+
acc[key] = field;
|
|
236
|
+
});
|
|
237
|
+
return acc;
|
|
238
|
+
}, {});
|
|
239
|
+
throw new CrdtSchemaError(`${context} must be an s.object or s.$intersection of objects`);
|
|
240
|
+
};
|
|
241
|
+
const assertObjectLike = (node, context) => {
|
|
242
|
+
flattenObjectShape$1(node, context);
|
|
243
|
+
};
|
|
244
|
+
const getDiscriminatorField = (node, key) => {
|
|
245
|
+
const field = flattenObjectShape$1(node, `s.$discriminatedUnion branch`)[key];
|
|
246
|
+
if (!field) return null;
|
|
247
|
+
const inner = unwrapOptional(field);
|
|
248
|
+
if (inner.kind === "literal") return inner;
|
|
249
|
+
if (inner.kind === "enum") {
|
|
250
|
+
if (inner.values.length === 1) return inner;
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
};
|
|
254
|
+
const string = () => {
|
|
255
|
+
return createSchemaNode("string", {});
|
|
256
|
+
};
|
|
257
|
+
const number = () => {
|
|
258
|
+
return createSchemaNode("number", {});
|
|
259
|
+
};
|
|
260
|
+
const boolean = () => {
|
|
261
|
+
return createSchemaNode("boolean", {});
|
|
262
|
+
};
|
|
263
|
+
const nullType = () => {
|
|
264
|
+
return createSchemaNode("null", {});
|
|
265
|
+
};
|
|
266
|
+
const literal = (value) => {
|
|
267
|
+
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") throw new CrdtSchemaError("s.literal only accepts JSON primitives (string, number, boolean)");
|
|
268
|
+
return createSchemaNode("literal", { value });
|
|
269
|
+
};
|
|
270
|
+
const enumType = (values) => {
|
|
271
|
+
if (!values.length) throw new CrdtSchemaError("s.enum requires at least one value");
|
|
272
|
+
if (new Set(values).size !== values.length) throw new CrdtSchemaError("s.enum values must be unique");
|
|
273
|
+
values.forEach((value) => {
|
|
274
|
+
if (typeof value !== "string") throw new CrdtSchemaError("s.enum values must be strings");
|
|
275
|
+
});
|
|
276
|
+
return createSchemaNode("enum", { values });
|
|
277
|
+
};
|
|
278
|
+
const array = (item) => {
|
|
279
|
+
assertNotOptional(item, "s.array item");
|
|
280
|
+
assertJsonSchema(item, "s.array item");
|
|
281
|
+
return createSchemaNode("array", { item });
|
|
282
|
+
};
|
|
283
|
+
const object = (shape) => {
|
|
284
|
+
Object.entries(shape).forEach(([key, field]) => {
|
|
285
|
+
if (!isSchemaNode(field)) throw new CrdtSchemaError(`s.object field "${key}" must be a schema node`);
|
|
286
|
+
const inner = unwrapOptional(field);
|
|
287
|
+
assertJsonSchema(inner, `s.object field "${key}"`);
|
|
288
|
+
});
|
|
289
|
+
return createSchemaNode("object", { shape });
|
|
290
|
+
};
|
|
291
|
+
const record = (value) => {
|
|
292
|
+
assertNotOptional(value, "s.record value");
|
|
293
|
+
assertJsonSchema(value, "s.record value");
|
|
294
|
+
return createSchemaNode("record", { value });
|
|
295
|
+
};
|
|
296
|
+
const $union = (options) => {
|
|
297
|
+
if (options.length < 2) throw new CrdtSchemaError("s.$union requires at least two options");
|
|
298
|
+
options.forEach((option, index) => {
|
|
299
|
+
assertNotOptional(option, `s.$union option[${index}]`);
|
|
300
|
+
if (!isSchemaNode(option)) throw new CrdtSchemaError(`s.$union option[${index}] must be a schema node`);
|
|
301
|
+
});
|
|
302
|
+
return createSchemaNode("union", { options });
|
|
303
|
+
};
|
|
304
|
+
const $intersection = (options) => {
|
|
305
|
+
if (options.length < 2) throw new CrdtSchemaError("s.$intersection requires at least two options");
|
|
306
|
+
options.forEach((option, index) => {
|
|
307
|
+
assertNotOptional(option, `s.$intersection option[${index}]`);
|
|
308
|
+
assertJsonSchema(option, `s.$intersection option[${index}]`);
|
|
309
|
+
assertObjectLike(option, `s.$intersection option[${index}]`);
|
|
310
|
+
});
|
|
311
|
+
flattenObjectShape$1(createSchemaNode("intersection", { options }), "s.$intersection");
|
|
312
|
+
return createSchemaNode("intersection", { options });
|
|
313
|
+
};
|
|
314
|
+
const $discriminatedUnion = (key, options) => {
|
|
315
|
+
if (options.length < 2) throw new CrdtSchemaError("s.$discriminatedUnion requires at least two options");
|
|
316
|
+
const tags = /* @__PURE__ */ new Set();
|
|
317
|
+
options.forEach((option, index) => {
|
|
318
|
+
assertNotOptional(option, `s.$discriminatedUnion option[${index}]`);
|
|
319
|
+
assertJsonSchema(option, `s.$discriminatedUnion option[${index}]`);
|
|
320
|
+
assertObjectLike(option, `s.$discriminatedUnion option[${index}]`);
|
|
321
|
+
const field = getDiscriminatorField(option, key);
|
|
322
|
+
if (!field) throw new CrdtSchemaError(`s.$discriminatedUnion option[${index}] must have a literal (or single-value enum) field "${key}"`);
|
|
323
|
+
const tag = field.kind === "literal" ? field.value : field.values[0];
|
|
324
|
+
if (tags.has(tag)) throw new CrdtSchemaError(`s.$discriminatedUnion has duplicate tag "${String(tag)}"`);
|
|
325
|
+
tags.add(tag);
|
|
326
|
+
});
|
|
327
|
+
return createSchemaNode("discriminatedUnion", {
|
|
328
|
+
discriminator: key,
|
|
329
|
+
options
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
const $nullable = (inner) => {
|
|
333
|
+
assertNotOptional(inner, "s.$nullable");
|
|
334
|
+
return $union([inner, nullType()]);
|
|
335
|
+
};
|
|
336
|
+
const $optional = (inner) => {
|
|
337
|
+
if (isOptionalNode(inner)) throw new CrdtSchemaError("s.$optional cannot wrap another s.$optional");
|
|
338
|
+
assertJsonSchema(inner, "s.$optional");
|
|
339
|
+
return createSchemaNode("optional", { inner });
|
|
340
|
+
};
|
|
341
|
+
const s = {
|
|
342
|
+
string,
|
|
343
|
+
number,
|
|
344
|
+
boolean,
|
|
345
|
+
null: nullType,
|
|
346
|
+
literal,
|
|
347
|
+
enum: enumType,
|
|
348
|
+
array,
|
|
349
|
+
object,
|
|
350
|
+
record,
|
|
351
|
+
$union,
|
|
352
|
+
$discriminatedUnion,
|
|
353
|
+
$intersection,
|
|
354
|
+
$nullable,
|
|
355
|
+
$optional
|
|
356
|
+
};
|
|
357
|
+
const fromJSONUnknown = (ast) => {
|
|
358
|
+
switch (ast.kind) {
|
|
359
|
+
case "string": return string();
|
|
360
|
+
case "number": return number();
|
|
361
|
+
case "boolean": return boolean();
|
|
362
|
+
case "null": return nullType();
|
|
363
|
+
case "literal": return literal(ast.value);
|
|
364
|
+
case "enum": return enumType(ast.values);
|
|
365
|
+
case "array": return array(fromJSONUnknown(ast.item));
|
|
366
|
+
case "object": {
|
|
367
|
+
const shape = Object.entries(ast.shape ?? {}).reduce((acc, [key, value]) => {
|
|
368
|
+
acc[key] = fromJSONUnknown(value);
|
|
369
|
+
return acc;
|
|
370
|
+
}, {});
|
|
371
|
+
return object(shape);
|
|
372
|
+
}
|
|
373
|
+
case "record": return record(fromJSONUnknown(ast.value));
|
|
374
|
+
case "union": return $union(ast.options.map(fromJSONUnknown));
|
|
375
|
+
case "intersection": return $intersection(ast.options.map(fromJSONUnknown));
|
|
376
|
+
case "discriminatedUnion": return $discriminatedUnion(ast.discriminator, ast.options.map(fromJSONUnknown));
|
|
377
|
+
case "optional": return $optional(fromJSONUnknown(ast.inner));
|
|
378
|
+
default: throw new CrdtSchemaError(`Unknown JSON schema kind "${ast.kind}"`);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
const fromJSON = fromJSONUnknown;
|
|
382
|
+
// src/schema/validate.ts
|
|
383
|
+
const isPlainObject = (value) => {
|
|
384
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
385
|
+
};
|
|
386
|
+
const flattenObjectShape = (node) => {
|
|
387
|
+
if (node.kind === "object") return node.shape;
|
|
388
|
+
if (node.kind === "intersection") return node.options.reduce((acc, option) => {
|
|
389
|
+
const shape = flattenObjectShape(option);
|
|
390
|
+
Object.entries(shape).forEach(([key, field]) => {
|
|
391
|
+
acc[key] = field;
|
|
392
|
+
});
|
|
393
|
+
return acc;
|
|
394
|
+
}, {});
|
|
395
|
+
throw new CrdtSchemaError(`Expected an object schema, received "${node.kind}"`);
|
|
396
|
+
};
|
|
397
|
+
const matchesLiteralOrEnum = (node, value) => {
|
|
398
|
+
if (node.kind === "literal") return node.value === value;
|
|
399
|
+
if (node.kind === "enum") return node.values.includes(value);
|
|
400
|
+
return false;
|
|
401
|
+
};
|
|
402
|
+
const validateJson = (node, value) => {
|
|
403
|
+
const current = unwrapOptional(node);
|
|
404
|
+
switch (current.kind) {
|
|
405
|
+
case "string": return typeof value === "string";
|
|
406
|
+
case "number": return typeof value === "number" && Number.isFinite(value);
|
|
407
|
+
case "boolean": return typeof value === "boolean";
|
|
408
|
+
case "null": return value === null;
|
|
409
|
+
case "literal": return current.value === value;
|
|
410
|
+
case "enum": return current.values.includes(value);
|
|
411
|
+
case "array": {
|
|
412
|
+
if (!Array.isArray(value)) return false;
|
|
413
|
+
const item = current.item;
|
|
414
|
+
return value.every((entry) => validateJson(item, entry));
|
|
415
|
+
}
|
|
416
|
+
case "object": {
|
|
417
|
+
if (!isPlainObject(value)) return false;
|
|
418
|
+
const shape = current.shape;
|
|
419
|
+
if (Object.keys(value).filter((key) => !(key in shape)).length) return false;
|
|
420
|
+
return Object.entries(shape).every(([key, field]) => {
|
|
421
|
+
if (!(key in value)) return isOptionalNode(field);
|
|
422
|
+
return validateJson(field, value[key]);
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
case "record": {
|
|
426
|
+
if (!isPlainObject(value)) return false;
|
|
427
|
+
const field = current.value;
|
|
428
|
+
return Object.values(value).every((entry) => validateJson(field, entry));
|
|
429
|
+
}
|
|
430
|
+
case "union": return current.options.some((option) => validateJson(option, value));
|
|
431
|
+
case "intersection": try {
|
|
432
|
+
const shape = flattenObjectShape(current);
|
|
433
|
+
return validateJson({
|
|
434
|
+
...current,
|
|
435
|
+
kind: "object",
|
|
436
|
+
shape
|
|
437
|
+
}, value);
|
|
438
|
+
} catch {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
case "discriminatedUnion": {
|
|
442
|
+
if (!isPlainObject(value)) return false;
|
|
443
|
+
const discriminator = current.discriminator;
|
|
444
|
+
const options = current.options;
|
|
445
|
+
const tag = value[discriminator];
|
|
446
|
+
const option = options.find((branch) => {
|
|
447
|
+
const field = flattenObjectShape(branch)[discriminator];
|
|
448
|
+
return field ? matchesLiteralOrEnum(unwrapOptional(field), tag) : false;
|
|
449
|
+
});
|
|
450
|
+
return option ? validateJson(option, value) : false;
|
|
451
|
+
}
|
|
452
|
+
default:
|
|
453
|
+
if (isUnseedableKind(current.kind)) return false;
|
|
454
|
+
if (current.kind === "yText" || current.kind === "loroText") return typeof value === "string";
|
|
455
|
+
if (current.kind === "loroCounter") return typeof value === "number" && Number.isFinite(value);
|
|
456
|
+
if (current.kind === "yArray" || current.kind === "loroList" || current.kind === "loroMovableList") return Array.isArray(value);
|
|
457
|
+
if (current.kind === "yMap" || current.kind === "loroMap") return isPlainObject(value);
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
const assertJsonValue = (node, value, context) => {
|
|
462
|
+
if (validateJson(node, value)) return;
|
|
463
|
+
throw new CrdtSchemaError(`${context} does not match schema kind "${node.kind}"`);
|
|
464
|
+
};
|
|
465
|
+
const pickUnionOption = (node, value) => {
|
|
466
|
+
if (node.kind === "union") return node.options.find((option) => canHydrate(option, value)) ?? null;
|
|
467
|
+
if (node.kind === "discriminatedUnion") {
|
|
468
|
+
if (!isPlainObject(value)) return null;
|
|
469
|
+
const discriminator = node.discriminator;
|
|
470
|
+
const options = node.options;
|
|
471
|
+
const tag = value[discriminator];
|
|
472
|
+
return options.find((branch) => {
|
|
473
|
+
const field = flattenObjectShape(branch)[discriminator];
|
|
474
|
+
return field ? matchesLiteralOrEnum(unwrapOptional(field), tag) : false;
|
|
475
|
+
}) ?? null;
|
|
476
|
+
}
|
|
477
|
+
return node;
|
|
478
|
+
};
|
|
479
|
+
const canHydrate = (node, value) => {
|
|
480
|
+
const current = unwrapOptional(node);
|
|
481
|
+
if (current.kind === "union" || current.kind === "discriminatedUnion") return pickUnionOption(current, value) !== null;
|
|
482
|
+
return validateJson(current, value);
|
|
483
|
+
};
|
|
484
|
+
export { $discriminatedUnion, $intersection, $nullable, $optional, $union, AbstractCrdtDocFactory, CrdtSchemaError, NoopCrdtDoc, NoopCrdtDocFactory, assertJsonSchema, assertJsonValue, assertNotOptional, canHydrate, createSchemaNode, flattenObjectShape, fromJSON, isCrdtKind, isJsonKind, isJsonSchema, isLoroCrdtKind, isOptionalNode, isSchemaNode, isUnseedableKind, isXmlKind, isYjsCrdtKind, noop, pickUnionOption, s, unwrapOptional };
|
|
485
|
+
|
|
486
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["flattenObjectShape"],"sources":["../src/AbstractCrdtDocFactory.ts","../src/NoopCrdtDoc.ts","../src/NoopCrdtDocFactory.ts","../src/noop.ts","../src/schema/error.ts","../src/schema/kinds.ts","../src/schema/node.ts","../src/schema/s.ts","../src/schema/validate.ts"],"sourcesContent":["import type { CrdtDocFactory, CrdtDocLike, Maybe } from \"@pluv/types\";\n\nexport abstract class AbstractCrdtDocFactory<\n TDoc extends any = any,\n TStorage extends Record<string, any> = Record<string, any>,\n TJson extends Record<string, any> = any,\n TSeed extends Record<string, any> = any,\n> implements CrdtDocFactory<TDoc, TStorage, TJson, TSeed> {\n public abstract getEmpty(): CrdtDocLike<TDoc, TStorage, TJson>;\n public abstract getFactory(seed?: TSeed): AbstractCrdtDocFactory<TDoc, TStorage, TJson, TSeed>;\n public abstract getInitialized(seed?: TSeed): CrdtDocLike<TDoc, TStorage, TJson>;\n\n public isEmpty(initialState: Maybe<string>): boolean {\n const doc = this.getEmpty().applyEncodedState({ update: initialState });\n const isEmpty = doc.isEmpty();\n doc.destroy();\n\n return isEmpty;\n }\n\n public resolveEncodedState(updates: string | string[] | readonly string[]): string | null {\n if (typeof updates === \"string\") return updates;\n if (Array.isArray(updates) && !updates.length) return null;\n\n const applied = this.getEmpty().batchApplyEncodedState({ updates });\n\n if (applied.isEmpty()) {\n applied.destroy();\n return null;\n }\n\n const encodedState = applied.getEncodedState();\n applied.destroy();\n\n return encodedState;\n }\n}\n","import {\n CrdtDocLike,\n DocApplyEncodedStateParams,\n DocBatchApplyEncodedStateParams,\n DocSubscribeCallbackParams,\n} from \"@pluv/types\";\n\nexport class NoopCrdtDoc implements CrdtDocLike<any, {}, {}> {\n public value: any = null;\n\n public applyEncodedState(_params: DocApplyEncodedStateParams): this {\n return this;\n }\n\n public batchApplyEncodedState(_params: DocBatchApplyEncodedStateParams): this {\n return this;\n }\n\n public captureUpdate(fn: () => void): string | null {\n fn();\n\n return null;\n }\n\n public canRedo(): boolean {\n return false;\n }\n\n public canUndo(): boolean {\n return false;\n }\n\n public destroy(): void {\n return;\n }\n\n public get(key?: undefined): {};\n public get<TKey extends never>(key: TKey): {}[TKey];\n public get(key?: string): {} | undefined {\n return typeof key === \"string\" ? undefined : {};\n }\n\n public encodeDiff(_stateVector: string): string {\n return \"\";\n }\n\n public getEncodedState(): string {\n return \"\";\n }\n\n public getStateVector(): string {\n return \"\";\n }\n\n public readStateVersion(_encoded: string): readonly (readonly [string, number])[] {\n return [];\n }\n\n public readUpdateVersion(_update: string): readonly (readonly [string, number])[] {\n return [];\n }\n\n public containsUpdate(_update: string): boolean {\n return true;\n }\n\n public hasPending(): boolean {\n return false;\n }\n\n public canDetectPending(): boolean {\n return true;\n }\n\n public isDirty(): boolean {\n return false;\n }\n\n public isEmpty(): boolean {\n return true;\n }\n\n public rebuildStorage(): this {\n return this;\n }\n\n public redo(): this {\n return this;\n }\n\n public subscribe(\n _listener: (params: DocSubscribeCallbackParams<any, {}, {}>) => void,\n ): () => void {\n return () => undefined;\n }\n\n public toJson(): any {\n return {};\n }\n\n public track(): this {\n return this;\n }\n\n public transact(fn: () => void, _origin?: string): this {\n fn();\n\n return this;\n }\n\n public undo(): this {\n return this;\n }\n}\n","import { AbstractCrdtDocFactory } from \"./AbstractCrdtDocFactory\";\nimport { NoopCrdtDoc } from \"./NoopCrdtDoc\";\n\nexport class NoopCrdtDocFactory extends AbstractCrdtDocFactory<any, {}, {}, {}> {\n public getEmpty(): NoopCrdtDoc {\n return new NoopCrdtDoc();\n }\n\n public getFactory(_seed?: {}): NoopCrdtDocFactory {\n return this;\n }\n\n public getInitialized(_seed?: {}): NoopCrdtDoc {\n return new NoopCrdtDoc();\n }\n}\n","import { NoopCrdtDocFactory } from \"./NoopCrdtDocFactory\";\n\nexport const noop = {\n doc: (args?: any) => new NoopCrdtDocFactory(),\n kind: \"noop\" as const,\n};\n","export class CrdtSchemaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CrdtSchemaError\";\n }\n}\n","export const JSON_KINDS = [\n \"string\",\n \"number\",\n \"boolean\",\n \"null\",\n \"literal\",\n \"enum\",\n \"array\",\n \"object\",\n \"record\",\n \"union\",\n \"intersection\",\n \"discriminatedUnion\",\n \"optional\",\n] as const;\n\nexport type JsonSchemaKind = (typeof JSON_KINDS)[number];\n\nexport const YJS_CRDT_KINDS = [\n \"yArray\",\n \"yMap\",\n \"yText\",\n \"yXmlText\",\n \"yXmlElement\",\n \"yXmlFragment\",\n] as const;\n\nexport type YjsCrdtKind = (typeof YJS_CRDT_KINDS)[number];\n\nexport const LORO_CRDT_KINDS = [\n \"loroList\",\n \"loroMap\",\n \"loroText\",\n \"loroMovableList\",\n \"loroCounter\",\n \"loroTree\",\n] as const;\n\nexport type LoroCrdtKind = (typeof LORO_CRDT_KINDS)[number];\n\nexport const CRDT_KINDS = [...YJS_CRDT_KINDS, ...LORO_CRDT_KINDS] as const;\n\nexport type CrdtSchemaKind = (typeof CRDT_KINDS)[number];\n\nexport const DOC_KINDS = [\"y.doc\", \"loro.doc\"] as const;\n\nexport type DocSchemaKind = (typeof DOC_KINDS)[number];\n\nexport const isJsonKind = (kind: string): kind is JsonSchemaKind => {\n return (JSON_KINDS as readonly string[]).includes(kind);\n};\n\nexport const isYjsCrdtKind = (kind: string): kind is YjsCrdtKind => {\n return (YJS_CRDT_KINDS as readonly string[]).includes(kind);\n};\n\nexport const isLoroCrdtKind = (kind: string): kind is LoroCrdtKind => {\n return (LORO_CRDT_KINDS as readonly string[]).includes(kind);\n};\n\nexport const isCrdtKind = (kind: string): kind is CrdtSchemaKind => {\n return (CRDT_KINDS as readonly string[]).includes(kind);\n};\n\nexport const isXmlKind = (kind: string): boolean => {\n return kind === \"yXmlText\" || kind === \"yXmlElement\" || kind === \"yXmlFragment\";\n};\n\nexport const isUnseedableKind = (kind: string): boolean => {\n return isXmlKind(kind) || kind === \"loroTree\";\n};\n","import { CrdtSchemaError } from \"./error\";\nimport { isCrdtKind, isJsonKind } from \"./kinds\";\n\ndeclare const SchemaStorage: unique symbol;\ndeclare const SchemaJson: unique symbol;\ndeclare const SchemaSeed: unique symbol;\n\nexport type SchemaAst = {\n kind: string;\n [key: string]: unknown;\n};\n\nexport interface SchemaNode<\n TKind extends string = string,\n TStorage = unknown,\n TJson = unknown,\n TSeed = unknown,\n> {\n readonly kind: TKind;\n readonly [SchemaStorage]?: TStorage;\n readonly [SchemaJson]?: TJson;\n readonly [SchemaSeed]?: TSeed;\n toJSON(): SchemaAst;\n}\n\nexport type InferNodeStorage<T> =\n T extends SchemaNode<string, infer TStorage, unknown, unknown> ? TStorage : never;\n\nexport type InferNodeJson<T> =\n T extends SchemaNode<string, unknown, infer TJson, unknown> ? TJson : never;\n\nexport type InferNodeSeed<T> =\n T extends SchemaNode<string, unknown, unknown, infer TSeed> ? TSeed : never;\n\nexport type AnySchemaNode = SchemaNode<string, any, any, any>;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nexport const isSchemaNode = (value: unknown): value is AnySchemaNode => {\n return isRecord(value) && typeof value.kind === \"string\" && typeof value.toJSON === \"function\";\n};\n\nexport const toAst = (value: unknown): unknown => {\n if (isSchemaNode(value)) return value.toJSON();\n if (Array.isArray(value)) return value.map(toAst);\n if (isRecord(value)) {\n return Object.entries(value).reduce<Record<string, unknown>>((acc, [key, nested]) => {\n acc[key] = toAst(nested);\n return acc;\n }, {});\n }\n\n return value;\n};\n\nexport const createSchemaNode = <\n TKind extends string,\n TStorage,\n TJson,\n TSeed,\n TExtras extends Record<string, unknown>,\n>(\n kind: TKind,\n extras: TExtras,\n): SchemaNode<TKind, TStorage, TJson, TSeed> & TExtras => {\n const node = {\n kind,\n ...extras,\n toJSON(): SchemaAst {\n const json: SchemaAst = { kind };\n\n Object.entries(extras).forEach(([key, value]) => {\n json[key] = toAst(value);\n });\n\n return json;\n },\n };\n\n return node as SchemaNode<TKind, TStorage, TJson, TSeed> & TExtras;\n};\n\nexport const isJsonSchema = (node: AnySchemaNode): boolean => {\n if (node.kind === \"optional\") {\n const inner = (node as AnySchemaNode & { inner: AnySchemaNode }).inner;\n return isJsonSchema(inner);\n }\n\n if (\n node.kind === \"union\" ||\n node.kind === \"intersection\" ||\n node.kind === \"discriminatedUnion\"\n ) {\n const options = (node as AnySchemaNode & { options: readonly AnySchemaNode[] }).options;\n return options.every(isJsonSchema);\n }\n\n if (node.kind === \"array\") {\n return isJsonSchema((node as AnySchemaNode & { item: AnySchemaNode }).item);\n }\n\n if (node.kind === \"record\") {\n return isJsonSchema((node as AnySchemaNode & { value: AnySchemaNode }).value);\n }\n\n if (node.kind === \"object\") {\n const shape = (node as AnySchemaNode & { shape: Record<string, AnySchemaNode> }).shape;\n return Object.values(shape).every(isJsonSchema);\n }\n\n return isJsonKind(node.kind) && !isCrdtKind(node.kind);\n};\n\nexport const isOptionalNode = (\n node: AnySchemaNode,\n): node is AnySchemaNode & { kind: \"optional\"; inner: AnySchemaNode } => {\n return node.kind === \"optional\";\n};\n\nexport const unwrapOptional = (node: AnySchemaNode): AnySchemaNode => {\n return isOptionalNode(node) ? node.inner : node;\n};\n\nexport const assertJsonSchema = (node: AnySchemaNode, context: string): void => {\n if (!isJsonSchema(node)) {\n throw new CrdtSchemaError(`${context} must be a JSON schema`);\n }\n};\n\nexport const assertNotOptional = (node: AnySchemaNode, context: string): void => {\n if (isOptionalNode(node)) {\n throw new CrdtSchemaError(\n `${context} cannot be optional; s.$optional is only valid on s.object fields`,\n );\n }\n};\n\nexport const assertSchemaNode = (\n value: unknown,\n context: string,\n): asserts value is AnySchemaNode => {\n if (!isSchemaNode(value)) {\n throw new CrdtSchemaError(`${context} must be a schema node`);\n }\n};\n","import { CrdtSchemaError } from \"./error\";\nimport type {\n ArrayNode,\n DiscriminatedUnionNode,\n EnumNode,\n IntersectionNode,\n LiteralNode,\n ObjectNode,\n OptionalNode,\n RecordNode,\n UnionNode,\n} from \"./infer\";\nimport type { AnySchemaNode, SchemaAst } from \"./node\";\nimport {\n assertJsonSchema,\n assertNotOptional,\n createSchemaNode,\n isOptionalNode,\n isSchemaNode,\n unwrapOptional,\n} from \"./node\";\n\nconst flattenObjectShape = (\n node: AnySchemaNode,\n context: string,\n): Record<string, AnySchemaNode> => {\n if (node.kind === \"object\") {\n return (node as ObjectNode<Record<string, AnySchemaNode>>).shape;\n }\n\n if (node.kind === \"intersection\") {\n const options = (node as IntersectionNode<readonly AnySchemaNode[]>).options;\n\n return options.reduce<Record<string, AnySchemaNode>>((acc, option) => {\n const shape = flattenObjectShape(option, context);\n Object.entries(shape).forEach(([key, field]) => {\n if (\n key in acc &&\n JSON.stringify(acc[key]!.toJSON()) !== JSON.stringify(field.toJSON())\n ) {\n throw new CrdtSchemaError(`${context} has conflicting types for key \"${key}\"`);\n }\n acc[key] = field;\n });\n return acc;\n }, {});\n }\n\n throw new CrdtSchemaError(`${context} must be an s.object or s.$intersection of objects`);\n};\n\nconst assertObjectLike = (node: AnySchemaNode, context: string): void => {\n flattenObjectShape(node, context);\n};\n\nconst getDiscriminatorField = (node: AnySchemaNode, key: string): AnySchemaNode | null => {\n const shape = flattenObjectShape(node, `s.$discriminatedUnion branch`);\n const field = shape[key];\n\n if (!field) return null;\n\n const inner = unwrapOptional(field);\n\n if (inner.kind === \"literal\") return inner;\n if (inner.kind === \"enum\") {\n const values = (inner as EnumNode<string> & { values: readonly string[] }).values;\n if (values.length === 1) return inner;\n }\n\n return null;\n};\n\nexport const string = (): SchemaNodeLike<\"string\", string> => {\n return createSchemaNode<\"string\", string, string, string, {}>(\"string\", {});\n};\n\nexport const number = (): SchemaNodeLike<\"number\", number> => {\n return createSchemaNode<\"number\", number, number, number, {}>(\"number\", {});\n};\n\nexport const boolean = (): SchemaNodeLike<\"boolean\", boolean> => {\n return createSchemaNode<\"boolean\", boolean, boolean, boolean, {}>(\"boolean\", {});\n};\n\nexport const nullType = (): SchemaNodeLike<\"null\", null> => {\n return createSchemaNode<\"null\", null, null, null, {}>(\"null\", {});\n};\n\ntype SchemaNodeLike<TKind extends string, TValue> = import(\"./node\").SchemaNode<\n TKind,\n TValue,\n TValue,\n TValue\n>;\n\nexport const literal = <T extends string | number | boolean>(\n value: T,\n): LiteralNode<T> & { value: T } => {\n if (typeof value !== \"string\" && typeof value !== \"number\" && typeof value !== \"boolean\") {\n throw new CrdtSchemaError(\n \"s.literal only accepts JSON primitives (string, number, boolean)\",\n );\n }\n\n return createSchemaNode<\"literal\", T, T, T, { value: T }>(\"literal\", { value });\n};\n\nexport const enumType = <const TValues extends readonly string[]>(\n values: TValues,\n): EnumNode<TValues[number]> & { values: TValues } => {\n if (!values.length) {\n throw new CrdtSchemaError(\"s.enum requires at least one value\");\n }\n\n const unique = new Set(values);\n if (unique.size !== values.length) {\n throw new CrdtSchemaError(\"s.enum values must be unique\");\n }\n\n values.forEach((value) => {\n if (typeof value !== \"string\") {\n throw new CrdtSchemaError(\"s.enum values must be strings\");\n }\n });\n\n return createSchemaNode<\n \"enum\",\n TValues[number],\n TValues[number],\n TValues[number],\n { values: TValues }\n >(\"enum\", { values });\n};\n\nexport const array = <TItem extends AnySchemaNode>(\n item: TItem,\n): ArrayNode<TItem> & { item: TItem } => {\n assertNotOptional(item, \"s.array item\");\n assertJsonSchema(item, \"s.array item\");\n\n return createSchemaNode(\"array\", { item }) as ArrayNode<TItem> & { item: TItem };\n};\n\nexport const object = <TShape extends Record<string, AnySchemaNode>>(\n shape: TShape,\n): ObjectNode<TShape> => {\n Object.entries(shape).forEach(([key, field]) => {\n if (!isSchemaNode(field)) {\n throw new CrdtSchemaError(`s.object field \"${key}\" must be a schema node`);\n }\n\n const inner = unwrapOptional(field);\n assertJsonSchema(inner, `s.object field \"${key}\"`);\n });\n\n return createSchemaNode(\"object\", { shape }) as ObjectNode<TShape>;\n};\n\nexport const record = <TValue extends AnySchemaNode>(\n value: TValue,\n): RecordNode<TValue> & { value: TValue } => {\n assertNotOptional(value, \"s.record value\");\n assertJsonSchema(value, \"s.record value\");\n\n return createSchemaNode(\"record\", { value }) as RecordNode<TValue> & { value: TValue };\n};\n\nexport const $union = <const TOptions extends readonly AnySchemaNode[]>(\n options: TOptions,\n): UnionNode<TOptions> => {\n if (options.length < 2) {\n throw new CrdtSchemaError(\"s.$union requires at least two options\");\n }\n\n options.forEach((option, index) => {\n assertNotOptional(option, `s.$union option[${index}]`);\n if (!isSchemaNode(option)) {\n throw new CrdtSchemaError(`s.$union option[${index}] must be a schema node`);\n }\n });\n\n return createSchemaNode(\"union\", { options }) as UnionNode<TOptions>;\n};\n\nexport const $intersection = <const TOptions extends readonly AnySchemaNode[]>(\n options: TOptions,\n): IntersectionNode<TOptions> => {\n if (options.length < 2) {\n throw new CrdtSchemaError(\"s.$intersection requires at least two options\");\n }\n\n options.forEach((option, index) => {\n assertNotOptional(option, `s.$intersection option[${index}]`);\n assertJsonSchema(option, `s.$intersection option[${index}]`);\n assertObjectLike(option, `s.$intersection option[${index}]`);\n });\n\n flattenObjectShape(\n createSchemaNode(\"intersection\", { options }) as AnySchemaNode,\n \"s.$intersection\",\n );\n\n return createSchemaNode(\"intersection\", { options }) as IntersectionNode<TOptions>;\n};\n\nexport const $discriminatedUnion = <\n TKey extends string,\n const TOptions extends readonly AnySchemaNode[],\n>(\n key: TKey,\n options: TOptions,\n): DiscriminatedUnionNode<TKey, TOptions> => {\n if (options.length < 2) {\n throw new CrdtSchemaError(\"s.$discriminatedUnion requires at least two options\");\n }\n\n const tags = new Set<unknown>();\n\n options.forEach((option, index) => {\n assertNotOptional(option, `s.$discriminatedUnion option[${index}]`);\n assertJsonSchema(option, `s.$discriminatedUnion option[${index}]`);\n assertObjectLike(option, `s.$discriminatedUnion option[${index}]`);\n\n const field = getDiscriminatorField(option, key);\n\n if (!field) {\n throw new CrdtSchemaError(\n `s.$discriminatedUnion option[${index}] must have a literal (or single-value enum) field \"${key}\"`,\n );\n }\n\n const tag =\n field.kind === \"literal\"\n ? (field as LiteralNode<string | number | boolean> & { value: unknown }).value\n : (field as EnumNode<string> & { values: readonly string[] }).values[0];\n\n if (tags.has(tag)) {\n throw new CrdtSchemaError(`s.$discriminatedUnion has duplicate tag \"${String(tag)}\"`);\n }\n\n tags.add(tag);\n });\n\n return createSchemaNode(\"discriminatedUnion\", {\n discriminator: key,\n options,\n }) as DiscriminatedUnionNode<TKey, TOptions>;\n};\n\nexport const $nullable = <TInner extends AnySchemaNode>(\n inner: TInner,\n): UnionNode<readonly [TInner, SchemaNodeLike<\"null\", null>]> => {\n assertNotOptional(inner, \"s.$nullable\");\n\n return $union([inner, nullType()] as const);\n};\n\nexport const $optional = <TInner extends AnySchemaNode>(inner: TInner): OptionalNode<TInner> => {\n if (isOptionalNode(inner)) {\n throw new CrdtSchemaError(\"s.$optional cannot wrap another s.$optional\");\n }\n\n assertJsonSchema(inner, \"s.$optional\");\n\n return createSchemaNode(\"optional\", { inner }) as OptionalNode<TInner>;\n};\n\nexport const s = {\n string,\n number,\n boolean,\n null: nullType,\n literal,\n enum: enumType,\n array,\n object,\n record,\n $union,\n $discriminatedUnion,\n $intersection,\n $nullable,\n $optional,\n};\n\nconst fromJSONUnknown = (ast: SchemaAst): AnySchemaNode => {\n switch (ast.kind) {\n case \"string\":\n return string();\n case \"number\":\n return number();\n case \"boolean\":\n return boolean();\n case \"null\":\n return nullType();\n case \"literal\":\n return literal(ast.value as string | number | boolean);\n case \"enum\":\n return enumType(ast.values as readonly string[]);\n case \"array\":\n return array(fromJSONUnknown(ast.item as SchemaAst));\n case \"object\": {\n const shape = Object.entries((ast.shape as Record<string, SchemaAst>) ?? {}).reduce<\n Record<string, AnySchemaNode>\n >((acc, [key, value]) => {\n acc[key] = fromJSONUnknown(value);\n return acc;\n }, {});\n return object(shape);\n }\n case \"record\":\n return record(fromJSONUnknown(ast.value as SchemaAst));\n case \"union\":\n return $union(\n (ast.options as SchemaAst[]).map(\n fromJSONUnknown,\n ) as unknown as readonly AnySchemaNode[],\n );\n case \"intersection\":\n return $intersection(\n (ast.options as SchemaAst[]).map(\n fromJSONUnknown,\n ) as unknown as readonly AnySchemaNode[],\n );\n case \"discriminatedUnion\":\n return $discriminatedUnion(\n ast.discriminator as string,\n (ast.options as SchemaAst[]).map(\n fromJSONUnknown,\n ) as unknown as readonly AnySchemaNode[],\n );\n case \"optional\":\n return $optional(fromJSONUnknown(ast.inner as SchemaAst));\n default:\n throw new CrdtSchemaError(`Unknown JSON schema kind \"${ast.kind}\"`);\n }\n};\n\nexport const fromJSON = fromJSONUnknown;\n","import { CrdtSchemaError } from \"./error\";\nimport { isUnseedableKind } from \"./kinds\";\nimport type { AnySchemaNode } from \"./node\";\nimport { isOptionalNode, unwrapOptional } from \"./node\";\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nexport const flattenObjectShape = (node: AnySchemaNode): Record<string, AnySchemaNode> => {\n if (node.kind === \"object\") {\n return (node as AnySchemaNode & { shape: Record<string, AnySchemaNode> }).shape;\n }\n\n if (node.kind === \"intersection\") {\n const options = (node as AnySchemaNode & { options: readonly AnySchemaNode[] }).options;\n\n return options.reduce<Record<string, AnySchemaNode>>((acc, option) => {\n const shape = flattenObjectShape(option);\n Object.entries(shape).forEach(([key, field]) => {\n acc[key] = field;\n });\n return acc;\n }, {});\n }\n\n throw new CrdtSchemaError(`Expected an object schema, received \"${node.kind}\"`);\n};\n\nconst matchesLiteralOrEnum = (node: AnySchemaNode, value: unknown): boolean => {\n if (node.kind === \"literal\") {\n return (node as AnySchemaNode & { value: unknown }).value === value;\n }\n\n if (node.kind === \"enum\") {\n const values = (node as AnySchemaNode & { values: readonly unknown[] }).values;\n return values.includes(value);\n }\n\n return false;\n};\n\nexport const validateJson = (node: AnySchemaNode, value: unknown): boolean => {\n const current = unwrapOptional(node);\n\n switch (current.kind) {\n case \"string\":\n return typeof value === \"string\";\n case \"number\":\n return typeof value === \"number\" && Number.isFinite(value);\n case \"boolean\":\n return typeof value === \"boolean\";\n case \"null\":\n return value === null;\n case \"literal\":\n return (current as AnySchemaNode & { value: unknown }).value === value;\n case \"enum\":\n return (current as AnySchemaNode & { values: readonly unknown[] }).values.includes(\n value,\n );\n case \"array\": {\n if (!Array.isArray(value)) return false;\n const item = (current as AnySchemaNode & { item: AnySchemaNode }).item;\n return value.every((entry) => validateJson(item, entry));\n }\n case \"object\": {\n if (!isPlainObject(value)) return false;\n const shape = (current as AnySchemaNode & { shape: Record<string, AnySchemaNode> })\n .shape;\n const extra = Object.keys(value).filter((key) => !(key in shape));\n if (extra.length) return false;\n\n return Object.entries(shape).every(([key, field]) => {\n if (!(key in value)) return isOptionalNode(field);\n return validateJson(field, value[key]);\n });\n }\n case \"record\": {\n if (!isPlainObject(value)) return false;\n const field = (current as AnySchemaNode & { value: AnySchemaNode }).value;\n return Object.values(value).every((entry) => validateJson(field, entry));\n }\n case \"union\": {\n const options = (current as AnySchemaNode & { options: readonly AnySchemaNode[] })\n .options;\n return options.some((option) => validateJson(option, value));\n }\n case \"intersection\": {\n try {\n const shape = flattenObjectShape(current);\n return validateJson({ ...current, kind: \"object\", shape } as AnySchemaNode, value);\n } catch {\n return false;\n }\n }\n case \"discriminatedUnion\": {\n if (!isPlainObject(value)) return false;\n const discriminator = (current as AnySchemaNode & { discriminator: string })\n .discriminator;\n const options = (current as AnySchemaNode & { options: readonly AnySchemaNode[] })\n .options;\n const tag = value[discriminator];\n const option = options.find((branch) => {\n const field = flattenObjectShape(branch)[discriminator];\n return field ? matchesLiteralOrEnum(unwrapOptional(field), tag) : false;\n });\n return option ? validateJson(option, value) : false;\n }\n default:\n if (isUnseedableKind(current.kind)) return false;\n if (current.kind === \"yText\" || current.kind === \"loroText\")\n return typeof value === \"string\";\n if (current.kind === \"loroCounter\")\n return typeof value === \"number\" && Number.isFinite(value);\n if (\n current.kind === \"yArray\" ||\n current.kind === \"loroList\" ||\n current.kind === \"loroMovableList\"\n ) {\n return Array.isArray(value);\n }\n if (current.kind === \"yMap\" || current.kind === \"loroMap\") {\n return isPlainObject(value);\n }\n return false;\n }\n};\n\nexport const assertJsonValue = (node: AnySchemaNode, value: unknown, context: string): void => {\n if (validateJson(node, value)) return;\n\n throw new CrdtSchemaError(`${context} does not match schema kind \"${node.kind}\"`);\n};\n\nexport const pickUnionOption = (node: AnySchemaNode, value: unknown): AnySchemaNode | null => {\n if (node.kind === \"union\") {\n const options = (node as AnySchemaNode & { options: readonly AnySchemaNode[] }).options;\n return options.find((option) => canHydrate(option, value)) ?? null;\n }\n\n if (node.kind === \"discriminatedUnion\") {\n if (!isPlainObject(value)) return null;\n const discriminator = (node as AnySchemaNode & { discriminator: string }).discriminator;\n const options = (node as AnySchemaNode & { options: readonly AnySchemaNode[] }).options;\n const tag = value[discriminator];\n\n return (\n options.find((branch) => {\n const field = flattenObjectShape(branch)[discriminator];\n return field ? matchesLiteralOrEnum(unwrapOptional(field), tag) : false;\n }) ?? null\n );\n }\n\n return node;\n};\n\nexport const canHydrate = (node: AnySchemaNode, value: unknown): boolean => {\n const current = unwrapOptional(node);\n\n if (current.kind === \"union\" || current.kind === \"discriminatedUnion\") {\n return pickUnionOption(current, value) !== null;\n }\n\n return validateJson(current, value);\n};\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pluv/crdt",
|
|
3
|
+
"version": "0.0.0-canary-20261027014949",
|
|
4
|
+
"description": "crdt base for @pluv/io",
|
|
5
|
+
"author": {
|
|
6
|
+
"email": "david@pluv.io",
|
|
7
|
+
"name": "i3dly",
|
|
8
|
+
"url": "https://github.com/i3dly"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"homepage": "https://github.com/pluv-io/pluv",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/pluv-io/pluv.git",
|
|
15
|
+
"directory": "packages/crdt"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"types": "./dist/index.d.mts",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@pluv/types": "^0.0.0-canary-20261027014949"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@pluv/tsconfig": "^0.0.0-canary-20261027014949",
|
|
30
|
+
"tsdown": "^0.23.2",
|
|
31
|
+
"typescript": "7.1.0-beta",
|
|
32
|
+
"vitest": "^5.0.5"
|
|
33
|
+
},
|
|
34
|
+
"exports": {
|
|
35
|
+
".": "./dist/index.mjs",
|
|
36
|
+
"./*": "./*"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsdown",
|
|
40
|
+
"dev": "tsdown --watch",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:watch": "vitest",
|
|
44
|
+
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
45
|
+
}
|
|
46
|
+
}
|