jazz-tools 0.7.0-alpha.6 → 0.7.0-alpha.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/coValues/account.js +62 -29
  3. package/dist/coValues/account.js.map +1 -1
  4. package/dist/coValues/coList.js +139 -89
  5. package/dist/coValues/coList.js.map +1 -1
  6. package/dist/coValues/coMap.js +135 -151
  7. package/dist/coValues/coMap.js.map +1 -1
  8. package/dist/coValues/coStream.js +131 -57
  9. package/dist/coValues/coStream.js.map +1 -1
  10. package/dist/coValues/extensions/imageDef.js +10 -7
  11. package/dist/coValues/extensions/imageDef.js.map +1 -1
  12. package/dist/coValues/group.js +8 -30
  13. package/dist/coValues/group.js.map +1 -1
  14. package/dist/coValues/interfaces.js +6 -2
  15. package/dist/coValues/interfaces.js.map +1 -1
  16. package/dist/implementation/encoding.js +21 -0
  17. package/dist/implementation/encoding.js.map +1 -1
  18. package/dist/implementation/refs.js +10 -9
  19. package/dist/implementation/refs.js.map +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/tests/coList.test.js +5 -9
  23. package/dist/tests/coList.test.js.map +1 -1
  24. package/dist/tests/coMap.test.js +99 -36
  25. package/dist/tests/coMap.test.js.map +1 -1
  26. package/dist/tests/coStream.test.js +46 -51
  27. package/dist/tests/coStream.test.js.map +1 -1
  28. package/package.json +2 -2
  29. package/src/coValues/account.ts +82 -52
  30. package/src/coValues/coList.ts +170 -107
  31. package/src/coValues/coMap.ts +196 -230
  32. package/src/coValues/coStream.ts +169 -91
  33. package/src/coValues/extensions/imageDef.ts +7 -11
  34. package/src/coValues/group.ts +16 -63
  35. package/src/coValues/interfaces.ts +9 -8
  36. package/src/implementation/encoding.ts +55 -16
  37. package/src/implementation/refs.ts +12 -10
  38. package/src/index.ts +1 -1
  39. package/src/tests/coList.test.ts +5 -9
  40. package/src/tests/coMap.test.ts +77 -51
  41. package/src/tests/coStream.test.ts +61 -66
@@ -22,7 +22,14 @@ import type {
22
22
  SubclassedConstructor,
23
23
  UnavailableError,
24
24
  } from "../internal.js";
25
- import { CoValueBase, Profile, Ref, inspect } from "../internal.js";
25
+ import {
26
+ CoValueBase,
27
+ Profile,
28
+ Ref,
29
+ SchemaInit,
30
+ inspect,
31
+ subscriptionsScopes,
32
+ } from "../internal.js";
26
33
  import type { Stream } from "effect/Stream";
27
34
 
28
35
  export class Account<
@@ -72,30 +79,30 @@ export class Account<
72
79
  ? Ref<NonNullable<Def["root"]>> | null
73
80
  : null;
74
81
  } {
75
- const profileID = this._raw.get("profile") as unknown as ID<
76
- NonNullable<Def["profile"]>
77
- > | undefined;
82
+ const profileID = this._raw.get("profile") as unknown as
83
+ | ID<NonNullable<Def["profile"]>>
84
+ | undefined;
78
85
  const rootID = this._raw.get("root") as unknown as
79
86
  | ID<NonNullable<Def["root"]>>
80
87
  | undefined;
81
88
  return {
82
- profile: profileID && (new Ref(
83
- profileID,
84
- this._loadedAs,
85
- (
89
+ profile:
90
+ profileID &&
91
+ (new Ref(
92
+ profileID,
93
+ this._loadedAs,
86
94
  this._encoding.profile as RefEncoded<
87
95
  NonNullable<Def["profile"]> & CoValue
88
96
  >
89
- ).ref()
90
- )) as any,
97
+ ) as any),
91
98
  root:
92
99
  rootID &&
93
100
  (new Ref(
94
101
  rootID,
95
102
  this._loadedAs,
96
- (
97
- this._encoding.root as RefEncoded<NonNullable<Def["root"]> & CoValue>
98
- ).ref()
103
+ this._encoding.root as RefEncoded<
104
+ NonNullable<Def["root"]> & CoValue
105
+ >
99
106
  ) as any),
100
107
  };
101
108
  }
@@ -128,40 +135,17 @@ export class Account<
128
135
  enumerable: false,
129
136
  },
130
137
  _raw: { value: options.fromRaw, enumerable: false },
131
- profile: {
132
- get: () => {
133
- const ref = this._refs.profile;
134
- return ref ? ref.accessFrom(this) : (undefined as any);
135
- },
136
- set: (value: Def["profile"] | null) => {
137
- if (value) {
138
- this._raw.set(
139
- "profile",
140
- value.id as unknown as CoID<RawCoMap>
141
- );
142
- }
143
- },
144
- },
145
- root: {
146
- get: () => {
147
- const ref = this._refs.root;
148
- return ref ? ref.accessFrom(this) : (undefined as any);
149
- },
150
- set: (value: Def["root"] | null) => {
151
- if (value) {
152
- this._raw.set(
153
- "root",
154
- value.id as unknown as CoID<RawCoMap>
155
- );
156
- }
157
- },
158
- },
159
138
  });
160
139
 
161
140
  if (this.isMe) {
162
141
  (this as Account & Me).sessionID =
163
142
  options.fromRaw.core.node.currentSessionID;
164
143
  }
144
+
145
+ return new Proxy(
146
+ this,
147
+ AccountAndGroupProxyHandler as ProxyHandler<this>
148
+ );
165
149
  }
166
150
 
167
151
  myRole(): "admin" | undefined {
@@ -263,20 +247,66 @@ export class Account<
263
247
  return this.toJSON();
264
248
  }
265
249
 
266
- static encoding<V extends Account>(
267
- this: { new (...args: any[]): V } & CoValueClass<V> & { _encoding: any },
268
- fields: {
269
- profile: V["_encoding"]["profile"];
270
- root: V["_encoding"]["root"];
271
- }
272
- ) {
273
- this._encoding ||= {};
274
- Object.assign(this._encoding, fields);
275
- }
276
-
277
250
  migrate: (() => void | Promise<void>) | undefined;
278
251
  }
279
252
 
253
+ export const AccountAndGroupProxyHandler: ProxyHandler<Account | Group> = {
254
+ get(target, key, receiver) {
255
+ if (key === "profile") {
256
+ const ref = target._refs.profile;
257
+ return ref ? ref.accessFrom(receiver) : (undefined as any);
258
+ } else if (key === "root") {
259
+ const ref = target._refs.root;
260
+ return ref ? ref.accessFrom(receiver) : (undefined as any);
261
+ } else {
262
+ return Reflect.get(target, key, receiver);
263
+ }
264
+ },
265
+ set(target, key, value, receiver) {
266
+ if (
267
+ (key === "profile" || key === "root") &&
268
+ typeof value === "object" &&
269
+ SchemaInit in value
270
+ ) {
271
+ (target.constructor as typeof CoMap)._encoding ||= {};
272
+ (target.constructor as typeof CoMap)._encoding[key] =
273
+ value[SchemaInit];
274
+ return true;
275
+ } else if (key === "profile") {
276
+ if (value) {
277
+ target._raw.set(
278
+ "profile",
279
+ value.id as unknown as CoID<RawCoMap>
280
+ );
281
+ }
282
+ subscriptionsScopes.get(receiver)?.onRefAccessedOrSet(value.id);
283
+ return true;
284
+ } else if (key === "root") {
285
+ if (value) {
286
+ target._raw.set("root", value.id as unknown as CoID<RawCoMap>);
287
+ }
288
+ subscriptionsScopes.get(receiver)?.onRefAccessedOrSet(value.id);
289
+ return true;
290
+ } else {
291
+ return Reflect.set(target, key, value, receiver);
292
+ }
293
+ },
294
+ defineProperty(target, key, descriptor) {
295
+ if (
296
+ (key === "profile" || key === "root") &&
297
+ typeof descriptor.value === "object" &&
298
+ SchemaInit in descriptor.value
299
+ ) {
300
+ (target.constructor as typeof CoMap)._encoding ||= {};
301
+ (target.constructor as typeof CoMap)._encoding[key] =
302
+ descriptor.value[SchemaInit];
303
+ return true;
304
+ } else {
305
+ return Reflect.defineProperty(target, key, descriptor);
306
+ }
307
+ },
308
+ };
309
+
280
310
  export interface Me {
281
311
  id: ID<any>;
282
312
  isMe: true;
@@ -11,21 +11,39 @@ import type {
11
11
  RefEncoded,
12
12
  SubclassedConstructor,
13
13
  UnavailableError,
14
+ IsVal,
14
15
  } from "../internal.js";
15
16
  import {
16
17
  Account,
17
18
  CoValueBase,
18
19
  Group,
20
+ InitValues,
21
+ ItemsSym,
19
22
  Ref,
23
+ SchemaInit,
24
+ val,
20
25
  inspect,
21
26
  makeRefs,
22
27
  } from "../internal.js";
23
28
  import { Schema } from "@effect/schema";
24
29
 
25
- export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
30
+ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
26
31
  extends Array<Item>
27
32
  implements CoValue<"CoList", RawCoList>
28
33
  {
34
+ static Of<Item extends ValidItem<Item, "CoList"> = any>(
35
+ item: IsVal<Item, Item>
36
+ ): typeof CoList<Item> {
37
+ return class CoListOf extends CoList<Item> {
38
+ [val.items] = item;
39
+ };
40
+ }
41
+
42
+ /** @deprecated Use UPPERCASE `CoList.Of` instead! */
43
+ static of(..._args: never): never {
44
+ throw new Error("Can't use Array.of with CoLists");
45
+ }
46
+
29
47
  id!: ID<this>;
30
48
  _type!: "CoList";
31
49
  static {
@@ -33,9 +51,11 @@ export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
33
51
  }
34
52
  _raw!: RawCoList;
35
53
 
54
+ /** @internal This is only a marker type and doesn't exist at runtime */
55
+ [ItemsSym]!: Item;
36
56
  static _encoding: any;
37
57
  get _encoding(): {
38
- _item: EncodingFor<Item>;
58
+ [ItemsSym]: EncodingFor<Item>;
39
59
  } {
40
60
  return (this.constructor as typeof CoList)._encoding;
41
61
  }
@@ -53,9 +73,7 @@ export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
53
73
  } & {
54
74
  length: number;
55
75
  [Symbol.iterator](): IterableIterator<
56
- NonNullable<Item> extends CoValue
57
- ? Ref<NonNullable<Item>>
58
- : never
76
+ NonNullable<Item> extends CoValue ? Ref<NonNullable<Item>> : never
59
77
  >;
60
78
  } {
61
79
  return makeRefs<number>(
@@ -66,7 +84,7 @@ export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
66
84
  (_, idx) => idx
67
85
  ),
68
86
  this._loadedAs,
69
- (_idx) => (this._encoding._item as RefEncoded<CoValue>).ref()
87
+ (_idx) => this._encoding[ItemsSym] as RefEncoded<CoValue>
70
88
  ) as any;
71
89
  }
72
90
 
@@ -85,71 +103,53 @@ export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
85
103
  return Account.fromNode(this._raw.core.node);
86
104
  }
87
105
 
106
+ [InitValues]?: {
107
+ init: Item[];
108
+ owner: Account | Group;
109
+ };
110
+
111
+ static get [Symbol.species]() {
112
+ return Array;
113
+ }
114
+
88
115
  constructor(_init: undefined, options: { fromRaw: RawCoList });
89
116
  constructor(init: Item[], options: { owner: Account | Group });
90
- constructor(init: number);
91
117
  constructor(
92
- init: Item[] | undefined | number,
118
+ init: Item[] | undefined,
93
119
  options?: { owner: Account | Group } | { fromRaw: RawCoList }
94
120
  ) {
95
- if (typeof init === "number") {
96
- // this might be called from an intrinsic, like map, trying to create an empty array
97
- // passing `0` as the only parameter
98
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
- return new Array(init) as any;
100
- }
101
-
102
121
  super();
103
122
 
104
123
  if (!options) {
105
124
  throw new Error("Must provide options");
106
125
  }
107
126
 
108
- let raw: RawCoList;
109
-
110
- if ("fromRaw" in options) {
111
- raw = options.fromRaw;
112
- } else {
113
- const rawOwner = options.owner._raw;
114
-
115
- const rawInit = init && this.toRawItems(init);
116
-
117
- raw = rawOwner.createList(rawInit);
127
+ if (init && "owner" in options) {
128
+ this[InitValues] = {
129
+ init,
130
+ owner: options.owner,
131
+ };
132
+ } else if ("fromRaw" in options) {
133
+ Object.defineProperties(this, {
134
+ id: {
135
+ value: options.fromRaw.id,
136
+ enumerable: false,
137
+ },
138
+ _raw: { value: options.fromRaw, enumerable: false },
139
+ });
118
140
  }
119
141
 
120
- Object.defineProperties(this, {
121
- id: {
122
- value: raw.id,
123
- enumerable: false,
124
- },
125
- _raw: { value: raw, enumerable: false },
126
- });
127
-
128
- return new Proxy(this, CoListProxyHandler<Item>(this._encoding._item));
129
- }
130
-
131
- private toRawItems(items: Item[]) {
132
- const itemDescriptor = this._encoding._item as Encoding;
133
- const rawItems =
134
- itemDescriptor === "json"
135
- ? items
136
- : "encoded" in itemDescriptor
137
- ? items?.map((e) =>
138
- Schema.encodeSync(itemDescriptor.encoded)(e)
139
- )
140
- : "ref" in itemDescriptor
141
- ? items?.map((v) => (v as unknown as CoValue).id)
142
- : (() => {
143
- throw new Error("Invalid element descriptor");
144
- })();
145
- return rawItems;
142
+ return new Proxy(this, CoListProxyHandler as ProxyHandler<this>);
146
143
  }
147
144
 
148
145
  push(...items: Item[]): number;
149
146
  /** @private For exact type compatibility with Array superclass */
150
147
  push(...items: Item[]): number;
151
148
  push(...items: Item[]): number {
152
- for (const item of this.toRawItems(items as Item[])) {
149
+ for (const item of toRawItems(
150
+ items as Item[],
151
+ this._encoding[ItemsSym]
152
+ )) {
153
153
  this._raw.append(item);
154
154
  }
155
155
 
@@ -160,7 +160,10 @@ export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
160
160
  /** @private For exact type compatibility with Array superclass */
161
161
  unshift(...items: Item[]): number;
162
162
  unshift(...items: Item[]): number {
163
- for (const item of this.toRawItems(items as Item[])) {
163
+ for (const item of toRawItems(
164
+ items as Item[],
165
+ this._encoding[ItemsSym]
166
+ )) {
164
167
  this._raw.prepend(item);
165
168
  }
166
169
 
@@ -197,7 +200,10 @@ export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
197
200
  }
198
201
 
199
202
  let appendAfter = start;
200
- for (const item of this.toRawItems(items as Item[])) {
203
+ for (const item of toRawItems(
204
+ items as Item[],
205
+ this._encoding[ItemsSym]
206
+ )) {
201
207
  this._raw.append(item, appendAfter);
202
208
  appendAfter++;
203
209
  }
@@ -206,7 +212,7 @@ export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
206
212
  }
207
213
 
208
214
  toJSON() {
209
- const itemDescriptor = this._encoding._item as Encoding;
215
+ const itemDescriptor = this._encoding[ItemsSym] as Encoding;
210
216
  if (itemDescriptor === "json") {
211
217
  return this._raw.asArray();
212
218
  } else if ("encoded" in itemDescriptor) {
@@ -265,63 +271,120 @@ export class CoList<Item extends ValidItem<Item, "Co.List"> = any>
265
271
 
266
272
  static encoding<V extends CoList>(
267
273
  this: { new (...args: any): V } & typeof CoList,
268
- def: { _item: V["_encoding"]["_item"] }
274
+ def: { [ItemsSym]: V["_encoding"][ItemsSym] }
269
275
  ) {
270
276
  this._encoding ||= {};
271
277
  Object.assign(this._encoding, def);
272
278
  }
273
279
  }
274
280
 
275
- function CoListProxyHandler<Item extends ValidItem<Item, "Co.List">>(
276
- itemDescriptor: Encoding
277
- ): ProxyHandler<CoList<Item>> {
278
- return {
279
- get(target, key, receiver) {
280
- if (typeof key === "string" && !isNaN(+key)) {
281
- const rawValue = target._raw.get(Number(key));
282
- if (itemDescriptor === "json") {
283
- return rawValue;
284
- } else if ("encoded" in itemDescriptor) {
285
- return rawValue === undefined
286
- ? undefined
287
- : Schema.decodeSync(itemDescriptor.encoded)(rawValue);
288
- } else if ("ref" in itemDescriptor) {
289
- return rawValue === undefined
290
- ? undefined
291
- : new Ref(
292
- rawValue as unknown as ID<CoValue>,
293
- target._loadedAs,
294
- itemDescriptor.ref()
295
- ).accessFrom(receiver);
296
- }
297
- } else if (key === "length") {
298
- return target._raw.entries().length;
299
- } else {
300
- return Reflect.get(target, key, receiver);
301
- }
302
- },
303
- set(target, key, value, receiver) {
304
- if (typeof key === "string" && !isNaN(+key)) {
305
- let rawValue;
306
- if (itemDescriptor === "json") {
307
- rawValue = value;
308
- } else if ("encoded" in itemDescriptor) {
309
- rawValue = Schema.encodeSync(itemDescriptor.encoded)(value);
310
- } else if ("ref" in itemDescriptor) {
311
- rawValue = value.id;
312
- }
313
- target._raw.replace(Number(key), rawValue);
314
- return true;
315
- } else {
316
- return Reflect.set(target, key, value, receiver);
281
+ function toRawItems<Item>(items: Item[], itemDescriptor: Encoding) {
282
+ const rawItems =
283
+ itemDescriptor === "json"
284
+ ? items
285
+ : "encoded" in itemDescriptor
286
+ ? items?.map((e) => Schema.encodeSync(itemDescriptor.encoded)(e))
287
+ : "ref" in itemDescriptor
288
+ ? items?.map((v) => (v as unknown as CoValue).id)
289
+ : (() => {
290
+ throw new Error("Invalid element descriptor");
291
+ })();
292
+ return rawItems;
293
+ }
294
+
295
+ function init(list: CoList) {
296
+ if (list[InitValues]) {
297
+ const { init, owner } = list[InitValues];
298
+ const raw = owner._raw.createList(
299
+ toRawItems(init, list._encoding[ItemsSym])
300
+ );
301
+
302
+ Object.defineProperties(list, {
303
+ id: {
304
+ value: raw.id,
305
+ enumerable: false,
306
+ },
307
+ _raw: { value: raw, enumerable: false },
308
+ });
309
+ delete list[InitValues];
310
+ }
311
+ }
312
+
313
+ const CoListProxyHandler: ProxyHandler<CoList> = {
314
+ get(target, key, receiver) {
315
+ if (typeof key === "string" && !isNaN(+key)) {
316
+ const itemDescriptor = target._encoding[ItemsSym] as Encoding;
317
+ const rawValue = target._raw.get(Number(key));
318
+ if (itemDescriptor === "json") {
319
+ return rawValue;
320
+ } else if ("encoded" in itemDescriptor) {
321
+ return rawValue === undefined
322
+ ? undefined
323
+ : Schema.decodeSync(itemDescriptor.encoded)(rawValue);
324
+ } else if ("ref" in itemDescriptor) {
325
+ return rawValue === undefined
326
+ ? undefined
327
+ : new Ref(
328
+ rawValue as unknown as ID<CoValue>,
329
+ target._loadedAs,
330
+ itemDescriptor
331
+ ).accessFrom(receiver);
317
332
  }
318
- },
319
- has(target, key) {
320
- if (typeof key === "string" && !isNaN(+key)) {
321
- return Number(key) < target._raw.entries().length;
322
- } else {
323
- return Reflect.has(target, key);
333
+ } else if (key === "length") {
334
+ return target._raw.entries().length;
335
+ } else {
336
+ return Reflect.get(target, key, receiver);
337
+ }
338
+ },
339
+ set(target, key, value, receiver) {
340
+ if (
341
+ key === ItemsSym &&
342
+ typeof value === "object" &&
343
+ SchemaInit in value
344
+ ) {
345
+ (target.constructor as typeof CoList)._encoding ||= {};
346
+ (target.constructor as typeof CoList)._encoding[ItemsSym] =
347
+ value[SchemaInit];
348
+ init(target);
349
+ return true;
350
+ }
351
+ if (typeof key === "string" && !isNaN(+key)) {
352
+ const itemDescriptor = target._encoding[ItemsSym] as Encoding;
353
+ let rawValue;
354
+ if (itemDescriptor === "json") {
355
+ rawValue = value;
356
+ } else if ("encoded" in itemDescriptor) {
357
+ rawValue = Schema.encodeSync(itemDescriptor.encoded)(value);
358
+ } else if ("ref" in itemDescriptor) {
359
+ rawValue = value.id;
324
360
  }
325
- },
326
- };
327
- }
361
+ target._raw.replace(Number(key), rawValue);
362
+ return true;
363
+ } else {
364
+ return Reflect.set(target, key, value, receiver);
365
+ }
366
+ },
367
+ defineProperty(target, key, descriptor) {
368
+ if (
369
+ descriptor.value &&
370
+ key === ItemsSym &&
371
+ typeof descriptor.value === "object" &&
372
+ SchemaInit in descriptor.value
373
+ ) {
374
+ (target.constructor as typeof CoList)._encoding ||= {};
375
+ (target.constructor as typeof CoList)._encoding[ItemsSym] =
376
+ descriptor.value[SchemaInit];
377
+ init(target);
378
+ return true;
379
+ } else {
380
+ return Reflect.defineProperty(target, key, descriptor);
381
+ }
382
+ },
383
+ has(target, key) {
384
+ if (typeof key === "string" && !isNaN(+key)) {
385
+ return Number(key) < target._raw.entries().length;
386
+ } else {
387
+ return Reflect.has(target, key);
388
+ }
389
+ },
390
+ };