Remove `options` from immutableJSONPatch.js
This commit is contained in:
parent
4774a50799
commit
b3ef0ad6a4
|
@ -41,14 +41,6 @@
|
||||||
* @typedef {JSONPatchOperation[]} JSONPatchDocument
|
* @typedef {JSONPatchOperation[]} JSONPatchDocument
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{
|
|
||||||
* fromJSON: function(json: JSON, previousObject: * | undefined),
|
|
||||||
* toJSON: function(object: *),
|
|
||||||
* clone: function(object: *)
|
|
||||||
* }} JSONPatchOptions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* patch: JSONPatchDocument,
|
* patch: JSONPatchDocument,
|
||||||
|
|
|
@ -9,22 +9,15 @@ import { compileJSONPointer, parseJSONPointer } from './jsonPointer.js'
|
||||||
import initial from 'lodash/initial.js'
|
import initial from 'lodash/initial.js'
|
||||||
import isEqual from 'lodash/isEqual.js'
|
import isEqual from 'lodash/isEqual.js'
|
||||||
|
|
||||||
const DEFAULT_OPTIONS = {
|
|
||||||
fromJSON: (json, previousObject) => json,
|
|
||||||
toJSON: (object) => object,
|
|
||||||
clone: (object) => object
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a patch to a JSON object
|
* Apply a patch to a JSON object
|
||||||
* The original JSON object will not be changed,
|
* The original JSON object will not be changed,
|
||||||
* instead, the patch is applied in an immutable way
|
* instead, the patch is applied in an immutable way
|
||||||
* @param {JSON} json
|
* @param {JSON} json
|
||||||
* @param {JSONPatchDocument} operations Array with JSON patch actions
|
* @param {JSONPatchDocument} operations Array with JSON patch actions
|
||||||
* @param {JSONPatchOptions} [options]
|
|
||||||
* @return {{json: JSON, revert: JSONPatchDocument, error: Error | null}}
|
* @return {{json: JSON, revert: JSONPatchDocument, error: Error | null}}
|
||||||
*/
|
*/
|
||||||
export function immutableJSONPatch (json, operations, options = DEFAULT_OPTIONS) {
|
export function immutableJSONPatch (json, operations) {
|
||||||
let updatedJson = json
|
let updatedJson = json
|
||||||
let revert = []
|
let revert = []
|
||||||
|
|
||||||
|
@ -35,14 +28,14 @@ export function immutableJSONPatch (json, operations, options = DEFAULT_OPTIONS)
|
||||||
|
|
||||||
switch (operation.op) {
|
switch (operation.op) {
|
||||||
case 'add': {
|
case 'add': {
|
||||||
const result = add(updatedJson, path, operation.value, options)
|
const result = add(updatedJson, path, operation.value)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'remove': {
|
case 'remove': {
|
||||||
const result = remove(updatedJson, path, options)
|
const result = remove(updatedJson, path)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
|
@ -50,7 +43,7 @@ export function immutableJSONPatch (json, operations, options = DEFAULT_OPTIONS)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'replace': {
|
case 'replace': {
|
||||||
const result = replace(updatedJson, path, operation.value, options)
|
const result = replace(updatedJson, path, operation.value)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
|
@ -66,7 +59,7 @@ export function immutableJSONPatch (json, operations, options = DEFAULT_OPTIONS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = copy(updatedJson, path, from, options)
|
const result = copy(updatedJson, path, from)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
|
@ -82,7 +75,7 @@ export function immutableJSONPatch (json, operations, options = DEFAULT_OPTIONS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = move(updatedJson, path, from, options)
|
const result = move(updatedJson, path, from)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
|
@ -91,7 +84,7 @@ export function immutableJSONPatch (json, operations, options = DEFAULT_OPTIONS)
|
||||||
|
|
||||||
case 'test': {
|
case 'test': {
|
||||||
// when a test fails, cancel the whole patch and return the error
|
// when a test fails, cancel the whole patch and return the error
|
||||||
const error = test(updatedJson, path, operation.value, options)
|
const error = test(updatedJson, path, operation.value)
|
||||||
if (error) {
|
if (error) {
|
||||||
return { json, revert: [], error}
|
return { json, revert: [], error}
|
||||||
}
|
}
|
||||||
|
@ -122,15 +115,13 @@ export function immutableJSONPatch (json, operations, options = DEFAULT_OPTIONS)
|
||||||
* @param {JSON} json
|
* @param {JSON} json
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {JSON} value
|
* @param {JSON} value
|
||||||
* @param {JSONPatchOptions} [options]
|
|
||||||
* @return {{json: JSON, revert: JSONPatchDocument}}
|
* @return {{json: JSON, revert: JSONPatchDocument}}
|
||||||
*/
|
*/
|
||||||
export function replace (json, path, value, options) {
|
export function replace (json, path, value) {
|
||||||
const oldValue = getIn(json, path)
|
const oldValue = getIn(json, path)
|
||||||
const newValue = options.fromJSON(value, oldValue)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
json: setIn(json, path, newValue),
|
json: setIn(json, path, value),
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
path: compileJSONPointer(path),
|
path: compileJSONPointer(path),
|
||||||
|
@ -143,10 +134,9 @@ export function replace (json, path, value, options) {
|
||||||
* Remove an item or property
|
* Remove an item or property
|
||||||
* @param {JSON} json
|
* @param {JSON} json
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {JSONPatchOptions} [options]
|
|
||||||
* @return {{json: JSON, revert: JSONPatchDocument}}
|
* @return {{json: JSON, revert: JSONPatchDocument}}
|
||||||
*/
|
*/
|
||||||
export function remove (json, path, options) {
|
export function remove (json, path) {
|
||||||
const oldValue = getIn(json, path)
|
const oldValue = getIn(json, path)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -154,7 +144,7 @@ export function remove (json, path, options) {
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'add',
|
op: 'add',
|
||||||
path: compileJSONPointer(path),
|
path: compileJSONPointer(path),
|
||||||
value: options.toJSON(oldValue)
|
value: oldValue
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,22 +153,20 @@ export function remove (json, path, options) {
|
||||||
* @param {JSON} json
|
* @param {JSON} json
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {JSON} value
|
* @param {JSON} value
|
||||||
* @param {JSONPatchOptions} [options]
|
|
||||||
* @return {{json: JSON, revert: JSONPatchDocument}}
|
* @return {{json: JSON, revert: JSONPatchDocument}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function add (json, path, value, options) {
|
export function add (json, path, value) {
|
||||||
const resolvedPath = resolvePathIndex(json, path)
|
const resolvedPath = resolvePathIndex(json, path)
|
||||||
const parent = getIn(json, initial(path))
|
const parent = getIn(json, initial(path))
|
||||||
const parentIsArray = Array.isArray(parent)
|
const parentIsArray = Array.isArray(parent)
|
||||||
const oldValue = parentIsArray
|
const oldValue = parentIsArray
|
||||||
? undefined
|
? undefined
|
||||||
: getIn(json, resolvedPath)
|
: getIn(json, resolvedPath)
|
||||||
const newValue = options.fromJSON(value, oldValue)
|
|
||||||
|
|
||||||
const updatedJson = parentIsArray
|
const updatedJson = parentIsArray
|
||||||
? insertAt(json, resolvedPath, newValue)
|
? insertAt(json, resolvedPath, value)
|
||||||
: setIn(json, resolvedPath, newValue)
|
: setIn(json, resolvedPath, value)
|
||||||
|
|
||||||
if (!parentIsArray && existsIn(json, resolvedPath)) {
|
if (!parentIsArray && existsIn(json, resolvedPath)) {
|
||||||
return {
|
return {
|
||||||
|
@ -186,7 +174,7 @@ export function add (json, path, value, options) {
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
path: compileJSONPointer(resolvedPath),
|
path: compileJSONPointer(resolvedPath),
|
||||||
value: options.toJSON(oldValue)
|
value: oldValue
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,20 +194,13 @@ export function add (json, path, value, options) {
|
||||||
* @param {JSON} json
|
* @param {JSON} json
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {Path} from
|
* @param {Path} from
|
||||||
* @param {JSONPatchOptions} [options]
|
|
||||||
* @return {{json: JSON, revert: JSONPatchDocument}}
|
* @return {{json: JSON, revert: JSONPatchDocument}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function copy (json, path, from, options) {
|
export function copy (json, path, from) {
|
||||||
const value = options.clone
|
const value = getIn(json, from)
|
||||||
? options.clone(getIn(json, from))
|
|
||||||
: options.fromJSON(options.toJSON(getIn(json, from)), undefined)
|
|
||||||
|
|
||||||
return add(json, path, value, {
|
return add(json, path, value)
|
||||||
fromJSON: DEFAULT_OPTIONS.fromJSON,
|
|
||||||
toJSON: options.toJSON,
|
|
||||||
clone: options.clone
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -227,18 +208,17 @@ export function copy (json, path, from, options) {
|
||||||
* @param {JSON} json
|
* @param {JSON} json
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {Path} from
|
* @param {Path} from
|
||||||
* @param {JSONPatchOptions} [options]
|
|
||||||
* @return {{json: JSON, revert: JSONPatchDocument}}
|
* @return {{json: JSON, revert: JSONPatchDocument}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function move (json, path, from, options) {
|
export function move (json, path, from) {
|
||||||
const resolvedPath = resolvePathIndex(json, path)
|
const resolvedPath = resolvePathIndex(json, path)
|
||||||
const parent = getIn(json, initial(path))
|
const parent = getIn(json, initial(path))
|
||||||
const parentIsArray = Array.isArray(parent)
|
const parentIsArray = Array.isArray(parent)
|
||||||
const oldValue = getIn(json, path)
|
const oldValue = getIn(json, path)
|
||||||
const value = getIn(json, from)
|
const value = getIn(json, from)
|
||||||
|
|
||||||
const removedJson = remove(json, from, options).json
|
const removedJson = remove(json, from).json
|
||||||
const updatedJson = parentIsArray
|
const updatedJson = parentIsArray
|
||||||
? insertAt(removedJson, resolvedPath, value)
|
? insertAt(removedJson, resolvedPath, value)
|
||||||
: setIn(removedJson, resolvedPath, value)
|
: setIn(removedJson, resolvedPath, value)
|
||||||
|
@ -256,7 +236,7 @@ export function move (json, path, from, options) {
|
||||||
{
|
{
|
||||||
op: 'add',
|
op: 'add',
|
||||||
path: compileJSONPointer(resolvedPath),
|
path: compileJSONPointer(resolvedPath),
|
||||||
value: options.toJSON(oldValue)
|
value: oldValue
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -281,10 +261,9 @@ export function move (json, path, from, options) {
|
||||||
* @param {JSON} json
|
* @param {JSON} json
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {JSON} value
|
* @param {JSON} value
|
||||||
* @param {JSONPatchOptions} [options]
|
|
||||||
* @return {null | Error} Returns an error when the tests, returns null otherwise
|
* @return {null | Error} Returns an error when the tests, returns null otherwise
|
||||||
*/
|
*/
|
||||||
export function test (json, path, value, options) {
|
export function test (json, path, value) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return new Error('Test failed, no value provided')
|
return new Error('Test failed, no value provided')
|
||||||
}
|
}
|
||||||
|
@ -293,7 +272,7 @@ export function test (json, path, value, options) {
|
||||||
return new Error('Test failed, path not found')
|
return new Error('Test failed, path not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
const actualValue = options.toJSON(getIn(json, path))
|
const actualValue = getIn(json, path)
|
||||||
if (!isEqual(actualValue, value)) {
|
if (!isEqual(actualValue, value)) {
|
||||||
return new Error('Test failed, value differs')
|
return new Error('Test failed, value differs')
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,40 +334,4 @@ test('jsonpatch test (fail: value not equal)', () => {
|
||||||
expect(result.error.toString()).toEqual('Error: Test failed, value differs')
|
expect(result.error.toString()).toEqual('Error: Test failed, value differs')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('jsonpatch options', () => {
|
|
||||||
const json = {
|
|
||||||
arr: [1,2,3],
|
|
||||||
obj: {a : 2}
|
|
||||||
}
|
|
||||||
|
|
||||||
const patch = [
|
|
||||||
{op: 'add', path: '/obj/a', value: 4 }
|
|
||||||
]
|
|
||||||
const result = immutableJSONPatch(json, patch, {
|
|
||||||
fromJSON: function (value, previousObject) {
|
|
||||||
return { value, previousObject }
|
|
||||||
},
|
|
||||||
toJSON: value => value
|
|
||||||
})
|
|
||||||
expect(result.json).toEqual({
|
|
||||||
arr: [1,2,3],
|
|
||||||
obj: {a : { value: 4, previousObject: 2 }}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
const patch2 = [
|
|
||||||
{op: 'add', path: '/obj/b', value: 4 }
|
|
||||||
]
|
|
||||||
const result2 = immutableJSONPatch(json, patch2, {
|
|
||||||
fromJSON: function (value, previousObject) {
|
|
||||||
return { value, previousObject }
|
|
||||||
},
|
|
||||||
toJSON: value => value
|
|
||||||
})
|
|
||||||
expect(result2.json).toEqual({
|
|
||||||
arr: [1,2,3],
|
|
||||||
obj: {a : 2, b: { value: 4, previousObject: undefined }}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// TODO: test all operations with JSONPatchOptions (not just add)
|
// TODO: test all operations with JSONPatchOptions (not just add)
|
Loading…
Reference in New Issue