diff --git a/src/jsonData.js b/src/jsonData.js index 443881b..5e9670d 100644 --- a/src/jsonData.js +++ b/src/jsonData.js @@ -131,7 +131,7 @@ export function patchData (data, patch) { const result = add(updatedData, action.path, newValue, options) updatedData = result.data - revert.unshift(result.revert) + revert = result.revert.concat(revert) break } @@ -139,7 +139,7 @@ export function patchData (data, patch) { case 'remove': { const result = remove(updatedData, action.path) updatedData = result.data - revert.unshift(result.revert) + revert = result.revert.concat(revert) break } @@ -157,7 +157,7 @@ export function patchData (data, patch) { const result = replace(updatedData, path, newValue) updatedData = result.data - revert.unshift(result.revert) + revert = result.revert.concat(revert) break } @@ -165,7 +165,7 @@ export function patchData (data, patch) { case 'copy': { const result = copy(updatedData, action.path, action.from, options) updatedData = result.data - revert.unshift(result.revert) + revert = result.revert.concat(revert) break } @@ -206,23 +206,23 @@ export function patchData (data, patch) { * @param {JSONData} data * @param {Path} path * @param {JSONData} value - * @return {{data: JSONData, revert: Object}} + * @return {{data: JSONData, revert: JSONPatch}} */ export function replace (data, path, value) { const dataPath = toDataPath(data, path) - const oldValue = dataToJson(getIn(data, dataPath)) + const oldValue = getIn(data, dataPath) return { // FIXME: keep the expanded state where possible data: setIn(data, dataPath, value), - revert: { + revert: [{ op: 'replace', path: compileJSONPointer(path), - value: oldValue, + value: dataToJson(oldValue), jsoneditor: { type: oldValue.type } - } + }] } } @@ -230,7 +230,7 @@ export function replace (data, path, value) { * Remove an item or property * @param {JSONData} data * @param {string} path - * @return {{data: JSONData, revert: Object}} + * @return {{data: JSONData, revert: JSONPatch}} */ export function remove (data, path) { // console.log('remove', path) @@ -246,14 +246,14 @@ export function remove (data, path) { return { data: deleteIn(data, dataPath), - revert: { + revert: [{ op: 'add', path, value, jsoneditor: { type: dataValue.type } - } + }] } } else { // object.type === 'Object' @@ -263,7 +263,7 @@ export function remove (data, path) { dataPath.pop() // remove the 'value' property, we want to remove the whole object property return { data: deleteIn(data, dataPath), - revert: { + revert: [{ op: 'add', path, value, @@ -271,7 +271,7 @@ export function remove (data, path) { type: dataValue.type, before: findNextProp(parent, prop) } - } + }] } } } @@ -281,7 +281,7 @@ export function remove (data, path) { * @param {string} path * @param {JSONData} value * @param {{before?: string}} [options] - * @return {{data: JSONData, revert: Object}} + * @return {{data: JSONData, revert: JSONPatch}} * @private */ export function add (data, path, value, options) { @@ -334,23 +334,23 @@ export function add (data, path, value, options) { if (parent.type === 'Object' && oldValue !== undefined) { return { data: updatedData, - revert: { + revert: [{ op: 'replace', path: compileJSONPointer(resolvedPath), value: dataToJson(oldValue), jsoneditor: { type: oldValue.type } - } + }] } } else { return { data: updatedData, - revert: { + revert: [{ op: 'remove', path: compileJSONPointer(resolvedPath) - } + }] } } } @@ -361,7 +361,7 @@ export function add (data, path, value, options) { * @param {string} path * @param {string} from * @param {{before?: string}} [options] - * @return {{data: JSONData, revert: Object}} + * @return {{data: JSONData, revert: JSONPatch}} * @private */ export function copy (data, path, from, options) { @@ -376,26 +376,35 @@ export function copy (data, path, from, options) { * @param {string} path * @param {string} from * @param {{before?: string}} [options] - * @return {{data: JSONData, revert: Object}} + * @return {{data: JSONData, revert: JSONPatch}} * @private */ export function move (data, path, from, options) { - if (path !== from) { - const value = getIn(data, toDataPath(data, parseJSONPointer(from))) + const dataValue = getIn(data, toDataPath(data, parseJSONPointer(from))) - const result1 = remove(data, from) - const result2 = add(result1.data, path, value, options) + const result1 = remove(data, from) + const result2 = add(result1.data, path, dataValue, options) + if (result2.revert[0].op === 'replace') { return { data: result2.data, - revert: result1.revert.concat(result2.revert) + revert: [ + { op: 'move', from: path, path: from }, + { + op: 'add', + path, + value: result2.revert[0].value, + jsoneditor: result2.revert[0].jsoneditor + } + ] } } - else { - // nothing to do + else { // result2.revert[0].op === 'remove' return { - data, - revert: [] + data: result2.data, + revert: [ + {op: 'move', from: path, path: from} + ] } } } diff --git a/test/jsonData.test.js b/test/jsonData.test.js index ac1455c..38fd4b5 100644 --- a/test/jsonData.test.js +++ b/test/jsonData.test.js @@ -365,8 +365,8 @@ test('jsonpatch remove', t => { obj: {} }) t.deepEqual(revert, [ - {op: 'add', path: '/arr/1', value: 2}, - {op: 'add', path: '/obj/a', value: 4} + {op: 'add', path: '/arr/1', value: 2, jsoneditor: {type: 'value'}}, + {op: 'add', path: '/obj/a', value: 4, jsoneditor: {type: 'value', before: null}} ]) // test revert @@ -402,8 +402,8 @@ test('jsonpatch replace', t => { obj: {a: 400} }) t.deepEqual(revert, [ - {op: 'replace', path: '/arr/1', value: 2}, - {op: 'replace', path: '/obj/a', value: 4} + {op: 'replace', path: '/arr/1', value: 2, jsoneditor: {type: 'value'}}, + {op: 'replace', path: '/obj/a', value: 4, jsoneditor: {type: 'value'}} ]) // test revert @@ -414,7 +414,10 @@ test('jsonpatch replace', t => { const patchedJson2 = dataToJson(patchedData2) t.deepEqual(patchedJson2, json) - t.deepEqual(revert2, patch) + t.deepEqual(revert2, [ + {op: 'replace', path: '/obj/a', value: 400, jsoneditor: {type: 'value'}}, + {op: 'replace', path: '/arr/1', value: 200, jsoneditor: {type: 'value'}} + ]) }) test('jsonpatch copy', t => { @@ -450,7 +453,7 @@ test('jsonpatch copy', t => { t.deepEqual(patchedJson2, json) t.deepEqual(revert2, [ - {op: 'add', path: '/arr/2', value: {a: 4}} + {op: 'add', path: '/arr/2', value: {a: 4}, jsoneditor: {type: 'Object'}} ]) }) @@ -470,6 +473,7 @@ test('jsonpatch move', t => { const revert = result.revert const patchedJson = dataToJson(patchedData) + t.is(result.error, null) t.deepEqual(patchedJson, { arr: [1, 2, {a:4}, 3] }) @@ -508,8 +512,8 @@ test('jsonpatch move and replace', t => { arr: {a:4} }) t.deepEqual(revert, [ - {op: 'move', from: '/arr', path: '/obj'}, - {op: 'add', path: '/arr', value: [1,2,3]} + {op:'move', from: '/arr', path: '/obj'}, + {op:'add', path:'/arr', value: [1,2,3], jsoneditor: {type: 'Array'}} ]) // test revert @@ -524,6 +528,8 @@ test('jsonpatch move and replace', t => { {op: 'remove', path: '/arr'}, {op: 'move', from: '/obj', path: '/arr'} ]) + + // TODO: would be nice when dataPatch could simplify revert2: see that the 'remove' action is redundant }) test('jsonpatch test (ok)', t => { @@ -605,3 +611,5 @@ test('jsonpatch test (fail: value not equal)', t => { t.deepEqual(revert, []) t.is(result.error.toString(), 'Error: Test failed, value differs') }) + +// TODO: test `jsoneditor.before` JSONPatch property \ No newline at end of file