-
Notifications
You must be signed in to change notification settings - Fork 510
/
Copy pathapply.js
102 lines (86 loc) · 2.55 KB
/
apply.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import {parsePatch} from './parse';
export function applyPatch(source, uniDiff, options = {}) {
if (typeof uniDiff === 'string') {
uniDiff = parsePatch(uniDiff);
}
if (Array.isArray(uniDiff)) {
if (uniDiff.length > 1) {
throw new Error('applyPatch only works with a single input.');
}
uniDiff = uniDiff[0];
}
// Apply the diff to the input
let lines = source.split('\n'),
hunks = uniDiff.hunks,
compareLine = options.compareLine || ((lineNumber, line, operation, patchContent) => line === patchContent),
errorCount = 0,
fuzzFactor = options.fuzzFactor || 0,
removeEOFNL,
addEOFNL;
for (let i = 0; i < hunks.length; i++) {
let hunk = hunks[i],
toPos = hunk.newStart - 1;
// Sanity check the input string. Bail if we don't match.
for (let j = 0; j < hunk.lines.length; j++) {
let line = hunk.lines[j],
operation = line[0],
content = line.substr(1);
if (operation === ' ' || operation === '-') {
// Context sanity check
if (!compareLine(toPos + 1, lines[toPos], operation, content)) {
errorCount++;
if (errorCount > fuzzFactor) {
return false;
}
}
}
if (operation === ' ') {
toPos++;
} else if (operation === '-') {
lines.splice(toPos, 1);
/* istanbul ignore else */
} else if (operation === '+') {
lines.splice(toPos, 0, content);
toPos++;
} else if (operation === '\\') {
let previousOperation = hunk.lines[j - 1] ? hunk.lines[j - 1][0] : null;
if (previousOperation === '+') {
removeEOFNL = true;
} else if (previousOperation === '-') {
addEOFNL = true;
}
}
}
}
// Handle EOFNL insertion/removal
if (removeEOFNL) {
while (!lines[lines.length - 1]) {
lines.pop();
}
} else if (addEOFNL) {
lines.push('');
}
return lines.join('\n');
}
// Wrapper that supports multiple file patches via callbacks.
export function applyPatches(uniDiff, options) {
if (typeof uniDiff === 'string') {
uniDiff = parsePatch(uniDiff);
}
let currentIndex = 0;
function processIndex() {
let index = uniDiff[currentIndex++];
if (!index) {
options.complete();
}
options.loadFile(index, function(err, data) {
if (err) {
return options.complete(err);
}
let updatedContent = applyPatch(data, index, options);
options.patched(index, updatedContent);
setTimeout(processIndex, 0);
});
}
processIndex();
}