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.
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;