jazz-tools 0.7.0-alpha.9 → 0.7.3
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/.eslintrc.cjs +3 -10
- package/.prettierrc.js +9 -0
- package/.turbo/turbo-build.log +14 -15
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +140 -0
- package/CHANGELOG.md +331 -27
- package/LICENSE.txt +1 -1
- package/README.md +10 -2
- package/dist/coValues/account.js +86 -41
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js +75 -48
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js +167 -44
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.js +192 -35
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/coValues/deepLoading.js +60 -0
- package/dist/coValues/deepLoading.js.map +1 -0
- package/dist/coValues/extensions/imageDef.js +10 -7
- package/dist/coValues/extensions/imageDef.js.map +1 -1
- package/dist/coValues/group.js +73 -13
- package/dist/coValues/group.js.map +1 -1
- package/dist/coValues/interfaces.js +58 -35
- package/dist/coValues/interfaces.js.map +1 -1
- package/dist/implementation/devtoolsFormatters.js +114 -0
- package/dist/implementation/devtoolsFormatters.js.map +1 -0
- package/dist/implementation/refs.js +58 -18
- package/dist/implementation/refs.js.map +1 -1
- package/dist/implementation/schema.js +58 -0
- package/dist/implementation/schema.js.map +1 -0
- package/dist/implementation/subscriptionScope.js +19 -1
- package/dist/implementation/subscriptionScope.js.map +1 -1
- package/dist/implementation/symbols.js +5 -0
- package/dist/implementation/symbols.js.map +1 -0
- package/dist/index.js +4 -5
- package/dist/index.js.map +1 -1
- package/dist/internal.js +5 -2
- package/dist/internal.js.map +1 -1
- package/dist/tests/coList.test.js +51 -48
- package/dist/tests/coList.test.js.map +1 -1
- package/dist/tests/coMap.test.js +131 -74
- package/dist/tests/coMap.test.js.map +1 -1
- package/dist/tests/coStream.test.js +56 -41
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/deepLoading.test.js +188 -0
- package/dist/tests/deepLoading.test.js.map +1 -0
- package/dist/tests/groupsAndAccounts.test.js +83 -0
- package/dist/tests/groupsAndAccounts.test.js.map +1 -0
- package/package.json +17 -9
- package/src/coValues/account.ts +186 -128
- package/src/coValues/coList.ts +156 -107
- package/src/coValues/coMap.ts +272 -148
- package/src/coValues/coStream.ts +388 -87
- package/src/coValues/deepLoading.ts +229 -0
- package/src/coValues/extensions/imageDef.ts +17 -13
- package/src/coValues/group.ts +166 -59
- package/src/coValues/interfaces.ts +189 -160
- package/src/implementation/devtoolsFormatters.ts +110 -0
- package/src/implementation/inspect.ts +1 -1
- package/src/implementation/refs.ts +80 -28
- package/src/implementation/schema.ts +141 -0
- package/src/implementation/subscriptionScope.ts +48 -12
- package/src/implementation/symbols.ts +11 -0
- package/src/index.ts +19 -8
- package/src/internal.ts +7 -3
- package/src/tests/coList.test.ts +77 -62
- package/src/tests/coMap.test.ts +201 -114
- package/src/tests/coStream.test.ts +113 -84
- package/src/tests/deepLoading.test.ts +304 -0
- package/src/tests/groupsAndAccounts.test.ts +91 -0
- package/dist/implementation/encoding.js +0 -26
- package/dist/implementation/encoding.js.map +0 -1
- package/src/implementation/encoding.ts +0 -105
package/src/coValues/coMap.ts
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
import type { JsonValue, RawCoMap } from "cojson";
|
2
2
|
import type { Simplify } from "effect/Types";
|
3
|
-
import {
|
3
|
+
import { encodeSync, decodeSync } from "@effect/schema/Schema";
|
4
4
|
import type {
|
5
5
|
CoValue,
|
6
|
-
|
7
|
-
EncodingFor,
|
6
|
+
Schema,
|
8
7
|
Group,
|
9
8
|
ID,
|
10
9
|
RefEncoded,
|
11
|
-
|
12
|
-
|
10
|
+
IfCo,
|
11
|
+
RefIfCoValue,
|
12
|
+
DepthsIn,
|
13
|
+
DeeplyLoaded,
|
14
|
+
UnavailableError,
|
15
|
+
AccountCtx,
|
16
|
+
CoValueClass,
|
13
17
|
} from "../internal.js";
|
14
18
|
import {
|
15
19
|
Account,
|
@@ -21,161 +25,193 @@ import {
|
|
21
25
|
subscriptionsScopes,
|
22
26
|
ItemsSym,
|
23
27
|
InitValues,
|
28
|
+
isRefEncoded,
|
29
|
+
loadCoValue,
|
30
|
+
loadCoValueEf,
|
31
|
+
subscribeToCoValue,
|
32
|
+
subscribeToCoValueEf,
|
33
|
+
ensureCoValueLoaded,
|
34
|
+
subscribeToExistingCoValue,
|
24
35
|
} from "../internal.js";
|
25
|
-
|
26
|
-
type ValidFields<Fields extends { [key: string]: any; [ItemsSym]?: any }> = {
|
27
|
-
[Key in keyof Fields & string as IsVal<
|
28
|
-
Fields[Key],
|
29
|
-
IfOptionalKey<Key, Fields>
|
30
|
-
>]?: EnsureCoValueNullable<Fields[Key], Key>;
|
31
|
-
} & {
|
32
|
-
[Key in keyof Fields & string as IsVal<
|
33
|
-
Fields[Key],
|
34
|
-
IfRequiredKey<Key, Fields>
|
35
|
-
>]: EnsureCoValueNullable<Fields[Key], Key>;
|
36
|
-
} & {
|
37
|
-
[Key in ItemsSym]?: EnsureCoValueNullable<Fields[ItemsSym], Key>;
|
38
|
-
};
|
39
|
-
|
40
|
-
type IfOptionalKey<Key extends keyof Obj, Obj> = Pick<
|
41
|
-
Partial<Obj>,
|
42
|
-
Key
|
43
|
-
> extends Pick<Obj, Key>
|
44
|
-
? Key
|
45
|
-
: never;
|
46
|
-
type IfRequiredKey<Key extends keyof Obj, Obj> = Pick<
|
47
|
-
Partial<Obj>,
|
48
|
-
Key
|
49
|
-
> extends Pick<Obj, Key>
|
50
|
-
? never
|
51
|
-
: Key;
|
52
|
-
|
53
|
-
type DefaultFields = {
|
54
|
-
[key: string]: any;
|
55
|
-
[ItemsSym]?: any;
|
56
|
-
};
|
57
|
-
|
58
|
-
type CoMapEncoding<Fields extends object> = {
|
59
|
-
[Key in OwnKeys<Fields> as IsVal<Fields[Key], Key>]: EncodingFor<
|
60
|
-
Fields[Key]
|
61
|
-
>;
|
62
|
-
} &
|
63
|
-
{
|
64
|
-
[ItemsSym]: ItemsSym extends keyof Fields ? EncodingFor<Fields[ItemsSym]> : never;
|
65
|
-
}
|
36
|
+
import { Effect, Stream } from "effect";
|
66
37
|
|
67
38
|
type CoMapEdit<V> = {
|
68
39
|
value?: V;
|
69
|
-
ref?:
|
40
|
+
ref?: RefIfCoValue<V>;
|
70
41
|
by?: Account;
|
71
42
|
madeAt: Date;
|
72
|
-
}
|
43
|
+
};
|
73
44
|
|
74
45
|
type InitValuesFor<C extends CoMap> = {
|
75
46
|
init: Simplify<CoMapInit<C>>;
|
76
47
|
owner: Account | Group;
|
77
|
-
}
|
48
|
+
};
|
78
49
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
50
|
+
/**
|
51
|
+
* CoMaps are collaborative versions of plain objects, mapping string-like keys to values.
|
52
|
+
*
|
53
|
+
* @categoryDescription Declaration
|
54
|
+
* Declare your own CoMap schemas by subclassing `CoMap` and assigning field schemas with `co`.
|
55
|
+
*
|
56
|
+
* ```ts
|
57
|
+
* import { co, CoMap } from "jazz-tools";
|
58
|
+
*
|
59
|
+
* class Person extends CoMap {
|
60
|
+
* name = co.string;
|
61
|
+
* age = co.number;
|
62
|
+
* pet = co.ref(Animal);
|
63
|
+
* }
|
64
|
+
* ```
|
65
|
+
*
|
66
|
+
* @categoryDescription Content
|
67
|
+
* You can access properties you declare on a `CoMap` (using `co`) as if they were normal properties on a plain object, using dot notation, `Object.keys()`, etc.
|
68
|
+
*
|
69
|
+
* ```ts
|
70
|
+
* person.name;
|
71
|
+
* person["age"];
|
72
|
+
* person.age = 42;
|
73
|
+
* person.pet?.name;
|
74
|
+
* Object.keys(person);
|
75
|
+
* // => ["name", "age", "pet"]
|
76
|
+
* ```
|
77
|
+
*
|
78
|
+
* @category CoValues
|
79
|
+
* */
|
80
|
+
export class CoMap extends CoValueBase implements CoValue {
|
81
|
+
/**
|
82
|
+
* The ID of this `CoMap`
|
83
|
+
* @category Content */
|
84
|
+
declare id: ID<this>;
|
85
|
+
/** @category Type Helpers */
|
86
|
+
declare _type: "CoMap";
|
85
87
|
static {
|
86
88
|
this.prototype._type = "CoMap";
|
87
89
|
}
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
/** @category Internals */
|
91
|
+
declare _raw: RawCoMap;
|
92
|
+
|
93
|
+
/** @internal */
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
95
|
+
static _schema: any;
|
96
|
+
/** @internal */
|
97
|
+
get _schema() {
|
98
|
+
return (this.constructor as typeof CoMap)._schema as {
|
99
|
+
[key: string]: Schema;
|
100
|
+
} & { [ItemsSym]?: Schema };
|
93
101
|
}
|
94
102
|
|
103
|
+
/**
|
104
|
+
* If property `prop` is a `co.ref(...)`, you can use `coMaps._refs.prop` to access
|
105
|
+
* the `Ref` instead of the potentially loaded/null value.
|
106
|
+
* This allows you to always get the ID or load the value manually.
|
107
|
+
*
|
108
|
+
* @example
|
109
|
+
* ```ts
|
110
|
+
* person._refs.pet.id; // => ID<Animal>
|
111
|
+
* person._refs.pet.value;
|
112
|
+
* // => Animal | undefined
|
113
|
+
* const pet = await person._refs.pet.load();
|
114
|
+
* ```
|
115
|
+
*
|
116
|
+
* @category Content */
|
95
117
|
get _refs(): {
|
96
|
-
[Key in
|
97
|
-
? Key
|
98
|
-
: never]: NonNullable<this[Key]> extends CoValue
|
99
|
-
? Ref<NonNullable<this[Key]>>
|
100
|
-
: never;
|
118
|
+
[Key in CoKeys<this>]: IfCo<this[Key], RefIfCoValue<this[Key]>>;
|
101
119
|
} {
|
102
|
-
return makeRefs<
|
120
|
+
return makeRefs<CoKeys<this>>(
|
103
121
|
(key) => this._raw.get(key as string) as unknown as ID<CoValue>,
|
104
|
-
() =>
|
105
|
-
|
106
|
-
const schema =
|
107
|
-
key as keyof typeof this.
|
108
|
-
|
109
|
-
schema !== "json" &&
|
110
|
-
}) as
|
122
|
+
() => {
|
123
|
+
const keys = this._raw.keys().filter((key) => {
|
124
|
+
const schema =
|
125
|
+
this._schema[key as keyof typeof this._schema] ||
|
126
|
+
(this._schema[ItemsSym] as Schema | undefined);
|
127
|
+
return schema && schema !== "json" && isRefEncoded(schema);
|
128
|
+
}) as CoKeys<this>[];
|
129
|
+
|
130
|
+
return keys;
|
131
|
+
},
|
111
132
|
this._loadedAs,
|
112
|
-
(key) =>
|
133
|
+
(key) =>
|
134
|
+
(this._schema[key] ||
|
135
|
+
this._schema[ItemsSym]) as RefEncoded<CoValue>,
|
136
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
113
137
|
) as any;
|
114
138
|
}
|
115
139
|
|
140
|
+
/** @category Collaboration */
|
116
141
|
get _edits() {
|
117
142
|
return new Proxy(this, {
|
118
143
|
get(target, key) {
|
119
144
|
const rawEdit = target._raw.lastEditAt(key as string);
|
120
145
|
if (!rawEdit) return undefined;
|
121
146
|
|
122
|
-
const descriptor = target.
|
123
|
-
key as keyof typeof target.
|
124
|
-
] as
|
147
|
+
const descriptor = target._schema[
|
148
|
+
key as keyof typeof target._schema
|
149
|
+
] as Schema;
|
125
150
|
|
126
151
|
return {
|
127
152
|
value:
|
128
153
|
descriptor === "json"
|
129
154
|
? rawEdit.value
|
130
155
|
: "encoded" in descriptor
|
131
|
-
?
|
132
|
-
rawEdit.value
|
133
|
-
)
|
156
|
+
? decodeSync(descriptor.encoded)(rawEdit.value)
|
134
157
|
: new Ref(
|
135
158
|
rawEdit.value as ID<CoValue>,
|
136
159
|
target._loadedAs,
|
137
|
-
descriptor
|
138
|
-
).accessFrom(
|
160
|
+
descriptor,
|
161
|
+
).accessFrom(
|
162
|
+
target,
|
163
|
+
"_edits." + key.toString() + ".value",
|
164
|
+
),
|
139
165
|
ref:
|
140
|
-
descriptor !== "json" &&
|
166
|
+
descriptor !== "json" && isRefEncoded(descriptor)
|
141
167
|
? new Ref(
|
142
168
|
rawEdit.value as ID<CoValue>,
|
143
169
|
target._loadedAs,
|
144
|
-
descriptor
|
170
|
+
descriptor,
|
145
171
|
)
|
146
172
|
: undefined,
|
147
173
|
by:
|
148
174
|
rawEdit.by &&
|
149
|
-
new Ref
|
150
|
-
|
151
|
-
|
175
|
+
new Ref<Account>(
|
176
|
+
rawEdit.by as ID<Account>,
|
177
|
+
target._loadedAs,
|
178
|
+
{
|
179
|
+
ref: Account,
|
180
|
+
optional: false,
|
181
|
+
},
|
182
|
+
).accessFrom(
|
183
|
+
target,
|
184
|
+
"_edits." + key.toString() + ".by",
|
185
|
+
),
|
152
186
|
madeAt: rawEdit.at,
|
153
187
|
};
|
154
188
|
},
|
155
189
|
}) as {
|
156
|
-
[Key in
|
190
|
+
[Key in CoKeys<this>]: IfCo<this[Key], CoMapEdit<this[Key]>>;
|
157
191
|
};
|
158
192
|
}
|
159
193
|
|
194
|
+
/** @internal */
|
160
195
|
get _loadedAs() {
|
161
196
|
return Account.fromNode(this._raw.core.node);
|
162
197
|
}
|
163
198
|
|
164
|
-
|
199
|
+
/** @internal */
|
200
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
201
|
+
[InitValues]?: any;
|
165
202
|
|
166
|
-
|
167
|
-
constructor(
|
168
|
-
init: Simplify<CoMapInit<Fields>>,
|
169
|
-
options: { owner: Account | Group }
|
170
|
-
);
|
203
|
+
/** @internal */
|
171
204
|
constructor(
|
172
|
-
|
173
|
-
options: {
|
205
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
206
|
+
options: { fromRaw: RawCoMap } | { init: any; owner: Account | Group },
|
174
207
|
) {
|
175
208
|
super();
|
176
209
|
|
177
|
-
if (
|
178
|
-
this[InitValues] = {
|
210
|
+
if ("owner" in options) {
|
211
|
+
this[InitValues] = {
|
212
|
+
init: options.init,
|
213
|
+
owner: options.owner,
|
214
|
+
} as InitValuesFor<this>;
|
179
215
|
} else if ("fromRaw" in options) {
|
180
216
|
Object.defineProperties(this, {
|
181
217
|
id: {
|
@@ -191,14 +227,25 @@ export class CoMap<Fields extends ValidFields<Fields> = DefaultFields>
|
|
191
227
|
return new Proxy(this, CoMapProxyHandler as ProxyHandler<this>);
|
192
228
|
}
|
193
229
|
|
230
|
+
/** @category Creation */
|
231
|
+
static create<M extends CoMap>(
|
232
|
+
this: CoValueClass<M>,
|
233
|
+
init: Simplify<CoMapInit<M>>,
|
234
|
+
options: { owner: Account | Group },
|
235
|
+
) {
|
236
|
+
return new this({ init, owner: options.owner });
|
237
|
+
}
|
238
|
+
|
194
239
|
toJSON() {
|
195
240
|
const jsonedFields = this._raw.keys().map((key) => {
|
196
|
-
const tKey = key as
|
197
|
-
const descriptor = this.
|
241
|
+
const tKey = key as CoKeys<this>;
|
242
|
+
const descriptor = (this._schema[tKey] ||
|
243
|
+
this._schema[ItemsSym]) as Schema;
|
198
244
|
|
199
245
|
if (descriptor == "json" || "encode" in descriptor) {
|
200
246
|
return [key, this._raw.get(key)];
|
201
|
-
} else if (
|
247
|
+
} else if (isRefEncoded(descriptor)) {
|
248
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
202
249
|
const jsonedRef = (this as any)[tKey]?.toJSON();
|
203
250
|
return [key, jsonedRef];
|
204
251
|
} else {
|
@@ -217,9 +264,11 @@ export class CoMap<Fields extends ValidFields<Fields> = DefaultFields>
|
|
217
264
|
return this.toJSON();
|
218
265
|
}
|
219
266
|
|
267
|
+
/** @internal */
|
268
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
220
269
|
rawFromInit<Fields extends object = Record<string, any>>(
|
221
270
|
init: Simplify<CoMapInit<Fields>> | undefined,
|
222
|
-
owner: Account | Group
|
271
|
+
owner: Account | Group,
|
223
272
|
) {
|
224
273
|
const rawOwner = owner._raw;
|
225
274
|
|
@@ -231,51 +280,119 @@ export class CoMap<Fields extends ValidFields<Fields> = DefaultFields>
|
|
231
280
|
for (const key of Object.keys(init) as (keyof Fields)[]) {
|
232
281
|
const initValue = init[key as keyof typeof init];
|
233
282
|
|
234
|
-
const descriptor = (this.
|
235
|
-
key as keyof typeof this.
|
236
|
-
] || this.
|
283
|
+
const descriptor = (this._schema[
|
284
|
+
key as keyof typeof this._schema
|
285
|
+
] || this._schema[ItemsSym]) as Schema;
|
237
286
|
|
238
287
|
if (descriptor === "json") {
|
239
288
|
rawInit[key] = initValue as JsonValue;
|
240
|
-
} else if (
|
289
|
+
} else if (isRefEncoded(descriptor)) {
|
241
290
|
if (initValue) {
|
242
291
|
rawInit[key] = (initValue as unknown as CoValue).id;
|
243
292
|
}
|
244
293
|
} else if ("encoded" in descriptor) {
|
245
|
-
rawInit[key] =
|
246
|
-
|
294
|
+
rawInit[key] = encodeSync(descriptor.encoded)(
|
295
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
296
|
+
initValue as any,
|
247
297
|
);
|
248
298
|
}
|
249
299
|
}
|
250
300
|
|
251
301
|
return rawOwner.createMap(rawInit);
|
252
302
|
}
|
303
|
+
|
304
|
+
/** @category Declaration */
|
305
|
+
static Record<Value>(value: IfCo<Value, Value>) {
|
306
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
307
|
+
class RecordLikeCoMap extends CoMap {
|
308
|
+
[ItemsSym] = value;
|
309
|
+
}
|
310
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
311
|
+
interface RecordLikeCoMap extends Record<string, Value> {}
|
312
|
+
|
313
|
+
return RecordLikeCoMap;
|
314
|
+
}
|
315
|
+
|
316
|
+
/** @category Subscription & Loading */
|
317
|
+
static load<M extends CoMap, Depth>(
|
318
|
+
this: CoValueClass<M>,
|
319
|
+
id: ID<M>,
|
320
|
+
as: Account,
|
321
|
+
depth: Depth & DepthsIn<M>,
|
322
|
+
): Promise<DeeplyLoaded<M, Depth> | undefined> {
|
323
|
+
return loadCoValue(this, id, as, depth);
|
324
|
+
}
|
325
|
+
|
326
|
+
/** @category Subscription & Loading */
|
327
|
+
static loadEf<M extends CoMap, Depth>(
|
328
|
+
this: CoValueClass<M>,
|
329
|
+
id: ID<M>,
|
330
|
+
depth: Depth & DepthsIn<M>,
|
331
|
+
): Effect.Effect<DeeplyLoaded<M, Depth>, UnavailableError, AccountCtx> {
|
332
|
+
return loadCoValueEf<M, Depth>(this, id, depth);
|
333
|
+
}
|
334
|
+
|
335
|
+
/** @category Subscription & Loading */
|
336
|
+
static subscribe<M extends CoMap, Depth>(
|
337
|
+
this: CoValueClass<M>,
|
338
|
+
id: ID<M>,
|
339
|
+
as: Account,
|
340
|
+
depth: Depth & DepthsIn<M>,
|
341
|
+
listener: (value: DeeplyLoaded<M, Depth>) => void,
|
342
|
+
): () => void {
|
343
|
+
return subscribeToCoValue<M, Depth>(this, id, as, depth, listener);
|
344
|
+
}
|
345
|
+
|
346
|
+
/** @category Subscription & Loading */
|
347
|
+
static subscribeEf<M extends CoMap, Depth>(
|
348
|
+
this: CoValueClass<M>,
|
349
|
+
id: ID<M>,
|
350
|
+
depth: Depth & DepthsIn<M>,
|
351
|
+
): Stream.Stream<DeeplyLoaded<M, Depth>, UnavailableError, AccountCtx> {
|
352
|
+
return subscribeToCoValueEf<M, Depth>(this, id, depth);
|
353
|
+
}
|
354
|
+
|
355
|
+
/** @category Subscription & Loading */
|
356
|
+
ensureLoaded<M extends CoMap, Depth>(
|
357
|
+
this: M,
|
358
|
+
depth: Depth & DepthsIn<M>,
|
359
|
+
): Promise<DeeplyLoaded<M, Depth> | undefined> {
|
360
|
+
return ensureCoValueLoaded(this, depth);
|
361
|
+
}
|
362
|
+
|
363
|
+
/** @category Subscription & Loading */
|
364
|
+
subscribe<M extends CoMap, Depth>(
|
365
|
+
this: M,
|
366
|
+
depth: Depth & DepthsIn<M>,
|
367
|
+
listener: (value: DeeplyLoaded<M, Depth>) => void,
|
368
|
+
): () => void {
|
369
|
+
return subscribeToExistingCoValue(this, depth, listener);
|
370
|
+
}
|
253
371
|
}
|
254
372
|
|
255
|
-
export type
|
256
|
-
keyof
|
257
|
-
keyof CoMap
|
373
|
+
export type CoKeys<Map extends object> = Exclude<
|
374
|
+
keyof Map & string,
|
375
|
+
keyof CoMap
|
258
376
|
>;
|
259
377
|
|
260
|
-
export type CoMapInit<
|
261
|
-
[Key in
|
378
|
+
export type CoMapInit<Map extends object> = {
|
379
|
+
[Key in CoKeys<Map> as undefined extends Map[Key]
|
262
380
|
? never
|
263
|
-
:
|
264
|
-
|
265
|
-
: IsVal<Fields[Key], Key>]: Fields[Key];
|
266
|
-
} & { [Key in OwnKeys<Fields> as IsVal<Fields[Key], Key>]?: Fields[Key] };
|
381
|
+
: IfCo<Map[Key], Key>]: Map[Key];
|
382
|
+
} & { [Key in CoKeys<Map> as IfCo<Map[Key], Key>]?: Map[Key] };
|
267
383
|
|
268
384
|
function tryInit(map: CoMap) {
|
269
385
|
if (
|
270
386
|
map[InitValues] &&
|
271
|
-
(map.
|
387
|
+
(map._schema[ItemsSym] ||
|
272
388
|
Object.keys(map[InitValues].init).every(
|
273
|
-
|
389
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
390
|
+
(key) => (map._schema as any)[key],
|
274
391
|
))
|
275
392
|
) {
|
276
393
|
const raw = map.rawFromInit(
|
277
394
|
map[InitValues].init,
|
278
|
-
map[InitValues].owner
|
395
|
+
map[InitValues].owner,
|
279
396
|
);
|
280
397
|
Object.defineProperties(map, {
|
281
398
|
id: {
|
@@ -291,14 +408,13 @@ function tryInit(map: CoMap) {
|
|
291
408
|
// TODO: cache handlers per descriptor for performance?
|
292
409
|
const CoMapProxyHandler: ProxyHandler<CoMap> = {
|
293
410
|
get(target, key, receiver) {
|
294
|
-
if (key === "
|
411
|
+
if (key === "_schema") {
|
295
412
|
return Reflect.get(target, key);
|
296
413
|
} else if (key in target) {
|
297
414
|
return Reflect.get(target, key, receiver);
|
298
415
|
} else {
|
299
|
-
const descriptor = (target.
|
300
|
-
|
301
|
-
] || target._encoding[ItemsSym]) as Encoding;
|
416
|
+
const descriptor = (target._schema[key as keyof CoMap["_schema"]] ||
|
417
|
+
target._schema[ItemsSym]) as Schema;
|
302
418
|
if (descriptor && typeof key === "string") {
|
303
419
|
const raw = target._raw.get(key);
|
304
420
|
|
@@ -307,15 +423,15 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
|
|
307
423
|
} else if ("encoded" in descriptor) {
|
308
424
|
return raw === undefined
|
309
425
|
? undefined
|
310
|
-
:
|
311
|
-
} else if (
|
426
|
+
: decodeSync(descriptor.encoded)(raw);
|
427
|
+
} else if (isRefEncoded(descriptor)) {
|
312
428
|
return raw === undefined
|
313
429
|
? undefined
|
314
430
|
: new Ref(
|
315
431
|
raw as unknown as ID<CoValue>,
|
316
432
|
target._loadedAs,
|
317
|
-
descriptor
|
318
|
-
).accessFrom(receiver);
|
433
|
+
descriptor,
|
434
|
+
).accessFrom(receiver, key);
|
319
435
|
}
|
320
436
|
} else {
|
321
437
|
return undefined;
|
@@ -328,26 +444,25 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
|
|
328
444
|
typeof value === "object" &&
|
329
445
|
SchemaInit in value
|
330
446
|
) {
|
331
|
-
(target.constructor as typeof CoMap).
|
332
|
-
(target.constructor as typeof CoMap).
|
447
|
+
(target.constructor as typeof CoMap)._schema ||= {};
|
448
|
+
(target.constructor as typeof CoMap)._schema[key] =
|
333
449
|
value[SchemaInit];
|
334
450
|
tryInit(target);
|
335
451
|
return true;
|
336
452
|
}
|
337
453
|
|
338
|
-
const descriptor = (target.
|
339
|
-
target.
|
454
|
+
const descriptor = (target._schema[key as keyof CoMap["_schema"]] ||
|
455
|
+
target._schema[ItemsSym]) as Schema;
|
340
456
|
if (descriptor && typeof key === "string") {
|
341
457
|
if (descriptor === "json") {
|
342
458
|
target._raw.set(key, value);
|
343
459
|
} else if ("encoded" in descriptor) {
|
344
|
-
target._raw.set(
|
345
|
-
|
346
|
-
Schema.encodeSync(descriptor.encoded)(value)
|
347
|
-
);
|
348
|
-
} else if ("ref" in descriptor) {
|
460
|
+
target._raw.set(key, encodeSync(descriptor.encoded)(value));
|
461
|
+
} else if (isRefEncoded(descriptor)) {
|
349
462
|
target._raw.set(key, value.id);
|
350
|
-
subscriptionsScopes
|
463
|
+
subscriptionsScopes
|
464
|
+
.get(target)
|
465
|
+
?.onRefAccessedOrSet(target.id, value.id);
|
351
466
|
}
|
352
467
|
return true;
|
353
468
|
} else {
|
@@ -360,8 +475,8 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
|
|
360
475
|
typeof attributes.value === "object" &&
|
361
476
|
SchemaInit in attributes.value
|
362
477
|
) {
|
363
|
-
(target.constructor as typeof CoMap).
|
364
|
-
(target.constructor as typeof CoMap).
|
478
|
+
(target.constructor as typeof CoMap)._schema ||= {};
|
479
|
+
(target.constructor as typeof CoMap)._schema[key as string] =
|
365
480
|
attributes.value[SchemaInit];
|
366
481
|
tryInit(target);
|
367
482
|
return true;
|
@@ -371,11 +486,11 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
|
|
371
486
|
},
|
372
487
|
ownKeys(target) {
|
373
488
|
const keys = Reflect.ownKeys(target).filter((k) => k !== ItemsSym);
|
374
|
-
for (const key of Reflect.ownKeys(target.
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
}
|
489
|
+
// for (const key of Reflect.ownKeys(target._schema)) {
|
490
|
+
// if (key !== ItemsSym && !keys.includes(key)) {
|
491
|
+
// keys.push(key);
|
492
|
+
// }
|
493
|
+
// }
|
379
494
|
for (const key of target._raw.keys()) {
|
380
495
|
if (!keys.includes(key)) {
|
381
496
|
keys.push(key);
|
@@ -388,9 +503,8 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
|
|
388
503
|
if (key in target) {
|
389
504
|
return Reflect.getOwnPropertyDescriptor(target, key);
|
390
505
|
} else {
|
391
|
-
const descriptor = (target.
|
392
|
-
|
393
|
-
] || target._encoding[ItemsSym]) as Encoding;
|
506
|
+
const descriptor = (target._schema[key as keyof CoMap["_schema"]] ||
|
507
|
+
target._schema[ItemsSym]) as Schema;
|
394
508
|
if (descriptor || key in target._raw.ops) {
|
395
509
|
return {
|
396
510
|
enumerable: true,
|
@@ -400,4 +514,14 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
|
|
400
514
|
}
|
401
515
|
}
|
402
516
|
},
|
517
|
+
deleteProperty(target, key) {
|
518
|
+
const descriptor = (target._schema[key as keyof CoMap["_schema"]] ||
|
519
|
+
target._schema[ItemsSym]) as Schema;
|
520
|
+
if (typeof key === "string" && descriptor) {
|
521
|
+
target._raw.delete(key);
|
522
|
+
return true;
|
523
|
+
} else {
|
524
|
+
return Reflect.deleteProperty(target, key);
|
525
|
+
}
|
526
|
+
},
|
403
527
|
};
|