diff --git a/lib/json0.js b/lib/json0.js index 9f538ee..912d005 100644 --- a/lib/json0.js +++ b/lib/json0.js @@ -65,13 +65,22 @@ json.create = function(data) { return data === undefined ? null : clone(data); }; -json.invertComponent = function(c) { +json.invertComponent = function(c, doc) { var c_ = {p: c.p}; + var hasDoc = typeof doc !== 'undefined'; + for (var i = 0; i < c.p.length; i++) { + var key = c.p[i]; + doc = doc && doc[key]; + } + // handle subtype ops if (c.t && subtypes[c.t]) { c_.t = c.t; - c_.o = subtypes[c.t].invert(c.o); + var subtype = subtypes[c.t]; + if (hasDoc && typeof subtype.invertWithDoc === 'function') c_.o = subtype.invertWithDoc(c.o, doc); + else if (typeof subtype.invert === 'function') c_.o = subtype.invert(c.o); + else throw new Error("Subtype '" + c.t + "' is not invertible"); } if (c.si !== void 0) c_.sd = c.si; @@ -99,6 +108,15 @@ json.invert = function(op) { return iop; }; +json.invertWithDoc = function(op, doc) { + var op_ = op.slice().reverse(); + var iop = []; + for (var i = 0; i < op_.length; i++) { + iop.push(json.invertComponent(op_[i], doc)); + } + return iop; +} + json.checkValidOp = function(op) { for (var i = 0; i < op.length; i++) { if (!isArray(op[i].p)) throw new Error('Missing path'); diff --git a/test/json0.coffee b/test/json0.coffee index e2ee6df..019efdb 100644 --- a/test/json0.coffee +++ b/test/json0.coffee @@ -222,6 +222,27 @@ genTests = (type) -> assert.deepEqual [{p:[100], si:'hi'}], type.compose [{p:[100], si:'h'}], [{p:[101], si:'i'}] assert.deepEqual [{p:[], t:'text0', o:[{p:100, i:'hi'}]}], type.compose [{p:[], t:'text0', o:[{p:100, i:'h'}]}], [{p:[], t:'text0', o:[{p:101, i:'i'}]}] + describe '#invertWithDoc()', -> + it 'passes the doc to the subtype', -> + op = null + doc = null + + type.registerSubtype + name: 'invertible' + invertWithDoc: (o, d) -> + op = o + doc = d + + type.invertWithDoc [{p: ['foo', 'bar'], t: 'invertible', o: [{increment: 1}]}], {foo: {bar: 5}} + assert.deepEqual [{increment: 1}], op + assert.deepEqual 5, doc + + it 'throws if the subtype does not support inversion', -> + type.registerSubtype + name: 'not-invertible' + + assert.throws -> type.invertWithDoc [{p: ['foo'], t: 'not-invertible', o: [{increment: 1}]}], {foo: 5} + it 'moves ops on a moved element with the element', -> assert.deepEqual [{p:[10], ld:'x'}], type.transform [{p:[4], ld:'x'}], [{p:[4], lm:10}], 'left' assert.deepEqual [{p:[10, 1], si:'a'}], type.transform [{p:[4, 1], si:'a'}], [{p:[4], lm:10}], 'left'