jazz-tools 0.7.0-alpha.9 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. package/.eslintrc.cjs +3 -10
  2. package/.prettierrc.js +9 -0
  3. package/.turbo/turbo-build.log +14 -15
  4. package/.turbo/turbo-lint.log +4 -0
  5. package/.turbo/turbo-test.log +140 -0
  6. package/CHANGELOG.md +331 -27
  7. package/LICENSE.txt +1 -1
  8. package/README.md +10 -2
  9. package/dist/coValues/account.js +86 -41
  10. package/dist/coValues/account.js.map +1 -1
  11. package/dist/coValues/coList.js +75 -48
  12. package/dist/coValues/coList.js.map +1 -1
  13. package/dist/coValues/coMap.js +167 -44
  14. package/dist/coValues/coMap.js.map +1 -1
  15. package/dist/coValues/coStream.js +192 -35
  16. package/dist/coValues/coStream.js.map +1 -1
  17. package/dist/coValues/deepLoading.js +60 -0
  18. package/dist/coValues/deepLoading.js.map +1 -0
  19. package/dist/coValues/extensions/imageDef.js +10 -7
  20. package/dist/coValues/extensions/imageDef.js.map +1 -1
  21. package/dist/coValues/group.js +73 -13
  22. package/dist/coValues/group.js.map +1 -1
  23. package/dist/coValues/interfaces.js +58 -35
  24. package/dist/coValues/interfaces.js.map +1 -1
  25. package/dist/implementation/devtoolsFormatters.js +114 -0
  26. package/dist/implementation/devtoolsFormatters.js.map +1 -0
  27. package/dist/implementation/refs.js +58 -18
  28. package/dist/implementation/refs.js.map +1 -1
  29. package/dist/implementation/schema.js +58 -0
  30. package/dist/implementation/schema.js.map +1 -0
  31. package/dist/implementation/subscriptionScope.js +19 -1
  32. package/dist/implementation/subscriptionScope.js.map +1 -1
  33. package/dist/implementation/symbols.js +5 -0
  34. package/dist/implementation/symbols.js.map +1 -0
  35. package/dist/index.js +4 -5
  36. package/dist/index.js.map +1 -1
  37. package/dist/internal.js +5 -2
  38. package/dist/internal.js.map +1 -1
  39. package/dist/tests/coList.test.js +51 -48
  40. package/dist/tests/coList.test.js.map +1 -1
  41. package/dist/tests/coMap.test.js +131 -74
  42. package/dist/tests/coMap.test.js.map +1 -1
  43. package/dist/tests/coStream.test.js +56 -41
  44. package/dist/tests/coStream.test.js.map +1 -1
  45. package/dist/tests/deepLoading.test.js +188 -0
  46. package/dist/tests/deepLoading.test.js.map +1 -0
  47. package/dist/tests/groupsAndAccounts.test.js +83 -0
  48. package/dist/tests/groupsAndAccounts.test.js.map +1 -0
  49. package/package.json +17 -9
  50. package/src/coValues/account.ts +186 -128
  51. package/src/coValues/coList.ts +156 -107
  52. package/src/coValues/coMap.ts +272 -148
  53. package/src/coValues/coStream.ts +388 -87
  54. package/src/coValues/deepLoading.ts +229 -0
  55. package/src/coValues/extensions/imageDef.ts +17 -13
  56. package/src/coValues/group.ts +166 -59
  57. package/src/coValues/interfaces.ts +189 -160
  58. package/src/implementation/devtoolsFormatters.ts +110 -0
  59. package/src/implementation/inspect.ts +1 -1
  60. package/src/implementation/refs.ts +80 -28
  61. package/src/implementation/schema.ts +141 -0
  62. package/src/implementation/subscriptionScope.ts +48 -12
  63. package/src/implementation/symbols.ts +11 -0
  64. package/src/index.ts +19 -8
  65. package/src/internal.ts +7 -3
  66. package/src/tests/coList.test.ts +77 -62
  67. package/src/tests/coMap.test.ts +201 -114
  68. package/src/tests/coStream.test.ts +113 -84
  69. package/src/tests/deepLoading.test.ts +304 -0
  70. package/src/tests/groupsAndAccounts.test.ts +91 -0
  71. package/dist/implementation/encoding.js +0 -26
  72. package/dist/implementation/encoding.js.map +0 -1
  73. package/src/implementation/encoding.ts +0 -105
@@ -1,41 +1,47 @@
1
1
  import type { RawCoList } from "cojson";
2
2
  import { RawAccount } from "cojson";
3
- import type { Effect, Stream } from "effect";
4
3
  import type {
5
- AccountCtx,
6
4
  CoValue,
7
- ValidItem,
8
- Encoding,
9
- EncodingFor,
5
+ Schema,
6
+ SchemaFor,
10
7
  ID,
11
8
  RefEncoded,
12
- SubclassedConstructor,
9
+ UnCo,
10
+ CoValueClass,
11
+ DepthsIn,
12
+ DeeplyLoaded,
13
13
  UnavailableError,
14
- IsVal,
14
+ AccountCtx,
15
+ CoValueFromRaw,
15
16
  } from "../internal.js";
16
17
  import {
17
18
  Account,
18
- CoValueBase,
19
19
  Group,
20
20
  InitValues,
21
21
  ItemsSym,
22
22
  Ref,
23
23
  SchemaInit,
24
- val,
24
+ co,
25
+ ensureCoValueLoaded,
25
26
  inspect,
27
+ isRefEncoded,
28
+ loadCoValue,
29
+ loadCoValueEf,
26
30
  makeRefs,
31
+ subscribeToCoValue,
32
+ subscribeToCoValueEf,
33
+ subscribeToExistingCoValue,
27
34
  } from "../internal.js";
28
- import { Schema } from "@effect/schema";
29
-
30
- export class CoList<Item extends ValidItem<Item, "CoList"> = any>
31
- extends Array<Item>
32
- implements CoValue<"CoList", RawCoList>
33
- {
34
- static Of<Item extends ValidItem<Item, "CoList"> = any>(
35
- item: IsVal<Item, Item>
36
- ): typeof CoList<Item> {
35
+ import { encodeSync, decodeSync } from "@effect/schema/Schema";
36
+ import { Effect, Stream } from "effect";
37
+
38
+ /** @category CoValues */
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ export class CoList<Item = any> extends Array<Item> implements CoValue {
41
+ static Of<Item>(item: Item): typeof CoList<Item> {
42
+ // TODO: cache superclass for item class
37
43
  return class CoListOf extends CoList<Item> {
38
- [val.items] = item;
44
+ [co.items] = item;
39
45
  };
40
46
  }
41
47
 
@@ -50,14 +56,16 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
50
56
  this.prototype._type = "CoList";
51
57
  }
52
58
  _raw!: RawCoList;
59
+ _instanceID!: string;
53
60
 
54
61
  /** @internal This is only a marker type and doesn't exist at runtime */
55
62
  [ItemsSym]!: Item;
56
- static _encoding: any;
57
- get _encoding(): {
58
- [ItemsSym]: EncodingFor<Item>;
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
+ static _schema: any;
65
+ get _schema(): {
66
+ [ItemsSym]: SchemaFor<Item>;
59
67
  } {
60
- return (this.constructor as typeof CoList)._encoding;
68
+ return (this.constructor as typeof CoList)._schema;
61
69
  }
62
70
 
63
71
  get _owner(): Account | Group {
@@ -66,14 +74,17 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
66
74
  : Group.fromRaw(this._raw.group);
67
75
  }
68
76
 
77
+ /** @category Content */
69
78
  get _refs(): {
70
- [idx: number]: NonNullable<Item> extends CoValue
71
- ? Ref<NonNullable<Item>>
79
+ [idx: number]: Exclude<Item, null> extends CoValue
80
+ ? Ref<UnCo<Exclude<Item, null>>>
72
81
  : never;
73
82
  } & {
74
83
  length: number;
75
84
  [Symbol.iterator](): IterableIterator<
76
- NonNullable<Item> extends CoValue ? Ref<NonNullable<Item>> : never
85
+ Exclude<Item, null> extends CoValue
86
+ ? Ref<Exclude<Item, null>>
87
+ : never
77
88
  >;
78
89
  } {
79
90
  return makeRefs<number>(
@@ -81,10 +92,11 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
81
92
  () =>
82
93
  Array.from(
83
94
  { length: this._raw.entries().length },
84
- (_, idx) => idx
95
+ (_, idx) => idx,
85
96
  ),
86
97
  this._loadedAs,
87
- (_idx) => this._encoding[ItemsSym] as RefEncoded<CoValue>
98
+ (_idx) => this._schema[ItemsSym] as RefEncoded<CoValue>,
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
100
  ) as any;
89
101
  }
90
102
 
@@ -103,30 +115,28 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
103
115
  return Account.fromNode(this._raw.core.node);
104
116
  }
105
117
 
106
- [InitValues]?: {
107
- init: Item[];
108
- owner: Account | Group;
109
- };
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ [InitValues]?: any;
110
120
 
111
121
  static get [Symbol.species]() {
112
122
  return Array;
113
123
  }
114
124
 
115
- constructor(_init: undefined, options: { fromRaw: RawCoList });
116
- constructor(init: Item[], options: { owner: Account | Group });
117
125
  constructor(
118
- init: Item[] | undefined,
119
- options?: { owner: Account | Group } | { fromRaw: RawCoList }
126
+ options:
127
+ | { init: Item[]; owner: Account | Group }
128
+ | { fromRaw: RawCoList },
120
129
  ) {
121
130
  super();
122
131
 
123
- if (!options) {
124
- throw new Error("Must provide options");
125
- }
132
+ Object.defineProperty(this, "_instanceID", {
133
+ value: `instance-${Math.random().toString(36).slice(2)}`,
134
+ enumerable: false,
135
+ });
126
136
 
127
- if (init && "owner" in options) {
137
+ if ("owner" in options) {
128
138
  this[InitValues] = {
129
- init,
139
+ init: options.init,
130
140
  owner: options.owner,
131
141
  };
132
142
  } else if ("fromRaw" in options) {
@@ -142,13 +152,21 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
142
152
  return new Proxy(this, CoListProxyHandler as ProxyHandler<this>);
143
153
  }
144
154
 
155
+ static create<L extends CoList>(
156
+ this: CoValueClass<L>,
157
+ items: UnCo<L[number]>[],
158
+ options: { owner: Account | Group },
159
+ ) {
160
+ return new this({ init: items, owner: options.owner });
161
+ }
162
+
145
163
  push(...items: Item[]): number;
146
164
  /** @private For exact type compatibility with Array superclass */
147
165
  push(...items: Item[]): number;
148
166
  push(...items: Item[]): number {
149
167
  for (const item of toRawItems(
150
168
  items as Item[],
151
- this._encoding[ItemsSym]
169
+ this._schema[ItemsSym],
152
170
  )) {
153
171
  this._raw.append(item);
154
172
  }
@@ -162,7 +180,7 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
162
180
  unshift(...items: Item[]): number {
163
181
  for (const item of toRawItems(
164
182
  items as Item[],
165
- this._encoding[ItemsSym]
183
+ this._schema[ItemsSym],
166
184
  )) {
167
185
  this._raw.prepend(item);
168
186
  }
@@ -186,24 +204,23 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
186
204
  return first;
187
205
  }
188
206
 
189
- splice(start: number, deleteCount: number, ...items: Item[]): Item[];
190
- splice(start: number, deleteCount: number, ...items: Item[]): Item[];
191
207
  splice(start: number, deleteCount: number, ...items: Item[]): Item[] {
192
208
  const deleted = this.slice(start, start + deleteCount);
193
209
 
194
210
  for (
195
- let idxToDelete = start + deleteCount;
196
- idxToDelete > start;
211
+ let idxToDelete = start + deleteCount - 1;
212
+ idxToDelete >= start;
197
213
  idxToDelete--
198
214
  ) {
199
215
  this._raw.delete(idxToDelete);
200
216
  }
201
217
 
202
- let appendAfter = start;
218
+ let appendAfter = Math.max(start - 1, 0);
203
219
  for (const item of toRawItems(
204
220
  items as Item[],
205
- this._encoding[ItemsSym]
221
+ this._schema[ItemsSym],
206
222
  )) {
223
+ console.log(this._raw.asArray(), appendAfter);
207
224
  this._raw.append(item, appendAfter);
208
225
  appendAfter++;
209
226
  }
@@ -212,14 +229,14 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
212
229
  }
213
230
 
214
231
  toJSON() {
215
- const itemDescriptor = this._encoding[ItemsSym] as Encoding;
232
+ const itemDescriptor = this._schema[ItemsSym] as Schema;
216
233
  if (itemDescriptor === "json") {
217
234
  return this._raw.asArray();
218
235
  } else if ("encoded" in itemDescriptor) {
219
236
  return this._raw
220
237
  .asArray()
221
- .map((e) => Schema.encodeSync(itemDescriptor.encoded)(e));
222
- } else if ("ref" in itemDescriptor) {
238
+ .map((e) => encodeSync(itemDescriptor.encoded)(e));
239
+ } else if (isRefEncoded(itemDescriptor)) {
223
240
  return this.map((item) => (item as unknown as CoValue)?.toJSON());
224
241
  } else {
225
242
  return [];
@@ -230,61 +247,93 @@ export class CoList<Item extends ValidItem<Item, "CoList"> = any>
230
247
  return this.toJSON();
231
248
  }
232
249
 
233
- subscribe!: (listener: (update: this) => void) => () => void;
234
- static {
235
- this.prototype.subscribe = CoValueBase.prototype.subscribe as any;
236
- }
237
-
238
- subscribeEf!: () => Stream.Stream<this, "unavailable", never>;
239
- static {
240
- this.prototype.subscribeEf = CoValueBase.prototype.subscribeEf as any;
241
- }
242
-
243
250
  static fromRaw<V extends CoList>(
244
- this: SubclassedConstructor<V> & typeof CoList,
245
- raw: RawCoList
251
+ this: CoValueClass<V> & typeof CoList,
252
+ raw: RawCoList,
246
253
  ) {
247
- return new this(undefined, { fromRaw: raw });
254
+ return new this({ fromRaw: raw });
248
255
  }
249
256
 
250
- static loadEf = CoValueBase.loadEf as unknown as <V extends CoValue>(
251
- this: SubclassedConstructor<V>,
252
- id: ID<V>
253
- ) => Effect.Effect<V, UnavailableError, AccountCtx>;
254
- static load = CoValueBase.load as unknown as <V extends CoValue>(
255
- this: SubclassedConstructor<V>,
256
- id: ID<V>,
257
- options: { as: Account | Group }
258
- ) => Promise<V | undefined>;
259
- static subscribeEf = CoValueBase.subscribeEf as unknown as <
260
- V extends CoValue,
261
- >(
262
- this: SubclassedConstructor<V>,
263
- id: ID<V>
264
- ) => Stream.Stream<V, UnavailableError, AccountCtx>;
265
- static subscribe = CoValueBase.subscribe as unknown as <V extends CoValue>(
266
- this: SubclassedConstructor<V>,
267
- id: ID<V>,
268
- options: { as: Account | Group },
269
- onUpdate: (value: V) => void
270
- ) => () => void;
271
-
272
- static encoding<V extends CoList>(
257
+ static schema<V extends CoList>(
258
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
273
259
  this: { new (...args: any): V } & typeof CoList,
274
- def: { [ItemsSym]: V["_encoding"][ItemsSym] }
260
+ def: { [ItemsSym]: V["_schema"][ItemsSym] },
275
261
  ) {
276
- this._encoding ||= {};
277
- Object.assign(this._encoding, def);
262
+ this._schema ||= {};
263
+ Object.assign(this._schema, def);
264
+ }
265
+
266
+ /** @category Subscription & Loading */
267
+ static load<L extends CoList, Depth>(
268
+ this: CoValueClass<L>,
269
+ id: ID<L>,
270
+ as: Account,
271
+ depth: Depth & DepthsIn<L>,
272
+ ): Promise<DeeplyLoaded<L, Depth> | undefined> {
273
+ return loadCoValue(this, id, as, depth);
274
+ }
275
+
276
+ /** @category Subscription & Loading */
277
+ static loadEf<L extends CoList, Depth>(
278
+ this: CoValueClass<L>,
279
+ id: ID<L>,
280
+ depth: Depth & DepthsIn<L>,
281
+ ): Effect.Effect<DeeplyLoaded<L, Depth>, UnavailableError, AccountCtx> {
282
+ return loadCoValueEf<L, Depth>(this, id, depth);
283
+ }
284
+
285
+ /** @category Subscription & Loading */
286
+ static subscribe<L extends CoList, Depth>(
287
+ this: CoValueClass<L>,
288
+ id: ID<L>,
289
+ as: Account,
290
+ depth: Depth & DepthsIn<L>,
291
+ listener: (value: DeeplyLoaded<L, Depth>) => void,
292
+ ): () => void {
293
+ return subscribeToCoValue<L, Depth>(this, id, as, depth, listener);
294
+ }
295
+
296
+ /** @category Subscription & Loading */
297
+ static subscribeEf<L extends CoList, Depth>(
298
+ this: CoValueClass<L>,
299
+ id: ID<L>,
300
+ depth: Depth & DepthsIn<L>,
301
+ ): Stream.Stream<DeeplyLoaded<L, Depth>, UnavailableError, AccountCtx> {
302
+ return subscribeToCoValueEf<L, Depth>(this, id, depth);
303
+ }
304
+
305
+ /** @category Subscription & Loading */
306
+ ensureLoaded<L extends CoList, Depth>(
307
+ this: L,
308
+ depth: Depth & DepthsIn<L>,
309
+ ): Promise<DeeplyLoaded<L, Depth> | undefined> {
310
+ return ensureCoValueLoaded(this, depth);
311
+ }
312
+
313
+ /** @category Subscription & Loading */
314
+ subscribe<L extends CoList, Depth>(
315
+ this: L,
316
+ depth: Depth & DepthsIn<L>,
317
+ listener: (value: DeeplyLoaded<L, Depth>) => void,
318
+ ): () => void {
319
+ return subscribeToExistingCoValue(this, depth, listener);
320
+ }
321
+
322
+ /** @category Type Helpers */
323
+ castAs<Cl extends CoValueClass & CoValueFromRaw<CoValue>>(
324
+ cl: Cl,
325
+ ): InstanceType<Cl> {
326
+ return cl.fromRaw(this._raw) as InstanceType<Cl>;
278
327
  }
279
328
  }
280
329
 
281
- function toRawItems<Item>(items: Item[], itemDescriptor: Encoding) {
330
+ function toRawItems<Item>(items: Item[], itemDescriptor: Schema) {
282
331
  const rawItems =
283
332
  itemDescriptor === "json"
284
333
  ? items
285
334
  : "encoded" in itemDescriptor
286
- ? items?.map((e) => Schema.encodeSync(itemDescriptor.encoded)(e))
287
- : "ref" in itemDescriptor
335
+ ? items?.map((e) => encodeSync(itemDescriptor.encoded)(e))
336
+ : isRefEncoded(itemDescriptor)
288
337
  ? items?.map((v) => (v as unknown as CoValue).id)
289
338
  : (() => {
290
339
  throw new Error("Invalid element descriptor");
@@ -296,7 +345,7 @@ function init(list: CoList) {
296
345
  if (list[InitValues]) {
297
346
  const { init, owner } = list[InitValues];
298
347
  const raw = owner._raw.createList(
299
- toRawItems(init, list._encoding[ItemsSym])
348
+ toRawItems(init, list._schema[ItemsSym]),
300
349
  );
301
350
 
302
351
  Object.defineProperties(list, {
@@ -313,22 +362,22 @@ function init(list: CoList) {
313
362
  const CoListProxyHandler: ProxyHandler<CoList> = {
314
363
  get(target, key, receiver) {
315
364
  if (typeof key === "string" && !isNaN(+key)) {
316
- const itemDescriptor = target._encoding[ItemsSym] as Encoding;
365
+ const itemDescriptor = target._schema[ItemsSym] as Schema;
317
366
  const rawValue = target._raw.get(Number(key));
318
367
  if (itemDescriptor === "json") {
319
368
  return rawValue;
320
369
  } else if ("encoded" in itemDescriptor) {
321
370
  return rawValue === undefined
322
371
  ? undefined
323
- : Schema.decodeSync(itemDescriptor.encoded)(rawValue);
324
- } else if ("ref" in itemDescriptor) {
372
+ : decodeSync(itemDescriptor.encoded)(rawValue);
373
+ } else if (isRefEncoded(itemDescriptor)) {
325
374
  return rawValue === undefined
326
375
  ? undefined
327
376
  : new Ref(
328
377
  rawValue as unknown as ID<CoValue>,
329
378
  target._loadedAs,
330
- itemDescriptor
331
- ).accessFrom(receiver);
379
+ itemDescriptor,
380
+ ).accessFrom(receiver, Number(key));
332
381
  }
333
382
  } else if (key === "length") {
334
383
  return target._raw.entries().length;
@@ -342,20 +391,20 @@ const CoListProxyHandler: ProxyHandler<CoList> = {
342
391
  typeof value === "object" &&
343
392
  SchemaInit in value
344
393
  ) {
345
- (target.constructor as typeof CoList)._encoding ||= {};
346
- (target.constructor as typeof CoList)._encoding[ItemsSym] =
394
+ (target.constructor as typeof CoList)._schema ||= {};
395
+ (target.constructor as typeof CoList)._schema[ItemsSym] =
347
396
  value[SchemaInit];
348
397
  init(target);
349
398
  return true;
350
399
  }
351
400
  if (typeof key === "string" && !isNaN(+key)) {
352
- const itemDescriptor = target._encoding[ItemsSym] as Encoding;
401
+ const itemDescriptor = target._schema[ItemsSym] as Schema;
353
402
  let rawValue;
354
403
  if (itemDescriptor === "json") {
355
404
  rawValue = value;
356
405
  } else if ("encoded" in itemDescriptor) {
357
- rawValue = Schema.encodeSync(itemDescriptor.encoded)(value);
358
- } else if ("ref" in itemDescriptor) {
406
+ rawValue = encodeSync(itemDescriptor.encoded)(value);
407
+ } else if (isRefEncoded(itemDescriptor)) {
359
408
  rawValue = value.id;
360
409
  }
361
410
  target._raw.replace(Number(key), rawValue);
@@ -371,8 +420,8 @@ const CoListProxyHandler: ProxyHandler<CoList> = {
371
420
  typeof descriptor.value === "object" &&
372
421
  SchemaInit in descriptor.value
373
422
  ) {
374
- (target.constructor as typeof CoList)._encoding ||= {};
375
- (target.constructor as typeof CoList)._encoding[ItemsSym] =
423
+ (target.constructor as typeof CoList)._schema ||= {};
424
+ (target.constructor as typeof CoList)._schema[ItemsSym] =
376
425
  descriptor.value[SchemaInit];
377
426
  init(target);
378
427
  return true;