jazz-tools 0.7.0-alpha.3 → 0.7.0-alpha.30

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