From ec35e5f14cb25193d5c49a41d4b016691c15c6a2 Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Wed, 29 Jun 2022 17:43:12 -0600 Subject: [PATCH] refactor apply operation to account for arrays (#38) * refactor apply operation to account for arrays * fix buig --- client/lib/json-patch-lib.ts | 38 +++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/client/lib/json-patch-lib.ts b/client/lib/json-patch-lib.ts index 8f2ab0e..aa251d9 100644 --- a/client/lib/json-patch-lib.ts +++ b/client/lib/json-patch-lib.ts @@ -39,7 +39,7 @@ export function applyOperation ( const add = { op: PatchOp.ADD, path, value: current} as const const replace = { op: PatchOp.REPLACE, path, value: current } as const - doc.data = recursiveApply(doc.data, jsonPathToKeyArray(path), value) + doc.data = recursiveApply(doc.data, jsonPathToKeyArray(path), op, value) switch (op) { case PatchOp.REMOVE: @@ -54,14 +54,22 @@ export function applyOperation ( } } -function recursiveApply> (data: T, path: readonly string[], value?: any): T { +function recursiveApply | any[]> (data: T, path: readonly string[], op: PatchOp, value?: any): T { if (!path.length) return value - - if (!isObject(data)) { - throw Error('Patch cannot be applied. Path contains non object') + + // object + if (isObject(data)) { + return recursiveApplyObject(data, path, op, value) + // array + } else if (Array.isArray(data)) { + return recursiveApplyArray(data, path, op, value) + } else { + throw 'unreachable' } +} - const updated = recursiveApply(data[path[0]], path.slice(1), value) +function recursiveApplyObject> (data: T, path: readonly string[], op: PatchOp, value?: any): T { + const updated = recursiveApply(data[path[0]], path.slice(1), op, value) const result = { ...data, [path[0]]: updated, @@ -74,8 +82,24 @@ function recursiveApply> (data: T, path: readonly st return result } +function recursiveApplyArray (data: T, path: readonly string[], op: PatchOp, value?: any): T { + const index = parseInt(path[0]) + + const updated = recursiveApply(data[index], path.slice(1), op, value) + const result = [...data] as T + if (op === PatchOp.ADD) { + result.splice(index, 0, updated) + } else if (op === PatchOp.REPLACE) { + result.splice(index, 1, updated) + } else { + result.splice(index, 1) + } + + return result +} + function isObject (val: any): val is Record { - return typeof val === 'object' && val !== null + return typeof val === 'object' && val !== null && !Array.isArray(val) } function jsonPathToKeyArray (path: string): string[] {