From 432e169f326a078a0a3134b573bd88d166977528 Mon Sep 17 00:00:00 2001 From: jos Date: Fri, 8 Sep 2017 13:36:15 +0200 Subject: [PATCH] Renamed 'jsonData' to 'ESON' --- src/actions.js | 58 ++--- src/components/JSONNode.js | 6 +- src/components/JSONNodeForm.js | 4 +- src/components/TextMode.js | 14 +- src/components/TreeMode.js | 44 ++-- src/components/utils/domSelector.js | 2 +- src/{jsonData.js => eson.js} | 228 +++++++++--------- src/index.js | 2 +- src/{jsonPatchData.js => patchEson.js} | 147 ++++++----- src/types.js | 65 ++--- test/{jsonData.test.js => eson.test.js} | 45 +++- ...sonPatchData.test.js => patchEson.test.js} | 134 +++++----- test/util.test.bak.js | 2 +- 13 files changed, 390 insertions(+), 361 deletions(-) rename src/{jsonData.js => eson.js} (63%) rename src/{jsonPatchData.js => patchEson.js} (70%) rename test/{jsonData.test.js => eson.test.js} (95%) rename test/{jsonPatchData.test.js => patchEson.test.js} (76%) diff --git a/src/actions.js b/src/actions.js index 07df352..409779b 100644 --- a/src/actions.js +++ b/src/actions.js @@ -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) { diff --git a/src/components/JSONNode.js b/src/components/JSONNode.js index 75dc4b0..bdeb5f5 100644 --- a/src/components/JSONNode.js +++ b/src/components/JSONNode.js @@ -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) { diff --git a/src/components/JSONNodeForm.js b/src/components/JSONNodeForm.js index 77552b4..2a67aa3 100644 --- a/src/components/JSONNodeForm.js +++ b/src/components/JSONNodeForm.js @@ -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) diff --git a/src/components/TextMode.js b/src/components/TextMode.js index 2a47807..264a03a 100644 --- a/src/components/TextMode.js +++ b/src/components/TextMode.js @@ -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, diff --git a/src/components/TreeMode.js b/src/components/TreeMode.js index 24d8af7..6bf7f14 100644 --- a/src/components/TreeMode.js +++ b/src/components/TreeMode.js @@ -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 } /** diff --git a/src/components/utils/domSelector.js b/src/components/utils/domSelector.js index 17cd28e..b971772 100644 --- a/src/components/utils/domSelector.js +++ b/src/components/utils/domSelector.js @@ -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 diff --git a/src/jsonData.js b/src/eson.js similarity index 63% rename from src/jsonData.js rename to src/eson.js index 9e49154..33d72d0 100644 --- a/src/jsonData.js +++ b/src/eson.js @@ -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} diff --git a/src/index.js b/src/index.js index cb1e2f4..4ca6164 100644 --- a/src/index.js +++ b/src/index.js @@ -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' diff --git a/src/jsonPatchData.js b/src/patchEson.js similarity index 70% rename from src/jsonPatchData.js rename to src/patchEson.js index 308d2fc..d9ee192 100644 --- a/src/jsonPatchData.js +++ b/src/patchEson.js @@ -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') } } diff --git a/src/types.js b/src/types.js index c599c5d..dd92f1f 100644 --- a/src/types.js +++ b/src/types.js @@ -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; +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 } diff --git a/test/jsonData.test.js b/test/eson.test.js similarity index 95% rename from test/jsonData.test.js rename to test/eson.test.js index 010b649..5691501 100644 --- a/test/jsonData.test.js +++ b/test/eson.test.js @@ -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 => { diff --git a/test/jsonPatchData.test.js b/test/patchEson.test.js similarity index 76% rename from test/jsonPatchData.test.js rename to test/patchEson.test.js index de4f338..322dd3f 100644 --- a/test/jsonPatchData.test.js +++ b/test/patchEson.test.js @@ -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, { diff --git a/test/util.test.bak.js b/test/util.test.bak.js index 85e743d..fbeaff5 100644 --- a/test/util.test.bak.js +++ b/test/util.test.bak.js @@ -64,7 +64,7 @@ describe('util', function () { }); - describe('jsonPath', function () { + describe('path', function () { it ('should parse a json path', function () { assert.deepEqual(util.parsePath(''), []);