@evolu/common 8.0.0-next.4 → 8.0.0

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 (237) hide show
  1. package/dist/src/Array.d.ts +279 -173
  2. package/dist/src/Array.d.ts.map +1 -1
  3. package/dist/src/Array.js +105 -101
  4. package/dist/src/Assert.d.ts +44 -44
  5. package/dist/src/Assert.d.ts.map +1 -1
  6. package/dist/src/Assert.js +44 -32
  7. package/dist/src/BigInt.d.ts +6 -3
  8. package/dist/src/BigInt.d.ts.map +1 -1
  9. package/dist/src/BigInt.js +5 -2
  10. package/dist/src/Brand.d.ts +27 -40
  11. package/dist/src/Brand.d.ts.map +1 -1
  12. package/dist/src/Buffer.d.ts +27 -11
  13. package/dist/src/Buffer.d.ts.map +1 -1
  14. package/dist/src/Cache.d.ts +9 -4
  15. package/dist/src/Cache.d.ts.map +1 -1
  16. package/dist/src/Cache.js +8 -3
  17. package/dist/src/Callbacks.d.ts +30 -19
  18. package/dist/src/Callbacks.d.ts.map +1 -1
  19. package/dist/src/Console.d.ts +145 -66
  20. package/dist/src/Console.d.ts.map +1 -1
  21. package/dist/src/Console.js +91 -43
  22. package/dist/src/Crypto.d.ts +85 -42
  23. package/dist/src/Crypto.d.ts.map +1 -1
  24. package/dist/src/Crypto.js +44 -20
  25. package/dist/src/Eq.d.ts +87 -21
  26. package/dist/src/Eq.d.ts.map +1 -1
  27. package/dist/src/Eq.js +67 -19
  28. package/dist/src/Error.d.ts +5 -3
  29. package/dist/src/Error.d.ts.map +1 -1
  30. package/dist/src/Error.js +16 -0
  31. package/dist/src/Function.d.ts +119 -58
  32. package/dist/src/Function.d.ts.map +1 -1
  33. package/dist/src/Function.js +86 -43
  34. package/dist/src/Http.d.ts +394 -0
  35. package/dist/src/Http.d.ts.map +1 -0
  36. package/dist/src/Http.js +102 -0
  37. package/dist/src/Identicon.d.ts +16 -7
  38. package/dist/src/Identicon.d.ts.map +1 -1
  39. package/dist/src/Identicon.js +14 -5
  40. package/dist/src/LeakDetector.d.ts +88 -0
  41. package/dist/src/LeakDetector.d.ts.map +1 -0
  42. package/dist/src/LeakDetector.js +86 -0
  43. package/dist/src/LockManager.d.ts +18 -9
  44. package/dist/src/LockManager.d.ts.map +1 -1
  45. package/dist/src/LockManager.js +7 -8
  46. package/dist/src/Lookup.d.ts +43 -13
  47. package/dist/src/Lookup.d.ts.map +1 -1
  48. package/dist/src/Lookup.js +28 -8
  49. package/dist/src/Microtask.d.ts +1 -1
  50. package/dist/src/Microtask.d.ts.map +1 -1
  51. package/dist/src/Microtask.js +3 -7
  52. package/dist/src/Number.d.ts +49 -13
  53. package/dist/src/Number.d.ts.map +1 -1
  54. package/dist/src/Number.js +34 -5
  55. package/dist/src/Object.d.ts +160 -40
  56. package/dist/src/Object.d.ts.map +1 -1
  57. package/dist/src/Object.js +92 -46
  58. package/dist/src/Option.d.ts +10 -7
  59. package/dist/src/Option.d.ts.map +1 -1
  60. package/dist/src/Option.js +9 -6
  61. package/dist/src/Order.d.ts +21 -21
  62. package/dist/src/Order.d.ts.map +1 -1
  63. package/dist/src/Order.js +18 -21
  64. package/dist/src/Platform.d.ts +31 -0
  65. package/dist/src/Platform.d.ts.map +1 -1
  66. package/dist/src/Platform.js +98 -0
  67. package/dist/src/Random.d.ts +32 -17
  68. package/dist/src/Random.d.ts.map +1 -1
  69. package/dist/src/Random.js +12 -8
  70. package/dist/src/Redacted.d.ts +43 -29
  71. package/dist/src/Redacted.d.ts.map +1 -1
  72. package/dist/src/Redacted.js +14 -3
  73. package/dist/src/Ref.d.ts +11 -3
  74. package/dist/src/Ref.d.ts.map +1 -1
  75. package/dist/src/Ref.js +2 -2
  76. package/dist/src/RefCount.d.ts +2 -6
  77. package/dist/src/RefCount.d.ts.map +1 -1
  78. package/dist/src/RefCount.js +33 -90
  79. package/dist/src/Relation.d.ts +70 -5
  80. package/dist/src/Relation.d.ts.map +1 -1
  81. package/dist/src/Relation.js +77 -2
  82. package/dist/src/Resource.d.ts +590 -155
  83. package/dist/src/Resource.d.ts.map +1 -1
  84. package/dist/src/Resource.js +592 -343
  85. package/dist/src/Result.d.ts +838 -191
  86. package/dist/src/Result.d.ts.map +1 -1
  87. package/dist/src/Result.js +163 -102
  88. package/dist/src/Schedule.d.ts +684 -231
  89. package/dist/src/Schedule.d.ts.map +1 -1
  90. package/dist/src/Schedule.js +766 -295
  91. package/dist/src/Set.d.ts +89 -40
  92. package/dist/src/Set.d.ts.map +1 -1
  93. package/dist/src/Set.js +50 -29
  94. package/dist/src/Sqlite.d.ts +29 -72
  95. package/dist/src/Sqlite.d.ts.map +1 -1
  96. package/dist/src/Sqlite.js +41 -46
  97. package/dist/src/StackTrace.d.ts +40 -0
  98. package/dist/src/StackTrace.d.ts.map +1 -0
  99. package/dist/src/StackTrace.js +140 -0
  100. package/dist/src/Store.d.ts +5 -4
  101. package/dist/src/Store.d.ts.map +1 -1
  102. package/dist/src/Store.js +5 -4
  103. package/dist/src/String.d.ts +7 -1
  104. package/dist/src/String.d.ts.map +1 -1
  105. package/dist/src/String.js +20 -7
  106. package/dist/src/Task.d.ts +3572 -1770
  107. package/dist/src/Task.d.ts.map +1 -1
  108. package/dist/src/Task.js +1879 -1274
  109. package/dist/src/Test.d.ts +17 -125
  110. package/dist/src/Test.d.ts.map +1 -1
  111. package/dist/src/Test.js +17 -68
  112. package/dist/src/Time.d.ts +108 -49
  113. package/dist/src/Time.d.ts.map +1 -1
  114. package/dist/src/Time.js +172 -73
  115. package/dist/src/Type.d.ts +3542 -1926
  116. package/dist/src/Type.d.ts.map +1 -1
  117. package/dist/src/Type.js +3070 -1784
  118. package/dist/src/Types.d.ts +200 -108
  119. package/dist/src/Types.d.ts.map +1 -1
  120. package/dist/src/Types.js +39 -8
  121. package/dist/src/WebSocket.d.ts +48 -23
  122. package/dist/src/WebSocket.d.ts.map +1 -1
  123. package/dist/src/WebSocket.js +15 -6
  124. package/dist/src/Worker.d.ts +94 -36
  125. package/dist/src/Worker.d.ts.map +1 -1
  126. package/dist/src/Worker.js +58 -24
  127. package/dist/src/index.d.ts +55 -52
  128. package/dist/src/index.d.ts.map +1 -1
  129. package/dist/src/index.js +3 -1
  130. package/dist/src/intl/cs.d.ts +94 -0
  131. package/dist/src/intl/cs.d.ts.map +1 -0
  132. package/dist/src/intl/cs.js +220 -0
  133. package/dist/src/intl/index.d.ts +7 -0
  134. package/dist/src/intl/index.d.ts.map +1 -0
  135. package/dist/src/intl/index.js +6 -0
  136. package/dist/src/local-first/Db.d.ts +12 -8
  137. package/dist/src/local-first/Db.d.ts.map +1 -1
  138. package/dist/src/local-first/Db.js +109 -132
  139. package/dist/src/local-first/Error.d.ts +4 -4
  140. package/dist/src/local-first/Evolu.d.ts +338 -92
  141. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  142. package/dist/src/local-first/Evolu.js +47 -55
  143. package/dist/src/local-first/LocalAuth.d.ts +4 -4
  144. package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
  145. package/dist/src/local-first/Owner.d.ts +61 -24
  146. package/dist/src/local-first/Owner.d.ts.map +1 -1
  147. package/dist/src/local-first/Owner.js +45 -8
  148. package/dist/src/local-first/Protocol.d.ts +44 -31
  149. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  150. package/dist/src/local-first/Protocol.js +36 -13
  151. package/dist/src/local-first/Query.d.ts +147 -62
  152. package/dist/src/local-first/Query.d.ts.map +1 -1
  153. package/dist/src/local-first/Query.js +112 -58
  154. package/dist/src/local-first/Relay.d.ts +44 -14
  155. package/dist/src/local-first/Relay.d.ts.map +1 -1
  156. package/dist/src/local-first/Schema.d.ts +92 -41
  157. package/dist/src/local-first/Schema.d.ts.map +1 -1
  158. package/dist/src/local-first/Schema.js +25 -8
  159. package/dist/src/local-first/Shared.d.ts +23 -21
  160. package/dist/src/local-first/Shared.d.ts.map +1 -1
  161. package/dist/src/local-first/Shared.js +100 -57
  162. package/dist/src/local-first/Storage.d.ts +53 -32
  163. package/dist/src/local-first/Storage.d.ts.map +1 -1
  164. package/dist/src/local-first/Storage.js +194 -234
  165. package/dist/src/local-first/Timestamp.d.ts +21 -21
  166. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  167. package/dist/src/local-first/Timestamp.js +2 -2
  168. package/dist/src/local-first/index.d.ts +11 -11
  169. package/package.json +14 -13
  170. package/src/Array.ts +306 -205
  171. package/src/Assert.ts +54 -69
  172. package/src/BigInt.ts +6 -3
  173. package/src/Brand.ts +27 -40
  174. package/src/Buffer.ts +28 -12
  175. package/src/Cache.ts +9 -4
  176. package/src/Callbacks.ts +30 -19
  177. package/src/Console.ts +156 -84
  178. package/src/Crypto.ts +83 -41
  179. package/src/Eq.ts +95 -22
  180. package/src/Error.ts +8 -4
  181. package/src/Function.ts +167 -59
  182. package/src/Http.ts +549 -0
  183. package/src/Identicon.ts +16 -7
  184. package/src/LeakDetector.ts +182 -0
  185. package/src/LockManager.ts +43 -39
  186. package/src/Lookup.ts +62 -28
  187. package/src/Microtask.ts +19 -23
  188. package/src/Number.ts +64 -12
  189. package/src/Object.ts +173 -49
  190. package/src/Option.ts +10 -7
  191. package/src/Order.ts +23 -21
  192. package/src/Platform.ts +136 -0
  193. package/src/Polyfills.ts +6 -12
  194. package/src/Random.ts +32 -19
  195. package/src/Redacted.ts +44 -30
  196. package/src/Ref.ts +14 -6
  197. package/src/RefCount.ts +38 -80
  198. package/src/Relation.ts +202 -10
  199. package/src/Resource.ts +1199 -591
  200. package/src/Result.ts +930 -271
  201. package/src/Schedule.ts +859 -343
  202. package/src/Set.ts +89 -40
  203. package/src/Sqlite.ts +144 -138
  204. package/src/StackTrace.ts +230 -0
  205. package/src/Store.ts +8 -7
  206. package/src/String.ts +22 -5
  207. package/src/Task.ts +5101 -2832
  208. package/src/Test.ts +20 -168
  209. package/src/Time.ts +293 -90
  210. package/src/Type.ts +10034 -4117
  211. package/src/Types.ts +227 -110
  212. package/src/WebSocket.ts +64 -36
  213. package/src/Worker.ts +180 -72
  214. package/src/index.ts +55 -52
  215. package/src/intl/cs.ts +388 -0
  216. package/src/intl/index.ts +7 -0
  217. package/src/local-first/Db.ts +152 -179
  218. package/src/local-first/Error.ts +4 -4
  219. package/src/local-first/Evolu.ts +495 -250
  220. package/src/local-first/LocalAuth.ts +6 -12
  221. package/src/local-first/Owner.ts +58 -21
  222. package/src/local-first/Protocol.ts +49 -31
  223. package/src/local-first/Query.ts +146 -61
  224. package/src/local-first/Relay.ts +51 -21
  225. package/src/local-first/Schema.ts +109 -51
  226. package/src/local-first/Shared.ts +266 -226
  227. package/src/local-first/Storage.ts +266 -264
  228. package/src/local-first/Timestamp.ts +25 -18
  229. package/src/local-first/index.ts +11 -11
  230. package/dist/src/Skiplist.d.ts +0 -28
  231. package/dist/src/Skiplist.d.ts.map +0 -1
  232. package/dist/src/Skiplist.js +0 -64
  233. package/dist/src/Tracer.d.ts +0 -48
  234. package/dist/src/Tracer.d.ts.map +0 -1
  235. package/dist/src/Tracer.js +0 -6
  236. package/src/Skiplist.ts +0 -108
  237. package/src/Tracer.ts +0 -54
@@ -55,87 +55,40 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
55
55
  var e = new Error(message);
56
56
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
57
57
  });
58
- import { assert, assertNotDisposed } from "./Assert.js";
59
- import { identity } from "./Function.js";
58
+ import { assert } from "./Assert.js";
59
+ import { disposable, identity } from "./Function.js";
60
60
  import { createLookupMap } from "./Lookup.js";
61
61
  import { NonNegativeInt, PositiveInt, zeroNonNegativeInt } from "./Type.js";
62
62
  /** Creates {@link RefCount}. */
63
63
  export const createRefCount = () => {
64
- const env_1 = { stack: [], error: void 0, hasError: false };
65
- try {
66
- // We use DisposableStack only because of assertNotDisposed.
67
- const disposer = __addDisposableResource(env_1, new DisposableStack(), false);
68
- let count = zeroNonNegativeInt;
69
- const disposables = disposer.move();
70
- return {
71
- increment: () => {
72
- assertNotDisposed(disposables);
73
- const nextCount = PositiveInt.orThrow(count + 1);
74
- count = nextCount;
75
- return nextCount;
76
- },
77
- decrement: () => {
78
- assertNotDisposed(disposables);
79
- assert(count > 0, "RefCount must not be decremented below zero.");
80
- count = NonNegativeInt.orThrow(count - 1);
81
- return count;
82
- },
83
- getCount: () => {
84
- assertNotDisposed(disposables);
85
- return count;
86
- },
87
- [Symbol.dispose]: () => disposables.dispose(),
88
- };
89
- }
90
- catch (e_1) {
91
- env_1.error = e_1;
92
- env_1.hasError = true;
93
- }
94
- finally {
95
- __disposeResources(env_1);
96
- }
64
+ let count = zeroNonNegativeInt;
65
+ return disposable({
66
+ increment: () => {
67
+ const nextCount = PositiveInt.orThrow(count + 1);
68
+ count = nextCount;
69
+ return nextCount;
70
+ },
71
+ decrement: () => {
72
+ assert(count > 0, "RefCount must not be decremented below zero.");
73
+ count = NonNegativeInt.orThrow(count - 1);
74
+ return count;
75
+ },
76
+ getCount: () => count,
77
+ });
97
78
  };
98
79
  export function createRefCountByKey({ lookup = identity, } = {}) {
99
- const env_2 = { stack: [], error: void 0, hasError: false };
80
+ const env_1 = { stack: [], error: void 0, hasError: false };
100
81
  try {
101
- // We use DisposableStack only because of assertNotDisposed.
102
- const disposer = __addDisposableResource(env_2, new DisposableStack(), false);
103
- const refCountByKey = disposer.adopt(createLookupMap({ lookup }), (refCountByKey) => {
104
- const env_3 = { stack: [], error: void 0, hasError: false };
105
- try {
106
- const disposer = __addDisposableResource(env_3, new DisposableStack(), false);
107
- disposer.defer(() => {
108
- refCountByKey.clear();
109
- });
110
- for (const refCount of refCountByKey.values()) {
111
- disposer.use(refCount);
112
- }
113
- }
114
- catch (e_3) {
115
- env_3.error = e_3;
116
- env_3.hasError = true;
117
- }
118
- finally {
119
- __disposeResources(env_3);
120
- }
82
+ const disposer = __addDisposableResource(env_1, new DisposableStack(), false);
83
+ const refCountByKey = createLookupMap({ lookup });
84
+ disposer.defer(() => {
85
+ refCountByKey.clear();
121
86
  });
122
- const disposables = disposer.move();
123
- const getRefCount = (key) => {
124
- let refCount = refCountByKey.get(key);
125
- if (!refCount) {
126
- refCount = createRefCount();
127
- refCountByKey.set(key, refCount);
128
- }
129
- return refCount;
130
- };
131
- return {
132
- increment: (key) => {
133
- assertNotDisposed(disposables);
134
- return getRefCount(key).increment();
135
- },
87
+ return disposable({
88
+ increment: (key) => refCountByKey.getOrInsertComputed(key, createRefCount).increment(),
136
89
  decrement: (key) => {
137
- assertNotDisposed(disposables);
138
- const refCount = getRefCount(key);
90
+ const refCount = refCountByKey.get(key);
91
+ assert(refCount, "RefCount must not be decremented for an untracked key.");
139
92
  const nextCount = refCount.decrement();
140
93
  if (nextCount === 0) {
141
94
  refCountByKey.delete(key);
@@ -143,26 +96,16 @@ export function createRefCountByKey({ lookup = identity, } = {}) {
143
96
  }
144
97
  return nextCount;
145
98
  },
146
- getCount: (key) => {
147
- assertNotDisposed(disposables);
148
- return refCountByKey.get(key)?.getCount() ?? zeroNonNegativeInt;
149
- },
150
- has: (key) => {
151
- assertNotDisposed(disposables);
152
- return refCountByKey.has(key);
153
- },
154
- keys: () => {
155
- assertNotDisposed(disposables);
156
- return new Set(refCountByKey.keys());
157
- },
158
- [Symbol.dispose]: () => disposables.dispose(),
159
- };
99
+ getCount: (key) => refCountByKey.get(key)?.getCount() ?? zeroNonNegativeInt,
100
+ has: (key) => refCountByKey.has(key),
101
+ keys: () => new Set(refCountByKey.keys()),
102
+ }, disposer);
160
103
  }
161
- catch (e_2) {
162
- env_2.error = e_2;
163
- env_2.hasError = true;
104
+ catch (e_1) {
105
+ env_1.error = e_1;
106
+ env_1.hasError = true;
164
107
  }
165
108
  finally {
166
- __disposeResources(env_2);
109
+ __disposeResources(env_1);
167
110
  }
168
111
  }
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import { type Lookup } from "./Lookup.js";
6
+ import { type Lookup } from "./Lookup.ts";
7
+ import { NonNegativeInt, PositiveInt } from "./Type.ts";
7
8
  /**
8
9
  * Bidirectional relation between two types.
9
10
  *
@@ -34,20 +35,33 @@ import { type Lookup } from "./Lookup.js";
34
35
  * The input parameter types of `lookupA` and `lookupB` determine which values
35
36
  * the returned relation accepts on each side.
36
37
  *
37
- * ### Example
38
+ * ### Reference identity
38
39
  *
39
40
  * Use the default identity semantics.
40
41
  *
41
42
  * ```ts
42
- * const relation = createRelation<WebSocket, string>();
43
+ * import { createRelation } from "@evolu/common";
44
+ *
45
+ * interface Socket {
46
+ * readonly id: string;
47
+ * }
48
+ *
49
+ * const relation = createRelation<Socket, string>();
50
+ * const socket = { id: "socket-1" };
51
+ *
43
52
  * relation.add(socket, "owner-1");
53
+ *
54
+ * expect(relation.has(socket, "owner-1")).toBe(true);
55
+ * expect(relation.has({ id: "socket-1" }, "owner-1")).toBe(false);
44
56
  * ```
45
57
  *
46
- * ### Example
58
+ * ### Lookup-derived equality
47
59
  *
48
60
  * Use lookup-derived equality.
49
61
  *
50
62
  * ```ts
63
+ * import { createRelation } from "@evolu/common";
64
+ *
51
65
  * interface Person {
52
66
  * readonly id: string;
53
67
  * readonly name: string;
@@ -59,7 +73,10 @@ import { type Lookup } from "./Lookup.js";
59
73
  * });
60
74
  *
61
75
  * relation.add({ id: "1", name: "Ada" }, { id: "admins" });
62
- * relation.has({ id: "1", name: "Grace" }, { id: "admins" }); // true
76
+ *
77
+ * expect(relation.has({ id: "1", name: "Grace" }, { id: "admins" })).toBe(
78
+ * true,
79
+ * );
63
80
  * ```
64
81
  *
65
82
  * @see {@link createRelation}
@@ -131,4 +148,52 @@ export interface CreateRelationOptions<A, B, LA = A, LB = B> {
131
148
  /** Creates a {@link Relation}. */
132
149
  export declare function createRelation<A, B>(): Relation<A, B>;
133
150
  export declare function createRelation<A, B, LA, LB>(options: CreateRelationOptions<A, B, LA, LB>): Relation<A, B>;
151
+ /**
152
+ * Bidirectional relation with a positive retain count for every active pair.
153
+ *
154
+ * Logical equality and canonical representatives follow the same lookup rules
155
+ * as {@link Relation}. The first active representative on each side remains
156
+ * canonical until that value has no active pairs. Increment and decrement
157
+ * return those representatives so callers can reliably handle pair transitions
158
+ * without repeating lookup or canonicalization logic.
159
+ *
160
+ * Unlike {@link Relation}'s live iterators, directional and entry reads return
161
+ * snapshots so callers can mutate this relation while iterating. Their order
162
+ * follows first insertion of the current canonical representatives and pairs.
163
+ */
164
+ export interface RefCountedRelation<A, B> {
165
+ /** Increments a pair count and returns its canonical values and new count. */
166
+ readonly increment: (a: A, b: B) => {
167
+ readonly a: A;
168
+ readonly b: B;
169
+ readonly count: PositiveInt;
170
+ };
171
+ /**
172
+ * Decrements a pair count and returns its canonical values and new count.
173
+ * Decrementing a missing pair is a programmer error checked with
174
+ * {@link assert}.
175
+ */
176
+ readonly decrement: (a: A, b: B) => {
177
+ readonly a: A;
178
+ readonly b: B;
179
+ readonly count: NonNegativeInt;
180
+ };
181
+ /** Returns the pair count, or zero when the pair is absent. */
182
+ readonly getCount: (a: A, b: B) => NonNegativeInt;
183
+ /** Returns a snapshot of canonical A values related to `b`. */
184
+ readonly getAs: (b: B) => ReadonlyArray<A>;
185
+ /** Returns a snapshot of canonical B values related to `a`. */
186
+ readonly getBs: (a: A) => ReadonlyArray<B>;
187
+ /** Returns whether an A value has at least one active pair. */
188
+ readonly hasA: (a: A) => boolean;
189
+ /** Returns whether a B value has at least one active pair. */
190
+ readonly hasB: (b: B) => boolean;
191
+ /** Returns a snapshot of every canonical pair and its positive count. */
192
+ readonly getEntries: () => ReadonlyArray<readonly [a: A, b: B, count: PositiveInt]>;
193
+ /** Removes all pair counts and both directional indexes. */
194
+ readonly clear: () => void;
195
+ }
196
+ /** Creates a {@link RefCountedRelation}. */
197
+ export declare function createRefCountedRelation<A, B>(): RefCountedRelation<A, B>;
198
+ export declare function createRefCountedRelation<A, B, LA, LB>(options: CreateRelationOptions<A, B, LA, LB>): RefCountedRelation<A, B>;
134
199
  //# sourceMappingURL=Relation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Relation.d.ts","sourceRoot":"","sources":["../../src/Relation.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAGL,KAAK,MAAM,EAEZ,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,EAAE,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IAEzC,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IAEtC,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IAEtC;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEjD;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEjD;;;OAGG;IACH,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAEpE,wDAAwD;IACxD,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IAEtC,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IAEjC,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IAEjC,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAE3B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC;IAE9B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC;IAE9B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IAEtC,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IAEtC,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC;IACzD,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEjC,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;CAClC;AAED,kCAAkC;AAClC,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvD,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EACzC,OAAO,EAAE,qBAAqB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,GAC3C,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"Relation.d.ts","sourceRoot":"","sources":["../../src/Relation.ts"],"names":[],"mappings":"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"}
@@ -7,13 +7,13 @@ import { emptyArray } from "./Array.js";
7
7
  import { assert } from "./Assert.js";
8
8
  import { identity } from "./Function.js";
9
9
  import { createLookupMap, createLookupSet, } from "./Lookup.js";
10
+ import { NonNegativeInt, onePositiveInt, PositiveInt, zeroNonNegativeInt, } from "./Type.js";
10
11
  export function createRelation({ lookupA = identity, lookupB = identity, } = {}) {
11
12
  const bByA = createLookupMap({ lookup: lookupA });
12
13
  const aByB = createLookupMap({ lookup: lookupB });
13
14
  let sizeInternal = 0;
14
15
  const removePair = (a, b) => {
15
16
  const relatedB = bByA.get(a);
16
- // This should only fail if a leaked view was mutated via an unsafe cast.
17
17
  assertRelationMappingConsistency(relatedB);
18
18
  assertRelationMappingConsistency(relatedB.has(b));
19
19
  relatedB.delete(b);
@@ -21,7 +21,6 @@ export function createRelation({ lookupA = identity, lookupB = identity, } = {})
21
21
  bByA.delete(a);
22
22
  }
23
23
  const relatedA = aByB.get(b);
24
- // This should only fail if a leaked view was mutated via an unsafe cast.
25
24
  assertRelationMappingConsistency(relatedA);
26
25
  assertRelationMappingConsistency(relatedA.has(a));
27
26
  relatedA.delete(a);
@@ -100,6 +99,82 @@ export function createRelation({ lookupA = identity, lookupB = identity, } = {})
100
99
  size: () => sizeInternal,
101
100
  };
102
101
  }
102
+ // This can fail if a lookup function violates its pure and stable contract.
103
103
  const assertRelationMappingConsistency = (condition) => {
104
104
  assert(condition, "Relation mapping inconsistency");
105
105
  };
106
+ export function createRefCountedRelation({ lookupA = identity, lookupB = identity, } = {}) {
107
+ const relatedBsByA = createLookupMap({ lookup: lookupA });
108
+ const relatedAsByB = createLookupMap({ lookup: lookupB });
109
+ return {
110
+ increment: (a, b) => {
111
+ let relatedBs = relatedBsByA.get(a);
112
+ const canonicalA = relatedBs ? relatedBs.a : a;
113
+ const relatedAs = relatedAsByB.get(b);
114
+ const canonicalB = relatedAs ? relatedAs.b : b;
115
+ if (!relatedBs) {
116
+ relatedBs = {
117
+ a: canonicalA,
118
+ countsByB: createLookupMap({ lookup: lookupB }),
119
+ };
120
+ relatedBsByA.set(canonicalA, relatedBs);
121
+ }
122
+ const count = relatedBs.countsByB.get(canonicalB);
123
+ if (count) {
124
+ const nextCount = PositiveInt.orThrow(count + 1);
125
+ relatedBs.countsByB.set(canonicalB, nextCount);
126
+ return { a: canonicalA, b: canonicalB, count: nextCount };
127
+ }
128
+ relatedBs.countsByB.set(canonicalB, onePositiveInt);
129
+ if (relatedAs) {
130
+ relatedAs.as.add(canonicalA);
131
+ }
132
+ else {
133
+ relatedAsByB.set(canonicalB, {
134
+ b: canonicalB,
135
+ as: createLookupSet({
136
+ lookup: lookupA,
137
+ values: [canonicalA],
138
+ }),
139
+ });
140
+ }
141
+ return { a: canonicalA, b: canonicalB, count: onePositiveInt };
142
+ },
143
+ decrement: (a, b) => {
144
+ const relatedBs = relatedBsByA.get(a);
145
+ const relatedAs = relatedAsByB.get(b);
146
+ const count = relatedBs?.countsByB.get(b);
147
+ assert(relatedBs && relatedAs && count, "RefCountedRelation pair must exist before decrement.");
148
+ const nextCount = NonNegativeInt.orThrow(count - 1);
149
+ if (nextCount > 0) {
150
+ relatedBs.countsByB.set(relatedAs.b, PositiveInt.orThrow(nextCount));
151
+ }
152
+ else {
153
+ relatedBs.countsByB.delete(relatedAs.b);
154
+ if (relatedBs.countsByB.size === 0)
155
+ relatedBsByA.delete(relatedBs.a);
156
+ relatedAs.as.delete(relatedBs.a);
157
+ if (relatedAs.as.size === 0)
158
+ relatedAsByB.delete(relatedAs.b);
159
+ }
160
+ return { a: relatedBs.a, b: relatedAs.b, count: nextCount };
161
+ },
162
+ getCount: (a, b) => relatedBsByA.get(a)?.countsByB.get(b) ?? zeroNonNegativeInt,
163
+ getAs: (b) => [...(relatedAsByB.get(b)?.as ?? emptyArray)],
164
+ getBs: (a) => [...(relatedBsByA.get(a)?.countsByB.keys() ?? emptyArray)],
165
+ hasA: (a) => relatedBsByA.has(a),
166
+ hasB: (b) => relatedAsByB.has(b),
167
+ getEntries: () => {
168
+ const entries = [];
169
+ for (const { a, countsByB } of relatedBsByA.values()) {
170
+ for (const [b, count] of countsByB)
171
+ entries.push([a, b, count]);
172
+ }
173
+ return entries;
174
+ },
175
+ clear: () => {
176
+ relatedBsByA.clear();
177
+ relatedAsByB.clear();
178
+ },
179
+ };
180
+ }