Extended immutableJSONPatch with options fromJSON, toJSON, clone
This commit is contained in:
parent
dc814a3aa5
commit
410353c86f
|
@ -159,7 +159,7 @@ class App extends Component {
|
||||||
|
|
||||||
handlePatch = (patch, revert) => {
|
handlePatch = (patch, revert) => {
|
||||||
this.log('onPatch patch=', patch, ', revert=', revert)
|
this.log('onPatch patch=', patch, ', revert=', revert)
|
||||||
window.immutableJsonPatch = patch
|
window.immutableJSONPatch = patch
|
||||||
window.revert = revert
|
window.revert = revert
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
name: 'myObject',
|
name: 'myObject',
|
||||||
onPatch: function (patch, revert) {
|
onPatch: function (patch, revert) {
|
||||||
log('onPatch patch=', patch, ', revert=', revert)
|
log('onPatch patch=', patch, ', revert=', revert)
|
||||||
window.immutableJsonPatch = patch
|
window.immutableJSONPatch = patch
|
||||||
window.revert = revert
|
window.revert = revert
|
||||||
},
|
},
|
||||||
onPatchText: function (patch, revert) {
|
onPatchText: function (patch, revert) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import { sort } from './actions'
|
import { sort } from './actions'
|
||||||
import { createAssertEqualEson } from './utils/assertEqualEson'
|
import { createAssertEqualEson } from './utils/assertEqualEson'
|
||||||
import { ID, syncEson } from './eson'
|
import { ID, syncEson } from './eson'
|
||||||
import { immutableJsonPatch } from './immutableJsonPatch'
|
import { immutableJSONPatch } from './immutableJSONPatch'
|
||||||
|
|
||||||
const assertEqualEson = createAssertEqualEson(expect)
|
const assertEqualEson = createAssertEqualEson(expect)
|
||||||
|
|
||||||
|
@ -20,14 +20,14 @@ const assertEqualEson = createAssertEqualEson(expect)
|
||||||
it('sort root Array', () => {
|
it('sort root Array', () => {
|
||||||
const eson = syncEson([1,3,2])
|
const eson = syncEson([1,3,2])
|
||||||
|
|
||||||
assertEqualEson(immutableJsonPatch(eson, sort(eson, [])).json, syncEson([1,2,3]))
|
assertEqualEson(immutableJSONPatch(eson, sort(eson, [])).json, syncEson([1,2,3]))
|
||||||
assertEqualEson(immutableJsonPatch(eson, sort(eson, [], 'asc')).json, syncEson([1,2,3]))
|
assertEqualEson(immutableJSONPatch(eson, sort(eson, [], 'asc')).json, syncEson([1,2,3]))
|
||||||
assertEqualEson(immutableJsonPatch(eson, sort(eson, [], 'desc')).json, syncEson([3,2,1]))
|
assertEqualEson(immutableJSONPatch(eson, sort(eson, [], 'desc')).json, syncEson([3,2,1]))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sort nested Array', () => {
|
it('sort nested Array', () => {
|
||||||
const eson = syncEson({arr: [4,1,8,5,3,9,2,7,6]})
|
const eson = syncEson({arr: [4,1,8,5,3,9,2,7,6]})
|
||||||
const actual = immutableJsonPatch(eson, sort(eson, ['arr'])).json
|
const actual = immutableJSONPatch(eson, sort(eson, ['arr'])).json
|
||||||
const expected = syncEson({arr: [1,2,3,4,5,6,7,8,9]})
|
const expected = syncEson({arr: [1,2,3,4,5,6,7,8,9]})
|
||||||
assertEqualEson(actual, expected)
|
assertEqualEson(actual, expected)
|
||||||
})
|
})
|
||||||
|
@ -35,7 +35,7 @@ it('sort nested Array', () => {
|
||||||
it('sort nested Array reverse order', () => {
|
it('sort nested Array reverse order', () => {
|
||||||
// no order provided -> order ascending, but if nothing changes, order descending
|
// no order provided -> order ascending, but if nothing changes, order descending
|
||||||
const eson = syncEson({arr: [1,2,3,4,5,6,7,8,9]})
|
const eson = syncEson({arr: [1,2,3,4,5,6,7,8,9]})
|
||||||
const actual = immutableJsonPatch(eson, sort(eson, ['arr'])).json
|
const actual = immutableJSONPatch(eson, sort(eson, ['arr'])).json
|
||||||
const expected = syncEson({arr: [9,8,7,6,5,4,3,2,1]})
|
const expected = syncEson({arr: [9,8,7,6,5,4,3,2,1]})
|
||||||
assertEqualEson(actual, expected)
|
assertEqualEson(actual, expected)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { createFindKeyBinding } from '../utils/keyBindings'
|
||||||
import { KEY_BINDINGS } from '../constants'
|
import { KEY_BINDINGS } from '../constants'
|
||||||
|
|
||||||
import ModeButton from './menu/ModeButton'
|
import ModeButton from './menu/ModeButton'
|
||||||
import { immutableJsonPatch } from '../immutableJsonPatch'
|
import { immutableJSONPatch } from '../immutableJSONPatch'
|
||||||
|
|
||||||
const AJV_OPTIONS = {
|
const AJV_OPTIONS = {
|
||||||
allErrors: true,
|
allErrors: true,
|
||||||
|
@ -330,7 +330,7 @@ export default class TextMode extends Component {
|
||||||
patch (operations) {
|
patch (operations) {
|
||||||
const json = this.get()
|
const json = this.get()
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, operations)
|
const result = immutableJSONPatch(json, operations)
|
||||||
|
|
||||||
this.set(result.data)
|
this.set(result.data)
|
||||||
|
|
||||||
|
|
|
@ -48,16 +48,15 @@ import {
|
||||||
} from './utils/domSelector'
|
} from './utils/domSelector'
|
||||||
import { createFindKeyBinding } from '../utils/keyBindings'
|
import { createFindKeyBinding } from '../utils/keyBindings'
|
||||||
import { KEY_BINDINGS } from '../constants'
|
import { KEY_BINDINGS } from '../constants'
|
||||||
import { immutableJsonPatch } from '../immutableJsonPatch'
|
import { immutableJSONPatch } from '../immutableJSONPatch'
|
||||||
import {
|
import {
|
||||||
applyErrors, applySelection, contentsFromPaths,
|
applyErrors, applySelection, contentsFromPaths,
|
||||||
expand,
|
expand,
|
||||||
EXPANDED,
|
EXPANDED,
|
||||||
expandPath,
|
expandPath, immutableESONPatch,
|
||||||
nextSearchResult, pathsFromSelection, previousSearchResult,
|
nextSearchResult, pathsFromSelection, previousSearchResult,
|
||||||
search,
|
search,
|
||||||
syncEson,
|
syncEson
|
||||||
toEsonPatchOperation
|
|
||||||
} from '../eson'
|
} from '../eson'
|
||||||
|
|
||||||
const AJV_OPTIONS = {
|
const AJV_OPTIONS = {
|
||||||
|
@ -904,8 +903,8 @@ export default class TreeMode extends PureComponent {
|
||||||
const historyIndex = this.state.historyIndex
|
const historyIndex = this.state.historyIndex
|
||||||
const historyItem = history[historyIndex]
|
const historyItem = history[historyIndex]
|
||||||
|
|
||||||
const jsonResult = immutableJsonPatch(this.state.json, historyItem.undo)
|
const jsonResult = immutableJSONPatch(this.state.json, historyItem.undo)
|
||||||
const esonResult = immutableJsonPatch(this.state.eson, historyItem.undo.map(toEsonPatchOperation))
|
const esonResult = immutableESONPatch(this.state.eson, historyItem.undo)
|
||||||
|
|
||||||
// FIXME: apply search
|
// FIXME: apply search
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -925,8 +924,8 @@ export default class TreeMode extends PureComponent {
|
||||||
const historyIndex = this.state.historyIndex - 1
|
const historyIndex = this.state.historyIndex - 1
|
||||||
const historyItem = history[historyIndex]
|
const historyItem = history[historyIndex]
|
||||||
|
|
||||||
const jsonResult = immutableJsonPatch(this.state.json, historyItem.redo)
|
const jsonResult = immutableJSONPatch(this.state.json, historyItem.redo)
|
||||||
const esonResult = immutableJsonPatch(this.state.eson, historyItem.undo.map(toEsonPatchOperation))
|
const esonResult = immutableESONPatch(this.state.eson, historyItem.redo)
|
||||||
|
|
||||||
// FIXME: apply search
|
// FIXME: apply search
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -954,8 +953,8 @@ export default class TreeMode extends PureComponent {
|
||||||
|
|
||||||
console.log('patch', operations) // TODO: cleanup
|
console.log('patch', operations) // TODO: cleanup
|
||||||
|
|
||||||
const jsonResult = immutableJsonPatch(this.state.json, operations)
|
const jsonResult = immutableJSONPatch(this.state.json, operations)
|
||||||
const esonResult = immutableJsonPatch(this.state.eson, operations.map(toEsonPatchOperation))
|
const esonResult = immutableESONPatch(this.state.eson, operations)
|
||||||
|
|
||||||
if (this.props.history !== false) {
|
if (this.props.history !== false) {
|
||||||
// update data and store history
|
// update data and store history
|
||||||
|
|
|
@ -7,6 +7,7 @@ import isEmpty from 'lodash/isEmpty'
|
||||||
import isEqual from 'lodash/isEqual'
|
import isEqual from 'lodash/isEqual'
|
||||||
import naturalSort from 'javascript-natural-sort'
|
import naturalSort from 'javascript-natural-sort'
|
||||||
import times from 'lodash/times'
|
import times from 'lodash/times'
|
||||||
|
import { immutableJSONPatch } from './immutableJSONPatch'
|
||||||
|
|
||||||
export const ID = typeof Symbol === 'function' ? Symbol('id') : '@jsoneditor-id'
|
export const ID = typeof Symbol === 'function' ? Symbol('id') : '@jsoneditor-id'
|
||||||
export const TYPE = typeof Symbol === 'function' ? Symbol('type') : '@jsoneditor-type' // 'object', 'array', 'value', or 'undefined'
|
export const TYPE = typeof Symbol === 'function' ? Symbol('type') : '@jsoneditor-type' // 'object', 'array', 'value', or 'undefined'
|
||||||
|
@ -529,14 +530,19 @@ export function pathsFromSelection (eson, selection) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the value of a JSON Patch action into a ESON object
|
* Apply a JSON patch document to an ESON object.
|
||||||
* @param {JSONPatchOperation} operation
|
* - Applies meta information to added values
|
||||||
* @returns {ESONPatchOperation}
|
* - Reckons with creating unique id's when duplicating data
|
||||||
|
* @param eson
|
||||||
|
* @param operations
|
||||||
|
* @returns {{json: JSON, revert: JSONPatchDocument, error: (Error|null)}}
|
||||||
*/
|
*/
|
||||||
export function toEsonPatchOperation (operation) {
|
export function immutableESONPatch (eson, operations) {
|
||||||
return ('value' in operation)
|
return immutableJSONPatch(eson, operations, {
|
||||||
? setIn(operation, ['value'], syncEson(operation.value))
|
fromJSON: (value, previousEson) => syncEson(value, previousEson),
|
||||||
: operation
|
toJSON: (eson) => eson[VALUE],
|
||||||
|
clone: (value) => setIn(value, [ID], createId())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
|
|
|
@ -4,15 +4,22 @@ import initial from 'lodash/initial'
|
||||||
import { setIn, getIn, deleteIn, insertAt, existsIn } from './utils/immutabilityHelpers'
|
import { setIn, getIn, deleteIn, insertAt, existsIn } from './utils/immutabilityHelpers'
|
||||||
import { parseJSONPointer, compileJSONPointer } from './jsonPointer'
|
import { parseJSONPointer, compileJSONPointer } from './jsonPointer'
|
||||||
|
|
||||||
|
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) {
|
export function immutableJSONPatch (json, operations, options = DEFAULT_OPTIONS) {
|
||||||
let updatedJson = json
|
let updatedJson = json
|
||||||
let revert = []
|
let revert = []
|
||||||
|
|
||||||
|
@ -23,14 +30,14 @@ export function immutableJsonPatch (json, operations) {
|
||||||
|
|
||||||
switch (operation.op) {
|
switch (operation.op) {
|
||||||
case 'add': {
|
case 'add': {
|
||||||
const result = add(updatedJson, path, operation.value)
|
const result = add(updatedJson, path, operation.value, options)
|
||||||
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)
|
const result = remove(updatedJson, path, options)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
|
@ -38,7 +45,7 @@ export function immutableJsonPatch (json, operations) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'replace': {
|
case 'replace': {
|
||||||
const result = replace(updatedJson, path, operation.value)
|
const result = replace(updatedJson, path, operation.value, options)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
|
@ -54,7 +61,7 @@ export function immutableJsonPatch (json, operations) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = copy(updatedJson, path, from)
|
const result = copy(updatedJson, path, from, options)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
|
@ -70,7 +77,7 @@ export function immutableJsonPatch (json, operations) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = move(updatedJson, path, from)
|
const result = move(updatedJson, path, from, options)
|
||||||
updatedJson = result.json
|
updatedJson = result.json
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
|
@ -79,7 +86,7 @@ export function immutableJsonPatch (json, operations) {
|
||||||
|
|
||||||
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)
|
const error = test(updatedJson, path, operation.value, options)
|
||||||
if (error) {
|
if (error) {
|
||||||
return { json, revert: [], error}
|
return { json, revert: [], error}
|
||||||
}
|
}
|
||||||
|
@ -110,13 +117,15 @@ export function immutableJsonPatch (json, operations) {
|
||||||
* @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) {
|
export function replace (json, path, value, options) {
|
||||||
const oldValue = getIn(json, path)
|
const oldValue = getIn(json, path)
|
||||||
|
const newValue = options.fromJSON(value, oldValue)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
json: setIn(json, path, value),
|
json: setIn(json, path, newValue),
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
path: compileJSONPointer(path),
|
path: compileJSONPointer(path),
|
||||||
|
@ -129,9 +138,10 @@ export function replace (json, path, value) {
|
||||||
* 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) {
|
export function remove (json, path, options) {
|
||||||
const oldValue = getIn(json, path)
|
const oldValue = getIn(json, path)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -139,7 +149,7 @@ export function remove (json, path) {
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'add',
|
op: 'add',
|
||||||
path: compileJSONPointer(path),
|
path: compileJSONPointer(path),
|
||||||
value: oldValue
|
value: options.toJSON(oldValue)
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,27 +158,28 @@ export function remove (json, path) {
|
||||||
* @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) {
|
export function add (json, path, value, options) {
|
||||||
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, resolvedPath)
|
||||||
|
const newValue = options.fromJSON(value, oldValue)
|
||||||
|
|
||||||
const updatedJson = parentIsArray
|
const updatedJson = parentIsArray
|
||||||
? insertAt(json, resolvedPath, value)
|
? insertAt(json, resolvedPath, newValue)
|
||||||
: setIn(json, resolvedPath, value)
|
: setIn(json, resolvedPath, newValue)
|
||||||
|
|
||||||
if (!parentIsArray && existsIn(json, resolvedPath)) {
|
if (!parentIsArray && existsIn(json, resolvedPath)) {
|
||||||
const oldValue = getIn(json, resolvedPath)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
json: updatedJson,
|
json: updatedJson,
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
path: compileJSONPointer(resolvedPath),
|
path: compileJSONPointer(resolvedPath),
|
||||||
value: oldValue
|
value: options.toJSON(oldValue)
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,13 +199,20 @@ export function add (json, path, value) {
|
||||||
* @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: ESONPatchDocument}}
|
* @return {{json: JSON, revert: ESONPatchDocument}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function copy (json, path, from) {
|
export function copy (json, path, from, options) {
|
||||||
const value = getIn(json, from)
|
const value = options.clone
|
||||||
|
? 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
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,17 +220,18 @@ export function copy (json, path, from) {
|
||||||
* @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: ESONPatchDocument}}
|
* @return {{json: JSON, revert: ESONPatchDocument}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function move (json, path, from) {
|
export function move (json, path, from, options) {
|
||||||
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).json
|
const removedJson = remove(json, from, options).json
|
||||||
const updatedJson = parentIsArray
|
const updatedJson = parentIsArray
|
||||||
? insertAt(removedJson, resolvedPath, value)
|
? insertAt(removedJson, resolvedPath, value)
|
||||||
: setIn(removedJson, resolvedPath, value)
|
: setIn(removedJson, resolvedPath, value)
|
||||||
|
@ -230,7 +249,7 @@ export function move (json, path, from) {
|
||||||
{
|
{
|
||||||
op: 'add',
|
op: 'add',
|
||||||
path: compileJSONPointer(resolvedPath),
|
path: compileJSONPointer(resolvedPath),
|
||||||
value: oldValue
|
value: options.toJSON(oldValue)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -254,10 +273,11 @@ export function move (json, path, from) {
|
||||||
* Throws an error when the test fails.
|
* Throws an error when the test fails.
|
||||||
* @param {JSON} json
|
* @param {JSON} json
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {*} 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) {
|
export function test (json, path, value, options) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return new Error('Test failed, no value provided')
|
return new Error('Test failed, no value provided')
|
||||||
}
|
}
|
||||||
|
@ -266,7 +286,7 @@ export function test (json, path, value) {
|
||||||
return new Error('Test failed, path not found')
|
return new Error('Test failed, path not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
const actualValue = getIn(json, path)
|
const actualValue = options.toJSON(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')
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
import { immutableJsonPatch } from './immutableJsonPatch'
|
import { immutableJSONPatch } from './immutableJSONPatch'
|
||||||
|
|
||||||
test('test toBe', () => {
|
test('test toBe', () => {
|
||||||
const a = { x: 2 }
|
const a = { x: 2 }
|
||||||
|
@ -22,7 +22,7 @@ test('jsonpatch add', () => {
|
||||||
{op: 'add', path: '/obj/b', value: {foo: 'bar'}}
|
{op: 'add', path: '/obj/b', value: {foo: 'bar'}}
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
arr: [1,2,3],
|
arr: [1,2,3],
|
||||||
|
@ -44,7 +44,7 @@ test('jsonpatch add: insert in matrix', () => {
|
||||||
{op: 'add', path: '/arr/1', value: 4}
|
{op: 'add', path: '/arr/1', value: 4}
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
arr: [1,4,2,3],
|
arr: [1,4,2,3],
|
||||||
|
@ -66,7 +66,7 @@ test('jsonpatch add: append to matrix', () => {
|
||||||
{op: 'add', path: '/arr/-', value: 4}
|
{op: 'add', path: '/arr/-', value: 4}
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
arr: [1,2,3,4],
|
arr: [1,2,3,4],
|
||||||
|
@ -90,7 +90,7 @@ test('jsonpatch remove', () => {
|
||||||
{op: 'remove', path: '/arr/1'},
|
{op: 'remove', path: '/arr/1'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
arr: [1,3],
|
arr: [1,3],
|
||||||
|
@ -103,7 +103,7 @@ test('jsonpatch remove', () => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const result2 = immutableJsonPatch(result.json, result.revert)
|
const result2 = immutableJSONPatch(result.json, result.revert)
|
||||||
|
|
||||||
expect(result2.json).toEqual(json)
|
expect(result2.json).toEqual(json)
|
||||||
expect(result2.revert).toEqual(patch)
|
expect(result2.revert).toEqual(patch)
|
||||||
|
@ -122,7 +122,7 @@ test('jsonpatch replace', () => {
|
||||||
{op: 'replace', path: '/arr/1', value: 200},
|
{op: 'replace', path: '/arr/1', value: 200},
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
arr: [1,200,3],
|
arr: [1,200,3],
|
||||||
|
@ -135,7 +135,7 @@ test('jsonpatch replace', () => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const result2 = immutableJsonPatch(result.json, result.revert)
|
const result2 = immutableJSONPatch(result.json, result.revert)
|
||||||
|
|
||||||
expect(result2.json).toEqual(json)
|
expect(result2.json).toEqual(json)
|
||||||
expect(result2.revert).toEqual([
|
expect(result2.revert).toEqual([
|
||||||
|
@ -155,7 +155,7 @@ test('jsonpatch copy', () => {
|
||||||
{op: 'copy', from: '/obj', path: '/arr/2'},
|
{op: 'copy', from: '/obj', path: '/arr/2'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
arr: [1, 2, {a:4}, 3],
|
arr: [1, 2, {a:4}, 3],
|
||||||
|
@ -166,7 +166,7 @@ test('jsonpatch copy', () => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const result2 = immutableJsonPatch(result.json, result.revert)
|
const result2 = immutableJSONPatch(result.json, result.revert)
|
||||||
|
|
||||||
expect(result2.json).toEqual(json)
|
expect(result2.json).toEqual(json)
|
||||||
expect(result2.revert).toEqual([
|
expect(result2.revert).toEqual([
|
||||||
|
@ -187,7 +187,7 @@ test('jsonpatch move', () => {
|
||||||
{op: 'move', from: '/obj', path: '/arr/2'},
|
{op: 'move', from: '/obj', path: '/arr/2'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.error).toEqual(null)
|
expect(result.error).toEqual(null)
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
|
@ -199,7 +199,7 @@ test('jsonpatch move', () => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const result2 = immutableJsonPatch(result.json, result.revert)
|
const result2 = immutableJSONPatch(result.json, result.revert)
|
||||||
|
|
||||||
expect(result2.json).toEqual(json)
|
expect(result2.json).toEqual(json)
|
||||||
expect(result2.revert).toEqual(patch)
|
expect(result2.revert).toEqual(patch)
|
||||||
|
@ -214,7 +214,7 @@ test('jsonpatch move and replace', () => {
|
||||||
{op: 'move', from: '/a', path: '/b'},
|
{op: 'move', from: '/a', path: '/b'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({ b : 2 })
|
expect(result.json).toEqual({ b : 2 })
|
||||||
expect(result.revert).toEqual([
|
expect(result.revert).toEqual([
|
||||||
|
@ -223,7 +223,7 @@ test('jsonpatch move and replace', () => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const result2 = immutableJsonPatch(result.json, result.revert)
|
const result2 = immutableJSONPatch(result.json, result.revert)
|
||||||
|
|
||||||
expect(result2.json).toEqual(json)
|
expect(result2.json).toEqual(json)
|
||||||
expect(result2.revert).toEqual([
|
expect(result2.revert).toEqual([
|
||||||
|
@ -243,7 +243,7 @@ test('jsonpatch move and replace (nested)', () => {
|
||||||
{op: 'move', from: '/obj', path: '/arr'},
|
{op: 'move', from: '/obj', path: '/arr'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
arr: {a:4},
|
arr: {a:4},
|
||||||
|
@ -255,7 +255,7 @@ test('jsonpatch move and replace (nested)', () => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const result2 = immutableJsonPatch(result.json, result.revert)
|
const result2 = immutableJSONPatch(result.json, result.revert)
|
||||||
|
|
||||||
expect(result2.json).toEqual(json)
|
expect(result2.json).toEqual(json)
|
||||||
expect(result2.revert).toEqual([
|
expect(result2.revert).toEqual([
|
||||||
|
@ -277,7 +277,7 @@ test('jsonpatch test (ok)', () => {
|
||||||
{op: 'add', path: '/added', value: 'ok'}
|
{op: 'add', path: '/added', value: 'ok'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
arr: [1,2,3],
|
arr: [1,2,3],
|
||||||
|
@ -300,7 +300,7 @@ test('jsonpatch test (fail: path not found)', () => {
|
||||||
{op: 'add', path: '/added', value: 'ok'}
|
{op: 'add', path: '/added', value: 'ok'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
// patch shouldn't be applied
|
// patch shouldn't be applied
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
|
@ -322,7 +322,7 @@ test('jsonpatch test (fail: value not equal)', () => {
|
||||||
{op: 'add', path: '/added', value: 'ok'}
|
{op: 'add', path: '/added', value: 'ok'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const result = immutableJsonPatch(json, patch)
|
const result = immutableJSONPatch(json, patch)
|
||||||
|
|
||||||
// patch shouldn't be applied
|
// patch shouldn't be applied
|
||||||
expect(result.json).toEqual({
|
expect(result.json).toEqual({
|
||||||
|
@ -332,3 +332,41 @@ test('jsonpatch test (fail: value not equal)', () => {
|
||||||
expect(result.revert).toEqual([])
|
expect(result.revert).toEqual([])
|
||||||
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)
|
|
@ -73,6 +73,14 @@
|
||||||
* @typedef {JSONPatchOperation[]} JSONPatchDocument
|
* @typedef {JSONPatchOperation[]} JSONPatchDocument
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* fromJSON: function(json: JSON, previousObject: * | undefined),
|
||||||
|
* toJSON: function(object: *),
|
||||||
|
* clone: function(object: *)
|
||||||
|
* }} JSONPatchOptions
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* op: 'add' | 'remove' | 'replace' | 'copy' | 'move' | 'test',
|
* op: 'add' | 'remove' | 'replace' | 'copy' | 'move' | 'test',
|
||||||
|
|
Loading…
Reference in New Issue