@verdant-web/common 1.11.0 → 1.12.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 (159) 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 +41 -41
  6. package/dist/cjs/batching.js +88 -88
  7. package/dist/cjs/files.d.ts +19 -19
  8. package/dist/cjs/files.js +18 -18
  9. package/dist/cjs/index.d.ts +18 -18
  10. package/dist/cjs/index.js +35 -35
  11. package/dist/cjs/indexes.d.ts +14 -14
  12. package/dist/cjs/indexes.js +115 -115
  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 +98 -98
  16. package/dist/cjs/migration.js +127 -127
  17. package/dist/cjs/oids.d.ts +85 -87
  18. package/dist/cjs/oids.js +363 -374
  19. package/dist/cjs/oids.js.map +1 -1
  20. package/dist/cjs/oids.test.d.ts +1 -1
  21. package/dist/cjs/oids.test.js +269 -251
  22. package/dist/cjs/oids.test.js.map +1 -1
  23. package/dist/cjs/operation.d.ts +139 -139
  24. package/dist/cjs/operation.js +532 -532
  25. package/dist/cjs/operation.js.map +1 -1
  26. package/dist/cjs/operation.test.d.ts +1 -1
  27. package/dist/cjs/operation.test.js +505 -505
  28. package/dist/cjs/operation.test.js.map +1 -1
  29. package/dist/cjs/patch.d.ts +26 -26
  30. package/dist/cjs/patch.js +226 -226
  31. package/dist/cjs/patch.js.map +1 -1
  32. package/dist/cjs/presence.d.ts +27 -27
  33. package/dist/cjs/presence.js +2 -2
  34. package/dist/cjs/protocol.d.ts +145 -145
  35. package/dist/cjs/protocol.js +3 -3
  36. package/dist/cjs/refs.d.ts +5 -5
  37. package/dist/cjs/refs.js +21 -21
  38. package/dist/cjs/replica.d.ts +28 -28
  39. package/dist/cjs/replica.js +28 -28
  40. package/dist/cjs/schema/defaults.d.ts +4 -4
  41. package/dist/cjs/schema/defaults.js +71 -71
  42. package/dist/cjs/schema/defaults.test.d.ts +1 -1
  43. package/dist/cjs/schema/defaults.test.js +20 -20
  44. package/dist/cjs/schema/defaults.test.js.map +1 -1
  45. package/dist/cjs/schema/index.d.ts +8 -8
  46. package/dist/cjs/schema/index.js +28 -28
  47. package/dist/cjs/schema/indexFilters.d.ts +6 -6
  48. package/dist/cjs/schema/indexFilters.js +30 -30
  49. package/dist/cjs/schema/types/collection.d.ts +51 -51
  50. package/dist/cjs/schema/types/collection.js +2 -2
  51. package/dist/cjs/schema/types/compounds.d.ts +12 -12
  52. package/dist/cjs/schema/types/compounds.js +2 -2
  53. package/dist/cjs/schema/types/fields.d.ts +59 -59
  54. package/dist/cjs/schema/types/fields.js +2 -2
  55. package/dist/cjs/schema/types/filters.d.ts +29 -29
  56. package/dist/cjs/schema/types/filters.js +2 -2
  57. package/dist/cjs/schema/types/shapes.d.ts +21 -21
  58. package/dist/cjs/schema/types/shapes.js +2 -2
  59. package/dist/cjs/schema/types/synthetics.d.ts +28 -28
  60. package/dist/cjs/schema/types/synthetics.js +2 -2
  61. package/dist/cjs/schema/types.d.ts +18 -18
  62. package/dist/cjs/schema/types.js +22 -22
  63. package/dist/cjs/timestamp.d.ts +48 -48
  64. package/dist/cjs/timestamp.js +243 -243
  65. package/dist/cjs/timestamp.test.d.ts +1 -1
  66. package/dist/cjs/timestamp.test.js +93 -93
  67. package/dist/cjs/undo.d.ts +3 -3
  68. package/dist/cjs/undo.js +198 -198
  69. package/dist/cjs/utils.d.ts +15 -15
  70. package/dist/cjs/utils.js +127 -127
  71. package/dist/cjs/utils.test.d.ts +1 -1
  72. package/dist/cjs/utils.test.js +36 -36
  73. package/dist/esm/EventSubscriber.d.ts +17 -17
  74. package/dist/esm/EventSubscriber.js +62 -62
  75. package/dist/esm/baseline.d.ts +5 -5
  76. package/dist/esm/baseline.js +1 -1
  77. package/dist/esm/batching.d.ts +41 -41
  78. package/dist/esm/batching.js +83 -83
  79. package/dist/esm/files.d.ts +19 -19
  80. package/dist/esm/files.js +12 -12
  81. package/dist/esm/index.d.ts +18 -18
  82. package/dist/esm/index.js +15 -15
  83. package/dist/esm/indexes.d.ts +14 -14
  84. package/dist/esm/indexes.js +105 -105
  85. package/dist/esm/indexes.test.d.ts +1 -1
  86. package/dist/esm/indexes.test.js +125 -125
  87. package/dist/esm/migration.d.ts +98 -98
  88. package/dist/esm/migration.js +121 -121
  89. package/dist/esm/oids.d.ts +85 -87
  90. package/dist/esm/oids.js +336 -347
  91. package/dist/esm/oids.js.map +1 -1
  92. package/dist/esm/oids.test.d.ts +1 -1
  93. package/dist/esm/oids.test.js +267 -249
  94. package/dist/esm/oids.test.js.map +1 -1
  95. package/dist/esm/operation.d.ts +139 -139
  96. package/dist/esm/operation.js +517 -517
  97. package/dist/esm/operation.js.map +1 -1
  98. package/dist/esm/operation.test.d.ts +1 -1
  99. package/dist/esm/operation.test.js +503 -503
  100. package/dist/esm/operation.test.js.map +1 -1
  101. package/dist/esm/patch.d.ts +26 -26
  102. package/dist/esm/patch.js +222 -222
  103. package/dist/esm/patch.js.map +1 -1
  104. package/dist/esm/presence.d.ts +27 -27
  105. package/dist/esm/presence.js +1 -1
  106. package/dist/esm/protocol.d.ts +145 -145
  107. package/dist/esm/protocol.js +2 -2
  108. package/dist/esm/refs.d.ts +5 -5
  109. package/dist/esm/refs.js +16 -16
  110. package/dist/esm/replica.d.ts +28 -28
  111. package/dist/esm/replica.js +25 -25
  112. package/dist/esm/schema/defaults.d.ts +4 -4
  113. package/dist/esm/schema/defaults.js +65 -65
  114. package/dist/esm/schema/defaults.test.d.ts +1 -1
  115. package/dist/esm/schema/defaults.test.js +18 -18
  116. package/dist/esm/schema/defaults.test.js.map +1 -1
  117. package/dist/esm/schema/index.d.ts +8 -8
  118. package/dist/esm/schema/index.js +9 -9
  119. package/dist/esm/schema/indexFilters.d.ts +6 -6
  120. package/dist/esm/schema/indexFilters.js +22 -22
  121. package/dist/esm/schema/types/collection.d.ts +51 -51
  122. package/dist/esm/schema/types/collection.js +1 -1
  123. package/dist/esm/schema/types/compounds.d.ts +12 -12
  124. package/dist/esm/schema/types/compounds.js +1 -1
  125. package/dist/esm/schema/types/fields.d.ts +59 -59
  126. package/dist/esm/schema/types/fields.js +1 -1
  127. package/dist/esm/schema/types/filters.d.ts +29 -29
  128. package/dist/esm/schema/types/filters.js +1 -1
  129. package/dist/esm/schema/types/shapes.d.ts +21 -21
  130. package/dist/esm/schema/types/shapes.js +1 -1
  131. package/dist/esm/schema/types/synthetics.d.ts +28 -28
  132. package/dist/esm/schema/types/synthetics.js +1 -1
  133. package/dist/esm/schema/types.d.ts +18 -18
  134. package/dist/esm/schema/types.js +6 -6
  135. package/dist/esm/timestamp.d.ts +48 -48
  136. package/dist/esm/timestamp.js +228 -228
  137. package/dist/esm/timestamp.test.d.ts +1 -1
  138. package/dist/esm/timestamp.test.js +91 -91
  139. package/dist/esm/undo.d.ts +3 -3
  140. package/dist/esm/undo.js +194 -194
  141. package/dist/esm/utils.d.ts +15 -15
  142. package/dist/esm/utils.js +113 -113
  143. package/dist/esm/utils.test.d.ts +1 -1
  144. package/dist/esm/utils.test.js +34 -34
  145. package/dist/tsconfig-cjs.tsbuildinfo +1 -1
  146. package/dist/tsconfig.tsbuildinfo +1 -1
  147. package/package.json +1 -1
  148. package/src/oids.test.ts +62 -51
  149. package/src/oids.ts +7 -26
  150. package/src/operation.test.ts +32 -40
  151. package/src/operation.ts +4 -16
  152. package/src/patch.ts +5 -15
  153. package/src/schema/defaults.test.ts +1 -1
  154. package/dist/cjs/files.test.d.ts +0 -1
  155. package/dist/cjs/files.test.js +0 -81
  156. package/dist/cjs/files.test.js.map +0 -1
  157. package/dist/esm/files.test.d.ts +0 -1
  158. package/dist/esm/files.test.js +0 -79
  159. package/dist/esm/files.test.js.map +0 -1
@@ -1,92 +1,92 @@
1
- import { describe, expect, it, vitest } from 'vitest';
2
- import { convertOldHlcTimestamp, HybridLogicalClockTimestampProvider, OLD_encodeVersion, OLD_serializeHlcTimestamp, } from './timestamp.js';
3
- describe('the hybrid logical clock', () => {
4
- it('always produces incrementing timestamps', async () => {
5
- const clock = new HybridLogicalClockTimestampProvider();
6
- let prev = clock.now(1);
7
- clock.update(prev);
8
- let now;
9
- for (let i = 0; i < 1000; i++) {
10
- now = clock.now(1);
11
- expect(now > prev, `${now} not later than ${prev}`).toBe(true);
12
- clock.update(now);
13
- prev = now;
14
- }
15
- let time = new Date().getTime();
16
- for (let i = 0; i < 1000; i++) {
17
- vitest.setSystemTime(time++);
18
- now = clock.now(1);
19
- expect(now > prev, `${now} not later than ${prev}`).toBe(true);
20
- clock.update(now);
21
- prev = now;
22
- }
23
- });
24
- it('groups blocks of time by version', () => {
25
- const clock = new HybridLogicalClockTimestampProvider();
26
- let prev = clock.now(1);
27
- clock.update(prev);
28
- let now;
29
- for (let i = 0; i < 10; i++) {
30
- now = clock.now(1);
31
- expect(now > prev, `${now} not later than ${prev}`).toBe(true);
32
- clock.update(now);
33
- prev = now;
34
- }
35
- for (let i = 0; i < 10; i++) {
36
- now = clock.now(2);
37
- expect(now > prev, `${now} not later than ${prev}`).toBe(true);
38
- clock.update(now);
39
- prev = now;
40
- }
41
- const startOfVersion2 = now;
42
- // jump back to 1
43
- prev = clock.now(1);
44
- clock.update(prev);
45
- for (let i = 0; i < 10; i++) {
46
- now = clock.now(1);
47
- expect(now > prev, `${now} not later than ${prev}`).toBe(true);
48
- expect(now < startOfVersion2, `${now} not earlier than ${startOfVersion2}`).toBe(true);
49
- clock.update(now);
50
- prev = now;
51
- }
52
- });
53
- it('is shorter than the previous format', () => {
54
- const clock = new HybridLogicalClockTimestampProvider();
55
- expect(clock.now(1).length).toBeLessThan(clock.OLD_now(1).length);
56
- });
57
- it('correctly converts old to new format', () => {
58
- const clock = new HybridLogicalClockTimestampProvider();
59
- const oldFormat = clock.OLD_now(1);
60
- const value = clock.timerState();
61
- const converted = convertOldHlcTimestamp(oldFormat);
62
- const newFormat = clock.get(1, value);
63
- expect(converted).toEqual(newFormat);
64
- });
65
- // this is mostly to verify as I move to the new format.
66
- // instead of attempting a distributed migration of timestamps, it
67
- // will be easier that the new format just acts as always in the
68
- // future of the old one. this will only mess with offline clients,
69
- // but nobody is using verdant but me yet at time of this change (2022-12-19)
70
- // which is kind of why I'm doing it now anyway.
71
- it('old format always comes before new format', () => {
72
- const clock = new HybridLogicalClockTimestampProvider();
73
- const newFormat = clock.now(1);
74
- const oldFormat = clock.OLD_now(1);
75
- expect(oldFormat < newFormat).toBe(true);
76
- // even far-future old timestamps are before new timestamps
77
- const oldFormat2 = OLD_serializeHlcTimestamp({
78
- counter: 999,
79
- node: '9876543210',
80
- time: new Date(3000, 1, 1).getTime(),
81
- });
82
- expect(OLD_encodeVersion(1) + oldFormat2 < newFormat).toBe(true);
83
- });
84
- it('decodes timestamps', () => {
85
- const time = new Date();
86
- vitest.setSystemTime(time);
87
- const clock = new HybridLogicalClockTimestampProvider();
88
- const now = clock.now(1);
89
- expect(clock.getWallClockTime(now)).toEqual(time.getTime());
90
- });
91
- });
1
+ import { describe, expect, it, vitest } from 'vitest';
2
+ import { convertOldHlcTimestamp, HybridLogicalClockTimestampProvider, OLD_encodeVersion, OLD_serializeHlcTimestamp, } from './timestamp.js';
3
+ describe('the hybrid logical clock', () => {
4
+ it('always produces incrementing timestamps', async () => {
5
+ const clock = new HybridLogicalClockTimestampProvider();
6
+ let prev = clock.now(1);
7
+ clock.update(prev);
8
+ let now;
9
+ for (let i = 0; i < 1000; i++) {
10
+ now = clock.now(1);
11
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
12
+ clock.update(now);
13
+ prev = now;
14
+ }
15
+ let time = new Date().getTime();
16
+ for (let i = 0; i < 1000; i++) {
17
+ vitest.setSystemTime(time++);
18
+ now = clock.now(1);
19
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
20
+ clock.update(now);
21
+ prev = now;
22
+ }
23
+ });
24
+ it('groups blocks of time by version', () => {
25
+ const clock = new HybridLogicalClockTimestampProvider();
26
+ let prev = clock.now(1);
27
+ clock.update(prev);
28
+ let now;
29
+ for (let i = 0; i < 10; i++) {
30
+ now = clock.now(1);
31
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
32
+ clock.update(now);
33
+ prev = now;
34
+ }
35
+ for (let i = 0; i < 10; i++) {
36
+ now = clock.now(2);
37
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
38
+ clock.update(now);
39
+ prev = now;
40
+ }
41
+ const startOfVersion2 = now;
42
+ // jump back to 1
43
+ prev = clock.now(1);
44
+ clock.update(prev);
45
+ for (let i = 0; i < 10; i++) {
46
+ now = clock.now(1);
47
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
48
+ expect(now < startOfVersion2, `${now} not earlier than ${startOfVersion2}`).toBe(true);
49
+ clock.update(now);
50
+ prev = now;
51
+ }
52
+ });
53
+ it('is shorter than the previous format', () => {
54
+ const clock = new HybridLogicalClockTimestampProvider();
55
+ expect(clock.now(1).length).toBeLessThan(clock.OLD_now(1).length);
56
+ });
57
+ it('correctly converts old to new format', () => {
58
+ const clock = new HybridLogicalClockTimestampProvider();
59
+ const oldFormat = clock.OLD_now(1);
60
+ const value = clock.timerState();
61
+ const converted = convertOldHlcTimestamp(oldFormat);
62
+ const newFormat = clock.get(1, value);
63
+ expect(converted).toEqual(newFormat);
64
+ });
65
+ // this is mostly to verify as I move to the new format.
66
+ // instead of attempting a distributed migration of timestamps, it
67
+ // will be easier that the new format just acts as always in the
68
+ // future of the old one. this will only mess with offline clients,
69
+ // but nobody is using verdant but me yet at time of this change (2022-12-19)
70
+ // which is kind of why I'm doing it now anyway.
71
+ it('old format always comes before new format', () => {
72
+ const clock = new HybridLogicalClockTimestampProvider();
73
+ const newFormat = clock.now(1);
74
+ const oldFormat = clock.OLD_now(1);
75
+ expect(oldFormat < newFormat).toBe(true);
76
+ // even far-future old timestamps are before new timestamps
77
+ const oldFormat2 = OLD_serializeHlcTimestamp({
78
+ counter: 999,
79
+ node: '9876543210',
80
+ time: new Date(3000, 1, 1).getTime(),
81
+ });
82
+ expect(OLD_encodeVersion(1) + oldFormat2 < newFormat).toBe(true);
83
+ });
84
+ it('decodes timestamps', () => {
85
+ const time = new Date();
86
+ vitest.setSystemTime(time);
87
+ const clock = new HybridLogicalClockTimestampProvider();
88
+ const now = clock.now(1);
89
+ expect(clock.getWallClockTime(now)).toEqual(time.getTime());
90
+ });
91
+ });
92
92
  //# sourceMappingURL=timestamp.test.js.map
@@ -1,3 +1,3 @@
1
- import { ObjectIdentifier } from './oids.js';
2
- import { Operation } from './operation.js';
3
- export declare function getUndoOperations(oid: ObjectIdentifier, initial: any, operations: Operation[], getNow: () => string): Operation[];
1
+ import { ObjectIdentifier } from './oids.js';
2
+ import { Operation } from './operation.js';
3
+ export declare function getUndoOperations(oid: ObjectIdentifier, initial: any, operations: Operation[], getNow: () => string): Operation[];
package/dist/esm/undo.js CHANGED
@@ -1,195 +1,195 @@
1
- import { applyPatch } from './operation.js';
2
- import { cloneDeep } from './utils.js';
3
- export function getUndoOperations(oid, initial, operations, getNow) {
4
- if (initial === undefined) {
5
- // if the initial state is nothing, then the undo is to delete everything.
6
- // there's nothing else to worry about!
7
- return [
8
- {
9
- oid,
10
- timestamp: getNow(),
11
- data: {
12
- op: 'delete',
13
- },
14
- },
15
- ];
16
- }
17
- // otherwise, traverse the operations one by one,
18
- // applying them, and using the prior state to determine
19
- // what the undo operation is.
20
- let state = cloneDeep(initial);
21
- const undoOperations = [];
22
- for (const operation of operations) {
23
- const undo = getUndoOperation(oid, state, operation, getNow);
24
- undoOperations.unshift(...undo);
25
- applyPatch(state, operation.data);
26
- }
27
- return undoOperations;
28
- }
29
- function getUndoOperation(oid, initial, operation, getNow) {
30
- const data = operation.data;
31
- switch (data.op) {
32
- case 'set':
33
- case 'remove':
34
- return [
35
- {
36
- oid,
37
- timestamp: getNow(),
38
- data: {
39
- op: 'set',
40
- name: data.name,
41
- value: initial[data.name],
42
- },
43
- },
44
- ];
45
- case 'list-insert':
46
- return [
47
- {
48
- oid,
49
- timestamp: getNow(),
50
- data: {
51
- op: 'list-delete',
52
- index: data.index,
53
- count: 1,
54
- },
55
- },
56
- ];
57
- case 'list-delete':
58
- return [
59
- {
60
- oid,
61
- timestamp: getNow(),
62
- data: {
63
- op: 'list-insert',
64
- index: data.index,
65
- values: initial.slice(data.index, data.count),
66
- },
67
- },
68
- ];
69
- case 'list-move-by-ref':
70
- return [
71
- {
72
- oid,
73
- timestamp: getNow(),
74
- data: {
75
- op: 'list-move-by-ref',
76
- value: data.value,
77
- index: initial.indexOf(data.value),
78
- },
79
- },
80
- ];
81
- case 'list-move-by-index':
82
- return [
83
- {
84
- oid,
85
- timestamp: getNow(),
86
- data: {
87
- op: 'list-move-by-index',
88
- from: data.to,
89
- to: data.from,
90
- },
91
- },
92
- ];
93
- case 'delete':
94
- return [
95
- {
96
- oid,
97
- timestamp: getNow(),
98
- data: {
99
- op: 'initialize',
100
- value: initial,
101
- },
102
- },
103
- ];
104
- case 'list-push':
105
- return [
106
- {
107
- oid,
108
- timestamp: getNow(),
109
- data: {
110
- op: 'list-remove',
111
- value: data.value,
112
- // best heuristic here - remove the last instance of the item.
113
- only: 'last',
114
- },
115
- },
116
- ];
117
- case 'list-remove':
118
- if (data.only === 'last') {
119
- const index = initial.lastIndexOf(data.value);
120
- return [
121
- {
122
- oid,
123
- timestamp: getNow(),
124
- data: {
125
- op: 'list-insert',
126
- index,
127
- values: [data.value],
128
- },
129
- },
130
- ];
131
- }
132
- else if (data.only === 'first') {
133
- const index = initial.indexOf(data.value);
134
- return [
135
- {
136
- oid,
137
- timestamp: getNow(),
138
- data: {
139
- op: 'list-insert',
140
- index,
141
- values: [data.value],
142
- },
143
- },
144
- ];
145
- }
146
- else {
147
- // find all instances of value and restore them at their
148
- // original index
149
- const indexesOfValue = [];
150
- let index = initial.indexOf(data.value);
151
- while (index !== -1) {
152
- indexesOfValue.push(index);
153
- index = initial.indexOf(data.value, index + 1);
154
- }
155
- return indexesOfValue.map((index) => ({
156
- oid,
157
- timestamp: getNow(),
158
- data: {
159
- op: 'list-insert',
160
- index,
161
- value: data.value,
162
- },
163
- }));
164
- }
165
- case 'list-add':
166
- // this one is kind of ambiguous. in theory the set may have
167
- // already included the value and so no change happened. but
168
- // basically we infer the intent is to remove what was meant
169
- // to be added by this change.
170
- return [
171
- {
172
- oid,
173
- timestamp: getNow(),
174
- data: {
175
- op: 'list-remove',
176
- value: data.value,
177
- only: 'last',
178
- },
179
- },
180
- ];
181
- case 'initialize':
182
- return [
183
- {
184
- oid,
185
- timestamp: getNow(),
186
- data: {
187
- op: 'delete',
188
- },
189
- },
190
- ];
191
- default:
192
- throw new Error(`Cannot undo operation type: ${data.op}`);
193
- }
194
- }
1
+ import { applyPatch } from './operation.js';
2
+ import { cloneDeep } from './utils.js';
3
+ export function getUndoOperations(oid, initial, operations, getNow) {
4
+ if (initial === undefined) {
5
+ // if the initial state is nothing, then the undo is to delete everything.
6
+ // there's nothing else to worry about!
7
+ return [
8
+ {
9
+ oid,
10
+ timestamp: getNow(),
11
+ data: {
12
+ op: 'delete',
13
+ },
14
+ },
15
+ ];
16
+ }
17
+ // otherwise, traverse the operations one by one,
18
+ // applying them, and using the prior state to determine
19
+ // what the undo operation is.
20
+ let state = cloneDeep(initial);
21
+ const undoOperations = [];
22
+ for (const operation of operations) {
23
+ const undo = getUndoOperation(oid, state, operation, getNow);
24
+ undoOperations.unshift(...undo);
25
+ applyPatch(state, operation.data);
26
+ }
27
+ return undoOperations;
28
+ }
29
+ function getUndoOperation(oid, initial, operation, getNow) {
30
+ const data = operation.data;
31
+ switch (data.op) {
32
+ case 'set':
33
+ case 'remove':
34
+ return [
35
+ {
36
+ oid,
37
+ timestamp: getNow(),
38
+ data: {
39
+ op: 'set',
40
+ name: data.name,
41
+ value: initial[data.name],
42
+ },
43
+ },
44
+ ];
45
+ case 'list-insert':
46
+ return [
47
+ {
48
+ oid,
49
+ timestamp: getNow(),
50
+ data: {
51
+ op: 'list-delete',
52
+ index: data.index,
53
+ count: 1,
54
+ },
55
+ },
56
+ ];
57
+ case 'list-delete':
58
+ return [
59
+ {
60
+ oid,
61
+ timestamp: getNow(),
62
+ data: {
63
+ op: 'list-insert',
64
+ index: data.index,
65
+ values: initial.slice(data.index, data.count),
66
+ },
67
+ },
68
+ ];
69
+ case 'list-move-by-ref':
70
+ return [
71
+ {
72
+ oid,
73
+ timestamp: getNow(),
74
+ data: {
75
+ op: 'list-move-by-ref',
76
+ value: data.value,
77
+ index: initial.indexOf(data.value),
78
+ },
79
+ },
80
+ ];
81
+ case 'list-move-by-index':
82
+ return [
83
+ {
84
+ oid,
85
+ timestamp: getNow(),
86
+ data: {
87
+ op: 'list-move-by-index',
88
+ from: data.to,
89
+ to: data.from,
90
+ },
91
+ },
92
+ ];
93
+ case 'delete':
94
+ return [
95
+ {
96
+ oid,
97
+ timestamp: getNow(),
98
+ data: {
99
+ op: 'initialize',
100
+ value: initial,
101
+ },
102
+ },
103
+ ];
104
+ case 'list-push':
105
+ return [
106
+ {
107
+ oid,
108
+ timestamp: getNow(),
109
+ data: {
110
+ op: 'list-remove',
111
+ value: data.value,
112
+ // best heuristic here - remove the last instance of the item.
113
+ only: 'last',
114
+ },
115
+ },
116
+ ];
117
+ case 'list-remove':
118
+ if (data.only === 'last') {
119
+ const index = initial.lastIndexOf(data.value);
120
+ return [
121
+ {
122
+ oid,
123
+ timestamp: getNow(),
124
+ data: {
125
+ op: 'list-insert',
126
+ index,
127
+ values: [data.value],
128
+ },
129
+ },
130
+ ];
131
+ }
132
+ else if (data.only === 'first') {
133
+ const index = initial.indexOf(data.value);
134
+ return [
135
+ {
136
+ oid,
137
+ timestamp: getNow(),
138
+ data: {
139
+ op: 'list-insert',
140
+ index,
141
+ values: [data.value],
142
+ },
143
+ },
144
+ ];
145
+ }
146
+ else {
147
+ // find all instances of value and restore them at their
148
+ // original index
149
+ const indexesOfValue = [];
150
+ let index = initial.indexOf(data.value);
151
+ while (index !== -1) {
152
+ indexesOfValue.push(index);
153
+ index = initial.indexOf(data.value, index + 1);
154
+ }
155
+ return indexesOfValue.map((index) => ({
156
+ oid,
157
+ timestamp: getNow(),
158
+ data: {
159
+ op: 'list-insert',
160
+ index,
161
+ value: data.value,
162
+ },
163
+ }));
164
+ }
165
+ case 'list-add':
166
+ // this one is kind of ambiguous. in theory the set may have
167
+ // already included the value and so no change happened. but
168
+ // basically we infer the intent is to remove what was meant
169
+ // to be added by this change.
170
+ return [
171
+ {
172
+ oid,
173
+ timestamp: getNow(),
174
+ data: {
175
+ op: 'list-remove',
176
+ value: data.value,
177
+ only: 'last',
178
+ },
179
+ },
180
+ ];
181
+ case 'initialize':
182
+ return [
183
+ {
184
+ oid,
185
+ timestamp: getNow(),
186
+ data: {
187
+ op: 'delete',
188
+ },
189
+ },
190
+ ];
191
+ default:
192
+ throw new Error(`Cannot undo operation type: ${data.op}`);
193
+ }
194
+ }
195
195
  //# sourceMappingURL=undo.js.map
@@ -1,15 +1,15 @@
1
- export declare function take<T extends object, Keys extends keyof T>(obj: T, keys: Keys[]): Pick<T, Keys>;
2
- export declare function omit<T extends object, Keys extends keyof T>(obj: T, keys: Keys[]): Omit<T, Keys>;
3
- export declare function getSortedIndex<T>(array: T[], insert: T, compare: (a: T, b: T) => number): number;
4
- /**
5
- * Consistently stringifies an object regardless
6
- * of key insertion order
7
- */
8
- export declare function stableStringify(obj: any): string;
9
- export declare function cloneDeep<T>(obj: T): T;
10
- export declare function hashObject(obj: any): string;
11
- export declare function isObject(obj: any): any;
12
- export declare function roughSizeOfObject(object: any): number;
13
- export declare function assert(condition: any, message?: string): asserts condition;
14
- export declare function generateId(length?: number): string;
15
- export declare function findLastIndex<T>(array: T[], predicate: (item: T) => boolean): number;
1
+ export declare function take<T extends object, Keys extends keyof T>(obj: T, keys: Keys[]): Pick<T, Keys>;
2
+ export declare function omit<T extends object, Keys extends keyof T>(obj: T, keys: Keys[]): Omit<T, Keys>;
3
+ export declare function getSortedIndex<T>(array: T[], insert: T, compare: (a: T, b: T) => number): number;
4
+ /**
5
+ * Consistently stringifies an object regardless
6
+ * of key insertion order
7
+ */
8
+ export declare function stableStringify(obj: any): string;
9
+ export declare function cloneDeep<T>(obj: T): T;
10
+ export declare function hashObject(obj: any): string;
11
+ export declare function isObject(obj: any): any;
12
+ export declare function roughSizeOfObject(object: any): number;
13
+ export declare function assert(condition: any, message?: string): asserts condition;
14
+ export declare function generateId(length?: number): string;
15
+ export declare function findLastIndex<T>(array: T[], predicate: (item: T) => boolean): number;