Repository: kpdecker/jsdiff (JavaScript)

Issue:
`callback` option has a weird signature
The diffing functions take a (currently undocumented) `callback` option. If provided, the diff is calculated in async mode and the result is passed as the *second* argument to the `callback` function.

Unless I'm missing something, the *first* argument is just... never provided. It's *always* `undefined`, whether the diff is calculated successfully or not.

This seems pretty bizarre. We should just eliminate the first argument.


Discussion:

Patch:
diff --git a/README.md b/README.md
index e360548b..9433575a 100644
--- a/README.md
+++ b/README.md
@@ -157,7 +157,7 @@ Broadly, jsdiff's diff functions all take an old text and a new text and perform
 
 Certain options can be provided in the `options` object of *any* method that calculates a diff:
 
-* `callback`: if provided, the diff will be computed in async mode to avoid blocking the event loop while the diff is calculated. The value of the `callback` option should be a function and will be passed the result of the diff as its second argument. The first argument will always be undefined. Only works with functions that return change objects, like `diffLines`, not those that return patches, like `structuredPatch` or `createPatch`.
+* `callback`: if provided, the diff will be computed in async mode to avoid blocking the event loop while the diff is calculated. The value of the `callback` option should be a function and will be passed the result of the diff as its first argument. Only works with functions that return change objects, like `diffLines`, not those that return patches, like `structuredPatch` or `createPatch`.
 
   (Note that if the ONLY option you want to provide is a callback, you can pass the callback function directly as the `options` parameter instead of passing an object with a `callback` property.)
 
diff --git a/release-notes.md b/release-notes.md
index 14a25faf..58a879ac 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -12,6 +12,7 @@
 - [#467](https://github.com/kpdecker/jsdiff/pull/467) When passing a `comparator(left, right)` to `diffArrays`, values from the old array will now consistently be passed as the first argument (`left`) and values from the new array as the second argument (`right`). Previously this was almost (but not quite) always the other way round.
 - [#480](https://github.com/kpdecker/jsdiff/pull/480) Passing `maxEditLength` to `createPatch` & `createTwoFilesPatch` now works properly (i.e. returns undefined if the max edit distance is exceeded; previous behavior was to crash with a `TypeError` if the edit distance was exceeded).
 - [#486](https://github.com/kpdecker/jsdiff/pull/486) The `ignoreWhitespace` option of `diffLines` behaves more sensibly now. `value`s in returned change objects now include leading/trailing whitespace even when `ignoreWhitespace` is used, just like how with `ignoreCase` the `value`s still reflect the case of one of the original texts instead of being all-lowercase. `ignoreWhitespace` is also now compatible with `newlineIsToken`. Finally, `diffTrimmedLines` is deprecated (and removed from the docs) in favour of using `diffLines` with `ignoreWhitespace: true`; the two are, and always have been, equivalent.
+- [#490](https://github.com/kpdecker/jsdiff/pull/490) When calling diffing functions in async mode by passing a `callback` option, the diff result will now be passed as the *first* argument to the callback instead of the second. (Previously, the first argument was never used at all and would always have value `undefined`.)
 
 ## v5.2.0
 
diff --git a/src/diff/base.js b/src/diff/base.js
index 489cce9d..38ef9216 100644
--- a/src/diff/base.js
+++ b/src/diff/base.js
@@ -13,7 +13,7 @@ Diff.prototype = {
 
     function done(value) {
       if (callback) {
-        setTimeout(function() { callback(undefined, value); }, 0);
+        setTimeout(function() { callback(value); }, 0);
         return true;
       } else {
         return value;


Test patch:
diff --git a/test/diff/word.js b/test/diff/word.js
index 4086ae21..4deb84c4 100644
--- a/test/diff/word.js
+++ b/test/diff/word.js
@@ -102,16 +102,14 @@ describe('WordDiff', function() {
 
   describe('#diffWords - async', function() {
     it('should diff whitespace', function(done) {
-      diffWords('New Value', 'New  ValueMoreData', function(err, diffResult) {
-        expect(err).to.be.undefined;
+      diffWords('New Value', 'New  ValueMoreData', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('New  <del>Value</del><ins>ValueMoreData</ins>');
         done();
       });
     });
 
     it('should diff multiple whitespace values', function(done) {
-      diffWords('New Value  ', 'New  ValueMoreData ', function(err, diffResult) {
-        expect(err).to.be.undefined;
+      diffWords('New Value  ', 'New  ValueMoreData ', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('New  <del>Value</del><ins>ValueMoreData</ins> ');
         done();
       });
@@ -119,8 +117,7 @@ describe('WordDiff', function() {
 
     // Diff on word boundary
     it('should diff on word boundaries', function(done) {
-      diffWords('New :Value:Test', 'New  ValueMoreData ', function(err, diffResult) {
-        expect(err).to.be.undefined;
+      diffWords('New :Value:Test', 'New  ValueMoreData ', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('New  <del>:Value:Test</del><ins>ValueMoreData </ins>');
         done();
       });
@@ -128,22 +125,19 @@ describe('WordDiff', function() {
 
     // Diff without changes
     it('should handle identity', function(done) {
-      diffWords('New Value', 'New Value', function(err, diffResult) {
-        expect(err).to.be.undefined;
+      diffWords('New Value', 'New Value', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('New Value');
         done();
       });
     });
     it('should handle empty', function(done) {
-      diffWords('', '', function(err, diffResult) {
-        expect(err).to.be.undefined;
+      diffWords('', '', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('');
         done();
       });
     });
     it('should diff has identical content', function(done) {
-      diffWords('New Value', 'New  Value', function(err, diffResult) {
-        expect(err).to.be.undefined;
+      diffWords('New Value', 'New  Value', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('New  Value');
         done();
       });
@@ -151,14 +145,14 @@ describe('WordDiff', function() {
 
     // Empty diffs
     it('should diff empty new content', function(done) {
-      diffWords('New Value', '', function(err, diffResult) {
+      diffWords('New Value', '', function(diffResult) {
         expect(diffResult.length).to.equal(1);
         expect(convertChangesToXML(diffResult)).to.equal('<del>New Value</del>');
         done();
       });
     });
     it('should diff empty old content', function(done) {
-      diffWords('', 'New Value', function(err, diffResult) {
+      diffWords('', 'New Value', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('<ins>New Value</ins>');
         done();
       });
@@ -166,7 +160,7 @@ describe('WordDiff', function() {
 
     // With without anchor (the Heckel algorithm error case)
     it('should diff when there is no anchor value', function(done) {
-      diffWords('New Value New Value', 'Value Value New New', function(err, diffResult) {
+      diffWords('New Value New Value', 'Value Value New New', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('<del>New</del><ins>Value</ins> Value New <del>Value</del><ins>New</ins>');
         done();
       });
@@ -219,7 +213,7 @@ describe('WordDiff', function() {
     });
 
     it('should perform async operations', function(done) {
-      diffWordsWithSpace('New Value  ', 'New  ValueMoreData ', function(err, diffResult) {
+      diffWordsWithSpace('New Value  ', 'New  ValueMoreData ', function(diffResult) {
         expect(convertChangesToXML(diffResult)).to.equal('New<del> Value</del>  <ins>ValueMoreData </ins>');
         done();
       });