Giter VIP home page Giter VIP logo

node-diff3's Introduction

build npm version

node-diff3

node-diff3 is a Javascript library to find differences between two buffers, generate and apply patches, and perform 3-way merging between an original and two changed buffers. It contains similar functionality to the GNU Diffutils tools.

The code originally came from project Synchrotron, created by Tony Garnock-Jones. For more detail please visit:

 

Usage

Use in Node

To install node-diff3 as a dependency in your project:

$  npm install --save node-diff3

node-diff3 is distributed in CJS and ESM module formats for maxmimum compatibility. (Read more about Javascript module formats)

const Diff3 = require('node-diff3');                   // CommonJS import all
const diff3Merge = require('node-diff3').diff3Merge;   // CommonJS import named
// or
import * as Diff3 from 'node-diff3';                   // ESM import all
import { diff3Merge } from 'node-diff3';               // ESM import named

Use in Browsers

You can also use node-diff3 directly in a web browser. A good way to do this is to fetch the "iife" bundle from the jsDelivr CDN, which can even deliver minified versions.

When you load this file in a <script> tag, you'll get a Diff3 global to use elsewhere in your scripts:

<head>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/index.iife.min.js"></script>
</head><script>
  const o = ['AA', 'ZZ', '00', 'M', '99'];
  const a = ['AA', 'a', 'b', 'c', 'ZZ', 'new', '00', 'a', 'a', 'M', '99'];
  const b = ['AA', 'a', 'd', 'c', 'ZZ', '11', 'M', 'z', 'z', '99'];
  const result = Diff3.diff3Merge(a, o, b);
</script>

👉 This project uses modern JavaScript syntax for use in supported node versions and modern browsers. If you need support for legacy environments like ES5 or Internet Explorer, you'll need to build your own bundle with something like Babel.

 

API Reference

 

3-way diff and merging

 

# Diff3.diff3Merge(a, o, b, options)

Performs a 3-way diff on buffers o (original), and a and b (changed). The buffers may be arrays or strings. If strings, they will be split into arrays on whitespace /\s+/ by default. The returned result alternates between "ok" and "conflict" blocks.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/diff3Merge.test.js

const o = ['AA', 'ZZ', '00', 'M', '99'];
const a = ['AA', 'a', 'b', 'c', 'ZZ', 'new', '00', 'a', 'a', 'M', '99'];
const b = ['AA', 'a', 'd', 'c', 'ZZ', '11', 'M', 'z', 'z', '99'];
const result = Diff3.diff3Merge(a, o, b);

Options may passed as an object:

{
  excludeFalseConflicts: true,
  stringSeparator: /\s+/
}
  • excludeFalseConflicts - If both a and b contain an identical change from o, this is considered a "false" conflict.
  • stringSeparator - If inputs buffers are strings, this controls how to split the strings into arrays. The separator value may be a string or a regular expression, as it is just passed to String.split().

 

# Diff3.merge(a, o, b, options)

Passes arguments to diff3Merge to generate a diff3-style merge result.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/merge.test.js

const r = Diff3.merge(a, o, b);
const result = r.result;
// [
//   'AA',
//   '<<<<<<<',
//   'a',
//   'b',
//   'c',
//   '=======',
//   'a',
//   'd',
//   'c',
//   '>>>>>>>',
//   'ZZ',
//   '<<<<<<<',
//   'new',
//   '00',
//   'a',
//   'a',
//   '=======',
//   '11',
//   '>>>>>>>',
//   'M',
//   'z',
//   'z',
//   '99'
//  ]

 

# Diff3.mergeDiff3(a, o, b, options)

Passes arguments to diff3Merge to generate a diff3-style merge result with original (similar to git-diff3).

See examples: https://github.com/bhousel/node-diff3/blob/main/test/mergeDiff3.test.js

const r = Diff3.mergeDiff3(a, o, b, { label: { a: 'a', o: 'o', b: 'b' } });
const result = r.result;
// [
//   'AA',
//   '<<<<<<< a',
//   'a',
//   'b',
//   'c',
//   '||||||| o',
//   '=======',
//   'a',
//   'd',
//   'c',
//   '>>>>>>> b',
//   'ZZ',
//   '<<<<<<< a',
//   'new',
//   '00',
//   'a',
//   'a',
//   '||||||| o',
//   '00',
//   '=======',
//   '11',
//   '>>>>>>> b',
//   'M',
//   'z',
//   'z',
//   '99'
//  ]

Extra options:

{
  // labels for conflict marker lines
  label: {
    a: 'a',
    o: 'o',
    b: 'b'
  },
}

 

# Diff3.mergeDigIn(a, o, b, options)

Passes arguments to diff3Merge to generate a digin-style merge result.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/mergeDigIn.test.js

 

# Diff3.diff3MergeRegions(a, o, b)

Low-level function used by diff3Merge to determine the stable and unstable regions between a, o, b.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/diff3MergeRegions.test.js

 

2-way diff and patching

 

# Diff3.diffPatch(buffer1, buffer2)

Performs a diff between arrays buffer1 and buffer2. The returned patch result contains the information about the differing regions and can be applied to buffer1 to yield buffer2.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/diffPatch.test.js

const buffer1 = ['AA', 'a', 'b', 'c', 'ZZ', 'new', '00', 'a', 'a', 'M', '99'];
const buffer2 = ['AA', 'a', 'd', 'c', 'ZZ', '11', 'M', 'z', 'z', '99'];
const patch = Diff3.diffPatch(buffer1, buffer2);
// `patch` contains the information needed to turn `buffer1` into `buffer2`

 

# Diff3.patch(buffer1, patch)

Applies a patch to a buffer, returning a new buffer without modifying the original.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/diffPatch.test.js

const result = Diff3.patch(buffer1, patch);
// `result` contains a new arrray which is a copy of `buffer2`

 

# Diff3.stripPatch(patch)

Strips some extra information from the patch, returning a new patch without modifying the original. The "stripped" patch can still patch buffer1 -> buffer2, but can no longer be inverted.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/diffPatch.test.js

const stripped = Diff3.stripPatch(patch);
// `stripped` contains a copy of a patch but with the extra information removed

 

# Diff3.invertPatch(patch)

Inverts the patch (for example to turn buffer2 back into buffer1), returning a new patch without modifying the original.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/diffPatch.test.js

const inverted = Diff3.invertPatch(patch);
// `inverted` contains a copy of a patch to turn `buffer2` back into `buffer1`

 

# Diff3.diffComm(buffer1, buffer2)

Returns a comm-style result of the differences between buffer1 and buffer2.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/diffComm.test.js

 

# Diff3.diffIndices(buffer1, buffer2)

Low-level function used by diff3MergeRegions to determine differing regions between buffer1 and buffer2.

See examples: https://github.com/bhousel/node-diff3/blob/main/test/diffIndices.test.js

 

Longest Common Sequence (LCS)

 

# Diff3.LCS(buffer1, buffer2)

Low-level function used by other functions to find the LCS between buffer1 and buffer2. Returns a result linked list chain containing the common sequence path.

See also:

See examples: https://github.com/bhousel/node-diff3/blob/main/test/LCS.test.js

 

License

This project is available under the MIT License. See the LICENSE.md file for more details.

node-diff3's People

Contributors

akphi avatar bhousel avatar bongione avatar dependabot-preview[bot] avatar dependabot[bot] avatar greenkeeper[bot] avatar jayakrishnanamburu avatar langram avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

node-diff3's Issues

Creating a merge of a three-way comparison

Thanks for this great work. I am trying to compare 3 YAML files to create the merge using diff3Merge. As indicated in #45, I have tried using hunks, but I lose spaces and newlines; I assume because the separation is done using the regular expression /\s+/. I tried using /\n/ to process line by line. Still, I get a false positive which I don't understand. I use the below arguments:

o:

title: "title"
description: "title"

a:

title: "title"
description: "title changed"

b:

title: "title changed"
description: "title"

result with /\n/:

[
    {
        "conflict": {
            "a": [
                "title": \{ "title",
                "description: \"title changed".
            ],
            "aIndex": 0,
            "o": [
                "title: \"title",
                "description: \"title""
            ],
            "oIndex": 0,
            "b": [
                "title: \"title changed\""
                "description: \"title""
            ],
            "bIndex": 0
        }
    },
    {
        "ok": [
            ""
        ]
    }
]

Whereas if I use /s+/:

[
    {
        "ok": [
            "title:",
            "title",
            "changed",
            "description:",
            "title",
            "changed"",
            ""
        ]
    }
]

but losing the spaces and newlines.

I expected to get as a result:

title: "title changed"
description: "title changed"

I don't understand if I'm doing something wrong or trying to use the library for a different purpose than the original one.

[Question] 2-way merge is not giving desired results.

I might be using this for a use-case which it might not be designed for. So, please close this if it's not related.
So, i have two code-snipped. And trying to do a 2-way merge between them. But my second snipped is always being overwritten.

Here is the url to reproduce --> https://codesandbox.io/s/vigorous-pond-mvf9u?file=/src/index.js
I have a remote and a base. And every time i try a 2-way merge on it. I am loosing some content from the base. Am i doing something wrong, or should i change to diffMerge3. But even with that, i had some similar experiences.

New TypeScript definition of 'patch' uses Buffer as a generic

Hi @bhousel

This is a minor issue, but I use tsc --pretty in my pipeline and I started getting an error when building a project using the 2.1.1 version of node-diff3, so I have to stay on 2.1.0 until resolved:

"Type 'Buffer' is not generic."

for the new definition of patch in node-diff3/index.d.ts:

"export function patch(buffer: T[], patch: IPatchRes[]): Buffer[];"

Thanks for making this very useful library!

An in-range update of rollup is breaking the build 🚨

The devDependency rollup was updated from 1.14.2 to 1.14.3.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

rollup is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).

Release Notes for v1.14.3

2019-06-06

Bug Fixes

  • Generate correct external imports when importing from a directory that would be above the root of the current working directory (#2902)

Pull Requests

Commits

The new version differs by 4 commits.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of eslint is breaking the build 🚨

Version 4.15.0 of eslint was just published.

Branch Build failing 🚨
Dependency eslint
Current Version 4.14.0
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

eslint is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Release Notes v4.15.0
  • 6ab04b5 New: Add context.report({ messageId }) (fixes #6740) (#9165) (Jed Fox)
  • fc7f404 Docs: add url to each of the rules (refs #6582) (#9788) (Patrick McElhaney)
  • fc44da9 Docs: fix sort-imports rule block language (#9805) (ferhat elmas)
  • 65f0176 New: CLIEngine#getRules() (refs #6582) (#9782) (Patrick McElhaney)
  • c64195f Update: More detailed assert message for rule-tester (#9769) (Weijia Wang)
  • 9fcfabf Fix: no-extra-parens false positive (fixes: #9755) (#9795) (Erin)
  • 61e5fa0 Docs: Add table of contents to Node.js API docs (#9785) (Patrick McElhaney)
  • 4c87f42 Fix: incorrect error messages of no-unused-vars (fixes #9774) (#9791) (akouryy)
  • bbabf34 Update: add ignoreComments option to indent rule (fixes #9018) (#9752) (Kevin Partington)
  • db431cb Docs: HTTP -> HTTPS (fixes #9768) (#9768) (Ronald Eddy Jr)
  • cbf0fb9 Docs: describe how to feature-detect scopeManager/visitorKeys support (#9764) (Teddy Katz)
  • f7dcb70 Docs: Add note about "patch release pending" label to maintainer guide (#9763) (Teddy Katz)
Commits

The new version differs by 14 commits.

  • e14ceb0 4.15.0
  • 2dfc3bd Build: changelog update for 4.15.0
  • 6ab04b5 New: Add context.report({ messageId }) (fixes #6740) (#9165)
  • fc7f404 Docs: add url to each of the rules (refs #6582) (#9788)
  • fc44da9 Docs: fix sort-imports rule block language (#9805)
  • 65f0176 New: CLIEngine#getRules() (refs #6582) (#9782)
  • c64195f Update: More detailed assert message for rule-tester (#9769)
  • 9fcfabf Fix: no-extra-parens false positive (fixes: #9755) (#9795)
  • 61e5fa0 Docs: Add table of contents to Node.js API docs (#9785)
  • 4c87f42 Fix: incorrect error messages of no-unused-vars (fixes #9774) (#9791)
  • bbabf34 Update: add ignoreComments option to indent rule (fixes #9018) (#9752)
  • db431cb Docs: HTTP -> HTTPS (fixes #9768) (#9768)
  • cbf0fb9 Docs: describe how to feature-detect scopeManager/visitorKeys support (#9764)
  • f7dcb70 Docs: Add note about "patch release pending" label to maintainer guide (#9763)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Tests for data with empty lines

I appreciate the tests included with the repo. I'm porting the solution to another language. My port was not working when the input data had empty lines. I noticed that none of the test cases included empty lines. Might be worth adding some.

For example:

    const a = ['AA', '', 'b', 'c', 'ZZ', '', 'z', '', '', '90', '', 'x'];
    const b = ['AA', '', 'd', 'c', 'ZZ', '', '', 'z', '', '99', '', 'x'];
    const result = Diff3.diffComm(a, b);

An in-range update of rollup is breaking the build 🚨

The devDependency rollup was updated from 1.9.2 to 1.9.3.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

rollup is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).

Release Notes for v1.9.3

2019-04-10

Bug Fixes

  • Simplify return expressions that are evaluated before the surrounding function is bound (#2803)

Pull Requests

  • #2803: Handle out-of-order binding of identifiers to improve tree-shaking (@lukastaegert)
Commits

The new version differs by 3 commits.

  • 516a06d 1.9.3
  • a5526ea Update changelog
  • c3d73ff Handle out-of-order binding of identifiers to improve tree-shaking (#2803)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Diff is working weird in some scenarios?

Hello,

We are experiencing a really weird behaviour with the following example:

const Diff3 = require('node-diff3');

const templateA = `
$capitalize($possessive([q#3])) Security Policies and Procedures were adopted as of (Date) by
`;

const templateB = `
$capitalize($possessive([q#3])) Security Policies and Procedures were adopted as of [Date] by

123
`;

const original = `
$capitalize($possessive([q#3])) Security Policies and Procedures were adopted as of (Date) by
`

const diffOutput = Diff3.diff3Merge(templateA, original, templateB, { stringSeparator: '\n' });
console.log(diffOutput[0].ok.join('\n'));
console.log(diffOutput);

My expectation from the code above is to get:

$capitalize($possessive([q#3])) Security Policies and Procedures were adopted as of (Date) by

123

However I am getting:

$capitalize($possessive([q#3])) Security Policies and Procedures were adopted as of [Date] by

123

Notice the parenthesis is not being applied to my [Date] piece. Any clue on what's happening? I am expecting to get a conflict but its not happening.

Thanks in advanced.

Version 10 of node.js has been released

Version 10 of Node.js (code name Dubnium) has been released! 🎊

To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:

  • Added the new Node.js version to your .travis.yml
  • The new Node.js version is in-range for the engines in 1 of your package.json files, so that was left alone

If you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.

More information on this issue

Greenkeeper has checked the engines key in any package.json file, the .nvmrc file, and the .travis.yml file, if present.

  • engines was only updated if it defined a single version, not a range.
  • .nvmrc was updated to Node.js 10
  • .travis.yml was only changed if there was a root-level node_js that didn’t already include Node.js 10, such as node or lts/*. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.

For many simpler .travis.yml configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖


FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper integration’s white list on Github. You'll find this list on your repo or organization’s settings page, under Installed GitHub Apps.

How to perform a merge?

I'm using diff3Merge to create a merge result but i'm trying to figure out how to actually apply it so I end up with a single final result (assuming no conflicts). How do I accomplish this?

TIA

Incorrect merge boundary placement

I have not had much time to investigate this in further detail, and I believe it may be an edge case that does not come up often in traditional diff3 applications, however, I am providing my findings in case this is unintended behavior.

When running diff3.merge on both fs files and strings containing HTML markup (mostly english sentences), with and without preprocessing to place each tag/word on its own line (thought that may be relevant), the following scenario results in a merge boundary that semantically adds additional text to the merged output instead by placing the text outside of the merge boundaries instead of inside:

Original (ancestor) file contains a sequence of spaced words.
File A adds a word to the sequence.
File B adds a word in the same place in the sequence, such that the last x letters match the first x letters of the following word.

For example:
x=2

O: 'I was touring'
A: 'I was here touring'
B: 'I was into touring'

Result:   'I was <<<<<<<<<here =========in>>>>>>>>>to touring'

In this case, the desired result is 'I was <<<<<<<<<here =========into>>>>>>>>> touring'.

I was able to replicate this for x=1 and x=3.

Could this be because the algorithm greedily examines the next token(s) and thus assumes any minimal match means it is done choosing text to be manually merged? Or perhaps I need to do additional processing on the data to achieve the result I want? Thank you.

generate separate ES5 bundle

I've been switching the code to use more ES6 JavaScript features, but I know that some people will still need this to work in a legacy browser like IE11, so I'm going to generate a compatible legacy build too. We already use rollup, so adding the buble plugin makes this easy.

Compatability with electron apps

i need to handle differential update serverside for my electron app. Will the library handle generating deltas between the two buffers of the apps and later appply the patch on top of the older version of the app to get the new one. will it work validly for this? thanks in advance

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.