| 88 | /** Apply a single RFC6902 JSON Patch operation to a mutable object. */ |
| 89 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 90 | function applyPatch(item: Record<string, any>, op: JsonPatchOperation) { |
| 91 | const segments = op.path.split('/').filter(Boolean) |
| 92 | |
| 93 | if (segments.length === 1) { |
| 94 | const key = segments[0] |
| 95 | if (op.op === 'replace' || op.op === 'add') { |
| 96 | item[key] = op.value |
| 97 | } else if (op.op === 'remove') { |
| 98 | delete item[key] |
| 99 | } |
| 100 | return |
| 101 | } |
| 102 | |
| 103 | let target = item |
| 104 | for (let i = 0; i < segments.length - 1; i++) { |
| 105 | const seg = segments[i] |
| 106 | if (Array.isArray(target)) { |
| 107 | target = target[Number(seg)] |
| 108 | } else { |
| 109 | target = target[seg] |
| 110 | } |
| 111 | if (target === undefined || target === null) return |
| 112 | } |
| 113 | |
| 114 | const lastSeg = segments[segments.length - 1] |
| 115 | |
| 116 | if (op.op === 'replace' || op.op === 'add') { |
| 117 | if (Array.isArray(target) && lastSeg === '-') { |
| 118 | target.push(op.value) |
| 119 | } else if (Array.isArray(target)) { |
| 120 | target[Number(lastSeg)] = op.value |
| 121 | } else { |
| 122 | target[lastSeg] = op.value |
| 123 | } |
| 124 | } else if (op.op === 'remove') { |
| 125 | if (Array.isArray(target)) { |
| 126 | target.splice(Number(lastSeg), 1) |
| 127 | } else { |
| 128 | delete target[lastSeg] |
| 129 | } |
| 130 | } |
| 131 | } |