diff --git a/src/diff-parser.js b/src/diff-parser.js index f83cf2a..cb1a8ce 100644 --- a/src/diff-parser.js +++ b/src/diff-parser.js @@ -133,19 +133,19 @@ var deletedFileMode = /^deleted file mode (\d{6})/; var newFileMode = /^new file mode (\d{6})/; - var copyFrom = /^copy from "?(.+?)"?/; - var copyTo = /^copy to "?(.+?)"?/; + var copyFrom = /^copy from "?(.+)"?/; + var copyTo = /^copy to "?(.+)"?/; - var renameFrom = /^rename from "?(.+?)"?/; - var renameTo = /^rename to "?(.+?)"?/; + var renameFrom = /^rename from "?(.+)"?/; + var renameTo = /^rename to "?(.+)"?/; var similarityIndex = /^similarity index (\d+)%/; var dissimilarityIndex = /^dissimilarity index (\d+)%/; - var index = /^index ([0-9a-z]+)..([0-9a-z]+) (\d{6})?/; + var index = /^index ([0-9a-z]+)\.\.([0-9a-z]+)\s*(\d{6})?/; /* Combined Diff */ - var combinedIndex = /^index ([0-9a-z]+),([0-9a-z]+)..([0-9a-z]+)/; - var combinedMode = /^mode (\d{6}),(\d{6})..(\d{6})/; + var combinedIndex = /^index ([0-9a-z]+),([0-9a-z]+)\.\.([0-9a-z]+)/; + var combinedMode = /^mode (\d{6}),(\d{6})\.\.(\d{6})/; var combinedNewFile = /^new file mode (\d{6})/; var combinedDeletedFile = /^deleted file mode (\d{6}),(\d{6})/; @@ -174,8 +174,10 @@ currentFile.newMode = values[1]; } else if ((values = deletedFileMode.exec(line))) { currentFile.deletedFileMode = values[1]; + currentFile.isDeleted = true; } else if ((values = newFileMode.exec(line))) { currentFile.newFileMode = values[1]; + currentFile.isNew = true; } else if ((values = copyFrom.exec(line))) { currentFile.oldName = values[1]; currentFile.isCopy = true; @@ -195,7 +197,7 @@ } else if ((values = index.exec(line))) { currentFile.checksumBefore = values[1]; currentFile.checksumAfter = values[2]; - values[2] && (currentFile.mode = values[3]); + values[3] && (currentFile.mode = values[3]); } else if ((values = combinedIndex.exec(line))) { currentFile.checksumBefore = [values[2], values[3]]; currentFile.checksumAfter = values[1]; @@ -204,8 +206,10 @@ currentFile.newMode = values[1]; } else if ((values = combinedNewFile.exec(line))) { currentFile.newFileMode = values[1]; + currentFile.isNew = true; } else if ((values = combinedDeletedFile.exec(line))) { currentFile.deletedFileMode = values[1]; + currentFile.isDeleted = true; } else if (currentBlock) { createLine(line); } @@ -229,7 +233,9 @@ function getSrcFilename(line, cfg) { var prefixes = ["a/", "i/", "w/", "c/", "o/"]; - if (cfg.srcPrefix) prefixes.push(cfg.srcPrefix); + if (cfg.srcPrefix) { + prefixes.push(cfg.srcPrefix); + } return _getFilename('---', line, prefixes); } @@ -237,7 +243,9 @@ function getDstFilename(line, cfg) { var prefixes = ["b/", "i/", "w/", "c/", "o/"]; - if (cfg.dstPrefix) prefixes.push(cfg.dstPrefix); + if (cfg.dstPrefix) { + prefixes.push(cfg.dstPrefix); + } return _getFilename('\\+\\+\\+', line, prefixes); } @@ -253,7 +261,10 @@ return filename.indexOf(p) === 0; }); - if (matchingPrefixes[0]) filename = filename.slice(matchingPrefixes[0].length); // remove prefix if exists + if (matchingPrefixes[0]) { + // Remove prefix if exists + filename = filename.slice(matchingPrefixes[0].length); + } } return filename; diff --git a/test/diff-parser-tests.js b/test/diff-parser-tests.js index 08e4881..d9789e0 100644 --- a/test/diff-parser-tests.js +++ b/test/diff-parser-tests.js @@ -106,5 +106,273 @@ describe('DiffParser', function() { assert.equal(1, file1.blocks.length); }); + it('should parse diff with deleted file', function() { + var diff = + 'diff --git a/src/var/strundefined.js b/src/var/strundefined.js\n' + + 'deleted file mode 100644\n' + + 'index 04e16b0..0000000\n' + + '--- a/src/var/strundefined.js\n' + + '+++ /dev/null\n' + + '@@ -1,3 +0,0 @@\n' + + '-define(function() {\n' + + '- return typeof undefined;\n' + + '-});\n'; + + var result = Diff2Html.getJsonFromDiff(diff); + assert.equal(1, result.length); + + var file1 = result[0]; + assert.equal(false, file1.isCombined); + assert.equal(0, file1.addedLines); + assert.equal(3, file1.deletedLines); + assert.equal('src/var/strundefined.js', file1.oldName); + assert.equal('/dev/null', file1.newName); + assert.equal(1, file1.blocks.length); + assert.equal(true, file1.isDeleted); + assert.equal('04e16b0', file1.checksumBefore); + assert.equal('0000000', file1.checksumAfter); + }); + + it('should parse diff with new file', function() { + var diff = + 'diff --git a/test.js b/test.js\n' + + 'new file mode 100644\n' + + 'index 0000000..e1e22ec\n' + + '--- /dev/null\n' + + '+++ b/test.js\n' + + '@@ -0,0 +1,5 @@\n' + + "+var parser = require('./source/git-parser');\n" + + '+\n' + + '+var patchLineList = [ false, false, false, false ];\n' + + '+\n' + + '+console.log(parser.parsePatchDiffResult(text, patchLineList));\n'; + + var result = Diff2Html.getJsonFromDiff(diff); + assert.equal(1, result.length); + + var file1 = result[0]; + assert.equal(false, file1.isCombined); + assert.equal(5, file1.addedLines); + assert.equal(0, file1.deletedLines); + assert.equal('/dev/null', file1.oldName); + assert.equal('test.js', file1.newName); + assert.equal(1, file1.blocks.length); + assert.equal(true, file1.isNew); + assert.equal(100644, file1.newFileMode); + assert.equal('0000000', file1.checksumBefore); + assert.equal('e1e22ec', file1.checksumAfter); + }); + + it('should parse diff with nested diff', function() { + var diff = + 'diff --git a/src/offset.js b/src/offset.js\n' + + 'index cc6ffb4..fa51f18 100644\n' + + '--- a/src/offset.js\n' + + '+++ b/src/offset.js\n' + + '@@ -1,6 +1,5 @@\n' + + "+var parser = require('./source/git-parser');\n" + + '+\n' + + "+var text = 'diff --git a/components/app/app.html b/components/app/app.html\\nindex ecb7a95..027bd9b 100644\\n--- a/components/app/app.html\\n+++ b/components/app/app.html\\n@@ -52,0 +53,3 @@\\n+\\n+\\n+\\n@@ -56,0 +60,3 @@\\n+\\n+\\n+\\n'\n" + + '+var patchLineList = [ false, false, false, false ];\n' + + '+\n' + + '+console.log(parser.parsePatchDiffResult(text, patchLineList));\n'; + + var result = Diff2Html.getJsonFromDiff(diff); + assert.equal(1, result.length); + + var file1 = result[0]; + assert.equal(false, file1.isCombined); + assert.equal(6, file1.addedLines); + assert.equal(0, file1.deletedLines); + assert.equal('src/offset.js', file1.oldName); + assert.equal('src/offset.js', file1.newName); + assert.equal(1, file1.blocks.length); + assert.equal(6, file1.blocks[0].lines.length); + assert.equal('cc6ffb4', file1.checksumBefore); + assert.equal('fa51f18', file1.checksumAfter); + }); + + it('should parse diff with multiple blocks', function() { + var diff = + 'diff --git a/src/attributes/classes.js b/src/attributes/classes.js\n' + + 'index c617824..c8d1393 100644\n' + + '--- a/src/attributes/classes.js\n' + + '+++ b/src/attributes/classes.js\n' + + '@@ -1,10 +1,9 @@\n' + + ' define([\n' + + ' "../core",\n' + + ' "../var/rnotwhite",\n' + + '- "../var/strundefined",\n' + + ' "../data/var/dataPriv",\n' + + ' "../core/init"\n' + + '-], function( jQuery, rnotwhite, strundefined, dataPriv ) {\n' + + '+], function( jQuery, rnotwhite, dataPriv ) {\n' + + ' \n' + + ' var rclass = /[\\t\\r\\n\\f]/g;\n' + + ' \n' + + '@@ -128,7 +127,7 @@ jQuery.fn.extend({\n' + + ' }\n' + + ' \n' + + ' // Toggle whole class name\n' + + '- } else if ( type === strundefined || type === "boolean" ) {\n' + + '+ } else if ( value === undefined || type === "boolean" ) {\n' + + ' if ( this.className ) {\n' + + ' // store className if set\n' + + ' dataPriv.set( this, "__className__", this.className );\n'; + + var result = Diff2Html.getJsonFromDiff(diff); + assert.equal(1, result.length); + + var file1 = result[0]; + assert.equal(false, file1.isCombined); + assert.equal(2, file1.addedLines); + assert.equal(3, file1.deletedLines); + assert.equal('src/attributes/classes.js', file1.oldName); + assert.equal('src/attributes/classes.js', file1.newName); + assert.equal(2, file1.blocks.length); + assert.equal(11, file1.blocks[0].lines.length); + assert.equal(8, file1.blocks[1].lines.length); + assert.equal('c617824', file1.checksumBefore); + assert.equal('c8d1393', file1.checksumAfter); + }); + + it('should parse diff with multiple files', function() { + var diff = + 'diff --git a/src/core/init.js b/src/core/init.js\n' + + 'index e49196a..50f310c 100644\n' + + '--- a/src/core/init.js\n' + + '+++ b/src/core/init.js\n' + + '@@ -101,7 +101,7 @@ var rootjQuery,\n' + + ' // HANDLE: $(function)\n' + + ' // Shortcut for document ready\n' + + ' } else if ( jQuery.isFunction( selector ) ) {\n' + + '- return typeof rootjQuery.ready !== "undefined" ?\n' + + '+ return rootjQuery.ready !== undefined ?\n' + + ' rootjQuery.ready( selector ) :\n' + + ' // Execute immediately if ready is not present\n' + + ' selector( jQuery );\n' + + 'diff --git a/src/event.js b/src/event.js\n' + + 'index 7336f4d..6183f70 100644\n' + + '--- a/src/event.js\n' + + '+++ b/src/event.js\n' + + '@@ -1,6 +1,5 @@\n' + + ' define([\n' + + ' "./core",\n' + + '- "./var/strundefined",\n' + + ' "./var/rnotwhite",\n' + + ' "./var/hasOwn",\n' + + ' "./var/slice",\n'; + + var result = Diff2Html.getJsonFromDiff(diff); + assert.equal(2, result.length); + + var file1 = result[0]; + assert.equal(false, file1.isCombined); + assert.equal(1, file1.addedLines); + assert.equal(1, file1.deletedLines); + assert.equal('src/core/init.js', file1.oldName); + assert.equal('src/core/init.js', file1.newName); + assert.equal(1, file1.blocks.length); + assert.equal(8, file1.blocks[0].lines.length); + assert.equal('e49196a', file1.checksumBefore); + assert.equal('50f310c', file1.checksumAfter); + + var file2 = result[1]; + assert.equal(false, file2.isCombined); + assert.equal(0, file2.addedLines); + assert.equal(1, file2.deletedLines); + assert.equal('src/event.js', file2.oldName); + assert.equal('src/event.js', file2.newName); + assert.equal(1, file2.blocks.length); + assert.equal(6, file2.blocks[0].lines.length); + assert.equal('7336f4d', file2.checksumBefore); + assert.equal('6183f70', file2.checksumAfter); + }); + + it('should parse combined diff', function() { + var diff = + 'diff --combined describe.c\n' + + 'index fabadb8,cc95eb0..4866510\n' + + '--- a/describe.c\n' + + '+++ b/describe.c\n' + + '@@@ -98,20 -98,12 +98,20 @@@\n' + + ' return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n' + + ' }\n' + + ' \n' + + '- static void describe(char *arg)\n' + + ' -static void describe(struct commit *cmit, int last_one)\n' + + '++static void describe(char *arg, int last_one)\n' + + ' {\n' + + ' + unsigned char sha1[20];\n' + + ' + struct commit *cmit;\n' + + ' struct commit_list *list;\n' + + ' static int initialized = 0;\n' + + ' struct commit_name *n;\n' + + ' \n' + + ' + if (get_sha1(arg, sha1) < 0)\n' + + ' + usage(describe_usage);\n' + + ' + cmit = lookup_commit_reference(sha1);\n' + + ' + if (!cmit)\n' + + ' + usage(describe_usage);\n' + + ' +\n' + + ' if (!initialized) {\n' + + ' initialized = 1;\n' + + ' for_each_ref(get_name);\n'; + + var result = Diff2Html.getJsonFromDiff(diff); + assert.equal(1, result.length); + + var file1 = result[0]; + assert.equal(true, file1.isCombined); + assert.equal(9, file1.addedLines); + assert.equal(2, file1.deletedLines); + assert.equal('describe.c', file1.oldName); + assert.equal('describe.c', file1.newName); + assert.equal(1, file1.blocks.length); + assert.equal(22, file1.blocks[0].lines.length); + assert.deepEqual(['4866510', 'cc95eb0'].sort(), file1.checksumBefore.sort()); + assert.equal('fabadb8', file1.checksumAfter); + }); + + it('should parse diffs with copied files', function() { + var diff = + 'diff --git a/index.js b/more-index.js\n' + + 'dissimilarity index 5%\n' + + 'copy from index.js\n' + + 'copy to more-index.js\n'; + + var result = Diff2Html.getJsonFromDiff(diff); + assert.equal(1, result.length); + + var file1 = result[0]; + assert.equal(0, file1.addedLines); + assert.equal(0, file1.deletedLines); + assert.equal('index.js', file1.oldName); + assert.equal('more-index.js', file1.newName); + assert.equal(0, file1.blocks.length); + assert.equal(true, file1.isCopy); + assert.equal(5, file1.changedPercentage); + }); + + it('should parse diffs with moved files', function() { + var diff = + 'diff --git a/more-index.js b/other-index.js\n' + + 'similarity index 86%\n' + + 'rename from more-index.js\n' + + 'rename to other-index.js\n'; + + var result = Diff2Html.getJsonFromDiff(diff); + assert.equal(1, result.length); + + var file1 = result[0]; + assert.equal(0, file1.addedLines); + assert.equal(0, file1.deletedLines); + assert.equal('more-index.js', file1.oldName); + assert.equal('other-index.js', file1.newName); + assert.equal(0, file1.blocks.length); + assert.equal(true, file1.isRename); + assert.equal(86, file1.unchangedPercentage); + }); + }); });