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

Using the library with the react-diff-viewer sandbox <https://8rhv2q.csb.app/> found different behaviour #220

Open
giampietrozambelli opened this issue Jun 18, 2024 · 7 comments

Comments

@giampietrozambelli
Copy link

giampietrozambelli commented Jun 18, 2024

@otakustay I try to diff the 2 following sample json in the react-diff-viewer sandbox https://8rhv2q.csb.app/ .

As in the attached picture:

image

I would expect to identify the pattern:
{
"firstname": "Mario",
"lastname": "Rossi"
}

as repeated and identical, while the library compare line per line in this case.

Note that just adding the following new element in the array:
{
"new_tag": "new";
}

image

the library identifies the correct repeated and identical item.

Any suggestions? Did I miss some configuration parameters to let the repeated element properly identified as identical in the 2 input variables?
{
"firstname": "Mario",
"lastname": "Rossi"
}

Regards,
Giampietro

The source code from the sandbox is:

import React, {useState, useCallback, useMemo} from 'react';
import ReactDOM from 'react-dom';
import {Input, Button} from 'antd';
import {diffLines, formatLines} from 'unidiff';
import {parseDiff, Diff, Hunk} from 'react-diff-view';
import {useInput} from './hooks';
import 'antd/dist/antd.min.css';
import 'react-diff-view/style/index.css';
import './styles.css';
import tokenize from './tokenize';
const EMPTY_HUNKS = [];
const renderToken = (token, defaultRender, i) => {
    switch (token.type) {
        case 'space':
            console.log(token);
            return (
                <span key={i} className="space">
                    {token.children && token.children.map((token, i) => renderToken(token, defaultRender, i))}
                </span>
            );
        default:
            return defaultRender(token, i);
    }
};
function App() {
    const oldText = useInput('');
    const newText = useInput('');
    const [{type, hunks}, setDiff] = useState('');
    const updateDiffText = useCallback(() => {
        const diffText = formatLines(diffLines(oldText.value, newText.value), {context: 0});
        const [diff] = parseDiff(diffText, {nearbySequences: 'zip'});
        //const [diff] = parseDiff(diffText);
        setDiff(diff);
    }, [oldText.value, newText.value, setDiff]);
    const tokens = useMemo(() => tokenize(hunks), [hunks]);
    return (
        <div>
            <header className="header">
                <div className="input">
                    <Input.TextArea className="text" rows={15} placeholder="old text..." {...oldText} />
                    <Input.TextArea className="text" rows={15} placeholder="new text..." {...newText} />
                </div>
                <Button className="submit" type="primary" onClick={updateDiffText}>
                    GENERATE DIFF
                </Button>
            </header>
            <main>
                <Diff
                    viewType="split"
                    diffType={type}
                    hunks={hunks || EMPTY_HUNKS}
                    tokens={tokens}
                    renderToken={renderToken}
                >
                    {(hunks) => hunks.map((hunk) => <Hunk key={hunk.content} hunk={hunk} />)}
                </Diff>
            </main>
        </div>
    );
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
@otakustay
Copy link
Owner

Could please paste your old and new code directly here, so I can have more debugging work to reproduce and identify the problem

@giampietrozambelli
Copy link
Author

// Sample 1 - OLD
{
"prop_a":[
  {
    "firstname": "Andrea",
    "lastname": "Chieppa"
  },
  {
    "firstname": "Mario",
    "lastname": "Rossi"
  }
 ]
}
// Sample 1 - NEW
{
"prop_a":[
  {
    "firstname": "Mario",
    "lastname": "Rossi"
  },
  {
    "firstname": "Guido",
    "lastname": "Bianchi"
  }
 ]
}

// Sample 2 - OLD
{
"prop_a":[
  {
    "firstname": "Andrea",
    "lastname": "Chieppa"
  },
  {
    "firstname": "Mario",
    "lastname": "Rossi"
  },
  {
    "new_tag": "new"
  }
 ]
}
// Sample 2 - NEW
{
"prop_a":[
  {
    "firstname": "Mario",
    "lastname": "Rossi"
  },
  {
    "firstname": "Guido",
    "lastname": "Bianchi"
  },
  {
    "new_tag": "new"
  }
 ]
}

@giampietrozambelli
Copy link
Author

The code of the sandbox can be found here: Sanbox URL

@giampietrozambelli
Copy link
Author

@otakustay Did you have a chance to reproduce the issue? Could you share more hints?

@giampietrozambelli
Copy link
Author

@otakustay Any news on the ability to reproduce the issue? Or you don't recognize it as an issue?

@otakustay
Copy link
Owner

Sorry for the sever delay, this issue is related to how we compute diff from source text using unidiff library, by default I didn't pass any options to diffLines function in my demo, this results a unwanted diff in your case.

I've changed the sandbox, adding an option object to diffLines call:

const diffText = formatLines(
    diffLines(oldText.value, newText.value, {newlineIsToken: true}),
    {context: 3},
);

Note the {newlineIsToken: true} object which helps produce a diff result similar to our expectation, however this introduce another problem that we can see extra empty lines between properties.

CleanShot 2024-07-05 at 21 34 43@2x

This for sure is not correct, and I believe the problem lies inside the formatLines function from unidiff package, I'd again search for information about this.

This is not a render issue for react-diff-view, but a problem with how we generate the diff text itself in demo, maybe I can have a look at how react-diff-viewer computes the diff text and find some inspiration.

@otakustay
Copy link
Owner

otakustay commented Jul 5, 2024

It's also weird to me that the Diff.createPatch function from diff package can produce a diff text exactly the same as the image I posted above:

const Diff = require('diff');

const a = `{
"prop_a":[
  {
    "firstname": "Andrea",
    "lastname": "Chieppa"
  },
  {
    "firstname": "Mario",
    "lastname": "Rossi"
  },
  {
    "new_tag": "new"
  }
 ]
}`;

const b = `{
"prop_a":[
  {
    "firstname": "Mario",
    "lastname": "Rossi"
  },
  {
    "firstname": "Guido",
    "lastname": "Bianchi"
  },
  {
    "new_tag": "new"
  }
 ]
}`;

const patch = Diff.createPatch(
    'a.txt',
    a,
    b,
    undefined,
    undefined,
    {
        newlineIsToken: true
    }
);

This results:

Index: a.txt
===================================================================
--- a.txt
+++ a.txt
@@ -1,16 +1,16 @@
 {
 "prop_a":[
   {
-    "firstname": "Andrea",
+    "firstname": "Mario",

-    "lastname": "Chieppa"
+    "lastname": "Rossi"

   },
   {
-    "firstname": "Mario",
+    "firstname": "Guido",

-    "lastname": "Rossi"
+    "lastname": "Bianchi"

   },
   {
     "new_tag": "new"

Don't know where the issue is currently

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