Skip to content

Commit 4d1841d

Browse files
committed
Convert applyPatch to use parsePatch utility
1 parent 532bcf9 commit 4d1841d

File tree

2 files changed

+78
-42
lines changed

2 files changed

+78
-42
lines changed

src/patch/apply.js

Lines changed: 34 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,53 @@
1-
export function applyPatch(oldStr, uniDiff) {
2-
let diffstr = uniDiff.split('\n'),
3-
hunks = [],
4-
i = 0,
5-
remEOFNL = false,
6-
addEOFNL = false;
1+
import {parsePatch} from './parse';
72

8-
// Skip to the first change hunk
9-
while (i < diffstr.length && !(/^@@/.test(diffstr[i]))) {
10-
i++;
3+
export function applyPatch(oldStr, uniDiff) {
4+
if (typeof uniDiff === 'string') {
5+
uniDiff = parsePatch(uniDiff);
116
}
127

13-
// Parse the unified diff
14-
for (; i < diffstr.length; i++) {
15-
if (diffstr[i][0] === '@') {
16-
let chnukHeader = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/);
17-
hunks.unshift({
18-
start: chnukHeader[3],
19-
oldlength: +chnukHeader[2],
20-
removed: [],
21-
newlength: chnukHeader[4],
22-
added: []
23-
});
24-
} else if (diffstr[i][0] === '+') {
25-
hunks[0].added.push(diffstr[i].substr(1));
26-
} else if (diffstr[i][0] === '-') {
27-
hunks[0].removed.push(diffstr[i].substr(1));
28-
} else if (diffstr[i][0] === ' ') {
29-
hunks[0].added.push(diffstr[i].substr(1));
30-
hunks[0].removed.push(diffstr[i].substr(1));
31-
} else if (diffstr[i][0] === '\\') {
32-
if (diffstr[i - 1][0] === '+') {
33-
remEOFNL = true;
34-
} else if (diffstr[i - 1][0] === '-') {
35-
addEOFNL = true;
36-
}
8+
if (Array.isArray(uniDiff)) {
9+
if (uniDiff.length > 1) {
10+
throw new Error('applyPatch only works with a single input.');
3711
}
12+
13+
uniDiff = uniDiff[0];
3814
}
3915

4016
// Apply the diff to the input
41-
let lines = oldStr.split('\n');
42-
for (i = hunks.length - 1; i >= 0; i--) {
43-
let hunk = hunks[i];
17+
let lines = oldStr.split('\n'),
18+
hunks = uniDiff.hunks;
19+
for (let i = 0; i < hunks.length; i++) {
20+
let hunk = hunks[i],
21+
toPos = hunk.to.line - 1;
22+
4423
// Sanity check the input string. Bail if we don't match.
45-
for (let j = 0; j < hunk.oldlength; j++) {
46-
if (lines[hunk.start - 1 + j] !== hunk.removed[j]) {
47-
return false;
24+
for (let j = 0; j < hunk.lines.length; j++) {
25+
let line = hunk.lines[j];
26+
if (line.operation === ' ' || line.operation === '-') {
27+
// Context sanity check
28+
if (lines[toPos] !== line.content) {
29+
return false;
30+
}
31+
}
32+
33+
if (line.operation === ' ') {
34+
toPos++;
35+
} else if (line.operation === '-') {
36+
lines.splice(toPos, 1);
37+
/* istanbul ignore else */
38+
} else if (line.operation === '+') {
39+
lines.splice(toPos, 0, line.content);
40+
toPos++;
4841
}
4942
}
50-
Array.prototype.splice.apply(lines, [hunk.start - 1, hunk.oldlength].concat(hunk.added));
5143
}
5244

5345
// Handle EOFNL insertion/removal
54-
if (remEOFNL) {
46+
if (uniDiff.removeEOFNL) {
5547
while (!lines[lines.length - 1]) {
5648
lines.pop();
5749
}
58-
} else if (addEOFNL) {
50+
} else if (uniDiff.addEOFNL) {
5951
lines.push('');
6052
}
6153
return lines.join('\n');

test/patch/apply.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,54 @@
11
import {applyPatch} from '../../lib/patch/apply';
2+
import {parsePatch} from '../../lib/patch/parse';
23
import {createPatch} from '../../lib/patch/create';
34

45
import {expect} from 'chai';
56

67
describe('patch/apply', function() {
78
describe('#applyPatch', function() {
9+
it('should accept parsed patches', function() {
10+
let patch = parsePatch(
11+
'Index: test\n'
12+
+ '===================================================================\n'
13+
+ '--- test\theader1\n'
14+
+ '+++ test\theader2\n'
15+
+ '@@ -1,3 +1,4 @@\n'
16+
+ ' line2\n'
17+
+ ' line3\n'
18+
+ '+line4\n'
19+
+ ' line5\n');
20+
21+
expect(applyPatch(
22+
'line2\n'
23+
+ 'line3\n'
24+
+ 'line5\n',
25+
26+
patch))
27+
.to.equal(
28+
'line2\n'
29+
+ 'line3\n'
30+
+ 'line4\n'
31+
+ 'line5\n');
32+
33+
expect(applyPatch(
34+
'line2\n'
35+
+ 'line3\n'
36+
+ 'line5\n',
37+
38+
patch[0]))
39+
.to.equal(
40+
'line2\n'
41+
+ 'line3\n'
42+
+ 'line4\n'
43+
+ 'line5\n');
44+
});
45+
46+
it('should error if passed multiple indexes', function() {
47+
expect(function() {
48+
applyPatch('', [1, 2]);
49+
}).to['throw']('applyPatch only works with a single input.');
50+
});
51+
852
it('should apply patches that change the last line', function() {
953
expect(applyPatch(
1054
'line2\n'

0 commit comments

Comments
 (0)