diff --git a/src/actions.js b/src/actions.js
index 812b071..07df352 100644
--- a/src/actions.js
+++ b/src/actions.js
@@ -145,7 +145,7 @@ export function insert (data, path, type) {
const index = parseInt(path[path.length - 1]) + 1
return [{
op: 'add',
- path: compileJSONPointer(parentPath.concat(index + '')),
+ path: compileJSONPointer(parentPath.concat(index)),
value,
jsoneditor: {
type
diff --git a/src/develop.html b/src/develop.html
index 00ed9e7..6207665 100644
--- a/src/develop.html
+++ b/src/develop.html
@@ -2,7 +2,7 @@
- Develop JSONEditor Next
+ Develop JSONEditor
diff --git a/src/jsonData.js b/src/jsonData.js
index 595fc6b..4d92490 100644
--- a/src/jsonData.js
+++ b/src/jsonData.js
@@ -117,97 +117,101 @@ export function toDataPath (data, path) {
export function patchData (data, patch) {
const expand = expandAll // TODO: customizable expand function
- try {
- let updatedData = data
- let revert = []
+ let updatedData = data
+ let revert = []
- patch.forEach(function (action) {
- const options = action.jsoneditor
+ for (let i = 0; i < patch.length; i++) {
+ const action = patch[i]
+ const options = action.jsoneditor
- switch (action.op) {
- case 'add': {
- const path = parseJSONPointer(action.path)
- const newValue = jsonToData(action.value, expand, path)
+ switch (action.op) {
+ case 'add': {
+ const path = parseJSONPointer(action.path)
+ const newValue = jsonToData(action.value, expand, path)
- // TODO: move setting type to jsonToData
- if (options && options.type) {
- // insert with type 'string' or 'value'
- newValue.type = options.type
- }
- // TODO: handle options.order
+ // TODO: move setting type to jsonToData
+ if (options && options.type) {
+ // insert with type 'string' or 'value'
+ newValue.type = options.type
+ }
+ // TODO: handle options.order
- const result = add(updatedData, action.path, newValue, options)
- updatedData = result.data
- revert = result.revert.concat(revert)
+ const result = add(updatedData, action.path, newValue, options)
+ updatedData = result.data
+ revert = result.revert.concat(revert)
- break
+ break
+ }
+
+ case 'remove': {
+ const result = remove(updatedData, action.path)
+ updatedData = result.data
+ revert = result.revert.concat(revert)
+
+ break
+ }
+
+ case 'replace': {
+ const path = parseJSONPointer(action.path)
+ let newValue = jsonToData(action.value, expand, path)
+
+ // TODO: move setting type to jsonToData
+ if (options && options.type) {
+ // insert with type 'string' or 'value'
+ newValue.type = options.type
+ }
+ // TODO: handle options.order
+
+ const result = replace(updatedData, path, newValue)
+ updatedData = result.data
+ revert = result.revert.concat(revert)
+
+ break
+ }
+
+ case 'copy': {
+ const result = copy(updatedData, action.path, action.from, options)
+ updatedData = result.data
+ revert = result.revert.concat(revert)
+
+ break
+ }
+
+ case 'move': {
+ const result = move(updatedData, action.path, action.from, options)
+ updatedData = result.data
+ revert = result.revert.concat(revert)
+
+ break
+ }
+
+ case 'test': {
+ // when a test fails, cancel the whole patch and return the error
+ const error = test(updatedData, action.path, action.value)
+ if (error) {
+ return { data, revert: [], error}
}
- case 'remove': {
- const result = remove(updatedData, action.path)
- updatedData = result.data
- revert = result.revert.concat(revert)
+ break
+ }
- break
- }
-
- case 'replace': {
- const path = parseJSONPointer(action.path)
- let newValue = jsonToData(action.value, expand, path)
-
- // TODO: move setting type to jsonToData
- if (options && options.type) {
- // insert with type 'string' or 'value'
- newValue.type = options.type
- }
- // TODO: handle options.order
-
- const result = replace(updatedData, path, newValue)
- updatedData = result.data
- revert = result.revert.concat(revert)
-
- break
- }
-
- case 'copy': {
- const result = copy(updatedData, action.path, action.from, options)
- updatedData = result.data
- revert = result.revert.concat(revert)
-
- break
- }
-
- case 'move': {
- const result = move(updatedData, action.path, action.from, options)
- updatedData = result.data
- revert = result.revert.concat(revert)
-
- break
- }
-
- case 'test': {
- test(updatedData, action.path, action.value)
-
- break
- }
-
- default: {
- throw new Error('Unknown jsonpatch op ' + JSON.stringify(action.op))
+ default: {
+ // unknown jsonpatch operation. Cancel the whole patch and return an error
+ return {
+ data,
+ revert: [],
+ error: new Error('Unknown jsonpatch op ' + JSON.stringify(action.op))
}
}
- })
-
- // TODO: Simplify revert when possible:
- // when a previous action takes place on the same path, remove the first
-
- return {
- data: updatedData,
- revert: simplifyPatch(revert),
- error: null
}
}
- catch (error) {
- return {data, revert: [], error}
+
+ // TODO: Simplify revert when possible:
+ // when a previous action takes place on the same path, remove the first
+ return {
+ data: updatedData,
+ revert: simplifyPatch(revert),
+ error: null
}
}
@@ -336,7 +340,7 @@ export function add (data, path, value, options) {
let updatedData
if (parent.type === 'Array') {
- updatedData = insertAt(data, dataPath.concat('items', prop), value)
+ updatedData = insertAt(data, dataPath.concat('items', prop), value)
}
else { // parent.type === 'Object'
updatedData = updateIn(data, dataPath, (object) => {
@@ -439,20 +443,21 @@ export function move (data, path, from, options) {
* @param {JSONData} data
* @param {string} path
* @param {*} value
+ * @return {null | Error} Returns an error when the tests, returns null otherwise
*/
export function test (data, path, value) {
if (value === undefined) {
- throw new Error('Test failed, no value provided')
+ return new Error('Test failed, no value provided')
}
const pathArray = parseJSONPointer(path)
if (!pathExists(data, pathArray)) {
- throw new Error('Test failed, path not found')
+ return new Error('Test failed, path not found')
}
const actualValue = getIn(data, toDataPath(data, pathArray))
if (!isEqual(dataToJson(actualValue), value)) {
- throw new Error('Test failed, value differs')
+ return new Error('Test failed, value differs')
}
}
@@ -614,15 +619,11 @@ export function findPropertyIndex (object, prop) {
/**
* Parse a JSON Pointer
- * WARNING: this is not a complete string implementation
+ * WARNING: this is not a complete implementation
* @param {string} pointer
* @return {Array}
*/
export function parseJSONPointer (pointer) {
- if (pointer === '/') {
- return []
- }
-
const path = pointer.split('/')
path.shift() // remove the first empty entry
@@ -631,12 +632,12 @@ export function parseJSONPointer (pointer) {
/**
* Compile a JSON Pointer
- * WARNING: this is not a complete string implementation
+ * WARNING: this is not a complete implementation
* @param {Path} path
* @return {string}
*/
export function compileJSONPointer (path) {
- return '/' + path
- .map(p => String(p).replace(/~/g, '~0').replace(/\//g, '~1'))
- .join('/')
+ return path
+ .map(p => '/' + String(p).replace(/~/g, '~0').replace(/\//g, '~1'))
+ .join('')
}
diff --git a/test/jsonData.test.js b/test/jsonData.test.js
index 297a6d9..c1e93cf 100644
--- a/test/jsonData.test.js
+++ b/test/jsonData.test.js
@@ -286,12 +286,15 @@ test('parseJSONPointer', t => {
t.deepEqual(parseJSONPointer('/arr/-'), ['arr', '-'])
t.deepEqual(parseJSONPointer('/foo/~1~0 ~0~1'), ['foo', '/~ ~/'])
t.deepEqual(parseJSONPointer('/obj'), ['obj'])
- t.deepEqual(parseJSONPointer('/'), [])
+ t.deepEqual(parseJSONPointer('/'), [''])
+ t.deepEqual(parseJSONPointer(''), [])
})
test('compileJSONPointer', t => {
t.deepEqual(compileJSONPointer(['foo', 'bar']), '/foo/bar')
t.deepEqual(compileJSONPointer(['foo', '/~ ~/']), '/foo/~1~0 ~0~1')
+ t.deepEqual(compileJSONPointer(['']), '/')
+ t.deepEqual(compileJSONPointer([]), '')
})
test('jsonpatch add', t => {