| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- /**
- * Parses a patch into structured data, in the same structure returned by `structuredPatch`.
- *
- * @return a JSON object representation of the a patch, suitable for use with the `applyPatch` method.
- */
- export function parsePatch(uniDiff) {
- const diffstr = uniDiff.split(/\n/), list = [];
- let i = 0;
- function parseIndex() {
- const index = {};
- list.push(index);
- // Parse diff metadata
- while (i < diffstr.length) {
- const line = diffstr[i];
- // File header found, end parsing diff metadata
- if ((/^(---|\+\+\+|@@)\s/).test(line)) {
- break;
- }
- // Diff index
- const header = (/^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/).exec(line);
- if (header) {
- index.index = header[1];
- }
- i++;
- }
- // Parse file headers if they are defined. Unified diff requires them, but
- // there's no technical issues to have an isolated hunk without file header
- parseFileHeader(index);
- parseFileHeader(index);
- // Parse hunks
- index.hunks = [];
- while (i < diffstr.length) {
- const line = diffstr[i];
- if ((/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/).test(line)) {
- break;
- }
- else if ((/^@@/).test(line)) {
- index.hunks.push(parseHunk());
- }
- else if (line) {
- throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(line));
- }
- else {
- i++;
- }
- }
- }
- // Parses the --- and +++ headers, if none are found, no lines
- // are consumed.
- function parseFileHeader(index) {
- const fileHeader = (/^(---|\+\+\+)\s+(.*)\r?$/).exec(diffstr[i]);
- if (fileHeader) {
- const data = fileHeader[2].split('\t', 2), header = (data[1] || '').trim();
- let fileName = data[0].replace(/\\\\/g, '\\');
- if ((/^".*"$/).test(fileName)) {
- fileName = fileName.substr(1, fileName.length - 2);
- }
- if (fileHeader[1] === '---') {
- index.oldFileName = fileName;
- index.oldHeader = header;
- }
- else {
- index.newFileName = fileName;
- index.newHeader = header;
- }
- i++;
- }
- }
- // Parses a hunk
- // This assumes that we are at the start of a hunk.
- function parseHunk() {
- var _a;
- const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
- const hunk = {
- oldStart: +chunkHeader[1],
- oldLines: typeof chunkHeader[2] === 'undefined' ? 1 : +chunkHeader[2],
- newStart: +chunkHeader[3],
- newLines: typeof chunkHeader[4] === 'undefined' ? 1 : +chunkHeader[4],
- lines: []
- };
- // Unified Diff Format quirk: If the chunk size is 0,
- // the first number is one lower than one would expect.
- // https://www.artima.com/weblogs/viewpost.jsp?thread=164293
- if (hunk.oldLines === 0) {
- hunk.oldStart += 1;
- }
- if (hunk.newLines === 0) {
- hunk.newStart += 1;
- }
- let addCount = 0, removeCount = 0;
- for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a = diffstr[i]) === null || _a === void 0 ? void 0 : _a.startsWith('\\'))); i++) {
- const operation = (diffstr[i].length == 0 && i != (diffstr.length - 1)) ? ' ' : diffstr[i][0];
- if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') {
- hunk.lines.push(diffstr[i]);
- if (operation === '+') {
- addCount++;
- }
- else if (operation === '-') {
- removeCount++;
- }
- else if (operation === ' ') {
- addCount++;
- removeCount++;
- }
- }
- else {
- throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
- }
- }
- // Handle the empty block count case
- if (!addCount && hunk.newLines === 1) {
- hunk.newLines = 0;
- }
- if (!removeCount && hunk.oldLines === 1) {
- hunk.oldLines = 0;
- }
- // Perform sanity checking
- if (addCount !== hunk.newLines) {
- throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
- }
- if (removeCount !== hunk.oldLines) {
- throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
- }
- return hunk;
- }
- while (i < diffstr.length) {
- parseIndex();
- }
- return list;
- }
|