diff --git a/src/jsonData.js b/src/jsonData.js index fb95332..96cc575 100644 --- a/src/jsonData.js +++ b/src/jsonData.js @@ -486,6 +486,8 @@ export function expand (data, callback, expanded) { * @private */ function expandRecursive (data, path, callback, expanded) { + // TODO: use the function transform here? + switch (data.type) { case 'Array': { let updatedData = callback(path) @@ -543,24 +545,74 @@ export function addErrors (data, errors) { } /** - * Remove errors which where added using addErrors + * Merge one or multiple errors (for example JSON schema errors) + * into the data * * @param {JSONData} data - * @param {Array.} errors + * @param {string} search */ -export function removeErrors (data, errors) { +export function setSearch (data, search) { let updatedData = data - errors.forEach(error => { - const dataPath = toDataPath(data, parseJSONPointer(error.dataPath)) - updatedData = deleteIn(updatedData, dataPath.concat('error')) - }) + // TODO: traverse over the data, add a field search: 'field'|'value' to all matching fields/values return updatedData } -// TODO: implement a function removeAllErrors (data) +/** + * + * @param {JSONData} data + * @param {function(value: JSONData, path: Path, root: JSONData)} callback + * @return {JSONData} Returns the transformed data + */ +export function transform (data, callback) { + return recurseTransform (data, [], data, callback) +} +/** + * Recursively transform JSONData + * @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 + * @return {JSONData} Returns the transformed data + */ +function recurseTransform (value, path, root, callback) { + let updatedValue = callback(value, path, root) + + switch (value.type) { + case 'Array': { + let updatedItems = updatedValue.items + + updatedValue.items.forEach((item, index) => { + updatedItems = setIn(updatedItems, [index], + recurseTransform(item, path.concat(String(index)), root, callback)) + }) + + updatedValue = setIn(updatedValue, ['items'], updatedItems) + + break + } + + case 'Object': { + let updatedProps = updatedValue.props + + updatedValue.props.forEach((prop, index) => { + updatedProps = setIn(updatedProps, [index, 'value'], + recurseTransform(prop.value, path.concat(prop.name), root, callback)) + }) + + updatedValue = setIn(updatedValue, ['props'], updatedProps) + + break + } + + default: // type 'string' or 'value' + // don't do anything: a value can't be expanded, only arrays and objects can + } + + return updatedValue +} /** * Test whether a path exists in the json data diff --git a/test/jsonData.test.js b/test/jsonData.test.js index 4536aca..c85694b 100644 --- a/test/jsonData.test.js +++ b/test/jsonData.test.js @@ -1,8 +1,8 @@ import test from 'ava'; import { - jsonToData, dataToJson, patchData, pathExists, + jsonToData, dataToJson, patchData, pathExists, transform, parseJSONPointer, compileJSONPointer, - expand, addErrors, removeErrors + expand, addErrors } from '../src/jsonData' @@ -736,7 +736,77 @@ test('jsonpatch test (fail: value not equal)', t => { test('add and remove errors', t => { const dataWithErrors = addErrors(JSON_DATA_EXAMPLE, JSON_SCHEMA_ERRORS) t.deepEqual(dataWithErrors, JSON_DATA_EXAMPLE_ERRORS) - - const dataWithoutErrors = removeErrors(dataWithErrors, JSON_SCHEMA_ERRORS) - t.deepEqual(dataWithoutErrors, JSON_DATA_EXAMPLE) +}) + +test('transform', t => { + // {obj: {a: 2}, arr: [3]} + const data = { + type: 'Object', + props: [ + { + name: 'obj', + value: { + type: 'Object', + props: [ + { + name: 'a', + value: { + type: 'value', + value: 2 + } + } + ] + } + }, + { + name: 'arr', + value: { + type: 'Array', + items: [ + { + type: 'value', + value: 3 + } + ] + } + } + ] + } + + + let log = [] + const transformed = transform(data, function (value, path, root) { + t.truthy(root === data) + + log.push([value, path, root]) + + if (path.length === 2 && path[0] === 'obj' && path[1] === 'a') { + // change the value + return { type: 'value', value: 42 } + } + + // leave the value unchanged + return value + }) + + // console.log('transformed', JSON.stringify(transformed, null, 2)) + + const EXPECTED_LOG = [ + [data, [], data], + [data.props[0].value, ['obj'], data], + [data.props[0].value.props[0].value, ['obj', 'a'], data], + [data.props[1].value, ['arr'], data], + [data.props[1].value.items[0], ['arr', '0'], data], + ] + + // log.forEach((row, index) => { + // t.deepEqual(log[index], EXPECTED_LOG[index], 'should have equal log at index ' + index ) + // }) + t.deepEqual(log, EXPECTED_LOG) + t.truthy(transformed !== data) + t.truthy(transformed.props[0].value !== data.props[0].value) + t.truthy(transformed.props[0].value.props[0].value !== data.props[0].value.props[0].value) + t.truthy(data.props[1].value === data.props[1].value) + t.truthy(data.props[1].value.items[0] === data.props[1].value.items[0]) + })