codekingpro/portable-devtools
115k
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.parsePatch = parsePatch;
4/**
5 * Parses a patch into structured data, in the same structure returned by `structuredPatch`.
6 *
7 * @return a JSON object representation of the a patch, suitable for use with the `applyPatch` method.
8 */
9function parsePatch(uniDiff) {
10 var diffstr = uniDiff.split(/\n/), list = [];
11 var i = 0;
12 function parseIndex() {
13 var index = {};
14 list.push(index);
15 // Parse diff metadata
16 while (i < diffstr.length) {
17 var line = diffstr[i];
18 // File header found, end parsing diff metadata
19 if ((/^(---|\+\+\+|@@)\s/).test(line)) {
20 break;
21 }
22 // Try to parse the line as a diff header, like
23 // Index: README.md
24 // or
25 // diff -r 9117c6561b0b -r 273ce12ad8f1 .hgignore
26 // or
27 // Index: something with multiple words
28 // and extract the filename (or whatever else is used as an index name)
29 // from the end (i.e. 'README.md', '.hgignore', or
30 // 'something with multiple words' in the examples above).
31 //
32 // TODO: It seems awkward that we indiscriminately trim off trailing
33 // whitespace here. Theoretically, couldn't that be meaningful -
34 // e.g. if the patch represents a diff of a file whose name ends
35 // with a space? Seems wrong to nuke it.
36 // But this behaviour has been around since v2.2.1 in 2015, so if
37 // it's going to change, it should be done cautiously and in a new
38 // major release, for backwards-compat reasons.
39 // -- ExplodingCabbage
40 var headerMatch = (/^(?:Index:|diff(?: -r \w+)+)\s+/).exec(line);
41 if (headerMatch) {
42 index.index = line.substring(headerMatch[0].length).trim();
43 }
44 i++;
45 }
46 // Parse file headers if they are defined. Unified diff requires them, but
47 // there's no technical issues to have an isolated hunk without file header
48 parseFileHeader(index);
49 parseFileHeader(index);
50 // Parse hunks
51 index.hunks = [];
52 while (i < diffstr.length) {
53 var line = diffstr[i];
54 if ((/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/).test(line)) {
55 break;
56 }
57 else if ((/^@@/).test(line)) {
58 index.hunks.push(parseHunk());
59 }
60 else if (line) {
61 throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(line));
62 }
63 else {
64 i++;
65 }
66 }
67 }
68 // Parses the --- and +++ headers, if none are found, no lines
69 // are consumed.
70 function parseFileHeader(index) {
71 var fileHeaderMatch = (/^(---|\+\+\+)\s+/).exec(diffstr[i]);
72 if (fileHeaderMatch) {
73 var prefix = fileHeaderMatch[1], data = diffstr[i].substring(3).trim().split('\t', 2), header = (data[1] || '').trim();
74 var fileName = data[0].replace(/\\\\/g, '\\');
75 if (fileName.startsWith('"') && fileName.endsWith('"')) {
76 fileName = fileName.substr(1, fileName.length - 2);
77 }
78 if (prefix === '---') {
79 index.oldFileName = fileName;
80 index.oldHeader = header;
81 }
82 else {
83 index.newFileName = fileName;
84 index.newHeader = header;
85 }
86 i++;
87 }
88 }
89 // Parses a hunk
90 // This assumes that we are at the start of a hunk.
91 function parseHunk() {
92 var _a;
93 var chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
94 var hunk = {
95 oldStart: +chunkHeader[1],
96 oldLines: typeof chunkHeader[2] === 'undefined' ? 1 : +chunkHeader[2],
97 newStart: +chunkHeader[3],
98 newLines: typeof chunkHeader[4] === 'undefined' ? 1 : +chunkHeader[4],
99 lines: []
100 };
101 // Unified Diff Format quirk: If the chunk size is 0,
102 // the first number is one lower than one would expect.
103 // https://www.artima.com/weblogs/viewpost.jsp?thread=164293
104 if (hunk.oldLines === 0) {
105 hunk.oldStart += 1;
106 }
107 if (hunk.newLines === 0) {
108 hunk.newStart += 1;
109 }
110 var addCount = 0, removeCount = 0;
111 for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a = diffstr[i]) === null || _a === void 0 ? void 0 : _a.startsWith('\\'))); i++) {
112 var operation = (diffstr[i].length == 0 && i != (diffstr.length - 1)) ? ' ' : diffstr[i][0];
113 if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') {
114 hunk.lines.push(diffstr[i]);
115 if (operation === '+') {
116 addCount++;
117 }
118 else if (operation === '-') {
119 removeCount++;
120 }
121 else if (operation === ' ') {
122 addCount++;
123 removeCount++;
124 }
125 }
126 else {
127 throw new Error("Hunk at line ".concat(chunkHeaderIndex + 1, " contained invalid line ").concat(diffstr[i]));
128 }
129 }
130 // Handle the empty block count case
131 if (!addCount && hunk.newLines === 1) {
132 hunk.newLines = 0;
133 }
134 if (!removeCount && hunk.oldLines === 1) {
135 hunk.oldLines = 0;
136 }
137 // Perform sanity checking
138 if (addCount !== hunk.newLines) {
139 throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
140 }
141 if (removeCount !== hunk.oldLines) {
142 throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
143 }
144 return hunk;
145 }
146 while (i < diffstr.length) {
147 parseIndex();
148 }
149 return list;
150}
151 