Renamed 'jsonData' to 'ESON'
This commit is contained in:
parent
2ee11399ec
commit
432e169f32
|
@ -1,4 +1,4 @@
|
||||||
import { compileJSONPointer, toDataPath, dataToJson, findNextProp } from './jsonData'
|
import { compileJSONPointer, toEsonPath, esonToJson, findNextProp } from './eson'
|
||||||
import { findUniqueName } from './utils/stringUtils'
|
import { findUniqueName } from './utils/stringUtils'
|
||||||
import { getIn } from './utils/immutabilityHelpers'
|
import { getIn } from './utils/immutabilityHelpers'
|
||||||
import { isObject, stringConvert } from './utils/typeUtils'
|
import { isObject, stringConvert } from './utils/typeUtils'
|
||||||
|
@ -7,7 +7,7 @@ import { compareAsc, compareDesc, strictShallowEqual } from './utils/arrayUtils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a JSONPatch to change the value of a property or item
|
* Create a JSONPatch to change the value of a property or item
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
|
@ -15,8 +15,8 @@ import { compareAsc, compareDesc, strictShallowEqual } from './utils/arrayUtils'
|
||||||
export function changeValue (data, path, value) {
|
export function changeValue (data, path, value) {
|
||||||
// console.log('changeValue', data, value)
|
// console.log('changeValue', data, value)
|
||||||
|
|
||||||
const dataPath = toDataPath(data, path)
|
const esonPath = toEsonPath(data, path)
|
||||||
const oldDataValue = getIn(data, dataPath)
|
const oldDataValue = getIn(data, esonPath)
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
|
@ -30,7 +30,7 @@ export function changeValue (data, path, value) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a JSONPatch to change a property name
|
* Create a JSONPatch to change a property name
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {Path} parentPath
|
* @param {Path} parentPath
|
||||||
* @param {string} oldProp
|
* @param {string} oldProp
|
||||||
* @param {string} newProp
|
* @param {string} newProp
|
||||||
|
@ -39,8 +39,8 @@ export function changeValue (data, path, value) {
|
||||||
export function changeProperty (data, parentPath, oldProp, newProp) {
|
export function changeProperty (data, parentPath, oldProp, newProp) {
|
||||||
// console.log('changeProperty', parentPath, oldProp, newProp)
|
// console.log('changeProperty', parentPath, oldProp, newProp)
|
||||||
|
|
||||||
const dataPath = toDataPath(data, parentPath)
|
const esonPath = toEsonPath(data, parentPath)
|
||||||
const parent = getIn(data, dataPath)
|
const parent = getIn(data, esonPath)
|
||||||
|
|
||||||
// prevent duplicate property names
|
// prevent duplicate property names
|
||||||
const uniqueNewProp = findUniqueName(newProp, parent.props.map(p => p.name))
|
const uniqueNewProp = findUniqueName(newProp, parent.props.map(p => p.name))
|
||||||
|
@ -57,14 +57,14 @@ export function changeProperty (data, parentPath, oldProp, newProp) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a JSONPatch to change the type of a property or item
|
* Create a JSONPatch to change the type of a property or item
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {JSONDataType} type
|
* @param {ESONType} type
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
export function changeType (data, path, type) {
|
export function changeType (data, path, type) {
|
||||||
const dataPath = toDataPath(data, path)
|
const esonPath = toEsonPath(data, path)
|
||||||
const oldValue = dataToJson(getIn(data, dataPath))
|
const oldValue = esonToJson(getIn(data, esonPath))
|
||||||
const newValue = convertType(oldValue, type)
|
const newValue = convertType(oldValue, type)
|
||||||
|
|
||||||
// console.log('changeType', path, type, oldValue, newValue)
|
// console.log('changeType', path, type, oldValue, newValue)
|
||||||
|
@ -86,7 +86,7 @@ export function changeType (data, path, type) {
|
||||||
* a unique property name for the duplicated node in case of duplicating
|
* a unique property name for the duplicated node in case of duplicating
|
||||||
* and object property
|
* and object property
|
||||||
*
|
*
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
|
@ -95,8 +95,8 @@ export function duplicate (data, path) {
|
||||||
|
|
||||||
const parentPath = path.slice(0, path.length - 1)
|
const parentPath = path.slice(0, path.length - 1)
|
||||||
|
|
||||||
const dataPath = toDataPath(data, parentPath)
|
const esonPath = toEsonPath(data, parentPath)
|
||||||
const parent = getIn(data, dataPath)
|
const parent = getIn(data, esonPath)
|
||||||
|
|
||||||
if (parent.type === 'Array') {
|
if (parent.type === 'Array') {
|
||||||
const index = parseInt(path[path.length - 1]) + 1
|
const index = parseInt(path[path.length - 1]) + 1
|
||||||
|
@ -128,17 +128,17 @@ export function duplicate (data, path) {
|
||||||
* a unique property name for the inserted node in case of duplicating
|
* a unique property name for the inserted node in case of duplicating
|
||||||
* and object property
|
* and object property
|
||||||
*
|
*
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {JSONDataType} type
|
* @param {ESONType} type
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
export function insert (data, path, type) {
|
export function insert (data, path, type) {
|
||||||
// console.log('insert', path, type)
|
// console.log('insert', path, type)
|
||||||
|
|
||||||
const parentPath = path.slice(0, path.length - 1)
|
const parentPath = path.slice(0, path.length - 1)
|
||||||
const dataPath = toDataPath(data, parentPath)
|
const esonPath = toEsonPath(data, parentPath)
|
||||||
const parent = getIn(data, dataPath)
|
const parent = getIn(data, esonPath)
|
||||||
const value = createEntry(type)
|
const value = createEntry(type)
|
||||||
|
|
||||||
if (parent.type === 'Array') {
|
if (parent.type === 'Array') {
|
||||||
|
@ -175,16 +175,16 @@ export function insert (data, path, type) {
|
||||||
* a unique property name for the inserted node in case of duplicating
|
* a unique property name for the inserted node in case of duplicating
|
||||||
* and object property
|
* and object property
|
||||||
*
|
*
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {Path} parentPath
|
* @param {Path} parentPath
|
||||||
* @param {JSONDataType} type
|
* @param {ESONType} type
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
export function append (data, parentPath, type) {
|
export function append (data, parentPath, type) {
|
||||||
// console.log('append', parentPath, value)
|
// console.log('append', parentPath, value)
|
||||||
|
|
||||||
const dataPath = toDataPath(data, parentPath)
|
const esonPath = toEsonPath(data, parentPath)
|
||||||
const parent = getIn(data, dataPath)
|
const parent = getIn(data, esonPath)
|
||||||
const value = createEntry(type)
|
const value = createEntry(type)
|
||||||
|
|
||||||
if (parent.type === 'Array') {
|
if (parent.type === 'Array') {
|
||||||
|
@ -225,7 +225,7 @@ export function remove (path) {
|
||||||
/**
|
/**
|
||||||
* Create a JSONPatch to order the items of an array or the properties of an object in ascending
|
* Create a JSONPatch to order the items of an array or the properties of an object in ascending
|
||||||
* or descending order
|
* or descending order
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {'asc' | 'desc' | null} [order=null] If not provided, will toggle current ordering
|
* @param {'asc' | 'desc' | null} [order=null] If not provided, will toggle current ordering
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
|
@ -234,8 +234,8 @@ export function sort (data, path, order = null) {
|
||||||
// console.log('sort', path, order)
|
// console.log('sort', path, order)
|
||||||
|
|
||||||
const compare = order === 'desc' ? compareDesc : compareAsc
|
const compare = order === 'desc' ? compareDesc : compareAsc
|
||||||
const dataPath = toDataPath(data, path)
|
const esonPath = toEsonPath(data, path)
|
||||||
const object = getIn(data, dataPath)
|
const object = getIn(data, esonPath)
|
||||||
|
|
||||||
if (object.type === 'Array') {
|
if (object.type === 'Array') {
|
||||||
const orderedItems = object.items.slice(0)
|
const orderedItems = object.items.slice(0)
|
||||||
|
@ -252,7 +252,7 @@ export function sort (data, path, order = null) {
|
||||||
return [{
|
return [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
path: compileJSONPointer(path),
|
path: compileJSONPointer(path),
|
||||||
value: dataToJson({
|
value: esonToJson({
|
||||||
type: 'Array',
|
type: 'Array',
|
||||||
items: orderedItems
|
items: orderedItems
|
||||||
})
|
})
|
||||||
|
@ -273,7 +273,7 @@ export function sort (data, path, order = null) {
|
||||||
return [{
|
return [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
path: compileJSONPointer(path),
|
path: compileJSONPointer(path),
|
||||||
value: dataToJson({
|
value: esonToJson({
|
||||||
type: 'Object',
|
type: 'Object',
|
||||||
props: orderedProps
|
props: orderedProps
|
||||||
}),
|
}),
|
||||||
|
@ -286,7 +286,7 @@ export function sort (data, path, order = null) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a JSON entry
|
* Create a JSON entry
|
||||||
* @param {JSONDataType} type
|
* @param {ESONType} type
|
||||||
* @return {Array | Object | string}
|
* @return {Array | Object | string}
|
||||||
*/
|
*/
|
||||||
export function createEntry (type) {
|
export function createEntry (type) {
|
||||||
|
@ -304,7 +304,7 @@ export function createEntry (type) {
|
||||||
/**
|
/**
|
||||||
* Convert a JSON object into a different type. When possible, data is retained
|
* Convert a JSON object into a different type. When possible, data is retained
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
* @param {JSONDataType} type
|
* @param {ESONType} type
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
export function convertType (value, type) {
|
export function convertType (value, type) {
|
||||||
|
|
|
@ -6,9 +6,9 @@ import ActionMenu from './menu/ActionMenu'
|
||||||
import { escapeHTML, unescapeHTML } from '../utils/stringUtils'
|
import { escapeHTML, unescapeHTML } from '../utils/stringUtils'
|
||||||
import { getInnerText, insideRect, findParentWithAttribute } from '../utils/domUtils'
|
import { getInnerText, insideRect, findParentWithAttribute } from '../utils/domUtils'
|
||||||
import { stringConvert, valueType, isUrl } from '../utils/typeUtils'
|
import { stringConvert, valueType, isUrl } from '../utils/typeUtils'
|
||||||
import { compileJSONPointer } from '../jsonData'
|
import { compileJSONPointer } from '../eson'
|
||||||
|
|
||||||
import type { PropertyData, JSONData, SearchResultStatus, Path } from '../types'
|
import type { ESONObjectProperty, ESON, SearchResultStatus, Path } from '../types'
|
||||||
|
|
||||||
export default class JSONNode extends Component {
|
export default class JSONNode extends Component {
|
||||||
static URL_TITLE = 'Ctrl+Click or Ctrl+Enter to open url'
|
static URL_TITLE = 'Ctrl+Click or Ctrl+Enter to open url'
|
||||||
|
@ -165,7 +165,7 @@ export default class JSONNode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: simplify the method renderProperty
|
// TODO: simplify the method renderProperty
|
||||||
renderProperty (prop?: PropertyData, index?: number, data: JSONData, options: {escapeUnicode: boolean, isPropertyEditable: (Path) => boolean}) {
|
renderProperty (prop?: ESONObjectProperty, index?: number, data: ESON, options: {escapeUnicode: boolean, isPropertyEditable: (Path) => boolean}) {
|
||||||
const isIndex = typeof index === 'number'
|
const isIndex = typeof index === 'number'
|
||||||
|
|
||||||
if (!prop && !isIndex) {
|
if (!prop && !isIndex) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import JSONNode from './JSONNode'
|
import JSONNode from './JSONNode'
|
||||||
|
|
||||||
import type { PropertyData, JSONData, Path } from '../types'
|
import type { ESONObjectProperty, ESON, Path } from '../types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSONNodeForm
|
* JSONNodeForm
|
||||||
|
@ -22,7 +22,7 @@ export default class JSONNodeForm extends JSONNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// render a readonly property
|
// render a readonly property
|
||||||
renderProperty (prop?: PropertyData, index?: number, data: JSONData, options: {escapeUnicode: boolean, isPropertyEditable: (Path) => boolean}) {
|
renderProperty (prop?: ESONObjectProperty, index?: number, data: ESON, options: {escapeUnicode: boolean, isPropertyEditable: (Path) => boolean}) {
|
||||||
const formOptions = Object.assign({}, options, { isPropertyEditable })
|
const formOptions = Object.assign({}, options, { isPropertyEditable })
|
||||||
|
|
||||||
return JSONNode.prototype.renderProperty.call(this, prop, index, data, formOptions)
|
return JSONNode.prototype.renderProperty.call(this, prop, index, data, formOptions)
|
||||||
|
|
|
@ -5,8 +5,8 @@ import Ajv from 'ajv'
|
||||||
import { parseJSON } from '../utils/jsonUtils'
|
import { parseJSON } from '../utils/jsonUtils'
|
||||||
import { escapeUnicodeChars } from '../utils/stringUtils'
|
import { escapeUnicodeChars } from '../utils/stringUtils'
|
||||||
import { enrichSchemaError, limitErrors } from '../utils/schemaUtils'
|
import { enrichSchemaError, limitErrors } from '../utils/schemaUtils'
|
||||||
import { jsonToData, dataToJson } from '../jsonData'
|
import { jsonToEson, esonToJson } from '../eson'
|
||||||
import { patchData } from '../jsonPatchData'
|
import { patchEson } from '../patchEson'
|
||||||
import { createFindKeyBinding } from '../utils/keyBindings'
|
import { createFindKeyBinding } from '../utils/keyBindings'
|
||||||
import { KEY_BINDINGS } from '../constants'
|
import { KEY_BINDINGS } from '../constants'
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ export default class TextMode extends Component {
|
||||||
// this is an ajv error message
|
// this is an ajv error message
|
||||||
return h('tr', { key: index }, [
|
return h('tr', { key: index }, [
|
||||||
h('td', {key: 'icon'}, icon),
|
h('td', {key: 'icon'}, icon),
|
||||||
h('td', {key: 'path'}, error.dataPath),
|
h('td', {key: 'path'}, error.esonPath),
|
||||||
h('td', {key: 'message'}, error.message)
|
h('td', {key: 'message'}, error.message)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -327,17 +327,17 @@ export default class TextMode extends Component {
|
||||||
/**
|
/**
|
||||||
* Apply a JSONPatch to the current JSON document
|
* Apply a JSONPatch to the current JSON document
|
||||||
* @param {JSONPatch} actions JSONPatch actions
|
* @param {JSONPatch} actions JSONPatch actions
|
||||||
* @return {JSONPatchResult} Returns a JSONPatch result containing the
|
* @return {ESONPatchAction} Returns a JSONPatch result containing the
|
||||||
* patch, a patch to revert the action, and
|
* patch, a patch to revert the action, and
|
||||||
* an error object which is null when successful
|
* an error object which is null when successful
|
||||||
*/
|
*/
|
||||||
patch (actions) {
|
patch (actions) {
|
||||||
const json = this.get()
|
const json = this.get()
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, actions)
|
const result = patchEson(data, actions)
|
||||||
|
|
||||||
this.set(dataToJson(result.data))
|
this.set(esonToJson(result.data))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
patch: actions,
|
patch: actions,
|
||||||
|
|
|
@ -9,12 +9,12 @@ import { parseJSON } from '../utils/jsonUtils'
|
||||||
import { allButLast } from '../utils/arrayUtils'
|
import { allButLast } from '../utils/arrayUtils'
|
||||||
import { enrichSchemaError } from '../utils/schemaUtils'
|
import { enrichSchemaError } from '../utils/schemaUtils'
|
||||||
import {
|
import {
|
||||||
jsonToData, dataToJson, toDataPath, pathExists,
|
jsonToEson, esonToJson, toEsonPath, pathExists,
|
||||||
expand, expandPath, addErrors,
|
expand, expandPath, addErrors,
|
||||||
search, addSearchResults, nextSearchResult, previousSearchResult,
|
search, addSearchResults, nextSearchResult, previousSearchResult,
|
||||||
compileJSONPointer
|
compileJSONPointer
|
||||||
} from '../jsonData'
|
} from '../eson'
|
||||||
import { patchData } from '../jsonPatchData'
|
import { patchEson } from '../patchEson'
|
||||||
import {
|
import {
|
||||||
duplicate, insert, append, remove,
|
duplicate, insert, append, remove,
|
||||||
changeType, changeValue, changeProperty, sort
|
changeType, changeValue, changeProperty, sort
|
||||||
|
@ -31,7 +31,7 @@ import {
|
||||||
import { createFindKeyBinding } from '../utils/keyBindings'
|
import { createFindKeyBinding } from '../utils/keyBindings'
|
||||||
import { KEY_BINDINGS } from '../constants'
|
import { KEY_BINDINGS } from '../constants'
|
||||||
|
|
||||||
import type { JSONData, JSONPatch } from '../types'
|
import type { ESON, ESONPatch } from '../types'
|
||||||
|
|
||||||
const AJV_OPTIONS = {
|
const AJV_OPTIONS = {
|
||||||
allErrors: true,
|
allErrors: true,
|
||||||
|
@ -64,7 +64,7 @@ export default class TreeMode extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
const data = jsonToData(this.props.data || {}, TreeMode.expandAll, [])
|
const data = jsonToEson(this.props.data || {}, TreeMode.expandAll, [])
|
||||||
|
|
||||||
this.id = Math.round(Math.random() * 1e5) // TODO: create a uuid here?
|
this.id = Math.round(Math.random() * 1e5) // TODO: create a uuid here?
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ export default class TreeMode extends Component {
|
||||||
*/
|
*/
|
||||||
getErrors () {
|
getErrors () {
|
||||||
if (this.state.compiledSchema) {
|
if (this.state.compiledSchema) {
|
||||||
const valid = this.state.compiledSchema(dataToJson(this.state.data))
|
const valid = this.state.compiledSchema(esonToJson(this.state.data))
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
return this.state.compiledSchema.errors.map(enrichSchemaError)
|
return this.state.compiledSchema.errors.map(enrichSchemaError)
|
||||||
}
|
}
|
||||||
|
@ -364,10 +364,10 @@ export default class TreeMode extends Component {
|
||||||
/** @private */
|
/** @private */
|
||||||
handleExpand = (path, expanded, recurse) => {
|
handleExpand = (path, expanded, recurse) => {
|
||||||
if (recurse) {
|
if (recurse) {
|
||||||
const dataPath = toDataPath(this.state.data, path)
|
const esonPath = toEsonPath(this.state.data, path)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: updateIn(this.state.data, dataPath, function (child) {
|
data: updateIn(this.state.data, esonPath, function (child) {
|
||||||
return expand(child, (path) => true, expanded)
|
return expand(child, (path) => true, expanded)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -474,8 +474,8 @@ export default class TreeMode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a JSONPatch to the current JSON document and emit a change event
|
* Apply a ESONPatch to the current JSON document and emit a change event
|
||||||
* @param {JSONPatch} actions
|
* @param {ESONPatch} actions
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handlePatch = (actions) => {
|
handlePatch = (actions) => {
|
||||||
|
@ -504,13 +504,13 @@ export default class TreeMode extends Component {
|
||||||
* Emit an onChange event when there is a listener for it.
|
* Emit an onChange event when there is a listener for it.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
emitOnChange (patch: JSONPatch, revert: JSONPatch, data: JSONData) {
|
emitOnChange (patch: ESONPatch, revert: ESONPatch, data: ESON) {
|
||||||
if (this.props.onPatch) {
|
if (this.props.onPatch) {
|
||||||
this.props.onPatch(patch, revert)
|
this.props.onPatch(patch, revert)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.onChange || this.props.onChangeText) {
|
if (this.props.onChange || this.props.onChangeText) {
|
||||||
const json = dataToJson(data)
|
const json = esonToJson(data)
|
||||||
|
|
||||||
if (this.props.onChange) {
|
if (this.props.onChange) {
|
||||||
this.props.onChange(json)
|
this.props.onChange(json)
|
||||||
|
@ -539,7 +539,7 @@ export default class TreeMode extends Component {
|
||||||
const historyIndex = this.state.historyIndex
|
const historyIndex = this.state.historyIndex
|
||||||
const historyItem = history[historyIndex]
|
const historyItem = history[historyIndex]
|
||||||
|
|
||||||
const result = patchData(this.state.data, historyItem.undo)
|
const result = patchEson(this.state.data, historyItem.undo)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: result.data,
|
data: result.data,
|
||||||
|
@ -557,7 +557,7 @@ export default class TreeMode extends Component {
|
||||||
const historyIndex = this.state.historyIndex - 1
|
const historyIndex = this.state.historyIndex - 1
|
||||||
const historyItem = history[historyIndex]
|
const historyItem = history[historyIndex]
|
||||||
|
|
||||||
const result = patchData(this.state.data, historyItem.redo)
|
const result = patchEson(this.state.data, historyItem.redo)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: result.data,
|
data: result.data,
|
||||||
|
@ -570,13 +570,13 @@ export default class TreeMode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a JSONPatch to the current JSON document
|
* Apply a ESONPatch to the current JSON document
|
||||||
* @param {JSONPatch} actions JSONPatch actions
|
* @param {ESONPatch} actions ESONPatch actions
|
||||||
* @param {PatchOptions} [options] If no expand function is provided, the
|
* @param {ESONPatchOptions} [options] If no expand function is provided, the
|
||||||
* expanded state will be kept as is for
|
* expanded state will be kept as is for
|
||||||
* existing paths. New paths will be fully
|
* existing paths. New paths will be fully
|
||||||
* expanded.
|
* expanded.
|
||||||
* @return {JSONPatchResult} Returns a JSONPatch result containing the
|
* @return {ESONPatchAction} Returns a ESONPatch result containing the
|
||||||
* patch, a patch to revert the action, and
|
* patch, a patch to revert the action, and
|
||||||
* an error object which is null when successful
|
* an error object which is null when successful
|
||||||
*/
|
*/
|
||||||
|
@ -586,7 +586,7 @@ export default class TreeMode extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
const expand = options.expand || (path => this.expandKeepOrExpandAll(path))
|
const expand = options.expand || (path => this.expandKeepOrExpandAll(path))
|
||||||
const result = patchData(this.state.data, actions, expand)
|
const result = patchEson(this.state.data, actions, expand)
|
||||||
const data = result.data
|
const data = result.data
|
||||||
|
|
||||||
if (this.props.history != false) {
|
if (this.props.history != false) {
|
||||||
|
@ -629,7 +629,7 @@ export default class TreeMode extends Component {
|
||||||
const expand = this.props.expand || TreeMode.expandRoot
|
const expand = this.props.expand || TreeMode.expandRoot
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: jsonToData(json, expand, []),
|
data: jsonToEson(json, expand, []),
|
||||||
|
|
||||||
// TODO: do we want to keep history when .set(json) is called? (currently we remove history)
|
// TODO: do we want to keep history when .set(json) is called? (currently we remove history)
|
||||||
history: [],
|
history: [],
|
||||||
|
@ -642,7 +642,7 @@ export default class TreeMode extends Component {
|
||||||
* @returns {Object | Array | string | number | boolean | null} json
|
* @returns {Object | Array | string | number | boolean | null} json
|
||||||
*/
|
*/
|
||||||
get () {
|
get () {
|
||||||
return dataToJson(this.state.data)
|
return esonToJson(this.state.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -723,7 +723,7 @@ export default class TreeMode extends Component {
|
||||||
* @return {boolean} Returns true when expanded, false otherwise
|
* @return {boolean} Returns true when expanded, false otherwise
|
||||||
*/
|
*/
|
||||||
isExpanded (path) {
|
isExpanded (path) {
|
||||||
return getIn(this.state.data, toDataPath(this.state.data, path)).expanded
|
return getIn(this.state.data, toEsonPath(this.state.data, path)).expanded
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {
|
||||||
selectContentEditable, hasClassName,
|
selectContentEditable, hasClassName,
|
||||||
findParentWithAttribute, findParentWithClassName
|
findParentWithAttribute, findParentWithClassName
|
||||||
} from '../../utils/domUtils'
|
} from '../../utils/domUtils'
|
||||||
import { compileJSONPointer, parseJSONPointer } from '../../jsonData'
|
import { compileJSONPointer, parseJSONPointer } from '../../eson'
|
||||||
|
|
||||||
// singleton
|
// singleton
|
||||||
let lastInputName = null
|
let lastInputName = null
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// @flow weak
|
// @flow weak
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file contains functions to act on a JSONData object.
|
* This file contains functions to act on a ESON object.
|
||||||
* All functions are pure and don't mutate the JSONData.
|
* All functions are pure and don't mutate the ESON.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { setIn, getIn } from './utils/immutabilityHelpers'
|
import { setIn, getIn } from './utils/immutabilityHelpers'
|
||||||
|
@ -10,9 +10,13 @@ import { isObject } from './utils/typeUtils'
|
||||||
import { last, allButLast } from './utils/arrayUtils'
|
import { last, allButLast } from './utils/arrayUtils'
|
||||||
import isEqual from 'lodash/isEqual'
|
import isEqual from 'lodash/isEqual'
|
||||||
|
|
||||||
import type { JSONData, ObjectData, ItemData, DataPointer, Path } from './types'
|
import type {
|
||||||
|
ESON, ESONObject, ESONArrayItem, ESONPointer, ESONType, ESONPath,
|
||||||
|
Path,
|
||||||
|
JSONPath, JSONType
|
||||||
|
} from './types'
|
||||||
|
|
||||||
type RecurseCallback = (value: JSONData, path: Path, root: JSONData) => JSONData
|
type RecurseCallback = (value: ESON, path: Path, root: ESON) => ESON
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand function which will expand all nodes
|
* Expand function which will expand all nodes
|
||||||
|
@ -24,14 +28,14 @@ export function expandAll (path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a JSON object into the internally used data model
|
* Convert a JSON object into ESON
|
||||||
* @param {Object | Array | string | number | boolean | null} json
|
* @param {Object | Array | string | number | boolean | null} json
|
||||||
* @param {function(path: Path)} [expand]
|
* @param {function(path: JSONPath)} [expand]
|
||||||
* @param {Path} [path=[]]
|
* @param {JSONPath} [path=[]]
|
||||||
* @param {JSONDataType} [type='value'] Optional json data type for the created value
|
* @param {ESONType} [type='value'] Optional eson type for the created value
|
||||||
* @return {JSONData}
|
* @return {ESON}
|
||||||
*/
|
*/
|
||||||
export function jsonToData (json, expand = expandAll, path = [], type = 'value') : JSONData {
|
export function jsonToEson (json, expand = expandAll, path: JSONPath = [], type: ESONType = 'value') : ESON {
|
||||||
if (Array.isArray(json)) {
|
if (Array.isArray(json)) {
|
||||||
return {
|
return {
|
||||||
type: 'Array',
|
type: 'Array',
|
||||||
|
@ -39,7 +43,7 @@ export function jsonToData (json, expand = expandAll, path = [], type = 'value')
|
||||||
items: json.map((child, index) => {
|
items: json.map((child, index) => {
|
||||||
return {
|
return {
|
||||||
id: getId(), // TODO: use id based on index (only has to be unique within this array)
|
id: getId(), // TODO: use id based on index (only has to be unique within this array)
|
||||||
value: jsonToData(child, expand, path.concat(index))
|
value: jsonToEson(child, expand, path.concat(index))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -52,75 +56,75 @@ export function jsonToData (json, expand = expandAll, path = [], type = 'value')
|
||||||
return {
|
return {
|
||||||
id: getId(), // TODO: use id based on index (only has to be unique within this array)
|
id: getId(), // TODO: use id based on index (only has to be unique within this array)
|
||||||
name,
|
name,
|
||||||
value: jsonToData(json[name], expand, path.concat(name))
|
value: jsonToEson(json[name], expand, path.concat(name))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // value
|
else { // value
|
||||||
return {
|
return {
|
||||||
type,
|
type: (type === 'string') ? 'string' : 'value',
|
||||||
value: json
|
value: json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the internal data model to a regular JSON object
|
* Convert an ESON object to a JSON object
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @return {Object | Array | string | number | boolean | null} json
|
* @return {Object | Array | string | number | boolean | null} json
|
||||||
*/
|
*/
|
||||||
export function dataToJson (data: JSONData) {
|
export function esonToJson (eson: ESON) {
|
||||||
switch (data.type) {
|
switch (eson.type) {
|
||||||
case 'Array':
|
case 'Array':
|
||||||
return data.items.map(item => dataToJson(item.value))
|
return eson.items.map(item => esonToJson(item.value))
|
||||||
|
|
||||||
case 'Object':
|
case 'Object':
|
||||||
const object = {}
|
const object = {}
|
||||||
|
|
||||||
data.props.forEach(prop => {
|
eson.props.forEach(prop => {
|
||||||
object[prop.name] = dataToJson(prop.value)
|
object[prop.name] = esonToJson(prop.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
return object
|
return object
|
||||||
|
|
||||||
default: // type 'string' or 'value'
|
default: // type 'string' or 'value'
|
||||||
return data.value
|
return eson.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a path of a JSON object into a path in the corresponding data model
|
* Convert a path of a JSON object into a path in the corresponding ESON object
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @param {Path} path
|
* @param {JSONPath} path
|
||||||
* @return {Path} dataPath
|
* @return {ESONPath} esonPath
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function toDataPath (data: JSONData, path: Path) : Path {
|
export function toEsonPath (eson: ESON, path: JSONPath) : ESONPath {
|
||||||
if (path.length === 0) {
|
if (path.length === 0) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.type === 'Array') {
|
if (eson.type === 'Array') {
|
||||||
// index of an array
|
// index of an array
|
||||||
const index = path[0]
|
const index = path[0]
|
||||||
const item = data.items[parseInt(index)]
|
const item = eson.items[parseInt(index)]
|
||||||
if (!item) {
|
if (!item) {
|
||||||
throw new Error('Array item "' + index + '" not found')
|
throw new Error('Array item "' + index + '" not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['items', index, 'value'].concat(toDataPath(item.value, path.slice(1)))
|
return ['items', index, 'value'].concat(toEsonPath(item.value, path.slice(1)))
|
||||||
}
|
}
|
||||||
else if (data.type === 'Object') {
|
else if (eson.type === 'Object') {
|
||||||
// object property. find the index of this property
|
// object property. find the index of this property
|
||||||
const index = findPropertyIndex(data, path[0])
|
const index = findPropertyIndex(eson, path[0])
|
||||||
const prop = data.props[index]
|
const prop = eson.props[index]
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
throw new Error('Object property "' + path[0] + '" not found')
|
throw new Error('Object property "' + path[0] + '" not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['props', index, 'value']
|
return ['props', index, 'value']
|
||||||
.concat(toDataPath(prop.value, path.slice(1)))
|
.concat(toEsonPath(prop.value, path.slice(1)))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return []
|
return []
|
||||||
|
@ -131,19 +135,19 @@ type ExpandCallback = (Path) => boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand or collapse one or multiple items or properties
|
* Expand or collapse one or multiple items or properties
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @param {function(path: Path) : boolean | Path} callback
|
* @param {function(path: Path) : boolean | Path} callback
|
||||||
* When a path, the object/array at this path will be expanded/collapsed
|
* When a path, the object/array at this path will be expanded/collapsed
|
||||||
* When a function, all objects and arrays for which callback
|
* When a function, all objects and arrays for which callback
|
||||||
* returns true will be expanded/collapsed
|
* returns true will be expanded/collapsed
|
||||||
* @param {boolean} [expanded=true] New expanded state: true to expand, false to collapse
|
* @param {boolean} [expanded=true] New expanded state: true to expand, false to collapse
|
||||||
* @return {JSONData}
|
* @return {ESON}
|
||||||
*/
|
*/
|
||||||
export function expand (data: JSONData, callback: Path | (Path) => boolean, expanded: boolean = true) {
|
export function expand (eson: ESON, callback: Path | (Path) => boolean, expanded: boolean = true) {
|
||||||
// console.log('expand', callback, expand)
|
// console.log('expand', callback, expand)
|
||||||
|
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
return transform(data, function (value: JSONData, path: Path, root: JSONData) : JSONData {
|
return transform(eson, function (value: ESON, path: Path, root: ESON) : ESON {
|
||||||
if (value.type === 'Array' || value.type === 'Object') {
|
if (value.type === 'Array' || value.type === 'Object') {
|
||||||
if (callback(path)) {
|
if (callback(path)) {
|
||||||
return setIn(value, ['expanded'], expanded)
|
return setIn(value, ['expanded'], expanded)
|
||||||
|
@ -154,9 +158,9 @@ export function expand (data: JSONData, callback: Path | (Path) => boolean, expa
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else if (Array.isArray(callback)) {
|
else if (Array.isArray(callback)) {
|
||||||
const dataPath: Path = toDataPath(data, callback)
|
const esonPath: Path = toEsonPath(eson, callback)
|
||||||
|
|
||||||
return setIn(data, dataPath.concat(['expanded']), expanded)
|
return setIn(eson, esonPath.concat(['expanded']), expanded)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error('Callback function or path expected')
|
throw new Error('Callback function or path expected')
|
||||||
|
@ -166,50 +170,49 @@ export function expand (data: JSONData, callback: Path | (Path) => boolean, expa
|
||||||
/**
|
/**
|
||||||
* Expand all Objects and Arrays on a path
|
* Expand all Objects and Arrays on a path
|
||||||
*/
|
*/
|
||||||
export function expandPath (data: JSONData, path?: Path) : JSONData {
|
export function expandPath (eson: ESON, path?: JSONPath) : ESON {
|
||||||
let updatedData = data
|
let updatedEson = eson
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
updatedData = expand(updatedData, [], true) // expand root
|
updatedEson = expand(updatedEson, [], true) // expand root
|
||||||
|
|
||||||
for (let i = 0; i < path.length; i++) {
|
for (let i = 0; i < path.length; i++) {
|
||||||
const pathPart = path.slice(0, i + 1)
|
const pathPart = path.slice(0, i + 1)
|
||||||
updatedData = expand(updatedData, pathPart, true)
|
updatedEson = expand(updatedEson, pathPart, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return updatedData
|
return updatedEson
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge one or multiple errors (for example JSON schema errors)
|
* Merge one or multiple errors (for example JSON schema errors) into the ESON object
|
||||||
* into the data
|
|
||||||
*
|
*
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @param {JSONSchemaError[]} errors
|
* @param {JSONSchemaError[]} errors
|
||||||
*/
|
*/
|
||||||
export function addErrors (data: JSONData, errors) {
|
export function addErrors (eson: ESON, errors) {
|
||||||
let updatedData = data
|
let updatedEson = eson
|
||||||
|
|
||||||
if (errors) {
|
if (errors) {
|
||||||
errors.forEach(error => {
|
errors.forEach(error => {
|
||||||
const dataPath = toDataPath(data, parseJSONPointer(error.dataPath))
|
const esonPath = toEsonPath(eson, parseJSONPointer(error.esonPath))
|
||||||
// TODO: do we want to be able to store multiple errors per item?
|
// TODO: do we want to be able to store multiple errors per item?
|
||||||
updatedData = setIn(updatedData, dataPath.concat('error'), error)
|
updatedEson = setIn(updatedEson, esonPath.concat('error'), error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return updatedData
|
return updatedEson
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search some text in all properties and values
|
* Search some text in all properties and values
|
||||||
*/
|
*/
|
||||||
export function search (data: JSONData, text: string): DataPointer[] {
|
export function search (eson: ESON, text: string): ESONPointer[] {
|
||||||
let results: DataPointer[] = []
|
let results: ESONPointer[] = []
|
||||||
|
|
||||||
if (text !== '') {
|
if (text !== '') {
|
||||||
traverse(data, function (value, path) {
|
traverse(eson, function (value, path: JSONPath) {
|
||||||
// check property name
|
// check property name
|
||||||
if (path.length > 0) {
|
if (path.length > 0) {
|
||||||
const prop = last(path)
|
const prop = last(path)
|
||||||
|
@ -217,7 +220,7 @@ export function search (data: JSONData, text: string): DataPointer[] {
|
||||||
// only add search result when this is an object property name,
|
// only add search result when this is an object property name,
|
||||||
// don't add search result for array indices
|
// don't add search result for array indices
|
||||||
const parentPath = allButLast(path)
|
const parentPath = allButLast(path)
|
||||||
const parent = getIn(data, toDataPath(data, parentPath))
|
const parent = getIn(eson, toEsonPath(eson, parentPath))
|
||||||
if (parent.type === 'Object') {
|
if (parent.type === 'Object') {
|
||||||
results.push({path, type: 'property'})
|
results.push({path, type: 'property'})
|
||||||
}
|
}
|
||||||
|
@ -244,7 +247,7 @@ export function search (data: JSONData, text: string): DataPointer[] {
|
||||||
* returned as next
|
* returned as next
|
||||||
* - When `searchResults` is empty, null will be returned
|
* - When `searchResults` is empty, null will be returned
|
||||||
*/
|
*/
|
||||||
export function nextSearchResult (searchResults: DataPointer[], current: DataPointer): DataPointer | null {
|
export function nextSearchResult (searchResults: ESONPointer[], current: ESONPointer): ESONPointer | null {
|
||||||
if (searchResults.length === 0) {
|
if (searchResults.length === 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -268,7 +271,7 @@ export function nextSearchResult (searchResults: DataPointer[], current: DataPoi
|
||||||
* returned as next
|
* returned as next
|
||||||
* - When `searchResults` is empty, null will be returned
|
* - When `searchResults` is empty, null will be returned
|
||||||
*/
|
*/
|
||||||
export function previousSearchResult (searchResults: DataPointer[], current: DataPointer): DataPointer | null {
|
export function previousSearchResult (searchResults: ESONPointer[], current: ESONPointer): ESONPointer | null {
|
||||||
if (searchResults.length === 0) {
|
if (searchResults.length === 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -285,27 +288,27 @@ export function previousSearchResult (searchResults: DataPointer[], current: Dat
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge searchResults into the data
|
* Merge searchResults into the eson object
|
||||||
*/
|
*/
|
||||||
export function addSearchResults (data: JSONData, searchResults: DataPointer[], activeSearchResult: DataPointer) {
|
export function addSearchResults (eson: ESON, searchResults: ESONPointer[], activeSearchResult: ESONPointer) {
|
||||||
let updatedData = data
|
let updatedEson = eson
|
||||||
|
|
||||||
searchResults.forEach(function (searchResult) {
|
searchResults.forEach(function (searchResult) {
|
||||||
if (searchResult.type === 'value') {
|
if (searchResult.type === 'value') {
|
||||||
const dataPath = toDataPath(data, searchResult.path).concat('searchResult')
|
const esonPath = toEsonPath(updatedEson, searchResult.path).concat('searchResult')
|
||||||
const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal'
|
const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal'
|
||||||
updatedData = setIn(updatedData, dataPath, value)
|
updatedEson = setIn(updatedEson, esonPath, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchResult.type === 'property') {
|
if (searchResult.type === 'property') {
|
||||||
const valueDataPath = toDataPath(data, searchResult.path)
|
const esonPath = toEsonPath(updatedEson, searchResult.path)
|
||||||
const propertyDataPath = allButLast(valueDataPath).concat('searchResult')
|
const propertyPath = allButLast(esonPath).concat('searchResult')
|
||||||
const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal'
|
const value = isEqual(searchResult, activeSearchResult) ? 'active' : 'normal'
|
||||||
updatedData = setIn(updatedData, propertyDataPath, value)
|
updatedEson = setIn(updatedEson, propertyPath, value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return updatedData
|
return updatedEson
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -319,25 +322,25 @@ export function containsCaseInsensitive (text: string, search: string): boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively transform JSONData: a recursive "map" function
|
* Recursively transform ESON: a recursive "map" function
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @param {function(value: JSONData, path: Path, root: JSONData)} callback
|
* @param {function(value: ESON, path: Path, root: ESON)} callback
|
||||||
* @return {JSONData} Returns the transformed data
|
* @return {ESON} Returns the transformed eson object
|
||||||
*/
|
*/
|
||||||
export function transform (data: JSONData, callback: RecurseCallback) {
|
export function transform (eson: ESON, callback: RecurseCallback) : ESON {
|
||||||
return recurseTransform (data, [], data, callback)
|
return recurseTransform (eson, [], eson, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively transform JSONData
|
* Recursively transform ESON
|
||||||
* @param {JSONData} value
|
* @param {ESON} value
|
||||||
* @param {Path} path
|
* @param {JSONPath} path
|
||||||
* @param {JSONData} root The root object, object at path=[]
|
* @param {ESON} root The root object, object at path=[]
|
||||||
* @param {function(value: JSONData, path: Path, root: JSONData)} callback
|
* @param {function(value: ESON, path: Path, root: ESON)} callback
|
||||||
* @return {JSONData} Returns the transformed data
|
* @return {ESON} Returns the transformed eson object
|
||||||
*/
|
*/
|
||||||
function recurseTransform (value: JSONData, path: Path, root: JSONData, callback: RecurseCallback) : JSONData {
|
function recurseTransform (value: ESON, path: JSONPath, root: ESON, callback: RecurseCallback) : ESON {
|
||||||
let updatedValue = callback(value, path, root)
|
let updatedValue: ESON = callback(value, path, root)
|
||||||
|
|
||||||
if (value.type === 'Array') {
|
if (value.type === 'Array') {
|
||||||
let updatedItems = updatedValue.items
|
let updatedItems = updatedValue.items
|
||||||
|
@ -367,27 +370,27 @@ function recurseTransform (value: JSONData, path: Path, root: JSONData, callback
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively loop over a JSONData object: a recursive "forEach" function.
|
* Recursively loop over a ESON object: a recursive "forEach" function.
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @param {function(value: JSONData, path: Path, root: JSONData)} callback
|
* @param {function(value: ESON, path: JSONPath, root: ESON)} callback
|
||||||
*/
|
*/
|
||||||
export function traverse (data: JSONData, callback: RecurseCallback) {
|
export function traverse (eson: ESON, callback: RecurseCallback) {
|
||||||
return recurseTraverse (data, [], data, callback)
|
return recurseTraverse (eson, [], eson, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively traverse a JSONData object
|
* Recursively traverse a ESON object
|
||||||
* @param {JSONData} value
|
* @param {ESON} value
|
||||||
* @param {Path} path
|
* @param {JSONPath} path
|
||||||
* @param {JSONData | null} root The root object, object at path=[]
|
* @param {ESON | null} root The root object, object at path=[]
|
||||||
* @param {function(value: JSONData, path: Path, root: JSONData)} callback
|
* @param {function(value: ESON, path: Path, root: ESON)} callback
|
||||||
*/
|
*/
|
||||||
function recurseTraverse (value: JSONData, path: Path, root: JSONData, callback: RecurseCallback) {
|
function recurseTraverse (value: ESON, path: JSONPath, root: ESON, callback: RecurseCallback) {
|
||||||
callback(value, path, root)
|
callback(value, path, root)
|
||||||
|
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case 'Array': {
|
case 'Array': {
|
||||||
value.items.forEach((item: ItemData, index) => {
|
value.items.forEach((item: ESONArrayItem, index) => {
|
||||||
recurseTraverse(item.value, path.concat(String(index)), root, callback)
|
recurseTraverse(item.value, path.concat(String(index)), root, callback)
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
@ -406,14 +409,14 @@ function recurseTraverse (value: JSONData, path: Path, root: JSONData, callback:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether a path exists in the json data
|
* Test whether a path exists in the eson object
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @param {Path} path
|
* @param {JSONPath} path
|
||||||
* @return {boolean} Returns true if the path exists, else returns false
|
* @return {boolean} Returns true if the path exists, else returns false
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function pathExists (data, path) {
|
export function pathExists (eson, path) {
|
||||||
if (data === undefined) {
|
if (eson === undefined) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,18 +424,17 @@ export function pathExists (data, path) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
let index
|
if (eson.type === 'Array') {
|
||||||
if (data.type === 'Array') {
|
|
||||||
// index of an array
|
// index of an array
|
||||||
index = path[0]
|
const index = path[0]
|
||||||
const item = data.items[index]
|
const item = eson.items[index]
|
||||||
|
|
||||||
return pathExists(item && item.value, path.slice(1))
|
return pathExists(item && item.value, path.slice(1))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// object property. find the index of this property
|
// object property. find the index of this property
|
||||||
index = findPropertyIndex(data, path[0])
|
const index = findPropertyIndex(eson, path[0])
|
||||||
const prop = data.props[index]
|
const prop = eson.props[index]
|
||||||
|
|
||||||
return pathExists(prop && prop.value, path.slice(1))
|
return pathExists(prop && prop.value, path.slice(1))
|
||||||
}
|
}
|
||||||
|
@ -441,14 +443,14 @@ export function pathExists (data, path) {
|
||||||
/**
|
/**
|
||||||
* Resolve the index for `arr/-`, replace it with an index value equal to the
|
* Resolve the index for `arr/-`, replace it with an index value equal to the
|
||||||
* length of the array
|
* length of the array
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @return {Path}
|
* @return {Path}
|
||||||
*/
|
*/
|
||||||
export function resolvePathIndex (data, path) {
|
export function resolvePathIndex (eson, path) {
|
||||||
if (path[path.length - 1] === '-') {
|
if (path[path.length - 1] === '-') {
|
||||||
const parentPath = path.slice(0, path.length - 1)
|
const parentPath = path.slice(0, path.length - 1)
|
||||||
const parent = getIn(data, toDataPath(data, parentPath))
|
const parent = getIn(eson, toEsonPath(eson, parentPath))
|
||||||
|
|
||||||
if (parent.type === 'Array') {
|
if (parent.type === 'Array') {
|
||||||
const index = parent.items.length
|
const index = parent.items.length
|
||||||
|
@ -464,12 +466,12 @@ export function resolvePathIndex (data, path) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the property after provided property
|
* Find the property after provided property
|
||||||
* @param {JSONData} parent
|
* @param {ESON} parent
|
||||||
* @param {string} prop
|
* @param {string} prop
|
||||||
* @return {string | null} Returns the name of the next property,
|
* @return {string | null} Returns the name of the next property,
|
||||||
* or null if there is none
|
* or null if there is none
|
||||||
*/
|
*/
|
||||||
export function findNextProp (parent: ObjectData, prop: string) : string | null {
|
export function findNextProp (parent: ESONObject, prop: string) : string | null {
|
||||||
const index = findPropertyIndex(parent, prop)
|
const index = findPropertyIndex(parent, prop)
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
return null
|
return null
|
||||||
|
@ -481,14 +483,16 @@ export function findNextProp (parent: ObjectData, prop: string) : string | null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the index of a property
|
* Find the index of a property
|
||||||
* @param {ObjectData} object
|
* @param {ESONObject} object
|
||||||
* @param {string} prop
|
* @param {string} prop
|
||||||
* @return {number} Returns the index when found, -1 when not found
|
* @return {number} Returns the index when found, -1 when not found
|
||||||
*/
|
*/
|
||||||
export function findPropertyIndex (object: ObjectData, prop: string) {
|
export function findPropertyIndex (object: ESONObject, prop: string) {
|
||||||
return object.props.findIndex(p => p.name === prop)
|
return object.props.findIndex(p => p.name === prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move parseJSONPointer and compileJSONPointer to a separate file
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a JSON Pointer
|
* Parse a JSON Pointer
|
||||||
* WARNING: this is not a complete implementation
|
* WARNING: this is not a complete implementation
|
||||||
|
@ -514,6 +518,8 @@ export function compileJSONPointer (path: Path) {
|
||||||
.join('')
|
.join('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move getId and createUniqueId to a separate file
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a new "unique" id. Id's are created from an incremental counter.
|
* Get a new "unique" id. Id's are created from an incremental counter.
|
||||||
* @return {number}
|
* @return {number}
|
|
@ -4,7 +4,7 @@ import JSONEditor from './components/JSONEditor'
|
||||||
import CodeMode from './components/CodeMode'
|
import CodeMode from './components/CodeMode'
|
||||||
import TextMode from './components/TextMode'
|
import TextMode from './components/TextMode'
|
||||||
import TreeMode from './components/TreeMode'
|
import TreeMode from './components/TreeMode'
|
||||||
import { compileJSONPointer, parseJSONPointer } from './jsonData'
|
import { compileJSONPointer, parseJSONPointer } from './eson'
|
||||||
|
|
||||||
import '!style!css!less!./jsoneditor.less'
|
import '!style!css!less!./jsoneditor.less'
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
import isEqual from 'lodash/isEqual'
|
import isEqual from 'lodash/isEqual'
|
||||||
|
|
||||||
import type {
|
import type { ESON, Path, JSONPatch, ESONPatchAction, ESONPatchOptions, ESONPatchResult } from './types'
|
||||||
JSONData, Path,
|
|
||||||
JSONPatch, JSONPatchAction, PatchOptions, JSONPatchResult
|
|
||||||
} from './types'
|
|
||||||
import { setIn, updateIn, getIn, deleteIn, insertAt } from './utils/immutabilityHelpers'
|
import { setIn, updateIn, getIn, deleteIn, insertAt } from './utils/immutabilityHelpers'
|
||||||
import { allButLast } from './utils/arrayUtils'
|
import { allButLast } from './utils/arrayUtils'
|
||||||
import {
|
import {
|
||||||
jsonToData, dataToJson, toDataPath,
|
jsonToEson, esonToJson, toEsonPath,
|
||||||
parseJSONPointer, compileJSONPointer,
|
parseJSONPointer, compileJSONPointer,
|
||||||
expandAll, pathExists, resolvePathIndex, findPropertyIndex, findNextProp, getId
|
expandAll, pathExists, resolvePathIndex, findPropertyIndex, findNextProp, getId
|
||||||
} from './jsonData'
|
} from './eson'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a patch to a JSONData object
|
* Apply a patch to a ESON object
|
||||||
* @param {JSONData} data
|
* @param {ESON} eson
|
||||||
* @param {Array} patch A JSON patch
|
* @param {Array} patch A JSON patch
|
||||||
* @param {function(path: Path)} [expand] Optional function to determine
|
* @param {function(path: Path)} [expand] Optional function to determine
|
||||||
* what nodes must be expanded
|
* what nodes must be expanded
|
||||||
* @return {{data: JSONData, revert: Object[], error: Error | null}}
|
* @return {{data: ESON, revert: Object[], error: Error | null}}
|
||||||
*/
|
*/
|
||||||
export function patchData (data: JSONData, patch: JSONPatchAction[], expand = expandAll) {
|
export function patchEson (eson: ESON, patch: ESONPatchAction[], expand = expandAll) {
|
||||||
let updatedData = data
|
let updatedEson = eson
|
||||||
let revert = []
|
let revert = []
|
||||||
|
|
||||||
for (let i = 0; i < patch.length; i++) {
|
for (let i = 0; i < patch.length; i++) {
|
||||||
|
@ -33,17 +30,17 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
|
||||||
switch (action.op) {
|
switch (action.op) {
|
||||||
case 'add': {
|
case 'add': {
|
||||||
const path = parseJSONPointer(action.path)
|
const path = parseJSONPointer(action.path)
|
||||||
const newValue = jsonToData(action.value, expand, path, options && options.type)
|
const newValue = jsonToEson(action.value, expand, path, options && options.type)
|
||||||
const result = add(updatedData, action.path, newValue, options)
|
const result = add(updatedEson, action.path, newValue, options)
|
||||||
updatedData = result.data
|
updatedEson = result.data
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'remove': {
|
case 'remove': {
|
||||||
const result = remove(updatedData, action.path)
|
const result = remove(updatedEson, action.path)
|
||||||
updatedData = result.data
|
updatedEson = result.data
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -51,9 +48,9 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
|
||||||
|
|
||||||
case 'replace': {
|
case 'replace': {
|
||||||
const path = parseJSONPointer(action.path)
|
const path = parseJSONPointer(action.path)
|
||||||
const newValue = jsonToData(action.value, expand, path, options && options.type)
|
const newValue = jsonToEson(action.value, expand, path, options && options.type)
|
||||||
const result = replace(updatedData, path, newValue)
|
const result = replace(updatedEson, path, newValue)
|
||||||
updatedData = result.data
|
updatedEson = result.data
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -62,14 +59,14 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
|
||||||
case 'copy': {
|
case 'copy': {
|
||||||
if (!action.from) {
|
if (!action.from) {
|
||||||
return {
|
return {
|
||||||
data,
|
data: eson,
|
||||||
revert: [],
|
revert: [],
|
||||||
error: new Error('Property "from" expected in copy action ' + JSON.stringify(action))
|
error: new Error('Property "from" expected in copy action ' + JSON.stringify(action))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = copy(updatedData, action.path, action.from, options)
|
const result = copy(updatedEson, action.path, action.from, options)
|
||||||
updatedData = result.data
|
updatedEson = result.data
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -78,14 +75,14 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
|
||||||
case 'move': {
|
case 'move': {
|
||||||
if (!action.from) {
|
if (!action.from) {
|
||||||
return {
|
return {
|
||||||
data,
|
data: eson,
|
||||||
revert: [],
|
revert: [],
|
||||||
error: new Error('Property "from" expected in move action ' + JSON.stringify(action))
|
error: new Error('Property "from" expected in move action ' + JSON.stringify(action))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = move(updatedData, action.path, action.from, options)
|
const result = move(updatedEson, action.path, action.from, options)
|
||||||
updatedData = result.data
|
updatedEson = result.data
|
||||||
revert = result.revert.concat(revert)
|
revert = result.revert.concat(revert)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -93,9 +90,9 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
|
||||||
|
|
||||||
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(updatedData, action.path, action.value)
|
const error = test(updatedEson, action.path, action.value)
|
||||||
if (error) {
|
if (error) {
|
||||||
return { data, revert: [], error}
|
return { data: eson, revert: [], error}
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -104,7 +101,7 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
|
||||||
default: {
|
default: {
|
||||||
// unknown jsonpatch operation. Cancel the whole patch and return an error
|
// unknown jsonpatch operation. Cancel the whole patch and return an error
|
||||||
return {
|
return {
|
||||||
data,
|
data: eson,
|
||||||
revert: [],
|
revert: [],
|
||||||
error: new Error('Unknown jsonpatch op ' + JSON.stringify(action.op))
|
error: new Error('Unknown jsonpatch op ' + JSON.stringify(action.op))
|
||||||
}
|
}
|
||||||
|
@ -115,7 +112,7 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
|
||||||
// TODO: Simplify revert when possible:
|
// TODO: Simplify revert when possible:
|
||||||
// when a previous action takes place on the same path, remove the first
|
// when a previous action takes place on the same path, remove the first
|
||||||
return {
|
return {
|
||||||
data: updatedData,
|
data: updatedEson,
|
||||||
revert: simplifyPatch(revert),
|
revert: simplifyPatch(revert),
|
||||||
error: null
|
error: null
|
||||||
}
|
}
|
||||||
|
@ -123,21 +120,21 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace an existing item
|
* Replace an existing item
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {Path} path
|
* @param {Path} path
|
||||||
* @param {JSONData} value
|
* @param {ESON} value
|
||||||
* @return {{data: JSONData, revert: JSONPatch}}
|
* @return {{data: ESON, revert: JSONPatch}}
|
||||||
*/
|
*/
|
||||||
export function replace (data: JSONData, path: Path, value: JSONData) {
|
export function replace (data: ESON, path: Path, value: ESON) {
|
||||||
const dataPath = toDataPath(data, path)
|
const esonPath = toEsonPath(data, path)
|
||||||
const oldValue = getIn(data, dataPath)
|
const oldValue = getIn(data, esonPath)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: setIn(data, dataPath, value),
|
data: setIn(data, esonPath, value),
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
path: compileJSONPointer(path),
|
path: compileJSONPointer(path),
|
||||||
value: dataToJson(oldValue),
|
value: esonToJson(oldValue),
|
||||||
jsoneditor: {
|
jsoneditor: {
|
||||||
type: oldValue.type
|
type: oldValue.type
|
||||||
}
|
}
|
||||||
|
@ -147,27 +144,27 @@ export function replace (data: JSONData, path: Path, value: JSONData) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an item or property
|
* Remove an item or property
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @return {{data: JSONData, revert: JSONPatch}}
|
* @return {{data: ESON, revert: JSONPatch}}
|
||||||
*/
|
*/
|
||||||
export function remove (data: JSONData, path: string) {
|
export function remove (data: ESON, path: string) {
|
||||||
// console.log('remove', path)
|
// console.log('remove', path)
|
||||||
const pathArray = parseJSONPointer(path)
|
const pathArray = parseJSONPointer(path)
|
||||||
|
|
||||||
const parentPath = pathArray.slice(0, pathArray.length - 1)
|
const parentPath = pathArray.slice(0, pathArray.length - 1)
|
||||||
const parent = getIn(data, toDataPath(data, parentPath))
|
const parent = getIn(data, toEsonPath(data, parentPath))
|
||||||
const dataValue = getIn(data, toDataPath(data, pathArray))
|
const dataValue = getIn(data, toEsonPath(data, pathArray))
|
||||||
const value = dataToJson(dataValue)
|
const value = esonToJson(dataValue)
|
||||||
|
|
||||||
if (parent.type === 'Array') {
|
if (parent.type === 'Array') {
|
||||||
const dataPath = toDataPath(data, pathArray)
|
const esonPath = toEsonPath(data, pathArray)
|
||||||
|
|
||||||
// remove the 'value' property, we want to remove the whole item from the items array
|
// remove the 'value' property, we want to remove the whole item from the items array
|
||||||
dataPath.pop()
|
esonPath.pop()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: deleteIn(data, dataPath),
|
data: deleteIn(data, esonPath),
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'add',
|
op: 'add',
|
||||||
path,
|
path,
|
||||||
|
@ -179,14 +176,14 @@ export function remove (data: JSONData, path: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // object.type === 'Object'
|
else { // object.type === 'Object'
|
||||||
const dataPath = toDataPath(data, pathArray)
|
const esonPath = toEsonPath(data, pathArray)
|
||||||
const prop = pathArray[pathArray.length - 1]
|
const prop = pathArray[pathArray.length - 1]
|
||||||
|
|
||||||
// remove the 'value' property, we want to remove the whole object property from props
|
// remove the 'value' property, we want to remove the whole object property from props
|
||||||
dataPath.pop()
|
esonPath.pop()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: deleteIn(data, dataPath),
|
data: deleteIn(data, esonPath),
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'add',
|
op: 'add',
|
||||||
path,
|
path,
|
||||||
|
@ -233,32 +230,32 @@ export function simplifyPatch(patch: JSONPatch) {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @param {JSONData} value
|
* @param {ESON} value
|
||||||
* @param {{before?: string}} [options]
|
* @param {{before?: string}} [options]
|
||||||
* @param {number} [id] Optional id for the new item
|
* @param {number} [id] Optional id for the new item
|
||||||
* @return {{data: JSONData, revert: JSONPatch}}
|
* @return {{data: ESON, revert: JSONPatch}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function add (data: JSONData, path: string, value: JSONData, options, id = getId()) {
|
export function add (data: ESON, path: string, value: ESON, options, id = getId()) {
|
||||||
const pathArray = parseJSONPointer(path)
|
const pathArray = parseJSONPointer(path)
|
||||||
const parentPath = pathArray.slice(0, pathArray.length - 1)
|
const parentPath = pathArray.slice(0, pathArray.length - 1)
|
||||||
const dataPath = toDataPath(data, parentPath)
|
const esonPath = toEsonPath(data, parentPath)
|
||||||
const parent = getIn(data, dataPath)
|
const parent = getIn(data, esonPath)
|
||||||
const resolvedPath = resolvePathIndex(data, pathArray)
|
const resolvedPath = resolvePathIndex(data, pathArray)
|
||||||
const prop = resolvedPath[resolvedPath.length - 1]
|
const prop = resolvedPath[resolvedPath.length - 1]
|
||||||
|
|
||||||
let updatedData
|
let updatedEson
|
||||||
if (parent.type === 'Array') {
|
if (parent.type === 'Array') {
|
||||||
const newItem = {
|
const newItem = {
|
||||||
id, // TODO: create a unique id within current id's instead of using a global, ever incrementing id
|
id, // TODO: create a unique id within current id's instead of using a global, ever incrementing id
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
updatedData = insertAt(data, dataPath.concat('items', prop), newItem)
|
updatedEson = insertAt(data, esonPath.concat('items', prop), newItem)
|
||||||
}
|
}
|
||||||
else { // parent.type === 'Object'
|
else { // parent.type === 'Object'
|
||||||
updatedData = updateIn(data, dataPath, (object) => {
|
updatedEson = updateIn(data, esonPath, (object) => {
|
||||||
const existingIndex = findPropertyIndex(object, prop)
|
const existingIndex = findPropertyIndex(object, prop)
|
||||||
if (existingIndex !== -1) {
|
if (existingIndex !== -1) {
|
||||||
// replace existing item
|
// replace existing item
|
||||||
|
@ -277,21 +274,21 @@ export function add (data: JSONData, path: string, value: JSONData, options, id
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent.type === 'Object' && pathExists(data, resolvedPath)) {
|
if (parent.type === 'Object' && pathExists(data, resolvedPath)) {
|
||||||
const oldValue = getIn(data, toDataPath(data, resolvedPath))
|
const oldValue = getIn(data, toEsonPath(data, resolvedPath))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: updatedData,
|
data: updatedEson,
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'replace',
|
op: 'replace',
|
||||||
path: compileJSONPointer(resolvedPath),
|
path: compileJSONPointer(resolvedPath),
|
||||||
value: dataToJson(oldValue),
|
value: esonToJson(oldValue),
|
||||||
jsoneditor: { type: oldValue.type }
|
jsoneditor: { type: oldValue.type }
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return {
|
return {
|
||||||
data: updatedData,
|
data: updatedEson,
|
||||||
revert: [{
|
revert: [{
|
||||||
op: 'remove',
|
op: 'remove',
|
||||||
path: compileJSONPointer(resolvedPath)
|
path: compileJSONPointer(resolvedPath)
|
||||||
|
@ -302,37 +299,37 @@ export function add (data: JSONData, path: string, value: JSONData, options, id
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy a value
|
* Copy a value
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @param {string} from
|
* @param {string} from
|
||||||
* @param {{before?: string}} [options]
|
* @param {{before?: string}} [options]
|
||||||
* @return {{data: JSONData, revert: JSONPatch}}
|
* @return {{data: ESON, revert: JSONPatch}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function copy (data: JSONData, path: string, from: string, options) {
|
export function copy (data: ESON, path: string, from: string, options) {
|
||||||
const value = getIn(data, toDataPath(data, parseJSONPointer(from)))
|
const value = getIn(data, toEsonPath(data, parseJSONPointer(from)))
|
||||||
|
|
||||||
return add(data, path, value, options)
|
return add(data, path, value, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move a value
|
* Move a value
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @param {string} from
|
* @param {string} from
|
||||||
* @param {{before?: string}} [options]
|
* @param {{before?: string}} [options]
|
||||||
* @return {{data: JSONData, revert: JSONPatch}}
|
* @return {{data: ESON, revert: JSONPatch}}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
export function move (data: JSONData, path: string, from: string, options) {
|
export function move (data: ESON, path: string, from: string, options) {
|
||||||
const fromArray = parseJSONPointer(from)
|
const fromArray = parseJSONPointer(from)
|
||||||
const prop = getIn(data, allButLast(toDataPath(data, fromArray)))
|
const prop = getIn(data, allButLast(toEsonPath(data, fromArray)))
|
||||||
const dataValue = prop.value
|
const dataValue = prop.value
|
||||||
const id = prop.id // we want to use the existing id in case the move is a renaming a property
|
const id = prop.id // we want to use the existing id in case the move is a renaming a property
|
||||||
// FIXME: only reuse the existing id when move is renaming a property in the same object
|
// FIXME: only reuse the existing id when move is renaming a property in the same object
|
||||||
|
|
||||||
const parentPathFrom = allButLast(fromArray)
|
const parentPathFrom = allButLast(fromArray)
|
||||||
const parent = getIn(data, toDataPath(data, parentPathFrom))
|
const parent = getIn(data, toEsonPath(data, parentPathFrom))
|
||||||
|
|
||||||
const result1 = remove(data, from)
|
const result1 = remove(data, from)
|
||||||
const result2 = add(result1.data, path, dataValue, options, id)
|
const result2 = add(result1.data, path, dataValue, options, id)
|
||||||
|
@ -367,12 +364,12 @@ export function move (data: JSONData, path: string, from: string, options) {
|
||||||
/**
|
/**
|
||||||
* Test whether the data contains the provided value at the specified path.
|
* Test whether the data contains the provided value at the specified path.
|
||||||
* Throws an error when the test fails.
|
* Throws an error when the test fails.
|
||||||
* @param {JSONData} data
|
* @param {ESON} data
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
* @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 (data: JSONData, path: string, value: any) {
|
export function test (data: ESON, path: string, value: any) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return new Error('Test failed, no value provided')
|
return new Error('Test failed, no value provided')
|
||||||
}
|
}
|
||||||
|
@ -382,8 +379,8 @@ export function test (data: JSONData, path: string, value: any) {
|
||||||
return new Error('Test failed, path not found')
|
return new Error('Test failed, path not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
const actualValue = getIn(data, toDataPath(data, pathArray))
|
const actualValue = getIn(data, toEsonPath(data, pathArray))
|
||||||
if (!isEqual(dataToJson(actualValue), value)) {
|
if (!isEqual(esonToJson(actualValue), value)) {
|
||||||
return new Error('Test failed, value differs')
|
return new Error('Test failed, value differs')
|
||||||
}
|
}
|
||||||
}
|
}
|
65
src/types.js
65
src/types.js
|
@ -25,59 +25,60 @@
|
||||||
|
|
||||||
/**************************** GENERIC JSON TYPES ******************************/
|
/**************************** GENERIC JSON TYPES ******************************/
|
||||||
|
|
||||||
export type JSONType = | string | number | boolean | null | JSONObjectType | JSONArrayType;
|
export type JSONType = | string | number | boolean | null | JSONObjectType | JSONArrayType
|
||||||
export type JSONObjectType = { [key:string]: JSONType };
|
export type JSONObjectType = { [key:string]: JSONType }
|
||||||
export type JSONArrayType = Array<JSONType>;
|
export type JSONArrayType = JSONType[]
|
||||||
|
|
||||||
|
|
||||||
/********************** TYPES FOR THE JSON DATA MODEL *************************/
|
/********************** TYPES FOR THE ESON OBJECT MODEL *************************/
|
||||||
|
|
||||||
export type SearchResultStatus = 'normal' | 'active'
|
export type SearchResultStatus = 'normal' | 'active'
|
||||||
export type DataPointerType = 'value' | 'property'
|
export type ESONPointerType = 'value' | 'property'
|
||||||
|
|
||||||
export type PropertyData = {
|
export type ESONObjectProperty = {
|
||||||
id: number,
|
id: number,
|
||||||
name: string,
|
name: string,
|
||||||
value: JSONData,
|
value: ESON,
|
||||||
searchResult?: SearchResultStatus
|
searchResult?: SearchResultStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ItemData = {
|
export type ESONArrayItem = {
|
||||||
id: number,
|
id: number,
|
||||||
value: JSONData
|
value: ESON
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ObjectData = {
|
export type ESONObject = {
|
||||||
type: 'Object',
|
type: 'Object',
|
||||||
expanded?: boolean,
|
expanded?: boolean,
|
||||||
props: PropertyData[]
|
props: ESONObjectProperty[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ArrayData = {
|
export type ESONArray = {
|
||||||
type: 'Array',
|
type: 'Array',
|
||||||
expanded?: boolean,
|
expanded?: boolean,
|
||||||
items: ItemData[]
|
items: ESONArrayItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ValueData = {
|
export type ESONValue = {
|
||||||
type: 'value' | 'string',
|
type: 'value' | 'string',
|
||||||
value?: any,
|
value?: any,
|
||||||
searchResult?: SearchResultStatus
|
searchResult?: SearchResultStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
export type JSONData = ObjectData | ArrayData | ValueData
|
export type ESON = ESONObject | ESONArray | ESONValue
|
||||||
|
|
||||||
export type JSONDataType = 'Object' | 'Array' | 'value' | 'string'
|
export type ESONType = 'Object' | 'Array' | 'value' | 'string'
|
||||||
|
|
||||||
|
export type Path = string[] // TODO: Path must become redundant, replace with JSONPath or ESONPath everywhere
|
||||||
|
export type JSONPath = string[]
|
||||||
|
export type ESONPath = string[]
|
||||||
|
|
||||||
|
export type ESONPointer = {
|
||||||
export type Path = string[]
|
path: ESONPath,
|
||||||
|
type: ESONPointerType
|
||||||
export type DataPointer = {
|
|
||||||
path: Path,
|
|
||||||
type: DataPointerType
|
|
||||||
}
|
}
|
||||||
// TODO: DataPointer.dataPath is an array, JSONSchemaError.dataPath is a string -> make this consistent
|
|
||||||
|
// TODO: ESONPointer.path is an array, JSONSchemaError.path is a string -> make this consistent
|
||||||
|
|
||||||
|
|
||||||
// TODO: remove SetOptions, merge into Options (everywhere in the public API)
|
// TODO: remove SetOptions, merge into Options (everywhere in the public API)
|
||||||
|
@ -85,27 +86,27 @@ export type SetOptions = {
|
||||||
expand?: (path: Path) => boolean
|
expand?: (path: Path) => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type JSONPatchAction = {
|
export type ESONPatchAction = {
|
||||||
op: string, // TODO: define allowed ops
|
op: string, // TODO: define allowed ops
|
||||||
path: string,
|
path: string,
|
||||||
from?: string,
|
from?: string,
|
||||||
value?: any,
|
value?: any,
|
||||||
jsoneditor?: PatchOptions
|
jsoneditor?: ESONPatchOptions
|
||||||
}
|
}
|
||||||
export type JSONPatch = JSONPatchAction[]
|
export type ESONPatch = ESONPatchAction[]
|
||||||
|
|
||||||
export type PatchOptions = {
|
export type ESONPatchOptions = {
|
||||||
type: JSONDataType,
|
type: ESONType,
|
||||||
expand: (Path) => boolean
|
expand: (Path) => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type JSONPatchResult = {
|
export type ESONPatchResult = {
|
||||||
patch: JSONPatch,
|
patch: ESONPatch,
|
||||||
revert: JSONPatch,
|
revert: ESONPatch,
|
||||||
error: null | Error
|
error: null | Error
|
||||||
}
|
}
|
||||||
|
|
||||||
export type JSONSchemaError = {
|
export type JSONSchemaError = {
|
||||||
dataPath: string,
|
path: string, // TODO: change type to JSONPath
|
||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import {
|
import {
|
||||||
jsonToData, dataToJson, pathExists, transform, traverse,
|
jsonToEson, esonToJson, pathExists, transform, traverse,
|
||||||
parseJSONPointer, compileJSONPointer,
|
parseJSONPointer, compileJSONPointer,
|
||||||
expand, addErrors, search, addSearchResults, nextSearchResult, previousSearchResult
|
expand, addErrors, search, addSearchResults, nextSearchResult, previousSearchResult
|
||||||
} from '../src/jsonData'
|
} from '../src/eson'
|
||||||
|
|
||||||
|
|
||||||
const JSON_EXAMPLE = {
|
const JSON_EXAMPLE = {
|
||||||
|
@ -105,6 +105,31 @@ const JSON_DATA_EXAMPLE = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const JSON_DUPLICATE_PROPERTY_EXAMPLE = {
|
||||||
|
type: 'Object',
|
||||||
|
expanded: true,
|
||||||
|
props: [
|
||||||
|
{
|
||||||
|
id: '[ID]',
|
||||||
|
name: 'name',
|
||||||
|
value: {
|
||||||
|
type: 'value',
|
||||||
|
expanded: true,
|
||||||
|
value: 'Joe'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '[ID]',
|
||||||
|
name: 'name',
|
||||||
|
value: {
|
||||||
|
type: 'value',
|
||||||
|
expanded: true,
|
||||||
|
value: 'Joe'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: instead of all slightly different copies of JSON_DATA_EXAMPLE, built them up via setIn, updateIn based on JSON_DATA_EXAMPLE
|
// TODO: instead of all slightly different copies of JSON_DATA_EXAMPLE, built them up via setIn, updateIn based on JSON_DATA_EXAMPLE
|
||||||
|
|
||||||
const JSON_DATA_EXAMPLE_COLLAPSED_1 = {
|
const JSON_DATA_EXAMPLE_COLLAPSED_1 = {
|
||||||
|
@ -426,8 +451,8 @@ const JSON_DATA_SMALL = {
|
||||||
|
|
||||||
|
|
||||||
const JSON_SCHEMA_ERRORS = [
|
const JSON_SCHEMA_ERRORS = [
|
||||||
{dataPath: '/obj/arr/2/last', message: 'String expected'},
|
{esonPath: '/obj/arr/2/last', message: 'String expected'},
|
||||||
{dataPath: '/nill', message: 'Null expected'}
|
{esonPath: '/nill', message: 'Null expected'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const JSON_DATA_EXAMPLE_ERRORS = {
|
const JSON_DATA_EXAMPLE_ERRORS = {
|
||||||
|
@ -522,19 +547,19 @@ const JSON_DATA_EXAMPLE_ERRORS = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
test('jsonToData', t => {
|
test('jsonToEson', t => {
|
||||||
function expand (path) {
|
function expand (path) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsonData = jsonToData(JSON_EXAMPLE, expand, [])
|
const ESON = jsonToEson(JSON_EXAMPLE, expand, [])
|
||||||
replaceIds(jsonData)
|
replaceIds(ESON)
|
||||||
|
|
||||||
t.deepEqual(jsonData, JSON_DATA_EXAMPLE)
|
t.deepEqual(ESON, JSON_DATA_EXAMPLE)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('dataToJson', t => {
|
test('esonToJson', t => {
|
||||||
t.deepEqual(dataToJson(JSON_DATA_EXAMPLE), JSON_EXAMPLE)
|
t.deepEqual(esonToJson(JSON_DATA_EXAMPLE), JSON_EXAMPLE)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('expand a single path', t => {
|
test('expand a single path', t => {
|
|
@ -1,6 +1,6 @@
|
||||||
import test from 'ava';
|
import test from 'ava';
|
||||||
import { jsonToData, dataToJson } from '../src/jsonData'
|
import { jsonToEson, esonToJson } from '../src/eson'
|
||||||
import { patchData } from '../src/jsonPatchData'
|
import { patchEson } from '../src/patchEson'
|
||||||
|
|
||||||
test('jsonpatch add', t => {
|
test('jsonpatch add', t => {
|
||||||
const json = {
|
const json = {
|
||||||
|
@ -12,11 +12,11 @@ test('jsonpatch add', t => {
|
||||||
{op: 'add', path: '/obj/b', value: {foo: 'bar'}}
|
{op: 'add', path: '/obj/b', value: {foo: 'bar'}}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
arr: [1,2,3],
|
arr: [1,2,3],
|
||||||
|
@ -37,11 +37,11 @@ test('jsonpatch add: append to matrix', t => {
|
||||||
{op: 'add', path: '/arr/-', value: 4}
|
{op: 'add', path: '/arr/-', value: 4}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
arr: [1,2,3,4],
|
arr: [1,2,3,4],
|
||||||
|
@ -64,11 +64,11 @@ test('jsonpatch remove', t => {
|
||||||
{op: 'remove', path: '/arr/1'},
|
{op: 'remove', path: '/arr/1'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
arr: [1,3],
|
arr: [1,3],
|
||||||
|
@ -80,11 +80,11 @@ test('jsonpatch remove', t => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const data2 = jsonToData(patchedJson)
|
const data2 = jsonToEson(patchedJson)
|
||||||
const result2 = patchData(data2, revert)
|
const result2 = patchEson(data2, revert)
|
||||||
const patchedData2 = result2.data
|
const patchedData2 = result2.data
|
||||||
const revert2 = result2.revert
|
const revert2 = result2.revert
|
||||||
const patchedJson2 = dataToJson(patchedData2)
|
const patchedJson2 = esonToJson(patchedData2)
|
||||||
|
|
||||||
t.deepEqual(patchedJson2, json)
|
t.deepEqual(patchedJson2, json)
|
||||||
t.deepEqual(revert2, patch)
|
t.deepEqual(revert2, patch)
|
||||||
|
@ -101,11 +101,11 @@ test('jsonpatch replace', t => {
|
||||||
{op: 'replace', path: '/arr/1', value: 200},
|
{op: 'replace', path: '/arr/1', value: 200},
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
arr: [1,200,3],
|
arr: [1,200,3],
|
||||||
|
@ -117,11 +117,11 @@ test('jsonpatch replace', t => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const data2 = jsonToData(patchedJson)
|
const data2 = jsonToEson(patchedJson)
|
||||||
const result2 = patchData(data2, revert)
|
const result2 = patchEson(data2, revert)
|
||||||
const patchedData2 = result2.data
|
const patchedData2 = result2.data
|
||||||
const revert2 = result2.revert
|
const revert2 = result2.revert
|
||||||
const patchedJson2 = dataToJson(patchedData2)
|
const patchedJson2 = esonToJson(patchedData2)
|
||||||
|
|
||||||
t.deepEqual(patchedJson2, json)
|
t.deepEqual(patchedJson2, json)
|
||||||
t.deepEqual(revert2, [
|
t.deepEqual(revert2, [
|
||||||
|
@ -136,10 +136,10 @@ test('jsonpatch replace (keep ids intact)', t => {
|
||||||
{op: 'replace', path: '/value', value: 100}
|
{op: 'replace', path: '/value', value: 100}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const valueId = data.props[0].id
|
const valueId = data.props[0].id
|
||||||
|
|
||||||
const patchedData = patchData(data, patch).data
|
const patchedData = patchEson(data, patch).data
|
||||||
const patchedValueId = patchedData.props[0].id
|
const patchedValueId = patchedData.props[0].id
|
||||||
|
|
||||||
t.is(patchedValueId, valueId)
|
t.is(patchedValueId, valueId)
|
||||||
|
@ -155,11 +155,11 @@ test('jsonpatch copy', t => {
|
||||||
{op: 'copy', from: '/obj', path: '/arr/2'},
|
{op: 'copy', from: '/obj', path: '/arr/2'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
arr: [1, 2, {a:4}, 3],
|
arr: [1, 2, {a:4}, 3],
|
||||||
|
@ -170,11 +170,11 @@ test('jsonpatch copy', t => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const data2 = jsonToData(patchedJson)
|
const data2 = jsonToEson(patchedJson)
|
||||||
const result2 = patchData(data2, revert)
|
const result2 = patchEson(data2, revert)
|
||||||
const patchedData2 = result2.data
|
const patchedData2 = result2.data
|
||||||
const revert2 = result2.revert
|
const revert2 = result2.revert
|
||||||
const patchedJson2 = dataToJson(patchedData2)
|
const patchedJson2 = esonToJson(patchedData2)
|
||||||
|
|
||||||
t.deepEqual(patchedJson2, json)
|
t.deepEqual(patchedJson2, json)
|
||||||
t.deepEqual(revert2, [
|
t.deepEqual(revert2, [
|
||||||
|
@ -188,11 +188,11 @@ test('jsonpatch copy (keeps the same ids)', t => {
|
||||||
{op: 'copy', from: '/foo', path: '/copied'}
|
{op: 'copy', from: '/foo', path: '/copied'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const fooId = data.props[0].id
|
const fooId = data.props[0].id
|
||||||
const barId = data.props[0].value.props[0].id
|
const barId = data.props[0].value.props[0].id
|
||||||
|
|
||||||
const patchedData = patchData(data, patch).data
|
const patchedData = patchEson(data, patch).data
|
||||||
const patchedFooId = patchedData.props[0].id
|
const patchedFooId = patchedData.props[0].id
|
||||||
const patchedBarId = patchedData.props[0].value.props[0].id
|
const patchedBarId = patchedData.props[0].value.props[0].id
|
||||||
const copiedId = patchedData.props[1].id
|
const copiedId = patchedData.props[1].id
|
||||||
|
@ -221,11 +221,11 @@ test('jsonpatch move', t => {
|
||||||
{op: 'move', from: '/obj', path: '/arr/2'},
|
{op: 'move', from: '/obj', path: '/arr/2'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.is(result.error, null)
|
t.is(result.error, null)
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
|
@ -236,11 +236,11 @@ test('jsonpatch move', t => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const data2 = jsonToData(patchedJson)
|
const data2 = jsonToEson(patchedJson)
|
||||||
const result2 = patchData(data2, revert)
|
const result2 = patchEson(data2, revert)
|
||||||
const patchedData2 = result2.data
|
const patchedData2 = result2.data
|
||||||
const revert2 = result2.revert
|
const revert2 = result2.revert
|
||||||
const patchedJson2 = dataToJson(patchedData2)
|
const patchedJson2 = esonToJson(patchedData2)
|
||||||
|
|
||||||
t.deepEqual(patchedJson2, json)
|
t.deepEqual(patchedJson2, json)
|
||||||
t.deepEqual(revert2, patch)
|
t.deepEqual(revert2, patch)
|
||||||
|
@ -257,11 +257,11 @@ test('jsonpatch move before', t => {
|
||||||
{op: 'move', from: '/obj', path: '/arr/2'},
|
{op: 'move', from: '/obj', path: '/arr/2'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.is(result.error, null)
|
t.is(result.error, null)
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
|
@ -273,11 +273,11 @@ test('jsonpatch move before', t => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const data2 = jsonToData(patchedJson)
|
const data2 = jsonToEson(patchedJson)
|
||||||
const result2 = patchData(data2, revert)
|
const result2 = patchEson(data2, revert)
|
||||||
const patchedData2 = result2.data
|
const patchedData2 = result2.data
|
||||||
const revert2 = result2.revert
|
const revert2 = result2.revert
|
||||||
const patchedJson2 = dataToJson(patchedData2)
|
const patchedJson2 = esonToJson(patchedData2)
|
||||||
|
|
||||||
t.deepEqual(patchedJson2, json)
|
t.deepEqual(patchedJson2, json)
|
||||||
t.deepEqual(revert2, patch)
|
t.deepEqual(revert2, patch)
|
||||||
|
@ -290,12 +290,12 @@ test('jsonpatch move and replace', t => {
|
||||||
{op: 'move', from: '/a', path: '/b'},
|
{op: 'move', from: '/a', path: '/b'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
|
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
// id of the replaced B must be kept intact
|
// id of the replaced B must be kept intact
|
||||||
t.is(patchedData.props[0].id, data.props[1].id)
|
t.is(patchedData.props[0].id, data.props[1].id)
|
||||||
|
@ -323,11 +323,11 @@ test('jsonpatch move and replace', t => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const data2 = jsonToData(patchedJson)
|
const data2 = jsonToEson(patchedJson)
|
||||||
const result2 = patchData(data2, revert)
|
const result2 = patchEson(data2, revert)
|
||||||
const patchedData2 = result2.data
|
const patchedData2 = result2.data
|
||||||
const revert2 = result2.revert
|
const revert2 = result2.revert
|
||||||
const patchedJson2 = dataToJson(patchedData2)
|
const patchedJson2 = esonToJson(patchedData2)
|
||||||
|
|
||||||
t.deepEqual(patchedJson2, json)
|
t.deepEqual(patchedJson2, json)
|
||||||
t.deepEqual(revert2, [
|
t.deepEqual(revert2, [
|
||||||
|
@ -345,11 +345,11 @@ test('jsonpatch move and replace (nested)', t => {
|
||||||
{op: 'move', from: '/obj', path: '/arr'},
|
{op: 'move', from: '/obj', path: '/arr'},
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
arr: {a:4}
|
arr: {a:4}
|
||||||
|
@ -360,11 +360,11 @@ test('jsonpatch move and replace (nested)', t => {
|
||||||
])
|
])
|
||||||
|
|
||||||
// test revert
|
// test revert
|
||||||
const data2 = jsonToData(patchedJson)
|
const data2 = jsonToEson(patchedJson)
|
||||||
const result2 = patchData(data2, revert)
|
const result2 = patchEson(data2, revert)
|
||||||
const patchedData2 = result2.data
|
const patchedData2 = result2.data
|
||||||
const revert2 = result2.revert
|
const revert2 = result2.revert
|
||||||
const patchedJson2 = dataToJson(patchedData2)
|
const patchedJson2 = esonToJson(patchedData2)
|
||||||
|
|
||||||
t.deepEqual(patchedJson2, json)
|
t.deepEqual(patchedJson2, json)
|
||||||
t.deepEqual(revert2, [
|
t.deepEqual(revert2, [
|
||||||
|
@ -378,10 +378,10 @@ test('jsonpatch move (keep id intact)', t => {
|
||||||
{op: 'move', from: '/value', path: '/moved'}
|
{op: 'move', from: '/value', path: '/moved'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const valueId = data.props[0].id
|
const valueId = data.props[0].id
|
||||||
|
|
||||||
const patchedData = patchData(data, patch).data
|
const patchedData = patchEson(data, patch).data
|
||||||
const patchedValueId = patchedData.props[0].id
|
const patchedValueId = patchedData.props[0].id
|
||||||
|
|
||||||
t.is(patchedValueId, valueId)
|
t.is(patchedValueId, valueId)
|
||||||
|
@ -393,13 +393,13 @@ test('jsonpatch move and replace (keep ids intact)', t => {
|
||||||
{op: 'move', from: '/a', path: '/b'}
|
{op: 'move', from: '/a', path: '/b'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const bId = data.props[1].id
|
const bId = data.props[1].id
|
||||||
|
|
||||||
t.is(data.props[0].name, 'a')
|
t.is(data.props[0].name, 'a')
|
||||||
t.is(data.props[1].name, 'b')
|
t.is(data.props[1].name, 'b')
|
||||||
|
|
||||||
const patchedData = patchData(data, patch).data
|
const patchedData = patchEson(data, patch).data
|
||||||
|
|
||||||
t.is(patchedData.props[0].name, 'b')
|
t.is(patchedData.props[0].name, 'b')
|
||||||
t.is(patchedData.props[0].id, bId)
|
t.is(patchedData.props[0].id, bId)
|
||||||
|
@ -416,11 +416,11 @@ test('jsonpatch test (ok)', t => {
|
||||||
{op: 'add', path: '/added', value: 'ok'}
|
{op: 'add', path: '/added', value: 'ok'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
arr: [1,2,3],
|
arr: [1,2,3],
|
||||||
|
@ -444,11 +444,11 @@ test('jsonpatch test (fail: path not found)', t => {
|
||||||
{op: 'add', path: '/added', value: 'ok'}
|
{op: 'add', path: '/added', value: 'ok'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
// patch shouldn't be applied
|
// patch shouldn't be applied
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
||||||
|
@ -470,11 +470,11 @@ test('jsonpatch test (fail: value not equal)', t => {
|
||||||
{op: 'add', path: '/added', value: 'ok'}
|
{op: 'add', path: '/added', value: 'ok'}
|
||||||
]
|
]
|
||||||
|
|
||||||
const data = jsonToData(json)
|
const data = jsonToEson(json)
|
||||||
const result = patchData(data, patch)
|
const result = patchEson(data, patch)
|
||||||
const patchedData = result.data
|
const patchedData = result.data
|
||||||
const revert = result.revert
|
const revert = result.revert
|
||||||
const patchedJson = dataToJson(patchedData)
|
const patchedJson = esonToJson(patchedData)
|
||||||
|
|
||||||
// patch shouldn't be applied
|
// patch shouldn't be applied
|
||||||
t.deepEqual(patchedJson, {
|
t.deepEqual(patchedJson, {
|
|
@ -64,7 +64,7 @@ describe('util', function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('jsonPath', function () {
|
describe('path', function () {
|
||||||
|
|
||||||
it ('should parse a json path', function () {
|
it ('should parse a json path', function () {
|
||||||
assert.deepEqual(util.parsePath(''), []);
|
assert.deepEqual(util.parsePath(''), []);
|
||||||
|
|
Loading…
Reference in New Issue