jazz-tools 0.8.15 → 0.8.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. package/CHANGELOG.md +276 -269
  2. package/dist/native/coValues/account.js +3 -6
  3. package/dist/native/coValues/account.js.map +1 -1
  4. package/dist/native/coValues/coList.js +3 -7
  5. package/dist/native/coValues/coList.js.map +1 -1
  6. package/dist/native/coValues/coMap.js +8 -14
  7. package/dist/native/coValues/coMap.js.map +1 -1
  8. package/dist/native/coValues/coStream.js +7 -12
  9. package/dist/native/coValues/coStream.js.map +1 -1
  10. package/dist/native/coValues/deepLoading.js +6 -3
  11. package/dist/native/coValues/deepLoading.js.map +1 -1
  12. package/dist/native/coValues/extensions/imageDef.js.map +1 -1
  13. package/dist/native/coValues/group.js +3 -6
  14. package/dist/native/coValues/group.js.map +1 -1
  15. package/dist/native/coValues/interfaces.js +4 -3
  16. package/dist/native/coValues/interfaces.js.map +1 -1
  17. package/dist/native/exports.js +3 -9
  18. package/dist/native/exports.js.map +1 -1
  19. package/dist/native/implementation/createContext.js +1 -2
  20. package/dist/native/implementation/createContext.js.map +1 -1
  21. package/dist/native/implementation/devtoolsFormatters.js +5 -25
  22. package/dist/native/implementation/devtoolsFormatters.js.map +1 -1
  23. package/dist/native/implementation/refs.js +1 -2
  24. package/dist/native/implementation/refs.js.map +1 -1
  25. package/dist/native/implementation/schema.js +1 -1
  26. package/dist/native/implementation/schema.js.map +1 -1
  27. package/dist/native/implementation/subscriptionScope.js +2 -4
  28. package/dist/native/implementation/subscriptionScope.js.map +1 -1
  29. package/dist/native/index.native.js +1 -1
  30. package/dist/native/index.native.js.map +1 -1
  31. package/dist/native/lib/cache.js.map +1 -1
  32. package/dist/native/lib/cache.test.js +1 -1
  33. package/dist/native/lib/cache.test.js.map +1 -1
  34. package/dist/web/coValues/account.js +3 -6
  35. package/dist/web/coValues/account.js.map +1 -1
  36. package/dist/web/coValues/coList.js +3 -7
  37. package/dist/web/coValues/coList.js.map +1 -1
  38. package/dist/web/coValues/coMap.js +8 -14
  39. package/dist/web/coValues/coMap.js.map +1 -1
  40. package/dist/web/coValues/coStream.js +7 -12
  41. package/dist/web/coValues/coStream.js.map +1 -1
  42. package/dist/web/coValues/deepLoading.js +6 -3
  43. package/dist/web/coValues/deepLoading.js.map +1 -1
  44. package/dist/web/coValues/extensions/imageDef.js.map +1 -1
  45. package/dist/web/coValues/group.js +3 -6
  46. package/dist/web/coValues/group.js.map +1 -1
  47. package/dist/web/coValues/interfaces.js +4 -3
  48. package/dist/web/coValues/interfaces.js.map +1 -1
  49. package/dist/web/exports.js +3 -9
  50. package/dist/web/exports.js.map +1 -1
  51. package/dist/web/implementation/createContext.js +1 -2
  52. package/dist/web/implementation/createContext.js.map +1 -1
  53. package/dist/web/implementation/devtoolsFormatters.js +5 -25
  54. package/dist/web/implementation/devtoolsFormatters.js.map +1 -1
  55. package/dist/web/implementation/refs.js +1 -2
  56. package/dist/web/implementation/refs.js.map +1 -1
  57. package/dist/web/implementation/schema.js +1 -1
  58. package/dist/web/implementation/schema.js.map +1 -1
  59. package/dist/web/implementation/subscriptionScope.js +2 -4
  60. package/dist/web/implementation/subscriptionScope.js.map +1 -1
  61. package/dist/web/lib/cache.js.map +1 -1
  62. package/dist/web/lib/cache.test.js +1 -1
  63. package/dist/web/lib/cache.test.js.map +1 -1
  64. package/package.json +5 -9
  65. package/src/coValues/account.ts +330 -339
  66. package/src/coValues/coList.ts +474 -495
  67. package/src/coValues/coMap.ts +584 -604
  68. package/src/coValues/coStream.ts +624 -650
  69. package/src/coValues/deepLoading.ts +184 -200
  70. package/src/coValues/extensions/imageDef.ts +44 -44
  71. package/src/coValues/group.ts +196 -210
  72. package/src/coValues/interfaces.ts +197 -199
  73. package/src/exports.ts +38 -26
  74. package/src/implementation/createContext.ts +206 -213
  75. package/src/implementation/devtoolsFormatters.ts +80 -100
  76. package/src/implementation/refs.ts +127 -139
  77. package/src/implementation/schema.ts +124 -128
  78. package/src/implementation/subscriptionScope.ts +111 -121
  79. package/src/index.native.ts +3 -3
  80. package/src/lib/cache.test.ts +48 -48
  81. package/src/lib/cache.ts +9 -9
  82. package/src/tests/coList.test.ts +264 -283
  83. package/src/tests/coMap.test.ts +741 -761
  84. package/src/tests/coStream.test.ts +405 -438
  85. package/src/tests/deepLoading.test.ts +251 -256
  86. package/src/tests/groupsAndAccounts.test.ts +70 -74
  87. package/src/tests/schema.test.ts +198 -198
  88. package/src/tests/subscribe.test.ts +312 -299
  89. package/tsconfig.json +2 -4
  90. package/tsconfig.native.json +4 -10
  91. package/tsconfig.web.json +4 -10
  92. package/.eslintrc.cjs +0 -24
  93. package/.prettierrc.js +0 -9
@@ -1,40 +1,40 @@
1
1
  import type { JsonValue, RawCoList } from "cojson";
2
2
  import { RawAccount } from "cojson";
3
3
  import type {
4
- CoValue,
5
- Schema,
6
- SchemaFor,
7
- ID,
8
- RefEncoded,
9
- UnCo,
10
- CoValueClass,
11
- DepthsIn,
12
- DeeplyLoaded,
13
- CoValueFromRaw,
4
+ CoValue,
5
+ CoValueClass,
6
+ CoValueFromRaw,
7
+ DeeplyLoaded,
8
+ DepthsIn,
9
+ ID,
10
+ RefEncoded,
11
+ Schema,
12
+ SchemaFor,
13
+ UnCo,
14
14
  } from "../internal.js";
15
15
  import {
16
- Account,
17
- AnonymousJazzAgent,
18
- Group,
19
- ItemsSym,
20
- Ref,
21
- SchemaInit,
22
- co,
23
- ensureCoValueLoaded,
24
- inspect,
25
- isRefEncoded,
26
- loadCoValue,
27
- makeRefs,
28
- subscribeToCoValue,
29
- subscribeToExistingCoValue,
30
- subscriptionsScopes,
16
+ Account,
17
+ AnonymousJazzAgent,
18
+ Group,
19
+ ItemsSym,
20
+ Ref,
21
+ SchemaInit,
22
+ co,
23
+ ensureCoValueLoaded,
24
+ inspect,
25
+ isRefEncoded,
26
+ loadCoValue,
27
+ makeRefs,
28
+ subscribeToCoValue,
29
+ subscribeToExistingCoValue,
30
+ subscriptionsScopes,
31
31
  } from "../internal.js";
32
32
  import { coValuesCache } from "../lib/cache.js";
33
33
 
34
34
  /**
35
35
  * CoLists are collaborative versions of plain arrays.
36
36
  *
37
- * * @categoryDescription Content
37
+ * @categoryDescription Content
38
38
  * You can access items on a `CoList` as if they were normal items on a plain array, using `[]` notation, etc.
39
39
  *
40
40
  * Since `CoList` is a subclass of `Array`, you can use all the normal array methods like `push`, `pop`, `splice`, etc.
@@ -50,504 +50,483 @@ import { coValuesCache } from "../lib/cache.js";
50
50
  */
51
51
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
52
  export class CoList<Item = any> extends Array<Item> implements CoValue {
53
- /**
54
- * Declare a `CoList` by subclassing `CoList.Of(...)` and passing the item schema using `co`.
55
- *
56
- * @example
57
- * ```ts
58
- * class ColorList extends CoList.Of(
59
- * co.string
60
- * ) {}
61
- * class AnimalList extends CoList.Of(
62
- * co.ref(Animal)
63
- * ) {}
64
- * ```
65
- *
66
- * @category Declaration
67
- */
68
- static Of<Item>(item: Item): typeof CoList<Item> {
69
- // TODO: cache superclass for item class
70
- return class CoListOf extends CoList<Item> {
71
- [co.items] = item;
72
- };
53
+ /**
54
+ * Declare a `CoList` by subclassing `CoList.Of(...)` and passing the item schema using `co`.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * class ColorList extends CoList.Of(
59
+ * co.string
60
+ * ) {}
61
+ * class AnimalList extends CoList.Of(
62
+ * co.ref(Animal)
63
+ * ) {}
64
+ * ```
65
+ *
66
+ * @category Declaration
67
+ */
68
+ static Of<Item>(item: Item): typeof CoList<Item> {
69
+ // TODO: cache superclass for item class
70
+ return class CoListOf extends CoList<Item> {
71
+ [co.items] = item;
72
+ };
73
+ }
74
+
75
+ /**
76
+ * @ignore
77
+ * @deprecated Use UPPERCASE `CoList.Of` instead! */
78
+ static of(..._args: never): never {
79
+ throw new Error("Can't use Array.of with CoLists");
80
+ }
81
+
82
+ /**
83
+ * The ID of this `CoList`
84
+ * @category Content */
85
+ declare id: ID<this>;
86
+ /** @category Type Helpers */
87
+ declare _type: "CoList";
88
+ static {
89
+ this.prototype._type = "CoList";
90
+ }
91
+ /** @category Internals */
92
+ declare _raw: RawCoList;
93
+ /** @category Internals */
94
+ declare _instanceID: string;
95
+
96
+ /** @internal This is only a marker type and doesn't exist at runtime */
97
+ [ItemsSym]!: Item;
98
+ /** @internal */
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
+ static _schema: any;
101
+ /** @internal */
102
+ get _schema(): {
103
+ [ItemsSym]: SchemaFor<Item>;
104
+ } {
105
+ return (this.constructor as typeof CoList)._schema;
106
+ }
107
+
108
+ /** @category Collaboration */
109
+ get _owner(): Account | Group {
110
+ return this._raw.group instanceof RawAccount
111
+ ? Account.fromRaw(this._raw.group)
112
+ : Group.fromRaw(this._raw.group);
113
+ }
114
+
115
+ /**
116
+ * If a `CoList`'s items are a `co.ref(...)`, you can use `coList._refs[i]` to access
117
+ * the `Ref` instead of the potentially loaded/null value.
118
+ *
119
+ * This allows you to always get the ID or load the value manually.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * animals._refs[0].id; // => ID<Animal>
124
+ * animals._refs[0].value;
125
+ * // => Animal | null
126
+ * const animal = await animals._refs[0].load();
127
+ * ```
128
+ *
129
+ * @category Content
130
+ **/
131
+ get _refs(): {
132
+ [idx: number]: Exclude<Item, null> extends CoValue
133
+ ? Ref<UnCo<Exclude<Item, null>>>
134
+ : never;
135
+ } & {
136
+ length: number;
137
+ [Symbol.iterator](): IterableIterator<
138
+ Exclude<Item, null> extends CoValue ? Ref<Exclude<Item, null>> : never
139
+ >;
140
+ } {
141
+ return makeRefs<number>(
142
+ (idx) => this._raw.get(idx) as unknown as ID<CoValue>,
143
+ () => Array.from({ length: this._raw.entries().length }, (_, idx) => idx),
144
+ this._loadedAs,
145
+ (_idx) => this._schema[ItemsSym] as RefEncoded<CoValue>,
146
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
147
+ ) as any;
148
+ }
149
+
150
+ get _edits(): {
151
+ [idx: number]: {
152
+ value?: Item;
153
+ ref?: Item extends CoValue ? Ref<Item> : never;
154
+ by?: Account;
155
+ madeAt: Date;
156
+ };
157
+ } {
158
+ throw new Error("Not implemented");
159
+ }
160
+
161
+ get _loadedAs() {
162
+ const rawAccount = this._raw.core.node.account;
163
+
164
+ if (rawAccount instanceof RawAccount) {
165
+ return coValuesCache.get(rawAccount, () => Account.fromRaw(rawAccount));
73
166
  }
74
167
 
75
- /**
76
- * @ignore
77
- * @deprecated Use UPPERCASE `CoList.Of` instead! */
78
- static of(..._args: never): never {
79
- throw new Error("Can't use Array.of with CoLists");
168
+ return new AnonymousJazzAgent(this._raw.core.node);
169
+ }
170
+
171
+ static get [Symbol.species]() {
172
+ return Array;
173
+ }
174
+
175
+ constructor(options: { fromRaw: RawCoList } | undefined) {
176
+ super();
177
+
178
+ Object.defineProperty(this, "_instanceID", {
179
+ value: `instance-${Math.random().toString(36).slice(2)}`,
180
+ enumerable: false,
181
+ });
182
+
183
+ if (options && "fromRaw" in options) {
184
+ Object.defineProperties(this, {
185
+ id: {
186
+ value: options.fromRaw.id,
187
+ enumerable: false,
188
+ },
189
+ _raw: { value: options.fromRaw, enumerable: false },
190
+ });
80
191
  }
81
192
 
82
- /**
83
- * The ID of this `CoList`
84
- * @category Content */
85
- declare id: ID<this>;
86
- /** @category Type Helpers */
87
- declare _type: "CoList";
88
- static {
89
- this.prototype._type = "CoList";
90
- }
91
- /** @category Internals */
92
- declare _raw: RawCoList;
93
- /** @category Internals */
94
- declare _instanceID: string;
95
-
96
- /** @internal This is only a marker type and doesn't exist at runtime */
97
- [ItemsSym]!: Item;
98
- /** @internal */
99
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
- static _schema: any;
101
- /** @internal */
102
- get _schema(): {
103
- [ItemsSym]: SchemaFor<Item>;
104
- } {
105
- return (this.constructor as typeof CoList)._schema;
193
+ return new Proxy(this, CoListProxyHandler as ProxyHandler<this>);
194
+ }
195
+
196
+ /**
197
+ * Create a new CoList with the given initial values and owner.
198
+ *
199
+ * The owner (a Group or Account) determines access rights to the CoMap.
200
+ *
201
+ * The CoList will immediately be persisted and synced to connected peers.
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * const colours = ColorList.create(
206
+ * ["red", "green", "blue"],
207
+ * { owner: me }
208
+ * );
209
+ * const animals = AnimalList.create(
210
+ * [cat, dog, fish],
211
+ * { owner: me }
212
+ * );
213
+ * ```
214
+ *
215
+ * @category Creation
216
+ **/
217
+ static create<L extends CoList>(
218
+ this: CoValueClass<L>,
219
+ items: UnCo<L[number]>[],
220
+ options: { owner: Account | Group },
221
+ ) {
222
+ const instance = new this({ init: items, owner: options.owner });
223
+ const raw = options.owner._raw.createList(
224
+ toRawItems(items, instance._schema[ItemsSym]),
225
+ );
226
+
227
+ Object.defineProperties(instance, {
228
+ id: {
229
+ value: raw.id,
230
+ enumerable: false,
231
+ },
232
+ _raw: { value: raw, enumerable: false },
233
+ });
234
+
235
+ return instance;
236
+ }
237
+
238
+ push(...items: Item[]): number {
239
+ for (const item of toRawItems(items as Item[], this._schema[ItemsSym])) {
240
+ this._raw.append(item);
106
241
  }
107
242
 
108
- /** @category Collaboration */
109
- get _owner(): Account | Group {
110
- return this._raw.group instanceof RawAccount
111
- ? Account.fromRaw(this._raw.group)
112
- : Group.fromRaw(this._raw.group);
113
- }
243
+ return this._raw.entries().length;
244
+ }
114
245
 
115
- /**
116
- * If a `CoList`'s items are a `co.ref(...)`, you can use `coList._refs[i]` to access
117
- * the `Ref` instead of the potentially loaded/null value.
118
- *
119
- * This allows you to always get the ID or load the value manually.
120
- *
121
- * @example
122
- * ```ts
123
- * animals._refs[0].id; // => ID<Animal>
124
- * animals._refs[0].value;
125
- * // => Animal | null
126
- * const animal = await animals._refs[0].load();
127
- * ```
128
- *
129
- * @category Content
130
- **/
131
- get _refs(): {
132
- [idx: number]: Exclude<Item, null> extends CoValue
133
- ? Ref<UnCo<Exclude<Item, null>>>
134
- : never;
135
- } & {
136
- length: number;
137
- [Symbol.iterator](): IterableIterator<
138
- Exclude<Item, null> extends CoValue
139
- ? Ref<Exclude<Item, null>>
140
- : never
141
- >;
142
- } {
143
- return makeRefs<number>(
144
- (idx) => this._raw.get(idx) as unknown as ID<CoValue>,
145
- () =>
146
- Array.from(
147
- { length: this._raw.entries().length },
148
- (_, idx) => idx,
149
- ),
150
- this._loadedAs,
151
- (_idx) => this._schema[ItemsSym] as RefEncoded<CoValue>,
152
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
153
- ) as any;
246
+ unshift(...items: Item[]): number {
247
+ for (const item of toRawItems(items as Item[], this._schema[ItemsSym])) {
248
+ this._raw.prepend(item);
154
249
  }
155
250
 
156
- get _edits(): {
157
- [idx: number]: {
158
- value?: Item;
159
- ref?: Item extends CoValue ? Ref<Item> : never;
160
- by?: Account;
161
- madeAt: Date;
162
- };
163
- } {
164
- throw new Error("Not implemented");
165
- }
251
+ return this._raw.entries().length;
252
+ }
166
253
 
167
- get _loadedAs() {
168
- const rawAccount = this._raw.core.node.account;
254
+ pop(): Item | undefined {
255
+ const last = this[this.length - 1];
169
256
 
170
- if (rawAccount instanceof RawAccount) {
171
- return coValuesCache.get(rawAccount, () => Account.fromRaw(rawAccount)) ;
172
- }
257
+ this._raw.delete(this.length - 1);
173
258
 
174
- return new AnonymousJazzAgent(this._raw.core.node);
175
- }
259
+ return last;
260
+ }
176
261
 
177
- static get [Symbol.species]() {
178
- return Array;
179
- }
262
+ shift(): Item | undefined {
263
+ const first = this[0];
180
264
 
181
- constructor(options: { fromRaw: RawCoList } | undefined) {
182
- super();
183
-
184
- Object.defineProperty(this, "_instanceID", {
185
- value: `instance-${Math.random().toString(36).slice(2)}`,
186
- enumerable: false,
187
- });
188
-
189
- if (options && "fromRaw" in options) {
190
- Object.defineProperties(this, {
191
- id: {
192
- value: options.fromRaw.id,
193
- enumerable: false,
194
- },
195
- _raw: { value: options.fromRaw, enumerable: false },
196
- });
197
- }
198
-
199
- return new Proxy(this, CoListProxyHandler as ProxyHandler<this>);
200
- }
265
+ this._raw.delete(0);
201
266
 
202
- /**
203
- * Create a new CoList with the given initial values and owner.
204
- *
205
- * The owner (a Group or Account) determines access rights to the CoMap.
206
- *
207
- * The CoList will immediately be persisted and synced to connected peers.
208
- *
209
- * @example
210
- * ```ts
211
- * const colours = ColorList.create(
212
- * ["red", "green", "blue"],
213
- * { owner: me }
214
- * );
215
- * const animals = AnimalList.create(
216
- * [cat, dog, fish],
217
- * { owner: me }
218
- * );
219
- * ```
220
- *
221
- * @category Creation
222
- **/
223
- static create<L extends CoList>(
224
- this: CoValueClass<L>,
225
- items: UnCo<L[number]>[],
226
- options: { owner: Account | Group },
227
- ) {
228
- const instance = new this({ init: items, owner: options.owner });
229
- const raw = options.owner._raw.createList(
230
- toRawItems(items, instance._schema[ItemsSym]),
231
- );
232
-
233
- Object.defineProperties(instance, {
234
- id: {
235
- value: raw.id,
236
- enumerable: false,
237
- },
238
- _raw: { value: raw, enumerable: false },
239
- });
240
-
241
- return instance;
242
- }
267
+ return first;
268
+ }
243
269
 
244
- push(...items: Item[]): number {
245
- for (const item of toRawItems(
246
- items as Item[],
247
- this._schema[ItemsSym],
248
- )) {
249
- this._raw.append(item);
250
- }
251
-
252
- return this._raw.entries().length;
253
- }
270
+ splice(start: number, deleteCount: number, ...items: Item[]): Item[] {
271
+ const deleted = this.slice(start, start + deleteCount);
254
272
 
255
- unshift(...items: Item[]): number {
256
- for (const item of toRawItems(
257
- items as Item[],
258
- this._schema[ItemsSym],
259
- )) {
260
- this._raw.prepend(item);
261
- }
262
-
263
- return this._raw.entries().length;
264
- }
265
-
266
- pop(): Item | undefined {
267
- const last = this[this.length - 1];
268
-
269
- this._raw.delete(this.length - 1);
270
-
271
- return last;
273
+ for (
274
+ let idxToDelete = start + deleteCount - 1;
275
+ idxToDelete >= start;
276
+ idxToDelete--
277
+ ) {
278
+ this._raw.delete(idxToDelete);
272
279
  }
273
280
 
274
- shift(): Item | undefined {
275
- const first = this[0];
276
-
277
- this._raw.delete(0);
278
-
279
- return first;
281
+ let appendAfter = Math.max(start - 1, 0);
282
+ for (const item of toRawItems(items as Item[], this._schema[ItemsSym])) {
283
+ console.log(this._raw.asArray(), appendAfter);
284
+ this._raw.append(item, appendAfter);
285
+ appendAfter++;
280
286
  }
281
287
 
282
- splice(start: number, deleteCount: number, ...items: Item[]): Item[] {
283
- const deleted = this.slice(start, start + deleteCount);
284
-
285
- for (
286
- let idxToDelete = start + deleteCount - 1;
287
- idxToDelete >= start;
288
- idxToDelete--
289
- ) {
290
- this._raw.delete(idxToDelete);
291
- }
292
-
293
- let appendAfter = Math.max(start - 1, 0);
294
- for (const item of toRawItems(
295
- items as Item[],
296
- this._schema[ItemsSym],
297
- )) {
298
- console.log(this._raw.asArray(), appendAfter);
299
- this._raw.append(item, appendAfter);
300
- appendAfter++;
301
- }
302
-
303
- return deleted;
288
+ return deleted;
289
+ }
290
+
291
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
292
+ toJSON(_key?: string, seenAbove?: ID<CoValue>[]): any[] {
293
+ const itemDescriptor = this._schema[ItemsSym] as Schema;
294
+ if (itemDescriptor === "json") {
295
+ return this._raw.asArray();
296
+ } else if ("encoded" in itemDescriptor) {
297
+ return this._raw.asArray().map((e) => itemDescriptor.encoded.encode(e));
298
+ } else if (isRefEncoded(itemDescriptor)) {
299
+ return this.map((item, idx) =>
300
+ seenAbove?.includes((item as CoValue)?.id)
301
+ ? { _circular: (item as CoValue).id }
302
+ : (item as unknown as CoValue)?.toJSON(idx + "", [
303
+ ...(seenAbove || []),
304
+ this.id,
305
+ ]),
306
+ );
307
+ } else {
308
+ return [];
304
309
  }
305
-
310
+ }
311
+
312
+ [inspect]() {
313
+ return this.toJSON();
314
+ }
315
+
316
+ /** @category Internals */
317
+ static fromRaw<V extends CoList>(
318
+ this: CoValueClass<V> & typeof CoList,
319
+ raw: RawCoList,
320
+ ) {
321
+ return new this({ fromRaw: raw });
322
+ }
323
+
324
+ /** @internal */
325
+ static schema<V extends CoList>(
306
326
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
307
- toJSON(_key?: string, seenAbove?: ID<CoValue>[]): any[] {
308
- const itemDescriptor = this._schema[ItemsSym] as Schema;
309
- if (itemDescriptor === "json") {
310
- return this._raw.asArray();
311
- } else if ("encoded" in itemDescriptor) {
312
- return this._raw
313
- .asArray()
314
- .map((e) => itemDescriptor.encoded.encode(e));
315
- } else if (isRefEncoded(itemDescriptor)) {
316
- return this.map((item, idx) =>
317
- seenAbove?.includes((item as CoValue)?.id)
318
- ? { _circular: (item as CoValue).id }
319
- : (item as unknown as CoValue)?.toJSON(idx + "", [
320
- ...(seenAbove || []),
321
- this.id,
322
- ]),
323
- );
324
- } else {
325
- return [];
326
- }
327
- }
328
-
329
- [inspect]() {
330
- return this.toJSON();
327
+ this: { new (...args: any): V } & typeof CoList,
328
+ def: { [ItemsSym]: V["_schema"][ItemsSym] },
329
+ ) {
330
+ this._schema ||= {};
331
+ Object.assign(this._schema, def);
332
+ }
333
+
334
+ /**
335
+ * Load a `CoList` with a given ID, as a given account.
336
+ *
337
+ * `depth` specifies if item CoValue references should be loaded as well before resolving.
338
+ * The `DeeplyLoaded` return type guarantees that corresponding referenced CoValues are loaded to the specified depth.
339
+ *
340
+ * You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
341
+ *
342
+ * Check out the `load` methods on `CoMap`/`CoList`/`CoStream`/`Group`/`Account` to see which depth structures are valid to nest.
343
+ *
344
+ * @example
345
+ * ```ts
346
+ * const animalsWithVets =
347
+ * await ListOfAnimals.load(
348
+ * "co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
349
+ * me,
350
+ * [{ vet: {} }]
351
+ * );
352
+ * ```
353
+ *
354
+ * @category Subscription & Loading
355
+ */
356
+ static load<L extends CoList, Depth>(
357
+ this: CoValueClass<L>,
358
+ id: ID<L>,
359
+ as: Account,
360
+ depth: Depth & DepthsIn<L>,
361
+ ): Promise<DeeplyLoaded<L, Depth> | undefined> {
362
+ return loadCoValue(this, id, as, depth);
363
+ }
364
+
365
+ /**
366
+ * Load and subscribe to a `CoList` with a given ID, as a given account.
367
+ *
368
+ * Automatically also subscribes to updates to all referenced/nested CoValues as soon as they are accessed in the listener.
369
+ *
370
+ * `depth` specifies if item CoValue references should be loaded as well before calling `listener` for the first time.
371
+ * The `DeeplyLoaded` return type guarantees that corresponding referenced CoValues are loaded to the specified depth.
372
+ *
373
+ * You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
374
+ *
375
+ * Check out the `load` methods on `CoMap`/`CoList`/`CoStream`/`Group`/`Account` to see which depth structures are valid to nest.
376
+ *
377
+ * Returns an unsubscribe function that you should call when you no longer need updates.
378
+ *
379
+ * Also see the `useCoState` hook to reactively subscribe to a CoValue in a React component.
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * const unsub = ListOfAnimals.subscribe(
384
+ * "co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
385
+ * me,
386
+ * { vet: {} },
387
+ * (animalsWithVets) => console.log(animalsWithVets)
388
+ * );
389
+ * ```
390
+ *
391
+ * @category Subscription & Loading
392
+ */
393
+ static subscribe<L extends CoList, Depth>(
394
+ this: CoValueClass<L>,
395
+ id: ID<L>,
396
+ as: Account,
397
+ depth: Depth & DepthsIn<L>,
398
+ listener: (value: DeeplyLoaded<L, Depth>) => void,
399
+ ): () => void {
400
+ return subscribeToCoValue<L, Depth>(this, id, as, depth, listener);
401
+ }
402
+
403
+ /**
404
+ * Given an already loaded `CoList`, ensure that items are loaded to the specified depth.
405
+ *
406
+ * Works like `CoList.load()`, but you don't need to pass the ID or the account to load as again.
407
+ *
408
+ * @category Subscription & Loading
409
+ */
410
+ ensureLoaded<L extends CoList, Depth>(
411
+ this: L,
412
+ depth: Depth & DepthsIn<L>,
413
+ ): Promise<DeeplyLoaded<L, Depth> | undefined> {
414
+ return ensureCoValueLoaded(this, depth);
415
+ }
416
+
417
+ /**
418
+ * Given an already loaded `CoList`, subscribe to updates to the `CoList` and ensure that items are loaded to the specified depth.
419
+ *
420
+ * Works like `CoList.subscribe()`, but you don't need to pass the ID or the account to load as again.
421
+ *
422
+ * Returns an unsubscribe function that you should call when you no longer need updates.
423
+ *
424
+ * @category Subscription & Loading
425
+ **/
426
+ subscribe<L extends CoList, Depth>(
427
+ this: L,
428
+ depth: Depth & DepthsIn<L>,
429
+ listener: (value: DeeplyLoaded<L, Depth>) => void,
430
+ ): () => void {
431
+ return subscribeToExistingCoValue(this, depth, listener);
432
+ }
433
+
434
+ /** @category Type Helpers */
435
+ castAs<Cl extends CoValueClass & CoValueFromRaw<CoValue>>(
436
+ cl: Cl,
437
+ ): InstanceType<Cl> {
438
+ const casted = cl.fromRaw(this._raw) as InstanceType<Cl>;
439
+ const subscriptionScope = subscriptionsScopes.get(this);
440
+ if (subscriptionScope) {
441
+ subscriptionsScopes.set(casted, subscriptionScope);
331
442
  }
443
+ return casted;
444
+ }
445
+ }
332
446
 
333
- /** @category Internals */
334
- static fromRaw<V extends CoList>(
335
- this: CoValueClass<V> & typeof CoList,
336
- raw: RawCoList,
337
- ) {
338
- return new this({ fromRaw: raw });
339
- }
447
+ function toRawItems<Item>(items: Item[], itemDescriptor: Schema) {
448
+ const rawItems =
449
+ itemDescriptor === "json"
450
+ ? (items as JsonValue[])
451
+ : "encoded" in itemDescriptor
452
+ ? items?.map((e) => itemDescriptor.encoded.encode(e))
453
+ : isRefEncoded(itemDescriptor)
454
+ ? items?.map((v) => (v as unknown as CoValue).id)
455
+ : (() => {
456
+ throw new Error("Invalid element descriptor");
457
+ })();
458
+ return rawItems;
459
+ }
340
460
 
341
- /** @internal */
342
- static schema<V extends CoList>(
343
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
344
- this: { new (...args: any): V } & typeof CoList,
345
- def: { [ItemsSym]: V["_schema"][ItemsSym] },
346
- ) {
347
- this._schema ||= {};
348
- Object.assign(this._schema, def);
461
+ const CoListProxyHandler: ProxyHandler<CoList> = {
462
+ get(target, key, receiver) {
463
+ if (typeof key === "string" && !isNaN(+key)) {
464
+ const itemDescriptor = target._schema[ItemsSym] as Schema;
465
+ const rawValue = target._raw.get(Number(key));
466
+ if (itemDescriptor === "json") {
467
+ return rawValue;
468
+ } else if ("encoded" in itemDescriptor) {
469
+ return rawValue === undefined
470
+ ? undefined
471
+ : itemDescriptor.encoded.decode(rawValue);
472
+ } else if (isRefEncoded(itemDescriptor)) {
473
+ return rawValue === undefined
474
+ ? undefined
475
+ : new Ref(
476
+ rawValue as unknown as ID<CoValue>,
477
+ target._loadedAs,
478
+ itemDescriptor,
479
+ ).accessFrom(receiver, Number(key));
480
+ }
481
+ } else if (key === "length") {
482
+ return target._raw.entries().length;
483
+ } else {
484
+ return Reflect.get(target, key, receiver);
349
485
  }
350
-
351
- /**
352
- * Load a `CoList` with a given ID, as a given account.
353
- *
354
- * `depth` specifies if item CoValue references should be loaded as well before resolving.
355
- * The `DeeplyLoaded` return type guarantees that corresponding referenced CoValues are loaded to the specified depth.
356
- *
357
- * You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
358
- *
359
- * Check out the `load` methods on `CoMap`/`CoList`/`CoStream`/`Group`/`Account` to see which depth structures are valid to nest.
360
- *
361
- * @example
362
- * ```ts
363
- * const animalsWithVets =
364
- * await ListOfAnimals.load(
365
- * "co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
366
- * me,
367
- * [{ vet: {} }]
368
- * );
369
- * ```
370
- *
371
- * @category Subscription & Loading
372
- */
373
- static load<L extends CoList, Depth>(
374
- this: CoValueClass<L>,
375
- id: ID<L>,
376
- as: Account,
377
- depth: Depth & DepthsIn<L>,
378
- ): Promise<DeeplyLoaded<L, Depth> | undefined> {
379
- return loadCoValue(this, id, as, depth);
486
+ },
487
+ set(target, key, value, receiver) {
488
+ if (key === ItemsSym && typeof value === "object" && SchemaInit in value) {
489
+ (target.constructor as typeof CoList)._schema ||= {};
490
+ (target.constructor as typeof CoList)._schema[ItemsSym] =
491
+ value[SchemaInit];
492
+ return true;
380
493
  }
381
-
382
- /**
383
- * Load and subscribe to a `CoList` with a given ID, as a given account.
384
- *
385
- * Automatically also subscribes to updates to all referenced/nested CoValues as soon as they are accessed in the listener.
386
- *
387
- * `depth` specifies if item CoValue references should be loaded as well before calling `listener` for the first time.
388
- * The `DeeplyLoaded` return type guarantees that corresponding referenced CoValues are loaded to the specified depth.
389
- *
390
- * You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
391
- *
392
- * Check out the `load` methods on `CoMap`/`CoList`/`CoStream`/`Group`/`Account` to see which depth structures are valid to nest.
393
- *
394
- * Returns an unsubscribe function that you should call when you no longer need updates.
395
- *
396
- * Also see the `useCoState` hook to reactively subscribe to a CoValue in a React component.
397
- *
398
- * @example
399
- * ```ts
400
- * const unsub = ListOfAnimals.subscribe(
401
- * "co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
402
- * me,
403
- * { vet: {} },
404
- * (animalsWithVets) => console.log(animalsWithVets)
405
- * );
406
- * ```
407
- *
408
- * @category Subscription & Loading
409
- */
410
- static subscribe<L extends CoList, Depth>(
411
- this: CoValueClass<L>,
412
- id: ID<L>,
413
- as: Account,
414
- depth: Depth & DepthsIn<L>,
415
- listener: (value: DeeplyLoaded<L, Depth>) => void,
416
- ): () => void {
417
- return subscribeToCoValue<L, Depth>(this, id, as, depth, listener);
494
+ if (typeof key === "string" && !isNaN(+key)) {
495
+ const itemDescriptor = target._schema[ItemsSym] as Schema;
496
+ let rawValue;
497
+ if (itemDescriptor === "json") {
498
+ rawValue = value;
499
+ } else if ("encoded" in itemDescriptor) {
500
+ rawValue = itemDescriptor.encoded.encode(value);
501
+ } else if (isRefEncoded(itemDescriptor)) {
502
+ rawValue = value.id;
503
+ }
504
+ target._raw.replace(Number(key), rawValue);
505
+ return true;
506
+ } else {
507
+ return Reflect.set(target, key, value, receiver);
418
508
  }
419
-
420
- /**
421
- * Given an already loaded `CoList`, ensure that items are loaded to the specified depth.
422
- *
423
- * Works like `CoList.load()`, but you don't need to pass the ID or the account to load as again.
424
- *
425
- * @category Subscription & Loading
426
- */
427
- ensureLoaded<L extends CoList, Depth>(
428
- this: L,
429
- depth: Depth & DepthsIn<L>,
430
- ): Promise<DeeplyLoaded<L, Depth> | undefined> {
431
- return ensureCoValueLoaded(this, depth);
509
+ },
510
+ defineProperty(target, key, descriptor) {
511
+ if (
512
+ descriptor.value &&
513
+ key === ItemsSym &&
514
+ typeof descriptor.value === "object" &&
515
+ SchemaInit in descriptor.value
516
+ ) {
517
+ (target.constructor as typeof CoList)._schema ||= {};
518
+ (target.constructor as typeof CoList)._schema[ItemsSym] =
519
+ descriptor.value[SchemaInit];
520
+ return true;
521
+ } else {
522
+ return Reflect.defineProperty(target, key, descriptor);
432
523
  }
433
-
434
- /**
435
- * Given an already loaded `CoList`, subscribe to updates to the `CoList` and ensure that items are loaded to the specified depth.
436
- *
437
- * Works like `CoList.subscribe()`, but you don't need to pass the ID or the account to load as again.
438
- *
439
- * Returns an unsubscribe function that you should call when you no longer need updates.
440
- *
441
- * @category Subscription & Loading
442
- **/
443
- subscribe<L extends CoList, Depth>(
444
- this: L,
445
- depth: Depth & DepthsIn<L>,
446
- listener: (value: DeeplyLoaded<L, Depth>) => void,
447
- ): () => void {
448
- return subscribeToExistingCoValue(this, depth, listener);
524
+ },
525
+ has(target, key) {
526
+ if (typeof key === "string" && !isNaN(+key)) {
527
+ return Number(key) < target._raw.entries().length;
528
+ } else {
529
+ return Reflect.has(target, key);
449
530
  }
450
-
451
- /** @category Type Helpers */
452
- castAs<Cl extends CoValueClass & CoValueFromRaw<CoValue>>(
453
- cl: Cl,
454
- ): InstanceType<Cl> {
455
- const casted = cl.fromRaw(this._raw) as InstanceType<Cl>;
456
- const subscriptionScope = subscriptionsScopes.get(this);
457
- if (subscriptionScope) {
458
- subscriptionsScopes.set(casted, subscriptionScope);
459
- }
460
- return casted;
461
- }
462
- }
463
-
464
- function toRawItems<Item>(items: Item[], itemDescriptor: Schema) {
465
- const rawItems =
466
- itemDescriptor === "json"
467
- ? (items as JsonValue[])
468
- : "encoded" in itemDescriptor
469
- ? items?.map((e) => itemDescriptor.encoded.encode(e))
470
- : isRefEncoded(itemDescriptor)
471
- ? items?.map((v) => (v as unknown as CoValue).id)
472
- : (() => {
473
- throw new Error("Invalid element descriptor");
474
- })();
475
- return rawItems;
476
- }
477
-
478
- const CoListProxyHandler: ProxyHandler<CoList> = {
479
- get(target, key, receiver) {
480
- if (typeof key === "string" && !isNaN(+key)) {
481
- const itemDescriptor = target._schema[ItemsSym] as Schema;
482
- const rawValue = target._raw.get(Number(key));
483
- if (itemDescriptor === "json") {
484
- return rawValue;
485
- } else if ("encoded" in itemDescriptor) {
486
- return rawValue === undefined
487
- ? undefined
488
- : itemDescriptor.encoded.decode(rawValue);
489
- } else if (isRefEncoded(itemDescriptor)) {
490
- return rawValue === undefined
491
- ? undefined
492
- : new Ref(
493
- rawValue as unknown as ID<CoValue>,
494
- target._loadedAs,
495
- itemDescriptor,
496
- ).accessFrom(receiver, Number(key));
497
- }
498
- } else if (key === "length") {
499
- return target._raw.entries().length;
500
- } else {
501
- return Reflect.get(target, key, receiver);
502
- }
503
- },
504
- set(target, key, value, receiver) {
505
- if (
506
- key === ItemsSym &&
507
- typeof value === "object" &&
508
- SchemaInit in value
509
- ) {
510
- (target.constructor as typeof CoList)._schema ||= {};
511
- (target.constructor as typeof CoList)._schema[ItemsSym] =
512
- value[SchemaInit];
513
- return true;
514
- }
515
- if (typeof key === "string" && !isNaN(+key)) {
516
- const itemDescriptor = target._schema[ItemsSym] as Schema;
517
- let rawValue;
518
- if (itemDescriptor === "json") {
519
- rawValue = value;
520
- } else if ("encoded" in itemDescriptor) {
521
- rawValue = itemDescriptor.encoded.encode(value);
522
- } else if (isRefEncoded(itemDescriptor)) {
523
- rawValue = value.id;
524
- }
525
- target._raw.replace(Number(key), rawValue);
526
- return true;
527
- } else {
528
- return Reflect.set(target, key, value, receiver);
529
- }
530
- },
531
- defineProperty(target, key, descriptor) {
532
- if (
533
- descriptor.value &&
534
- key === ItemsSym &&
535
- typeof descriptor.value === "object" &&
536
- SchemaInit in descriptor.value
537
- ) {
538
- (target.constructor as typeof CoList)._schema ||= {};
539
- (target.constructor as typeof CoList)._schema[ItemsSym] =
540
- descriptor.value[SchemaInit];
541
- return true;
542
- } else {
543
- return Reflect.defineProperty(target, key, descriptor);
544
- }
545
- },
546
- has(target, key) {
547
- if (typeof key === "string" && !isNaN(+key)) {
548
- return Number(key) < target._raw.entries().length;
549
- } else {
550
- return Reflect.has(target, key);
551
- }
552
- },
531
+ },
553
532
  };