Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 556805b

Browse files
committedJul 29, 2020
comments feature, fix vulnerabilities
1 parent 9ac4ba9 commit 556805b

13 files changed

+15344
-3752
lines changed
 

‎.eslintrc

+19-6
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,24 @@
22
"extends": ["airbnb-base", "plugin:@typescript-eslint/recommended"],
33
"rules": {
44
"no-tabs": "off",
5-
"@typescript-eslint/indent": ["error", 2],
6-
"max-len": ["error", {
7-
"code": 100
8-
}],
95
"arrow-body-style": "off",
6+
"comma-dangle": "off",
7+
"@typescript-eslint/no-var-requires": 0,
8+
"operator-linebreak": "off",
9+
"@typescript-eslint/no-explicit-any": 0,
10+
"@typescript-eslint/explicit-function-return-type": 0,
11+
"implicit-arrow-linebreak": "off",
12+
"@typescript-eslint/indent": 0,
13+
"import/extensions": [
14+
"error",
15+
"ignorePackages",
16+
{
17+
"ts": "never",
18+
"js": "never",
19+
"mjs": "never",
20+
"jsx": "never"
21+
}
22+
]
1023
},
1124
"settings": {
1225
"import/resolver": {
@@ -18,6 +31,6 @@
1831
"env": {
1932
"mocha": true,
2033
"node": true,
21-
"browser": true,
22-
},
34+
"browser": true
35+
}
2336
}

‎.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
node_modules
22
dist
33
lib
4-
*.log
4+
*.log

‎examples/src/CommentBlock.tsx

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import * as React from 'react';
2+
import { CommentInfo } from '../../lib';
3+
4+
interface Props {
5+
updateComment: (commentInfo: CommentInfo, text: string) => void;
6+
removeComment: (lineId: string) => void;
7+
comment: any;
8+
show: boolean;
9+
}
10+
11+
const CommentBlock: React.FC<Props> = ({
12+
updateComment,
13+
removeComment,
14+
comment,
15+
show
16+
}) => {
17+
const [isComment, setIsComment] = React.useState<boolean>(show);
18+
const [text, setText] = React.useState<string>(
19+
comment.body ? comment.body.text : ''
20+
);
21+
22+
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
23+
setText(e.target.value);
24+
};
25+
26+
if (!isComment) {
27+
return (
28+
<div className='p-2'>
29+
<div className='form-group mb-2'>
30+
<textarea
31+
onChange={handleChange}
32+
value={text}
33+
className='form-control'
34+
/>
35+
</div>
36+
<button
37+
className='btn btn-primary mr-2'
38+
onClick={() => {
39+
if (!text) {
40+
return removeComment(comment.lineId);
41+
}
42+
updateComment(comment, text);
43+
setIsComment(true);
44+
}}
45+
>
46+
Submit
47+
</button>
48+
<button
49+
className='btn btn-secondary'
50+
onClick={() => {
51+
if (!text) {
52+
return removeComment(comment.lineId);
53+
}
54+
setIsComment(true);
55+
}}
56+
>
57+
Cancel
58+
</button>
59+
</div>
60+
);
61+
}
62+
return (
63+
<div className='p-2'>
64+
<div className='mb-2 bg-light rounded p-2'>
65+
{comment.body.text &&
66+
comment.body.text
67+
.split('\n')
68+
.map((str: string, i: number) => <div key={i}>{str}</div>)}
69+
</div>
70+
<button
71+
onClick={() => setIsComment(false)}
72+
className='btn btn-primary mr-2'
73+
>
74+
Edit
75+
</button>
76+
<button
77+
onClick={() => removeComment(comment.lineId)}
78+
className='btn btn-secondary mr-2'
79+
>
80+
Delete
81+
</button>
82+
</div>
83+
);
84+
};
85+
86+
export default CommentBlock;

‎examples/src/index.tsx

+113-26
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
require('./style.scss');
21
import * as React from 'react';
32
import * as ReactDOM from 'react-dom';
4-
53
import ReactDiff, { DiffMethod } from '../../lib/index';
6-
4+
import CommentBlock from './CommentBlock';
5+
import { CommentInfo } from '../../lib/index';
76
const oldJs = require('./diff/javascript/old.rjs').default;
87
const newJs = require('./diff/javascript/new.rjs').default;
9-
108
const logo = require('../../logo.png');
9+
require('./style.scss');
1110

1211
interface ExampleState {
1312
splitView?: boolean;
1413
highlightLine?: string[];
1514
language?: string;
1615
enableSyntaxHighlighting?: boolean;
1716
compareMethod?: DiffMethod;
17+
comments: any[];
1818
}
1919

2020
const P = (window as any).Prism;
@@ -25,13 +25,27 @@ class Example extends React.Component<{}, ExampleState> {
2525
this.state = {
2626
highlightLine: [],
2727
enableSyntaxHighlighting: true,
28+
comments: [
29+
{
30+
body: {
31+
lineId: 'L-12-beforeCommit-afterCommit-test/test.jsx',
32+
text: 'Awesome\ncomment!',
33+
fileId: 'test/test.jsx',
34+
prefix: 'L',
35+
lineNumber: 12,
36+
specifier: 'beforeCommit-afterCommit'
37+
}
38+
}
39+
]
2840
};
2941
}
3042

3143
private onLineNumberClick = (
3244
id: string,
33-
e: React.MouseEvent<HTMLTableCellElement>,
45+
uiniqueLindeId: string,
46+
e: React.MouseEvent<HTMLTableCellElement>
3447
): void => {
48+
console.log(uiniqueLindeId);
3549
let highlightLine = [id];
3650
if (e.shiftKey && this.state.highlightLine.length === 1) {
3751
const [dir, oldId] = this.state.highlightLine[0].split('-');
@@ -46,45 +60,99 @@ class Example extends React.Component<{}, ExampleState> {
4660
}
4761
}
4862
this.setState({
49-
highlightLine,
63+
highlightLine
5064
});
5165
};
5266

53-
private syntaxHighlight = (str: string): any => {
54-
if (!str) return;
55-
const language = P.highlight(str, P.languages.javascript);
56-
return <span dangerouslySetInnerHTML={{ __html: language }} />;
67+
private syntaxHighlight = (source: string, lineId?: string): any => {
68+
if (!source) return;
69+
const language = P.highlight(source, P.languages.javascript);
70+
return <span id={lineId} dangerouslySetInnerHTML={{ __html: language }} />;
5771
};
5872

59-
public render(): JSX.Element {
73+
private updateComment = (commentInfo: any, text?: string) => {
74+
const updatedComments = this.state.comments.map(comment => {
75+
console.log(comment);
76+
if (comment.lineId === commentInfo.lineId) {
77+
return {
78+
...commentInfo,
79+
lineId: commentInfo.uniqueLineId,
80+
body: text
81+
};
82+
}
83+
return comment;
84+
});
85+
86+
this.setState({
87+
comments: updatedComments
88+
});
89+
};
90+
91+
private removeComment = (lineId: string) => {
92+
const updatedComments = this.state.comments.filter(
93+
comment => comment.lineId !== lineId
94+
);
95+
this.setState({ comments: updatedComments });
96+
};
97+
98+
private createComment = (commentInfo: CommentInfo) => {
99+
const updatedComments = [
100+
...this.state.comments,
101+
{
102+
body: {
103+
...commentInfo,
104+
lineId: commentInfo.lineId,
105+
text: ''
106+
}
107+
}
108+
];
109+
this.setState({ comments: updatedComments });
110+
};
111+
112+
/**
113+
*
114+
* helper that return Array with uniqueLineIds (comment.lineId)
115+
*
116+
* @param arr Array with commentLineIds
117+
*
118+
*/
60119

120+
private getlineIdsArray = (arr: any[]) => {
121+
return arr.reduce((acc: Array<string>, comment) => {
122+
acc.push(comment.body.lineId);
123+
return acc;
124+
}, []);
125+
};
126+
127+
public render(): JSX.Element {
61128
return (
62-
<div className="react-diff-viewer-example">
63-
<div className="radial"></div>
64-
<div className="banner">
65-
<div className="img-container">
66-
<img src={logo} alt="React Diff Viewer Logo" />
129+
<div className='react-diff-viewer-example'>
130+
<div className='radial'></div>
131+
<div className='banner'>
132+
<div className='img-container'>
133+
<img src={logo} alt='React Diff Viewer Logo' />
67134
</div>
68135
<p>
69136
A simple and beautiful text diff viewer made with{' '}
70-
<a href="https://github.com/kpdecker/jsdiff" target="_blank">
137+
<a href='https://github.com/kpdecker/jsdiff' target='_blank'>
71138
Diff{' '}
72139
</a>
73140
and{' '}
74-
<a href="https://reactjs.org" target="_blank">
141+
<a href='https://reactjs.org' target='_blank'>
75142
React.{' '}
76143
</a>
77-
Featuring split view, inline view, word diff, line highlight and more.
144+
Featuring split view, inline view, word diff, line highlight and
145+
more.
78146
</p>
79-
<div className="cta">
80-
<a href="https://github.com/praneshr/react-diff-viewer#install">
81-
<button type="button" className="btn btn-primary btn-lg">
147+
<div className='cta'>
148+
<a href='https://github.com/praneshr/react-diff-viewer#install'>
149+
<button type='button' className='btn btn-primary btn-lg'>
82150
Documentation
83151
</button>
84152
</a>
85153
</div>
86154
</div>
87-
<div className="diff-viewer">
155+
<div className='diff-viewer'>
88156
<ReactDiff
89157
highlightLines={this.state.highlightLine}
90158
onLineNumberClick={this.onLineNumberClick}
@@ -93,13 +161,32 @@ class Example extends React.Component<{}, ExampleState> {
93161
newValue={newJs}
94162
renderContent={this.syntaxHighlight}
95163
useDarkTheme
96-
leftTitle="webpack.config.js master@2178133 - pushed 2 hours ago."
97-
rightTitle="webpack.config.js master@64207ee - pushed 13 hours ago."
164+
leftTitle='webpack.config.js master@2178133 - pushed 2 hours ago.'
165+
rightTitle='webpack.config.js master@64207ee - pushed 13 hours ago.'
166+
afterCommit={'afterCommit'}
167+
beforeCommit={'beforeCommit'}
168+
commentLineIds={this.getlineIdsArray(this.state.comments)}
169+
getCommentInfo={commentInfo => this.createComment(commentInfo)}
170+
renderCommentBlock={commentInfo => {
171+
console.log(commentInfo);
172+
const currComment = this.state.comments.find(
173+
comment => comment.body.lineId === commentInfo.lineId
174+
);
175+
return (
176+
<CommentBlock
177+
updateComment={this.updateComment}
178+
removeComment={this.removeComment}
179+
comment={currComment}
180+
show={!!currComment.body.text}
181+
/>
182+
);
183+
}}
184+
fileId={'test/test.jsx'}
98185
/>
99186
</div>
100187
<footer>
101188
Made with 💓 by{' '}
102-
<a href="https://praneshravi.in" target="_blank">
189+
<a href='https://praneshravi.in' target='_blank'>
103190
Pranesh Ravi
104191
</a>
105192
</footer>

‎package-lock.json

+11,022
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+85-86
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,87 @@
11
{
2-
"name": "react-diff-viewer",
3-
"version": "3.1.1",
4-
"private": false,
5-
"description": "A simple and beautiful text diff viewer component made with diff and React",
6-
"keywords": [
7-
"review",
8-
"code-review",
9-
"diff",
10-
"diff-viewer",
11-
"github",
12-
"react",
13-
"react-component",
14-
"ui"
15-
],
16-
"repository": "git@github.com:praneshr/react-diff-viewer.git",
17-
"license": "MIT",
18-
"author": "Pranesh Ravi<praneshpranesh@gmail.com>",
19-
"main": "lib/index",
20-
"typings": "lib/index",
21-
"scripts": {
22-
"build": "tsc --outDir lib/",
23-
"build:examples": "webpack --progress --colors",
24-
"build:watch": "tsc --outDir lib/ -w",
25-
"publish:examples": "NODE_ENV=production yarn build:examples && gh-pages -d examples/dist -r $GITHUB_REPO_URL",
26-
"publish:examples:local": "NODE_ENV=production yarn build:examples && gh-pages -d examples/dist",
27-
"start:examples": "webpack-dev-server --open --hot --inline",
28-
"test": "mocha --require ts-node/register --require enzyme.ts ./test/**",
29-
"test:watch": "mocha --require ts-node/register --require enzyme.ts --watch-extensions ts,tsx --watch ./test/**"
30-
},
31-
"dependencies": {
32-
"classnames": "^2.2.6",
33-
"create-emotion": "^10.0.14",
34-
"diff": "^4.0.1",
35-
"emotion": "^10.0.14",
36-
"memoize-one": "^5.0.4",
37-
"prop-types": "^15.6.2"
38-
},
39-
"devDependencies": {
40-
"@types/classnames": "^2.2.6",
41-
"@types/diff": "^4.0.2",
42-
"@types/enzyme": "^3.1.14",
43-
"@types/enzyme-adapter-react-16": "^1.0.3",
44-
"@types/expect": "^1.20.3",
45-
"@types/memoize-one": "^4.1.1",
46-
"@types/mocha": "^5.2.5",
47-
"@types/node": "^12.0.12",
48-
"@types/react": "^16.4.14",
49-
"@types/react-dom": "^16.0.8",
50-
"@types/webpack": "^4.4.13",
51-
"@typescript-eslint/eslint-plugin": "^1.11.0",
52-
"@typescript-eslint/parser": "^1.11.0",
53-
"css-loader": "^3.0.0",
54-
"enzyme": "^3.7.0",
55-
"enzyme-adapter-react-16": "^1.6.0",
56-
"eslint": "6.0.1",
57-
"eslint-config-airbnb": "17.1.1",
58-
"eslint-plugin-import": "^2.18.0",
59-
"eslint-plugin-jsx-a11y": "^6.2.3",
60-
"eslint-plugin-react": "^7.14.2",
61-
"expect": "^24.8.0",
62-
"favicons-webpack-plugin": "^0.0.9",
63-
"file-loader": "^4.0.0",
64-
"gh-pages": "^2.0.1",
65-
"html-webpack-plugin": "^3.2.0",
66-
"mini-css-extract-plugin": "^0.7.0",
67-
"mocha": "^6.1.4",
68-
"node-sass": "^4.9.3",
69-
"raw-loader": "^3.0.0",
70-
"react": "^16.5.2",
71-
"react-dom": "^16.5.2",
72-
"sass-loader": "^7.1.0",
73-
"spy": "^1.0.0",
74-
"ts-loader": "^6.0.4",
75-
"ts-node": "^8.3.0",
76-
"typescript": "^3.5.2",
77-
"webpack": "^4.20.2",
78-
"webpack-cli": "^3.1.1",
79-
"webpack-dev-server": "^3.1.9"
80-
},
81-
"peerDependencies": {
82-
"react": "^15.3.0 || ^16.0.0",
83-
"react-dom": "^15.3.0 || ^16.0.0"
84-
},
85-
"engines": {
86-
"node": ">= 8"
87-
}
2+
"name": "react-diff-viewer",
3+
"version": "3.2.0",
4+
"private": false,
5+
"description": "A simple and beautiful text diff viewer component made with diff and React",
6+
"keywords": [
7+
"review",
8+
"code-review",
9+
"diff",
10+
"diff-viewer",
11+
"github",
12+
"react",
13+
"react-component",
14+
"ui"
15+
],
16+
"repository": "git@github.com:praneshr/react-diff-viewer.git",
17+
"license": "MIT",
18+
"author": "Pranesh Ravi<praneshpranesh@gmail.com>",
19+
"main": "lib/index",
20+
"typings": "lib/index",
21+
"scripts": {
22+
"build": "tsc --outDir lib/",
23+
"build:examples": "webpack --progress --colors",
24+
"build:watch": "tsc --outDir lib/ -w",
25+
"publish:examples": "NODE_ENV=production yarn build:examples && gh-pages -d examples/dist -r $GITHUB_REPO_URL",
26+
"publish:examples:local": "NODE_ENV=production yarn build:examples && gh-pages -d examples/dist",
27+
"start:examples": "webpack-dev-server --open --hot --inline",
28+
"test": "mocha --require ts-node/register --require enzyme.ts ./test/**",
29+
"test:watch": "mocha --require ts-node/register --require enzyme.ts --watch-extensions ts,tsx --watch ./test/**"
30+
},
31+
"dependencies": {
32+
"classnames": "^2.2.6",
33+
"create-emotion": "^10.0.14",
34+
"diff": "^4.0.1",
35+
"emotion": "^10.0.14",
36+
"memoize-one": "^5.0.4",
37+
"prop-types": "^15.6.2"
38+
},
39+
"devDependencies": {
40+
"@types/classnames": "^2.2.6",
41+
"@types/diff": "^4.0.2",
42+
"@types/enzyme": "^3.1.14",
43+
"@types/enzyme-adapter-react-16": "^1.0.3",
44+
"@types/expect": "^1.20.3",
45+
"@types/memoize-one": "^4.1.1",
46+
"@types/mocha": "^5.2.5",
47+
"@types/node": "^12.12.53",
48+
"@types/react": "^16.9.43",
49+
"@types/react-dom": "^16.0.8",
50+
"@types/webpack": "^4.41.21",
51+
"@typescript-eslint/eslint-plugin": "^1.13.0",
52+
"@typescript-eslint/parser": "^1.13.0",
53+
"css-loader": "^3.6.0",
54+
"enzyme": "^3.7.0",
55+
"enzyme-adapter-react-16": "^1.6.0",
56+
"eslint-config-airbnb": "17.1.1",
57+
"eslint-plugin-import": "^2.22.0",
58+
"eslint-plugin-jsx-a11y": "^6.3.1",
59+
"eslint-plugin-react": "^7.20.5",
60+
"expect": "^24.8.0",
61+
"favicons-webpack-plugin": "^4.2.0",
62+
"file-loader": "^4.0.0",
63+
"gh-pages": "^2.0.1",
64+
"html-webpack-plugin": "^4.3.0",
65+
"mini-css-extract-plugin": "^0.7.0",
66+
"mocha": "^6.1.4",
67+
"node-sass": "^4.9.3",
68+
"raw-loader": "^3.0.0",
69+
"react": "^16.5.2",
70+
"react-dom": "^16.5.2",
71+
"sass-loader": "^7.1.0",
72+
"spy": "^1.0.0",
73+
"ts-loader": "^6.0.4",
74+
"ts-node": "^8.10.2",
75+
"typescript": "^3.5.2",
76+
"webpack": "^4.44.0",
77+
"webpack-cli": "^3.3.12",
78+
"webpack-dev-server": "^3.1.9"
79+
},
80+
"peerDependencies": {
81+
"react": "^15.3.0 || ^16.0.0",
82+
"react-dom": "^15.3.0 || ^16.0.0"
83+
},
84+
"engines": {
85+
"node": ">= 8"
86+
}
8887
}

‎src/compute-lines.ts

+197-197
Large diffs are not rendered by default.

‎src/index.tsx

+760-565
Large diffs are not rendered by default.

‎src/styles.ts

+408-374
Large diffs are not rendered by default.

‎test/react-diff-viewer-test.tsx

+14-13
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,30 @@ const bb = 456
2525

2626
describe('Testing react diff viewer', (): void => {
2727
it('It should render a table', (): void => {
28-
const node = shallow(<DiffViewer
29-
oldValue={oldCode}
30-
newValue={newCode}
31-
/>);
28+
const node = shallow(
29+
<DiffViewer oldValue={oldCode} newValue={newCode} commentLineIds={[]} />
30+
);
3231

3332
expect(node.find('table').length).toEqual(1);
3433
});
3534

3635
it('It should render diff lines in diff view', (): void => {
37-
const node = shallow(<DiffViewer
38-
oldValue={oldCode}
39-
newValue={newCode}
40-
/>);
36+
const node = shallow(
37+
<DiffViewer oldValue={oldCode} newValue={newCode} commentLineIds={[]} />
38+
);
4139

4240
expect(node.find('table > tbody tr').length).toEqual(7);
4341
});
4442

4543
it('It should render diff lines in inline view', (): void => {
46-
const node = shallow(<DiffViewer
47-
oldValue={oldCode}
48-
newValue={newCode}
49-
splitView={false}
50-
/>);
44+
const node = shallow(
45+
<DiffViewer
46+
oldValue={oldCode}
47+
newValue={newCode}
48+
splitView={false}
49+
commentLineIds={[]}
50+
/>
51+
);
5152

5253
expect(node.find('table > tbody tr').length).toEqual(9);
5354
});

‎tsconfig.json

+2-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@
99
"declaration": true,
1010
"downlevelIteration": true,
1111
"lib": ["es2017", "dom"],
12-
"types": [
13-
"mocha",
14-
"node"
15-
]
12+
"types": ["mocha", "node"]
1613
},
1714
"include": ["./src/*", "enzyme.js"],
18-
"exclude": ["node_modules"],
15+
"exclude": ["node_modules"]
1916
}

‎webpack.config.js

+25-27
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,56 @@ const FavIconsWebpackPlugin = require('favicons-webpack-plugin');
55

66
module.exports = {
77
entry: {
8-
main: './examples/src/index.tsx',
8+
main: './examples/src/index.tsx'
99
},
10-
mode: process.env.NODE_ENV === 'production' ?
11-
'production' : 'development',
10+
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
1211
resolve: {
13-
extensions: ['.jsx', '.tsx', '.ts', '.scss', '.css', '.js'],
12+
extensions: ['.jsx', '.tsx', '.ts', '.scss', '.css', '.js']
1413
},
1514
output: {
1615
path: path.resolve(__dirname, 'examples/dist'),
17-
filename: '[name].js',
16+
filename: '[name].js'
1817
},
1918
devServer: {
2019
contentBase: path.resolve(__dirname, 'examples/dist'),
2120
port: 8000,
22-
hot: true,
21+
hot: true
2322
},
2423
module: {
25-
rules: [{
24+
rules: [
25+
{
2626
test: /\.tsx?$/,
27-
use: [{
28-
loader: 'ts-loader',
29-
options: {
30-
configFile: 'tsconfig.examples.json',
31-
},
32-
}],
33-
exclude: /node_modules/,
27+
use: [
28+
{
29+
loader: 'ts-loader',
30+
options: {
31+
configFile: 'tsconfig.examples.json'
32+
}
33+
}
34+
],
35+
exclude: /node_modules/
3436
},
3537
{
3638
test: /\.s?css$/,
37-
use: [
38-
Css.loader,
39-
'css-loader',
40-
'sass-loader',
41-
],
39+
use: [Css.loader, 'css-loader', 'sass-loader']
4240
},
4341
{
4442
test: /\.xml|.rjs|.java/,
45-
use: 'raw-loader',
43+
use: 'raw-loader'
4644
},
4745
{
4846
test: /\.svg|.png/,
49-
use: 'file-loader',
50-
},
51-
],
47+
use: 'file-loader'
48+
}
49+
]
5250
},
5351
plugins: [
5452
new HtmlWebpackPlugin({
55-
template: './examples/src/index.ejs',
53+
template: './examples/src/index.ejs'
5654
}),
5755
new FavIconsWebpackPlugin('./logo-standalone.png'),
5856
new Css({
59-
filename: 'main.css',
60-
}),
61-
],
57+
filename: 'main.css'
58+
})
59+
]
6260
};

‎yarn.lock

+2,612-2,452
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.