@verdant-web/common 1.15.2 → 1.15.3-next.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.
- package/dist/cjs/EventSubscriber.d.ts +17 -17
- package/dist/cjs/EventSubscriber.js +66 -66
- package/dist/cjs/baseline.d.ts +5 -5
- package/dist/cjs/baseline.js +2 -2
- package/dist/cjs/batching.d.ts +42 -42
- package/dist/cjs/batching.js +91 -91
- package/dist/cjs/files.d.ts +19 -19
- package/dist/cjs/files.js +18 -18
- package/dist/cjs/files.test.d.ts +1 -0
- package/dist/cjs/files.test.js +81 -0
- package/dist/cjs/files.test.js.map +1 -0
- package/dist/cjs/index.d.ts +19 -18
- package/dist/cjs/index.js +41 -36
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/indexes.d.ts +17 -17
- package/dist/cjs/indexes.js +142 -142
- package/dist/cjs/indexes.test.d.ts +1 -1
- package/dist/cjs/indexes.test.js +127 -127
- package/dist/cjs/migration.d.ts +172 -172
- package/dist/cjs/migration.js +301 -301
- package/dist/cjs/oids.d.ts +100 -96
- package/dist/cjs/oids.js +457 -439
- package/dist/cjs/oids.js.map +1 -1
- package/dist/cjs/oids.test.d.ts +1 -1
- package/dist/cjs/oids.test.js +348 -272
- package/dist/cjs/oids.test.js.map +1 -1
- package/dist/cjs/operation.d.ts +139 -139
- package/dist/cjs/operation.js +545 -545
- package/dist/cjs/operation.test.d.ts +1 -1
- package/dist/cjs/operation.test.js +529 -529
- package/dist/cjs/patch.d.ts +26 -26
- package/dist/cjs/patch.js +226 -226
- package/dist/cjs/presence.d.ts +27 -27
- package/dist/cjs/presence.js +2 -2
- package/dist/cjs/protocol.d.ts +145 -145
- package/dist/cjs/protocol.js +3 -3
- package/dist/cjs/refs.d.ts +7 -5
- package/dist/cjs/refs.js +29 -21
- package/dist/cjs/refs.js.map +1 -1
- package/dist/cjs/replica.d.ts +28 -28
- package/dist/cjs/replica.js +28 -28
- package/dist/cjs/schema/defaults.d.ts +4 -0
- package/dist/cjs/schema/defaults.js +72 -0
- package/dist/cjs/schema/defaults.js.map +1 -0
- package/dist/cjs/schema/defaults.test.d.ts +1 -1
- package/dist/cjs/schema/defaults.test.js +20 -20
- package/dist/cjs/schema/fields.d.ts +9 -9
- package/dist/cjs/schema/fields.js +144 -144
- package/dist/cjs/schema/index.d.ts +8 -8
- package/dist/cjs/schema/index.js +51 -51
- package/dist/cjs/schema/indexFilters.d.ts +6 -6
- package/dist/cjs/schema/indexFilters.js +30 -30
- package/dist/cjs/schema/types/collection.d.ts +23 -23
- package/dist/cjs/schema/types/collection.js +2 -2
- package/dist/cjs/schema/types/compounds.d.ts +11 -11
- package/dist/cjs/schema/types/compounds.js +2 -2
- package/dist/cjs/schema/types/fields.d.ts +75 -75
- package/dist/cjs/schema/types/fields.js +2 -2
- package/dist/cjs/schema/types/filters.d.ts +29 -29
- package/dist/cjs/schema/types/filters.js +2 -2
- package/dist/cjs/schema/types/shapes.d.ts +21 -21
- package/dist/cjs/schema/types/shapes.js +2 -2
- package/dist/cjs/schema/types/synthetics.d.ts +37 -37
- package/dist/cjs/schema/types/synthetics.js +2 -2
- package/dist/cjs/schema/types.d.ts +18 -18
- package/dist/cjs/schema/types.js +22 -22
- package/dist/cjs/schema/validation.d.ts +3 -3
- package/dist/cjs/schema/validation.js +86 -86
- package/dist/cjs/timestamp.d.ts +50 -50
- package/dist/cjs/timestamp.js +251 -251
- package/dist/cjs/timestamp.test.d.ts +1 -1
- package/dist/cjs/timestamp.test.js +104 -104
- package/dist/cjs/undo.d.ts +3 -3
- package/dist/cjs/undo.js +198 -198
- package/dist/cjs/utils.d.ts +20 -20
- package/dist/cjs/utils.js +145 -145
- package/dist/cjs/utils.test.d.ts +1 -1
- package/dist/cjs/utils.test.js +36 -36
- package/dist/esm/EventSubscriber.d.ts +17 -17
- package/dist/esm/EventSubscriber.js +62 -62
- package/dist/esm/baseline.d.ts +5 -5
- package/dist/esm/baseline.js +1 -1
- package/dist/esm/batching.d.ts +42 -42
- package/dist/esm/batching.js +86 -86
- package/dist/esm/files.d.ts +19 -19
- package/dist/esm/files.js +12 -12
- package/dist/esm/files.test.d.ts +1 -0
- package/dist/esm/files.test.js +79 -0
- package/dist/esm/files.test.js.map +1 -0
- package/dist/esm/index.d.ts +19 -18
- package/dist/esm/index.js +16 -15
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/indexes.d.ts +17 -17
- package/dist/esm/indexes.js +130 -130
- package/dist/esm/indexes.test.d.ts +1 -1
- package/dist/esm/indexes.test.js +125 -125
- package/dist/esm/migration.d.ts +172 -172
- package/dist/esm/migration.js +294 -294
- package/dist/esm/oids.d.ts +100 -96
- package/dist/esm/oids.js +422 -407
- package/dist/esm/oids.js.map +1 -1
- package/dist/esm/oids.test.d.ts +1 -1
- package/dist/esm/oids.test.js +346 -270
- package/dist/esm/oids.test.js.map +1 -1
- package/dist/esm/operation.d.ts +139 -139
- package/dist/esm/operation.js +530 -530
- package/dist/esm/operation.test.d.ts +1 -1
- package/dist/esm/operation.test.js +527 -527
- package/dist/esm/patch.d.ts +26 -26
- package/dist/esm/patch.js +222 -222
- package/dist/esm/presence.d.ts +27 -27
- package/dist/esm/presence.js +1 -1
- package/dist/esm/protocol.d.ts +145 -145
- package/dist/esm/protocol.js +2 -2
- package/dist/esm/refs.d.ts +7 -5
- package/dist/esm/refs.js +22 -16
- package/dist/esm/refs.js.map +1 -1
- package/dist/esm/replica.d.ts +28 -28
- package/dist/esm/replica.js +25 -25
- package/dist/esm/schema/defaults.d.ts +4 -0
- package/dist/esm/schema/defaults.js +66 -0
- package/dist/esm/schema/defaults.js.map +1 -0
- package/dist/esm/schema/defaults.test.d.ts +1 -1
- package/dist/esm/schema/defaults.test.js +18 -18
- package/dist/esm/schema/fields.d.ts +9 -9
- package/dist/esm/schema/fields.js +133 -133
- package/dist/esm/schema/index.d.ts +8 -8
- package/dist/esm/schema/index.js +32 -32
- package/dist/esm/schema/indexFilters.d.ts +6 -6
- package/dist/esm/schema/indexFilters.js +22 -22
- package/dist/esm/schema/types/collection.d.ts +23 -23
- package/dist/esm/schema/types/collection.js +1 -1
- package/dist/esm/schema/types/compounds.d.ts +11 -11
- package/dist/esm/schema/types/compounds.js +1 -1
- package/dist/esm/schema/types/fields.d.ts +75 -75
- package/dist/esm/schema/types/fields.js +1 -1
- package/dist/esm/schema/types/filters.d.ts +29 -29
- package/dist/esm/schema/types/filters.js +1 -1
- package/dist/esm/schema/types/shapes.d.ts +21 -21
- package/dist/esm/schema/types/shapes.js +1 -1
- package/dist/esm/schema/types/synthetics.d.ts +37 -37
- package/dist/esm/schema/types/synthetics.js +1 -1
- package/dist/esm/schema/types.d.ts +18 -18
- package/dist/esm/schema/types.js +6 -6
- package/dist/esm/schema/validation.d.ts +3 -3
- package/dist/esm/schema/validation.js +81 -81
- package/dist/esm/timestamp.d.ts +50 -50
- package/dist/esm/timestamp.js +234 -234
- package/dist/esm/timestamp.test.d.ts +1 -1
- package/dist/esm/timestamp.test.js +102 -102
- package/dist/esm/undo.d.ts +3 -3
- package/dist/esm/undo.js +194 -194
- package/dist/esm/utils.d.ts +20 -20
- package/dist/esm/utils.js +127 -127
- package/dist/esm/utils.test.d.ts +1 -1
- package/dist/esm/utils.test.js +34 -34
- package/dist/tsconfig-cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/oids.test.ts +82 -0
- package/src/oids.ts +17 -0
- package/src/refs.ts +8 -0
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { createFileRef } from './files.js';
|
|
3
|
-
import { assignOid, assignOidsToAllSubObjects, createRef, getOid, } from './oids.js';
|
|
4
|
-
import { applyPatch, applyOperations, diffToPatches, initialToPatches, substituteRefsWithObjects, } from './operation.js';
|
|
5
|
-
function createClock(init = 0) {
|
|
6
|
-
let i = init;
|
|
7
|
-
const clock = () => (i++).toString();
|
|
8
|
-
Object.defineProperty(clock, 'current', {
|
|
9
|
-
get() {
|
|
10
|
-
return i;
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
return clock;
|
|
14
|
-
}
|
|
15
|
-
describe('creating diff patch operations', () => {
|
|
16
|
-
describe('on flat objects', () => {
|
|
17
|
-
it('generates and applies set and remove operations', () => {
|
|
18
|
-
const from = { foo: 'bar', baz: 'qux', zing: 1 };
|
|
19
|
-
assignOid(from, 'test/a');
|
|
20
|
-
const to = { foo: 'bar', baz: 'pop' };
|
|
21
|
-
assignOid(to, 'test/a');
|
|
22
|
-
const ops = diffToPatches(from, to, createClock());
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createFileRef } from './files.js';
|
|
3
|
+
import { assignOid, assignOidsToAllSubObjects, createRef, getOid, } from './oids.js';
|
|
4
|
+
import { applyPatch, applyOperations, diffToPatches, initialToPatches, substituteRefsWithObjects, } from './operation.js';
|
|
5
|
+
function createClock(init = 0) {
|
|
6
|
+
let i = init;
|
|
7
|
+
const clock = () => (i++).toString();
|
|
8
|
+
Object.defineProperty(clock, 'current', {
|
|
9
|
+
get() {
|
|
10
|
+
return i;
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
return clock;
|
|
14
|
+
}
|
|
15
|
+
describe('creating diff patch operations', () => {
|
|
16
|
+
describe('on flat objects', () => {
|
|
17
|
+
it('generates and applies set and remove operations', () => {
|
|
18
|
+
const from = { foo: 'bar', baz: 'qux', zing: 1 };
|
|
19
|
+
assignOid(from, 'test/a');
|
|
20
|
+
const to = { foo: 'bar', baz: 'pop' };
|
|
21
|
+
assignOid(to, 'test/a');
|
|
22
|
+
const ops = diffToPatches(from, to, createClock());
|
|
23
23
|
expect(ops).toMatchInlineSnapshot(`
|
|
24
24
|
[
|
|
25
25
|
{
|
|
@@ -40,22 +40,22 @@ describe('creating diff patch operations', () => {
|
|
|
40
40
|
"timestamp": "1",
|
|
41
41
|
},
|
|
42
42
|
]
|
|
43
|
-
`);
|
|
44
|
-
const result = applyOperations(from, ops);
|
|
45
|
-
expect(result).toEqual(to);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe('on nested objects', () => {
|
|
49
|
-
it('replaces whole nested objects', () => {
|
|
50
|
-
const from = assignOid({
|
|
51
|
-
foo: 'bar',
|
|
52
|
-
baz: assignOid({ qux: 'corge' }, 'test/a:0'),
|
|
53
|
-
}, 'test/a');
|
|
54
|
-
const to = assignOid({
|
|
55
|
-
foo: 'bar',
|
|
56
|
-
baz: assignOid({ qux: 'grault' }, 'test/a:1'),
|
|
57
|
-
}, 'test/a');
|
|
58
|
-
const patches = diffToPatches(from, to, createClock());
|
|
43
|
+
`);
|
|
44
|
+
const result = applyOperations(from, ops);
|
|
45
|
+
expect(result).toEqual(to);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe('on nested objects', () => {
|
|
49
|
+
it('replaces whole nested objects', () => {
|
|
50
|
+
const from = assignOid({
|
|
51
|
+
foo: 'bar',
|
|
52
|
+
baz: assignOid({ qux: 'corge' }, 'test/a:0'),
|
|
53
|
+
}, 'test/a');
|
|
54
|
+
const to = assignOid({
|
|
55
|
+
foo: 'bar',
|
|
56
|
+
baz: assignOid({ qux: 'grault' }, 'test/a:1'),
|
|
57
|
+
}, 'test/a');
|
|
58
|
+
const patches = diffToPatches(from, to, createClock());
|
|
59
59
|
expect(patches).toMatchInlineSnapshot(`
|
|
60
60
|
[
|
|
61
61
|
{
|
|
@@ -88,22 +88,22 @@ describe('creating diff patch operations', () => {
|
|
|
88
88
|
"timestamp": "2",
|
|
89
89
|
},
|
|
90
90
|
]
|
|
91
|
-
`);
|
|
92
|
-
});
|
|
93
|
-
it('replaces whole nested objects with different ids even if fields are the same', () => {
|
|
94
|
-
const from = {
|
|
95
|
-
foo: 'bar',
|
|
96
|
-
baz: { qux: 'corge' },
|
|
97
|
-
};
|
|
98
|
-
assignOid(from, 'test/a');
|
|
99
|
-
assignOid(from.baz, 'test/a:0');
|
|
100
|
-
const to = {
|
|
101
|
-
foo: 'bar',
|
|
102
|
-
baz: { qux: 'corge' },
|
|
103
|
-
};
|
|
104
|
-
assignOid(to, 'test/a');
|
|
105
|
-
assignOid(to.baz, 'test/a:1');
|
|
106
|
-
const patches = diffToPatches(from, to, createClock());
|
|
91
|
+
`);
|
|
92
|
+
});
|
|
93
|
+
it('replaces whole nested objects with different ids even if fields are the same', () => {
|
|
94
|
+
const from = {
|
|
95
|
+
foo: 'bar',
|
|
96
|
+
baz: { qux: 'corge' },
|
|
97
|
+
};
|
|
98
|
+
assignOid(from, 'test/a');
|
|
99
|
+
assignOid(from.baz, 'test/a:0');
|
|
100
|
+
const to = {
|
|
101
|
+
foo: 'bar',
|
|
102
|
+
baz: { qux: 'corge' },
|
|
103
|
+
};
|
|
104
|
+
assignOid(to, 'test/a');
|
|
105
|
+
assignOid(to.baz, 'test/a:1');
|
|
106
|
+
const patches = diffToPatches(from, to, createClock());
|
|
107
107
|
expect(patches).toMatchInlineSnapshot(`
|
|
108
108
|
[
|
|
109
109
|
{
|
|
@@ -136,38 +136,38 @@ describe('creating diff patch operations', () => {
|
|
|
136
136
|
"timestamp": "2",
|
|
137
137
|
},
|
|
138
138
|
]
|
|
139
|
-
`);
|
|
140
|
-
});
|
|
141
|
-
it('does not replace objects with the same identity and same fields', () => {
|
|
142
|
-
const from = {
|
|
143
|
-
foo: 'bar',
|
|
144
|
-
baz: { qux: 'corge' },
|
|
145
|
-
};
|
|
146
|
-
assignOid(from, 'test/a');
|
|
147
|
-
assignOid(from.baz, 'test/a:0');
|
|
148
|
-
const to = {
|
|
149
|
-
foo: 'bar',
|
|
150
|
-
baz: { qux: 'corge' },
|
|
151
|
-
};
|
|
152
|
-
assignOid(to, 'test/a');
|
|
153
|
-
assignOid(to.baz, 'test/a:0');
|
|
154
|
-
const patches = diffToPatches(from, to, createClock());
|
|
155
|
-
expect(patches).toEqual([]);
|
|
156
|
-
});
|
|
157
|
-
it('patches sub-objects with same identity', () => {
|
|
158
|
-
const from = {
|
|
159
|
-
foo: 'bar',
|
|
160
|
-
baz: { qux: 'corge' },
|
|
161
|
-
};
|
|
162
|
-
assignOid(from, 'test/a');
|
|
163
|
-
assignOid(from.baz, 'test/a:0');
|
|
164
|
-
const to = {
|
|
165
|
-
foo: 'bar',
|
|
166
|
-
baz: { qux: 'fig' },
|
|
167
|
-
};
|
|
168
|
-
assignOid(to, 'test/a');
|
|
169
|
-
assignOid(to.baz, 'test/a:0');
|
|
170
|
-
const patches = diffToPatches(from, to, createClock());
|
|
139
|
+
`);
|
|
140
|
+
});
|
|
141
|
+
it('does not replace objects with the same identity and same fields', () => {
|
|
142
|
+
const from = {
|
|
143
|
+
foo: 'bar',
|
|
144
|
+
baz: { qux: 'corge' },
|
|
145
|
+
};
|
|
146
|
+
assignOid(from, 'test/a');
|
|
147
|
+
assignOid(from.baz, 'test/a:0');
|
|
148
|
+
const to = {
|
|
149
|
+
foo: 'bar',
|
|
150
|
+
baz: { qux: 'corge' },
|
|
151
|
+
};
|
|
152
|
+
assignOid(to, 'test/a');
|
|
153
|
+
assignOid(to.baz, 'test/a:0');
|
|
154
|
+
const patches = diffToPatches(from, to, createClock());
|
|
155
|
+
expect(patches).toEqual([]);
|
|
156
|
+
});
|
|
157
|
+
it('patches sub-objects with same identity', () => {
|
|
158
|
+
const from = {
|
|
159
|
+
foo: 'bar',
|
|
160
|
+
baz: { qux: 'corge' },
|
|
161
|
+
};
|
|
162
|
+
assignOid(from, 'test/a');
|
|
163
|
+
assignOid(from.baz, 'test/a:0');
|
|
164
|
+
const to = {
|
|
165
|
+
foo: 'bar',
|
|
166
|
+
baz: { qux: 'fig' },
|
|
167
|
+
};
|
|
168
|
+
assignOid(to, 'test/a');
|
|
169
|
+
assignOid(to.baz, 'test/a:0');
|
|
170
|
+
const patches = diffToPatches(from, to, createClock());
|
|
171
171
|
expect(patches).toMatchInlineSnapshot(`
|
|
172
172
|
[
|
|
173
173
|
{
|
|
@@ -180,23 +180,23 @@ describe('creating diff patch operations', () => {
|
|
|
180
180
|
"timestamp": "0",
|
|
181
181
|
},
|
|
182
182
|
]
|
|
183
|
-
`);
|
|
184
|
-
});
|
|
185
|
-
it('retains keys which are undefined in new object if defaultUndefined is set', () => {
|
|
186
|
-
const from = {
|
|
187
|
-
foo: 'bar',
|
|
188
|
-
baz: { qux: 'corge' },
|
|
189
|
-
};
|
|
190
|
-
assignOid(from, 'test/a');
|
|
191
|
-
assignOid(from.baz, 'test/a:0');
|
|
192
|
-
const to = {
|
|
193
|
-
foo: 'bip',
|
|
194
|
-
};
|
|
195
|
-
assignOid(to, 'test/a');
|
|
196
|
-
const patches = diffToPatches(from, to, createClock(), undefined, [], {
|
|
197
|
-
defaultUndefined: true,
|
|
198
|
-
mergeUnknownObjects: true,
|
|
199
|
-
});
|
|
183
|
+
`);
|
|
184
|
+
});
|
|
185
|
+
it('retains keys which are undefined in new object if defaultUndefined is set', () => {
|
|
186
|
+
const from = {
|
|
187
|
+
foo: 'bar',
|
|
188
|
+
baz: { qux: 'corge' },
|
|
189
|
+
};
|
|
190
|
+
assignOid(from, 'test/a');
|
|
191
|
+
assignOid(from.baz, 'test/a:0');
|
|
192
|
+
const to = {
|
|
193
|
+
foo: 'bip',
|
|
194
|
+
};
|
|
195
|
+
assignOid(to, 'test/a');
|
|
196
|
+
const patches = diffToPatches(from, to, createClock(), undefined, [], {
|
|
197
|
+
defaultUndefined: true,
|
|
198
|
+
mergeUnknownObjects: true,
|
|
199
|
+
});
|
|
200
200
|
expect(patches).toMatchInlineSnapshot(`
|
|
201
201
|
[
|
|
202
202
|
{
|
|
@@ -209,74 +209,74 @@ describe('creating diff patch operations', () => {
|
|
|
209
209
|
"timestamp": "0",
|
|
210
210
|
},
|
|
211
211
|
]
|
|
212
|
-
`);
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
describe('on lists of primitives', () => {
|
|
216
|
-
it('pushes items', async () => {
|
|
217
|
-
expect(applyOperations(assignOid(['foo', 'bar'], 'test/a'), [
|
|
218
|
-
{
|
|
219
|
-
oid: 'test/a',
|
|
220
|
-
timestamp: 'meh',
|
|
221
|
-
data: {
|
|
222
|
-
op: 'list-push',
|
|
223
|
-
value: 'baz',
|
|
224
|
-
},
|
|
225
|
-
},
|
|
226
|
-
])).toEqual(assignOid(['foo', 'bar', 'baz'], 'test/a'));
|
|
227
|
-
});
|
|
228
|
-
it.todo('sets items');
|
|
229
|
-
it.todo('inserts items');
|
|
230
|
-
it.todo('removes items by index');
|
|
231
|
-
it.todo('removes items by value');
|
|
232
|
-
it.todo('moves items by index');
|
|
233
|
-
it.todo('moves items by value');
|
|
234
|
-
});
|
|
235
|
-
describe.todo('on lists of objects', () => {
|
|
236
|
-
it.todo('pushes items');
|
|
237
|
-
it.todo('moves objects by identity');
|
|
238
|
-
it.todo('removes objects by identity');
|
|
239
|
-
});
|
|
240
|
-
describe.todo('on lists of lists', () => {
|
|
241
|
-
it.todo('rejects operations by value or identity');
|
|
242
|
-
});
|
|
243
|
-
it('should work for complex nested arrays and objects', () => {
|
|
244
|
-
const from = {
|
|
245
|
-
foo: {
|
|
246
|
-
bar: [1, 2, 3],
|
|
247
|
-
},
|
|
248
|
-
baz: [
|
|
249
|
-
{
|
|
250
|
-
corge: true,
|
|
251
|
-
},
|
|
252
|
-
],
|
|
253
|
-
};
|
|
254
|
-
assignOid(from, 'test/a');
|
|
255
|
-
assignOid(from.foo, 'test/a:1');
|
|
256
|
-
assignOid(from.foo.bar, 'test/a:2');
|
|
257
|
-
assignOid(from.baz, 'test/a:3');
|
|
258
|
-
assignOid(from.baz[0], 'test/a:4');
|
|
259
|
-
const to = {
|
|
260
|
-
foo: {
|
|
261
|
-
bar: [1, 2],
|
|
262
|
-
bop: [0],
|
|
263
|
-
},
|
|
264
|
-
baz: [
|
|
265
|
-
{
|
|
266
|
-
corge: false,
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
corge: false,
|
|
270
|
-
},
|
|
271
|
-
],
|
|
272
|
-
};
|
|
273
|
-
assignOid(to, 'test/a');
|
|
274
|
-
assignOid(to.foo, 'test/a:1');
|
|
275
|
-
assignOid(to.foo.bar, 'test/a:2');
|
|
276
|
-
assignOid(to.foo.bop, 'test/a:6');
|
|
277
|
-
assignOid(to.baz, 'test/a:3');
|
|
278
|
-
assignOid(to.baz[0], 'test/a:4');
|
|
279
|
-
assignOid(to.baz[1], 'test/a:5');
|
|
212
|
+
`);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
describe('on lists of primitives', () => {
|
|
216
|
+
it('pushes items', async () => {
|
|
217
|
+
expect(applyOperations(assignOid(['foo', 'bar'], 'test/a'), [
|
|
218
|
+
{
|
|
219
|
+
oid: 'test/a',
|
|
220
|
+
timestamp: 'meh',
|
|
221
|
+
data: {
|
|
222
|
+
op: 'list-push',
|
|
223
|
+
value: 'baz',
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
])).toEqual(assignOid(['foo', 'bar', 'baz'], 'test/a'));
|
|
227
|
+
});
|
|
228
|
+
it.todo('sets items');
|
|
229
|
+
it.todo('inserts items');
|
|
230
|
+
it.todo('removes items by index');
|
|
231
|
+
it.todo('removes items by value');
|
|
232
|
+
it.todo('moves items by index');
|
|
233
|
+
it.todo('moves items by value');
|
|
234
|
+
});
|
|
235
|
+
describe.todo('on lists of objects', () => {
|
|
236
|
+
it.todo('pushes items');
|
|
237
|
+
it.todo('moves objects by identity');
|
|
238
|
+
it.todo('removes objects by identity');
|
|
239
|
+
});
|
|
240
|
+
describe.todo('on lists of lists', () => {
|
|
241
|
+
it.todo('rejects operations by value or identity');
|
|
242
|
+
});
|
|
243
|
+
it('should work for complex nested arrays and objects', () => {
|
|
244
|
+
const from = {
|
|
245
|
+
foo: {
|
|
246
|
+
bar: [1, 2, 3],
|
|
247
|
+
},
|
|
248
|
+
baz: [
|
|
249
|
+
{
|
|
250
|
+
corge: true,
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
};
|
|
254
|
+
assignOid(from, 'test/a');
|
|
255
|
+
assignOid(from.foo, 'test/a:1');
|
|
256
|
+
assignOid(from.foo.bar, 'test/a:2');
|
|
257
|
+
assignOid(from.baz, 'test/a:3');
|
|
258
|
+
assignOid(from.baz[0], 'test/a:4');
|
|
259
|
+
const to = {
|
|
260
|
+
foo: {
|
|
261
|
+
bar: [1, 2],
|
|
262
|
+
bop: [0],
|
|
263
|
+
},
|
|
264
|
+
baz: [
|
|
265
|
+
{
|
|
266
|
+
corge: false,
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
corge: false,
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
};
|
|
273
|
+
assignOid(to, 'test/a');
|
|
274
|
+
assignOid(to.foo, 'test/a:1');
|
|
275
|
+
assignOid(to.foo.bar, 'test/a:2');
|
|
276
|
+
assignOid(to.foo.bop, 'test/a:6');
|
|
277
|
+
assignOid(to.baz, 'test/a:3');
|
|
278
|
+
assignOid(to.baz[0], 'test/a:4');
|
|
279
|
+
assignOid(to.baz[1], 'test/a:5');
|
|
280
280
|
expect(diffToPatches(from, to, createClock())).toMatchInlineSnapshot(`
|
|
281
281
|
[
|
|
282
282
|
{
|
|
@@ -342,37 +342,37 @@ describe('creating diff patch operations', () => {
|
|
|
342
342
|
"timestamp": "5",
|
|
343
343
|
},
|
|
344
344
|
]
|
|
345
|
-
`);
|
|
346
|
-
});
|
|
347
|
-
it('should try to merge unknown objects if specified to do so', () => {
|
|
348
|
-
const from = {
|
|
349
|
-
foo: {
|
|
350
|
-
bar: [1, 2, 3],
|
|
351
|
-
},
|
|
352
|
-
baz: [
|
|
353
|
-
{
|
|
354
|
-
corge: true,
|
|
355
|
-
},
|
|
356
|
-
],
|
|
357
|
-
};
|
|
358
|
-
assignOid(from, 'test/a');
|
|
359
|
-
assignOidsToAllSubObjects(from, createClock());
|
|
360
|
-
const to = {
|
|
361
|
-
foo: {
|
|
362
|
-
bar: [1, 2],
|
|
363
|
-
bop: [0],
|
|
364
|
-
},
|
|
365
|
-
baz: [
|
|
366
|
-
{
|
|
367
|
-
corge: false,
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
corge: false,
|
|
371
|
-
},
|
|
372
|
-
],
|
|
373
|
-
};
|
|
374
|
-
expect(diffToPatches(from, to, createClock(), createClock(5), [], {
|
|
375
|
-
mergeUnknownObjects: true,
|
|
345
|
+
`);
|
|
346
|
+
});
|
|
347
|
+
it('should try to merge unknown objects if specified to do so', () => {
|
|
348
|
+
const from = {
|
|
349
|
+
foo: {
|
|
350
|
+
bar: [1, 2, 3],
|
|
351
|
+
},
|
|
352
|
+
baz: [
|
|
353
|
+
{
|
|
354
|
+
corge: true,
|
|
355
|
+
},
|
|
356
|
+
],
|
|
357
|
+
};
|
|
358
|
+
assignOid(from, 'test/a');
|
|
359
|
+
assignOidsToAllSubObjects(from, createClock());
|
|
360
|
+
const to = {
|
|
361
|
+
foo: {
|
|
362
|
+
bar: [1, 2],
|
|
363
|
+
bop: [0],
|
|
364
|
+
},
|
|
365
|
+
baz: [
|
|
366
|
+
{
|
|
367
|
+
corge: false,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
corge: false,
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
};
|
|
374
|
+
expect(diffToPatches(from, to, createClock(), createClock(5), [], {
|
|
375
|
+
mergeUnknownObjects: true,
|
|
376
376
|
})).toMatchInlineSnapshot(`
|
|
377
377
|
[
|
|
378
378
|
{
|
|
@@ -438,25 +438,25 @@ describe('creating diff patch operations', () => {
|
|
|
438
438
|
"timestamp": "5",
|
|
439
439
|
},
|
|
440
440
|
]
|
|
441
|
-
`);
|
|
442
|
-
});
|
|
443
|
-
it('should not diff file refs', () => {
|
|
444
|
-
const from = {
|
|
445
|
-
foo: {
|
|
446
|
-
file: createFileRef('abc123'),
|
|
447
|
-
},
|
|
448
|
-
bar: [createFileRef('def456'), createFileRef('ghi789')],
|
|
449
|
-
};
|
|
450
|
-
assignOid(from, 'test/a');
|
|
451
|
-
assignOidsToAllSubObjects(from, createClock());
|
|
452
|
-
const to = {
|
|
453
|
-
foo: {
|
|
454
|
-
file: createFileRef('abc456'),
|
|
455
|
-
},
|
|
456
|
-
bar: [createFileRef('def456')],
|
|
457
|
-
};
|
|
458
|
-
expect(diffToPatches(from, to, createClock(), createClock(5), [], {
|
|
459
|
-
mergeUnknownObjects: true,
|
|
441
|
+
`);
|
|
442
|
+
});
|
|
443
|
+
it('should not diff file refs', () => {
|
|
444
|
+
const from = {
|
|
445
|
+
foo: {
|
|
446
|
+
file: createFileRef('abc123'),
|
|
447
|
+
},
|
|
448
|
+
bar: [createFileRef('def456'), createFileRef('ghi789')],
|
|
449
|
+
};
|
|
450
|
+
assignOid(from, 'test/a');
|
|
451
|
+
assignOidsToAllSubObjects(from, createClock());
|
|
452
|
+
const to = {
|
|
453
|
+
foo: {
|
|
454
|
+
file: createFileRef('abc456'),
|
|
455
|
+
},
|
|
456
|
+
bar: [createFileRef('def456')],
|
|
457
|
+
};
|
|
458
|
+
expect(diffToPatches(from, to, createClock(), createClock(5), [], {
|
|
459
|
+
mergeUnknownObjects: true,
|
|
460
460
|
})).toMatchInlineSnapshot(`
|
|
461
461
|
[
|
|
462
462
|
{
|
|
@@ -481,26 +481,26 @@ describe('creating diff patch operations', () => {
|
|
|
481
481
|
"timestamp": "1",
|
|
482
482
|
},
|
|
483
483
|
]
|
|
484
|
-
`);
|
|
485
|
-
});
|
|
486
|
-
it('should assign a new OID to objects which had an incompatible existing OID', () => {
|
|
487
|
-
const from = {
|
|
488
|
-
foo: {
|
|
489
|
-
bar: [1, 2, 3],
|
|
490
|
-
},
|
|
491
|
-
};
|
|
492
|
-
assignOid(from, 'test/a');
|
|
493
|
-
assignOidsToAllSubObjects(from, createClock());
|
|
494
|
-
const to = {
|
|
495
|
-
foo: {
|
|
496
|
-
bar: [1, 2],
|
|
497
|
-
},
|
|
498
|
-
};
|
|
499
|
-
assignOid(to, 'test/a');
|
|
500
|
-
assignOid(to.foo, 'uff/b');
|
|
501
|
-
assignOidsToAllSubObjects(to.foo, createClock());
|
|
502
|
-
expect(diffToPatches(from, to, createClock(), createClock(5), [], {
|
|
503
|
-
mergeUnknownObjects: true,
|
|
484
|
+
`);
|
|
485
|
+
});
|
|
486
|
+
it('should assign a new OID to objects which had an incompatible existing OID', () => {
|
|
487
|
+
const from = {
|
|
488
|
+
foo: {
|
|
489
|
+
bar: [1, 2, 3],
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
assignOid(from, 'test/a');
|
|
493
|
+
assignOidsToAllSubObjects(from, createClock());
|
|
494
|
+
const to = {
|
|
495
|
+
foo: {
|
|
496
|
+
bar: [1, 2],
|
|
497
|
+
},
|
|
498
|
+
};
|
|
499
|
+
assignOid(to, 'test/a');
|
|
500
|
+
assignOid(to.foo, 'uff/b');
|
|
501
|
+
assignOidsToAllSubObjects(to.foo, createClock());
|
|
502
|
+
expect(diffToPatches(from, to, createClock(), createClock(5), [], {
|
|
503
|
+
mergeUnknownObjects: true,
|
|
504
504
|
})).toMatchInlineSnapshot(`
|
|
505
505
|
[
|
|
506
506
|
{
|
|
@@ -547,25 +547,25 @@ describe('creating diff patch operations', () => {
|
|
|
547
547
|
"timestamp": "3",
|
|
548
548
|
},
|
|
549
549
|
]
|
|
550
|
-
`);
|
|
551
|
-
});
|
|
552
|
-
// an edge case - if a subobject which contains nested objects changes identity,
|
|
553
|
-
// this gets written as a new init patch tree - we want to ensure all init subobjects
|
|
554
|
-
// in that tree have compatible OIDs.
|
|
555
|
-
it('should assign a new OID to objects which have an incompatible OID when parent identity changes', () => {
|
|
556
|
-
const from = {
|
|
557
|
-
bar: [],
|
|
558
|
-
};
|
|
559
|
-
assignOid(from, 'test/a');
|
|
560
|
-
assignOid(from.bar, 'test/random');
|
|
561
|
-
const to = {
|
|
562
|
-
bar: [{ baz: 1 }, { baz: 2 }],
|
|
563
|
-
};
|
|
564
|
-
assignOid(to, 'test/a');
|
|
565
|
-
assignOidsToAllSubObjects(to, createClock());
|
|
566
|
-
assignOid(to.bar[0], 'uff/b');
|
|
567
|
-
expect(diffToPatches(from, to, createClock(), createClock(5), [], {
|
|
568
|
-
mergeUnknownObjects: true,
|
|
550
|
+
`);
|
|
551
|
+
});
|
|
552
|
+
// an edge case - if a subobject which contains nested objects changes identity,
|
|
553
|
+
// this gets written as a new init patch tree - we want to ensure all init subobjects
|
|
554
|
+
// in that tree have compatible OIDs.
|
|
555
|
+
it('should assign a new OID to objects which have an incompatible OID when parent identity changes', () => {
|
|
556
|
+
const from = {
|
|
557
|
+
bar: [],
|
|
558
|
+
};
|
|
559
|
+
assignOid(from, 'test/a');
|
|
560
|
+
assignOid(from.bar, 'test/random');
|
|
561
|
+
const to = {
|
|
562
|
+
bar: [{ baz: 1 }, { baz: 2 }],
|
|
563
|
+
};
|
|
564
|
+
assignOid(to, 'test/a');
|
|
565
|
+
assignOidsToAllSubObjects(to, createClock());
|
|
566
|
+
assignOid(to.bar[0], 'uff/b');
|
|
567
|
+
expect(diffToPatches(from, to, createClock(), createClock(5), [], {
|
|
568
|
+
mergeUnknownObjects: true,
|
|
569
569
|
})).toMatchInlineSnapshot(`
|
|
570
570
|
[
|
|
571
571
|
{
|
|
@@ -625,157 +625,157 @@ describe('creating diff patch operations', () => {
|
|
|
625
625
|
"timestamp": "4",
|
|
626
626
|
},
|
|
627
627
|
]
|
|
628
|
-
`);
|
|
629
|
-
});
|
|
630
|
-
});
|
|
631
|
-
describe('substituting refs with objects', () => {
|
|
632
|
-
it('does nothing when no refs exist', () => {
|
|
633
|
-
const root = {
|
|
634
|
-
foo: 'bar',
|
|
635
|
-
};
|
|
636
|
-
assignOid(root, 'test/a');
|
|
637
|
-
const substituted = substituteRefsWithObjects(root, new Map());
|
|
638
|
-
expect(root).toEqual(assignOid({
|
|
639
|
-
foo: 'bar',
|
|
640
|
-
}, 'test/a'));
|
|
641
|
-
expect(substituted).toEqual([]);
|
|
642
|
-
});
|
|
643
|
-
it('inserts top level objects with oids', () => {
|
|
644
|
-
const root = {
|
|
645
|
-
foo: {
|
|
646
|
-
'@@type': 'ref',
|
|
647
|
-
id: 'test/1:a',
|
|
648
|
-
},
|
|
649
|
-
qux: 1,
|
|
650
|
-
};
|
|
651
|
-
assignOid(root, 'test/1');
|
|
652
|
-
const substituted = substituteRefsWithObjects(root, new Map([['test/1:a', { foo: 'bar' }]]));
|
|
653
|
-
expect(root).toEqual(assignOid({
|
|
654
|
-
foo: assignOid({
|
|
655
|
-
foo: 'bar',
|
|
656
|
-
}, 'test/1:a'),
|
|
657
|
-
qux: 1,
|
|
658
|
-
}, 'test/1'));
|
|
659
|
-
expect(substituted).toEqual(['test/1:a']);
|
|
660
|
-
expect(getOid(root)).toEqual('test/1');
|
|
661
|
-
expect(getOid(root.foo)).toEqual('test/1:a');
|
|
662
|
-
});
|
|
663
|
-
it('inserts nested objects with oids', () => {
|
|
664
|
-
const root = {
|
|
665
|
-
foo: {
|
|
666
|
-
'@@type': 'ref',
|
|
667
|
-
id: 'test/1:a',
|
|
668
|
-
},
|
|
669
|
-
};
|
|
670
|
-
assignOid(root, 'test/1');
|
|
671
|
-
const substituted = substituteRefsWithObjects(root, new Map([
|
|
672
|
-
[
|
|
673
|
-
'test/1:a',
|
|
674
|
-
{
|
|
675
|
-
foo: 'bar',
|
|
676
|
-
baz: {
|
|
677
|
-
'@@type': 'ref',
|
|
678
|
-
id: 'test/1:b',
|
|
679
|
-
},
|
|
680
|
-
},
|
|
681
|
-
],
|
|
682
|
-
[
|
|
683
|
-
'test/1:b',
|
|
684
|
-
{
|
|
685
|
-
qux: 'corge',
|
|
686
|
-
},
|
|
687
|
-
],
|
|
688
|
-
]));
|
|
689
|
-
expect(root).toEqual(assignOid({
|
|
690
|
-
foo: assignOid({
|
|
691
|
-
foo: 'bar',
|
|
692
|
-
baz: assignOid({
|
|
693
|
-
qux: 'corge',
|
|
694
|
-
}, 'test/1:b'),
|
|
695
|
-
}, 'test/1:a'),
|
|
696
|
-
}, 'test/1'));
|
|
697
|
-
expect(substituted).toEqual(['test/1:a', 'test/1:b']);
|
|
698
|
-
expect(getOid(root)).toEqual('test/1');
|
|
699
|
-
expect(getOid(root.foo)).toEqual('test/1:a');
|
|
700
|
-
expect(getOid(root.foo.baz)).toEqual('test/1:b');
|
|
701
|
-
});
|
|
702
|
-
it('substitutes arrays of objects', () => {
|
|
703
|
-
const root = {
|
|
704
|
-
foo: {
|
|
705
|
-
'@@type': 'ref',
|
|
706
|
-
id: 'test/1:c',
|
|
707
|
-
},
|
|
708
|
-
};
|
|
709
|
-
assignOid(root, 'test/1');
|
|
710
|
-
const substituted = substituteRefsWithObjects(root, new Map([
|
|
711
|
-
[
|
|
712
|
-
'test/1:c',
|
|
713
|
-
[
|
|
714
|
-
{
|
|
715
|
-
'@@type': 'ref',
|
|
716
|
-
id: 'test/1:a',
|
|
717
|
-
},
|
|
718
|
-
{
|
|
719
|
-
'@@type': 'ref',
|
|
720
|
-
id: 'test/1:b',
|
|
721
|
-
},
|
|
722
|
-
],
|
|
723
|
-
],
|
|
724
|
-
[
|
|
725
|
-
'test/1:a',
|
|
726
|
-
{
|
|
727
|
-
foo: 'bar',
|
|
728
|
-
},
|
|
729
|
-
],
|
|
730
|
-
[
|
|
731
|
-
'test/1:b',
|
|
732
|
-
{
|
|
733
|
-
qux: 'corge',
|
|
734
|
-
},
|
|
735
|
-
],
|
|
736
|
-
]));
|
|
737
|
-
expect(root).toEqual({
|
|
738
|
-
foo: assignOid([
|
|
739
|
-
assignOid({
|
|
740
|
-
foo: 'bar',
|
|
741
|
-
}, 'test/1:a'),
|
|
742
|
-
assignOid({
|
|
743
|
-
qux: 'corge',
|
|
744
|
-
}, 'test/1:b'),
|
|
745
|
-
], 'test/1:c'),
|
|
746
|
-
});
|
|
747
|
-
expect(substituted).toEqual(['test/1:c', 'test/1:a', 'test/1:b']);
|
|
748
|
-
expect(getOid(root)).toEqual('test/1');
|
|
749
|
-
expect(getOid(root.foo)).toEqual('test/1:c');
|
|
750
|
-
expect(getOid(root.foo[0])).toEqual('test/1:a');
|
|
751
|
-
expect(getOid(root.foo[1])).toEqual('test/1:b');
|
|
752
|
-
});
|
|
753
|
-
it.todo('substitutes arrays of arrays of objects');
|
|
754
|
-
});
|
|
755
|
-
describe('creating patches from initial state', () => {
|
|
756
|
-
it('adds oids to all sub-objects', async () => {
|
|
757
|
-
let i = 0;
|
|
758
|
-
function createSubId() {
|
|
759
|
-
return (i++).toString();
|
|
760
|
-
}
|
|
761
|
-
const result = initialToPatches({
|
|
762
|
-
foo: {
|
|
763
|
-
bar: 'baz',
|
|
764
|
-
},
|
|
765
|
-
qux: [
|
|
766
|
-
{
|
|
767
|
-
corge: 'grault',
|
|
768
|
-
},
|
|
769
|
-
{
|
|
770
|
-
bin: {
|
|
771
|
-
oof: 1,
|
|
772
|
-
},
|
|
773
|
-
},
|
|
774
|
-
],
|
|
775
|
-
}, 'test/a', createClock(), createSubId);
|
|
776
|
-
/**
|
|
777
|
-
* Patches should not include assigned OID property
|
|
778
|
-
*/
|
|
628
|
+
`);
|
|
629
|
+
});
|
|
630
|
+
});
|
|
631
|
+
describe('substituting refs with objects', () => {
|
|
632
|
+
it('does nothing when no refs exist', () => {
|
|
633
|
+
const root = {
|
|
634
|
+
foo: 'bar',
|
|
635
|
+
};
|
|
636
|
+
assignOid(root, 'test/a');
|
|
637
|
+
const substituted = substituteRefsWithObjects(root, new Map());
|
|
638
|
+
expect(root).toEqual(assignOid({
|
|
639
|
+
foo: 'bar',
|
|
640
|
+
}, 'test/a'));
|
|
641
|
+
expect(substituted).toEqual([]);
|
|
642
|
+
});
|
|
643
|
+
it('inserts top level objects with oids', () => {
|
|
644
|
+
const root = {
|
|
645
|
+
foo: {
|
|
646
|
+
'@@type': 'ref',
|
|
647
|
+
id: 'test/1:a',
|
|
648
|
+
},
|
|
649
|
+
qux: 1,
|
|
650
|
+
};
|
|
651
|
+
assignOid(root, 'test/1');
|
|
652
|
+
const substituted = substituteRefsWithObjects(root, new Map([['test/1:a', { foo: 'bar' }]]));
|
|
653
|
+
expect(root).toEqual(assignOid({
|
|
654
|
+
foo: assignOid({
|
|
655
|
+
foo: 'bar',
|
|
656
|
+
}, 'test/1:a'),
|
|
657
|
+
qux: 1,
|
|
658
|
+
}, 'test/1'));
|
|
659
|
+
expect(substituted).toEqual(['test/1:a']);
|
|
660
|
+
expect(getOid(root)).toEqual('test/1');
|
|
661
|
+
expect(getOid(root.foo)).toEqual('test/1:a');
|
|
662
|
+
});
|
|
663
|
+
it('inserts nested objects with oids', () => {
|
|
664
|
+
const root = {
|
|
665
|
+
foo: {
|
|
666
|
+
'@@type': 'ref',
|
|
667
|
+
id: 'test/1:a',
|
|
668
|
+
},
|
|
669
|
+
};
|
|
670
|
+
assignOid(root, 'test/1');
|
|
671
|
+
const substituted = substituteRefsWithObjects(root, new Map([
|
|
672
|
+
[
|
|
673
|
+
'test/1:a',
|
|
674
|
+
{
|
|
675
|
+
foo: 'bar',
|
|
676
|
+
baz: {
|
|
677
|
+
'@@type': 'ref',
|
|
678
|
+
id: 'test/1:b',
|
|
679
|
+
},
|
|
680
|
+
},
|
|
681
|
+
],
|
|
682
|
+
[
|
|
683
|
+
'test/1:b',
|
|
684
|
+
{
|
|
685
|
+
qux: 'corge',
|
|
686
|
+
},
|
|
687
|
+
],
|
|
688
|
+
]));
|
|
689
|
+
expect(root).toEqual(assignOid({
|
|
690
|
+
foo: assignOid({
|
|
691
|
+
foo: 'bar',
|
|
692
|
+
baz: assignOid({
|
|
693
|
+
qux: 'corge',
|
|
694
|
+
}, 'test/1:b'),
|
|
695
|
+
}, 'test/1:a'),
|
|
696
|
+
}, 'test/1'));
|
|
697
|
+
expect(substituted).toEqual(['test/1:a', 'test/1:b']);
|
|
698
|
+
expect(getOid(root)).toEqual('test/1');
|
|
699
|
+
expect(getOid(root.foo)).toEqual('test/1:a');
|
|
700
|
+
expect(getOid(root.foo.baz)).toEqual('test/1:b');
|
|
701
|
+
});
|
|
702
|
+
it('substitutes arrays of objects', () => {
|
|
703
|
+
const root = {
|
|
704
|
+
foo: {
|
|
705
|
+
'@@type': 'ref',
|
|
706
|
+
id: 'test/1:c',
|
|
707
|
+
},
|
|
708
|
+
};
|
|
709
|
+
assignOid(root, 'test/1');
|
|
710
|
+
const substituted = substituteRefsWithObjects(root, new Map([
|
|
711
|
+
[
|
|
712
|
+
'test/1:c',
|
|
713
|
+
[
|
|
714
|
+
{
|
|
715
|
+
'@@type': 'ref',
|
|
716
|
+
id: 'test/1:a',
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
'@@type': 'ref',
|
|
720
|
+
id: 'test/1:b',
|
|
721
|
+
},
|
|
722
|
+
],
|
|
723
|
+
],
|
|
724
|
+
[
|
|
725
|
+
'test/1:a',
|
|
726
|
+
{
|
|
727
|
+
foo: 'bar',
|
|
728
|
+
},
|
|
729
|
+
],
|
|
730
|
+
[
|
|
731
|
+
'test/1:b',
|
|
732
|
+
{
|
|
733
|
+
qux: 'corge',
|
|
734
|
+
},
|
|
735
|
+
],
|
|
736
|
+
]));
|
|
737
|
+
expect(root).toEqual({
|
|
738
|
+
foo: assignOid([
|
|
739
|
+
assignOid({
|
|
740
|
+
foo: 'bar',
|
|
741
|
+
}, 'test/1:a'),
|
|
742
|
+
assignOid({
|
|
743
|
+
qux: 'corge',
|
|
744
|
+
}, 'test/1:b'),
|
|
745
|
+
], 'test/1:c'),
|
|
746
|
+
});
|
|
747
|
+
expect(substituted).toEqual(['test/1:c', 'test/1:a', 'test/1:b']);
|
|
748
|
+
expect(getOid(root)).toEqual('test/1');
|
|
749
|
+
expect(getOid(root.foo)).toEqual('test/1:c');
|
|
750
|
+
expect(getOid(root.foo[0])).toEqual('test/1:a');
|
|
751
|
+
expect(getOid(root.foo[1])).toEqual('test/1:b');
|
|
752
|
+
});
|
|
753
|
+
it.todo('substitutes arrays of arrays of objects');
|
|
754
|
+
});
|
|
755
|
+
describe('creating patches from initial state', () => {
|
|
756
|
+
it('adds oids to all sub-objects', async () => {
|
|
757
|
+
let i = 0;
|
|
758
|
+
function createSubId() {
|
|
759
|
+
return (i++).toString();
|
|
760
|
+
}
|
|
761
|
+
const result = initialToPatches({
|
|
762
|
+
foo: {
|
|
763
|
+
bar: 'baz',
|
|
764
|
+
},
|
|
765
|
+
qux: [
|
|
766
|
+
{
|
|
767
|
+
corge: 'grault',
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
bin: {
|
|
771
|
+
oof: 1,
|
|
772
|
+
},
|
|
773
|
+
},
|
|
774
|
+
],
|
|
775
|
+
}, 'test/a', createClock(), createSubId);
|
|
776
|
+
/**
|
|
777
|
+
* Patches should not include assigned OID property
|
|
778
|
+
*/
|
|
779
779
|
expect(result).toMatchInlineSnapshot(`
|
|
780
780
|
[
|
|
781
781
|
{
|
|
@@ -856,120 +856,120 @@ describe('creating patches from initial state', () => {
|
|
|
856
856
|
"timestamp": "5",
|
|
857
857
|
},
|
|
858
858
|
]
|
|
859
|
-
`);
|
|
860
|
-
});
|
|
861
|
-
});
|
|
862
|
-
describe('applying individual operations', () => {
|
|
863
|
-
it('applies a list-remove of only the last instance', () => {
|
|
864
|
-
expect(applyPatch(['a', 'b', 'c', 'a', 'b'], {
|
|
865
|
-
op: 'list-remove',
|
|
866
|
-
value: 'a',
|
|
867
|
-
only: 'last',
|
|
868
|
-
})).toEqual(['a', 'b', 'c', 'b']);
|
|
869
|
-
});
|
|
870
|
-
it('applies a list-remove of only the first instance', () => {
|
|
871
|
-
expect(applyPatch(['a', 'b', 'c', 'a', 'b'], {
|
|
872
|
-
op: 'list-remove',
|
|
873
|
-
value: 'a',
|
|
874
|
-
only: 'first',
|
|
875
|
-
})).toEqual(['b', 'c', 'a', 'b']);
|
|
876
|
-
});
|
|
877
|
-
it('applies a list-remove of all instances', () => {
|
|
878
|
-
expect(applyPatch(['a', 'b', 'c', 'a', 'b'], {
|
|
879
|
-
op: 'list-remove',
|
|
880
|
-
value: 'a',
|
|
881
|
-
})).toEqual(['b', 'c', 'b']);
|
|
882
|
-
});
|
|
883
|
-
it('applies a list-remove of an object ref', () => {
|
|
884
|
-
expect(applyPatch([
|
|
885
|
-
createRef('a'),
|
|
886
|
-
createRef('b'),
|
|
887
|
-
createRef('c'),
|
|
888
|
-
createRef('a'),
|
|
889
|
-
createRef('b'),
|
|
890
|
-
], {
|
|
891
|
-
op: 'list-remove',
|
|
892
|
-
value: createRef('a'),
|
|
893
|
-
only: 'last',
|
|
894
|
-
})).toEqual([createRef('a'), createRef('b'), createRef('c'), createRef('b')]);
|
|
895
|
-
});
|
|
896
|
-
it('applies a list-add of a nonexistent item', () => {
|
|
897
|
-
expect(applyPatch(['a', 'b', 'c'], {
|
|
898
|
-
op: 'list-add',
|
|
899
|
-
value: 'd',
|
|
900
|
-
})).toEqual(['a', 'b', 'c', 'd']);
|
|
901
|
-
});
|
|
902
|
-
it('does not apply a list-add if the item is already present', () => {
|
|
903
|
-
expect(applyPatch(['a', 'b', 'c'], {
|
|
904
|
-
op: 'list-add',
|
|
905
|
-
value: 'b',
|
|
906
|
-
})).toEqual(['a', 'b', 'c']);
|
|
907
|
-
});
|
|
908
|
-
});
|
|
909
|
-
describe('collecting deleted refs during patch application', () => {
|
|
910
|
-
it('collects refs that are removed from a list', () => {
|
|
911
|
-
const refs = [];
|
|
912
|
-
expect(applyPatch([
|
|
913
|
-
createRef('a'),
|
|
914
|
-
createRef('b'),
|
|
915
|
-
createRef('c'),
|
|
916
|
-
createRef('d'),
|
|
917
|
-
createRef('e'),
|
|
918
|
-
], {
|
|
919
|
-
op: 'list-remove',
|
|
920
|
-
value: createRef('c'),
|
|
921
|
-
}, refs)).toEqual([createRef('a'), createRef('b'), createRef('d'), createRef('e')]);
|
|
922
|
-
expect(refs).toEqual([createRef('c')]);
|
|
923
|
-
});
|
|
924
|
-
it('collects a deleted ref field from an object', () => {
|
|
925
|
-
const refs = [];
|
|
926
|
-
expect(applyPatch({
|
|
927
|
-
a: createRef('a'),
|
|
928
|
-
b: createRef('b'),
|
|
929
|
-
c: createRef('c'),
|
|
930
|
-
}, {
|
|
931
|
-
op: 'remove',
|
|
932
|
-
name: 'b',
|
|
933
|
-
}, refs)).toEqual({
|
|
934
|
-
a: createRef('a'),
|
|
935
|
-
c: createRef('c'),
|
|
936
|
-
});
|
|
937
|
-
expect(refs).toEqual([createRef('b')]);
|
|
938
|
-
});
|
|
939
|
-
it('collects all refs in a deleted object', () => {
|
|
940
|
-
const refs = [];
|
|
941
|
-
expect(applyPatch({
|
|
942
|
-
a: createRef('a'),
|
|
943
|
-
b: createRef('b'),
|
|
944
|
-
c: createRef('c'),
|
|
945
|
-
}, {
|
|
946
|
-
op: 'delete',
|
|
947
|
-
}, refs)).toEqual(undefined);
|
|
948
|
-
expect(refs).toEqual([createRef('a'), createRef('b'), createRef('c')]);
|
|
949
|
-
});
|
|
950
|
-
it('collects all refs in a deleted list', () => {
|
|
951
|
-
const refs = [];
|
|
952
|
-
expect(applyPatch([createRef('a'), createRef('b'), createRef('c')], {
|
|
953
|
-
op: 'delete',
|
|
954
|
-
}, refs)).toEqual(undefined);
|
|
955
|
-
expect(refs).toEqual([createRef('a'), createRef('b'), createRef('c')]);
|
|
956
|
-
});
|
|
957
|
-
it('collects a ref in a replaced field', () => {
|
|
958
|
-
const refs = [];
|
|
959
|
-
expect(applyPatch({
|
|
960
|
-
a: createRef('a'),
|
|
961
|
-
b: createRef('b'),
|
|
962
|
-
c: createRef('c'),
|
|
963
|
-
}, {
|
|
964
|
-
op: 'set',
|
|
965
|
-
name: 'b',
|
|
966
|
-
value: createRef('d'),
|
|
967
|
-
}, refs)).toEqual({
|
|
968
|
-
a: createRef('a'),
|
|
969
|
-
b: createRef('d'),
|
|
970
|
-
c: createRef('c'),
|
|
971
|
-
});
|
|
972
|
-
expect(refs).toEqual([createRef('b')]);
|
|
973
|
-
});
|
|
974
|
-
});
|
|
859
|
+
`);
|
|
860
|
+
});
|
|
861
|
+
});
|
|
862
|
+
describe('applying individual operations', () => {
|
|
863
|
+
it('applies a list-remove of only the last instance', () => {
|
|
864
|
+
expect(applyPatch(['a', 'b', 'c', 'a', 'b'], {
|
|
865
|
+
op: 'list-remove',
|
|
866
|
+
value: 'a',
|
|
867
|
+
only: 'last',
|
|
868
|
+
})).toEqual(['a', 'b', 'c', 'b']);
|
|
869
|
+
});
|
|
870
|
+
it('applies a list-remove of only the first instance', () => {
|
|
871
|
+
expect(applyPatch(['a', 'b', 'c', 'a', 'b'], {
|
|
872
|
+
op: 'list-remove',
|
|
873
|
+
value: 'a',
|
|
874
|
+
only: 'first',
|
|
875
|
+
})).toEqual(['b', 'c', 'a', 'b']);
|
|
876
|
+
});
|
|
877
|
+
it('applies a list-remove of all instances', () => {
|
|
878
|
+
expect(applyPatch(['a', 'b', 'c', 'a', 'b'], {
|
|
879
|
+
op: 'list-remove',
|
|
880
|
+
value: 'a',
|
|
881
|
+
})).toEqual(['b', 'c', 'b']);
|
|
882
|
+
});
|
|
883
|
+
it('applies a list-remove of an object ref', () => {
|
|
884
|
+
expect(applyPatch([
|
|
885
|
+
createRef('a'),
|
|
886
|
+
createRef('b'),
|
|
887
|
+
createRef('c'),
|
|
888
|
+
createRef('a'),
|
|
889
|
+
createRef('b'),
|
|
890
|
+
], {
|
|
891
|
+
op: 'list-remove',
|
|
892
|
+
value: createRef('a'),
|
|
893
|
+
only: 'last',
|
|
894
|
+
})).toEqual([createRef('a'), createRef('b'), createRef('c'), createRef('b')]);
|
|
895
|
+
});
|
|
896
|
+
it('applies a list-add of a nonexistent item', () => {
|
|
897
|
+
expect(applyPatch(['a', 'b', 'c'], {
|
|
898
|
+
op: 'list-add',
|
|
899
|
+
value: 'd',
|
|
900
|
+
})).toEqual(['a', 'b', 'c', 'd']);
|
|
901
|
+
});
|
|
902
|
+
it('does not apply a list-add if the item is already present', () => {
|
|
903
|
+
expect(applyPatch(['a', 'b', 'c'], {
|
|
904
|
+
op: 'list-add',
|
|
905
|
+
value: 'b',
|
|
906
|
+
})).toEqual(['a', 'b', 'c']);
|
|
907
|
+
});
|
|
908
|
+
});
|
|
909
|
+
describe('collecting deleted refs during patch application', () => {
|
|
910
|
+
it('collects refs that are removed from a list', () => {
|
|
911
|
+
const refs = [];
|
|
912
|
+
expect(applyPatch([
|
|
913
|
+
createRef('a'),
|
|
914
|
+
createRef('b'),
|
|
915
|
+
createRef('c'),
|
|
916
|
+
createRef('d'),
|
|
917
|
+
createRef('e'),
|
|
918
|
+
], {
|
|
919
|
+
op: 'list-remove',
|
|
920
|
+
value: createRef('c'),
|
|
921
|
+
}, refs)).toEqual([createRef('a'), createRef('b'), createRef('d'), createRef('e')]);
|
|
922
|
+
expect(refs).toEqual([createRef('c')]);
|
|
923
|
+
});
|
|
924
|
+
it('collects a deleted ref field from an object', () => {
|
|
925
|
+
const refs = [];
|
|
926
|
+
expect(applyPatch({
|
|
927
|
+
a: createRef('a'),
|
|
928
|
+
b: createRef('b'),
|
|
929
|
+
c: createRef('c'),
|
|
930
|
+
}, {
|
|
931
|
+
op: 'remove',
|
|
932
|
+
name: 'b',
|
|
933
|
+
}, refs)).toEqual({
|
|
934
|
+
a: createRef('a'),
|
|
935
|
+
c: createRef('c'),
|
|
936
|
+
});
|
|
937
|
+
expect(refs).toEqual([createRef('b')]);
|
|
938
|
+
});
|
|
939
|
+
it('collects all refs in a deleted object', () => {
|
|
940
|
+
const refs = [];
|
|
941
|
+
expect(applyPatch({
|
|
942
|
+
a: createRef('a'),
|
|
943
|
+
b: createRef('b'),
|
|
944
|
+
c: createRef('c'),
|
|
945
|
+
}, {
|
|
946
|
+
op: 'delete',
|
|
947
|
+
}, refs)).toEqual(undefined);
|
|
948
|
+
expect(refs).toEqual([createRef('a'), createRef('b'), createRef('c')]);
|
|
949
|
+
});
|
|
950
|
+
it('collects all refs in a deleted list', () => {
|
|
951
|
+
const refs = [];
|
|
952
|
+
expect(applyPatch([createRef('a'), createRef('b'), createRef('c')], {
|
|
953
|
+
op: 'delete',
|
|
954
|
+
}, refs)).toEqual(undefined);
|
|
955
|
+
expect(refs).toEqual([createRef('a'), createRef('b'), createRef('c')]);
|
|
956
|
+
});
|
|
957
|
+
it('collects a ref in a replaced field', () => {
|
|
958
|
+
const refs = [];
|
|
959
|
+
expect(applyPatch({
|
|
960
|
+
a: createRef('a'),
|
|
961
|
+
b: createRef('b'),
|
|
962
|
+
c: createRef('c'),
|
|
963
|
+
}, {
|
|
964
|
+
op: 'set',
|
|
965
|
+
name: 'b',
|
|
966
|
+
value: createRef('d'),
|
|
967
|
+
}, refs)).toEqual({
|
|
968
|
+
a: createRef('a'),
|
|
969
|
+
b: createRef('d'),
|
|
970
|
+
c: createRef('c'),
|
|
971
|
+
});
|
|
972
|
+
expect(refs).toEqual([createRef('b')]);
|
|
973
|
+
});
|
|
974
|
+
});
|
|
975
975
|
//# sourceMappingURL=operation.test.js.map
|