Renamed 'jsonData' to 'ESON'

This commit is contained in:
jos 2017-09-08 13:36:15 +02:00
parent 2ee11399ec
commit 432e169f32
13 changed files with 390 additions and 361 deletions

View File

@ -1,4 +1,4 @@
import { compileJSONPointer, toDataPath, dataToJson, findNextProp } from './jsonData'
import { compileJSONPointer, toEsonPath, esonToJson, findNextProp } from './eson'
import { findUniqueName } from './utils/stringUtils'
import { getIn } from './utils/immutabilityHelpers'
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
* @param {JSONData} data
* @param {ESON} data
* @param {Path} path
* @param {*} value
* @return {Array}
@ -15,8 +15,8 @@ import { compareAsc, compareDesc, strictShallowEqual } from './utils/arrayUtils'
export function changeValue (data, path, value) {
// console.log('changeValue', data, value)
const dataPath = toDataPath(data, path)
const oldDataValue = getIn(data, dataPath)
const esonPath = toEsonPath(data, path)
const oldDataValue = getIn(data, esonPath)
return [{
op: 'replace',
@ -30,7 +30,7 @@ export function changeValue (data, path, value) {
/**
* Create a JSONPatch to change a property name
* @param {JSONData} data
* @param {ESON} data
* @param {Path} parentPath
* @param {string} oldProp
* @param {string} newProp
@ -39,8 +39,8 @@ export function changeValue (data, path, value) {
export function changeProperty (data, parentPath, oldProp, newProp) {
// console.log('changeProperty', parentPath, oldProp, newProp)
const dataPath = toDataPath(data, parentPath)
const parent = getIn(data, dataPath)
const esonPath = toEsonPath(data, parentPath)
const parent = getIn(data, esonPath)
// prevent duplicate property names
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
* @param {JSONData} data
* @param {ESON} data
* @param {Path} path
* @param {JSONDataType} type
* @param {ESONType} type
* @return {Array}
*/
export function changeType (data, path, type) {
const dataPath = toDataPath(data, path)
const oldValue = dataToJson(getIn(data, dataPath))
const esonPath = toEsonPath(data, path)
const oldValue = esonToJson(getIn(data, esonPath))
const newValue = convertType(oldValue, type)
// 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
* and object property
*
* @param {JSONData} data
* @param {ESON} data
* @param {Path} path
* @return {Array}
*/
@ -95,8 +95,8 @@ export function duplicate (data, path) {
const parentPath = path.slice(0, path.length - 1)
const dataPath = toDataPath(data, parentPath)
const parent = getIn(data, dataPath)
const esonPath = toEsonPath(data, parentPath)
const parent = getIn(data, esonPath)
if (parent.type === 'Array') {
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
* and object property
*
* @param {JSONData} data
* @param {ESON} data
* @param {Path} path
* @param {JSONDataType} type
* @param {ESONType} type
* @return {Array}
*/
export function insert (data, path, type) {
// console.log('insert', path, type)
const parentPath = path.slice(0, path.length - 1)
const dataPath = toDataPath(data, parentPath)
const parent = getIn(data, dataPath)
const esonPath = toEsonPath(data, parentPath)
const parent = getIn(data, esonPath)
const value = createEntry(type)
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
* and object property
*
* @param {JSONData} data
* @param {ESON} data
* @param {Path} parentPath
* @param {JSONDataType} type
* @param {ESONType} type
* @return {Array}
*/
export function append (data, parentPath, type) {
// console.log('append', parentPath, value)
const dataPath = toDataPath(data, parentPath)
const parent = getIn(data, dataPath)
const esonPath = toEsonPath(data, parentPath)
const parent = getIn(data, esonPath)
const value = createEntry(type)
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
* or descending order
* @param {JSONData} data
* @param {ESON} data
* @param {Path} path
* @param {'asc' | 'desc' | null} [order=null] If not provided, will toggle current ordering
* @return {Array}
@ -234,8 +234,8 @@ export function sort (data, path, order = null) {
// console.log('sort', path, order)
const compare = order === 'desc' ? compareDesc : compareAsc
const dataPath = toDataPath(data, path)
const object = getIn(data, dataPath)
const esonPath = toEsonPath(data, path)
const object = getIn(data, esonPath)
if (object.type === 'Array') {
const orderedItems = object.items.slice(0)
@ -252,7 +252,7 @@ export function sort (data, path, order = null) {
return [{
op: 'replace',
path: compileJSONPointer(path),
value: dataToJson({
value: esonToJson({
type: 'Array',
items: orderedItems
})
@ -273,7 +273,7 @@ export function sort (data, path, order = null) {
return [{
op: 'replace',
path: compileJSONPointer(path),
value: dataToJson({
value: esonToJson({
type: 'Object',
props: orderedProps
}),
@ -286,7 +286,7 @@ export function sort (data, path, order = null) {
/**
* Create a JSON entry
* @param {JSONDataType} type
* @param {ESONType} type
* @return {Array | Object | string}
*/
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
* @param {*} value
* @param {JSONDataType} type
* @param {ESONType} type
* @return {*}
*/
export function convertType (value, type) {

View File

@ -6,9 +6,9 @@ import ActionMenu from './menu/ActionMenu'
import { escapeHTML, unescapeHTML } from '../utils/stringUtils'
import { getInnerText, insideRect, findParentWithAttribute } from '../utils/domUtils'
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 {
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
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'
if (!prop && !isIndex) {

View File

@ -2,7 +2,7 @@
import JSONNode from './JSONNode'
import type { PropertyData, JSONData, Path } from '../types'
import type { ESONObjectProperty, ESON, Path } from '../types'
/**
* JSONNodeForm
@ -22,7 +22,7 @@ export default class JSONNodeForm extends JSONNode {
}
// 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 })
return JSONNode.prototype.renderProperty.call(this, prop, index, data, formOptions)

View File

@ -5,8 +5,8 @@ import Ajv from 'ajv'
import { parseJSON } from '../utils/jsonUtils'
import { escapeUnicodeChars } from '../utils/stringUtils'
import { enrichSchemaError, limitErrors } from '../utils/schemaUtils'
import { jsonToData, dataToJson } from '../jsonData'
import { patchData } from '../jsonPatchData'
import { jsonToEson, esonToJson } from '../eson'
import { patchEson } from '../patchEson'
import { createFindKeyBinding } from '../utils/keyBindings'
import { KEY_BINDINGS } from '../constants'
@ -201,7 +201,7 @@ export default class TextMode extends Component {
// this is an ajv error message
return h('tr', { key: index }, [
h('td', {key: 'icon'}, icon),
h('td', {key: 'path'}, error.dataPath),
h('td', {key: 'path'}, error.esonPath),
h('td', {key: 'message'}, error.message)
])
}
@ -327,17 +327,17 @@ export default class TextMode extends Component {
/**
* Apply a JSONPatch to the current JSON document
* @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
* an error object which is null when successful
*/
patch (actions) {
const json = this.get()
const data = jsonToData(json)
const result = patchData(data, actions)
const data = jsonToEson(json)
const result = patchEson(data, actions)
this.set(dataToJson(result.data))
this.set(esonToJson(result.data))
return {
patch: actions,

View File

@ -9,12 +9,12 @@ import { parseJSON } from '../utils/jsonUtils'
import { allButLast } from '../utils/arrayUtils'
import { enrichSchemaError } from '../utils/schemaUtils'
import {
jsonToData, dataToJson, toDataPath, pathExists,
jsonToEson, esonToJson, toEsonPath, pathExists,
expand, expandPath, addErrors,
search, addSearchResults, nextSearchResult, previousSearchResult,
compileJSONPointer
} from '../jsonData'
import { patchData } from '../jsonPatchData'
} from '../eson'
import { patchEson } from '../patchEson'
import {
duplicate, insert, append, remove,
changeType, changeValue, changeProperty, sort
@ -31,7 +31,7 @@ import {
import { createFindKeyBinding } from '../utils/keyBindings'
import { KEY_BINDINGS } from '../constants'
import type { JSONData, JSONPatch } from '../types'
import type { ESON, ESONPatch } from '../types'
const AJV_OPTIONS = {
allErrors: true,
@ -64,7 +64,7 @@ export default class TreeMode extends Component {
constructor (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?
@ -270,7 +270,7 @@ export default class TreeMode extends Component {
*/
getErrors () {
if (this.state.compiledSchema) {
const valid = this.state.compiledSchema(dataToJson(this.state.data))
const valid = this.state.compiledSchema(esonToJson(this.state.data))
if (!valid) {
return this.state.compiledSchema.errors.map(enrichSchemaError)
}
@ -364,10 +364,10 @@ export default class TreeMode extends Component {
/** @private */
handleExpand = (path, expanded, recurse) => {
if (recurse) {
const dataPath = toDataPath(this.state.data, path)
const esonPath = toEsonPath(this.state.data, path)
this.setState({
data: updateIn(this.state.data, dataPath, function (child) {
data: updateIn(this.state.data, esonPath, function (child) {
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
* @param {JSONPatch} actions
* Apply a ESONPatch to the current JSON document and emit a change event
* @param {ESONPatch} actions
* @private
*/
handlePatch = (actions) => {
@ -504,13 +504,13 @@ export default class TreeMode extends Component {
* Emit an onChange event when there is a listener for it.
* @private
*/
emitOnChange (patch: JSONPatch, revert: JSONPatch, data: JSONData) {
emitOnChange (patch: ESONPatch, revert: ESONPatch, data: ESON) {
if (this.props.onPatch) {
this.props.onPatch(patch, revert)
}
if (this.props.onChange || this.props.onChangeText) {
const json = dataToJson(data)
const json = esonToJson(data)
if (this.props.onChange) {
this.props.onChange(json)
@ -539,7 +539,7 @@ export default class TreeMode extends Component {
const historyIndex = this.state.historyIndex
const historyItem = history[historyIndex]
const result = patchData(this.state.data, historyItem.undo)
const result = patchEson(this.state.data, historyItem.undo)
this.setState({
data: result.data,
@ -557,7 +557,7 @@ export default class TreeMode extends Component {
const historyIndex = this.state.historyIndex - 1
const historyItem = history[historyIndex]
const result = patchData(this.state.data, historyItem.redo)
const result = patchEson(this.state.data, historyItem.redo)
this.setState({
data: result.data,
@ -570,13 +570,13 @@ export default class TreeMode extends Component {
}
/**
* Apply a JSONPatch to the current JSON document
* @param {JSONPatch} actions JSONPatch actions
* @param {PatchOptions} [options] If no expand function is provided, the
* Apply a ESONPatch to the current JSON document
* @param {ESONPatch} actions ESONPatch actions
* @param {ESONPatchOptions} [options] If no expand function is provided, the
* expanded state will be kept as is for
* existing paths. New paths will be fully
* 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
* 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 result = patchData(this.state.data, actions, expand)
const result = patchEson(this.state.data, actions, expand)
const data = result.data
if (this.props.history != false) {
@ -629,7 +629,7 @@ export default class TreeMode extends Component {
const expand = this.props.expand || TreeMode.expandRoot
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)
history: [],
@ -642,7 +642,7 @@ export default class TreeMode extends Component {
* @returns {Object | Array | string | number | boolean | null} json
*/
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
*/
isExpanded (path) {
return getIn(this.state.data, toDataPath(this.state.data, path)).expanded
return getIn(this.state.data, toEsonPath(this.state.data, path)).expanded
}
/**

View File

@ -2,7 +2,7 @@ import {
selectContentEditable, hasClassName,
findParentWithAttribute, findParentWithClassName
} from '../../utils/domUtils'
import { compileJSONPointer, parseJSONPointer } from '../../jsonData'
import { compileJSONPointer, parseJSONPointer } from '../../eson'
// singleton
let lastInputName = null

View File

@ -1,8 +1,8 @@
// @flow weak
/**
* This file contains functions to act on a JSONData object.
* All functions are pure and don't mutate the JSONData.
* This file contains functions to act on a ESON object.
* All functions are pure and don't mutate the ESON.
*/
import { setIn, getIn } from './utils/immutabilityHelpers'
@ -10,9 +10,13 @@ import { isObject } from './utils/typeUtils'
import { last, allButLast } from './utils/arrayUtils'
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
@ -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 {function(path: Path)} [expand]
* @param {Path} [path=[]]
* @param {JSONDataType} [type='value'] Optional json data type for the created value
* @return {JSONData}
* @param {function(path: JSONPath)} [expand]
* @param {JSONPath} [path=[]]
* @param {ESONType} [type='value'] Optional eson type for the created value
* @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)) {
return {
type: 'Array',
@ -39,7 +43,7 @@ export function jsonToData (json, expand = expandAll, path = [], type = 'value')
items: json.map((child, index) => {
return {
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 {
id: getId(), // TODO: use id based on index (only has to be unique within this array)
name,
value: jsonToData(json[name], expand, path.concat(name))
value: jsonToEson(json[name], expand, path.concat(name))
}
})
}
}
else { // value
return {
type,
type: (type === 'string') ? 'string' : 'value',
value: json
}
}
}
/**
* Convert the internal data model to a regular JSON object
* @param {JSONData} data
* Convert an ESON object to a JSON object
* @param {ESON} eson
* @return {Object | Array | string | number | boolean | null} json
*/
export function dataToJson (data: JSONData) {
switch (data.type) {
export function esonToJson (eson: ESON) {
switch (eson.type) {
case 'Array':
return data.items.map(item => dataToJson(item.value))
return eson.items.map(item => esonToJson(item.value))
case 'Object':
const object = {}
data.props.forEach(prop => {
object[prop.name] = dataToJson(prop.value)
eson.props.forEach(prop => {
object[prop.name] = esonToJson(prop.value)
})
return object
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
* @param {JSONData} data
* @param {Path} path
* @return {Path} dataPath
* Convert a path of a JSON object into a path in the corresponding ESON object
* @param {ESON} eson
* @param {JSONPath} path
* @return {ESONPath} esonPath
* @private
*/
export function toDataPath (data: JSONData, path: Path) : Path {
export function toEsonPath (eson: ESON, path: JSONPath) : ESONPath {
if (path.length === 0) {
return []
}
if (data.type === 'Array') {
if (eson.type === 'Array') {
// index of an array
const index = path[0]
const item = data.items[parseInt(index)]
const item = eson.items[parseInt(index)]
if (!item) {
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
const index = findPropertyIndex(data, path[0])
const prop = data.props[index]
const index = findPropertyIndex(eson, path[0])
const prop = eson.props[index]
if (!prop) {
throw new Error('Object property "' + path[0] + '" not found')
}
return ['props', index, 'value']
.concat(toDataPath(prop.value, path.slice(1)))
.concat(toEsonPath(prop.value, path.slice(1)))
}
else {
return []
@ -131,19 +135,19 @@ type ExpandCallback = (Path) => boolean
/**
* Expand or collapse one or multiple items or properties
* @param {JSONData} data
* @param {ESON} eson
* @param {function(path: Path) : boolean | Path} callback
* When a path, the object/array at this path will be expanded/collapsed
* When a function, all objects and arrays for which callback
* returns true will be expanded/collapsed
* @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)
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 (callback(path)) {
return setIn(value, ['expanded'], expanded)
@ -154,9 +158,9 @@ export function expand (data: JSONData, callback: Path | (Path) => boolean, expa
})
}
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 {
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
*/
export function expandPath (data: JSONData, path?: Path) : JSONData {
let updatedData = data
export function expandPath (eson: ESON, path?: JSONPath) : ESON {
let updatedEson = eson
if (path) {
updatedData = expand(updatedData, [], true) // expand root
updatedEson = expand(updatedEson, [], true) // expand root
for (let i = 0; i < path.length; i++) {
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)
* into the data
* Merge one or multiple errors (for example JSON schema errors) into the ESON object
*
* @param {JSONData} data
* @param {ESON} eson
* @param {JSONSchemaError[]} errors
*/
export function addErrors (data: JSONData, errors) {
let updatedData = data
export function addErrors (eson: ESON, errors) {
let updatedEson = eson
if (errors) {
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?
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
*/
export function search (data: JSONData, text: string): DataPointer[] {
let results: DataPointer[] = []
export function search (eson: ESON, text: string): ESONPointer[] {
let results: ESONPointer[] = []
if (text !== '') {
traverse(data, function (value, path) {
traverse(eson, function (value, path: JSONPath) {
// check property name
if (path.length > 0) {
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,
// don't add search result for array indices
const parentPath = allButLast(path)
const parent = getIn(data, toDataPath(data, parentPath))
const parent = getIn(eson, toEsonPath(eson, parentPath))
if (parent.type === 'Object') {
results.push({path, type: 'property'})
}
@ -244,7 +247,7 @@ export function search (data: JSONData, text: string): DataPointer[] {
* returned as next
* - 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) {
return null
}
@ -268,7 +271,7 @@ export function nextSearchResult (searchResults: DataPointer[], current: DataPoi
* returned as next
* - 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) {
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) {
let updatedData = data
export function addSearchResults (eson: ESON, searchResults: ESONPointer[], activeSearchResult: ESONPointer) {
let updatedEson = eson
searchResults.forEach(function (searchResult) {
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'
updatedData = setIn(updatedData, dataPath, value)
updatedEson = setIn(updatedEson, esonPath, value)
}
if (searchResult.type === 'property') {
const valueDataPath = toDataPath(data, searchResult.path)
const propertyDataPath = allButLast(valueDataPath).concat('searchResult')
const esonPath = toEsonPath(updatedEson, searchResult.path)
const propertyPath = allButLast(esonPath).concat('searchResult')
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
* @param {JSONData} data
* @param {function(value: JSONData, path: Path, root: JSONData)} callback
* @return {JSONData} Returns the transformed data
* Recursively transform ESON: a recursive "map" function
* @param {ESON} eson
* @param {function(value: ESON, path: Path, root: ESON)} callback
* @return {ESON} Returns the transformed eson object
*/
export function transform (data: JSONData, callback: RecurseCallback) {
return recurseTransform (data, [], data, callback)
export function transform (eson: ESON, callback: RecurseCallback) : ESON {
return recurseTransform (eson, [], eson, callback)
}
/**
* Recursively transform JSONData
* @param {JSONData} value
* @param {Path} path
* @param {JSONData} root The root object, object at path=[]
* @param {function(value: JSONData, path: Path, root: JSONData)} callback
* @return {JSONData} Returns the transformed data
* Recursively transform ESON
* @param {ESON} value
* @param {JSONPath} path
* @param {ESON} root The root object, object at path=[]
* @param {function(value: ESON, path: Path, root: ESON)} callback
* @return {ESON} Returns the transformed eson object
*/
function recurseTransform (value: JSONData, path: Path, root: JSONData, callback: RecurseCallback) : JSONData {
let updatedValue = callback(value, path, root)
function recurseTransform (value: ESON, path: JSONPath, root: ESON, callback: RecurseCallback) : ESON {
let updatedValue: ESON = callback(value, path, root)
if (value.type === 'Array') {
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.
* @param {JSONData} data
* @param {function(value: JSONData, path: Path, root: JSONData)} callback
* Recursively loop over a ESON object: a recursive "forEach" function.
* @param {ESON} eson
* @param {function(value: ESON, path: JSONPath, root: ESON)} callback
*/
export function traverse (data: JSONData, callback: RecurseCallback) {
return recurseTraverse (data, [], data, callback)
export function traverse (eson: ESON, callback: RecurseCallback) {
return recurseTraverse (eson, [], eson, callback)
}
/**
* Recursively traverse a JSONData object
* @param {JSONData} value
* @param {Path} path
* @param {JSONData | null} root The root object, object at path=[]
* @param {function(value: JSONData, path: Path, root: JSONData)} callback
* Recursively traverse a ESON object
* @param {ESON} value
* @param {JSONPath} path
* @param {ESON | null} root The root object, object at path=[]
* @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)
switch (value.type) {
case 'Array': {
value.items.forEach((item: ItemData, index) => {
value.items.forEach((item: ESONArrayItem, index) => {
recurseTraverse(item.value, path.concat(String(index)), root, callback)
})
break
@ -406,14 +409,14 @@ function recurseTraverse (value: JSONData, path: Path, root: JSONData, callback:
}
/**
* Test whether a path exists in the json data
* @param {JSONData} data
* @param {Path} path
* Test whether a path exists in the eson object
* @param {ESON} eson
* @param {JSONPath} path
* @return {boolean} Returns true if the path exists, else returns false
* @private
*/
export function pathExists (data, path) {
if (data === undefined) {
export function pathExists (eson, path) {
if (eson === undefined) {
return false
}
@ -421,18 +424,17 @@ export function pathExists (data, path) {
return true
}
let index
if (data.type === 'Array') {
if (eson.type === 'Array') {
// index of an array
index = path[0]
const item = data.items[index]
const index = path[0]
const item = eson.items[index]
return pathExists(item && item.value, path.slice(1))
}
else {
// object property. find the index of this property
index = findPropertyIndex(data, path[0])
const prop = data.props[index]
const index = findPropertyIndex(eson, path[0])
const prop = eson.props[index]
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
* length of the array
* @param {JSONData} data
* @param {ESON} eson
* @param {Path} path
* @return {Path}
*/
export function resolvePathIndex (data, path) {
export function resolvePathIndex (eson, path) {
if (path[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') {
const index = parent.items.length
@ -464,12 +466,12 @@ export function resolvePathIndex (data, path) {
/**
* Find the property after provided property
* @param {JSONData} parent
* @param {ESON} parent
* @param {string} prop
* @return {string | null} Returns the name of the next property,
* 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)
if (index === -1) {
return null
@ -481,14 +483,16 @@ export function findNextProp (parent: ObjectData, prop: string) : string | null
/**
* Find the index of a property
* @param {ObjectData} object
* @param {ESONObject} object
* @param {string} prop
* @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)
}
// TODO: move parseJSONPointer and compileJSONPointer to a separate file
/**
* Parse a JSON Pointer
* WARNING: this is not a complete implementation
@ -514,6 +518,8 @@ export function compileJSONPointer (path: Path) {
.join('')
}
// TODO: move getId and createUniqueId to a separate file
/**
* Get a new "unique" id. Id's are created from an incremental counter.
* @return {number}

View File

@ -4,7 +4,7 @@ import JSONEditor from './components/JSONEditor'
import CodeMode from './components/CodeMode'
import TextMode from './components/TextMode'
import TreeMode from './components/TreeMode'
import { compileJSONPointer, parseJSONPointer } from './jsonData'
import { compileJSONPointer, parseJSONPointer } from './eson'
import '!style!css!less!./jsoneditor.less'

View File

@ -1,27 +1,24 @@
import isEqual from 'lodash/isEqual'
import type {
JSONData, Path,
JSONPatch, JSONPatchAction, PatchOptions, JSONPatchResult
} from './types'
import type { ESON, Path, JSONPatch, ESONPatchAction, ESONPatchOptions, ESONPatchResult } from './types'
import { setIn, updateIn, getIn, deleteIn, insertAt } from './utils/immutabilityHelpers'
import { allButLast } from './utils/arrayUtils'
import {
jsonToData, dataToJson, toDataPath,
jsonToEson, esonToJson, toEsonPath,
parseJSONPointer, compileJSONPointer,
expandAll, pathExists, resolvePathIndex, findPropertyIndex, findNextProp, getId
} from './jsonData'
} from './eson'
/**
* Apply a patch to a JSONData object
* @param {JSONData} data
* Apply a patch to a ESON object
* @param {ESON} eson
* @param {Array} patch A JSON patch
* @param {function(path: Path)} [expand] Optional function to determine
* 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) {
let updatedData = data
export function patchEson (eson: ESON, patch: ESONPatchAction[], expand = expandAll) {
let updatedEson = eson
let revert = []
for (let i = 0; i < patch.length; i++) {
@ -33,17 +30,17 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
switch (action.op) {
case 'add': {
const path = parseJSONPointer(action.path)
const newValue = jsonToData(action.value, expand, path, options && options.type)
const result = add(updatedData, action.path, newValue, options)
updatedData = result.data
const newValue = jsonToEson(action.value, expand, path, options && options.type)
const result = add(updatedEson, action.path, newValue, options)
updatedEson = result.data
revert = result.revert.concat(revert)
break
}
case 'remove': {
const result = remove(updatedData, action.path)
updatedData = result.data
const result = remove(updatedEson, action.path)
updatedEson = result.data
revert = result.revert.concat(revert)
break
@ -51,9 +48,9 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
case 'replace': {
const path = parseJSONPointer(action.path)
const newValue = jsonToData(action.value, expand, path, options && options.type)
const result = replace(updatedData, path, newValue)
updatedData = result.data
const newValue = jsonToEson(action.value, expand, path, options && options.type)
const result = replace(updatedEson, path, newValue)
updatedEson = result.data
revert = result.revert.concat(revert)
break
@ -62,14 +59,14 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
case 'copy': {
if (!action.from) {
return {
data,
data: eson,
revert: [],
error: new Error('Property "from" expected in copy action ' + JSON.stringify(action))
}
}
const result = copy(updatedData, action.path, action.from, options)
updatedData = result.data
const result = copy(updatedEson, action.path, action.from, options)
updatedEson = result.data
revert = result.revert.concat(revert)
break
@ -78,14 +75,14 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
case 'move': {
if (!action.from) {
return {
data,
data: eson,
revert: [],
error: new Error('Property "from" expected in move action ' + JSON.stringify(action))
}
}
const result = move(updatedData, action.path, action.from, options)
updatedData = result.data
const result = move(updatedEson, action.path, action.from, options)
updatedEson = result.data
revert = result.revert.concat(revert)
break
@ -93,9 +90,9 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
case 'test': {
// 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) {
return { data, revert: [], error}
return { data: eson, revert: [], error}
}
break
@ -104,7 +101,7 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
default: {
// unknown jsonpatch operation. Cancel the whole patch and return an error
return {
data,
data: eson,
revert: [],
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:
// when a previous action takes place on the same path, remove the first
return {
data: updatedData,
data: updatedEson,
revert: simplifyPatch(revert),
error: null
}
@ -123,21 +120,21 @@ export function patchData (data: JSONData, patch: JSONPatchAction[], expand = ex
/**
* Replace an existing item
* @param {JSONData} data
* @param {ESON} data
* @param {Path} path
* @param {JSONData} value
* @return {{data: JSONData, revert: JSONPatch}}
* @param {ESON} value
* @return {{data: ESON, revert: JSONPatch}}
*/
export function replace (data: JSONData, path: Path, value: JSONData) {
const dataPath = toDataPath(data, path)
const oldValue = getIn(data, dataPath)
export function replace (data: ESON, path: Path, value: ESON) {
const esonPath = toEsonPath(data, path)
const oldValue = getIn(data, esonPath)
return {
data: setIn(data, dataPath, value),
data: setIn(data, esonPath, value),
revert: [{
op: 'replace',
path: compileJSONPointer(path),
value: dataToJson(oldValue),
value: esonToJson(oldValue),
jsoneditor: {
type: oldValue.type
}
@ -147,27 +144,27 @@ export function replace (data: JSONData, path: Path, value: JSONData) {
/**
* Remove an item or property
* @param {JSONData} data
* @param {ESON} data
* @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)
const pathArray = parseJSONPointer(path)
const parentPath = pathArray.slice(0, pathArray.length - 1)
const parent = getIn(data, toDataPath(data, parentPath))
const dataValue = getIn(data, toDataPath(data, pathArray))
const value = dataToJson(dataValue)
const parent = getIn(data, toEsonPath(data, parentPath))
const dataValue = getIn(data, toEsonPath(data, pathArray))
const value = esonToJson(dataValue)
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
dataPath.pop()
esonPath.pop()
return {
data: deleteIn(data, dataPath),
data: deleteIn(data, esonPath),
revert: [{
op: 'add',
path,
@ -179,14 +176,14 @@ export function remove (data: JSONData, path: string) {
}
}
else { // object.type === 'Object'
const dataPath = toDataPath(data, pathArray)
const esonPath = toEsonPath(data, pathArray)
const prop = pathArray[pathArray.length - 1]
// remove the 'value' property, we want to remove the whole object property from props
dataPath.pop()
esonPath.pop()
return {
data: deleteIn(data, dataPath),
data: deleteIn(data, esonPath),
revert: [{
op: 'add',
path,
@ -233,32 +230,32 @@ export function simplifyPatch(patch: JSONPatch) {
/**
* @param {JSONData} data
* @param {ESON} data
* @param {string} path
* @param {JSONData} value
* @param {ESON} value
* @param {{before?: string}} [options]
* @param {number} [id] Optional id for the new item
* @return {{data: JSONData, revert: JSONPatch}}
* @return {{data: ESON, revert: JSONPatch}}
* @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 parentPath = pathArray.slice(0, pathArray.length - 1)
const dataPath = toDataPath(data, parentPath)
const parent = getIn(data, dataPath)
const esonPath = toEsonPath(data, parentPath)
const parent = getIn(data, esonPath)
const resolvedPath = resolvePathIndex(data, pathArray)
const prop = resolvedPath[resolvedPath.length - 1]
let updatedData
let updatedEson
if (parent.type === 'Array') {
const newItem = {
id, // TODO: create a unique id within current id's instead of using a global, ever incrementing id
value
}
updatedData = insertAt(data, dataPath.concat('items', prop), newItem)
updatedEson = insertAt(data, esonPath.concat('items', prop), newItem)
}
else { // parent.type === 'Object'
updatedData = updateIn(data, dataPath, (object) => {
updatedEson = updateIn(data, esonPath, (object) => {
const existingIndex = findPropertyIndex(object, prop)
if (existingIndex !== -1) {
// 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)) {
const oldValue = getIn(data, toDataPath(data, resolvedPath))
const oldValue = getIn(data, toEsonPath(data, resolvedPath))
return {
data: updatedData,
data: updatedEson,
revert: [{
op: 'replace',
path: compileJSONPointer(resolvedPath),
value: dataToJson(oldValue),
value: esonToJson(oldValue),
jsoneditor: { type: oldValue.type }
}]
}
}
else {
return {
data: updatedData,
data: updatedEson,
revert: [{
op: 'remove',
path: compileJSONPointer(resolvedPath)
@ -302,37 +299,37 @@ export function add (data: JSONData, path: string, value: JSONData, options, id
/**
* Copy a value
* @param {JSONData} data
* @param {ESON} data
* @param {string} path
* @param {string} from
* @param {{before?: string}} [options]
* @return {{data: JSONData, revert: JSONPatch}}
* @return {{data: ESON, revert: JSONPatch}}
* @private
*/
export function copy (data: JSONData, path: string, from: string, options) {
const value = getIn(data, toDataPath(data, parseJSONPointer(from)))
export function copy (data: ESON, path: string, from: string, options) {
const value = getIn(data, toEsonPath(data, parseJSONPointer(from)))
return add(data, path, value, options)
}
/**
* Move a value
* @param {JSONData} data
* @param {ESON} data
* @param {string} path
* @param {string} from
* @param {{before?: string}} [options]
* @return {{data: JSONData, revert: JSONPatch}}
* @return {{data: ESON, revert: JSONPatch}}
* @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 prop = getIn(data, allButLast(toDataPath(data, fromArray)))
const prop = getIn(data, allButLast(toEsonPath(data, fromArray)))
const dataValue = prop.value
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
const parentPathFrom = allButLast(fromArray)
const parent = getIn(data, toDataPath(data, parentPathFrom))
const parent = getIn(data, toEsonPath(data, parentPathFrom))
const result1 = remove(data, from)
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.
* Throws an error when the test fails.
* @param {JSONData} data
* @param {ESON} data
* @param {string} path
* @param {*} value
* @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) {
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')
}
const actualValue = getIn(data, toDataPath(data, pathArray))
if (!isEqual(dataToJson(actualValue), value)) {
const actualValue = getIn(data, toEsonPath(data, pathArray))
if (!isEqual(esonToJson(actualValue), value)) {
return new Error('Test failed, value differs')
}
}

View File

@ -25,59 +25,60 @@
/**************************** GENERIC JSON TYPES ******************************/
export type JSONType = | string | number | boolean | null | JSONObjectType | JSONArrayType;
export type JSONObjectType = { [key:string]: JSONType };
export type JSONArrayType = Array<JSONType>;
export type JSONType = | string | number | boolean | null | JSONObjectType | JSONArrayType
export type JSONObjectType = { [key:string]: JSONType }
export type JSONArrayType = JSONType[]
/********************** TYPES FOR THE JSON DATA MODEL *************************/
/********************** TYPES FOR THE ESON OBJECT MODEL *************************/
export type SearchResultStatus = 'normal' | 'active'
export type DataPointerType = 'value' | 'property'
export type ESONPointerType = 'value' | 'property'
export type PropertyData = {
export type ESONObjectProperty = {
id: number,
name: string,
value: JSONData,
value: ESON,
searchResult?: SearchResultStatus
}
export type ItemData = {
export type ESONArrayItem = {
id: number,
value: JSONData
value: ESON
}
export type ObjectData = {
export type ESONObject = {
type: 'Object',
expanded?: boolean,
props: PropertyData[]
props: ESONObjectProperty[]
}
export type ArrayData = {
export type ESONArray = {
type: 'Array',
expanded?: boolean,
items: ItemData[]
items: ESONArrayItem[]
}
export type ValueData = {
export type ESONValue = {
type: 'value' | 'string',
value?: any,
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 Path = string[]
export type DataPointer = {
path: Path,
type: DataPointerType
export type ESONPointer = {
path: ESONPath,
type: ESONPointerType
}
// 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)
@ -85,27 +86,27 @@ export type SetOptions = {
expand?: (path: Path) => boolean
}
export type JSONPatchAction = {
export type ESONPatchAction = {
op: string, // TODO: define allowed ops
path: string,
from?: string,
value?: any,
jsoneditor?: PatchOptions
jsoneditor?: ESONPatchOptions
}
export type JSONPatch = JSONPatchAction[]
export type ESONPatch = ESONPatchAction[]
export type PatchOptions = {
type: JSONDataType,
export type ESONPatchOptions = {
type: ESONType,
expand: (Path) => boolean
}
export type JSONPatchResult = {
patch: JSONPatch,
revert: JSONPatch,
export type ESONPatchResult = {
patch: ESONPatch,
revert: ESONPatch,
error: null | Error
}
export type JSONSchemaError = {
dataPath: string,
path: string, // TODO: change type to JSONPath
message: string
}

View File

@ -1,9 +1,9 @@
import test from 'ava';
import {
jsonToData, dataToJson, pathExists, transform, traverse,
jsonToEson, esonToJson, pathExists, transform, traverse,
parseJSONPointer, compileJSONPointer,
expand, addErrors, search, addSearchResults, nextSearchResult, previousSearchResult
} from '../src/jsonData'
} from '../src/eson'
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
const JSON_DATA_EXAMPLE_COLLAPSED_1 = {
@ -426,8 +451,8 @@ const JSON_DATA_SMALL = {
const JSON_SCHEMA_ERRORS = [
{dataPath: '/obj/arr/2/last', message: 'String expected'},
{dataPath: '/nill', message: 'Null expected'}
{esonPath: '/obj/arr/2/last', message: 'String expected'},
{esonPath: '/nill', message: 'Null expected'}
]
const JSON_DATA_EXAMPLE_ERRORS = {
@ -522,19 +547,19 @@ const JSON_DATA_EXAMPLE_ERRORS = {
]
}
test('jsonToData', t => {
test('jsonToEson', t => {
function expand (path) {
return true
}
const jsonData = jsonToData(JSON_EXAMPLE, expand, [])
replaceIds(jsonData)
const ESON = jsonToEson(JSON_EXAMPLE, expand, [])
replaceIds(ESON)
t.deepEqual(jsonData, JSON_DATA_EXAMPLE)
t.deepEqual(ESON, JSON_DATA_EXAMPLE)
})
test('dataToJson', t => {
t.deepEqual(dataToJson(JSON_DATA_EXAMPLE), JSON_EXAMPLE)
test('esonToJson', t => {
t.deepEqual(esonToJson(JSON_DATA_EXAMPLE), JSON_EXAMPLE)
})
test('expand a single path', t => {

View File

@ -1,6 +1,6 @@
import test from 'ava';
import { jsonToData, dataToJson } from '../src/jsonData'
import { patchData } from '../src/jsonPatchData'
import { jsonToEson, esonToJson } from '../src/eson'
import { patchEson } from '../src/patchEson'
test('jsonpatch add', t => {
const json = {
@ -12,11 +12,11 @@ test('jsonpatch add', t => {
{op: 'add', path: '/obj/b', value: {foo: 'bar'}}
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.deepEqual(patchedJson, {
arr: [1,2,3],
@ -37,11 +37,11 @@ test('jsonpatch add: append to matrix', t => {
{op: 'add', path: '/arr/-', value: 4}
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.deepEqual(patchedJson, {
arr: [1,2,3,4],
@ -64,11 +64,11 @@ test('jsonpatch remove', t => {
{op: 'remove', path: '/arr/1'},
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.deepEqual(patchedJson, {
arr: [1,3],
@ -80,11 +80,11 @@ test('jsonpatch remove', t => {
])
// test revert
const data2 = jsonToData(patchedJson)
const result2 = patchData(data2, revert)
const data2 = jsonToEson(patchedJson)
const result2 = patchEson(data2, revert)
const patchedData2 = result2.data
const revert2 = result2.revert
const patchedJson2 = dataToJson(patchedData2)
const patchedJson2 = esonToJson(patchedData2)
t.deepEqual(patchedJson2, json)
t.deepEqual(revert2, patch)
@ -101,11 +101,11 @@ test('jsonpatch replace', t => {
{op: 'replace', path: '/arr/1', value: 200},
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.deepEqual(patchedJson, {
arr: [1,200,3],
@ -117,11 +117,11 @@ test('jsonpatch replace', t => {
])
// test revert
const data2 = jsonToData(patchedJson)
const result2 = patchData(data2, revert)
const data2 = jsonToEson(patchedJson)
const result2 = patchEson(data2, revert)
const patchedData2 = result2.data
const revert2 = result2.revert
const patchedJson2 = dataToJson(patchedData2)
const patchedJson2 = esonToJson(patchedData2)
t.deepEqual(patchedJson2, json)
t.deepEqual(revert2, [
@ -136,10 +136,10 @@ test('jsonpatch replace (keep ids intact)', t => {
{op: 'replace', path: '/value', value: 100}
]
const data = jsonToData(json)
const data = jsonToEson(json)
const valueId = data.props[0].id
const patchedData = patchData(data, patch).data
const patchedData = patchEson(data, patch).data
const patchedValueId = patchedData.props[0].id
t.is(patchedValueId, valueId)
@ -155,11 +155,11 @@ test('jsonpatch copy', t => {
{op: 'copy', from: '/obj', path: '/arr/2'},
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.deepEqual(patchedJson, {
arr: [1, 2, {a:4}, 3],
@ -170,11 +170,11 @@ test('jsonpatch copy', t => {
])
// test revert
const data2 = jsonToData(patchedJson)
const result2 = patchData(data2, revert)
const data2 = jsonToEson(patchedJson)
const result2 = patchEson(data2, revert)
const patchedData2 = result2.data
const revert2 = result2.revert
const patchedJson2 = dataToJson(patchedData2)
const patchedJson2 = esonToJson(patchedData2)
t.deepEqual(patchedJson2, json)
t.deepEqual(revert2, [
@ -188,11 +188,11 @@ test('jsonpatch copy (keeps the same ids)', t => {
{op: 'copy', from: '/foo', path: '/copied'}
]
const data = jsonToData(json)
const data = jsonToEson(json)
const fooId = data.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 patchedBarId = patchedData.props[0].value.props[0].id
const copiedId = patchedData.props[1].id
@ -221,11 +221,11 @@ test('jsonpatch move', t => {
{op: 'move', from: '/obj', path: '/arr/2'},
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.is(result.error, null)
t.deepEqual(patchedJson, {
@ -236,11 +236,11 @@ test('jsonpatch move', t => {
])
// test revert
const data2 = jsonToData(patchedJson)
const result2 = patchData(data2, revert)
const data2 = jsonToEson(patchedJson)
const result2 = patchEson(data2, revert)
const patchedData2 = result2.data
const revert2 = result2.revert
const patchedJson2 = dataToJson(patchedData2)
const patchedJson2 = esonToJson(patchedData2)
t.deepEqual(patchedJson2, json)
t.deepEqual(revert2, patch)
@ -257,11 +257,11 @@ test('jsonpatch move before', t => {
{op: 'move', from: '/obj', path: '/arr/2'},
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.is(result.error, null)
t.deepEqual(patchedJson, {
@ -273,11 +273,11 @@ test('jsonpatch move before', t => {
])
// test revert
const data2 = jsonToData(patchedJson)
const result2 = patchData(data2, revert)
const data2 = jsonToEson(patchedJson)
const result2 = patchEson(data2, revert)
const patchedData2 = result2.data
const revert2 = result2.revert
const patchedJson2 = dataToJson(patchedData2)
const patchedJson2 = esonToJson(patchedData2)
t.deepEqual(patchedJson2, json)
t.deepEqual(revert2, patch)
@ -290,12 +290,12 @@ test('jsonpatch move and replace', t => {
{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 revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
// id of the replaced B must be kept intact
t.is(patchedData.props[0].id, data.props[1].id)
@ -323,11 +323,11 @@ test('jsonpatch move and replace', t => {
])
// test revert
const data2 = jsonToData(patchedJson)
const result2 = patchData(data2, revert)
const data2 = jsonToEson(patchedJson)
const result2 = patchEson(data2, revert)
const patchedData2 = result2.data
const revert2 = result2.revert
const patchedJson2 = dataToJson(patchedData2)
const patchedJson2 = esonToJson(patchedData2)
t.deepEqual(patchedJson2, json)
t.deepEqual(revert2, [
@ -345,11 +345,11 @@ test('jsonpatch move and replace (nested)', t => {
{op: 'move', from: '/obj', path: '/arr'},
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.deepEqual(patchedJson, {
arr: {a:4}
@ -360,11 +360,11 @@ test('jsonpatch move and replace (nested)', t => {
])
// test revert
const data2 = jsonToData(patchedJson)
const result2 = patchData(data2, revert)
const data2 = jsonToEson(patchedJson)
const result2 = patchEson(data2, revert)
const patchedData2 = result2.data
const revert2 = result2.revert
const patchedJson2 = dataToJson(patchedData2)
const patchedJson2 = esonToJson(patchedData2)
t.deepEqual(patchedJson2, json)
t.deepEqual(revert2, [
@ -378,10 +378,10 @@ test('jsonpatch move (keep id intact)', t => {
{op: 'move', from: '/value', path: '/moved'}
]
const data = jsonToData(json)
const data = jsonToEson(json)
const valueId = data.props[0].id
const patchedData = patchData(data, patch).data
const patchedData = patchEson(data, patch).data
const patchedValueId = patchedData.props[0].id
t.is(patchedValueId, valueId)
@ -393,13 +393,13 @@ test('jsonpatch move and replace (keep ids intact)', t => {
{op: 'move', from: '/a', path: '/b'}
]
const data = jsonToData(json)
const data = jsonToEson(json)
const bId = data.props[1].id
t.is(data.props[0].name, 'a')
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].id, bId)
@ -416,11 +416,11 @@ test('jsonpatch test (ok)', t => {
{op: 'add', path: '/added', value: 'ok'}
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
t.deepEqual(patchedJson, {
arr: [1,2,3],
@ -444,11 +444,11 @@ test('jsonpatch test (fail: path not found)', t => {
{op: 'add', path: '/added', value: 'ok'}
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
// patch shouldn't be applied
t.deepEqual(patchedJson, {
@ -470,11 +470,11 @@ test('jsonpatch test (fail: value not equal)', t => {
{op: 'add', path: '/added', value: 'ok'}
]
const data = jsonToData(json)
const result = patchData(data, patch)
const data = jsonToEson(json)
const result = patchEson(data, patch)
const patchedData = result.data
const revert = result.revert
const patchedJson = dataToJson(patchedData)
const patchedJson = esonToJson(patchedData)
// patch shouldn't be applied
t.deepEqual(patchedJson, {

View File

@ -64,7 +64,7 @@ describe('util', function () {
});
describe('jsonPath', function () {
describe('path', function () {
it ('should parse a json path', function () {
assert.deepEqual(util.parsePath(''), []);