jazz-tools 0.7.0-alpha.4 → 0.7.0-alpha.42

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