parse-diff
Advanced tools
Comparing version 0.7.1 to 0.8.0
const parse = require("../index"); | ||
describe("diff parser", function() { | ||
describe("diff parser", function () { | ||
it("should parse null", () => { | ||
@@ -16,3 +16,3 @@ expect(parse(null).length).toBe(0); | ||
it("should parse simple git-like diff", function() { | ||
it("should parse simple git-like diff", function () { | ||
const diff = `\ | ||
@@ -32,2 +32,4 @@ diff --git a/file b/file | ||
expect(file.to).toBe("file"); | ||
expect(file.deletions).toBe(1); | ||
expect(file.additions).toBe(1); | ||
expect(file.chunks.length).toBe(1); | ||
@@ -41,3 +43,3 @@ const chunk = file.chunks[0]; | ||
it("should parse simple git-like diff with file enclosed by double-quote", function() { | ||
it("should parse simple git-like diff with file enclosed by double-quote", function () { | ||
const diff = `\ | ||
@@ -57,3 +59,3 @@ diff --git "a/file1" "b/file2" | ||
it('should parse file names for changed binaries with spaces in their names', function() { | ||
it("should parse file names for changed binaries with spaces in their names", function () { | ||
const diff = `\ | ||
@@ -65,9 +67,13 @@ diff --git a/Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png b/Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png | ||
const files = parse(diff); | ||
expect(files.length).toBe(1) | ||
const file = files[0] | ||
expect(file.from).toBe("Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png") | ||
expect(file.to).toBe("Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png") | ||
expect(files.length).toBe(1); | ||
const file = files[0]; | ||
expect(file.from).toBe( | ||
"Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png" | ||
); | ||
expect(file.to).toBe( | ||
"Artsy_Tests/ReferenceImages/ARTopMenuViewControllerSpec/selects 'home' by default as ipad@2x.png" | ||
); | ||
}); | ||
it("should parse diff with new file mode line", function() { | ||
it("should parse diff with new file mode line", function () { | ||
const diff = `\ | ||
@@ -95,3 +101,3 @@ diff --git a/test b/test | ||
it("should parse diff with deleted file mode line", function() { | ||
it("should parse diff with deleted file mode line", function () { | ||
const diff = `\ | ||
@@ -119,3 +125,3 @@ diff --git a/test b/test | ||
it("should parse diff with single line files", function() { | ||
it("should parse diff with single line files", function () { | ||
const diff = `\ | ||
@@ -161,3 +167,3 @@ diff --git a/file1 b/file1 | ||
it("should parse multiple files in diff", function() { | ||
it("should parse multiple files in diff", function () { | ||
const diff = `\ | ||
@@ -197,3 +203,3 @@ diff --git a/file1 b/file1 | ||
it("should parse diff with EOF flag", function() { | ||
it("should parse diff with EOF flag", function () { | ||
const diff = `\ | ||
@@ -223,3 +229,3 @@ diff --git a/file1 b/file1 | ||
it("should parse gnu sample diff", function() { | ||
it("should parse gnu sample diff", function () { | ||
const diff = `\ | ||
@@ -264,3 +270,3 @@ --- lao 2002-02-21 23:30:39.942229878 -0800 | ||
it("should parse hg diff output", function() { | ||
it("should parse hg diff output", function () { | ||
const diff = `\ | ||
@@ -289,3 +295,3 @@ diff -r 514fc757521e lib/parsers.coffee | ||
it("should parse svn diff output", function() { | ||
it("should parse svn diff output", function () { | ||
const diff = `\ | ||
@@ -321,3 +327,3 @@ Index: new.txt | ||
it("should parse file names for n new empty file", function() { | ||
it("should parse file names for n new empty file", function () { | ||
const diff = `\ | ||
@@ -335,3 +341,3 @@ diff --git a/newFile.txt b/newFile.txt | ||
it("should parse file names for a deleted file", function() { | ||
it("should parse file names for a deleted file", function () { | ||
const diff = `\ | ||
@@ -349,3 +355,3 @@ diff --git a/deletedFile.txt b/deletedFile.txt | ||
it("should parse rename diff with space in path with no changes", function() { | ||
it("should parse rename diff with space in path with no changes", function () { | ||
const diff = `\ | ||
@@ -365,3 +371,3 @@ diff --git a/My Folder/File b/My Folder/a/File | ||
it("should parse rename diff with space in path with changes", function() { | ||
it("should parse rename diff with space in path with changes", function () { | ||
const diff = `\ | ||
@@ -368,0 +374,0 @@ diff --git a/My Folder/File b/My Folder/a/File |
216
index.js
@@ -1,214 +0,2 @@ | ||
// Generated by CoffeeScript 2.5.1 | ||
// parses unified diff | ||
// http://www.gnu.org/software/diffutils/manual/diffutils.html#Unified-Format | ||
var defaultToWhiteSpace, escapeRegExp, ltrim, makeString, parseFile, parseFileFallback, trimLeft, | ||
slice = [].slice; | ||
module.exports = function(input) { | ||
var add, chunk, current, del, deleted_file, eof, file, files, from_file, index, j, len, line, lines, ln_add, ln_del, new_file, normal, parse, restart, schema, start, to_file; | ||
if (!input) { | ||
return []; | ||
} | ||
if (input.match(/^\s+$/)) { | ||
return []; | ||
} | ||
lines = input.split('\n'); | ||
if (lines.length === 0) { | ||
return []; | ||
} | ||
files = []; | ||
file = null; | ||
ln_del = 0; | ||
ln_add = 0; | ||
current = null; | ||
start = function(line) { | ||
var fileNames; | ||
file = { | ||
chunks: [], | ||
deletions: 0, | ||
additions: 0 | ||
}; | ||
files.push(file); | ||
if (!file.to && !file.from) { | ||
fileNames = parseFile(line); | ||
if (fileNames) { | ||
file.from = fileNames[0]; | ||
return file.to = fileNames[1]; | ||
} | ||
} | ||
}; | ||
restart = function() { | ||
if (!file || file.chunks.length) { | ||
return start(); | ||
} | ||
}; | ||
new_file = function() { | ||
restart(); | ||
file.new = true; | ||
return file.from = '/dev/null'; | ||
}; | ||
deleted_file = function() { | ||
restart(); | ||
file.deleted = true; | ||
return file.to = '/dev/null'; | ||
}; | ||
index = function(line) { | ||
restart(); | ||
return file.index = line.split(' ').slice(1); | ||
}; | ||
from_file = function(line) { | ||
restart(); | ||
return file.from = parseFileFallback(line); | ||
}; | ||
to_file = function(line) { | ||
restart(); | ||
return file.to = parseFileFallback(line); | ||
}; | ||
chunk = function(line, match) { | ||
var newLines, newStart, oldLines, oldStart; | ||
ln_del = oldStart = +match[1]; | ||
oldLines = +(match[2] || 1); | ||
ln_add = newStart = +match[3]; | ||
newLines = +(match[4] || 1); | ||
current = { | ||
content: line, | ||
changes: [], | ||
oldStart, | ||
oldLines, | ||
newStart, | ||
newLines | ||
}; | ||
return file.chunks.push(current); | ||
}; | ||
del = function(line) { | ||
if (!current) { | ||
return; | ||
} | ||
current.changes.push({ | ||
type: 'del', | ||
del: true, | ||
ln: ln_del++, | ||
content: line | ||
}); | ||
return file.deletions++; | ||
}; | ||
add = function(line) { | ||
if (!current) { | ||
return; | ||
} | ||
current.changes.push({ | ||
type: 'add', | ||
add: true, | ||
ln: ln_add++, | ||
content: line | ||
}); | ||
return file.additions++; | ||
}; | ||
normal = function(line) { | ||
if (!current) { | ||
return; | ||
} | ||
return current.changes.push({ | ||
type: 'normal', | ||
normal: true, | ||
ln1: ln_del++, | ||
ln2: ln_add++, | ||
content: line | ||
}); | ||
}; | ||
eof = function(line) { | ||
var recentChange, ref; | ||
ref = current.changes, [recentChange] = slice.call(ref, -1); | ||
return current.changes.push({ | ||
type: recentChange.type, | ||
[`${recentChange.type}`]: true, | ||
ln1: recentChange.ln1, | ||
ln2: recentChange.ln2, | ||
ln: recentChange.ln, | ||
content: line | ||
}); | ||
}; | ||
// todo beter regexp to avoid detect normal line starting with diff | ||
schema = [[/^\s+/, normal], [/^diff\s/, start], [/^new file mode \d+$/, new_file], [/^deleted file mode \d+$/, deleted_file], [/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/, index], [/^---\s/, from_file], [/^\+\+\+\s/, to_file], [/^@@\s+\-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/, chunk], [/^-/, del], [/^\+/, add], [/^\\ No newline at end of file$/, eof]]; | ||
parse = function(line) { | ||
var j, len, m, p; | ||
for (j = 0, len = schema.length; j < len; j++) { | ||
p = schema[j]; | ||
m = line.match(p[0]); | ||
if (m) { | ||
p[1](line, m); | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
for (j = 0, len = lines.length; j < len; j++) { | ||
line = lines[j]; | ||
parse(line); | ||
} | ||
return files; | ||
}; | ||
parseFile = function(s) { | ||
var fileNames; | ||
if (!s) { | ||
return; | ||
} | ||
fileNames = s.match(/a\/.*(?=["']? ["']?b\/)|b\/.*$/g); | ||
fileNames.map(function(fileName, i) { | ||
return fileNames[i] = fileName.replace(/^(a|b)\//, '').replace(/("|')$/, ''); | ||
}); | ||
return fileNames; | ||
}; | ||
// fallback function to overwrite file.from and file.to if executed | ||
parseFileFallback = function(s) { | ||
var t; | ||
s = ltrim(s, '-'); | ||
s = ltrim(s, '+'); | ||
s = s.trim(); | ||
// ignore possible time stamp | ||
t = /\t.*|\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/.exec(s); | ||
if (t) { | ||
s = s.substring(0, t.index).trim(); | ||
} | ||
// ignore git prefixes a/ or b/ | ||
if (s.match(/^(a|b)\//)) { | ||
return s.substr(2); | ||
} else { | ||
return s; | ||
} | ||
}; | ||
ltrim = function(s, chars) { | ||
s = makeString(s); | ||
if (!chars && trimLeft) { | ||
return trimLeft.call(s); | ||
} | ||
chars = defaultToWhiteSpace(chars); | ||
return s.replace(new RegExp('^' + chars + '+'), ''); | ||
}; | ||
makeString = function(s) { | ||
if (s === null) { | ||
return ''; | ||
} else { | ||
return s + ''; | ||
} | ||
}; | ||
trimLeft = String.prototype.trimLeft; | ||
defaultToWhiteSpace = function(chars) { | ||
if (chars === null) { | ||
return '\\s'; | ||
} | ||
if (chars.source) { | ||
return chars.source; | ||
} | ||
return '[' + escapeRegExp(chars) + ']'; | ||
}; | ||
escapeRegExp = function(s) { | ||
return makeString(s).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); | ||
}; | ||
"use strict";function _createForOfIteratorHelper(o,allowArrayLike){var it;if(typeof Symbol==="undefined"||o[Symbol.iterator]==null){if(Array.isArray(o)||(it=_unsupportedIterableToArray(o))||allowArrayLike&&o&&typeof o.length==="number"){if(it)o=it;var i=0;var F=function F(){};return{s:F,n:function n(){if(i>=o.length)return{done:true};return{done:false,value:o[i++]}},e:function e(_e2){throw _e2},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var normalCompletion=true,didErr=false,err;return{s:function s(){it=o[Symbol.iterator]()},n:function n(){var step=it.next();normalCompletion=step.done;return step},e:function e(_e3){didErr=true;err=_e3},f:function f(){try{if(!normalCompletion&&it["return"]!=null)it["return"]()}finally{if(didErr)throw err}}}}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_unsupportedIterableToArray(arr,i)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(o,minLen){if(!o)return;if(typeof o==="string")return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);if(n==="Object"&&o.constructor)n=o.constructor.name;if(n==="Map"||n==="Set")return Array.from(o);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen)}function _arrayLikeToArray(arr,len){if(len==null||len>arr.length)len=arr.length;for(var i=0,arr2=new Array(len);i<len;i++){arr2[i]=arr[i]}return arr2}function _iterableToArrayLimit(arr,i){if(typeof Symbol==="undefined"||!(Symbol.iterator in Object(arr)))return;var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i["return"]!=null)_i["return"]()}finally{if(_d)throw _e}}return _arr}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr}module.exports=function(input){if(!input)return[];if(typeof input!=="string"||input.match(/^\s+$/))return[];var lines=input.split("\n");if(lines.length===0)return[];var files=[];var currentFile=null;var currentChunk=null;var deletedLineCounter=0;var addedLineCounter=0;var normal=function normal(line){var _currentChunk;(_currentChunk=currentChunk)===null||_currentChunk===void 0?void 0:_currentChunk.changes.push({type:"normal",normal:true,ln1:deletedLineCounter++,ln2:addedLineCounter++,content:line})};var start=function start(line){var _parseFiles;var _ref=(_parseFiles=parseFiles(line))!==null&&_parseFiles!==void 0?_parseFiles:[],_ref2=_slicedToArray(_ref,2),fromFileName=_ref2[0],toFileName=_ref2[1];currentFile={chunks:[],deletions:0,additions:0,from:fromFileName,to:toFileName};files.push(currentFile)};var restart=function restart(){if(!currentFile||currentFile.chunks.length)start()};var newFile=function newFile(){restart();currentFile["new"]=true;currentFile.from="/dev/null"};var deletedFile=function deletedFile(){restart();currentFile.deleted=true;currentFile.to="/dev/null"};var index=function index(line){restart();currentFile.index=line.split(" ").slice(1)};var fromFile=function fromFile(line){restart();currentFile.from=parseOldOrNewFile(line)};var toFile=function toFile(line){restart();currentFile.to=parseOldOrNewFile(line)};var chunk=function chunk(line,match){if(!currentFile)return;var _match$slice=match.slice(1),_match$slice2=_slicedToArray(_match$slice,4),oldStart=_match$slice2[0],oldNumLines=_match$slice2[1],newStart=_match$slice2[2],newNumLines=_match$slice2[3];deletedLineCounter=+oldStart;addedLineCounter=+newStart;currentChunk={content:line,changes:[],oldStart:+oldStart,oldLines:+(oldNumLines||1),newStart:+newStart,newLines:+(newNumLines||1)};currentFile.chunks.push(currentChunk)};var del=function del(line){if(!currentChunk)return;currentChunk.changes.push({type:"del",del:true,ln:deletedLineCounter++,content:line});currentFile.deletions++};var add=function add(line){if(!currentChunk)return;currentChunk.changes.push({type:"add",add:true,ln:addedLineCounter++,content:line});currentFile.additions++};var eof=function eof(line){var _currentChunk$changes3;if(!currentChunk)return;var _currentChunk$changes=currentChunk.changes.slice(-1),_currentChunk$changes2=_slicedToArray(_currentChunk$changes,1),mostRecentChange=_currentChunk$changes2[0];currentChunk.changes.push((_currentChunk$changes3={type:mostRecentChange.type},_defineProperty(_currentChunk$changes3,mostRecentChange.type,true),_defineProperty(_currentChunk$changes3,"ln1",mostRecentChange.ln1),_defineProperty(_currentChunk$changes3,"ln2",mostRecentChange.ln2),_defineProperty(_currentChunk$changes3,"ln",mostRecentChange.ln),_defineProperty(_currentChunk$changes3,"content",line),_currentChunk$changes3))};var schema=[// TODO: better regexp to avoid detect normal line starting with diff | ||
[/^\s+/,normal],[/^diff\s/,start],[/^new file mode \d+$/,newFile],[/^deleted file mode \d+$/,deletedFile],[/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/,index],[/^---\s/,fromFile],[/^\+\+\+\s/,toFile],[/^@@\s+-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/,chunk],[/^-/,del],[/^\+/,add],[/^\\ No newline at end of file$/,eof]];var parseLine=function parseLine(line){var _iterator=_createForOfIteratorHelper(schema),_step;try{for(_iterator.s();!(_step=_iterator.n()).done;){var _step$value=_slicedToArray(_step.value,2),pattern=_step$value[0],handler=_step$value[1];var match=line.match(pattern);if(match){handler(line,match);return true}}}catch(err){_iterator.e(err)}finally{_iterator.f()}return false};var _iterator2=_createForOfIteratorHelper(lines),_step2;try{for(_iterator2.s();!(_step2=_iterator2.n()).done;){var line=_step2.value;parseLine(line)}}catch(err){_iterator2.e(err)}finally{_iterator2.f()}return files};var fileNameDiffRegex=/a\/.*(?=["']? ["']?b\/)|b\/.*$/g;var parseFiles=function parseFiles(line){var fileNames=line===null||line===void 0?void 0:line.match(fileNameDiffRegex);return fileNames===null||fileNames===void 0?void 0:fileNames.map(function(fileName){return fileName.replace(/^(a|b)\//,"").replace(/("|')$/,"")})};var parseOldOrNewFile=function parseOldOrNewFile(line){var fileName=leftTrimChars(line,"-+").trim();fileName=removeTimeStamp(fileName);return /^(a|b)\//.test(fileName)?fileName.substr(2):fileName};var leftTrimChars=function leftTrimChars(string,trimmingChars){string=makeString(string);if(!trimmingChars&&String.prototype.trimLeft)return string.trimLeft();var trimmingString=formTrimmingString(trimmingChars);return string.replace(new RegExp("^".concat(trimmingString,"+")),"")};var timeStampRegex=/\t.*|\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/;var removeTimeStamp=function removeTimeStamp(string){var timeStamp=timeStampRegex.exec(string);if(timeStamp){string=string.substring(0,timeStamp.index).trim()}return string};var formTrimmingString=function formTrimmingString(trimmingChars){if(trimmingChars===null||trimmingChars===undefined)return"\\s";else if(trimmingChars instanceof RegExp)return trimmingChars.source;return"[".concat(makeString(trimmingChars).replace(/([.*+?^=!:${}()|[\]/\\])/g,"\\$1"),"]")};var makeString=function makeString(itemToConvert){return(itemToConvert!==null&&itemToConvert!==void 0?itemToConvert:"")+""}; |
{ | ||
"name": "parse-diff", | ||
"version": "0.7.1", | ||
"version": "0.8.0", | ||
"description": "Unified diff parser", | ||
@@ -19,11 +19,17 @@ "author": "Sergey Todyshev <stodyshev@gmail.com>", | ||
"devDependencies": { | ||
"coffeelint": "^2.1.0", | ||
"coffeescript": "^2.5.1", | ||
"jest": "^26.4.2" | ||
"@babel/cli": "^7.13.10", | ||
"@babel/core": "^7.13.10", | ||
"@babel/preset-env": "^7.13.10", | ||
"eslint": "^7.21.0", | ||
"eslint-config-prettier": "^8.1.0", | ||
"eslint-plugin-prettier": "^3.3.1", | ||
"jest": "^26.6.3", | ||
"prettier": "^2.2.1" | ||
}, | ||
"scripts": { | ||
"lint": "coffeelint *.coffee", | ||
"build": "coffee -b -o index.js parse.coffee", | ||
"format": "eslint --fix parse.js __tests__/*.js", | ||
"lint": "eslint parse.js __tests__/*.js", | ||
"build": "babel -o index.js --minified parse.js", | ||
"test": "jest" | ||
} | ||
} |
@@ -1,3 +0,2 @@ | ||
[![Build Status](https://travis-ci.org/sergeyt/parse-diff.svg?branch=master)](https://travis-ci.org/sergeyt/parse-diff) | ||
[![DevDeps Status](https://david-dm.org/sergeyt/parse-diff/dev-status.png)](https://david-dm.org/sergeyt/parse-diff#info=devDependencies) | ||
[![Build Status](https://github.com/sergeyt/parse-diff/actions/workflows/ci.yml/badge.svg)](https://github.com/sergeyt/parse-diff/actions/workflows/ci.yml) | ||
[![Total downloads](https://img.shields.io/npm/dt/parse-diff.svg)](https://www.npmjs.com/package/parse-diff) | ||
@@ -9,3 +8,3 @@ | ||
Simple unified diff parser for nodejs | ||
Simple unified diff parser for JavaScript | ||
@@ -12,0 +11,0 @@ ## JavaScript Usage Example |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28619
12
623
8
25