parse.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.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. */
  9. function 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. // Diff index
  23. var header = (/^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/).exec(line);
  24. if (header) {
  25. index.index = header[1];
  26. }
  27. i++;
  28. }
  29. // Parse file headers if they are defined. Unified diff requires them, but
  30. // there's no technical issues to have an isolated hunk without file header
  31. parseFileHeader(index);
  32. parseFileHeader(index);
  33. // Parse hunks
  34. index.hunks = [];
  35. while (i < diffstr.length) {
  36. var line = diffstr[i];
  37. if ((/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/).test(line)) {
  38. break;
  39. }
  40. else if ((/^@@/).test(line)) {
  41. index.hunks.push(parseHunk());
  42. }
  43. else if (line) {
  44. throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(line));
  45. }
  46. else {
  47. i++;
  48. }
  49. }
  50. }
  51. // Parses the --- and +++ headers, if none are found, no lines
  52. // are consumed.
  53. function parseFileHeader(index) {
  54. var fileHeader = (/^(---|\+\+\+)\s+(.*)\r?$/).exec(diffstr[i]);
  55. if (fileHeader) {
  56. var data = fileHeader[2].split('\t', 2), header = (data[1] || '').trim();
  57. var fileName = data[0].replace(/\\\\/g, '\\');
  58. if ((/^".*"$/).test(fileName)) {
  59. fileName = fileName.substr(1, fileName.length - 2);
  60. }
  61. if (fileHeader[1] === '---') {
  62. index.oldFileName = fileName;
  63. index.oldHeader = header;
  64. }
  65. else {
  66. index.newFileName = fileName;
  67. index.newHeader = header;
  68. }
  69. i++;
  70. }
  71. }
  72. // Parses a hunk
  73. // This assumes that we are at the start of a hunk.
  74. function parseHunk() {
  75. var _a;
  76. var chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
  77. var hunk = {
  78. oldStart: +chunkHeader[1],
  79. oldLines: typeof chunkHeader[2] === 'undefined' ? 1 : +chunkHeader[2],
  80. newStart: +chunkHeader[3],
  81. newLines: typeof chunkHeader[4] === 'undefined' ? 1 : +chunkHeader[4],
  82. lines: []
  83. };
  84. // Unified Diff Format quirk: If the chunk size is 0,
  85. // the first number is one lower than one would expect.
  86. // https://www.artima.com/weblogs/viewpost.jsp?thread=164293
  87. if (hunk.oldLines === 0) {
  88. hunk.oldStart += 1;
  89. }
  90. if (hunk.newLines === 0) {
  91. hunk.newStart += 1;
  92. }
  93. var addCount = 0, removeCount = 0;
  94. for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a = diffstr[i]) === null || _a === void 0 ? void 0 : _a.startsWith('\\'))); i++) {
  95. var operation = (diffstr[i].length == 0 && i != (diffstr.length - 1)) ? ' ' : diffstr[i][0];
  96. if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') {
  97. hunk.lines.push(diffstr[i]);
  98. if (operation === '+') {
  99. addCount++;
  100. }
  101. else if (operation === '-') {
  102. removeCount++;
  103. }
  104. else if (operation === ' ') {
  105. addCount++;
  106. removeCount++;
  107. }
  108. }
  109. else {
  110. throw new Error("Hunk at line ".concat(chunkHeaderIndex + 1, " contained invalid line ").concat(diffstr[i]));
  111. }
  112. }
  113. // Handle the empty block count case
  114. if (!addCount && hunk.newLines === 1) {
  115. hunk.newLines = 0;
  116. }
  117. if (!removeCount && hunk.oldLines === 1) {
  118. hunk.oldLines = 0;
  119. }
  120. // Perform sanity checking
  121. if (addCount !== hunk.newLines) {
  122. throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
  123. }
  124. if (removeCount !== hunk.oldLines) {
  125. throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
  126. }
  127. return hunk;
  128. }
  129. while (i < diffstr.length) {
  130. parseIndex();
  131. }
  132. return list;
  133. }