Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert from RFC 6902 to jsondiffpatch #381

Open
cschloer opened this issue Feb 19, 2025 · 1 comment
Open

Convert from RFC 6902 to jsondiffpatch #381

cschloer opened this issue Feb 19, 2025 · 1 comment

Comments

@cschloer
Copy link

Hi,

I see that there is a custom formatter designed to convert from the jsondiffpatch format to RFC 6902. Is there a way to go in the reverse direction?

I've got RFC 6902 patches coming from a backend service and would like to use the HTML formatter provided by this library, but it only takes the jsondiffpatch specific diff format.

@1j01
Copy link

1j01 commented Feb 19, 2025

I also had this question today.
In my case, I assumed jsondiffpatch would support jsonpatch format bidirectionally, and I ended up going with the native Delta format for compactness, but I apparently saved one or more files with the jsonpatch format while working on this.
(I'm using it for storing playthroughs of levels in a puzzle game, used for proving solvability, automated testing of the whole game, and viewing solutions.)

Seeing this issue, I decided to take a crack at it. At first I thought it would look something like this:

import type { AddedDelta, ModifiedDelta, DeletedDelta, MovedDelta, Delta } from 'jsondiffpatch'
import type { Op } from "jsondiffpatch/formatters/jsonpatch"

export function parse(jsonpatch: Op[]): Delta[] { // wrong
  const deltas: Delta[] = [] // wrong
  for (const op of jsonpatch) {
    switch (op.op) {
      case 'add':
        deltas.push([op.value] as AddedDelta)
        break
      case 'remove':
        deltas.push([undefined, 0, 0] as DeletedDelta)
        break
      case 'replace':
        deltas.push([undefined, op.value] as ModifiedDelta)
        break
      case 'move':
        deltas.push([op.from, parseInt(op.path.match(/\d+$/)[0]), 3] as MovedDelta)
        break
    }
  }
  return deltas
}

...but then I realized that it shouldn't be returning an array of Deltas, but one Delta, and the jsonpatch format may not include all the information necessary to convert to the Delta format, without also passing in the source document.
The Delta format uses ObjectDelta and ArrayDelta depending on the type of value in the document, and these recursively define modifications.
The jsonpatch format may be ambiguous as to whether an operation is targeting an array or object, for example
{ "op": "replace", "path": "/baz/0", "value": "boo" } could apply to {"baz": ["bar"]} or {"baz": {"0": "bar", "otherStuff": true}}
It might be possible to get a basic conversion that works in most cases without passing in the source document, by assuming that numerical keys are always used for arrays,
If the source document is available, it should be possible to create a robust conversion, however it would be more complicated than my code sketch above, involving recursion, and it might even need to simulate applying each operation to the document in order to have a correct baseline for determining the types of values at different paths in the document at different times in the sequence. I'm not sure.

Those are my thoughts on this, from a quick exploration. I'd be happy to know if I'm wrong :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants