Renamed keys to props in ESON model

This commit is contained in:
jos 2017-12-15 21:02:17 +01:00
parent 1a6661fbb5
commit 7064578b31
7 changed files with 56 additions and 71 deletions

View File

@ -45,7 +45,7 @@ export function changeProperty (eson, parentPath, oldProp, newProp) {
const parent = getIn(eson, parentPath) const parent = getIn(eson, parentPath)
// prevent duplicate property names // prevent duplicate property names
const uniqueNewProp = findUniqueName(newProp, parent[META].keys) const uniqueNewProp = findUniqueName(newProp, parent[META].props)
return [{ return [{
op: 'move', op: 'move',
@ -110,11 +110,11 @@ export function duplicate (eson, selection) {
})) }))
} }
else { // object.type === 'Object' else { // object.type === 'Object'
const before = root[META].keys[maxIndex] || null const before = root[META].props[maxIndex] || null
return paths.map(path => { return paths.map(path => {
const prop = last(path) const prop = last(path)
const newProp = findUniqueName(prop, root[META].keys) const newProp = findUniqueName(prop, root[META].props)
return { return {
op: 'copy', op: 'copy',
@ -158,7 +158,7 @@ export function insertBefore (eson, path, values) { // TODO: find a better name
else { // object.type === 'Object' else { // object.type === 'Object'
const before = last(path) const before = last(path)
return values.map(entry => { return values.map(entry => {
const newProp = findUniqueName(entry.name, parent[META].keys) const newProp = findUniqueName(entry.name, parent[META].props)
return { return {
op: 'add', op: 'add',
path: compileJSONPointer(parentPath.concat(newProp)), path: compileJSONPointer(parentPath.concat(newProp)),
@ -203,11 +203,11 @@ export function replace (eson, selection, values) { // TODO: find a better name
return removeActions.concat(insertActions) return removeActions.concat(insertActions)
} }
else { // object.type === 'Object' else { // object.type === 'Object'
const before = root[META].keys[maxIndex] || null const before = root[META].props[maxIndex] || null
const removeActions = removeAll(pathsFromSelection(eson, selection)) const removeActions = removeAll(pathsFromSelection(eson, selection))
const insertActions = values.map(entry => { const insertActions = values.map(entry => {
const newProp = findUniqueName(entry.name, root[META].keys) const newProp = findUniqueName(entry.name, root[META].props)
return { return {
op: 'add', op: 'add',
path: compileJSONPointer(rootPath.concat(newProp)), path: compileJSONPointer(rootPath.concat(newProp)),
@ -252,7 +252,7 @@ export function append (eson, parentPath, type) {
}] }]
} }
else { // object.type === 'Object' else { // object.type === 'Object'
const newProp = findUniqueName('', parent[META].keys) const newProp = findUniqueName('', parent[META].props)
return [{ return [{
op: 'add', op: 'add',
@ -327,24 +327,21 @@ export function sort (eson, path, order = null) {
else { // object.type === 'Object' else { // object.type === 'Object'
// order the properties by key // order the properties by key
const orderedKeys = object[META].keys.slice().sort((a, b) => compare(a.name, b.name)) const orderedProps = object[META].props.slice().sort((a, b) => compare(a.name, b.name))
// when no order is provided, test whether ordering ascending // when no order is provided, test whether ordering ascending
// changed anything. If not, sort descending // changed anything. If not, sort descending
if (!order && strictShallowEqual(object[META].keys, orderedKeys)) { if (!order && strictShallowEqual(object[META].props, orderedProps)) {
orderedKeys.reverse() orderedProps.reverse()
} }
const orderedProps = cloneWithSymbols(object) const orderedObject = cloneWithSymbols(object)
orderedProps[META] = setIn(object[META], ['keys'], orderedKeys) orderedObject[META] = setIn(object[META], ['props'], orderedProps)
return [{ return [{
op: 'replace', op: 'replace',
path: compileJSONPointer(path), path: compileJSONPointer(path),
value: esonToJson({ value: esonToJson(orderedObject),
type: 'Object',
props: orderedProps
}),
jsoneditor: { jsoneditor: {
order: orderedProps.map(prop => prop.name) order: orderedProps.map(prop => prop.name)
} }

View File

@ -58,7 +58,7 @@ export default class JSONNode extends PureComponent {
} }
renderJSONObject ({prop, index, eson, options, events}) { renderJSONObject ({prop, index, eson, options, events}) {
const keys = eson[META].keys const props = eson[META].props
const node = h('div', { const node = h('div', {
key: 'node', key: 'node',
onKeyDown: this.handleKeyDown, onKeyDown: this.handleKeyDown,
@ -68,24 +68,24 @@ export default class JSONNode extends PureComponent {
// this.renderActionMenu('update', this.state.menu, this.handleCloseActionMenu), // this.renderActionMenu('update', this.state.menu, this.handleCloseActionMenu),
// this.renderActionMenuButton(), // this.renderActionMenuButton(),
this.renderProperty(prop, index, eson, options), this.renderProperty(prop, index, eson, options),
this.renderReadonly(`{${keys.length}}`, `Array containing ${keys.length} items`), this.renderReadonly(`{${props.length}}`, `Array containing ${props.length} items`),
// this.renderFloatingMenuButton(), // this.renderFloatingMenuButton(),
this.renderError(eson[META].error) this.renderError(eson[META].error)
]) ])
let childs let childs
if (eson[META].expanded) { if (eson[META].expanded) {
if (keys.length > 0) { if (props.length > 0) {
const props = keys.map(key => h(this.constructor, { const propsChilds = props.map(prop => h(this.constructor, {
key: eson[key][META].id, key: eson[prop][META].id,
// parent: this, // parent: this,
prop: key, prop,
eson: eson[key], eson: eson[prop],
options, options,
events events
})) }))
childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, props) childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, propsChilds)
} }
else { else {
childs = h('div', {key: 'childs', className: 'jsoneditor-list'}, childs = h('div', {key: 'childs', className: 'jsoneditor-list'},

View File

@ -49,10 +49,9 @@ export function jsonToEson (json, path = []) {
if (isObject(json)) { if (isObject(json)) {
let eson = {} let eson = {}
const keys = Object.keys(json) const props = Object.keys(json)
keys.forEach((key) => eson[key] = jsonToEson(json[key], path.concat(key))) props.forEach((prop) => eson[prop] = jsonToEson(json[prop], path.concat(prop)))
// TODO: rename keys to props eson[META] = { id, path, type: 'Object', props }
eson[META] = { id, path, type: 'Object', keys }
return eson return eson
} }
else if (Array.isArray(json)) { else if (Array.isArray(json)) {
@ -80,7 +79,7 @@ export function esonToJson (eson: ESON) {
case 'Object': case 'Object':
const object = {} const object = {}
eson[META].keys.forEach(prop => { eson[META].props.forEach(prop => {
object[prop] = esonToJson(eson[prop]) object[prop] = esonToJson(eson[prop])
}) })
@ -385,13 +384,13 @@ export function applySelection (eson, selection) {
// TODO: simplify the update function. Use pathsFromSelection ? // TODO: simplify the update function. Use pathsFromSelection ?
if (root[META].type === 'Object') { if (root[META].type === 'Object') {
const startIndex = root[META].keys.indexOf(start) const startIndex = root[META].props.indexOf(start)
const endIndex = root[META].keys.indexOf(end) const endIndex = root[META].props.indexOf(end)
const minIndex = Math.min(startIndex, endIndex) const minIndex = Math.min(startIndex, endIndex)
const maxIndex = Math.max(startIndex, endIndex) + 1 // include max index itself const maxIndex = Math.max(startIndex, endIndex) + 1 // include max index itself
const selectedProps = root[META].keys.slice(minIndex, maxIndex) const selectedProps = root[META].props.slice(minIndex, maxIndex)
selectedPaths = selectedProps.map(prop => rootPath.concat(prop)) selectedPaths = selectedProps.map(prop => rootPath.concat(prop))
let updatedObj = cloneWithSymbols(root) let updatedObj = cloneWithSymbols(root)
selectedProps.forEach(prop => { selectedProps.forEach(prop => {
@ -441,8 +440,8 @@ export function findSelectionIndices (root, rootPath, selection) {
const end = (selection.after || selection.before || selection.end)[rootPath.length] const end = (selection.after || selection.before || selection.end)[rootPath.length]
// if no object we assume it's an Array // if no object we assume it's an Array
const startIndex = root[META].type === 'Object' ? root[META].keys.indexOf(start) : parseInt(start) const startIndex = root[META].type === 'Object' ? root[META].props.indexOf(start) : parseInt(start)
const endIndex = root[META].type === 'Object' ? root[META].keys.indexOf(end) : parseInt(end) const endIndex = root[META].type === 'Object' ? root[META].props.indexOf(end) : parseInt(end)
const minIndex = Math.min(startIndex, endIndex) const minIndex = Math.min(startIndex, endIndex)
const maxIndex = Math.max(startIndex, endIndex) + const maxIndex = Math.max(startIndex, endIndex) +
@ -462,7 +461,7 @@ export function pathsFromSelection (eson, selection: Selection): JSONPath[] {
const { minIndex, maxIndex } = findSelectionIndices(root, rootPath, selection) const { minIndex, maxIndex } = findSelectionIndices(root, rootPath, selection)
if (root[META].type === 'Object') { if (root[META].type === 'Object') {
return times(maxIndex - minIndex, i => rootPath.concat(root[META].keys[i + minIndex])) return times(maxIndex - minIndex, i => rootPath.concat(root[META].props[i + minIndex]))
} }
else { // root.type === 'Array' else { // root.type === 'Array'
return times(maxIndex - minIndex, i => rootPath.concat(String(i + minIndex))) return times(maxIndex - minIndex, i => rootPath.concat(String(i + minIndex)))
@ -580,18 +579,8 @@ export function resolvePathIndex (eson, path) {
* or null if there is none * or null if there is none
*/ */
export function findNextProp (parent, prop) { export function findNextProp (parent, prop) {
const index = parent[META].keys.indexOf(prop) const index = parent[META].props.indexOf(prop)
return parent[META].keys[index + 1] || null return parent[META].props[index + 1] || null
}
/**
* Find the index of a property
* @param {ESON} object
* @param {string} prop
* @return {number} Returns the index when found, -1 when not found
*/
export function findPropertyIndex (object, prop) {
return object[META].keys.indexOf(prop)
} }
// TODO: move parseJSONPointer and compileJSONPointer to a separate file // TODO: move parseJSONPointer and compileJSONPointer to a separate file

View File

@ -179,11 +179,11 @@ export function remove (data, path) {
} }
else { // object.type === 'Object' else { // object.type === 'Object'
const prop = last(pathArray) const prop = last(pathArray)
const index = parent[META].keys.indexOf(prop) const index = parent[META].props.indexOf(prop)
const nextProp = parent[META].keys[index + 1] || null const nextProp = parent[META].props[index + 1] || null
let updatedParent = deleteIn(parent, [prop]) let updatedParent = deleteIn(parent, [prop])
updatedParent[META] = deleteIn(parent[META], ['keys', index], parent[META].keys) updatedParent[META] = deleteIn(parent[META], ['props', index], parent[META].props)
return { return {
data: setIn(data, parentPath, updatePaths(updatedParent, parentPath)), data: setIn(data, parentPath, updatePaths(updatedParent, parentPath)),
@ -224,7 +224,7 @@ export function add (data, path, value, options) {
else { // parent.type === 'Object' else { // parent.type === 'Object'
updatedEson = updateIn(data, parentPath, (parent) => { updatedEson = updateIn(data, parentPath, (parent) => {
const oldValue = getIn(data, pathArray) const oldValue = getIn(data, pathArray)
const props = parent[META].keys const props = parent[META].props
const existingIndex = props.indexOf(prop) const existingIndex = props.indexOf(prop)
if (existingIndex !== -1) { if (existingIndex !== -1) {
@ -235,7 +235,6 @@ export function add (data, path, value, options) {
newValue[META] = setIn(newValue[META], ['id'], oldValue[META].id) newValue[META] = setIn(newValue[META], ['id'], oldValue[META].id)
// console.log('copied id from existing value' + oldValue[META].id) // console.log('copied id from existing value' + oldValue[META].id)
// TODO: update paths of existing value
return setIn(parent, [prop], newValue) return setIn(parent, [prop], newValue)
} }
else { else {
@ -247,7 +246,7 @@ export function add (data, path, value, options) {
let updatedKeys = props.slice() let updatedKeys = props.slice()
updatedKeys.splice(index, 0, prop) updatedKeys.splice(index, 0, prop)
const updatedParent = setIn(parent, [prop], updatePaths(value, parentPath.concat(prop))) const updatedParent = setIn(parent, [prop], updatePaths(value, parentPath.concat(prop)))
return setIn(updatedParent, [META, 'keys'], updatedKeys) return setIn(updatedParent, [META, 'props'], updatedKeys)
} }
}) })
} }

View File

@ -23,7 +23,7 @@ test('jsonToEson', t => {
assertDeepEqualEson(t, jsonToEson(null), {[META]: {id: '[ID]', path: [], type: 'value', value: null}}) assertDeepEqualEson(t, jsonToEson(null), {[META]: {id: '[ID]', path: [], type: 'value', value: null}})
assertDeepEqualEson(t, jsonToEson(false), {[META]: {id: '[ID]', path: [], type: 'value', value: false}}) assertDeepEqualEson(t, jsonToEson(false), {[META]: {id: '[ID]', path: [], type: 'value', value: false}})
assertDeepEqualEson(t, jsonToEson({a:1, b: 2}), { assertDeepEqualEson(t, jsonToEson({a:1, b: 2}), {
[META]: {id: '[ID]', path: [], type: 'Object', keys: ['a', 'b']}, [META]: {id: '[ID]', path: [], type: 'Object', props: ['a', 'b']},
a: {[META]: {id: '[ID]', path: ['a'], type: 'value', value: 1}}, a: {[META]: {id: '[ID]', path: ['a'], type: 'value', value: 1}},
b: {[META]: {id: '[ID]', path: ['b'], type: 'value', value: 2}} b: {[META]: {id: '[ID]', path: ['b'], type: 'value', value: 2}}
}) })

View File

@ -394,22 +394,22 @@ test('jsonpatch move (keep id intact)', t => {
t.is(patchedValueId, valueId) t.is(patchedValueId, valueId)
}) })
// test('jsonpatch move and replace (keep ids intact)', t => { test('jsonpatch move and replace (keep ids intact)', t => {
// const json = { a: 2, b: 3 } const json = { a: 2, b: 3 }
// const patch = [ const patch = [
// {op: 'move', from: '/a', path: '/b'} {op: 'move', from: '/a', path: '/b'}
// ] ]
//
// const data = jsonToEson(json) const data = jsonToEson(json)
// const bId = data.b[META].id const bId = data.b[META].id
//
// t.deepEqual(data[META].keys, ['a', 'b']) t.deepEqual(data[META].props, ['a', 'b'])
//
// const patchedData = patchEson(data, patch).data const patchedData = patchEson(data, patch).data
//
// t.is(patchedData.b[META].id, bId) t.is(patchedData.b[META].id, bId)
// t.deepEqual(data[META].keys, ['b']) t.deepEqual(patchedData[META].props, ['b'])
// }) })
test('jsonpatch test (ok)', t => { test('jsonpatch test (ok)', t => {
const json = { const json = {

View File

@ -20,7 +20,7 @@ export function assertDeepEqualEson (t, actual, expected, path = [], ignoreIds =
} }
else if (actualMeta.type === 'Object') { else if (actualMeta.type === 'Object') {
t.deepEqual(Object.keys(actual).sort(), Object.keys(expected).sort(), 'Actual properties should be equal, path=[${path.join(\', \')}]') t.deepEqual(Object.keys(actual).sort(), Object.keys(expected).sort(), 'Actual properties should be equal, path=[${path.join(\', \')}]')
actualMeta.keys.forEach(key => assertDeepEqualEson(t, actual[key], expected[key], path.concat(key)), ignoreIds) actualMeta.props.forEach(key => assertDeepEqualEson(t, actual[key], expected[key], path.concat(key)), ignoreIds)
} }
else { // actual[META].type === 'value' else { // actual[META].type === 'value'
t.deepEqual(Object.keys(actual), [], 'Value should not contain additional properties, path=[${path.join(\', \')}]') t.deepEqual(Object.keys(actual), [], 'Value should not contain additional properties, path=[${path.join(\', \')}]')