diff --git a/src/App.svelte b/src/App.svelte index 9aa841c..fba4ea7 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -8,33 +8,33 @@ export let searchText = '' let json = { - 'array': [1, 2, 3, { - name: 'Item ' + 2, - id: String(2), - index: 2, - time: new Date().toISOString(), - location: { - latitude: 1.23, - longitude: 23.44, - coordinates: [23.44, 1.23] - }, - }], + // 'array': [1, 2, 3, { + // name: 'Item ' + 2, + // id: String(2), + // index: 2, + // time: new Date().toISOString(), + // location: { + // latitude: 1.23, + // longitude: 23.44, + // coordinates: [23.44, 1.23] + // }, + // }], 'boolean': true, 'color': '#82b92c', 'null': null, 'number': 123, - 'object': {'a': 'b', 'c': 'd', nested: { - name: 'Item ' + 2, - id: String(2), - index: 2, - time: new Date().toISOString(), - location: { - latitude: 1.23, - longitude: 23.44, - coordinates: [23.44, 1.23] - }, - }}, - 'string': 'Hello World' + // 'object': {'a': 'b', 'c': 'd', nested: { + // name: 'Item ' + 2, + // id: String(2), + // index: 2, + // time: new Date().toISOString(), + // location: { + // latitude: 1.23, + // longitude: 23.44, + // coordinates: [23.44, 1.23] + // }, + // }}, + // 'string': 'Hello World' } let uniDirectionalValue = 'test uni directional flow in Svelte'; diff --git a/src/JSONNode.svelte b/src/JSONNode.svelte index 0e99e14..2fda14a 100644 --- a/src/JSONNode.svelte +++ b/src/JSONNode.svelte @@ -4,9 +4,8 @@ import { SEARCH_PROPERTY, SEARCH_VALUE } from './search' import classnames from 'classnames' import { isUrl, valueType } from './utils/typeUtils' - import { escapeHTML } from './utils/stringUtils' - import uniqueId from 'lodash/uniqueId.js' - import remove from 'lodash/remove.js' + import { escapeHTML } from './utils/stringUtils.js' + import { createUpdateProps } from './utils/updateProps.js' export let key = 'root' export let value @@ -18,32 +17,18 @@ const DEFAULT_LIMIT = 10000 const escapeUnicode = false // TODO: pass via options + // create lazy, memoized updateProps function + let updateProps = function lazyUpdateProps (value) { + updateProps = createUpdateProps() + return updateProps(value) + } + let limit = DEFAULT_LIMIT $: type = valueType (value) - - function getOrCreateId (childKey) { - if (ids === undefined) { - ids = {} - } - - if (ids[childKey] === undefined) { - ids[childKey] = uniqueId() - } - - return ids[childKey] - } - - // FIXME: this should not be needed, use Svelte notation for looping over an object - let ids = undefined $: props = type === 'object' - ? Object.keys(value).map(childKey => { - return { - id: getOrCreateId(childKey), - key: childKey - } - }) + ? updateProps(value) : undefined $: limited = type === 'array' && value.length > limit @@ -88,9 +73,10 @@ } }) - if (ids !== undefined) { - ids[newChildKey] = ids[oldChildKey] - delete ids[oldChildKey] + const index = props.findIndex(item => item.key === oldChildKey) + if (index !== -1) { + // FIXME: make immutable (not possible as long as prevProps is stored in updateProps + props[index].key = newChildKey } onChangeValue(updatedValue, key) diff --git a/src/utils/updateProps.js b/src/utils/updateProps.js new file mode 100644 index 0000000..5812ae4 --- /dev/null +++ b/src/utils/updateProps.js @@ -0,0 +1,37 @@ +import { isObject } from './typeUtils.js' +import uniqueId from 'lodash/uniqueId.js' + +export function createUpdateProps () { + let prevProps = undefined + + return function updateProps (value) { + // TODO: optimize. check if value is the same as prevValue, if so, don't do anything + + if (isObject(value)) { + const props = prevProps + ? prevProps.filter(item => value[item.key] !== undefined) // copy the props that still exist + : [] + + // process added props + const prevKeys = new Set(props.map(item => item.key)) // TODO: this is inefficient, creating a set. cache this set? + + console.log('updateProps', { value, prevProps, props}) + + Object.keys(value).forEach(key => { + if (!prevKeys.has(key)) { + console.log('add key', key) + props.push({ + id: uniqueId(), + key + }) + } + }) + + prevProps = props + return props + } else { + prevProps = undefined + return undefined + } + } +} diff --git a/src/utils/updateProps.test.js b/src/utils/updateProps.test.js new file mode 100644 index 0000000..8277d8c --- /dev/null +++ b/src/utils/updateProps.test.js @@ -0,0 +1,20 @@ +import { createUpdateProps } from './updateProps.js' +import { expect } from './testUtils.js' // FIXME: replace jest with mocha tests, or move to jest + +const test = it // TODO: replace jest with mocha tests, or move to jest + +test('updateProps (1)', () => { + const updateProps = createUpdateProps() + + expect(updateProps({b: 2}).map(item => item.key)).toEqual(['b']) + + const result2 = updateProps({a: 1, b: 2}) + expect(result2.map(item => item.key)).toEqual(['b', 'a']) + expect(result2[0].id).toEqual('1') +}) + +test('updateProps (2)', () => { + const updateProps = createUpdateProps() + const result1 = updateProps({a: 1, b: 2}) + expect(updateProps({a: 1, b: 2})).toEqual(result1) +})