Remove `options` from immutableJSONPatch.js

This commit is contained in:
josdejong 2020-05-08 21:07:35 +02:00
parent 4774a50799
commit b3ef0ad6a4
3 changed files with 23 additions and 88 deletions

View File

@ -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,

View File

@ -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')
} }

View File

@ -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)