@verdant-web/common 1.15.3-next.0 → 1.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/cjs/EventSubscriber.d.ts +17 -17
  2. package/dist/cjs/EventSubscriber.js +66 -66
  3. package/dist/cjs/baseline.d.ts +5 -5
  4. package/dist/cjs/baseline.js +2 -2
  5. package/dist/cjs/batching.d.ts +42 -42
  6. package/dist/cjs/batching.js +91 -91
  7. package/dist/cjs/files.d.ts +19 -19
  8. package/dist/cjs/files.js +18 -18
  9. package/dist/cjs/index.d.ts +19 -19
  10. package/dist/cjs/index.js +41 -41
  11. package/dist/cjs/indexes.d.ts +17 -17
  12. package/dist/cjs/indexes.js +142 -142
  13. package/dist/cjs/indexes.test.d.ts +1 -1
  14. package/dist/cjs/indexes.test.js +127 -127
  15. package/dist/cjs/migration.d.ts +172 -172
  16. package/dist/cjs/migration.js +301 -301
  17. package/dist/cjs/oids.d.ts +100 -100
  18. package/dist/cjs/oids.js +457 -457
  19. package/dist/cjs/oids.test.d.ts +1 -1
  20. package/dist/cjs/oids.test.js +348 -348
  21. package/dist/cjs/operation.d.ts +139 -139
  22. package/dist/cjs/operation.js +545 -545
  23. package/dist/cjs/operation.test.d.ts +1 -1
  24. package/dist/cjs/operation.test.js +529 -529
  25. package/dist/cjs/patch.d.ts +26 -26
  26. package/dist/cjs/patch.js +226 -226
  27. package/dist/cjs/presence.d.ts +27 -27
  28. package/dist/cjs/presence.js +2 -2
  29. package/dist/cjs/protocol.d.ts +145 -145
  30. package/dist/cjs/protocol.js +3 -3
  31. package/dist/cjs/refs.d.ts +7 -7
  32. package/dist/cjs/refs.js +29 -29
  33. package/dist/cjs/replica.d.ts +28 -28
  34. package/dist/cjs/replica.js +28 -28
  35. package/dist/cjs/schema/defaults.test.d.ts +1 -1
  36. package/dist/cjs/schema/defaults.test.js +20 -20
  37. package/dist/cjs/schema/fields.d.ts +9 -9
  38. package/dist/cjs/schema/fields.js +144 -144
  39. package/dist/cjs/schema/index.d.ts +8 -8
  40. package/dist/cjs/schema/index.js +51 -51
  41. package/dist/cjs/schema/indexFilters.d.ts +6 -6
  42. package/dist/cjs/schema/indexFilters.js +30 -30
  43. package/dist/cjs/schema/types/collection.d.ts +23 -23
  44. package/dist/cjs/schema/types/collection.js +2 -2
  45. package/dist/cjs/schema/types/compounds.d.ts +11 -11
  46. package/dist/cjs/schema/types/compounds.js +2 -2
  47. package/dist/cjs/schema/types/fields.d.ts +75 -75
  48. package/dist/cjs/schema/types/fields.js +2 -2
  49. package/dist/cjs/schema/types/filters.d.ts +29 -29
  50. package/dist/cjs/schema/types/filters.js +2 -2
  51. package/dist/cjs/schema/types/shapes.d.ts +21 -21
  52. package/dist/cjs/schema/types/shapes.js +2 -2
  53. package/dist/cjs/schema/types/synthetics.d.ts +37 -37
  54. package/dist/cjs/schema/types/synthetics.js +2 -2
  55. package/dist/cjs/schema/types.d.ts +18 -18
  56. package/dist/cjs/schema/types.js +22 -22
  57. package/dist/cjs/schema/validation.d.ts +3 -3
  58. package/dist/cjs/schema/validation.js +86 -86
  59. package/dist/cjs/timestamp.d.ts +50 -50
  60. package/dist/cjs/timestamp.js +251 -251
  61. package/dist/cjs/timestamp.test.d.ts +1 -1
  62. package/dist/cjs/timestamp.test.js +104 -104
  63. package/dist/cjs/undo.d.ts +3 -3
  64. package/dist/cjs/undo.js +198 -198
  65. package/dist/cjs/utils.d.ts +20 -20
  66. package/dist/cjs/utils.js +145 -145
  67. package/dist/cjs/utils.test.d.ts +1 -1
  68. package/dist/cjs/utils.test.js +36 -36
  69. package/dist/esm/EventSubscriber.d.ts +17 -17
  70. package/dist/esm/EventSubscriber.js +62 -62
  71. package/dist/esm/baseline.d.ts +5 -5
  72. package/dist/esm/baseline.js +1 -1
  73. package/dist/esm/batching.d.ts +42 -42
  74. package/dist/esm/batching.js +86 -86
  75. package/dist/esm/files.d.ts +19 -19
  76. package/dist/esm/files.js +12 -12
  77. package/dist/esm/index.d.ts +19 -19
  78. package/dist/esm/index.js +16 -16
  79. package/dist/esm/indexes.d.ts +17 -17
  80. package/dist/esm/indexes.js +130 -130
  81. package/dist/esm/indexes.test.d.ts +1 -1
  82. package/dist/esm/indexes.test.js +125 -125
  83. package/dist/esm/migration.d.ts +172 -172
  84. package/dist/esm/migration.js +294 -294
  85. package/dist/esm/oids.d.ts +100 -100
  86. package/dist/esm/oids.js +422 -422
  87. package/dist/esm/oids.test.d.ts +1 -1
  88. package/dist/esm/oids.test.js +346 -346
  89. package/dist/esm/operation.d.ts +139 -139
  90. package/dist/esm/operation.js +530 -530
  91. package/dist/esm/operation.test.d.ts +1 -1
  92. package/dist/esm/operation.test.js +527 -527
  93. package/dist/esm/patch.d.ts +26 -26
  94. package/dist/esm/patch.js +222 -222
  95. package/dist/esm/presence.d.ts +27 -27
  96. package/dist/esm/presence.js +1 -1
  97. package/dist/esm/protocol.d.ts +145 -145
  98. package/dist/esm/protocol.js +2 -2
  99. package/dist/esm/refs.d.ts +7 -7
  100. package/dist/esm/refs.js +22 -22
  101. package/dist/esm/replica.d.ts +28 -28
  102. package/dist/esm/replica.js +25 -25
  103. package/dist/esm/schema/defaults.test.d.ts +1 -1
  104. package/dist/esm/schema/defaults.test.js +18 -18
  105. package/dist/esm/schema/fields.d.ts +9 -9
  106. package/dist/esm/schema/fields.js +133 -133
  107. package/dist/esm/schema/index.d.ts +8 -8
  108. package/dist/esm/schema/index.js +32 -32
  109. package/dist/esm/schema/indexFilters.d.ts +6 -6
  110. package/dist/esm/schema/indexFilters.js +22 -22
  111. package/dist/esm/schema/types/collection.d.ts +23 -23
  112. package/dist/esm/schema/types/collection.js +1 -1
  113. package/dist/esm/schema/types/compounds.d.ts +11 -11
  114. package/dist/esm/schema/types/compounds.js +1 -1
  115. package/dist/esm/schema/types/fields.d.ts +75 -75
  116. package/dist/esm/schema/types/fields.js +1 -1
  117. package/dist/esm/schema/types/filters.d.ts +29 -29
  118. package/dist/esm/schema/types/filters.js +1 -1
  119. package/dist/esm/schema/types/shapes.d.ts +21 -21
  120. package/dist/esm/schema/types/shapes.js +1 -1
  121. package/dist/esm/schema/types/synthetics.d.ts +37 -37
  122. package/dist/esm/schema/types/synthetics.js +1 -1
  123. package/dist/esm/schema/types.d.ts +18 -18
  124. package/dist/esm/schema/types.js +6 -6
  125. package/dist/esm/schema/validation.d.ts +3 -3
  126. package/dist/esm/schema/validation.js +81 -81
  127. package/dist/esm/timestamp.d.ts +50 -50
  128. package/dist/esm/timestamp.js +234 -234
  129. package/dist/esm/timestamp.test.d.ts +1 -1
  130. package/dist/esm/timestamp.test.js +102 -102
  131. package/dist/esm/undo.d.ts +3 -3
  132. package/dist/esm/undo.js +194 -194
  133. package/dist/esm/utils.d.ts +20 -20
  134. package/dist/esm/utils.js +127 -127
  135. package/dist/esm/utils.test.d.ts +1 -1
  136. package/dist/esm/utils.test.js +34 -34
  137. package/dist/tsconfig-cjs.tsbuildinfo +1 -1
  138. package/dist/tsconfig.tsbuildinfo +1 -1
  139. package/package.json +1 -1
  140. package/dist/cjs/files.test.d.ts +0 -1
  141. package/dist/cjs/files.test.js +0 -81
  142. package/dist/cjs/files.test.js.map +0 -1
  143. package/dist/cjs/schema/defaults.d.ts +0 -4
  144. package/dist/cjs/schema/defaults.js +0 -72
  145. package/dist/cjs/schema/defaults.js.map +0 -1
  146. package/dist/esm/files.test.d.ts +0 -1
  147. package/dist/esm/files.test.js +0 -79
  148. package/dist/esm/files.test.js.map +0 -1
  149. package/dist/esm/schema/defaults.d.ts +0 -4
  150. package/dist/esm/schema/defaults.js +0 -66
  151. package/dist/esm/schema/defaults.js.map +0 -1
package/dist/esm/oids.js CHANGED
@@ -1,423 +1,423 @@
1
- import { v4 } from 'uuid';
2
- import { isFileRef } from './files.js';
3
- import { isObjectRef } from './operation.js';
4
- import { isRef } from './refs.js';
5
- import { isObject, assert } from './utils.js';
6
- export const LEGACY_OID_KEY = '__@@oid_do_not_use';
7
- export const OID_KEY = '@@id';
8
- const COLLECTION_SEPARATOR = '/';
9
- const RANDOM_SEPARATOR = ':';
10
- /**
11
- * This is the global, in-memory storage for all OIDs. It is used to
12
- * associate JS objects with OIDs without modifying the objects themselves.
13
- */
14
- const oidMap = new WeakMap();
15
- export function getOid(obj) {
16
- const oid = maybeGetOid(obj);
17
- assert(!!oid, `Object ${JSON.stringify(obj)} does not have an OID assigned to it`);
18
- return oid;
19
- }
20
- export function maybeGetOid(obj) {
21
- var _a, _b;
22
- if (!isObject(obj)) {
23
- return undefined;
24
- }
25
- return (_b = (_a = oidMap.get(obj)) !== null && _a !== void 0 ? _a : obj[OID_KEY]) !== null && _b !== void 0 ? _b : obj[LEGACY_OID_KEY];
26
- }
27
- export function assignOid(obj, oid) {
28
- assert(isObject(obj), `Only objects can be assigned OIDs, received ${JSON.stringify(obj)}`);
29
- if (hasOid(obj)) {
30
- removeOid(obj);
31
- }
32
- oidMap.set(obj, oid);
33
- return obj;
34
- }
35
- export function hasOid(obj) {
36
- return !!maybeGetOid(obj);
37
- }
38
- export function removeOid(obj) {
39
- oidMap.delete(obj);
40
- return obj;
41
- }
42
- export function isOidKey(key) {
43
- return key === OID_KEY || key === LEGACY_OID_KEY;
44
- }
45
- /**
46
- * For sub-objects, assign a random sub-OID if no OID
47
- * is already assigned.
48
- */
49
- export function ensureOid(obj, rootOid, createSubId) {
50
- if (!hasOid(obj)) {
51
- const oid = createSubOid(rootOid, createSubId);
52
- assignOid(obj, oid);
53
- return oid;
54
- }
55
- else {
56
- return getOid(obj);
57
- }
58
- }
59
- export function ensureCompatibleOid(obj, rootOid, createSubId) {
60
- if (!hasOid(obj)) {
61
- const oid = createSubOid(rootOid, createSubId);
62
- assignOid(obj, oid);
63
- return oid;
64
- }
65
- else {
66
- const existingOid = getOid(obj);
67
- if (!areOidsRelated(existingOid, rootOid)) {
68
- const oid = createSubOid(rootOid, createSubId);
69
- assignOid(obj, oid);
70
- return oid;
71
- }
72
- else {
73
- return getOid(obj);
74
- }
75
- }
76
- }
77
- const SANTIIZE_PLACEHOLDERS = {
78
- '.': '˙',
79
- '/': '&slash;',
80
- ':': ':',
81
- };
82
- function sanitizeFragment(id) {
83
- // replaces separator characters with placeholders
84
- return id
85
- .replace(/[/]/g, SANTIIZE_PLACEHOLDERS['/'])
86
- .replace(/[:]/g, SANTIIZE_PLACEHOLDERS[':'])
87
- .replace(/[.]/g, SANTIIZE_PLACEHOLDERS['.']);
88
- }
89
- function unsanitizeFragment(id) {
90
- // replaces placeholders with separator characters
91
- return id
92
- .replace(/&slash;/g, '/')
93
- .replace(/:/g, ':')
94
- .replace(/˙/g, '.');
95
- }
96
- export function createOid(collection, documentId, subId) {
97
- let oid = sanitizeFragment(collection) +
98
- COLLECTION_SEPARATOR +
99
- sanitizeFragment(documentId);
100
- if (subId) {
101
- oid += RANDOM_SEPARATOR + subId;
102
- }
103
- return oid;
104
- }
105
- export function createSubOid(root, createSubId = createOidSubId) {
106
- const { collection, id } = decomposeOid(root);
107
- return createOid(collection, id, createSubId());
108
- }
109
- export function decomposeOid(oid) {
110
- const [core, random] = oid.split(RANDOM_SEPARATOR);
111
- const [collection, idOrLegacyPathId] = core.split('/');
112
- let id;
113
- if (idOrLegacyPathId.includes('.')) {
114
- id = idOrLegacyPathId.slice(0, idOrLegacyPathId.indexOf('.'));
115
- }
116
- else {
117
- id = idOrLegacyPathId;
118
- }
119
- return {
120
- collection: unsanitizeFragment(collection),
121
- id: unsanitizeFragment(id),
122
- subId: random,
123
- };
124
- }
125
- export function assertAllLevelsHaveOids(obj, root) {
126
- assert(getOid(obj), `Object ${JSON.stringify(obj)} must have an oid (child of ${JSON.stringify(root)})`);
127
- if (Array.isArray(obj)) {
128
- for (const item of obj) {
129
- assertAllLevelsHaveOids(item, root || obj);
130
- }
131
- }
132
- else if (isObject(obj)) {
133
- for (const key of Object.keys(obj)) {
134
- assertAllLevelsHaveOids(obj[key], root || obj);
135
- }
136
- }
137
- }
138
- export function assignOidsToAllSubObjects(obj, createSubId) {
139
- const rootOid = getOid(obj);
140
- if (Array.isArray(obj)) {
141
- let item;
142
- for (let i = 0; i < obj.length; i++) {
143
- item = obj[i];
144
- if (isObject(item) && !isRef(item)) {
145
- ensureCompatibleOid(item, rootOid, createSubId);
146
- assignOidsToAllSubObjects(item, createSubId);
147
- }
148
- }
149
- }
150
- else if (isObject(obj) && !isRef(obj)) {
151
- for (const key of Object.keys(obj)) {
152
- if (isObject(obj[key]) && !isRef(obj[key])) {
153
- ensureCompatibleOid(obj[key], rootOid, createSubId);
154
- assignOidsToAllSubObjects(obj[key], createSubId);
155
- }
156
- }
157
- }
158
- }
159
- export function assignOidProperty(obj, oid) {
160
- assert(isObject(obj), `Only objects can be assigned OIDs, received ${JSON.stringify(obj)}`);
161
- obj[OID_KEY] = oid;
162
- return obj;
163
- }
164
- export function maybeGetOidProperty(obj) {
165
- if (!isObject(obj)) {
166
- return undefined;
167
- }
168
- return obj[OID_KEY] || obj[LEGACY_OID_KEY];
169
- }
170
- function removeOidProperty(obj) {
171
- if (!isObject(obj)) {
172
- return obj;
173
- }
174
- delete obj[LEGACY_OID_KEY];
175
- delete obj[OID_KEY];
176
- return obj;
177
- }
178
- function transferOidFromSystemToProperty(obj) {
179
- const oid = maybeGetOid(obj);
180
- if (oid) {
181
- assignOidProperty(obj, oid);
182
- }
183
- }
184
- /**
185
- * Assigns a special property to all objects in the given object
186
- * which have an OID
187
- */
188
- export function assignOidPropertiesToAllSubObjects(obj) {
189
- transferOidFromSystemToProperty(obj);
190
- if (Array.isArray(obj)) {
191
- for (let i = 0; i < obj.length; i++) {
192
- assignOidPropertiesToAllSubObjects(obj[i]);
193
- }
194
- }
195
- else if (isObject(obj)) {
196
- for (const key of Object.keys(obj)) {
197
- assignOidPropertiesToAllSubObjects(obj[key]);
198
- }
199
- }
200
- }
201
- function copyOidFromPropertyToSystem(obj) {
202
- const oid = maybeGetOidProperty(obj);
203
- if (oid) {
204
- assignOid(obj, oid);
205
- }
206
- }
207
- /**
208
- *
209
- * Removes the special property from all objects in the given object
210
- * which have an OID, transferring the OID from the property to the OID
211
- * system in-memory.
212
- */
213
- export function removeOidPropertiesFromAllSubObjects(obj) {
214
- copyOidFromPropertyToSystem(obj);
215
- removeOidProperty(obj);
216
- if (Array.isArray(obj)) {
217
- for (let i = 0; i < obj.length; i++) {
218
- removeOidPropertiesFromAllSubObjects(obj[i]);
219
- }
220
- }
221
- else if (isObject(obj)) {
222
- for (const key of Object.keys(obj)) {
223
- removeOidPropertiesFromAllSubObjects(obj[key]);
224
- }
225
- }
226
- }
227
- export function removeOidsFromAllSubObjects(obj) {
228
- removeOid(obj);
229
- if (Array.isArray(obj)) {
230
- for (let i = 0; i < obj.length; i++) {
231
- removeOidsFromAllSubObjects(obj[i]);
232
- }
233
- }
234
- else if (isObject(obj)) {
235
- for (const key of Object.keys(obj)) {
236
- removeOidsFromAllSubObjects(obj[key]);
237
- }
238
- }
239
- }
240
- export function createOidSubId() {
241
- return v4().slice(0, 8);
242
- }
243
- export function createRef(oid) {
244
- return {
245
- '@@type': 'ref',
246
- id: oid,
247
- };
248
- }
249
- export function normalize(obj, refs = new Map()) {
250
- if (Array.isArray(obj)) {
251
- const oid = getOid(obj);
252
- const copy = assignOid([], oid);
253
- for (let i = 0; i < obj.length; i++) {
254
- const value = obj[i];
255
- if (isObject(value)) {
256
- if (isObjectRef(value)) {
257
- throw new Error('An attempt was made to normalize an already normalized object! This is an error in verdant itself.');
258
- }
259
- else if (isFileRef(value)) {
260
- copy[i] = value;
261
- continue;
262
- }
263
- else {
264
- const itemOid = getOid(value);
265
- copy[i] = createRef(itemOid);
266
- normalize(value, refs);
267
- }
268
- }
269
- else {
270
- copy[i] = value;
271
- }
272
- }
273
- refs.set(oid, copy);
274
- }
275
- else if (isObject(obj) && !isRef(obj)) {
276
- const oid = getOid(obj);
277
- const copy = assignOid({}, oid);
278
- for (const key of Object.keys(obj)) {
279
- const value = obj[key];
280
- if (isObject(value)) {
281
- if (isObjectRef(value)) {
282
- throw new Error('An attempt was made to normalize an already normalized object! This is an error in verdant itself.');
283
- }
284
- else if (isFileRef(value)) {
285
- // stop here
286
- copy[key] = value;
287
- }
288
- else {
289
- const itemOid = getOid(value);
290
- copy[key] = createRef(itemOid);
291
- normalize(value, refs);
292
- }
293
- }
294
- else {
295
- copy[key] = value;
296
- }
297
- }
298
- refs.set(oid, copy);
299
- }
300
- else if (isRef(obj)) {
301
- }
302
- return refs;
303
- }
304
- /**
305
- * Only normalizes direct children. The created map
306
- * of objects will still have nested objects.
307
- */
308
- export function normalizeFirstLevel(obj) {
309
- const refs = new Map();
310
- const oidKeyPairs = new Map();
311
- if (Array.isArray(obj)) {
312
- const oid = getOid(obj);
313
- const copy = assignOid([], oid);
314
- for (let i = 0; i < obj.length; i++) {
315
- const value = obj[i];
316
- if (isObject(value)) {
317
- const itemOid = getOid(value);
318
- copy[i] = createRef(itemOid);
319
- refs.set(itemOid, value);
320
- oidKeyPairs.set(itemOid, i);
321
- }
322
- else {
323
- copy[i] = value;
324
- }
325
- }
326
- refs.set(oid, copy);
327
- }
328
- else if (isObject(obj)) {
329
- const oid = getOid(obj);
330
- const copy = assignOid({}, oid);
331
- for (const key of Object.keys(obj)) {
332
- const value = obj[key];
333
- if (isObject(value)) {
334
- const itemOid = getOid(value);
335
- copy[key] = createRef(itemOid);
336
- refs.set(itemOid, value);
337
- oidKeyPairs.set(itemOid, key);
338
- }
339
- else {
340
- copy[key] = value;
341
- }
342
- }
343
- refs.set(oid, copy);
344
- }
345
- return { refs, oidKeyPairs };
346
- }
347
- export function getOidRoot(oid) {
348
- return oid.split('.')[0].split(RANDOM_SEPARATOR)[0];
349
- }
350
- /**
351
- * Returns an inclusive range of OIDs that represent
352
- * all of an OID's possible sub-objects.
353
- */
354
- export function getOidSubIdRange(oid) {
355
- const root = getOidRoot(oid);
356
- const lastSubId = createSubOid(root, () => '\uffff');
357
- return [`${root}${RANDOM_SEPARATOR}`, lastSubId];
358
- }
359
- export function getLegacyDotOidSubIdRange(oid) {
360
- const root = getOidRoot(oid);
361
- return [`${root}.`, `${root}.\uffff`];
362
- }
363
- export function getRoots(oids) {
364
- const set = new Set();
365
- for (const oid of oids) {
366
- set.add(getOidRoot(oid));
367
- }
368
- return Array.from(set);
369
- }
370
- export function areOidsRelated(oidA, oidB) {
371
- return getOidRoot(oidA) === getOidRoot(oidB);
372
- }
373
- /**
374
- * Recursively rewrites any OIDs in an object which are 'foreign' -
375
- * i.e. relate to some other object/entity - to be local to the
376
- * current object. This is deterministic, so it can be done
377
- * on multiple clients independently with predictable results.
378
- */
379
- export function fixForeignOids(obj) {
380
- const oid = maybeGetOid(obj);
381
- if (!oid)
382
- return;
383
- if (Array.isArray(obj)) {
384
- for (let i = 0; i < obj.length; i++) {
385
- migrateForeignOid(oid, obj[i]);
386
- fixForeignOids(obj[i]);
387
- }
388
- }
389
- else if (isObject(obj)) {
390
- for (const key of Object.keys(obj)) {
391
- migrateForeignOid(oid, obj[key]);
392
- fixForeignOids(obj[key]);
393
- }
394
- }
395
- }
396
- function migrateForeignOid(parentOid, child) {
397
- const childOid = maybeGetOid(child);
398
- if (childOid && !areOidsRelated(parentOid, childOid)) {
399
- const { subId, id } = decomposeOid(childOid);
400
- // reuse existing subId. if child is a foreign root, use its id as subId
401
- assignOid(child, createSubOid(parentOid, () => subId || id));
402
- }
403
- }
404
- export function isLegacyDotOid(oid) {
405
- const partBeforeRandomSep = oid.split(RANDOM_SEPARATOR)[0];
406
- return partBeforeRandomSep.includes('.');
407
- }
408
- export function convertLegacyOid(oid) {
409
- const { collection, id, subId } = decomposeOid(oid);
410
- return createOid(collection, id, subId);
411
- }
412
- export const MATCH_LEGACY_OID_JSON_STRING = /"[^"]+\/[^"]+?(\.[^"]+)+\:[^"]+"/g;
413
- export function replaceLegacyOidsInJsonString(string) {
414
- // replace every match of a legacy OID, converting to a new OID
415
- return string.replaceAll(MATCH_LEGACY_OID_JSON_STRING, (match) => {
416
- const legacyOid = match.slice(1, match.length - 1);
417
- return `"${convertLegacyOid(legacyOid)}"`;
418
- });
419
- }
420
- export function replaceLegacyOidsInObject(obj) {
421
- return JSON.parse(replaceLegacyOidsInJsonString(JSON.stringify(obj)));
422
- }
1
+ import { v4 } from 'uuid';
2
+ import { isFileRef } from './files.js';
3
+ import { isObjectRef } from './operation.js';
4
+ import { isRef } from './refs.js';
5
+ import { isObject, assert } from './utils.js';
6
+ export const LEGACY_OID_KEY = '__@@oid_do_not_use';
7
+ export const OID_KEY = '@@id';
8
+ const COLLECTION_SEPARATOR = '/';
9
+ const RANDOM_SEPARATOR = ':';
10
+ /**
11
+ * This is the global, in-memory storage for all OIDs. It is used to
12
+ * associate JS objects with OIDs without modifying the objects themselves.
13
+ */
14
+ const oidMap = new WeakMap();
15
+ export function getOid(obj) {
16
+ const oid = maybeGetOid(obj);
17
+ assert(!!oid, `Object ${JSON.stringify(obj)} does not have an OID assigned to it`);
18
+ return oid;
19
+ }
20
+ export function maybeGetOid(obj) {
21
+ var _a, _b;
22
+ if (!isObject(obj)) {
23
+ return undefined;
24
+ }
25
+ return (_b = (_a = oidMap.get(obj)) !== null && _a !== void 0 ? _a : obj[OID_KEY]) !== null && _b !== void 0 ? _b : obj[LEGACY_OID_KEY];
26
+ }
27
+ export function assignOid(obj, oid) {
28
+ assert(isObject(obj), `Only objects can be assigned OIDs, received ${JSON.stringify(obj)}`);
29
+ if (hasOid(obj)) {
30
+ removeOid(obj);
31
+ }
32
+ oidMap.set(obj, oid);
33
+ return obj;
34
+ }
35
+ export function hasOid(obj) {
36
+ return !!maybeGetOid(obj);
37
+ }
38
+ export function removeOid(obj) {
39
+ oidMap.delete(obj);
40
+ return obj;
41
+ }
42
+ export function isOidKey(key) {
43
+ return key === OID_KEY || key === LEGACY_OID_KEY;
44
+ }
45
+ /**
46
+ * For sub-objects, assign a random sub-OID if no OID
47
+ * is already assigned.
48
+ */
49
+ export function ensureOid(obj, rootOid, createSubId) {
50
+ if (!hasOid(obj)) {
51
+ const oid = createSubOid(rootOid, createSubId);
52
+ assignOid(obj, oid);
53
+ return oid;
54
+ }
55
+ else {
56
+ return getOid(obj);
57
+ }
58
+ }
59
+ export function ensureCompatibleOid(obj, rootOid, createSubId) {
60
+ if (!hasOid(obj)) {
61
+ const oid = createSubOid(rootOid, createSubId);
62
+ assignOid(obj, oid);
63
+ return oid;
64
+ }
65
+ else {
66
+ const existingOid = getOid(obj);
67
+ if (!areOidsRelated(existingOid, rootOid)) {
68
+ const oid = createSubOid(rootOid, createSubId);
69
+ assignOid(obj, oid);
70
+ return oid;
71
+ }
72
+ else {
73
+ return getOid(obj);
74
+ }
75
+ }
76
+ }
77
+ const SANTIIZE_PLACEHOLDERS = {
78
+ '.': '&dot;',
79
+ '/': '&slash;',
80
+ ':': '&colon;',
81
+ };
82
+ function sanitizeFragment(id) {
83
+ // replaces separator characters with placeholders
84
+ return id
85
+ .replace(/[/]/g, SANTIIZE_PLACEHOLDERS['/'])
86
+ .replace(/[:]/g, SANTIIZE_PLACEHOLDERS[':'])
87
+ .replace(/[.]/g, SANTIIZE_PLACEHOLDERS['.']);
88
+ }
89
+ function unsanitizeFragment(id) {
90
+ // replaces placeholders with separator characters
91
+ return id
92
+ .replace(/&slash;/g, '/')
93
+ .replace(/&colon;/g, ':')
94
+ .replace(/&dot;/g, '.');
95
+ }
96
+ export function createOid(collection, documentId, subId) {
97
+ let oid = sanitizeFragment(collection) +
98
+ COLLECTION_SEPARATOR +
99
+ sanitizeFragment(documentId);
100
+ if (subId) {
101
+ oid += RANDOM_SEPARATOR + subId;
102
+ }
103
+ return oid;
104
+ }
105
+ export function createSubOid(root, createSubId = createOidSubId) {
106
+ const { collection, id } = decomposeOid(root);
107
+ return createOid(collection, id, createSubId());
108
+ }
109
+ export function decomposeOid(oid) {
110
+ const [core, random] = oid.split(RANDOM_SEPARATOR);
111
+ const [collection, idOrLegacyPathId] = core.split('/');
112
+ let id;
113
+ if (idOrLegacyPathId.includes('.')) {
114
+ id = idOrLegacyPathId.slice(0, idOrLegacyPathId.indexOf('.'));
115
+ }
116
+ else {
117
+ id = idOrLegacyPathId;
118
+ }
119
+ return {
120
+ collection: unsanitizeFragment(collection),
121
+ id: unsanitizeFragment(id),
122
+ subId: random,
123
+ };
124
+ }
125
+ export function assertAllLevelsHaveOids(obj, root) {
126
+ assert(getOid(obj), `Object ${JSON.stringify(obj)} must have an oid (child of ${JSON.stringify(root)})`);
127
+ if (Array.isArray(obj)) {
128
+ for (const item of obj) {
129
+ assertAllLevelsHaveOids(item, root || obj);
130
+ }
131
+ }
132
+ else if (isObject(obj)) {
133
+ for (const key of Object.keys(obj)) {
134
+ assertAllLevelsHaveOids(obj[key], root || obj);
135
+ }
136
+ }
137
+ }
138
+ export function assignOidsToAllSubObjects(obj, createSubId) {
139
+ const rootOid = getOid(obj);
140
+ if (Array.isArray(obj)) {
141
+ let item;
142
+ for (let i = 0; i < obj.length; i++) {
143
+ item = obj[i];
144
+ if (isObject(item) && !isRef(item)) {
145
+ ensureCompatibleOid(item, rootOid, createSubId);
146
+ assignOidsToAllSubObjects(item, createSubId);
147
+ }
148
+ }
149
+ }
150
+ else if (isObject(obj) && !isRef(obj)) {
151
+ for (const key of Object.keys(obj)) {
152
+ if (isObject(obj[key]) && !isRef(obj[key])) {
153
+ ensureCompatibleOid(obj[key], rootOid, createSubId);
154
+ assignOidsToAllSubObjects(obj[key], createSubId);
155
+ }
156
+ }
157
+ }
158
+ }
159
+ export function assignOidProperty(obj, oid) {
160
+ assert(isObject(obj), `Only objects can be assigned OIDs, received ${JSON.stringify(obj)}`);
161
+ obj[OID_KEY] = oid;
162
+ return obj;
163
+ }
164
+ export function maybeGetOidProperty(obj) {
165
+ if (!isObject(obj)) {
166
+ return undefined;
167
+ }
168
+ return obj[OID_KEY] || obj[LEGACY_OID_KEY];
169
+ }
170
+ function removeOidProperty(obj) {
171
+ if (!isObject(obj)) {
172
+ return obj;
173
+ }
174
+ delete obj[LEGACY_OID_KEY];
175
+ delete obj[OID_KEY];
176
+ return obj;
177
+ }
178
+ function transferOidFromSystemToProperty(obj) {
179
+ const oid = maybeGetOid(obj);
180
+ if (oid) {
181
+ assignOidProperty(obj, oid);
182
+ }
183
+ }
184
+ /**
185
+ * Assigns a special property to all objects in the given object
186
+ * which have an OID
187
+ */
188
+ export function assignOidPropertiesToAllSubObjects(obj) {
189
+ transferOidFromSystemToProperty(obj);
190
+ if (Array.isArray(obj)) {
191
+ for (let i = 0; i < obj.length; i++) {
192
+ assignOidPropertiesToAllSubObjects(obj[i]);
193
+ }
194
+ }
195
+ else if (isObject(obj)) {
196
+ for (const key of Object.keys(obj)) {
197
+ assignOidPropertiesToAllSubObjects(obj[key]);
198
+ }
199
+ }
200
+ }
201
+ function copyOidFromPropertyToSystem(obj) {
202
+ const oid = maybeGetOidProperty(obj);
203
+ if (oid) {
204
+ assignOid(obj, oid);
205
+ }
206
+ }
207
+ /**
208
+ *
209
+ * Removes the special property from all objects in the given object
210
+ * which have an OID, transferring the OID from the property to the OID
211
+ * system in-memory.
212
+ */
213
+ export function removeOidPropertiesFromAllSubObjects(obj) {
214
+ copyOidFromPropertyToSystem(obj);
215
+ removeOidProperty(obj);
216
+ if (Array.isArray(obj)) {
217
+ for (let i = 0; i < obj.length; i++) {
218
+ removeOidPropertiesFromAllSubObjects(obj[i]);
219
+ }
220
+ }
221
+ else if (isObject(obj)) {
222
+ for (const key of Object.keys(obj)) {
223
+ removeOidPropertiesFromAllSubObjects(obj[key]);
224
+ }
225
+ }
226
+ }
227
+ export function removeOidsFromAllSubObjects(obj) {
228
+ removeOid(obj);
229
+ if (Array.isArray(obj)) {
230
+ for (let i = 0; i < obj.length; i++) {
231
+ removeOidsFromAllSubObjects(obj[i]);
232
+ }
233
+ }
234
+ else if (isObject(obj)) {
235
+ for (const key of Object.keys(obj)) {
236
+ removeOidsFromAllSubObjects(obj[key]);
237
+ }
238
+ }
239
+ }
240
+ export function createOidSubId() {
241
+ return v4().slice(0, 8);
242
+ }
243
+ export function createRef(oid) {
244
+ return {
245
+ '@@type': 'ref',
246
+ id: oid,
247
+ };
248
+ }
249
+ export function normalize(obj, refs = new Map()) {
250
+ if (Array.isArray(obj)) {
251
+ const oid = getOid(obj);
252
+ const copy = assignOid([], oid);
253
+ for (let i = 0; i < obj.length; i++) {
254
+ const value = obj[i];
255
+ if (isObject(value)) {
256
+ if (isObjectRef(value)) {
257
+ throw new Error('An attempt was made to normalize an already normalized object! This is an error in verdant itself.');
258
+ }
259
+ else if (isFileRef(value)) {
260
+ copy[i] = value;
261
+ continue;
262
+ }
263
+ else {
264
+ const itemOid = getOid(value);
265
+ copy[i] = createRef(itemOid);
266
+ normalize(value, refs);
267
+ }
268
+ }
269
+ else {
270
+ copy[i] = value;
271
+ }
272
+ }
273
+ refs.set(oid, copy);
274
+ }
275
+ else if (isObject(obj) && !isRef(obj)) {
276
+ const oid = getOid(obj);
277
+ const copy = assignOid({}, oid);
278
+ for (const key of Object.keys(obj)) {
279
+ const value = obj[key];
280
+ if (isObject(value)) {
281
+ if (isObjectRef(value)) {
282
+ throw new Error('An attempt was made to normalize an already normalized object! This is an error in verdant itself.');
283
+ }
284
+ else if (isFileRef(value)) {
285
+ // stop here
286
+ copy[key] = value;
287
+ }
288
+ else {
289
+ const itemOid = getOid(value);
290
+ copy[key] = createRef(itemOid);
291
+ normalize(value, refs);
292
+ }
293
+ }
294
+ else {
295
+ copy[key] = value;
296
+ }
297
+ }
298
+ refs.set(oid, copy);
299
+ }
300
+ else if (isRef(obj)) {
301
+ }
302
+ return refs;
303
+ }
304
+ /**
305
+ * Only normalizes direct children. The created map
306
+ * of objects will still have nested objects.
307
+ */
308
+ export function normalizeFirstLevel(obj) {
309
+ const refs = new Map();
310
+ const oidKeyPairs = new Map();
311
+ if (Array.isArray(obj)) {
312
+ const oid = getOid(obj);
313
+ const copy = assignOid([], oid);
314
+ for (let i = 0; i < obj.length; i++) {
315
+ const value = obj[i];
316
+ if (isObject(value)) {
317
+ const itemOid = getOid(value);
318
+ copy[i] = createRef(itemOid);
319
+ refs.set(itemOid, value);
320
+ oidKeyPairs.set(itemOid, i);
321
+ }
322
+ else {
323
+ copy[i] = value;
324
+ }
325
+ }
326
+ refs.set(oid, copy);
327
+ }
328
+ else if (isObject(obj)) {
329
+ const oid = getOid(obj);
330
+ const copy = assignOid({}, oid);
331
+ for (const key of Object.keys(obj)) {
332
+ const value = obj[key];
333
+ if (isObject(value)) {
334
+ const itemOid = getOid(value);
335
+ copy[key] = createRef(itemOid);
336
+ refs.set(itemOid, value);
337
+ oidKeyPairs.set(itemOid, key);
338
+ }
339
+ else {
340
+ copy[key] = value;
341
+ }
342
+ }
343
+ refs.set(oid, copy);
344
+ }
345
+ return { refs, oidKeyPairs };
346
+ }
347
+ export function getOidRoot(oid) {
348
+ return oid.split('.')[0].split(RANDOM_SEPARATOR)[0];
349
+ }
350
+ /**
351
+ * Returns an inclusive range of OIDs that represent
352
+ * all of an OID's possible sub-objects.
353
+ */
354
+ export function getOidSubIdRange(oid) {
355
+ const root = getOidRoot(oid);
356
+ const lastSubId = createSubOid(root, () => '\uffff');
357
+ return [`${root}${RANDOM_SEPARATOR}`, lastSubId];
358
+ }
359
+ export function getLegacyDotOidSubIdRange(oid) {
360
+ const root = getOidRoot(oid);
361
+ return [`${root}.`, `${root}.\uffff`];
362
+ }
363
+ export function getRoots(oids) {
364
+ const set = new Set();
365
+ for (const oid of oids) {
366
+ set.add(getOidRoot(oid));
367
+ }
368
+ return Array.from(set);
369
+ }
370
+ export function areOidsRelated(oidA, oidB) {
371
+ return getOidRoot(oidA) === getOidRoot(oidB);
372
+ }
373
+ /**
374
+ * Recursively rewrites any OIDs in an object which are 'foreign' -
375
+ * i.e. relate to some other object/entity - to be local to the
376
+ * current object. This is deterministic, so it can be done
377
+ * on multiple clients independently with predictable results.
378
+ */
379
+ export function fixForeignOids(obj) {
380
+ const oid = maybeGetOid(obj);
381
+ if (!oid)
382
+ return;
383
+ if (Array.isArray(obj)) {
384
+ for (let i = 0; i < obj.length; i++) {
385
+ migrateForeignOid(oid, obj[i]);
386
+ fixForeignOids(obj[i]);
387
+ }
388
+ }
389
+ else if (isObject(obj)) {
390
+ for (const key of Object.keys(obj)) {
391
+ migrateForeignOid(oid, obj[key]);
392
+ fixForeignOids(obj[key]);
393
+ }
394
+ }
395
+ }
396
+ function migrateForeignOid(parentOid, child) {
397
+ const childOid = maybeGetOid(child);
398
+ if (childOid && !areOidsRelated(parentOid, childOid)) {
399
+ const { subId, id } = decomposeOid(childOid);
400
+ // reuse existing subId. if child is a foreign root, use its id as subId
401
+ assignOid(child, createSubOid(parentOid, () => subId || id));
402
+ }
403
+ }
404
+ export function isLegacyDotOid(oid) {
405
+ const partBeforeRandomSep = oid.split(RANDOM_SEPARATOR)[0];
406
+ return partBeforeRandomSep.includes('.');
407
+ }
408
+ export function convertLegacyOid(oid) {
409
+ const { collection, id, subId } = decomposeOid(oid);
410
+ return createOid(collection, id, subId);
411
+ }
412
+ export const MATCH_LEGACY_OID_JSON_STRING = /"[^"]+\/[^"]+?(\.[^"]+)+\:[^"]+"/g;
413
+ export function replaceLegacyOidsInJsonString(string) {
414
+ // replace every match of a legacy OID, converting to a new OID
415
+ return string.replaceAll(MATCH_LEGACY_OID_JSON_STRING, (match) => {
416
+ const legacyOid = match.slice(1, match.length - 1);
417
+ return `"${convertLegacyOid(legacyOid)}"`;
418
+ });
419
+ }
420
+ export function replaceLegacyOidsInObject(obj) {
421
+ return JSON.parse(replaceLegacyOidsInJsonString(JSON.stringify(obj)));
422
+ }
423
423
  //# sourceMappingURL=oids.js.map