diff --git a/src/JSONNode.js b/src/JSONNode.js index e051e29..deb46e1 100644 --- a/src/JSONNode.js +++ b/src/JSONNode.js @@ -10,9 +10,9 @@ const TYPE_TITLES = { 'value': 'Item type "value". ' + 'The item type is automatically determined from the value ' + 'and can be a string, number, boolean, or null.', - 'object': 'Item type "object". ' + + 'Object': 'Item type "object". ' + 'An object contains an unordered set of key/value pairs.', - 'array': 'Item type "array". ' + + 'Array': 'Item type "array". ' + 'An array contains an ordered collection of values.', 'string': 'Item type "string". ' + 'Item type is not determined from the value, ' + @@ -40,10 +40,10 @@ export default class JSONNode extends Component { } render (props, state) { - if (props.data.type === 'array') { + if (props.data.type === 'Array') { return this.renderJSONArray(props) } - else if (props.data.type === 'object') { + else if (props.data.type === 'Object') { return this.renderJSONObject(props) } else { @@ -322,15 +322,15 @@ export default class JSONNode extends Component { }, { text: 'Array', - className: 'jsoneditor-type-array' + (type == 'array' ? ' jsoneditor-selected' : ''), + className: 'jsoneditor-type-array' + (type == 'Array' ? ' jsoneditor-selected' : ''), title: TYPE_TITLES.array, - click: () => events.onChangeType(path, 'array') + click: () => events.onChangeType(path, 'Array') }, { text: 'Object', - className: 'jsoneditor-type-object' + (type == 'object' ? ' jsoneditor-selected' : ''), + className: 'jsoneditor-type-object' + (type == 'Object' ? ' jsoneditor-selected' : ''), title: TYPE_TITLES.object, - click: () => events.onChangeType(path, 'object') + click: () => events.onChangeType(path, 'Object') }, { text: 'String', @@ -341,7 +341,7 @@ export default class JSONNode extends Component { ] }) - if (type === 'array' || type === 'object') { + if (type === 'Array' || type === 'Object') { var direction = ((this.sortOrder == 'asc') ? 'desc': 'asc') items.push({ text: 'Sort', @@ -391,13 +391,13 @@ export default class JSONNode extends Component { text: 'Array', className: 'jsoneditor-type-array', title: TYPE_TITLES.array, - click: () => events.onInsert(path, 'array') + click: () => events.onInsert(path, 'Array') }, { text: 'Object', className: 'jsoneditor-type-object', title: TYPE_TITLES.object, - click: () => events.onInsert(path, 'object') + click: () => events.onInsert(path, 'Object') }, { text: 'String', @@ -458,13 +458,13 @@ export default class JSONNode extends Component { text: 'Array', className: 'jsoneditor-type-array', title: TYPE_TITLES.array, - click: () => events.onAppend(path, 'array') + click: () => events.onAppend(path, 'Array') }, { text: 'Object', className: 'jsoneditor-type-object', title: TYPE_TITLES.object, - click: () => events.onAppend(path, 'object') + click: () => events.onAppend(path, 'Object') }, { text: 'String', @@ -501,7 +501,7 @@ export default class JSONNode extends Component { static getRootName (data, options) { return typeof options.name === 'string' ? options.name - : (data.type === 'object' || data.type === 'array') + : (data.type === 'Object' || data.type === 'Array') ? data.type : valueType(data.value) } diff --git a/src/actions.js b/src/actions.js index fed57bb..80e8eea 100644 --- a/src/actions.js +++ b/src/actions.js @@ -17,13 +17,22 @@ export function changeValue (data, path, value) { const dataPath = toDataPath(data, path) const oldDataValue = getIn(data, dataPath) - return [{ + let patch = [{ op: 'replace', path: compileJSONPointer(path), - value: value, - jsoneditor: { type: oldDataValue.type } // TODO: send type only in case of 'string' - // TODO: send some information to ensure the correct order of fields? + value: value }] + + // when the old type is not something that can be detected from the + // value itself, store the type information + if(!isNativeType(oldDataValue.type)) { + // it's a string + patch[0].jsoneditor = { + type: oldDataValue.type + } + } + + return patch } /** @@ -35,7 +44,7 @@ export function changeValue (data, path, value) { * @return {Array} */ export function changeProperty (data, parentPath, oldProp, newProp) { - console.log('changeProperty', parentPath, oldProp, newProp) + // console.log('changeProperty', parentPath, oldProp, newProp) const dataPath = toDataPath(data, parentPath) const parent = getIn(data, dataPath) @@ -101,7 +110,7 @@ export function duplicate (data, path) { const dataPath = toDataPath(data, parentPath) const parent = getIn(data, dataPath) - if (parent.type === 'array') { + if (parent.type === 'Array') { const index = parseInt(path[path.length - 1]) + 1 return [{ op: 'copy', @@ -109,7 +118,7 @@ export function duplicate (data, path) { path: compileJSONPointer(parentPath.concat(index)) }] } - else { // object.type === 'object' + else { // object.type === 'Object' const afterProp = path[path.length - 1] const newProp = findUniqueName(afterProp, parent.props.map(p => p.name)) @@ -142,7 +151,7 @@ export function insert (data, path, type) { const parent = getIn(data, dataPath) const value = createEntry(type) - if (parent.type === 'array') { + if (parent.type === 'Array') { const index = parseInt(path[path.length - 1]) + 1 return [{ op: 'add', @@ -150,7 +159,7 @@ export function insert (data, path, type) { value }] } - else { // object.type === 'object' + else { // object.type === 'Object' const afterProp = path[path.length - 1] const newProp = findUniqueName('', parent.props.map(p => p.name)) @@ -182,14 +191,14 @@ export function append (data, parentPath, type) { const parent = getIn(data, dataPath) const value = createEntry(type) - if (parent.type === 'array') { + if (parent.type === 'Array') { return [{ op: 'add', path: compileJSONPointer(parentPath.concat('-')), value }] } - else { // object.type === 'object' + else { // object.type === 'Object' const newProp = findUniqueName('', parent.props.map(p => p.name)) return [{ @@ -215,7 +224,7 @@ export function sort (data, path, order = null) { const dataPath = toDataPath(data, path) const object = getIn(data, dataPath) - if (object.type === 'array') { + if (object.type === 'Array') { const orderedItems = object.items.slice(0) // order the items by value @@ -231,12 +240,12 @@ export function sort (data, path, order = null) { op: 'replace', path: compileJSONPointer(path), value: dataToJson({ - type: 'array', + type: 'Array', items: orderedItems }) }] } - else { // object.type === 'object' + else { // object.type === 'Object' const orderedProps = object.props.slice(0) // order the properties by key @@ -252,7 +261,7 @@ export function sort (data, path, order = null) { op: 'replace', path: compileJSONPointer(path), value: dataToJson({ - type: 'object', + type: 'Object', props: orderedProps }), jsoneditor: { @@ -268,10 +277,10 @@ export function sort (data, path, order = null) { * @return {Array | Object | string} */ export function createEntry (type) { - if (type === 'array') { + if (type === 'Array') { return [] } - else if (type === 'object') { + else if (type === 'Object') { return {} } else { @@ -305,7 +314,7 @@ export function convertType (value, type) { } } - if (type === 'object') { + if (type === 'Object') { let object = {} if (Array.isArray(value)) { @@ -315,7 +324,7 @@ export function convertType (value, type) { return object } - if (type === 'array') { + if (type === 'Array') { let array = [] if (isObject(value)) { @@ -329,3 +338,13 @@ export function convertType (value, type) { throw new Error(`Unknown type '${type}'`) } + +/** + * Test whether a type is a native JSON type: + * Native types are: Array, Object, or value + * @param {JSONDataType} type + * @return {boolean} + */ +export function isNativeType (type) { + return type === 'Object' || type === 'Array' || type === 'value' +} diff --git a/src/jsonData.js b/src/jsonData.js index 9a327d8..3ea29d1 100644 --- a/src/jsonData.js +++ b/src/jsonData.js @@ -24,14 +24,14 @@ const expandNever = function (path) { export function jsonToData (path, json, expand) { if (Array.isArray(json)) { return { - type: 'array', + type: 'Array', expanded: expand(path), items: json.map((child, index) => jsonToData(path.concat(index), child, expand)) } } else if (isObject(json)) { return { - type: 'object', + type: 'Object', expanded: expand(path), props: Object.keys(json).map(name => { return { @@ -56,10 +56,10 @@ export function jsonToData (path, json, expand) { */ export function dataToJson (data) { switch (data.type) { - case 'array': + case 'Array': return data.items.map(dataToJson) - case 'object': + case 'Object': const object = {} data.props.forEach(prop => { @@ -86,7 +86,7 @@ export function toDataPath (data, path) { } let index - if (data.type === 'array') { + if (data.type === 'Array') { // index of an array index = path[0] @@ -235,7 +235,7 @@ export function remove (data, path) { // FIXME: store before } - if (parent.type === 'array') { + if (parent.type === 'Array') { const dataPath = toDataPath(data, _path) return { @@ -243,7 +243,7 @@ export function remove (data, path) { revert: {op: 'add', path, value, jsoneditor} } } - else { // object.type === 'object' + else { // object.type === 'Object' const dataPath = toDataPath(data, _path) dataPath.pop() // remove the 'value' property, we want to remove the whole object property @@ -281,7 +281,7 @@ export function add (data, path, value, afterProp) { catch (err) {} let updatedData - if (parent.type === 'array') { + if (parent.type === 'Array') { // TODO: create an immutable helper function to insert an item in an Array updatedData = updateIn(data, dataPath.concat('items'), (items) => { const index = parseInt(prop) @@ -292,7 +292,7 @@ export function add (data, path, value, afterProp) { return updatedItems }) } - else { // parent.type === 'object' + else { // parent.type === 'Object' // TODO: create an immutable helper function to append an item to an Array updatedData = updateIn(data, dataPath.concat('props'), (props) => { const newProp = { name: prop, value } @@ -313,7 +313,7 @@ export function add (data, path, value, afterProp) { return { data: updatedData, - revert: (parent.type === 'object' && oldValue !== undefined) + revert: (parent.type === 'Object' && oldValue !== undefined) ? {op: 'replace', path: compileJSONPointer(resolvedPath), value: dataToJson(oldValue)} : {op: 'remove', path: compileJSONPointer(resolvedPath)} } @@ -450,7 +450,7 @@ export function expand (data, callback, expanded) { */ function expandRecursive (data, path, callback, expanded) { switch (data.type) { - case 'array': { + case 'Array': { let updatedData = callback(path) ? setIn(data, ['expanded'], expanded) : data @@ -464,7 +464,7 @@ function expandRecursive (data, path, callback, expanded) { return setIn(updatedData, ['items'], updatedItems) } - case 'object': { + case 'Object': { let updatedData = callback(path) ? setIn(data, ['expanded'], expanded) : data @@ -501,7 +501,7 @@ export function pathExists (data, path) { } let index - if (data.type === 'array') { + if (data.type === 'Array') { // index of an array index = path[0] return pathExists(data.items[index], path.slice(1)) @@ -527,7 +527,7 @@ export function resolvePathIndex (data, path) { const parentPath = path.slice(0, path.length - 1) const parent = getIn(data, toDataPath(data, parentPath)) - if (parent.type === 'array') { + if (parent.type === 'Array') { const index = parent.items.length const resolvedPath = path.slice(0) resolvedPath[resolvedPath.length - 1] = index diff --git a/src/typedef.js b/src/typedef.js index 51bd9ef..3516258 100644 --- a/src/typedef.js +++ b/src/typedef.js @@ -1,13 +1,12 @@ -// TODO: rename type 'array' to 'Array' and 'object' to 'Object' /** * @typedef {{ - * type: 'array', + * type: 'Array', * expanded: boolean?, * props: Array.<{name: string, value: JSONData}>? * }} ObjectData * * @typedef {{ - * type: 'object', + * type: 'Object', * expanded: boolean?, * items: JSONData[]? * }} ArrayData @@ -21,7 +20,7 @@ * * @typedef {ObjectData | ArrayData | ValueData} JSONData * - * @typedef {'object' | 'array' | 'value' | 'string'} JSONDataType + * @typedef {'Object' | 'Array' | 'value' | 'string'} JSONDataType * * @typedef {Array.<{op: string, path?: string, from?: string, value?: *}>} JSONPatch * diff --git a/src/utils/typeUtils.js b/src/utils/typeUtils.js index 0534d89..be68be8 100644 --- a/src/utils/typeUtils.js +++ b/src/utils/typeUtils.js @@ -48,10 +48,10 @@ export function valueType(value) { return 'regexp' } if (Array.isArray(value)) { - return 'array' + return 'Array' } - return 'object' + return 'Object' } /** diff --git a/test/jsonData.test.js b/test/jsonData.test.js index 31e9c6e..ac1455c 100644 --- a/test/jsonData.test.js +++ b/test/jsonData.test.js @@ -15,19 +15,19 @@ const JSON_EXAMPLE = { } const JSON_DATA_EXAMPLE = { - type: 'object', + type: 'Object', expanded: true, props: [ { name: 'obj', value: { - type: 'object', + type: 'Object', expanded: true, props: [ { name: 'arr', value: { - type: 'array', + type: 'Array', expanded: true, items: [ { @@ -39,7 +39,7 @@ const JSON_DATA_EXAMPLE = { value: 2 }, { - type: 'object', + type: 'Object', expanded: true, props: [ { @@ -89,19 +89,19 @@ const JSON_DATA_EXAMPLE = { } const JSON_DATA_EXAMPLE_COLLAPSED_1 = { - type: 'object', + type: 'Object', expanded: true, props: [ { name: 'obj', value: { - type: 'object', + type: 'Object', expanded: true, props: [ { name: 'arr', value: { - type: 'array', + type: 'Array', expanded: true, items: [ { @@ -113,7 +113,7 @@ const JSON_DATA_EXAMPLE_COLLAPSED_1 = { value: 2 }, { - type: 'object', + type: 'Object', expanded: false, props: [ { @@ -163,19 +163,19 @@ const JSON_DATA_EXAMPLE_COLLAPSED_1 = { } const JSON_DATA_EXAMPLE_COLLAPSED_2 = { - type: 'object', + type: 'Object', expanded: true, props: [ { name: 'obj', value: { - type: 'object', + type: 'Object', expanded: false, props: [ { name: 'arr', value: { - type: 'array', + type: 'Array', expanded: false, items: [ { @@ -187,7 +187,7 @@ const JSON_DATA_EXAMPLE_COLLAPSED_2 = { value: 2 }, { - type: 'object', + type: 'Object', expanded: false, props: [ {