diff --git a/frontend/context.js b/frontend/context.js index a6d658f2..915511e1 100644 --- a/frontend/context.js +++ b/frontend/context.js @@ -229,7 +229,14 @@ class Context { */ createNestedObjects(obj, key, value, insert, pred, elemId) { if (value[OBJECT_ID]) { - throw new RangeError('Cannot create a reference to an existing document object') + const object = this.updated[obj] || this.cache[obj] + const conflicts = object && object[CONFLICTS][key] + const valueInConflicts = conflicts && Object.values(conflicts) + .some(v => v && v[OBJECT_ID] === value[OBJECT_ID]) + + if (!valueInConflicts) { + throw new RangeError('Cannot create a reference to an existing document object') + } } const objectId = this.nextOpId() diff --git a/test/test.js b/test/test.js index 3fc2f7e7..efa1caf9 100644 --- a/test/test.js +++ b/test/test.js @@ -547,6 +547,20 @@ describe('Automerge', () => { }, /Cannot create a reference to an existing document object/) }) + it('should allow allow referencing an existing object that is part of the conflict set', () => { + s2 = Automerge.clone(s1) + s1 = Automerge.change(s1, doc => doc.object = { id: 'a' }) + s2 = Automerge.change(s2, doc => doc.object = { id: 'b' }) + + const result = Automerge.merge(s1, s2) + const conflicts = Automerge.getConflicts(result, 'object') + + // Should not throw "Cannot create a reference to an existing document object" + Automerge.change(result, doc => { + doc.object = Object.values(conflicts)[0] + }) + }) + it('should handle deletion of properties within a map', () => { s1 = Automerge.change(s1, 'set style', doc => { doc.textStyle = {typeface: 'Optima', bold: false, fontSize: 12} @@ -773,6 +787,20 @@ describe('Automerge', () => { }, /Cannot create a reference to an existing document object/) }) + it('should allow referencing an existing list that is part of the conflict set', () => { + s2 = Automerge.clone(s1) + s1 = Automerge.change(s1, doc => doc.list = ['a']) + s2 = Automerge.change(s2, doc => doc.list = ['b']) + + const result = Automerge.merge(s1, s2) + const conflicts = Automerge.getConflicts(result, 'list') + + // Should not throw "Cannot create a reference to an existing document object" + Automerge.change(result, doc => { + doc.list = Object.values(conflicts)[0] + }) + }) + it('concurrent edits insert in reverse actorid order if counters equal', () => { s1 = Automerge.init('aaaa') s2 = Automerge.init('bbbb')