react-diff-view
Advanced tools
Comparing version 1.4.11 to 1.5.0
{ | ||
"name": "react-diff-view", | ||
"version": "1.4.11", | ||
"version": "1.5.0", | ||
"description": "A git diff component to consume the git unified diff output.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "jest", | ||
"start": "webpack-dev-server --config=webpack.demo.config.js", | ||
"build": "webpack --config=webpack.build.config.js", | ||
"prepare": "npm run lint && npm run build", | ||
"prepublishOnly": "npm run lint && npm run build", | ||
"lint": "eslint src demo" | ||
@@ -16,3 +17,2 @@ }, | ||
"classnames": "^2.2.5", | ||
"diff": "^3.4.0", | ||
"gitdiff-parser": "0.0.8", | ||
@@ -23,35 +23,42 @@ "leven": "^2.1.0", | ||
"lodash.mapvalues": "^4.6.0", | ||
"warning": "^3.0.0" | ||
"warning": "^4.0.1" | ||
}, | ||
"devDependencies": { | ||
"antd": "^2.13.11", | ||
"@ecomfe/eslint-config": "^1.0.0", | ||
"antd": "^3.2.3", | ||
"babel-core": "^6.26.0", | ||
"babel-eslint": "^7.2.3", | ||
"babel-loader": "^7.1.2", | ||
"babel-plugin-add-react-displayname": "0.0.4", | ||
"babel-eslint": "^8.2.2", | ||
"babel-jest": "^23.0.1", | ||
"babel-loader": "^7.1.4", | ||
"babel-plugin-add-react-displayname": "0.0.5", | ||
"babel-plugin-react-require": "^3.0.0", | ||
"babel-plugin-transform-decorators-legacy": "^1.3.4", | ||
"babel-polyfill": "^6.26.0", | ||
"babel-preset-env": "^1.6.1", | ||
"babel-preset-es2015": "^6.24.1", | ||
"babel-preset-react": "^6.24.1", | ||
"babel-preset-stage-0": "^6.24.1", | ||
"case-sensitive-paths-webpack-plugin": "^2.1.1", | ||
"copy-webpack-plugin": "^4.2.3", | ||
"css-loader": "^0.28.5", | ||
"eslint": "^4.12.1", | ||
"eslint-plugin-react": "^7.5.1", | ||
"extract-text-webpack-plugin": "^3.0.2", | ||
"html-webpack-plugin": "^2.30.1", | ||
"copy-webpack-plugin": "^4.5.0", | ||
"css-loader": "^0.28.10", | ||
"diff": "^3.5.0", | ||
"eslint": "^4.18.2", | ||
"eslint-loader": "^2.0.0", | ||
"eslint-plugin-babel": "^5.1.0", | ||
"eslint-plugin-import": "^2.12.0", | ||
"eslint-plugin-react": "^7.7.0", | ||
"extract-text-webpack-plugin": "^4.0.0-beta.0", | ||
"html-webpack-plugin": "^3.0.6", | ||
"jest": "^23.1.0", | ||
"lang-map": "^0.4.0", | ||
"lodash": "^4.17.4", | ||
"lodash-decorators": "^4.5.0", | ||
"lodash": "^4.17.5", | ||
"lodash-decorators": "^5.0.1", | ||
"path-parse": "^1.0.5", | ||
"prismjs": "^1.9.0", | ||
"prismjs": "^1.11.0", | ||
"raw-loader": "^0.5.1", | ||
"react": "^16.2.0", | ||
"react-addons-perf": "^15.4.2", | ||
"react-dom": "^16.2.0", | ||
"react-infinite-scroller": "^1.1.1", | ||
"react-markdown": "^2.5.1", | ||
"react-timeago": "^3.4.3", | ||
"react-infinite-scroller": "^1.1.3", | ||
"react-markdown": "^3.3.0", | ||
"react-test-renderer": "^16.2.0", | ||
"react-timeago": "^4.1.9", | ||
"react-whether": "^1.0.1", | ||
@@ -61,12 +68,13 @@ "reselect": "^3.0.1", | ||
"short-hash": "^1.0.0", | ||
"style-loader": "^0.18.2", | ||
"sinon": "^5.0.10", | ||
"style-loader": "^0.21.0", | ||
"svg-react-loader": "^0.4.5", | ||
"uglifyjs-webpack-plugin": "^1.1.2", | ||
"webpack": "^3.10.0", | ||
"webpack-dev-server": "^2.9.7", | ||
"worker-loader": "^0.8.1" | ||
"webpack": "^4.1.0", | ||
"webpack-cli": "^2.1.5", | ||
"webpack-dev-server": "^3.1.4", | ||
"worker-loader": "^2.0.0" | ||
}, | ||
"peerDependencies": { | ||
"react": "^15.6.2 || ^16.0.0", | ||
"prop-types": "^15.6.0" | ||
"react": ">=15.6.2", | ||
"prop-types": ">=15.6.0" | ||
}, | ||
@@ -97,3 +105,25 @@ "repository": { | ||
"src" | ||
] | ||
], | ||
"jest": { | ||
"collectCoverage": true, | ||
"coverageDirectory": "coverage", | ||
"verbose": true, | ||
"roots": [ | ||
"./test" | ||
], | ||
"transform": { | ||
"^.+\\.jsx?$": "babel-jest" | ||
}, | ||
"coverageThreshold": { | ||
"global": { | ||
"branches": 78, | ||
"functions": 90, | ||
"lines": 90, | ||
"statements": 90 | ||
} | ||
}, | ||
"setupFiles": [ | ||
"./test/setupTest" | ||
] | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.reactDiffView=n():e.reactDiffView=n()}("undefined"!=typeof self?self:this,function(){return function(e){function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var t={};return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=4)}([,,,,function(e,n,t){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),t.d(n,"parseDiff",function(){return l}),t.d(n,"addStubHunk",function(){return f});var r=t(5),i=t.n(r),o=t(6),u=t.n(o),a=Object.assign||function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])}return e},s=function(){return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,n){var t=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(t.push(u.value),!n||t.length!==n);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return t}(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),c=function(e,n){var t="zip"===n.nearbySequences?function(e){var n=e.reduce(function(e,n,t){var r=s(e,3),i=r[0],o=r[1],u=r[2];return o?n.isInsert&&u>=0?(i.splice(u+1,0,n),[i,n,u+2]):(i.push(n),[i,n,n.isDelete&&o.isDelete?u:t]):(i.push(n),[i,n,n.isDelete?t:-1])},[[],null,-1]);return s(n,1)[0]}(e.changes):e.changes;return a({},e,{isPlain:!1,changes:t})},l=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};u()(!n.stubHunk,"stubHunk options is deprecated, use addStubHunk function later to add a stub hunk, this function can receive an extra referenceCodeOrLines argument to determine whether stub hunk is required");return i.a.parse(e).map(function(e){return function(e,n){var t=e.hunks.map(function(e){return c(e,n)});return a({},e,{hunks:n.stubHunk?f(t):t})}(e,n)})},f=function(e,n){if(!e||!e.length)return e;if(!function(){if(!n)return!0;var t="string"==typeof n?n.split("\n"):n,r=e[e.length-1],i=r.oldStart+r.oldLines-1;return t.length>i}())return e;var t=e[e.length-1],r={oldStart:t.oldStart+t.oldLines,oldLines:0,newStart:t.newStart+t.newLines,newLines:0,content:"STUB",changes:[]};return[].concat(function(e){if(Array.isArray(e)){for(var n=0,t=Array(e.length);n<e.length;n++)t[n]=e[n];return t}return Array.from(e)}(e),[r])}},function(e,n,t){!function(t){var r={parse:function(e){for(var n,t,r,i,o=[],u=2,a=e.split("\n"),s=a.length,c=0;c<s;){var l=a[c];if(0===l.indexOf("diff --git")){var f=l.slice(11),d=null,h=null;switch(f.indexOf('"')){case-1:d=(g=f.split(" "))[0].slice(2),h=g[1].slice(2);break;case 0:var p=f.indexOf('"',2);d=f.slice(3,p);var v=f.indexOf('"',p+1);h=v<0?f.slice(p+4):f.slice(v+3,-1);break;default:d=(g=f.split(" "))[0].slice(2),h=g[1].slice(3,-1)}n={oldPath:d,newPath:h,hunks:[]},o.push(n);var y=null,m=a[c+1];0===m.indexOf("old")&&(n.oldMode=m.slice(9,16),n.newMode=a[c+2].slice(9,16),m=a[(c+=2)+1]),0===m.indexOf("similarity")&&(n.similarity=parseInt(m.split(" ")[2],10),c+=1);var w;e:for(;w=a[++c];){var g;switch((g=w.split(" "))[0]){case"diff":c--;break e;case"index":var b=g[1].split("..");n.oldRevision=b[0],n.newRevision=b[1],g[2]&&(n.oldMode=n.newMode=g[2]),u=5;var x=a[c+1];if(0===x.indexOf("---")){var O=a[c+2];/\s\/dev\/null$/.test(x)?(n.oldPath="/dev/null",y="add"):/\s\/dev\/null$/.test(O)&&(n.newPath="/dev/null",y="delete"),c+=2}break e}y||(y=g[0])}n.type=y||"modify"}else if(0===l.indexOf("Binary"))n.isBinary=!0,u=2,n=null;else if(5===u)if(0===l.indexOf("@@")){var T=/^@@\s+-([0-9]+)(,([0-9]+))?\s+\+([0-9]+)(,([0-9]+))?/.exec(l);t={content:l,oldStart:T[1]-0,newStart:T[4]-0,oldLines:T[3]-0||1,newLines:T[6]-0||1,changes:[]},n.hunks.push(t),r=t.oldStart,i=t.newStart}else{var k=l.slice(0,1),L={content:l.slice(1)};switch(k){case"+":L.type="insert",L.isInsert=!0,L.lineNumber=i,i++;break;case"-":L.type="delete",L.isDelete=!0,L.lineNumber=r,r++;break;case" ":L.type="normal",L.isNormal=!0,L.oldLineNumber=r,L.newLineNumber=i,r++,i++}L.type&&t.changes.push(L)}c++}return o}};n=e.exports=r}()},function(e,n,t){"use strict";(function(n){var t=function(){};"production"!==n.env.NODE_ENV&&(t=function(e,n,t){var r=arguments.length;t=new Array(r>2?r-2:0);for(var i=2;i<r;i++)t[i-2]=arguments[i];if(void 0===n)throw new Error("`warning(condition, format, ...args)` requires a warning message argument");if(n.length<10||/^[s\W]*$/.test(n))throw new Error("The warning format should be able to uniquely identify this warning. Please, use a more descriptive format than: "+n);if(!e){var o=0,u="Warning: "+n.replace(/%s/g,function(){return t[o++]});"undefined"!=typeof console&&console.error(u);try{throw new Error(u)}catch(e){}}}),e.exports=t}).call(n,t(7))},function(e,n){function t(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(c===setTimeout)return setTimeout(e,0);if((c===t||!c)&&setTimeout)return c=setTimeout,setTimeout(e,0);try{return c(e,0)}catch(n){try{return c.call(null,e,0)}catch(n){return c.call(this,e,0)}}}function o(){p&&d&&(p=!1,d.length?h=d.concat(h):v=-1,h.length&&u())}function u(){if(!p){var e=i(o);p=!0;for(var n=h.length;n;){for(d=h,h=[];++v<n;)d&&d[v].run();v=-1,n=h.length}d=null,p=!1,function(e){if(l===clearTimeout)return clearTimeout(e);if((l===r||!l)&&clearTimeout)return l=clearTimeout,clearTimeout(e);try{l(e)}catch(n){try{return l.call(null,e)}catch(n){return l.call(this,e)}}}(e)}}function a(e,n){this.fun=e,this.array=n}function s(){}var c,l,f=e.exports={};!function(){try{c="function"==typeof setTimeout?setTimeout:t}catch(e){c=t}try{l="function"==typeof clearTimeout?clearTimeout:r}catch(e){l=r}}();var d,h=[],p=!1,v=-1;f.nextTick=function(e){var n=new Array(arguments.length-1);if(arguments.length>1)for(var t=1;t<arguments.length;t++)n[t-1]=arguments[t];h.push(new a(e,n)),1!==h.length||p||i(u)},a.prototype.run=function(){this.fun.apply(null,this.array)},f.title="browser",f.browser=!0,f.env={},f.argv=[],f.version="",f.versions={},f.on=s,f.addListener=s,f.once=s,f.off=s,f.removeListener=s,f.removeAllListeners=s,f.emit=s,f.prependListener=s,f.prependOnceListener=s,f.listeners=function(e){return[]},f.binding=function(e){throw new Error("process.binding is not supported")},f.cwd=function(){return"/"},f.chdir=function(e){throw new Error("process.chdir is not supported")},f.umask=function(){return 0}}])}); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.reactDiffView=t():e.reactDiffView=t()}(window,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=9)}({6:function(e,t,n){"use strict";var r=function(){};e.exports=r},8:function(e,t,n){var r;r={parse:function(e){for(var t,n,r,i,u=[],o=2,a=e.split("\n"),s=a.length,l=0;l<s;){var f=a[l];if(0===f.indexOf("diff --git")){var c=f.slice(11),d=null,p=null;switch(c.indexOf('"')){case-1:d=(m=c.split(" "))[0].slice(2),p=m[1].slice(2);break;case 0:var v=c.indexOf('"',2);d=c.slice(3,v);var y=c.indexOf('"',v+1);p=y<0?c.slice(v+4):c.slice(y+3,-1);break;default:d=(m=c.split(" "))[0].slice(2),p=m[1].slice(3,-1)}t={oldPath:d,newPath:p,hunks:[]},u.push(t);var h,b=null,g=a[l+1];0===g.indexOf("old")&&(t.oldMode=g.slice(9,16),t.newMode=a[l+2].slice(9,16),g=a[(l+=2)+1]),0===g.indexOf("similarity")&&(t.similarity=parseInt(g.split(" ")[2],10),l+=1);e:for(;h=a[++l];){var m;switch((m=h.split(" "))[0]){case"diff":l--;break e;case"index":var w=m[1].split("..");t.oldRevision=w[0],t.newRevision=w[1],m[2]&&(t.oldMode=t.newMode=m[2]),o=5;var x=a[l+1];if(0===x.indexOf("---")){var O=a[l+2];/\s\/dev\/null$/.test(x)?(t.oldPath="/dev/null",b="add"):/\s\/dev\/null$/.test(O)&&(t.newPath="/dev/null",b="delete"),l+=2}break e}b||(b=m[0])}t.type=b||"modify"}else if(0===f.indexOf("Binary"))t.isBinary=!0,o=2,t=null;else if(5===o)if(0===f.indexOf("@@")){var S=/^@@\s+-([0-9]+)(,([0-9]+))?\s+\+([0-9]+)(,([0-9]+))?/.exec(f);n={content:f,oldStart:S[1]-0,newStart:S[4]-0,oldLines:S[3]-0||1,newLines:S[6]-0||1,changes:[]},t.hunks.push(n),r=n.oldStart,i=n.newStart}else{var k=f.slice(0,1),j={content:f.slice(1)};switch(k){case"+":j.type="insert",j.isInsert=!0,j.lineNumber=i,i++;break;case"-":j.type="delete",j.isDelete=!0,j.lineNumber=r,r++;break;case" ":j.type="normal",j.isNormal=!0,j.oldLineNumber=r,j.newLineNumber=i,r++,i++}j.type&&n.changes.push(j)}l++}return u}},e.exports=r},9:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.addStubHunk=t.parseDiff=void 0;var r=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},i=function(){return function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,u=void 0;try{for(var o,a=e[Symbol.iterator]();!(r=(o=a.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(e){i=!0,u=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw u}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),u=a(n(8)),o=a(n(6));function a(e){return e&&e.__esModule?e:{default:e}}var s=function(e,t){var n="zip"===t.nearbySequences?function(e){var t=e.reduce(function(e,t,n){var r=i(e,3),u=r[0],o=r[1],a=r[2];return o?t.isInsert&&a>=0?(u.splice(a+1,0,t),[u,t,a+2]):(u.push(t),[u,t,t.isDelete&&o.isDelete?a:n]):(u.push(t),[u,t,t.isDelete?n:-1])},[[],null,-1]);return i(t,1)[0]}(e.changes):e.changes;return r({},e,{isPlain:!1,changes:n})},l=(t.parseDiff=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(0,o.default)(!t.stubHunk,"stubHunk options is deprecated, use addStubHunk function later to add a stub hunk, this function can receive an extra referenceCodeOrLines argument to determine whether stub hunk is required"),u.default.parse(e).map(function(e){return function(e,t){var n=e.hunks.map(function(e){return s(e,t)});return r({},e,{hunks:t.stubHunk?l(n):n})}(e,t)})},t.addStubHunk=function(e,t){if(!e||!e.length)return e;if(!function(){if(!t)return!0;var n="string"==typeof t?t.split("\n"):t,r=e[e.length-1],i=r.oldStart+r.oldLines-1;return n.length>i}())return e;var n=e[e.length-1],r={oldStart:n.oldStart+n.oldLines,oldLines:0,newStart:n.newStart+n.newLines,newLines:0,content:"STUB",changes:[]};return[].concat(function(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}(e),[r])})}})}); | ||
//# sourceMappingURL=parse.js.map |
@@ -67,3 +67,3 @@ # react-diff-view | ||
WHen the value `"zip"` is passed, the diff will be modified to: | ||
When the value `"zip"` is passed, the diff will be modified to: | ||
@@ -92,3 +92,3 @@ ```diff | ||
- `{Hunk[]} hunks`: The hunks of diff, simply get it from the `parseDiff` output. | ||
- `{ReactElement[]} children`: Instead of passing a list of hunks, you can make each hunk a more customizable `Hunk` component, see [Customize hunk header](#customize-hunk-header) sectionf or its use case. | ||
- `{ReactElement[]} children`: Instead of passing a list of hunks, you can make each hunk a more customizable `Hunk` component, see [Customize hunk header](#customize-hunk-header) section or its use case. | ||
- `{string} viewType`: Can be either `"unified"` or `"split"` to determine how the diff should look like. | ||
@@ -104,2 +104,3 @@ - `{string} className`: An extra css class. | ||
- `{boolean} gutterAnchor`: Whether to create an `<a>` element in gutter so user can click gutter to scroll to corresponding line, `generateAnchorID` prop must be specified if this prop is `true`. | ||
- `{boolean} hideGutter`: Whether to hide gutter (line number) columns. | ||
@@ -148,6 +149,6 @@ A basic use case is to pass `hunks` and `viewType` prop to `Diff` component, the diff will be rendered: | ||
1. Instead of pass the `hunks` props, map each hunk to a `Hunk` component and pass it as children of `Diff`. | ||
1. Instead of passing the `hunks` prop, map each hunk to a `Hunk` component and pass it as children of `Diff`. | ||
2. Customize your `header` prop for `Hunk` component. | ||
The `Hunk` named export is a component representing a hunk of diff, each hunk accepts a `header` prop with possible different types of value: | ||
The `Hunk` named export is a component representing a hunk of diff, each hunk accepts a `header` prop with possible different types of values: | ||
@@ -186,3 +187,3 @@ - `undefined`: Then `Hunk` will append a default header containing the content of hunk. | ||
To mark an edits between changes, you can provide the `markEdits` function prop to `Diff` component, this function receives two changes and returns a tuple (array) of `[Edit[], Edit[]]`, the first element is edits for the old change, the second element is for the new change. | ||
To mark edits between changes, you can provide the `markEdits` function prop to `Diff` component, this function receives two changes and returns a tuple (array) of `[Edit[], Edit[]]`, the first element is edits for the old change, the second element is for the new change. | ||
@@ -214,3 +215,3 @@ A edit is simply an array with two numbers `[startIndex, length]`, the first element is the start index in original text, the second number represents the length of this edit. | ||
For example, following code asks `Diff` component to compare old and new content word by word when their distance is shorter than 30, if the content's distance is longer than 30, the entires line is marked: | ||
For example, the following code asks the `Diff` component to compare old and new content word by word when their distance is shorter than 30, if the content's distance is longer than 30, the entires line is marked: | ||
@@ -267,3 +268,3 @@ ```javascript | ||
For more complex case, you can get a full example in [demo/File.js](demo/File.js) about how to implement code comment with `widgets` prop | ||
For a more complex case, you can reference the example in [demo/File.js](demo/File.js) about implementing code comments with the `widgets` prop. | ||
@@ -288,3 +289,3 @@ ### Customize styles | ||
- `diff-gutter-selected`: Gutter of a selected change. | ||
- `diff-line`: The `<tr>` element for a line of diff. | ||
- `diff-line`: The `<tr>` element for a diff line. | ||
- `diff-line-old-only`: The `<tr>` element which only contains the left side columns, appears in split view | ||
@@ -302,11 +303,11 @@ - `diff-line-new-only`: The `<tr>` element which only contains the right side columns, appears in split view | ||
You can pass `className` prop to `Diff` component to add custom class to the `<table>` element. | ||
You can pass the `className` prop to a `Diff` component to add a custom class to the `<table>` element. | ||
The `Diff` component also accepts a `customClassNames` prop which contains custom css classes for different part, it can be a object with multiple keys: `hunk`, `hunkHeader`, `gutterHeader`, `codeHeader`, `line`, `gutter`, `code`, each value can be a string, the value will be appended to corresponding part's `className` prop. | ||
The `Diff` component also accepts a `customClassNames` prop which contains custom css classes for a different part, it can be an object with multiple keys: `hunk`, `hunkHeader`, `gutterHeader`, `codeHeader`, `line`, `gutter`, `code`. Each value can be a string, and the value will be appended to corresponding part's `className` prop. | ||
### Customize events | ||
You can pass a `customEvents` object to `Diff` component to add events to different part, the accepted keys are `gutterHeader`, `codeHeader`, `gutter` and `code`, each value is an object containing DOM events key/value pair. | ||
You can pass a `customEvents` object to a `Diff` component to add events to different parts. The accepted keys are `gutterHeader`, `codeHeader`, `gutter` and `code`. Each value is an object containing DOM events key/value pair. | ||
One of the common case for `customEvents` is to add code selecting functionality, this can be archived simply by passing a `onClick` event to gutter and manipulate the `selectedChanges` prop: | ||
One of the common cases for `customEvents` is to add code selecting functionality. This can be archived simply by passing an `onClick` event to gutter and manipulating the `selectedChanges` prop: | ||
@@ -341,3 +342,3 @@ ```javascript | ||
`customEvents` can also be utilized to add comment or expand collapsed code, see [demo/File.js](demo/File.js) for more implementation details. | ||
`customEvents` can also be utilized to add a comment or expand collapsed code, see [demo/File.js](demo/File.js) for more implementation details. | ||
@@ -417,3 +418,3 @@ ### Syntax highlight | ||
- `{Hunk[]} expandFromRawCode({Hunk[]} hunks, {string|string[]} rawCodeOrLines, {number} start, {number} end)`: Create a hunk from source code slicing from `start` to `end`, then insert this hunk into `hunks`, merging with existing hunks are automatically done. | ||
- `{Hunk[]} addStubHunk({Hunk[]} hunks, {string|string[]} referenceRawCodeOrLines)`: This is an overload of `addStubHunk` function, once you provide the second `referenceRawCodeOrLines`, the stub hunk will only be appended when there are more code after the last hunk. | ||
- `{Hunk[]} addStubHunk({Hunk[]} hunks, {string|string[]} referenceRawCodeOrLines)`: This is an overload of `addStubHunk` function, once you provide the second `referenceRawCodeOrLines`, the stub hunk will only be appended when there is more code after the last hunk. | ||
- `{Hunk[]} expandCollapsedBlockBy({Hunk[]} hunks, {string|string[]} rawCodeOrLines, {Function} predicate)`: Iterate over all collapsed block (lines between 2 hunks) and expand those with `predicate` returns `true`. The `predicate` function receives `({number} lines, {number} oldStart, {number} newStart)` as arguments. | ||
@@ -425,9 +426,9 @@ | ||
No, there isn't a wordwrap configuration, lines are automatically wrapped by default, and there is almost impossible to implement other wrap styles, unless we choose `table-layout: auto` which critically hit the performance. | ||
No, there isn't a wordwrap configuration. Lines are automatically wrapped by default, and it is almost impossible to implement other wrap styles, unless we choose `table-layout: auto` which critically hinders the performance. | ||
Any solutions of this issue are welcome. | ||
Any solutions for this issue are welcome. | ||
### Test | ||
I don't really know how to test such a complicated and UI centric component, any helps are welcome. | ||
I don't really know how to test such a complicated and UI centric component, any help is welcome. | ||
@@ -529,1 +530,5 @@ ## Change Log | ||
- Fix a bug where a stub hunk will crash the hunk insertion. | ||
### 1.5.0 | ||
- Add `hideGutter` prop to hide gutter columns |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable no-empty-function */ | ||
import {PureComponent} from 'react'; | ||
@@ -30,6 +31,8 @@ | ||
/* eslint-enable no-unused-vars */ | ||
const ref = cell => this.cell = cell; | ||
const ref = cell => (this.cell = cell); | ||
if (html) { | ||
/* eslint-disable react/no-danger */ | ||
return <td ref={ref} {...props} dangerouslySetInnerHTML={{__html: html}} />; | ||
/* eslint-enable react/no-danger */ | ||
} | ||
@@ -36,0 +39,0 @@ |
@@ -10,2 +10,3 @@ import {Children, cloneElement} from 'react'; | ||
const monotonous = diffType === 'add' || diffType === 'delete'; | ||
const {hideGutter} = props; | ||
const cols = ((viewType, monotonous) => { | ||
@@ -15,4 +16,4 @@ if (viewType === 'unified') { | ||
<colgroup> | ||
<col className="diff-gutter-col" /> | ||
<col className="diff-gutter-col" /> | ||
{!hideGutter && <col className="diff-gutter-col" />} | ||
{!hideGutter && <col className="diff-gutter-col" />} | ||
<col /> | ||
@@ -26,3 +27,3 @@ </colgroup> | ||
<colgroup> | ||
<col className="diff-gutter-col" /> | ||
{!hideGutter && <col className="diff-gutter-col" />} | ||
<col /> | ||
@@ -35,5 +36,5 @@ </colgroup> | ||
<colgroup> | ||
<col className="diff-gutter-col" /> | ||
{!hideGutter && <col className="diff-gutter-col" />} | ||
<col /> | ||
<col className="diff-gutter-col" /> | ||
{!hideGutter && <col className="diff-gutter-col" />} | ||
<col /> | ||
@@ -56,4 +57,7 @@ </colgroup> | ||
Diff.propTypes = { | ||
// TODO: [2.x] `diffType` should be required. | ||
diffType: PropTypes.oneOf(['add', 'delete', 'modify', 'rename', 'copy']), | ||
viewType: viewTypePropType.isRequired, | ||
// TODO: [2.x] Merge `hideGutter` and `gutterAnchor` into `gutterType` | ||
hideGutter: PropTypes.bool, | ||
hunks: PropTypes.arrayOf(hunkPropType), | ||
@@ -66,2 +70,7 @@ gutterAnchor: PropTypes.bool, | ||
Diff.defaultProps = { | ||
diffType: 'modify', | ||
hunks: undefined, | ||
children: undefined, | ||
hideGutter: false, | ||
gutterAnchor: false, | ||
generateAnchorID() { | ||
@@ -68,0 +77,0 @@ return undefined; |
@@ -17,3 +17,3 @@ import {PureComponent} from 'react'; | ||
selectedChanges: PropTypes.arrayOf(PropTypes.string), | ||
customEvents: eventsPropType, | ||
customEvents: eventsPropType | ||
}; | ||
@@ -23,2 +23,3 @@ | ||
viewType: 'split', | ||
header: undefined, | ||
widgets: {}, | ||
@@ -25,0 +26,0 @@ selectedChanges: [], |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable no-empty-function */ | ||
import {PureComponent} from 'react'; | ||
@@ -28,9 +29,13 @@ import PropTypes from 'prop-types'; | ||
gutterAnchor, | ||
gutterAnchorTarget | ||
gutterAnchorTarget, | ||
hideGutter | ||
} = args; | ||
if (!change) { | ||
const gutterClassName = classNames('diff-gutter', 'diff-gutter-omit', customClassNames.gutter); | ||
const codeClassName = classNames('diff-code', 'diff-code-omit', customClassNames.code); | ||
return [ | ||
<td key="gutter" className={classNames('diff-gutter', 'diff-gutter-omit', customClassNames.gutter)} />, | ||
<td key="code" className={classNames('diff-code', 'diff-code-omit', customClassNames.code)} /> | ||
!hideGutter && <td key="gutter" className={gutterClassName} />, | ||
<td key="code" className={codeClassName} /> | ||
]; | ||
@@ -49,3 +54,2 @@ } | ||
const gutterProps = { | ||
'key': 'gutter', | ||
id: anchorID, | ||
@@ -65,3 +69,2 @@ 'className': gutterClassName, | ||
const codeProps = { | ||
key: 'code', | ||
className: codeClassName, | ||
@@ -74,7 +77,8 @@ onRender: onRenderCode, | ||
return [ | ||
<td {...gutterProps} />, | ||
<CodeCell {...codeProps} text={content} /> | ||
!hideGutter && <td key="gutter" {...gutterProps} />, | ||
<CodeCell key="code" {...codeProps} text={content} /> | ||
]; | ||
} | ||
/* eslint-disable no-param-reassign */ | ||
const {html: editMarkedHTML, lastIndex} = edits.reduce( | ||
@@ -92,7 +96,8 @@ (result, [start, length]) => { | ||
); | ||
/* eslint-enable no-param-reassign */ | ||
const tailHTML = escape(content.substring(lastIndex)); | ||
return [ | ||
<td {...gutterProps} />, | ||
<CodeCell {...codeProps} html={editMarkedHTML + tailHTML} /> | ||
!hideGutter && <td key="gutter" {...gutterProps} />, | ||
<CodeCell key="code" {...codeProps} html={editMarkedHTML + tailHTML} /> | ||
]; | ||
@@ -124,3 +129,6 @@ }; | ||
static defaultProps = { | ||
oldChange: null, | ||
newChange: null, | ||
customEvents: {}, | ||
customClassNames: {}, | ||
markEdits() { | ||
@@ -144,2 +152,3 @@ return NO_EDITS; | ||
onRenderCode, | ||
hideGutter, | ||
generateAnchorID, | ||
@@ -151,3 +160,3 @@ gutterAnchor | ||
const commons = {monotonous, customClassNames, customEvents, onRenderCode}; | ||
const commons = {monotonous, hideGutter, customClassNames, customEvents, onRenderCode}; | ||
const oldAnchorID = oldChange && generateAnchorID(oldChange); | ||
@@ -154,0 +163,0 @@ const oldArgs = { |
@@ -0,1 +1,2 @@ | ||
import warning from 'warning'; | ||
import mapValues from 'lodash.mapvalues'; | ||
@@ -58,3 +59,3 @@ import classNames from 'classnames'; | ||
const renderRow = ([type, key, oldValue, newValue], i, selectedChanges, monotonous, props) => { | ||
const renderRow = ([type, key, oldValue, newValue], i, selectedChanges, monotonous, hideGutter, props) => { | ||
if (type === 'change') { | ||
@@ -70,2 +71,3 @@ const oldSelected = oldValue ? selectedChanges.includes(getChangeKey(oldValue)) : false; | ||
monotonous={monotonous} | ||
hideGutter={hideGutter} | ||
oldSelected={oldSelected} | ||
@@ -78,3 +80,11 @@ newSelected={newSelected} | ||
else if (type === 'widget') { | ||
return <SplitWidget key={`widget${key}`} monotonous={monotonous} oldElement={oldValue} newElement={newValue} />; | ||
return ( | ||
<SplitWidget | ||
key={`widget${key}`} | ||
monotonous={monotonous} | ||
hideGutter={hideGutter} | ||
oldElement={oldValue} | ||
newElement={newValue} | ||
/> | ||
); | ||
} | ||
@@ -87,2 +97,3 @@ | ||
const { | ||
hideGutter, | ||
hunk, | ||
@@ -104,2 +115,4 @@ monotonous, | ||
const computedContentClassName = classNames('diff-hunk-header-content', contentClassName); | ||
const columnCount = (hideGutter ? 2 : 4) / (monotonous ? 2 : 1); | ||
const headerContentColSpan = columnCount - (hideGutter ? 0 : 1); | ||
@@ -109,5 +122,5 @@ if (elements === undefined) { | ||
<tr className={computedClassName}> | ||
<td className={computedGutterClassName} {...boundGutterEvents}></td> | ||
{!hideGutter && <td className={computedGutterClassName} {...boundGutterEvents} />} | ||
<td | ||
colSpan={monotonous ? 1 : 3} | ||
colSpan={headerContentColSpan} | ||
className={computedContentClassName} | ||
@@ -127,2 +140,7 @@ {...boundContentEvents} | ||
if (Array.isArray(elements)) { | ||
warning( | ||
!hideGutter, | ||
'Gutter element in hunk header will not be rendered since hideGutter prop is set to true' | ||
); | ||
const [gutter, content] = elements; | ||
@@ -132,5 +150,5 @@ | ||
<tr className={computedClassName}> | ||
<td className={computedGutterClassName} {...boundGutterEvents}>{gutter}</td> | ||
{!hideGutter && <td className={computedGutterClassName} {...boundGutterEvents}>{gutter}</td>} | ||
<td | ||
colSpan={monotonous ? 1 : 3} | ||
colSpan={headerContentColSpan} | ||
className={computedContentClassName} | ||
@@ -148,3 +166,3 @@ {...boundContentEvents} | ||
<td | ||
colSpan={monotonous ? 2 : 4} | ||
colSpan={columnCount} | ||
className={computedContentClassName} | ||
@@ -163,2 +181,3 @@ {...boundContentEvents} | ||
monotonous, | ||
hideGutter, | ||
widgets, | ||
@@ -182,2 +201,3 @@ selectedChanges, | ||
monotonous={monotonous} | ||
hideGutter={hideGutter} | ||
elements={header} | ||
@@ -190,3 +210,3 @@ gutterEvents={headerGutterEvents} | ||
/> | ||
{elements.map((element, i) => renderRow(element, i, selectedChanges, monotonous, childrenProps))} | ||
{elements.map((item, i) => renderRow(item, i, selectedChanges, monotonous, hideGutter, childrenProps))} | ||
</tbody> | ||
@@ -193,0 +213,0 @@ ); |
import './Widget.css'; | ||
const SplitWidget = ({oldElement, newElement, monotonous}) => { | ||
const SplitWidget = ({oldElement, newElement, monotonous, hideGutter}) => { | ||
if (monotonous) { | ||
return ( | ||
<tr className="diff-widget"> | ||
<td colSpan={2} className="diff-widget-content"> | ||
<td colSpan={hideGutter ? 1 : 2} className="diff-widget-content"> | ||
{oldElement || newElement} | ||
@@ -17,3 +17,3 @@ </td> | ||
<tr className="diff-widget"> | ||
<td colSpan={4} className="diff-widget-content"> | ||
<td colSpan={hideGutter ? 2 : 4} className="diff-widget-content"> | ||
{oldElement} | ||
@@ -27,6 +27,6 @@ </td> | ||
<tr className="diff-widget"> | ||
<td colSpan={2} className="diff-widget-content"> | ||
<td colSpan={hideGutter ? 1 : 2} className="diff-widget-content"> | ||
{oldElement} | ||
</td> | ||
<td colSpan={2} className="diff-widget-content"> | ||
<td colSpan={hideGutter ? 1 : 2} className="diff-widget-content"> | ||
{newElement} | ||
@@ -33,0 +33,0 @@ </td> |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable no-empty-function */ | ||
import {PureComponent} from 'react'; | ||
@@ -9,2 +10,14 @@ import PropTypes from 'prop-types'; | ||
const GutterCell = ({hide, className, lineNumber, gutterAnchor, anchorID, ...props}) => { | ||
if (hide) { | ||
return null; | ||
} | ||
return ( | ||
<td className={className} data-line-number={lineNumber} {...props}> | ||
{gutterAnchor ? <a href={'#' + anchorID} data-line-number={lineNumber} /> : null} | ||
</td> | ||
); | ||
}; | ||
export default class UnifiedChange extends PureComponent { | ||
@@ -27,2 +40,3 @@ | ||
customEvents: {}, | ||
customClassNames: {}, | ||
onRenderCode() { | ||
@@ -43,3 +57,11 @@ } | ||
render() { | ||
const {change, selected, customClassNames, customEvents, gutterAnchor, generateAnchorID} = this.props; | ||
const { | ||
change, | ||
selected, | ||
customClassNames, | ||
customEvents, | ||
hideGutter, | ||
gutterAnchor, | ||
generateAnchorID | ||
} = this.props; | ||
const {type, content} = change; | ||
@@ -72,10 +94,20 @@ const oldLine = computeOldLineNumber(change); | ||
className={classNames('diff-line', customClassNames.line)} | ||
ref={container => this.container = container} | ||
ref={container => (this.container = container)} | ||
> | ||
<td className={gutterClassName} data-line-number={oldLineNumber} {...boundGutterEvents}> | ||
{gutterAnchor ? <a href={'#' + anchorID} data-line-number={oldLineNumber} /> : null} | ||
</td> | ||
<td className={gutterClassName} data-line-number={newLineNumber} {...boundGutterEvents}> | ||
{gutterAnchor ? <a href={'#' + anchorID} data-line-number={newLineNumber} /> : null} | ||
</td> | ||
<GutterCell | ||
hide={hideGutter} | ||
className={gutterClassName} | ||
lineNumber={oldLineNumber} | ||
gutterAnchor={gutterAnchor} | ||
anchorID={anchorID} | ||
{...boundGutterEvents} | ||
/> | ||
<GutterCell | ||
hide={hideGutter} | ||
className={gutterClassName} | ||
lineNumber={newLineNumber} | ||
gutterAnchor={gutterAnchor} | ||
anchorID={anchorID} | ||
{...boundGutterEvents} | ||
/> | ||
<td className={codeClassName} {...boundCodeEvents}>{content}</td> | ||
@@ -82,0 +114,0 @@ </tr> |
@@ -26,7 +26,16 @@ import {PureComponent} from 'react'; | ||
const renderRow = ([type, key, value], i, selectedChanges, props) => { | ||
const {hideGutter} = props; | ||
if (type === 'change') { | ||
return <UnifiedChange key={`change${key}`} change={value} selected={selectedChanges.includes(key)} {...props} />; | ||
return ( | ||
<UnifiedChange | ||
key={`change${key}`} | ||
change={value} | ||
selected={selectedChanges.includes(key)} | ||
{...props} | ||
/> | ||
); | ||
} | ||
else if (type === 'widget') { | ||
return <UnifiedWidget key={`widget${key}`} element={value} />; | ||
return <UnifiedWidget key={`widget${key}`} hideGutter={hideGutter} element={value} />; | ||
} | ||
@@ -45,2 +54,3 @@ | ||
const { | ||
hideGutter, | ||
hunk, | ||
@@ -58,4 +68,11 @@ elements, | ||
const computedClassName = classNames('diff-hunk-header', className); | ||
const computedGutterClassName = classNames('diff-hunk-header-gutter', gutterClassName); | ||
const computedContentClassName = classNames('diff-hunk-header-content', contentClassName); | ||
const gutterProps = { | ||
colSpan: 2, | ||
className: classNames('diff-hunk-header-gutter', gutterClassName), | ||
...boundGutterEvents | ||
}; | ||
const contentProps = { | ||
className: classNames('diff-hunk-header-content', contentClassName), | ||
...boundContentEvents | ||
}; | ||
@@ -65,4 +82,4 @@ if (elements === undefined) { | ||
<tr className={computedClassName}> | ||
<td colSpan={2} className={computedGutterClassName} {...boundGutterEvents}></td> | ||
<td className={computedContentClassName} {...boundContentEvents}>{hunk.content}</td> | ||
{!hideGutter && <td {...gutterProps} />} | ||
<td {...contentProps}>{hunk.content}</td> | ||
</tr> | ||
@@ -81,4 +98,4 @@ ); | ||
<tr className={computedClassName}> | ||
<td colSpan={2} className={computedGutterClassName} {...boundGutterEvents}>{gutter}</td> | ||
<td className={computedContentClassName} {...boundContentEvents}>{content}</td> | ||
{!hideGutter && <td {...gutterProps}>{gutter}</td>} | ||
<td {...contentProps}>{content}</td> | ||
</tr> | ||
@@ -90,3 +107,3 @@ ); | ||
<tr className={computedClassName}> | ||
<td colSpan={3} className={computedContentClassName} {...boundContentEvents}>{elements}</td> | ||
<td {...contentProps} colSpan={hideGutter ? 1 : 3}>{elements}</td> | ||
</tr> | ||
@@ -111,2 +128,3 @@ ); | ||
} = props; | ||
const {hideGutter} = childrenProps; | ||
const elements = groupElements(hunk.changes, widgets); | ||
@@ -117,2 +135,3 @@ | ||
<HunkHeader | ||
hideGutter={hideGutter} | ||
hunk={hunk} | ||
@@ -119,0 +138,0 @@ elements={header} |
import './Widget.css'; | ||
const UnifiedWidget = ({element}) => ( | ||
const UnifiedWidget = ({hideGutter, element}) => ( | ||
<tr className="diff-widget"> | ||
<td colSpan={3} className="diff-widget-content"> | ||
<td colSpan={hideGutter ? 1 : 3} className="diff-widget-content"> | ||
{element} | ||
@@ -7,0 +7,0 @@ </td> |
@@ -40,2 +40,3 @@ import leven from 'leven'; | ||
}; | ||
/* eslint-disable no-param-reassign */ | ||
const hunk = changes.reduce( | ||
@@ -67,2 +68,3 @@ (hunk, change) => { | ||
); | ||
/* eslint-enable no-param-reassign */ | ||
const {oldStart, oldLines, newStart, newLines} = hunk; | ||
@@ -145,2 +147,3 @@ | ||
/* eslint-disable consistent-return */ | ||
const createFindChangeByLineNumberFunction = side => { | ||
@@ -160,2 +163,3 @@ const computeLineNumber = side === 'old' ? computeOldLineNumber : computeNewLineNumber; | ||
}; | ||
/* eslint-enable consistent-return */ | ||
@@ -177,2 +181,3 @@ export const findChangeByOldLineNumber = createFindChangeByLineNumberFunction('old'); | ||
/* eslint-disable complexity */ | ||
return (hunks, lineNumber) => { | ||
@@ -236,2 +241,3 @@ const firstHunk = first(hunks); | ||
}; | ||
/* eslint-enable complexity */ | ||
}; | ||
@@ -530,2 +536,3 @@ | ||
const diff = computeDiff(oldContent, newContent); | ||
/* eslint-disable no-param-reassign */ | ||
const {aEdits, bEdits} = diff.reduce( | ||
@@ -554,2 +561,3 @@ (result, {added, removed, value}) => { | ||
); | ||
/* eslint-enable no-param-reassign */ | ||
@@ -556,0 +564,0 @@ return [aEdits, bEdits]; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
9
1863
522
701920
48
+ Addedreact@19.0.0(transitive)
+ Addedwarning@4.0.3(transitive)
- Removeddiff@^3.4.0
- Removeddiff@3.5.0(transitive)
- Removedreact@16.14.0(transitive)
- Removedwarning@3.0.0(transitive)
Updatedwarning@^4.0.1