@pierre/diffs 1.6.0-beta.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/components/CodeView.d.ts +3 -2
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +18 -14
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts +31 -9
  6. package/dist/components/File.d.ts.map +1 -1
  7. package/dist/components/File.js +165 -84
  8. package/dist/components/File.js.map +1 -1
  9. package/dist/components/FileDiff.d.ts +32 -9
  10. package/dist/components/FileDiff.d.ts.map +1 -1
  11. package/dist/components/FileDiff.js +213 -124
  12. package/dist/components/FileDiff.js.map +1 -1
  13. package/dist/components/UnresolvedFile.d.ts +14 -4
  14. package/dist/components/UnresolvedFile.d.ts.map +1 -1
  15. package/dist/components/UnresolvedFile.js +35 -16
  16. package/dist/components/UnresolvedFile.js.map +1 -1
  17. package/dist/components/VirtualizedFile.d.ts +3 -2
  18. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  19. package/dist/components/VirtualizedFile.js +28 -20
  20. package/dist/components/VirtualizedFile.js.map +1 -1
  21. package/dist/components/VirtualizedFileDiff.d.ts +3 -2
  22. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  23. package/dist/components/VirtualizedFileDiff.js +31 -24
  24. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  25. package/dist/constants.d.ts +2 -1
  26. package/dist/constants.d.ts.map +1 -1
  27. package/dist/constants.js +2 -1
  28. package/dist/constants.js.map +1 -1
  29. package/dist/editor/platform.d.ts +1 -1
  30. package/dist/editor/platform.js +5 -4
  31. package/dist/editor/platform.js.map +1 -1
  32. package/dist/editor/selection.d.ts +2 -2
  33. package/dist/editor/selection.d.ts.map +1 -1
  34. package/dist/editor/selection.js +31 -6
  35. package/dist/editor/selection.js.map +1 -1
  36. package/dist/highlighter/shared_highlighter.d.ts +2 -1
  37. package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
  38. package/dist/highlighter/shared_highlighter.js +2 -2
  39. package/dist/highlighter/shared_highlighter.js.map +1 -1
  40. package/dist/index.d.ts +10 -5
  41. package/dist/index.js +8 -3
  42. package/dist/react/CodeView.d.ts +4 -3
  43. package/dist/react/CodeView.d.ts.map +1 -1
  44. package/dist/react/CodeView.js +48 -39
  45. package/dist/react/CodeView.js.map +1 -1
  46. package/dist/react/File.js +3 -3
  47. package/dist/react/File.js.map +1 -1
  48. package/dist/react/FileDiff.js +3 -3
  49. package/dist/react/FileDiff.js.map +1 -1
  50. package/dist/react/MultiFileDiff.js +2 -2
  51. package/dist/react/MultiFileDiff.js.map +1 -1
  52. package/dist/react/PatchDiff.js +3 -3
  53. package/dist/react/PatchDiff.js.map +1 -1
  54. package/dist/react/UnresolvedFile.js +2 -2
  55. package/dist/react/UnresolvedFile.js.map +1 -1
  56. package/dist/react/index.d.ts +2 -2
  57. package/dist/react/types.d.ts +4 -2
  58. package/dist/react/types.d.ts.map +1 -1
  59. package/dist/react/utils/renderDiffChildren.js +1 -1
  60. package/dist/react/utils/renderDiffChildren.js.map +1 -1
  61. package/dist/react/utils/renderFileChildren.js +1 -1
  62. package/dist/react/utils/renderFileChildren.js.map +1 -1
  63. package/dist/react/utils/useFileDiffInstance.d.ts +1 -0
  64. package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
  65. package/dist/react/utils/useFileDiffInstance.js +29 -24
  66. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  67. package/dist/react/utils/useFileInstance.d.ts +2 -0
  68. package/dist/react/utils/useFileInstance.d.ts.map +1 -1
  69. package/dist/react/utils/useFileInstance.js +38 -28
  70. package/dist/react/utils/useFileInstance.js.map +1 -1
  71. package/dist/react/utils/useForceUpdate.d.ts +5 -0
  72. package/dist/react/utils/useForceUpdate.d.ts.map +1 -0
  73. package/dist/react/utils/useForceUpdate.js +27 -0
  74. package/dist/react/utils/useForceUpdate.js.map +1 -0
  75. package/dist/react/utils/useNextRenderData.d.ts +9 -0
  76. package/dist/react/utils/useNextRenderData.d.ts.map +1 -0
  77. package/dist/react/utils/useNextRenderData.js +9 -0
  78. package/dist/react/utils/useNextRenderData.js.map +1 -0
  79. package/dist/react/utils/useUnresolvedFileInstance.d.ts +1 -0
  80. package/dist/react/utils/useUnresolvedFileInstance.d.ts.map +1 -1
  81. package/dist/react/utils/useUnresolvedFileInstance.js +26 -11
  82. package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
  83. package/dist/renderers/DiffHunksRenderer.d.ts +2 -1
  84. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  85. package/dist/renderers/DiffHunksRenderer.js +62 -32
  86. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  87. package/dist/renderers/FileRenderer.d.ts +4 -1
  88. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  89. package/dist/renderers/FileRenderer.js +55 -30
  90. package/dist/renderers/FileRenderer.js.map +1 -1
  91. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
  92. package/dist/renderers/UnresolvedFileHunksRenderer.js +1 -1
  93. package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
  94. package/dist/ssr/FileDiffReact.js +1 -1
  95. package/dist/types.d.ts +10 -0
  96. package/dist/types.d.ts.map +1 -1
  97. package/dist/utils/canUseWASM.d.ts +13 -0
  98. package/dist/utils/canUseWASM.d.ts.map +1 -0
  99. package/dist/utils/canUseWASM.js +59 -0
  100. package/dist/utils/canUseWASM.js.map +1 -0
  101. package/dist/utils/getCodeViewItemRenderData.d.ts +10 -0
  102. package/dist/utils/getCodeViewItemRenderData.d.ts.map +1 -0
  103. package/dist/utils/getCodeViewItemRenderData.js +19 -0
  104. package/dist/utils/getCodeViewItemRenderData.js.map +1 -0
  105. package/dist/utils/hastToHtml.d.ts +2 -2
  106. package/dist/utils/hastToHtml.js +2 -2
  107. package/dist/utils/hastToHtml.js.map +1 -1
  108. package/dist/utils/hydratePartialDiff.js +4 -0
  109. package/dist/utils/hydratePartialDiff.js.map +1 -1
  110. package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
  111. package/dist/utils/parseMergeConflictDiffFromFile.js +2 -0
  112. package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
  113. package/dist/utils/parsePatchFiles.d.ts.map +1 -1
  114. package/dist/utils/parsePatchFiles.js +24 -4
  115. package/dist/utils/parsePatchFiles.js.map +1 -1
  116. package/dist/utils/renderTokenLines.d.ts +6 -1
  117. package/dist/utils/renderTokenLines.d.ts.map +1 -1
  118. package/dist/utils/renderTokenLines.js +4 -0
  119. package/dist/utils/renderTokenLines.js.map +1 -1
  120. package/dist/utils/resolveRegion.js +20 -10
  121. package/dist/utils/resolveRegion.js.map +1 -1
  122. package/dist/utils/tokenStyle.d.ts +5 -1
  123. package/dist/utils/tokenStyle.d.ts.map +1 -1
  124. package/dist/utils/tokenStyle.js +5 -1
  125. package/dist/utils/tokenStyle.js.map +1 -1
  126. package/dist/utils/tokensToHtml.d.ts +5 -2
  127. package/dist/utils/tokensToHtml.d.ts.map +1 -1
  128. package/dist/utils/tokensToHtml.js +5 -2
  129. package/dist/utils/tokensToHtml.js.map +1 -1
  130. package/dist/utils/updateDiffHunks.d.ts +2 -2
  131. package/dist/utils/updateDiffHunks.d.ts.map +1 -1
  132. package/dist/utils/updateDiffHunks.js +7 -3
  133. package/dist/utils/updateDiffHunks.js.map +1 -1
  134. package/dist/worker/WorkerPoolManager.d.ts +12 -0
  135. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  136. package/dist/worker/WorkerPoolManager.js +99 -21
  137. package/dist/worker/WorkerPoolManager.js.map +1 -1
  138. package/dist/worker/{highlights-sAHlxqlf.js → highlights-CpZm9DAR.js} +2 -2
  139. package/dist/worker/{highlights-sAHlxqlf.js.map → highlights-CpZm9DAR.js.map} +1 -1
  140. package/dist/worker/{shiki-Bx2JpdqZ.js → shiki-Ci4cdHsM.js} +2 -2
  141. package/dist/worker/{shiki-Bx2JpdqZ.js.map → shiki-Ci4cdHsM.js.map} +1 -1
  142. package/dist/worker/{stream-tokenizer-YZ6M1qSx.js → stream-tokenizer-DK9xp5M5.js} +8 -5
  143. package/dist/worker/stream-tokenizer-DK9xp5M5.js.map +1 -0
  144. package/dist/worker/types.d.ts +11 -0
  145. package/dist/worker/types.d.ts.map +1 -1
  146. package/dist/worker/worker-portable.js +2 -2
  147. package/dist/worker/worker-portable.js.map +1 -1
  148. package/dist/worker/worker.js +12 -3
  149. package/dist/worker/worker.js.map +1 -1
  150. package/package.json +28 -30
  151. package/dist/worker/stream-tokenizer-YZ6M1qSx.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"parsePatchFiles.d.ts","names":[],"sources":["../../src/utils/parsePatchFiles.ts"],"mappings":";;iBAsCgB,aACd,cACA,yBACA,yBACC;UAiFO;EACR;EACA;EACA,UAAU;EACV,UAAU;EACV;;iBAGc,YACd,wBACA,UAAU,qBACT;;;;;;;;;;;;iBA8hBa,gBACd,cACA,yBACA,yBACC"}
1
+ {"version":3,"file":"parsePatchFiles.d.ts","names":[],"sources":["../../src/utils/parsePatchFiles.ts"],"mappings":";;iBAsCgB,aACd,cACA,yBACA,yBACC;UAiFO;EACR;EACA;EACA,UAAU;EACV,UAAU;EACV;;iBAGc,YACd,wBACA,UAAU,qBACT;;;;;;;;;;;;iBA8iBa,gBACd,cACA,yBACA,yBACC"}
@@ -83,6 +83,8 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
83
83
  isPartial,
84
84
  additionLines: !isPartial && oldFile != null && newFile != null ? splitFileContents(newFile.contents) : [],
85
85
  deletionLines: !isPartial && oldFile != null && newFile != null ? splitFileContents(oldFile.contents) : [],
86
+ additionCharacterCount: !isPartial && oldFile != null && newFile != null ? newFile.contents.length : 0,
87
+ deletionCharacterCount: !isPartial && oldFile != null && newFile != null ? oldFile.contents.length : 0,
86
88
  cacheKey: maybeDetachOptionalString(cacheKey)
87
89
  };
88
90
  if (currentFile.additionLines.length === 1 && newFile?.contents === "") currentFile.additionLines.length = 0;
@@ -188,7 +190,10 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
188
190
  }
189
191
  additionLineIndex++;
190
192
  parsedAdditionLines++;
191
- if (isPartial) currentFile.additionLines.push(line);
193
+ if (isPartial) {
194
+ currentFile.additionLines.push(line);
195
+ currentFile.additionCharacterCount += line.length;
196
+ }
192
197
  currentContent.additions++;
193
198
  additionLines++;
194
199
  lastLineType = "addition";
@@ -201,7 +206,10 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
201
206
  }
202
207
  deletionLineIndex++;
203
208
  parsedDeletionLines++;
204
- if (isPartial) currentFile.deletionLines.push(line);
209
+ if (isPartial) {
210
+ currentFile.deletionLines.push(line);
211
+ currentFile.deletionCharacterCount += line.length;
212
+ }
205
213
  currentContent.deletions++;
206
214
  deletionLines++;
207
215
  lastLineType = "deletion";
@@ -219,6 +227,8 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
219
227
  if (isPartial) {
220
228
  currentFile.deletionLines.push(line);
221
229
  currentFile.additionLines.push(line);
230
+ currentFile.deletionCharacterCount += line.length;
231
+ currentFile.additionCharacterCount += line.length;
222
232
  }
223
233
  currentContent.lines++;
224
234
  lastLineType = "context";
@@ -230,11 +240,21 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
230
240
  else if (lastLineType === "addition") hunkData.noEOFCRAdditions = true;
231
241
  if (isPartial && (lastLineType === "addition" || lastLineType === "context")) {
232
242
  const lastIndex = currentFile.additionLines.length - 1;
233
- if (lastIndex >= 0) currentFile.additionLines[lastIndex] = cleanLastNewline(currentFile.additionLines[lastIndex]);
243
+ if (lastIndex >= 0) {
244
+ const line = currentFile.additionLines[lastIndex];
245
+ const cleanedLine = cleanLastNewline(line);
246
+ currentFile.additionLines[lastIndex] = cleanedLine;
247
+ currentFile.additionCharacterCount += cleanedLine.length - line.length;
248
+ }
234
249
  }
235
250
  if (isPartial && (lastLineType === "deletion" || lastLineType === "context")) {
236
251
  const lastIndex = currentFile.deletionLines.length - 1;
237
- if (lastIndex >= 0) currentFile.deletionLines[lastIndex] = cleanLastNewline(currentFile.deletionLines[lastIndex]);
252
+ if (lastIndex >= 0) {
253
+ const line = currentFile.deletionLines[lastIndex];
254
+ const cleanedLine = cleanLastNewline(line);
255
+ currentFile.deletionLines[lastIndex] = cleanedLine;
256
+ currentFile.deletionCharacterCount += cleanedLine.length - line.length;
257
+ }
238
258
  }
239
259
  }
240
260
  }
@@ -1 +1 @@
1
- {"version":3,"file":"parsePatchFiles.js","names":[],"sources":["../../src/utils/parsePatchFiles.ts"],"sourcesContent":["import {\n COMMIT_METADATA_SPLIT,\n FILENAME_HEADER_REGEX,\n GIT_DIFF_FILE_BREAK_REGEX,\n INDEX_LINE_METADATA,\n} from '../constants';\nimport type {\n ChangeContent,\n ContextContent,\n FileContents,\n FileDiffMetadata,\n Hunk,\n HunkLineType,\n ParsedPatch,\n} from '../types';\nimport { cleanLastNewline } from './cleanLastNewline';\nimport { composeCacheKey } from './composeCacheKey';\nimport { detachString, releaseStringDetachBuffer } from './detachString';\nimport {\n getHunkSideEndBoundary,\n getHunkSideStartBoundary,\n} from './getHunkSideBoundaries';\nimport { parseQuotedDiffFileName } from './parseQuotedDiffFileName';\nimport { realignChangeContentBySimilarity } from './realignChangeContent';\n\n// Keep quotes and transport prefixes until decoding, while allowing spaces in\n// unquoted paths and escaped quotes inside quoted paths.\nconst GIT_DIFF_HEADER_FILENAMES =\n /^diff --git (\"a\\/(?:[^\"\\\\]|\\\\.)*\"|a\\/.+?) (\"b\\/(?:[^\"\\\\]|\\\\.)*\"|b\\/.+?)$/;\n\ninterface ParsedHunkHeader {\n additionCount: number;\n additionStart: number;\n deletionCount: number;\n deletionStart: number;\n hunkContext?: string;\n}\n\nexport function processPatch(\n data: string,\n cacheKeyPrefix?: string,\n throwOnError?: boolean\n): ParsedPatch {\n try {\n return _processPatch(data, cacheKeyPrefix, throwOnError);\n } finally {\n releaseStringDetachBuffer();\n }\n}\n\nfunction _processPatch(\n data: string,\n cacheKeyPrefix?: string,\n throwOnError = false,\n patchIndex?: number\n): ParsedPatch {\n const isGitDiff = isGitDiffPatch(data);\n const rawFiles = isGitDiff\n ? splitGitDiffFiles(data)\n : splitUnifiedDiffFiles(data);\n let patchMetadata: string | undefined;\n const files: FileDiffMetadata[] = [];\n for (const fileOrPatchMetadata of rawFiles) {\n if (isGitDiff && !GIT_DIFF_FILE_BREAK_REGEX.test(fileOrPatchMetadata)) {\n if (patchMetadata == null) {\n patchMetadata = detachString(fileOrPatchMetadata);\n } else {\n if (throwOnError) {\n throw Error('parsePatchContent: unknown file blob');\n } else {\n console.error(\n 'parsePatchContent: unknown file blob:',\n fileOrPatchMetadata\n );\n }\n }\n // If we get in here, it's most likely the introductory metadata from the\n // patch, or something is fucked with the diff format\n continue;\n } else if (\n !isGitDiff &&\n !startsWithUnifiedDiffFileHeader(fileOrPatchMetadata)\n ) {\n if (patchMetadata == null) {\n patchMetadata = detachString(fileOrPatchMetadata);\n } else {\n if (throwOnError) {\n throw Error('parsePatchContent: unknown file blob');\n } else {\n console.error(\n 'parsePatchContent: unknown file blob:',\n fileOrPatchMetadata\n );\n }\n }\n continue;\n }\n const currentFile = _processFile(fileOrPatchMetadata, {\n cacheKey:\n cacheKeyPrefix != null\n ? patchIndex == null\n ? composeCacheKey(\n 'patch-file',\n cacheKeyPrefix,\n String(files.length)\n )\n : composeCacheKey(\n 'patch-file',\n cacheKeyPrefix,\n String(patchIndex),\n String(files.length)\n )\n : undefined,\n isGitDiff,\n throwOnError,\n });\n if (currentFile != null) {\n files.push(currentFile);\n }\n }\n return { patchMetadata, files };\n}\n\ninterface ProcessFileOptions {\n cacheKey?: string;\n isGitDiff?: boolean;\n oldFile?: FileContents;\n newFile?: FileContents;\n throwOnError?: boolean;\n}\n\nexport function processFile(\n fileDiffString: string,\n options?: ProcessFileOptions\n): FileDiffMetadata | undefined {\n try {\n return _processFile(fileDiffString, options);\n } finally {\n releaseStringDetachBuffer();\n }\n}\n\nfunction _processFile(\n fileDiffString: string,\n {\n cacheKey,\n isGitDiff = GIT_DIFF_FILE_BREAK_REGEX.test(fileDiffString),\n oldFile,\n newFile,\n throwOnError = false,\n }: ProcessFileOptions = {}\n): FileDiffMetadata | undefined {\n let lastHunkEnd = 0;\n const hunks = splitAtLinePrefix(fileDiffString, '@@ ');\n let currentFile: FileDiffMetadata | undefined;\n const isPartial = oldFile == null || newFile == null;\n let deletionLineIndex = 0;\n let additionLineIndex = 0;\n for (const hunk of hunks) {\n const lines = splitWithNewlines(hunk);\n const firstLine = lines[0];\n if (firstLine == null) {\n if (throwOnError) {\n throw Error('parsePatchContent: invalid hunk');\n } else {\n console.error('parsePatchContent: invalid hunk', hunk);\n }\n continue;\n }\n const fileHeader = parseHunkHeader(firstLine);\n let additionLines = 0;\n let deletionLines = 0;\n // Setup currentFile, this should be the first iteration of our hunks, and\n // technically not a hunk\n if (fileHeader == null || currentFile == null) {\n if (currentFile != null) {\n if (throwOnError) {\n throw Error('parsePatchContent: Invalid hunk');\n } else {\n console.error('parsePatchContent: Invalid hunk', hunk);\n }\n continue;\n }\n currentFile = {\n name: '',\n type: 'change',\n hunks: [],\n splitLineCount: 0,\n unifiedLineCount: 0,\n isPartial,\n additionLines:\n !isPartial && oldFile != null && newFile != null\n ? splitFileContents(newFile.contents)\n : [],\n deletionLines:\n !isPartial && oldFile != null && newFile != null\n ? splitFileContents(oldFile.contents)\n : [],\n cacheKey: maybeDetachOptionalString(cacheKey),\n };\n // If either file is technically empty, then we should empty the\n // arrays respectively\n if (currentFile.additionLines.length === 1 && newFile?.contents === '') {\n currentFile.additionLines.length = 0;\n }\n if (currentFile.deletionLines.length === 1 && oldFile?.contents === '') {\n currentFile.deletionLines.length = 0;\n }\n\n for (const line of lines) {\n if (line.startsWith('diff --git')) {\n const filenameMatch = line.trim().match(GIT_DIFF_HEADER_FILENAMES);\n if (filenameMatch == null) {\n if (throwOnError) {\n throw Error('parsePatchContent: invalid git diff header');\n } else {\n console.error('parsePatchContent: invalid git diff header', line);\n }\n continue;\n }\n const prevName = decodeDiffFileName(filenameMatch[1], true);\n const name = decodeDiffFileName(filenameMatch[2], true);\n currentFile.name = detachString(name);\n if (prevName !== name) {\n currentFile.prevName = detachString(prevName);\n }\n continue;\n }\n\n const filenameMatch =\n line.startsWith('---') || line.startsWith('+++')\n ? line.match(FILENAME_HEADER_REGEX)\n : null;\n if (filenameMatch != null) {\n const [, type, rawFileName] = filenameMatch;\n const fileName = decodeDiffFileName(rawFileName, isGitDiff);\n if (type === '---' && fileName !== '/dev/null') {\n const detachedFileName = detachString(fileName);\n currentFile.prevName = detachedFileName;\n currentFile.name = detachedFileName;\n } else if (type === '+++' && fileName !== '/dev/null') {\n currentFile.name = detachString(fileName);\n }\n }\n // Git diffs have a bunch of additional metadata we can pull from\n else if (isGitDiff) {\n if (line.startsWith('new mode ')) {\n currentFile.mode = detachString(\n line.slice('new mode'.length).trim()\n );\n }\n if (line.startsWith('old mode ')) {\n currentFile.prevMode = detachString(\n line.slice('old mode'.length).trim()\n );\n }\n if (line.startsWith('new file mode')) {\n currentFile.type = 'new';\n currentFile.mode = detachString(\n line.slice('new file mode'.length).trim()\n );\n }\n if (line.startsWith('deleted file mode')) {\n currentFile.type = 'deleted';\n currentFile.mode = detachString(\n line.slice('deleted file mode'.length).trim()\n );\n }\n if (line.startsWith('similarity index')) {\n if (line.startsWith('similarity index 100%')) {\n currentFile.type = 'rename-pure';\n } else {\n currentFile.type = 'rename-changed';\n }\n }\n if (line.startsWith('index ')) {\n const [, prevObjectId, newObjectId, mode] =\n line.trim().match(INDEX_LINE_METADATA) ?? [];\n if (prevObjectId != null) {\n currentFile.prevObjectId = detachString(prevObjectId);\n }\n if (newObjectId != null) {\n currentFile.newObjectId = detachString(newObjectId);\n }\n if (mode != null) {\n currentFile.mode = detachString(mode);\n }\n }\n // Pure renames and copies have no --- / +++ headers. These paths\n // are already relative to the repository, without transport prefixes.\n if (\n line.startsWith('rename from ') ||\n line.startsWith('copy from ')\n ) {\n currentFile.prevName = detachString(\n decodeDiffFileName(\n line.slice(\n line.startsWith('rename')\n ? 'rename from '.length\n : 'copy from '.length\n )\n )\n );\n }\n if (line.startsWith('rename to ') || line.startsWith('copy to ')) {\n currentFile.name = detachString(\n decodeDiffFileName(\n line.slice(\n line.startsWith('rename')\n ? 'rename to '.length\n : 'copy to '.length\n )\n )\n );\n }\n }\n }\n continue;\n }\n\n // Otherwise, time to start parsing out the hunk\n let currentContent: ContextContent | ChangeContent | undefined;\n let lastLineType: 'context' | 'addition' | 'deletion' | undefined;\n\n // Strip trailing bare newlines (format-patch separators between commits)\n // if needed\n while (\n lines.length > 0 &&\n (lines[lines.length - 1] === '\\n' ||\n lines[lines.length - 1] === '\\r' ||\n lines[lines.length - 1] === '\\r\\n' ||\n lines[lines.length - 1] === '')\n ) {\n lines.pop();\n }\n\n const { additionStart, deletionStart } = fileHeader;\n deletionLineIndex = isPartial ? deletionLineIndex : deletionStart - 1;\n additionLineIndex = isPartial ? additionLineIndex : additionStart - 1;\n\n const hunkData: Hunk = {\n collapsedBefore: 0,\n\n splitLineCount: 0,\n splitLineStart: 0,\n\n unifiedLineCount: 0,\n unifiedLineStart: 0,\n\n additionCount: fileHeader.additionCount,\n additionStart,\n additionLines,\n\n deletionCount: fileHeader.deletionCount,\n deletionStart,\n deletionLines,\n\n deletionLineIndex,\n additionLineIndex,\n\n hunkContent: [],\n hunkContext: maybeDetachOptionalString(fileHeader.hunkContext),\n hunkSpecs: detachString(firstLine),\n\n noEOFCRAdditions: false,\n noEOFCRDeletions: false,\n };\n\n // Now we process each line of the hunk\n let parsedAdditionLines = 0;\n let parsedDeletionLines = 0;\n for (let lineIndex = 1; lineIndex < lines.length; lineIndex++) {\n const rawLine = lines[lineIndex];\n if (\n parsedAdditionLines >= hunkData.additionCount &&\n parsedDeletionLines >= hunkData.deletionCount &&\n !rawLine.startsWith('\\\\')\n ) {\n const isUnexpectedBodyLine =\n isHunkBodyLine(rawLine) && !isFormatPatchVersionSeparator(rawLine);\n if (!isUnexpectedBodyLine) {\n break;\n }\n if (throwOnError) {\n throw Error('parsePatchContent: hunk has more lines than expected');\n }\n }\n\n const firstChar = rawLine[0];\n // If we can't properly process the line, well, lets just try to salvage\n // things and continue... It's possible an AI generated diff might have\n // some stray blank lines or something in there\n if (\n firstChar !== '+' &&\n firstChar !== '-' &&\n firstChar !== ' ' &&\n firstChar !== '\\\\'\n ) {\n if (throwOnError) {\n throw Error('parsePatchContent: invalid hunk line');\n }\n console.error(\n `parseLineType: Invalid firstChar: \"${firstChar}\", full line: \"${rawLine}\"`\n );\n console.error('processFile: invalid rawLine:', rawLine);\n continue;\n }\n\n const type = parseRawLineType(firstChar);\n if (type === 'addition') {\n if (throwOnError && parsedAdditionLines >= hunkData.additionCount) {\n throw Error('parsePatchContent: hunk has too many addition lines');\n }\n const line = getParsedLineContent(rawLine);\n if (currentContent == null || currentContent.type !== 'change') {\n currentContent = createContentGroup(\n 'change',\n deletionLineIndex,\n additionLineIndex\n );\n hunkData.hunkContent.push(currentContent);\n }\n additionLineIndex++;\n parsedAdditionLines++;\n if (isPartial) {\n currentFile.additionLines.push(line);\n }\n currentContent.additions++;\n additionLines++;\n lastLineType = 'addition';\n } else if (type === 'deletion') {\n if (throwOnError && parsedDeletionLines >= hunkData.deletionCount) {\n throw Error('parsePatchContent: hunk has too many deletion lines');\n }\n const line = getParsedLineContent(rawLine);\n if (currentContent == null || currentContent.type !== 'change') {\n currentContent = createContentGroup(\n 'change',\n deletionLineIndex,\n additionLineIndex\n );\n hunkData.hunkContent.push(currentContent);\n }\n deletionLineIndex++;\n parsedDeletionLines++;\n if (isPartial) {\n currentFile.deletionLines.push(line);\n }\n currentContent.deletions++;\n deletionLines++;\n lastLineType = 'deletion';\n } else if (type === 'context') {\n if (\n throwOnError &&\n (parsedDeletionLines >= hunkData.deletionCount ||\n parsedAdditionLines >= hunkData.additionCount)\n ) {\n throw Error('parsePatchContent: hunk has too many context lines');\n }\n const line = getParsedLineContent(rawLine);\n if (currentContent == null || currentContent.type !== 'context') {\n currentContent = createContentGroup(\n 'context',\n deletionLineIndex,\n additionLineIndex\n );\n hunkData.hunkContent.push(currentContent);\n }\n additionLineIndex++;\n deletionLineIndex++;\n parsedAdditionLines++;\n parsedDeletionLines++;\n if (isPartial) {\n currentFile.deletionLines.push(line);\n currentFile.additionLines.push(line);\n }\n currentContent.lines++;\n lastLineType = 'context';\n } else if (type === 'metadata' && currentContent != null) {\n if (currentContent.type === 'context') {\n hunkData.noEOFCRAdditions = true;\n hunkData.noEOFCRDeletions = true;\n } else if (lastLineType === 'deletion') {\n hunkData.noEOFCRDeletions = true;\n } else if (lastLineType === 'addition') {\n hunkData.noEOFCRAdditions = true;\n }\n // If we're dealing with partial content from a diff, we need to strip\n // newlines manually from the content\n if (\n isPartial &&\n (lastLineType === 'addition' || lastLineType === 'context')\n ) {\n const lastIndex = currentFile.additionLines.length - 1;\n if (lastIndex >= 0) {\n currentFile.additionLines[lastIndex] = cleanLastNewline(\n currentFile.additionLines[lastIndex]\n );\n }\n }\n if (\n isPartial &&\n (lastLineType === 'deletion' || lastLineType === 'context')\n ) {\n const lastIndex = currentFile.deletionLines.length - 1;\n if (lastIndex >= 0) {\n currentFile.deletionLines[lastIndex] = cleanLastNewline(\n currentFile.deletionLines[lastIndex]\n );\n }\n }\n }\n }\n\n if (\n parsedAdditionLines !== hunkData.additionCount ||\n parsedDeletionLines !== hunkData.deletionCount\n ) {\n if (throwOnError) {\n throw Error('parsePatchContent: hunk line count mismatch');\n }\n console.error(\n `parsePatchContent: hunk line count mismatch: \"${firstLine.trimEnd()}\", declared old/new ${hunkData.deletionCount}/${hunkData.additionCount}, parsed old/new ${parsedDeletionLines}/${parsedAdditionLines}`\n );\n // Re-encode each original boundary using the repaired count. Zero-count\n // ranges use the boundary itself as their start; positive ranges use +1.\n const repairedAdditionStart =\n getHunkSideStartBoundary(\n hunkData.additionStart,\n hunkData.additionCount\n ) + (parsedAdditionLines === 0 ? 0 : 1);\n const repairedDeletionStart =\n getHunkSideStartBoundary(\n hunkData.deletionStart,\n hunkData.deletionCount\n ) + (parsedDeletionLines === 0 ? 0 : 1);\n\n // Hydrated hunks index into full-file line arrays, so their indexes must\n // move with repaired starts. Partial hunks index patch-built arrays.\n if (!isPartial) {\n const additionStartDelta =\n repairedAdditionStart - hunkData.additionStart;\n const deletionStartDelta =\n repairedDeletionStart - hunkData.deletionStart;\n hunkData.additionLineIndex += additionStartDelta;\n hunkData.deletionLineIndex += deletionStartDelta;\n for (const content of hunkData.hunkContent) {\n content.additionLineIndex += additionStartDelta;\n content.deletionLineIndex += deletionStartDelta;\n }\n }\n\n hunkData.additionStart = repairedAdditionStart;\n hunkData.deletionStart = repairedDeletionStart;\n hunkData.additionCount = parsedAdditionLines;\n hunkData.deletionCount = parsedDeletionLines;\n }\n\n hunkData.additionLines = additionLines;\n hunkData.deletionLines = deletionLines;\n\n hunkData.collapsedBefore = Math.max(\n getHunkSideStartBoundary(hunkData.additionStart, hunkData.additionCount) -\n lastHunkEnd,\n 0\n );\n currentFile.hunks.push(hunkData);\n lastHunkEnd = getHunkSideEndBoundary(\n hunkData.additionStart,\n hunkData.additionCount\n );\n for (const content of hunkData.hunkContent) {\n if (content.type === 'context') {\n hunkData.splitLineCount += content.lines;\n hunkData.unifiedLineCount += content.lines;\n } else {\n hunkData.splitLineCount += Math.max(\n content.additions,\n content.deletions\n );\n hunkData.unifiedLineCount += content.deletions + content.additions;\n }\n }\n hunkData.splitLineStart =\n currentFile.splitLineCount + hunkData.collapsedBefore;\n hunkData.unifiedLineStart =\n currentFile.unifiedLineCount + hunkData.collapsedBefore;\n\n currentFile.splitLineCount +=\n hunkData.collapsedBefore + hunkData.splitLineCount;\n currentFile.unifiedLineCount +=\n hunkData.collapsedBefore + hunkData.unifiedLineCount;\n }\n if (currentFile == null) {\n return undefined;\n }\n if (\n throwOnError &&\n isPartial &&\n !isGitDiff &&\n currentFile.hunks.length === 0\n ) {\n throw Error('parsePatchContent: unified file has no hunks');\n }\n\n // Account for collapsed lines after the final hunk and increment the\n // split/unified counts properly\n if (\n currentFile.hunks.length > 0 &&\n !isPartial &&\n currentFile.additionLines.length > 0 &&\n currentFile.deletionLines.length > 0\n ) {\n const lastHunk = currentFile.hunks[currentFile.hunks.length - 1];\n const lastHunkEnd = getHunkSideEndBoundary(\n lastHunk.additionStart,\n lastHunk.additionCount\n );\n const totalFileLines = currentFile.additionLines.length;\n const collapsedAfter = Math.max(totalFileLines - lastHunkEnd, 0);\n currentFile.splitLineCount += collapsedAfter;\n currentFile.unifiedLineCount += collapsedAfter;\n }\n\n // If this isn't a git diff style patch, then we'll need to sus out some\n // additional metadata manually\n if (!isGitDiff) {\n if (\n currentFile.prevName != null &&\n currentFile.name !== currentFile.prevName\n ) {\n if (currentFile.hunks.length > 0) {\n currentFile.type = 'rename-changed';\n } else {\n currentFile.type = 'rename-pure';\n }\n }\n // Sort of a hack for detecting deleted/added files...\n else if (\n (oldFile == null || oldFile.contents === '') &&\n newFile != null &&\n newFile.contents !== ''\n ) {\n currentFile.type = 'new';\n } else if (\n oldFile != null &&\n oldFile.contents !== '' &&\n (newFile == null || newFile.contents === '')\n ) {\n currentFile.type = 'deleted';\n }\n }\n if (\n currentFile.type !== 'rename-pure' &&\n currentFile.type !== 'rename-changed'\n ) {\n currentFile.prevName = undefined;\n }\n // Pair change-block lines by similarity instead of the patch's positional\n // ordering. Partial diffs work too: their hunk line indexes point into the\n // patch-built line arrays, which hold every line a block references.\n realignChangeContentBySimilarity(currentFile);\n return currentFile;\n}\n\n/**\n * Parses a patch file string into an array of parsed patches.\n *\n * @param data - The raw patch file content (supports multi-commit patches)\n * @param cacheKeyPrefix - Optional prefix for collision-safe cache keys derived\n * from the prefix, patch index, and file index. This enables caching of\n * rendered diff results in the worker pool.\n * @param throwOnError - When true, invalid data throws. When false, invalid data\n * is reported with `console.error` and the parser attempts to recover when\n * possible. Recovery is best-effort and does not guarantee valid output.\n */\nexport function parsePatchFiles(\n data: string,\n cacheKeyPrefix?: string,\n throwOnError = false\n): ParsedPatch[] {\n // NOTE(amadeus): This function is pretty forgiving in that it can accept a\n // patch file that includes commit metdata, multiple commits, or not\n const patches: ParsedPatch[] = [];\n const rawPatches = hasCommitMetadataBoundary(data)\n ? data.split(COMMIT_METADATA_SPLIT)\n : [data];\n for (const patch of rawPatches) {\n try {\n patches.push(\n _processPatch(\n patch,\n cacheKeyPrefix,\n throwOnError,\n cacheKeyPrefix != null ? patches.length : undefined\n )\n );\n } catch (error) {\n if (throwOnError) {\n throw error;\n } else {\n console.error(error);\n }\n } finally {\n releaseStringDetachBuffer();\n }\n }\n return patches;\n}\n\n// Decode only quoted tokens, preserving whitespace inside them. Git's a/ and\n// b/ prefixes are part of the quoted token and must be removed after decoding.\nfunction decodeDiffFileName(value: string, stripGitPrefix = false): string {\n const rawName = value.trim();\n const name = rawName.startsWith('\"')\n ? (parseQuotedDiffFileName(rawName)?.fileName ?? rawName)\n : rawName;\n return stripGitPrefix && (name.startsWith('a/') || name.startsWith('b/'))\n ? name.slice(2)\n : name;\n}\n\nfunction hasCommitMetadataBoundary(data: string): boolean {\n return data.startsWith('From ') || data.includes('\\nFrom ');\n}\n\nfunction splitFileContents(contents: string): string[] {\n const lines = splitWithNewlines(contents);\n for (let index = 0; index < lines.length; index++) {\n lines[index] = detachString(lines[index]);\n }\n return lines;\n}\n\nfunction splitWithNewlines(contents: string): string[] {\n if (contents.length === 0) {\n return [''];\n }\n\n const lines: string[] = [];\n let startIndex = 0;\n for (;;) {\n const newlineIndex = contents.indexOf('\\n', startIndex);\n if (newlineIndex === -1) {\n break;\n }\n\n lines.push(contents.slice(startIndex, newlineIndex + 1));\n startIndex = newlineIndex + 1;\n }\n\n if (startIndex < contents.length) {\n lines.push(contents.slice(startIndex));\n }\n return lines;\n}\n\nfunction splitGitDiffFiles(contents: string): string[] {\n return splitAtLinePrefix(contents, 'diff --git');\n}\n\nfunction splitUnifiedDiffFiles(contents: string): string[] {\n if (contents.length === 0) {\n return [''];\n }\n\n const parts: string[] = [];\n let partStartIndex = 0;\n let lineStartIndex = 0;\n let remainingDeletionLines = 0;\n let remainingAdditionLines = 0;\n let hasOpenedUnifiedFile = false;\n\n while (lineStartIndex < contents.length) {\n const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);\n if (remainingDeletionLines <= 0 && remainingAdditionLines <= 0) {\n if (isUnifiedDiffFileHeaderAt(contents, lineStartIndex)) {\n if (lineStartIndex > partStartIndex) {\n parts.push(contents.slice(partStartIndex, lineStartIndex));\n }\n partStartIndex = lineStartIndex;\n hasOpenedUnifiedFile = true;\n lineStartIndex = getNextLineStartIndex(contents, nextLineStartIndex);\n continue;\n }\n\n if (hasOpenedUnifiedFile && contents.startsWith('@@ -', lineStartIndex)) {\n const fileHeader = parseHunkHeader(\n contents.slice(lineStartIndex, nextLineStartIndex)\n );\n if (fileHeader != null) {\n remainingDeletionLines = fileHeader.deletionCount;\n remainingAdditionLines = fileHeader.additionCount;\n }\n }\n lineStartIndex = nextLineStartIndex;\n continue;\n }\n\n const firstChar = contents[lineStartIndex];\n if (firstChar === '\\\\') {\n lineStartIndex = nextLineStartIndex;\n continue;\n }\n\n if (firstChar === ' ') {\n remainingDeletionLines = Math.max(remainingDeletionLines - 1, 0);\n remainingAdditionLines = Math.max(remainingAdditionLines - 1, 0);\n } else if (firstChar === '-') {\n remainingDeletionLines = Math.max(remainingDeletionLines - 1, 0);\n } else if (firstChar === '+') {\n remainingAdditionLines = Math.max(remainingAdditionLines - 1, 0);\n }\n lineStartIndex = nextLineStartIndex;\n }\n\n parts.push(contents.slice(partStartIndex));\n return parts;\n}\n\nfunction startsWithUnifiedDiffFileHeader(contents: string): boolean {\n return isUnifiedDiffFileHeaderAt(contents, 0);\n}\n\nfunction isUnifiedDiffFileHeaderAt(contents: string, lineStartIndex: number) {\n const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);\n return (\n isUnifiedDiffHeaderLineAt(contents, lineStartIndex, '---') &&\n isUnifiedDiffHeaderLineAt(contents, nextLineStartIndex, '+++')\n );\n}\n\nfunction isUnifiedDiffHeaderLineAt(\n contents: string,\n lineStartIndex: number,\n prefix: '---' | '+++'\n): boolean {\n if (!contents.startsWith(prefix, lineStartIndex)) {\n return false;\n }\n\n const separator = contents[lineStartIndex + prefix.length];\n if (separator !== ' ' && separator !== '\\t') {\n return false;\n }\n\n for (\n let index = lineStartIndex + prefix.length + 1;\n index < contents.length;\n index++\n ) {\n const char = contents[index];\n if (char === '\\n' || char === '\\r') {\n break;\n }\n if (char !== ' ' && char !== '\\t') {\n return true;\n }\n }\n return false;\n}\n\nfunction getNextLineStartIndex(\n contents: string,\n lineStartIndex: number\n): number {\n const newlineIndex = contents.indexOf('\\n', lineStartIndex);\n return newlineIndex === -1 ? contents.length : newlineIndex + 1;\n}\n\nfunction isHunkBodyLine(line: string): boolean {\n const firstChar = line[0];\n return firstChar === '+' || firstChar === '-' || firstChar === ' ';\n}\n\nfunction isFormatPatchVersionSeparator(line: string): boolean {\n if (!line.startsWith('--')) {\n return false;\n }\n\n for (let index = 2; index < line.length; index++) {\n const char = line[index];\n if (char !== ' ' && char !== '\\t' && char !== '\\n' && char !== '\\r') {\n return false;\n }\n }\n return true;\n}\n\nfunction parseHunkHeader(line: string): ParsedHunkHeader | undefined {\n if (!line.startsWith('@@ -')) {\n return undefined;\n }\n\n let index = 4;\n const deletionStartResult = readPositiveInteger(line, index);\n if (deletionStartResult == null) {\n return undefined;\n }\n const deletionStart = deletionStartResult.value;\n index = deletionStartResult.endIndex;\n\n let deletionCount = 1;\n if (line[index] === ',') {\n const deletionCountResult = readPositiveInteger(line, index + 1);\n if (deletionCountResult == null) {\n return undefined;\n }\n deletionCount = deletionCountResult.value;\n index = deletionCountResult.endIndex;\n }\n\n if (line[index] !== ' ' || line[index + 1] !== '+') {\n return undefined;\n }\n index += 2;\n\n const additionStartResult = readPositiveInteger(line, index);\n if (additionStartResult == null) {\n return undefined;\n }\n const additionStart = additionStartResult.value;\n index = additionStartResult.endIndex;\n\n let additionCount = 1;\n if (line[index] === ',') {\n const additionCountResult = readPositiveInteger(line, index + 1);\n if (additionCountResult == null) {\n return undefined;\n }\n additionCount = additionCountResult.value;\n index = additionCountResult.endIndex;\n }\n\n if (\n line[index] !== ' ' ||\n line[index + 1] !== '@' ||\n line[index + 2] !== '@'\n ) {\n return undefined;\n }\n\n let hunkContext: string | undefined;\n const contextStartIndex = index + 3;\n if (line[contextStartIndex] === ' ') {\n hunkContext = trimLineEnd(line.slice(contextStartIndex + 1));\n }\n\n return {\n additionCount,\n additionStart,\n deletionCount,\n deletionStart,\n hunkContext,\n };\n}\n\nfunction readPositiveInteger(\n value: string,\n startIndex: number\n): { value: number; endIndex: number } | undefined {\n let index = startIndex;\n let parsedValue = 0;\n for (; index < value.length; index++) {\n const digit = value.charCodeAt(index) - 48;\n if (digit < 0 || digit > 9) {\n break;\n }\n parsedValue = parsedValue * 10 + digit;\n }\n\n if (index === startIndex) {\n return undefined;\n }\n return { value: parsedValue, endIndex: index };\n}\n\nfunction trimLineEnd(value: string): string {\n if (value.endsWith('\\r\\n')) {\n return value.slice(0, -2);\n }\n if (value.endsWith('\\n')) {\n return value.slice(0, -1);\n }\n return value;\n}\n\nfunction isGitDiffPatch(data: string): boolean {\n return data.startsWith('diff --git') || data.includes('\\ndiff --git');\n}\n\nfunction splitAtLinePrefix(contents: string, prefix: string): string[] {\n if (contents.length === 0) {\n return [''];\n }\n\n const newlinePrefix = `\\n${prefix}`;\n const firstBoundaryIndex = contents.startsWith(prefix)\n ? 0\n : findLinePrefixIndex(contents, newlinePrefix, 0);\n if (firstBoundaryIndex === -1) {\n return [contents];\n }\n\n const parts: string[] = [];\n if (firstBoundaryIndex > 0) {\n parts.push(contents.slice(0, firstBoundaryIndex));\n }\n\n let startIndex = firstBoundaryIndex;\n for (;;) {\n const nextBoundaryIndex = findLinePrefixIndex(\n contents,\n newlinePrefix,\n startIndex + 1\n );\n if (nextBoundaryIndex === -1) {\n break;\n }\n\n parts.push(contents.slice(startIndex, nextBoundaryIndex));\n startIndex = nextBoundaryIndex;\n }\n parts.push(contents.slice(startIndex));\n return parts;\n}\n\nfunction findLinePrefixIndex(\n contents: string,\n newlinePrefix: string,\n fromIndex: number\n): number {\n const index = contents.indexOf(newlinePrefix, fromIndex);\n return index === -1 ? -1 : index + 1;\n}\n\nfunction maybeDetachOptionalString<T extends string | undefined>(value: T): T {\n return (value == null ? value : detachString(value)) as T;\n}\n\nfunction parseRawLineType(\n firstChar: string | undefined\n): Exclude<HunkLineType, 'expanded'> {\n return firstChar === ' '\n ? 'context'\n : firstChar === '\\\\'\n ? 'metadata'\n : firstChar === '+'\n ? 'addition'\n : 'deletion';\n}\n\nfunction getParsedLineContent(rawLine: string): string {\n const processedLine = rawLine.slice(1);\n return detachString(processedLine === '' ? '\\n' : processedLine);\n}\n\nfunction createContentGroup(\n type: 'change',\n deletionLineIndex: number,\n additionLineIndex: number\n): ChangeContent;\nfunction createContentGroup(\n type: 'context',\n deletionLineIndex: number,\n additionLineIndex: number\n): ContextContent;\nfunction createContentGroup(\n type: 'change' | 'context',\n deletionLineIndex: number,\n additionLineIndex: number\n): ChangeContent | ContextContent {\n if (type === 'change') {\n return {\n type: 'change',\n additions: 0,\n deletions: 0,\n additionLineIndex,\n deletionLineIndex,\n };\n }\n return {\n type: 'context',\n lines: 0,\n additionLineIndex,\n deletionLineIndex,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"parsePatchFiles.js","names":[],"sources":["../../src/utils/parsePatchFiles.ts"],"sourcesContent":["import {\n COMMIT_METADATA_SPLIT,\n FILENAME_HEADER_REGEX,\n GIT_DIFF_FILE_BREAK_REGEX,\n INDEX_LINE_METADATA,\n} from '../constants';\nimport type {\n ChangeContent,\n ContextContent,\n FileContents,\n FileDiffMetadata,\n Hunk,\n HunkLineType,\n ParsedPatch,\n} from '../types';\nimport { cleanLastNewline } from './cleanLastNewline';\nimport { composeCacheKey } from './composeCacheKey';\nimport { detachString, releaseStringDetachBuffer } from './detachString';\nimport {\n getHunkSideEndBoundary,\n getHunkSideStartBoundary,\n} from './getHunkSideBoundaries';\nimport { parseQuotedDiffFileName } from './parseQuotedDiffFileName';\nimport { realignChangeContentBySimilarity } from './realignChangeContent';\n\n// Keep quotes and transport prefixes until decoding, while allowing spaces in\n// unquoted paths and escaped quotes inside quoted paths.\nconst GIT_DIFF_HEADER_FILENAMES =\n /^diff --git (\"a\\/(?:[^\"\\\\]|\\\\.)*\"|a\\/.+?) (\"b\\/(?:[^\"\\\\]|\\\\.)*\"|b\\/.+?)$/;\n\ninterface ParsedHunkHeader {\n additionCount: number;\n additionStart: number;\n deletionCount: number;\n deletionStart: number;\n hunkContext?: string;\n}\n\nexport function processPatch(\n data: string,\n cacheKeyPrefix?: string,\n throwOnError?: boolean\n): ParsedPatch {\n try {\n return _processPatch(data, cacheKeyPrefix, throwOnError);\n } finally {\n releaseStringDetachBuffer();\n }\n}\n\nfunction _processPatch(\n data: string,\n cacheKeyPrefix?: string,\n throwOnError = false,\n patchIndex?: number\n): ParsedPatch {\n const isGitDiff = isGitDiffPatch(data);\n const rawFiles = isGitDiff\n ? splitGitDiffFiles(data)\n : splitUnifiedDiffFiles(data);\n let patchMetadata: string | undefined;\n const files: FileDiffMetadata[] = [];\n for (const fileOrPatchMetadata of rawFiles) {\n if (isGitDiff && !GIT_DIFF_FILE_BREAK_REGEX.test(fileOrPatchMetadata)) {\n if (patchMetadata == null) {\n patchMetadata = detachString(fileOrPatchMetadata);\n } else {\n if (throwOnError) {\n throw Error('parsePatchContent: unknown file blob');\n } else {\n console.error(\n 'parsePatchContent: unknown file blob:',\n fileOrPatchMetadata\n );\n }\n }\n // If we get in here, it's most likely the introductory metadata from the\n // patch, or something is fucked with the diff format\n continue;\n } else if (\n !isGitDiff &&\n !startsWithUnifiedDiffFileHeader(fileOrPatchMetadata)\n ) {\n if (patchMetadata == null) {\n patchMetadata = detachString(fileOrPatchMetadata);\n } else {\n if (throwOnError) {\n throw Error('parsePatchContent: unknown file blob');\n } else {\n console.error(\n 'parsePatchContent: unknown file blob:',\n fileOrPatchMetadata\n );\n }\n }\n continue;\n }\n const currentFile = _processFile(fileOrPatchMetadata, {\n cacheKey:\n cacheKeyPrefix != null\n ? patchIndex == null\n ? composeCacheKey(\n 'patch-file',\n cacheKeyPrefix,\n String(files.length)\n )\n : composeCacheKey(\n 'patch-file',\n cacheKeyPrefix,\n String(patchIndex),\n String(files.length)\n )\n : undefined,\n isGitDiff,\n throwOnError,\n });\n if (currentFile != null) {\n files.push(currentFile);\n }\n }\n return { patchMetadata, files };\n}\n\ninterface ProcessFileOptions {\n cacheKey?: string;\n isGitDiff?: boolean;\n oldFile?: FileContents;\n newFile?: FileContents;\n throwOnError?: boolean;\n}\n\nexport function processFile(\n fileDiffString: string,\n options?: ProcessFileOptions\n): FileDiffMetadata | undefined {\n try {\n return _processFile(fileDiffString, options);\n } finally {\n releaseStringDetachBuffer();\n }\n}\n\nfunction _processFile(\n fileDiffString: string,\n {\n cacheKey,\n isGitDiff = GIT_DIFF_FILE_BREAK_REGEX.test(fileDiffString),\n oldFile,\n newFile,\n throwOnError = false,\n }: ProcessFileOptions = {}\n): FileDiffMetadata | undefined {\n let lastHunkEnd = 0;\n const hunks = splitAtLinePrefix(fileDiffString, '@@ ');\n let currentFile: FileDiffMetadata | undefined;\n const isPartial = oldFile == null || newFile == null;\n let deletionLineIndex = 0;\n let additionLineIndex = 0;\n for (const hunk of hunks) {\n const lines = splitWithNewlines(hunk);\n const firstLine = lines[0];\n if (firstLine == null) {\n if (throwOnError) {\n throw Error('parsePatchContent: invalid hunk');\n } else {\n console.error('parsePatchContent: invalid hunk', hunk);\n }\n continue;\n }\n const fileHeader = parseHunkHeader(firstLine);\n let additionLines = 0;\n let deletionLines = 0;\n // Setup currentFile, this should be the first iteration of our hunks, and\n // technically not a hunk\n if (fileHeader == null || currentFile == null) {\n if (currentFile != null) {\n if (throwOnError) {\n throw Error('parsePatchContent: Invalid hunk');\n } else {\n console.error('parsePatchContent: Invalid hunk', hunk);\n }\n continue;\n }\n currentFile = {\n name: '',\n type: 'change',\n hunks: [],\n splitLineCount: 0,\n unifiedLineCount: 0,\n isPartial,\n additionLines:\n !isPartial && oldFile != null && newFile != null\n ? splitFileContents(newFile.contents)\n : [],\n deletionLines:\n !isPartial && oldFile != null && newFile != null\n ? splitFileContents(oldFile.contents)\n : [],\n additionCharacterCount:\n !isPartial && oldFile != null && newFile != null\n ? newFile.contents.length\n : 0,\n deletionCharacterCount:\n !isPartial && oldFile != null && newFile != null\n ? oldFile.contents.length\n : 0,\n cacheKey: maybeDetachOptionalString(cacheKey),\n };\n // If either file is technically empty, then we should empty the\n // arrays respectively\n if (currentFile.additionLines.length === 1 && newFile?.contents === '') {\n currentFile.additionLines.length = 0;\n }\n if (currentFile.deletionLines.length === 1 && oldFile?.contents === '') {\n currentFile.deletionLines.length = 0;\n }\n\n for (const line of lines) {\n if (line.startsWith('diff --git')) {\n const filenameMatch = line.trim().match(GIT_DIFF_HEADER_FILENAMES);\n if (filenameMatch == null) {\n if (throwOnError) {\n throw Error('parsePatchContent: invalid git diff header');\n } else {\n console.error('parsePatchContent: invalid git diff header', line);\n }\n continue;\n }\n const prevName = decodeDiffFileName(filenameMatch[1], true);\n const name = decodeDiffFileName(filenameMatch[2], true);\n currentFile.name = detachString(name);\n if (prevName !== name) {\n currentFile.prevName = detachString(prevName);\n }\n continue;\n }\n\n const filenameMatch =\n line.startsWith('---') || line.startsWith('+++')\n ? line.match(FILENAME_HEADER_REGEX)\n : null;\n if (filenameMatch != null) {\n const [, type, rawFileName] = filenameMatch;\n const fileName = decodeDiffFileName(rawFileName, isGitDiff);\n if (type === '---' && fileName !== '/dev/null') {\n const detachedFileName = detachString(fileName);\n currentFile.prevName = detachedFileName;\n currentFile.name = detachedFileName;\n } else if (type === '+++' && fileName !== '/dev/null') {\n currentFile.name = detachString(fileName);\n }\n }\n // Git diffs have a bunch of additional metadata we can pull from\n else if (isGitDiff) {\n if (line.startsWith('new mode ')) {\n currentFile.mode = detachString(\n line.slice('new mode'.length).trim()\n );\n }\n if (line.startsWith('old mode ')) {\n currentFile.prevMode = detachString(\n line.slice('old mode'.length).trim()\n );\n }\n if (line.startsWith('new file mode')) {\n currentFile.type = 'new';\n currentFile.mode = detachString(\n line.slice('new file mode'.length).trim()\n );\n }\n if (line.startsWith('deleted file mode')) {\n currentFile.type = 'deleted';\n currentFile.mode = detachString(\n line.slice('deleted file mode'.length).trim()\n );\n }\n if (line.startsWith('similarity index')) {\n if (line.startsWith('similarity index 100%')) {\n currentFile.type = 'rename-pure';\n } else {\n currentFile.type = 'rename-changed';\n }\n }\n if (line.startsWith('index ')) {\n const [, prevObjectId, newObjectId, mode] =\n line.trim().match(INDEX_LINE_METADATA) ?? [];\n if (prevObjectId != null) {\n currentFile.prevObjectId = detachString(prevObjectId);\n }\n if (newObjectId != null) {\n currentFile.newObjectId = detachString(newObjectId);\n }\n if (mode != null) {\n currentFile.mode = detachString(mode);\n }\n }\n // Pure renames and copies have no --- / +++ headers. These paths\n // are already relative to the repository, without transport prefixes.\n if (\n line.startsWith('rename from ') ||\n line.startsWith('copy from ')\n ) {\n currentFile.prevName = detachString(\n decodeDiffFileName(\n line.slice(\n line.startsWith('rename')\n ? 'rename from '.length\n : 'copy from '.length\n )\n )\n );\n }\n if (line.startsWith('rename to ') || line.startsWith('copy to ')) {\n currentFile.name = detachString(\n decodeDiffFileName(\n line.slice(\n line.startsWith('rename')\n ? 'rename to '.length\n : 'copy to '.length\n )\n )\n );\n }\n }\n }\n continue;\n }\n\n // Otherwise, time to start parsing out the hunk\n let currentContent: ContextContent | ChangeContent | undefined;\n let lastLineType: 'context' | 'addition' | 'deletion' | undefined;\n\n // Strip trailing bare newlines (format-patch separators between commits)\n // if needed\n while (\n lines.length > 0 &&\n (lines[lines.length - 1] === '\\n' ||\n lines[lines.length - 1] === '\\r' ||\n lines[lines.length - 1] === '\\r\\n' ||\n lines[lines.length - 1] === '')\n ) {\n lines.pop();\n }\n\n const { additionStart, deletionStart } = fileHeader;\n deletionLineIndex = isPartial ? deletionLineIndex : deletionStart - 1;\n additionLineIndex = isPartial ? additionLineIndex : additionStart - 1;\n\n const hunkData: Hunk = {\n collapsedBefore: 0,\n\n splitLineCount: 0,\n splitLineStart: 0,\n\n unifiedLineCount: 0,\n unifiedLineStart: 0,\n\n additionCount: fileHeader.additionCount,\n additionStart,\n additionLines,\n\n deletionCount: fileHeader.deletionCount,\n deletionStart,\n deletionLines,\n\n deletionLineIndex,\n additionLineIndex,\n\n hunkContent: [],\n hunkContext: maybeDetachOptionalString(fileHeader.hunkContext),\n hunkSpecs: detachString(firstLine),\n\n noEOFCRAdditions: false,\n noEOFCRDeletions: false,\n };\n\n // Now we process each line of the hunk\n let parsedAdditionLines = 0;\n let parsedDeletionLines = 0;\n for (let lineIndex = 1; lineIndex < lines.length; lineIndex++) {\n const rawLine = lines[lineIndex];\n if (\n parsedAdditionLines >= hunkData.additionCount &&\n parsedDeletionLines >= hunkData.deletionCount &&\n !rawLine.startsWith('\\\\')\n ) {\n const isUnexpectedBodyLine =\n isHunkBodyLine(rawLine) && !isFormatPatchVersionSeparator(rawLine);\n if (!isUnexpectedBodyLine) {\n break;\n }\n if (throwOnError) {\n throw Error('parsePatchContent: hunk has more lines than expected');\n }\n }\n\n const firstChar = rawLine[0];\n // If we can't properly process the line, well, lets just try to salvage\n // things and continue... It's possible an AI generated diff might have\n // some stray blank lines or something in there\n if (\n firstChar !== '+' &&\n firstChar !== '-' &&\n firstChar !== ' ' &&\n firstChar !== '\\\\'\n ) {\n if (throwOnError) {\n throw Error('parsePatchContent: invalid hunk line');\n }\n console.error(\n `parseLineType: Invalid firstChar: \"${firstChar}\", full line: \"${rawLine}\"`\n );\n console.error('processFile: invalid rawLine:', rawLine);\n continue;\n }\n\n const type = parseRawLineType(firstChar);\n if (type === 'addition') {\n if (throwOnError && parsedAdditionLines >= hunkData.additionCount) {\n throw Error('parsePatchContent: hunk has too many addition lines');\n }\n const line = getParsedLineContent(rawLine);\n if (currentContent == null || currentContent.type !== 'change') {\n currentContent = createContentGroup(\n 'change',\n deletionLineIndex,\n additionLineIndex\n );\n hunkData.hunkContent.push(currentContent);\n }\n additionLineIndex++;\n parsedAdditionLines++;\n if (isPartial) {\n currentFile.additionLines.push(line);\n currentFile.additionCharacterCount += line.length;\n }\n currentContent.additions++;\n additionLines++;\n lastLineType = 'addition';\n } else if (type === 'deletion') {\n if (throwOnError && parsedDeletionLines >= hunkData.deletionCount) {\n throw Error('parsePatchContent: hunk has too many deletion lines');\n }\n const line = getParsedLineContent(rawLine);\n if (currentContent == null || currentContent.type !== 'change') {\n currentContent = createContentGroup(\n 'change',\n deletionLineIndex,\n additionLineIndex\n );\n hunkData.hunkContent.push(currentContent);\n }\n deletionLineIndex++;\n parsedDeletionLines++;\n if (isPartial) {\n currentFile.deletionLines.push(line);\n currentFile.deletionCharacterCount += line.length;\n }\n currentContent.deletions++;\n deletionLines++;\n lastLineType = 'deletion';\n } else if (type === 'context') {\n if (\n throwOnError &&\n (parsedDeletionLines >= hunkData.deletionCount ||\n parsedAdditionLines >= hunkData.additionCount)\n ) {\n throw Error('parsePatchContent: hunk has too many context lines');\n }\n const line = getParsedLineContent(rawLine);\n if (currentContent == null || currentContent.type !== 'context') {\n currentContent = createContentGroup(\n 'context',\n deletionLineIndex,\n additionLineIndex\n );\n hunkData.hunkContent.push(currentContent);\n }\n additionLineIndex++;\n deletionLineIndex++;\n parsedAdditionLines++;\n parsedDeletionLines++;\n if (isPartial) {\n currentFile.deletionLines.push(line);\n currentFile.additionLines.push(line);\n currentFile.deletionCharacterCount += line.length;\n currentFile.additionCharacterCount += line.length;\n }\n currentContent.lines++;\n lastLineType = 'context';\n } else if (type === 'metadata' && currentContent != null) {\n if (currentContent.type === 'context') {\n hunkData.noEOFCRAdditions = true;\n hunkData.noEOFCRDeletions = true;\n } else if (lastLineType === 'deletion') {\n hunkData.noEOFCRDeletions = true;\n } else if (lastLineType === 'addition') {\n hunkData.noEOFCRAdditions = true;\n }\n // If we're dealing with partial content from a diff, we need to strip\n // newlines manually from the content\n if (\n isPartial &&\n (lastLineType === 'addition' || lastLineType === 'context')\n ) {\n const lastIndex = currentFile.additionLines.length - 1;\n if (lastIndex >= 0) {\n const line = currentFile.additionLines[lastIndex];\n const cleanedLine = cleanLastNewline(line);\n currentFile.additionLines[lastIndex] = cleanedLine;\n currentFile.additionCharacterCount +=\n cleanedLine.length - line.length;\n }\n }\n if (\n isPartial &&\n (lastLineType === 'deletion' || lastLineType === 'context')\n ) {\n const lastIndex = currentFile.deletionLines.length - 1;\n if (lastIndex >= 0) {\n const line = currentFile.deletionLines[lastIndex];\n const cleanedLine = cleanLastNewline(line);\n currentFile.deletionLines[lastIndex] = cleanedLine;\n currentFile.deletionCharacterCount +=\n cleanedLine.length - line.length;\n }\n }\n }\n }\n\n if (\n parsedAdditionLines !== hunkData.additionCount ||\n parsedDeletionLines !== hunkData.deletionCount\n ) {\n if (throwOnError) {\n throw Error('parsePatchContent: hunk line count mismatch');\n }\n console.error(\n `parsePatchContent: hunk line count mismatch: \"${firstLine.trimEnd()}\", declared old/new ${hunkData.deletionCount}/${hunkData.additionCount}, parsed old/new ${parsedDeletionLines}/${parsedAdditionLines}`\n );\n // Re-encode each original boundary using the repaired count. Zero-count\n // ranges use the boundary itself as their start; positive ranges use +1.\n const repairedAdditionStart =\n getHunkSideStartBoundary(\n hunkData.additionStart,\n hunkData.additionCount\n ) + (parsedAdditionLines === 0 ? 0 : 1);\n const repairedDeletionStart =\n getHunkSideStartBoundary(\n hunkData.deletionStart,\n hunkData.deletionCount\n ) + (parsedDeletionLines === 0 ? 0 : 1);\n\n // Hydrated hunks index into full-file line arrays, so their indexes must\n // move with repaired starts. Partial hunks index patch-built arrays.\n if (!isPartial) {\n const additionStartDelta =\n repairedAdditionStart - hunkData.additionStart;\n const deletionStartDelta =\n repairedDeletionStart - hunkData.deletionStart;\n hunkData.additionLineIndex += additionStartDelta;\n hunkData.deletionLineIndex += deletionStartDelta;\n for (const content of hunkData.hunkContent) {\n content.additionLineIndex += additionStartDelta;\n content.deletionLineIndex += deletionStartDelta;\n }\n }\n\n hunkData.additionStart = repairedAdditionStart;\n hunkData.deletionStart = repairedDeletionStart;\n hunkData.additionCount = parsedAdditionLines;\n hunkData.deletionCount = parsedDeletionLines;\n }\n\n hunkData.additionLines = additionLines;\n hunkData.deletionLines = deletionLines;\n\n hunkData.collapsedBefore = Math.max(\n getHunkSideStartBoundary(hunkData.additionStart, hunkData.additionCount) -\n lastHunkEnd,\n 0\n );\n currentFile.hunks.push(hunkData);\n lastHunkEnd = getHunkSideEndBoundary(\n hunkData.additionStart,\n hunkData.additionCount\n );\n for (const content of hunkData.hunkContent) {\n if (content.type === 'context') {\n hunkData.splitLineCount += content.lines;\n hunkData.unifiedLineCount += content.lines;\n } else {\n hunkData.splitLineCount += Math.max(\n content.additions,\n content.deletions\n );\n hunkData.unifiedLineCount += content.deletions + content.additions;\n }\n }\n hunkData.splitLineStart =\n currentFile.splitLineCount + hunkData.collapsedBefore;\n hunkData.unifiedLineStart =\n currentFile.unifiedLineCount + hunkData.collapsedBefore;\n\n currentFile.splitLineCount +=\n hunkData.collapsedBefore + hunkData.splitLineCount;\n currentFile.unifiedLineCount +=\n hunkData.collapsedBefore + hunkData.unifiedLineCount;\n }\n if (currentFile == null) {\n return undefined;\n }\n if (\n throwOnError &&\n isPartial &&\n !isGitDiff &&\n currentFile.hunks.length === 0\n ) {\n throw Error('parsePatchContent: unified file has no hunks');\n }\n\n // Account for collapsed lines after the final hunk and increment the\n // split/unified counts properly\n if (\n currentFile.hunks.length > 0 &&\n !isPartial &&\n currentFile.additionLines.length > 0 &&\n currentFile.deletionLines.length > 0\n ) {\n const lastHunk = currentFile.hunks[currentFile.hunks.length - 1];\n const lastHunkEnd = getHunkSideEndBoundary(\n lastHunk.additionStart,\n lastHunk.additionCount\n );\n const totalFileLines = currentFile.additionLines.length;\n const collapsedAfter = Math.max(totalFileLines - lastHunkEnd, 0);\n currentFile.splitLineCount += collapsedAfter;\n currentFile.unifiedLineCount += collapsedAfter;\n }\n\n // If this isn't a git diff style patch, then we'll need to sus out some\n // additional metadata manually\n if (!isGitDiff) {\n if (\n currentFile.prevName != null &&\n currentFile.name !== currentFile.prevName\n ) {\n if (currentFile.hunks.length > 0) {\n currentFile.type = 'rename-changed';\n } else {\n currentFile.type = 'rename-pure';\n }\n }\n // Sort of a hack for detecting deleted/added files...\n else if (\n (oldFile == null || oldFile.contents === '') &&\n newFile != null &&\n newFile.contents !== ''\n ) {\n currentFile.type = 'new';\n } else if (\n oldFile != null &&\n oldFile.contents !== '' &&\n (newFile == null || newFile.contents === '')\n ) {\n currentFile.type = 'deleted';\n }\n }\n if (\n currentFile.type !== 'rename-pure' &&\n currentFile.type !== 'rename-changed'\n ) {\n currentFile.prevName = undefined;\n }\n // Pair change-block lines by similarity instead of the patch's positional\n // ordering. Partial diffs work too: their hunk line indexes point into the\n // patch-built line arrays, which hold every line a block references.\n realignChangeContentBySimilarity(currentFile);\n return currentFile;\n}\n\n/**\n * Parses a patch file string into an array of parsed patches.\n *\n * @param data - The raw patch file content (supports multi-commit patches)\n * @param cacheKeyPrefix - Optional prefix for collision-safe cache keys derived\n * from the prefix, patch index, and file index. This enables caching of\n * rendered diff results in the worker pool.\n * @param throwOnError - When true, invalid data throws. When false, invalid data\n * is reported with `console.error` and the parser attempts to recover when\n * possible. Recovery is best-effort and does not guarantee valid output.\n */\nexport function parsePatchFiles(\n data: string,\n cacheKeyPrefix?: string,\n throwOnError = false\n): ParsedPatch[] {\n // NOTE(amadeus): This function is pretty forgiving in that it can accept a\n // patch file that includes commit metdata, multiple commits, or not\n const patches: ParsedPatch[] = [];\n const rawPatches = hasCommitMetadataBoundary(data)\n ? data.split(COMMIT_METADATA_SPLIT)\n : [data];\n for (const patch of rawPatches) {\n try {\n patches.push(\n _processPatch(\n patch,\n cacheKeyPrefix,\n throwOnError,\n cacheKeyPrefix != null ? patches.length : undefined\n )\n );\n } catch (error) {\n if (throwOnError) {\n throw error;\n } else {\n console.error(error);\n }\n } finally {\n releaseStringDetachBuffer();\n }\n }\n return patches;\n}\n\n// Decode only quoted tokens, preserving whitespace inside them. Git's a/ and\n// b/ prefixes are part of the quoted token and must be removed after decoding.\nfunction decodeDiffFileName(value: string, stripGitPrefix = false): string {\n const rawName = value.trim();\n const name = rawName.startsWith('\"')\n ? (parseQuotedDiffFileName(rawName)?.fileName ?? rawName)\n : rawName;\n return stripGitPrefix && (name.startsWith('a/') || name.startsWith('b/'))\n ? name.slice(2)\n : name;\n}\n\nfunction hasCommitMetadataBoundary(data: string): boolean {\n return data.startsWith('From ') || data.includes('\\nFrom ');\n}\n\nfunction splitFileContents(contents: string): string[] {\n const lines = splitWithNewlines(contents);\n for (let index = 0; index < lines.length; index++) {\n lines[index] = detachString(lines[index]);\n }\n return lines;\n}\n\nfunction splitWithNewlines(contents: string): string[] {\n if (contents.length === 0) {\n return [''];\n }\n\n const lines: string[] = [];\n let startIndex = 0;\n for (;;) {\n const newlineIndex = contents.indexOf('\\n', startIndex);\n if (newlineIndex === -1) {\n break;\n }\n\n lines.push(contents.slice(startIndex, newlineIndex + 1));\n startIndex = newlineIndex + 1;\n }\n\n if (startIndex < contents.length) {\n lines.push(contents.slice(startIndex));\n }\n return lines;\n}\n\nfunction splitGitDiffFiles(contents: string): string[] {\n return splitAtLinePrefix(contents, 'diff --git');\n}\n\nfunction splitUnifiedDiffFiles(contents: string): string[] {\n if (contents.length === 0) {\n return [''];\n }\n\n const parts: string[] = [];\n let partStartIndex = 0;\n let lineStartIndex = 0;\n let remainingDeletionLines = 0;\n let remainingAdditionLines = 0;\n let hasOpenedUnifiedFile = false;\n\n while (lineStartIndex < contents.length) {\n const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);\n if (remainingDeletionLines <= 0 && remainingAdditionLines <= 0) {\n if (isUnifiedDiffFileHeaderAt(contents, lineStartIndex)) {\n if (lineStartIndex > partStartIndex) {\n parts.push(contents.slice(partStartIndex, lineStartIndex));\n }\n partStartIndex = lineStartIndex;\n hasOpenedUnifiedFile = true;\n lineStartIndex = getNextLineStartIndex(contents, nextLineStartIndex);\n continue;\n }\n\n if (hasOpenedUnifiedFile && contents.startsWith('@@ -', lineStartIndex)) {\n const fileHeader = parseHunkHeader(\n contents.slice(lineStartIndex, nextLineStartIndex)\n );\n if (fileHeader != null) {\n remainingDeletionLines = fileHeader.deletionCount;\n remainingAdditionLines = fileHeader.additionCount;\n }\n }\n lineStartIndex = nextLineStartIndex;\n continue;\n }\n\n const firstChar = contents[lineStartIndex];\n if (firstChar === '\\\\') {\n lineStartIndex = nextLineStartIndex;\n continue;\n }\n\n if (firstChar === ' ') {\n remainingDeletionLines = Math.max(remainingDeletionLines - 1, 0);\n remainingAdditionLines = Math.max(remainingAdditionLines - 1, 0);\n } else if (firstChar === '-') {\n remainingDeletionLines = Math.max(remainingDeletionLines - 1, 0);\n } else if (firstChar === '+') {\n remainingAdditionLines = Math.max(remainingAdditionLines - 1, 0);\n }\n lineStartIndex = nextLineStartIndex;\n }\n\n parts.push(contents.slice(partStartIndex));\n return parts;\n}\n\nfunction startsWithUnifiedDiffFileHeader(contents: string): boolean {\n return isUnifiedDiffFileHeaderAt(contents, 0);\n}\n\nfunction isUnifiedDiffFileHeaderAt(contents: string, lineStartIndex: number) {\n const nextLineStartIndex = getNextLineStartIndex(contents, lineStartIndex);\n return (\n isUnifiedDiffHeaderLineAt(contents, lineStartIndex, '---') &&\n isUnifiedDiffHeaderLineAt(contents, nextLineStartIndex, '+++')\n );\n}\n\nfunction isUnifiedDiffHeaderLineAt(\n contents: string,\n lineStartIndex: number,\n prefix: '---' | '+++'\n): boolean {\n if (!contents.startsWith(prefix, lineStartIndex)) {\n return false;\n }\n\n const separator = contents[lineStartIndex + prefix.length];\n if (separator !== ' ' && separator !== '\\t') {\n return false;\n }\n\n for (\n let index = lineStartIndex + prefix.length + 1;\n index < contents.length;\n index++\n ) {\n const char = contents[index];\n if (char === '\\n' || char === '\\r') {\n break;\n }\n if (char !== ' ' && char !== '\\t') {\n return true;\n }\n }\n return false;\n}\n\nfunction getNextLineStartIndex(\n contents: string,\n lineStartIndex: number\n): number {\n const newlineIndex = contents.indexOf('\\n', lineStartIndex);\n return newlineIndex === -1 ? contents.length : newlineIndex + 1;\n}\n\nfunction isHunkBodyLine(line: string): boolean {\n const firstChar = line[0];\n return firstChar === '+' || firstChar === '-' || firstChar === ' ';\n}\n\nfunction isFormatPatchVersionSeparator(line: string): boolean {\n if (!line.startsWith('--')) {\n return false;\n }\n\n for (let index = 2; index < line.length; index++) {\n const char = line[index];\n if (char !== ' ' && char !== '\\t' && char !== '\\n' && char !== '\\r') {\n return false;\n }\n }\n return true;\n}\n\nfunction parseHunkHeader(line: string): ParsedHunkHeader | undefined {\n if (!line.startsWith('@@ -')) {\n return undefined;\n }\n\n let index = 4;\n const deletionStartResult = readPositiveInteger(line, index);\n if (deletionStartResult == null) {\n return undefined;\n }\n const deletionStart = deletionStartResult.value;\n index = deletionStartResult.endIndex;\n\n let deletionCount = 1;\n if (line[index] === ',') {\n const deletionCountResult = readPositiveInteger(line, index + 1);\n if (deletionCountResult == null) {\n return undefined;\n }\n deletionCount = deletionCountResult.value;\n index = deletionCountResult.endIndex;\n }\n\n if (line[index] !== ' ' || line[index + 1] !== '+') {\n return undefined;\n }\n index += 2;\n\n const additionStartResult = readPositiveInteger(line, index);\n if (additionStartResult == null) {\n return undefined;\n }\n const additionStart = additionStartResult.value;\n index = additionStartResult.endIndex;\n\n let additionCount = 1;\n if (line[index] === ',') {\n const additionCountResult = readPositiveInteger(line, index + 1);\n if (additionCountResult == null) {\n return undefined;\n }\n additionCount = additionCountResult.value;\n index = additionCountResult.endIndex;\n }\n\n if (\n line[index] !== ' ' ||\n line[index + 1] !== '@' ||\n line[index + 2] !== '@'\n ) {\n return undefined;\n }\n\n let hunkContext: string | undefined;\n const contextStartIndex = index + 3;\n if (line[contextStartIndex] === ' ') {\n hunkContext = trimLineEnd(line.slice(contextStartIndex + 1));\n }\n\n return {\n additionCount,\n additionStart,\n deletionCount,\n deletionStart,\n hunkContext,\n };\n}\n\nfunction readPositiveInteger(\n value: string,\n startIndex: number\n): { value: number; endIndex: number } | undefined {\n let index = startIndex;\n let parsedValue = 0;\n for (; index < value.length; index++) {\n const digit = value.charCodeAt(index) - 48;\n if (digit < 0 || digit > 9) {\n break;\n }\n parsedValue = parsedValue * 10 + digit;\n }\n\n if (index === startIndex) {\n return undefined;\n }\n return { value: parsedValue, endIndex: index };\n}\n\nfunction trimLineEnd(value: string): string {\n if (value.endsWith('\\r\\n')) {\n return value.slice(0, -2);\n }\n if (value.endsWith('\\n')) {\n return value.slice(0, -1);\n }\n return value;\n}\n\nfunction isGitDiffPatch(data: string): boolean {\n return data.startsWith('diff --git') || data.includes('\\ndiff --git');\n}\n\nfunction splitAtLinePrefix(contents: string, prefix: string): string[] {\n if (contents.length === 0) {\n return [''];\n }\n\n const newlinePrefix = `\\n${prefix}`;\n const firstBoundaryIndex = contents.startsWith(prefix)\n ? 0\n : findLinePrefixIndex(contents, newlinePrefix, 0);\n if (firstBoundaryIndex === -1) {\n return [contents];\n }\n\n const parts: string[] = [];\n if (firstBoundaryIndex > 0) {\n parts.push(contents.slice(0, firstBoundaryIndex));\n }\n\n let startIndex = firstBoundaryIndex;\n for (;;) {\n const nextBoundaryIndex = findLinePrefixIndex(\n contents,\n newlinePrefix,\n startIndex + 1\n );\n if (nextBoundaryIndex === -1) {\n break;\n }\n\n parts.push(contents.slice(startIndex, nextBoundaryIndex));\n startIndex = nextBoundaryIndex;\n }\n parts.push(contents.slice(startIndex));\n return parts;\n}\n\nfunction findLinePrefixIndex(\n contents: string,\n newlinePrefix: string,\n fromIndex: number\n): number {\n const index = contents.indexOf(newlinePrefix, fromIndex);\n return index === -1 ? -1 : index + 1;\n}\n\nfunction maybeDetachOptionalString<T extends string | undefined>(value: T): T {\n return (value == null ? value : detachString(value)) as T;\n}\n\nfunction parseRawLineType(\n firstChar: string | undefined\n): Exclude<HunkLineType, 'expanded'> {\n return firstChar === ' '\n ? 'context'\n : firstChar === '\\\\'\n ? 'metadata'\n : firstChar === '+'\n ? 'addition'\n : 'deletion';\n}\n\nfunction getParsedLineContent(rawLine: string): string {\n const processedLine = rawLine.slice(1);\n return detachString(processedLine === '' ? '\\n' : processedLine);\n}\n\nfunction createContentGroup(\n type: 'change',\n deletionLineIndex: number,\n additionLineIndex: number\n): ChangeContent;\nfunction createContentGroup(\n type: 'context',\n deletionLineIndex: number,\n additionLineIndex: number\n): ContextContent;\nfunction createContentGroup(\n type: 'change' | 'context',\n deletionLineIndex: number,\n additionLineIndex: number\n): ChangeContent | ContextContent {\n if (type === 'change') {\n return {\n type: 'change',\n additions: 0,\n deletions: 0,\n additionLineIndex,\n deletionLineIndex,\n };\n }\n return {\n type: 'context',\n lines: 0,\n additionLineIndex,\n deletionLineIndex,\n };\n}\n"],"mappings":"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"}
@@ -9,9 +9,14 @@ interface RenderTokenLinesOptions {
9
9
  useTokenTransformer?: boolean;
10
10
  mergeWhitespaces?: 'never' | 'always';
11
11
  decorations?: DecorationItem[];
12
+ /** UTF-16 line start offsets, required for numeric decoration positions. */
12
13
  lineOffsets?: number[];
13
14
  }
15
+ /**
16
+ * Converts highlighted tokens to one HAST element per line for custom renderers.
17
+ * Callers provide any line separators and enclosing pre/code elements.
18
+ */
14
19
  declare function renderTokenLines(lines: ThemedToken[][], { state, lazyLineAST, cacheHtmlStyles, useTokenTransformer, mergeWhitespaces, decorations, lineOffsets }: RenderTokenLinesOptions): ElementContent[];
15
20
  //#endregion
16
- export { renderTokenLines };
21
+ export { RenderTokenLinesOptions, renderTokenLines };
17
22
  //# sourceMappingURL=renderTokenLines.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderTokenLines.d.ts","names":[],"sources":["../../src/utils/renderTokenLines.ts"],"mappings":";;;;UAQU;EACR;EACA;EACA,QAAQ;EACR;EACA;EACA,cAAc;EACd;;iBAsBc,iBACd,OAAO,mBAEL,OACA,aACA,iBACA,qBACA,kBACA,aACA,eACC,0BACF"}
1
+ {"version":3,"file":"renderTokenLines.d.ts","names":[],"sources":["../../src/utils/renderTokenLines.ts"],"mappings":";;;;UAQiB;EACf;EACA;EACA,QAAQ;EACR;EACA;EACA,cAAc;;EAEd;;;;;;iBA0Bc,iBACd,OAAO,mBAEL,OACA,aACA,iBACA,qBACA,kBACA,aACA,eACC,0BACF"}
@@ -3,6 +3,10 @@ import { setDeferredArrayItem } from "./setDeferredArrayItem.js";
3
3
  import { tokenStyle } from "./tokenStyle.js";
4
4
  import { wrapTokenFragments } from "./wrapTokenFragments.js";
5
5
  //#region src/utils/renderTokenLines.ts
6
+ /**
7
+ * Converts highlighted tokens to one HAST element per line for custom renderers.
8
+ * Callers provide any line separators and enclosing pre/code elements.
9
+ */
6
10
  function renderTokenLines(lines, { state, lazyLineAST = false, cacheHtmlStyles = false, useTokenTransformer = false, mergeWhitespaces = "always", decorations = [], lineOffsets = [] }) {
7
11
  let decorationsByLine;
8
12
  for (const decoration of decorations) {
@@ -1 +1 @@
1
- {"version":3,"file":"renderTokenLines.js","names":[],"sources":["../../src/utils/renderTokenLines.ts"],"sourcesContent":["import type { Element, ElementContent, Properties } from 'hast';\n\nimport type { DecorationItem, SharedRenderState, ThemedToken } from '../types';\nimport { processLine } from './processLine';\nimport { setDeferredArrayItem } from './setDeferredArrayItem';\nimport { tokenStyle } from './tokenStyle';\nimport { wrapTokenFragments } from './wrapTokenFragments';\n\ninterface RenderTokenLinesOptions {\n lazyLineAST?: boolean;\n cacheHtmlStyles?: boolean;\n state?: SharedRenderState;\n useTokenTransformer?: boolean;\n mergeWhitespaces?: 'never' | 'always';\n decorations?: DecorationItem[];\n lineOffsets?: number[];\n}\n\ninterface LineDecoration extends Omit<DecorationItem, 'start' | 'end'> {\n start: { line: number; character: number };\n end: { line: number; character: number };\n}\n\n// from/to are columns within this line; order preserves outer-to-inner nesting.\ninterface LineDecorationRange {\n decoration: LineDecoration;\n order: number;\n from: number;\n to: number;\n}\n\ninterface DecorationBoundary {\n position: number;\n range: LineDecorationRange;\n start: boolean;\n}\n\nexport function renderTokenLines(\n lines: ThemedToken[][],\n {\n state,\n lazyLineAST = false,\n cacheHtmlStyles = false,\n useTokenTransformer = false,\n mergeWhitespaces = 'always',\n decorations = [],\n lineOffsets = [],\n }: RenderTokenLinesOptions\n): ElementContent[] {\n let decorationsByLine: Map<number, LineDecoration[]> | undefined;\n for (const decoration of decorations) {\n const byLine = (decorationsByLine ??= new Map());\n const normalized: LineDecoration = {\n ...decoration,\n start: getDecorationPosition(decoration.start, lineOffsets),\n end: getDecorationPosition(decoration.end, lineOffsets),\n };\n const lastLine = Math.min(normalized.end.line, lines.length - 1);\n for (let line = normalized.start.line; line <= lastLine; line++) {\n let spans = byLine.get(line);\n if (spans == null) byLine.set(line, (spans = []));\n spans.push(normalized);\n }\n }\n const renderLine = (tokens: ThemedToken[], lineIndex: number) => {\n let normalized: ThemedToken[] | undefined;\n if (useTokenTransformer || mergeWhitespaces !== 'never') {\n let pendingWhitespace = '';\n let whitespaceOffset = 0;\n for (let i = 0; i < tokens.length; i++) {\n let token = tokens[i];\n if (useTokenTransformer) {\n const content = token.content.trim();\n if (content !== '' && content !== token.content) {\n normalized ??= tokens.slice(0, i);\n const start = token.content.indexOf(content);\n if (start > 0)\n normalized.push({\n content: token.content.slice(0, start),\n offset: token.offset,\n });\n normalized.push({\n ...token,\n content,\n offset: token.offset + start,\n });\n const end = start + content.length;\n if (end < token.content.length)\n normalized.push({\n content: token.content.slice(end),\n offset: token.offset + end,\n });\n continue;\n }\n } else {\n const decoratedWhitespace = ((token.fontStyle ?? 0) & 12) !== 0;\n if (\n !decoratedWhitespace &&\n /^\\s+$/.test(token.content) &&\n i < tokens.length - 1\n ) {\n normalized ??= tokens.slice(0, i);\n if (pendingWhitespace === '') whitespaceOffset = token.offset;\n pendingWhitespace += token.content;\n continue;\n }\n if (pendingWhitespace !== '' && normalized != null) {\n if (decoratedWhitespace)\n normalized.push({\n content: pendingWhitespace,\n offset: whitespaceOffset,\n });\n else\n token = {\n ...token,\n content: pendingWhitespace + token.content,\n offset: whitespaceOffset,\n };\n pendingWhitespace = '';\n }\n }\n normalized?.push(token);\n }\n }\n normalized ??= tokens;\n const line: Element = {\n type: 'element',\n tagName: state == null ? 'span' : 'div',\n properties: state == null ? { class: 'line' } : {},\n children: [],\n };\n const spans = decorationsByLine?.get(lineIndex);\n const column =\n spans == null\n ? appendTokens(line, normalized, useTokenTransformer, cacheHtmlStyles)\n : appendDecoratedTokens(\n line,\n normalized,\n spans,\n lineIndex,\n useTokenTransformer,\n cacheHtmlStyles\n );\n if (useTokenTransformer && column === 0) {\n line.children.push({\n type: 'element',\n tagName: 'br',\n properties: {},\n children: [],\n });\n }\n // Undecorated tokens already have one span per editor position.\n if (useTokenTransformer && spans != null) wrapTokenFragments(line);\n return state == null ? line : processLine(line, lineIndex + 1, state);\n };\n if (!lazyLineAST) return lines.map(renderLine);\n const rows: ElementContent[] = new Array(lines.length);\n for (let index = 0; index < lines.length; index++) {\n // Warning: capture one line, not `lines`; unbuilt rows would keep every\n // line's tokens alive.\n const tokens = lines[index];\n setDeferredArrayItem(rows, index, () => renderLine(tokens, index));\n }\n return rows;\n}\n\n// Returns the line length in UTF-16 code units.\nfunction appendTokens(\n line: Element,\n tokens: ThemedToken[],\n useTokenTransformer: boolean,\n cacheHtmlStyles: boolean\n): number {\n let column = 0;\n for (const token of tokens) {\n if (token.content === '') continue;\n line.children.push(\n createTokenSpan(\n token,\n tokenStyle(token, cacheHtmlStyles),\n token.content,\n column,\n useTokenTransformer\n )\n );\n column += token.content.length;\n }\n return column;\n}\n\n// Visit sorted boundaries once to avoid scanning every decoration per token.\n// Emit empty ranges before text at the same position.\nfunction appendDecoratedTokens(\n line: Element,\n tokens: ThemedToken[],\n spans: LineDecoration[],\n lineIndex: number,\n useTokenTransformer: boolean,\n cacheHtmlStyles: boolean\n): number {\n // Open outer ranges first, regardless of their order in the input.\n if (spans.length > 1)\n spans.sort((a, b) => {\n if (a.start.line !== b.start.line) return a.start.line - b.start.line;\n if (a.start.character !== b.start.character)\n return a.start.character - b.start.character;\n if (a.end.line !== b.end.line) return b.end.line - a.end.line;\n return b.end.character - a.end.character;\n });\n const lineLength = tokens.reduce(\n (length, token) => length + token.content.length,\n 0\n );\n const boundaries: DecorationBoundary[] = [];\n for (let order = 0; order < spans.length; order++) {\n const decoration = spans[order];\n const range: LineDecorationRange = {\n decoration,\n order,\n from:\n decoration.start.line === lineIndex ? decoration.start.character : 0,\n to:\n decoration.end.line === lineIndex\n ? decoration.end.character\n : lineLength,\n };\n boundaries.push(\n {\n position: Math.max(0, Math.min(range.from, lineLength)),\n range,\n start: true,\n },\n {\n position: Math.max(0, Math.min(range.to, lineLength)),\n range,\n start: false,\n }\n );\n }\n boundaries.sort((a, b) => a.position - b.position);\n const active: LineDecorationRange[] = [];\n const decorationStack: { range: LineDecorationRange; node: Element }[] = [];\n let boundaryIndex = 0;\n\n // Keep the same outer-to-inner order even when decorations cross each other.\n const updateActive = (range: LineDecorationRange, add: boolean): void => {\n let low = 0;\n let high = active.length;\n while (low < high) {\n const middle = (low + high) >>> 1;\n if (active[middle].order < range.order) low = middle + 1;\n else high = middle;\n }\n if (add) active.splice(low, 0, range);\n else if (active[low] === range) active.splice(low, 1);\n };\n\n // Reuse wrappers across tokens so a continuous range stays in one element.\n const getParent = (): Element => {\n let parent = line;\n let depth = 0;\n for (const range of active) {\n if (decorationStack[depth]?.range !== range) {\n decorationStack.length = depth;\n const wrapper: Element = {\n type: 'element',\n tagName: 'span',\n properties: { ...range.decoration.properties },\n children: [],\n };\n parent.children.push(wrapper);\n decorationStack.push({ range, node: wrapper });\n }\n parent = decorationStack[depth++].node;\n }\n decorationStack.length = depth;\n return parent;\n };\n\n let parent = line;\n\n // Markers belong inside ranges starting here, except at the line end,\n // where they belong inside ranges ending here.\n const advanceBoundary = (position: number): void => {\n const first = boundaryIndex;\n while (boundaries[boundaryIndex]?.position === position) boundaryIndex++;\n let hasMarker = false;\n for (let i = first; i < boundaryIndex; i++) {\n const { range, start } = boundaries[i];\n if (!start && range.from !== range.to && position < lineLength)\n updateActive(range, false);\n }\n for (let i = first; i < boundaryIndex; i++) {\n const { range, start } = boundaries[i];\n if (\n start &&\n range.from <= position &&\n range.to >= position &&\n (range.to > position ||\n range.from === position ||\n position === lineLength)\n ) {\n updateActive(range, true);\n if (range.from === range.to) hasMarker = true;\n }\n }\n if (hasMarker) {\n getParent();\n for (let i = first; i < boundaryIndex; i++) {\n const { range, start } = boundaries[i];\n if (start && range.from === range.to) updateActive(range, false);\n }\n }\n if (position < lineLength) parent = getParent();\n };\n\n let column = 0;\n for (const token of tokens) {\n if (token.content === '') continue;\n const start = column;\n const end = start + token.content.length;\n const style = tokenStyle(token, cacheHtmlStyles);\n while (column < end) {\n if (boundaries[boundaryIndex]?.position === column)\n advanceBoundary(column);\n const to = Math.min(end, boundaries[boundaryIndex]?.position ?? end);\n parent.children.push(\n createTokenSpan(\n token,\n style,\n column === start && to === end\n ? token.content\n : token.content.slice(column - start, to - start),\n start,\n useTokenTransformer\n )\n );\n column = to;\n }\n }\n if (boundaries[boundaryIndex]?.position === column) advanceBoundary(column);\n return column;\n}\n\n// data-char must retain the original token column when decorations split it.\nfunction createTokenSpan(\n token: ThemedToken,\n style: string,\n text: string,\n start: number,\n useTokenTransformer: boolean\n): Element {\n const properties: Properties =\n token.htmlAttrs != null ? { ...token.htmlAttrs } : {};\n if (style !== '') properties.style = style;\n if (useTokenTransformer) properties['data-char'] = start;\n return {\n type: 'element',\n tagName: 'span',\n properties,\n children: [{ type: 'text', value: text }],\n };\n}\n\n// Convert absolute UTF-16 offsets to the line coordinates used by decorations.\nfunction getDecorationPosition(\n position: DecorationItem['start'],\n lineOffsets: number[]\n): { line: number; character: number } {\n if (typeof position !== 'number') return position;\n let low = 0;\n let high = lineOffsets.length;\n while (low + 1 < high) {\n const middle = (low + high) >>> 1;\n if (lineOffsets[middle] <= position) low = middle;\n else high = middle;\n }\n return { line: low, character: position - (lineOffsets[low] ?? 0) };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"renderTokenLines.js","names":[],"sources":["../../src/utils/renderTokenLines.ts"],"sourcesContent":["import type { Element, ElementContent, Properties } from 'hast';\n\nimport type { DecorationItem, SharedRenderState, ThemedToken } from '../types';\nimport { processLine } from './processLine';\nimport { setDeferredArrayItem } from './setDeferredArrayItem';\nimport { tokenStyle } from './tokenStyle';\nimport { wrapTokenFragments } from './wrapTokenFragments';\n\nexport interface RenderTokenLinesOptions {\n lazyLineAST?: boolean;\n cacheHtmlStyles?: boolean;\n state?: SharedRenderState;\n useTokenTransformer?: boolean;\n mergeWhitespaces?: 'never' | 'always';\n decorations?: DecorationItem[];\n /** UTF-16 line start offsets, required for numeric decoration positions. */\n lineOffsets?: number[];\n}\n\ninterface LineDecoration extends Omit<DecorationItem, 'start' | 'end'> {\n start: { line: number; character: number };\n end: { line: number; character: number };\n}\n\n// from/to are columns within this line; order preserves outer-to-inner nesting.\ninterface LineDecorationRange {\n decoration: LineDecoration;\n order: number;\n from: number;\n to: number;\n}\n\ninterface DecorationBoundary {\n position: number;\n range: LineDecorationRange;\n start: boolean;\n}\n\n/**\n * Converts highlighted tokens to one HAST element per line for custom renderers.\n * Callers provide any line separators and enclosing pre/code elements.\n */\nexport function renderTokenLines(\n lines: ThemedToken[][],\n {\n state,\n lazyLineAST = false,\n cacheHtmlStyles = false,\n useTokenTransformer = false,\n mergeWhitespaces = 'always',\n decorations = [],\n lineOffsets = [],\n }: RenderTokenLinesOptions\n): ElementContent[] {\n let decorationsByLine: Map<number, LineDecoration[]> | undefined;\n for (const decoration of decorations) {\n const byLine = (decorationsByLine ??= new Map());\n const normalized: LineDecoration = {\n ...decoration,\n start: getDecorationPosition(decoration.start, lineOffsets),\n end: getDecorationPosition(decoration.end, lineOffsets),\n };\n const lastLine = Math.min(normalized.end.line, lines.length - 1);\n for (let line = normalized.start.line; line <= lastLine; line++) {\n let spans = byLine.get(line);\n if (spans == null) byLine.set(line, (spans = []));\n spans.push(normalized);\n }\n }\n const renderLine = (tokens: ThemedToken[], lineIndex: number) => {\n let normalized: ThemedToken[] | undefined;\n if (useTokenTransformer || mergeWhitespaces !== 'never') {\n let pendingWhitespace = '';\n let whitespaceOffset = 0;\n for (let i = 0; i < tokens.length; i++) {\n let token = tokens[i];\n if (useTokenTransformer) {\n const content = token.content.trim();\n if (content !== '' && content !== token.content) {\n normalized ??= tokens.slice(0, i);\n const start = token.content.indexOf(content);\n if (start > 0)\n normalized.push({\n content: token.content.slice(0, start),\n offset: token.offset,\n });\n normalized.push({\n ...token,\n content,\n offset: token.offset + start,\n });\n const end = start + content.length;\n if (end < token.content.length)\n normalized.push({\n content: token.content.slice(end),\n offset: token.offset + end,\n });\n continue;\n }\n } else {\n const decoratedWhitespace = ((token.fontStyle ?? 0) & 12) !== 0;\n if (\n !decoratedWhitespace &&\n /^\\s+$/.test(token.content) &&\n i < tokens.length - 1\n ) {\n normalized ??= tokens.slice(0, i);\n if (pendingWhitespace === '') whitespaceOffset = token.offset;\n pendingWhitespace += token.content;\n continue;\n }\n if (pendingWhitespace !== '' && normalized != null) {\n if (decoratedWhitespace)\n normalized.push({\n content: pendingWhitespace,\n offset: whitespaceOffset,\n });\n else\n token = {\n ...token,\n content: pendingWhitespace + token.content,\n offset: whitespaceOffset,\n };\n pendingWhitespace = '';\n }\n }\n normalized?.push(token);\n }\n }\n normalized ??= tokens;\n const line: Element = {\n type: 'element',\n tagName: state == null ? 'span' : 'div',\n properties: state == null ? { class: 'line' } : {},\n children: [],\n };\n const spans = decorationsByLine?.get(lineIndex);\n const column =\n spans == null\n ? appendTokens(line, normalized, useTokenTransformer, cacheHtmlStyles)\n : appendDecoratedTokens(\n line,\n normalized,\n spans,\n lineIndex,\n useTokenTransformer,\n cacheHtmlStyles\n );\n if (useTokenTransformer && column === 0) {\n line.children.push({\n type: 'element',\n tagName: 'br',\n properties: {},\n children: [],\n });\n }\n // Undecorated tokens already have one span per editor position.\n if (useTokenTransformer && spans != null) wrapTokenFragments(line);\n return state == null ? line : processLine(line, lineIndex + 1, state);\n };\n if (!lazyLineAST) return lines.map(renderLine);\n const rows: ElementContent[] = new Array(lines.length);\n for (let index = 0; index < lines.length; index++) {\n // Warning: capture one line, not `lines`; unbuilt rows would keep every\n // line's tokens alive.\n const tokens = lines[index];\n setDeferredArrayItem(rows, index, () => renderLine(tokens, index));\n }\n return rows;\n}\n\n// Returns the line length in UTF-16 code units.\nfunction appendTokens(\n line: Element,\n tokens: ThemedToken[],\n useTokenTransformer: boolean,\n cacheHtmlStyles: boolean\n): number {\n let column = 0;\n for (const token of tokens) {\n if (token.content === '') continue;\n line.children.push(\n createTokenSpan(\n token,\n tokenStyle(token, cacheHtmlStyles),\n token.content,\n column,\n useTokenTransformer\n )\n );\n column += token.content.length;\n }\n return column;\n}\n\n// Visit sorted boundaries once to avoid scanning every decoration per token.\n// Emit empty ranges before text at the same position.\nfunction appendDecoratedTokens(\n line: Element,\n tokens: ThemedToken[],\n spans: LineDecoration[],\n lineIndex: number,\n useTokenTransformer: boolean,\n cacheHtmlStyles: boolean\n): number {\n // Open outer ranges first, regardless of their order in the input.\n if (spans.length > 1)\n spans.sort((a, b) => {\n if (a.start.line !== b.start.line) return a.start.line - b.start.line;\n if (a.start.character !== b.start.character)\n return a.start.character - b.start.character;\n if (a.end.line !== b.end.line) return b.end.line - a.end.line;\n return b.end.character - a.end.character;\n });\n const lineLength = tokens.reduce(\n (length, token) => length + token.content.length,\n 0\n );\n const boundaries: DecorationBoundary[] = [];\n for (let order = 0; order < spans.length; order++) {\n const decoration = spans[order];\n const range: LineDecorationRange = {\n decoration,\n order,\n from:\n decoration.start.line === lineIndex ? decoration.start.character : 0,\n to:\n decoration.end.line === lineIndex\n ? decoration.end.character\n : lineLength,\n };\n boundaries.push(\n {\n position: Math.max(0, Math.min(range.from, lineLength)),\n range,\n start: true,\n },\n {\n position: Math.max(0, Math.min(range.to, lineLength)),\n range,\n start: false,\n }\n );\n }\n boundaries.sort((a, b) => a.position - b.position);\n const active: LineDecorationRange[] = [];\n const decorationStack: { range: LineDecorationRange; node: Element }[] = [];\n let boundaryIndex = 0;\n\n // Keep the same outer-to-inner order even when decorations cross each other.\n const updateActive = (range: LineDecorationRange, add: boolean): void => {\n let low = 0;\n let high = active.length;\n while (low < high) {\n const middle = (low + high) >>> 1;\n if (active[middle].order < range.order) low = middle + 1;\n else high = middle;\n }\n if (add) active.splice(low, 0, range);\n else if (active[low] === range) active.splice(low, 1);\n };\n\n // Reuse wrappers across tokens so a continuous range stays in one element.\n const getParent = (): Element => {\n let parent = line;\n let depth = 0;\n for (const range of active) {\n if (decorationStack[depth]?.range !== range) {\n decorationStack.length = depth;\n const wrapper: Element = {\n type: 'element',\n tagName: 'span',\n properties: { ...range.decoration.properties },\n children: [],\n };\n parent.children.push(wrapper);\n decorationStack.push({ range, node: wrapper });\n }\n parent = decorationStack[depth++].node;\n }\n decorationStack.length = depth;\n return parent;\n };\n\n let parent = line;\n\n // Markers belong inside ranges starting here, except at the line end,\n // where they belong inside ranges ending here.\n const advanceBoundary = (position: number): void => {\n const first = boundaryIndex;\n while (boundaries[boundaryIndex]?.position === position) boundaryIndex++;\n let hasMarker = false;\n for (let i = first; i < boundaryIndex; i++) {\n const { range, start } = boundaries[i];\n if (!start && range.from !== range.to && position < lineLength)\n updateActive(range, false);\n }\n for (let i = first; i < boundaryIndex; i++) {\n const { range, start } = boundaries[i];\n if (\n start &&\n range.from <= position &&\n range.to >= position &&\n (range.to > position ||\n range.from === position ||\n position === lineLength)\n ) {\n updateActive(range, true);\n if (range.from === range.to) hasMarker = true;\n }\n }\n if (hasMarker) {\n getParent();\n for (let i = first; i < boundaryIndex; i++) {\n const { range, start } = boundaries[i];\n if (start && range.from === range.to) updateActive(range, false);\n }\n }\n if (position < lineLength) parent = getParent();\n };\n\n let column = 0;\n for (const token of tokens) {\n if (token.content === '') continue;\n const start = column;\n const end = start + token.content.length;\n const style = tokenStyle(token, cacheHtmlStyles);\n while (column < end) {\n if (boundaries[boundaryIndex]?.position === column)\n advanceBoundary(column);\n const to = Math.min(end, boundaries[boundaryIndex]?.position ?? end);\n parent.children.push(\n createTokenSpan(\n token,\n style,\n column === start && to === end\n ? token.content\n : token.content.slice(column - start, to - start),\n start,\n useTokenTransformer\n )\n );\n column = to;\n }\n }\n if (boundaries[boundaryIndex]?.position === column) advanceBoundary(column);\n return column;\n}\n\n// data-char must retain the original token column when decorations split it.\nfunction createTokenSpan(\n token: ThemedToken,\n style: string,\n text: string,\n start: number,\n useTokenTransformer: boolean\n): Element {\n const properties: Properties =\n token.htmlAttrs != null ? { ...token.htmlAttrs } : {};\n if (style !== '') properties.style = style;\n if (useTokenTransformer) properties['data-char'] = start;\n return {\n type: 'element',\n tagName: 'span',\n properties,\n children: [{ type: 'text', value: text }],\n };\n}\n\n// Convert absolute UTF-16 offsets to the line coordinates used by decorations.\nfunction getDecorationPosition(\n position: DecorationItem['start'],\n lineOffsets: number[]\n): { line: number; character: number } {\n if (typeof position !== 'number') return position;\n let low = 0;\n let high = lineOffsets.length;\n while (low + 1 < high) {\n const middle = (low + high) >>> 1;\n if (lineOffsets[middle] <= position) low = middle;\n else high = middle;\n }\n return { line: low, character: position - (lineOffsets[low] ?? 0) };\n}\n"],"mappings":"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"}
@@ -17,6 +17,8 @@ function resolveRegion(diff, target) {
17
17
  hunks: [],
18
18
  deletionLines: [],
19
19
  additionLines: [],
20
+ deletionCharacterCount: 0,
21
+ additionCharacterCount: 0,
20
22
  splitLineCount: 0,
21
23
  unifiedLineCount: 0,
22
24
  cacheKey: diff.cacheKey != null ? `${diff.cacheKey}:${resolution[0]}-${hunkIndex}:${startContentIndex}-${endContentIndex}` : void 0
@@ -117,8 +119,8 @@ function pushCollapsedContextLines(diff, deletionLines, additionLines, deletionL
117
119
  const deletionLine = deletionLines[deletionLineIndex + index];
118
120
  const additionLine = additionLines[additionLineIndex + index];
119
121
  if (deletionLine == null || additionLine == null) throw new Error("pushCollapsedContextLines: missing collapsed context line");
120
- diff.deletionLines.push(deletionLine);
121
- diff.additionLines.push(additionLine);
122
+ pushDeletionLine(diff, deletionLine);
123
+ pushAdditionLine(diff, additionLine);
122
124
  }
123
125
  }
124
126
  function processCollapsedContext(sourceDiff, resolvedDiff, cursor, deletionLineIndex, additionLineIndex, lineCount, shouldProcessContent) {
@@ -144,8 +146,8 @@ function pushContentLinesToDiff(content, diff, deletionLines, additionLines) {
144
146
  });
145
147
  throw new Error("pushContentLinesToDiff: Context line does not exist");
146
148
  }
147
- diff.deletionLines.push(line);
148
- diff.additionLines.push(line);
149
+ pushDeletionLine(diff, line);
150
+ pushAdditionLine(diff, line);
149
151
  }
150
152
  else {
151
153
  const len = Math.max(content.deletions, content.additions);
@@ -160,7 +162,7 @@ function pushContentLinesToDiff(content, diff, deletionLines, additionLines) {
160
162
  });
161
163
  throw new Error("pushContentLinesToDiff: Deletion line does not exist");
162
164
  }
163
- diff.deletionLines.push(line);
165
+ pushDeletionLine(diff, line);
164
166
  }
165
167
  if (i < content.additions) {
166
168
  const line = additionLines[content.additionLineIndex + i];
@@ -172,7 +174,7 @@ function pushContentLinesToDiff(content, diff, deletionLines, additionLines) {
172
174
  });
173
175
  throw new Error("pushContentLinesToDiff: Addition line does not exist");
174
176
  }
175
- diff.additionLines.push(line);
177
+ pushAdditionLine(diff, line);
176
178
  }
177
179
  }
178
180
  }
@@ -188,8 +190,8 @@ function pushResolveLinesToDiff(resolution, content, diff, deletionLines, additi
188
190
  });
189
191
  throw new Error("pushResolveLinesToDiff: Deletion line does not exist");
190
192
  }
191
- diff.deletionLines.push(line);
192
- diff.additionLines.push(line);
193
+ pushDeletionLine(diff, line);
194
+ pushAdditionLine(diff, line);
193
195
  }
194
196
  if (resolution === "additions" || resolution === "both") for (let i = 0; i < content.additions; i++) {
195
197
  const line = additionLines[content.additionLineIndex + i];
@@ -201,8 +203,8 @@ function pushResolveLinesToDiff(resolution, content, diff, deletionLines, additi
201
203
  });
202
204
  throw new Error("pushResolveLinesToDiff: Addition line does not exist");
203
205
  }
204
- diff.deletionLines.push(line);
205
- diff.additionLines.push(line);
206
+ pushDeletionLine(diff, line);
207
+ pushAdditionLine(diff, line);
206
208
  }
207
209
  }
208
210
  function advanceCursor(content, cursor, hunk) {
@@ -232,6 +234,14 @@ function advanceCursor(content, cursor, hunk) {
232
234
  hunk.unifiedLineCount += content.deletions + content.additions;
233
235
  }
234
236
  }
237
+ function pushDeletionLine(diff, line) {
238
+ diff.deletionLines.push(line);
239
+ diff.deletionCharacterCount += line.length;
240
+ }
241
+ function pushAdditionLine(diff, line) {
242
+ diff.additionLines.push(line);
243
+ diff.additionCharacterCount += line.length;
244
+ }
235
245
  //#endregion
236
246
  export { resolveRegion };
237
247
 
@@ -1 +1 @@
1
- {"version":3,"file":"resolveRegion.js","names":[],"sources":["../../src/utils/resolveRegion.ts"],"sourcesContent":["import type {\n ChangeContent,\n ContextContent,\n FileDiffMetadata,\n Hunk,\n} from '../types';\nimport {\n getHunkSideEndBoundary,\n getHunkSideStartBoundary,\n} from './getHunkSideBoundaries';\n\ninterface RegionResolutionTarget {\n hunkIndex: number;\n startContentIndex: number;\n endContentIndex: number;\n resolution: 'deletions' | 'additions' | 'both';\n indexesToDelete?: Set<number>;\n}\n\ninterface CursorState {\n nextAdditionLineIndex: number;\n nextDeletionLineIndex: number;\n nextAdditionStart: number;\n nextDeletionStart: number;\n splitLineCount: number;\n unifiedLineCount: number;\n}\n\nexport function resolveRegion(\n diff: FileDiffMetadata,\n target: RegionResolutionTarget\n): FileDiffMetadata {\n const {\n resolution,\n hunkIndex,\n startContentIndex,\n endContentIndex,\n indexesToDelete = new Set(),\n } = target;\n const currentHunk = diff.hunks[hunkIndex];\n if (currentHunk == null) {\n console.error({ diff, hunkIndex });\n throw new Error(`resolveRegion: Invalid hunk index: ${hunkIndex}`);\n }\n\n if (\n startContentIndex < 0 ||\n endContentIndex >= currentHunk.hunkContent.length ||\n startContentIndex > endContentIndex\n ) {\n throw new Error(\n `resolveRegion: Invalid content range, ${startContentIndex}, ${endContentIndex}`\n );\n }\n\n const { hunks, additionLines, deletionLines } = diff;\n const resolvedDiff: FileDiffMetadata = {\n ...diff,\n hunks: [],\n deletionLines: [],\n additionLines: [],\n splitLineCount: 0,\n unifiedLineCount: 0,\n cacheKey:\n diff.cacheKey != null\n ? `${diff.cacheKey}:${resolution[0]}-${hunkIndex}:${startContentIndex}-${endContentIndex}`\n : undefined,\n };\n\n const cursor: CursorState = {\n nextAdditionLineIndex: 0,\n nextDeletionLineIndex: 0,\n nextAdditionStart: 1,\n nextDeletionStart: 1,\n splitLineCount: 0,\n unifiedLineCount: 0,\n };\n const updatesEOFState =\n hunkIndex === hunks.length - 1 &&\n endContentIndex === currentHunk.hunkContent.length - 1;\n const shouldProcessCollapsedContext = !diff.isPartial;\n\n for (const [index, hunk] of hunks.entries()) {\n processCollapsedContext(\n diff,\n resolvedDiff,\n cursor,\n getHunkSideStartBoundary(hunk.deletionStart, hunk.deletionCount) -\n hunk.collapsedBefore,\n getHunkSideStartBoundary(hunk.additionStart, hunk.additionCount) -\n hunk.collapsedBefore,\n hunk.collapsedBefore,\n shouldProcessCollapsedContext\n );\n\n const newHunk: Hunk = {\n ...hunk,\n hunkContent: [],\n additionStart: cursor.nextAdditionStart,\n deletionStart: cursor.nextDeletionStart,\n additionLineIndex: cursor.nextAdditionLineIndex,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n additionCount: 0,\n deletionCount: 0,\n deletionLines: 0,\n additionLines: 0,\n splitLineStart: cursor.splitLineCount,\n unifiedLineStart: cursor.unifiedLineCount,\n splitLineCount: 0,\n unifiedLineCount: 0,\n };\n\n for (const [contentIndex, content] of hunk.hunkContent.entries()) {\n // If we are outside of the targeted hunk or content region\n if (\n index !== hunkIndex ||\n contentIndex < startContentIndex ||\n contentIndex > endContentIndex\n ) {\n pushContentLinesToDiff(\n content,\n resolvedDiff,\n deletionLines,\n additionLines\n );\n const newContent = {\n ...content,\n additionLineIndex: cursor.nextAdditionLineIndex,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n };\n newHunk.hunkContent.push(newContent);\n advanceCursor(newContent, cursor, newHunk);\n }\n // If we are at an index to delete, replace with an empty context node\n else if (indexesToDelete.has(contentIndex)) {\n newHunk.hunkContent.push({\n type: 'context',\n lines: 0,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n additionLineIndex: cursor.nextAdditionLineIndex,\n });\n }\n // There's nothing to `resolve` with context nodes, so just push them as\n // they are\n else if (content.type === 'context') {\n pushContentLinesToDiff(\n content,\n resolvedDiff,\n deletionLines,\n additionLines\n );\n const newContent: ContextContent = {\n ...content,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n additionLineIndex: cursor.nextAdditionLineIndex,\n };\n newHunk.hunkContent.push(newContent);\n advanceCursor(newContent, cursor, newHunk);\n }\n // Looks like we have a change to resolve and push\n else {\n pushResolveLinesToDiff(\n resolution,\n content,\n resolvedDiff,\n deletionLines,\n additionLines\n );\n const newContent: ContextContent = {\n type: 'context',\n lines:\n resolution === 'deletions'\n ? content.deletions\n : resolution === 'additions'\n ? content.additions\n : content.deletions + content.additions,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n additionLineIndex: cursor.nextAdditionLineIndex,\n };\n newHunk.hunkContent.push(newContent);\n advanceCursor(newContent, cursor, newHunk);\n }\n }\n\n if (index === hunkIndex && updatesEOFState) {\n const noEOFCR =\n resolution === 'deletions'\n ? hunk.noEOFCRDeletions\n : hunk.noEOFCRAdditions;\n newHunk.noEOFCRAdditions = noEOFCR;\n newHunk.noEOFCRDeletions = noEOFCR;\n }\n\n if (newHunk.additionCount === 0) {\n newHunk.additionStart--;\n if (!diff.isPartial) {\n newHunk.additionLineIndex--;\n }\n }\n if (newHunk.deletionCount === 0) {\n newHunk.deletionStart--;\n if (!diff.isPartial) {\n newHunk.deletionLineIndex--;\n }\n }\n\n resolvedDiff.hunks.push(newHunk);\n }\n\n const finalHunk = hunks.at(-1);\n if (finalHunk != null && !diff.isPartial) {\n const finalDeletionEnd = getHunkSideEndBoundary(\n finalHunk.deletionStart,\n finalHunk.deletionCount\n );\n const finalAdditionEnd = getHunkSideEndBoundary(\n finalHunk.additionStart,\n finalHunk.additionCount\n );\n const trailingContext = Math.min(\n deletionLines.length - finalDeletionEnd,\n additionLines.length - finalAdditionEnd\n );\n pushCollapsedContextLines(\n resolvedDiff,\n deletionLines,\n additionLines,\n finalDeletionEnd,\n finalAdditionEnd,\n trailingContext\n );\n cursor.splitLineCount += trailingContext;\n cursor.unifiedLineCount += trailingContext;\n }\n\n resolvedDiff.splitLineCount = cursor.splitLineCount;\n resolvedDiff.unifiedLineCount = cursor.unifiedLineCount;\n\n return resolvedDiff;\n}\n\nfunction pushCollapsedContextLines(\n diff: FileDiffMetadata,\n deletionLines: string[],\n additionLines: string[],\n deletionLineIndex: number,\n additionLineIndex: number,\n lineCount: number\n) {\n for (let index = 0; index < lineCount; index++) {\n const deletionLine = deletionLines[deletionLineIndex + index];\n const additionLine = additionLines[additionLineIndex + index];\n if (deletionLine == null || additionLine == null) {\n throw new Error(\n 'pushCollapsedContextLines: missing collapsed context line'\n );\n }\n diff.deletionLines.push(deletionLine);\n diff.additionLines.push(additionLine);\n }\n}\n\n// Partial patches track omitted context in `collapsedBefore`, but those lines do\n// not exist in the diff's line arrays. Keep the virtual row counts and file\n// positions in sync without inventing hidden lines.\nfunction processCollapsedContext(\n sourceDiff: FileDiffMetadata,\n resolvedDiff: FileDiffMetadata,\n cursor: CursorState,\n deletionLineIndex: number,\n additionLineIndex: number,\n lineCount: number,\n shouldProcessContent: boolean\n) {\n if (lineCount <= 0) {\n return;\n }\n\n if (shouldProcessContent) {\n pushCollapsedContextLines(\n resolvedDiff,\n sourceDiff.deletionLines,\n sourceDiff.additionLines,\n deletionLineIndex,\n additionLineIndex,\n lineCount\n );\n cursor.nextAdditionLineIndex += lineCount;\n cursor.nextDeletionLineIndex += lineCount;\n }\n\n cursor.nextAdditionStart += lineCount;\n cursor.nextDeletionStart += lineCount;\n cursor.splitLineCount += lineCount;\n cursor.unifiedLineCount += lineCount;\n}\n\nfunction pushContentLinesToDiff(\n content: ContextContent | ChangeContent,\n diff: FileDiffMetadata,\n deletionLines: string[],\n additionLines: string[]\n) {\n if (content.type === 'context') {\n for (let i = 0; i < content.lines; i++) {\n const line = additionLines[content.additionLineIndex + i];\n if (line == null) {\n console.error({ additionLines, content, i });\n throw new Error('pushContentLinesToDiff: Context line does not exist');\n }\n diff.deletionLines.push(line);\n diff.additionLines.push(line);\n }\n } else {\n const len = Math.max(content.deletions, content.additions);\n for (let i = 0; i < len; i++) {\n if (i < content.deletions) {\n const line = deletionLines[content.deletionLineIndex + i];\n if (line == null) {\n console.error({ deletionLines, content, i });\n throw new Error(\n 'pushContentLinesToDiff: Deletion line does not exist'\n );\n }\n diff.deletionLines.push(line);\n }\n if (i < content.additions) {\n const line = additionLines[content.additionLineIndex + i];\n if (line == null) {\n console.error({ additionLines, content, i });\n throw new Error(\n 'pushContentLinesToDiff: Addition line does not exist'\n );\n }\n diff.additionLines.push(line);\n }\n }\n }\n}\n\nfunction pushResolveLinesToDiff(\n resolution: 'deletions' | 'additions' | 'both',\n content: ChangeContent,\n diff: FileDiffMetadata,\n deletionLines: string[],\n additionLines: string[]\n) {\n if (resolution === 'deletions' || resolution === 'both') {\n for (let i = 0; i < content.deletions; i++) {\n const line = deletionLines[content.deletionLineIndex + i];\n if (line == null) {\n console.error({ deletionLines, content, i });\n throw new Error('pushResolveLinesToDiff: Deletion line does not exist');\n }\n diff.deletionLines.push(line);\n diff.additionLines.push(line);\n }\n }\n if (resolution === 'additions' || resolution === 'both') {\n for (let i = 0; i < content.additions; i++) {\n const line = additionLines[content.additionLineIndex + i];\n if (line == null) {\n console.error({ additionLines, content, i });\n throw new Error('pushResolveLinesToDiff: Addition line does not exist');\n }\n diff.deletionLines.push(line);\n diff.additionLines.push(line);\n }\n }\n}\n\nfunction advanceCursor(\n content: ChangeContent | ContextContent,\n cursor: CursorState,\n hunk: Hunk\n) {\n if (content.type === 'context') {\n cursor.nextAdditionLineIndex += content.lines;\n cursor.nextDeletionLineIndex += content.lines;\n cursor.nextAdditionStart += content.lines;\n cursor.nextDeletionStart += content.lines;\n cursor.splitLineCount += content.lines;\n cursor.unifiedLineCount += content.lines;\n\n hunk.additionCount += content.lines;\n hunk.deletionCount += content.lines;\n hunk.splitLineCount += content.lines;\n hunk.unifiedLineCount += content.lines;\n } else {\n cursor.nextAdditionLineIndex += content.additions;\n cursor.nextDeletionLineIndex += content.deletions;\n cursor.nextAdditionStart += content.additions;\n cursor.nextDeletionStart += content.deletions;\n cursor.splitLineCount += Math.max(content.deletions, content.additions);\n cursor.unifiedLineCount += content.deletions + content.additions;\n\n hunk.deletionCount += content.deletions;\n hunk.deletionLines += content.deletions;\n hunk.additionCount += content.additions;\n hunk.additionLines += content.additions;\n hunk.splitLineCount += Math.max(content.deletions, content.additions);\n hunk.unifiedLineCount += content.deletions + content.additions;\n }\n}\n"],"mappings":";;AA4BA,SAAgB,cACd,MACA,QACkB;CAClB,MAAM,EACJ,YACA,WACA,mBACA,iBACA,kCAAkB,IAAI,IAAI,MACxB;CACJ,MAAM,cAAc,KAAK,MAAM;CAC/B,IAAI,eAAe,MAAM;EACvB,QAAQ,MAAM;GAAE;GAAM;EAAU,CAAC;EACjC,MAAM,IAAI,MAAM,sCAAsC,WAAW;CACnE;CAEA,IACE,oBAAoB,KACpB,mBAAmB,YAAY,YAAY,UAC3C,oBAAoB,iBAEpB,MAAM,IAAI,MACR,yCAAyC,kBAAkB,IAAI,iBACjE;CAGF,MAAM,EAAE,OAAO,eAAe,kBAAkB;CAChD,MAAM,eAAiC;EACrC,GAAG;EACH,OAAO,CAAC;EACR,eAAe,CAAC;EAChB,eAAe,CAAC;EAChB,gBAAgB;EAChB,kBAAkB;EAClB,UACE,KAAK,YAAY,OACb,GAAG,KAAK,SAAS,GAAG,WAAW,GAAG,GAAG,UAAU,GAAG,kBAAkB,GAAG,oBACvE,KAAA;CACR;CAEA,MAAM,SAAsB;EAC1B,uBAAuB;EACvB,uBAAuB;EACvB,mBAAmB;EACnB,mBAAmB;EACnB,gBAAgB;EAChB,kBAAkB;CACpB;CACA,MAAM,kBACJ,cAAc,MAAM,SAAS,KAC7B,oBAAoB,YAAY,YAAY,SAAS;CACvD,MAAM,gCAAgC,CAAC,KAAK;CAE5C,KAAK,MAAM,CAAC,OAAO,SAAS,MAAM,QAAQ,GAAG;EAC3C,wBACE,MACA,cACA,QACA,yBAAyB,KAAK,eAAe,KAAK,aAAa,IAC7D,KAAK,iBACP,yBAAyB,KAAK,eAAe,KAAK,aAAa,IAC7D,KAAK,iBACP,KAAK,iBACL,6BACF;EAEA,MAAM,UAAgB;GACpB,GAAG;GACH,aAAa,CAAC;GACd,eAAe,OAAO;GACtB,eAAe,OAAO;GACtB,mBAAmB,OAAO;GAC1B,mBAAmB,OAAO;GAC1B,eAAe;GACf,eAAe;GACf,eAAe;GACf,eAAe;GACf,gBAAgB,OAAO;GACvB,kBAAkB,OAAO;GACzB,gBAAgB;GAChB,kBAAkB;EACpB;EAEA,KAAK,MAAM,CAAC,cAAc,YAAY,KAAK,YAAY,QAAQ,GAE7D,IACE,UAAU,aACV,eAAe,qBACf,eAAe,iBACf;GACA,uBACE,SACA,cACA,eACA,aACF;GACA,MAAM,aAAa;IACjB,GAAG;IACH,mBAAmB,OAAO;IAC1B,mBAAmB,OAAO;GAC5B;GACA,QAAQ,YAAY,KAAK,UAAU;GACnC,cAAc,YAAY,QAAQ,OAAO;EAC3C,OAEK,IAAI,gBAAgB,IAAI,YAAY,GACvC,QAAQ,YAAY,KAAK;GACvB,MAAM;GACN,OAAO;GACP,mBAAmB,OAAO;GAC1B,mBAAmB,OAAO;EAC5B,CAAC;OAIE,IAAI,QAAQ,SAAS,WAAW;GACnC,uBACE,SACA,cACA,eACA,aACF;GACA,MAAM,aAA6B;IACjC,GAAG;IACH,mBAAmB,OAAO;IAC1B,mBAAmB,OAAO;GAC5B;GACA,QAAQ,YAAY,KAAK,UAAU;GACnC,cAAc,YAAY,QAAQ,OAAO;EAC3C,OAEK;GACH,uBACE,YACA,SACA,cACA,eACA,aACF;GACA,MAAM,aAA6B;IACjC,MAAM;IACN,OACE,eAAe,cACX,QAAQ,YACR,eAAe,cACb,QAAQ,YACR,QAAQ,YAAY,QAAQ;IACpC,mBAAmB,OAAO;IAC1B,mBAAmB,OAAO;GAC5B;GACA,QAAQ,YAAY,KAAK,UAAU;GACnC,cAAc,YAAY,QAAQ,OAAO;EAC3C;EAGF,IAAI,UAAU,aAAa,iBAAiB;GAC1C,MAAM,UACJ,eAAe,cACX,KAAK,mBACL,KAAK;GACX,QAAQ,mBAAmB;GAC3B,QAAQ,mBAAmB;EAC7B;EAEA,IAAI,QAAQ,kBAAkB,GAAG;GAC/B,QAAQ;GACR,IAAI,CAAC,KAAK,WACR,QAAQ;EAEZ;EACA,IAAI,QAAQ,kBAAkB,GAAG;GAC/B,QAAQ;GACR,IAAI,CAAC,KAAK,WACR,QAAQ;EAEZ;EAEA,aAAa,MAAM,KAAK,OAAO;CACjC;CAEA,MAAM,YAAY,MAAM,GAAG,EAAE;CAC7B,IAAI,aAAa,QAAQ,CAAC,KAAK,WAAW;EACxC,MAAM,mBAAmB,uBACvB,UAAU,eACV,UAAU,aACZ;EACA,MAAM,mBAAmB,uBACvB,UAAU,eACV,UAAU,aACZ;EACA,MAAM,kBAAkB,KAAK,IAC3B,cAAc,SAAS,kBACvB,cAAc,SAAS,gBACzB;EACA,0BACE,cACA,eACA,eACA,kBACA,kBACA,eACF;EACA,OAAO,kBAAkB;EACzB,OAAO,oBAAoB;CAC7B;CAEA,aAAa,iBAAiB,OAAO;CACrC,aAAa,mBAAmB,OAAO;CAEvC,OAAO;AACT;AAEA,SAAS,0BACP,MACA,eACA,eACA,mBACA,mBACA,WACA;CACA,KAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,SAAS;EAC9C,MAAM,eAAe,cAAc,oBAAoB;EACvD,MAAM,eAAe,cAAc,oBAAoB;EACvD,IAAI,gBAAgB,QAAQ,gBAAgB,MAC1C,MAAM,IAAI,MACR,2DACF;EAEF,KAAK,cAAc,KAAK,YAAY;EACpC,KAAK,cAAc,KAAK,YAAY;CACtC;AACF;AAKA,SAAS,wBACP,YACA,cACA,QACA,mBACA,mBACA,WACA,sBACA;CACA,IAAI,aAAa,GACf;CAGF,IAAI,sBAAsB;EACxB,0BACE,cACA,WAAW,eACX,WAAW,eACX,mBACA,mBACA,SACF;EACA,OAAO,yBAAyB;EAChC,OAAO,yBAAyB;CAClC;CAEA,OAAO,qBAAqB;CAC5B,OAAO,qBAAqB;CAC5B,OAAO,kBAAkB;CACzB,OAAO,oBAAoB;AAC7B;AAEA,SAAS,uBACP,SACA,MACA,eACA,eACA;CACA,IAAI,QAAQ,SAAS,WACnB,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,OAAO,KAAK;EACtC,MAAM,OAAO,cAAc,QAAQ,oBAAoB;EACvD,IAAI,QAAQ,MAAM;GAChB,QAAQ,MAAM;IAAE;IAAe;IAAS;GAAE,CAAC;GAC3C,MAAM,IAAI,MAAM,qDAAqD;EACvE;EACA,KAAK,cAAc,KAAK,IAAI;EAC5B,KAAK,cAAc,KAAK,IAAI;CAC9B;MACK;EACL,MAAM,MAAM,KAAK,IAAI,QAAQ,WAAW,QAAQ,SAAS;EACzD,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK;GAC5B,IAAI,IAAI,QAAQ,WAAW;IACzB,MAAM,OAAO,cAAc,QAAQ,oBAAoB;IACvD,IAAI,QAAQ,MAAM;KAChB,QAAQ,MAAM;MAAE;MAAe;MAAS;KAAE,CAAC;KAC3C,MAAM,IAAI,MACR,sDACF;IACF;IACA,KAAK,cAAc,KAAK,IAAI;GAC9B;GACA,IAAI,IAAI,QAAQ,WAAW;IACzB,MAAM,OAAO,cAAc,QAAQ,oBAAoB;IACvD,IAAI,QAAQ,MAAM;KAChB,QAAQ,MAAM;MAAE;MAAe;MAAS;KAAE,CAAC;KAC3C,MAAM,IAAI,MACR,sDACF;IACF;IACA,KAAK,cAAc,KAAK,IAAI;GAC9B;EACF;CACF;AACF;AAEA,SAAS,uBACP,YACA,SACA,MACA,eACA,eACA;CACA,IAAI,eAAe,eAAe,eAAe,QAC/C,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,WAAW,KAAK;EAC1C,MAAM,OAAO,cAAc,QAAQ,oBAAoB;EACvD,IAAI,QAAQ,MAAM;GAChB,QAAQ,MAAM;IAAE;IAAe;IAAS;GAAE,CAAC;GAC3C,MAAM,IAAI,MAAM,sDAAsD;EACxE;EACA,KAAK,cAAc,KAAK,IAAI;EAC5B,KAAK,cAAc,KAAK,IAAI;CAC9B;CAEF,IAAI,eAAe,eAAe,eAAe,QAC/C,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,WAAW,KAAK;EAC1C,MAAM,OAAO,cAAc,QAAQ,oBAAoB;EACvD,IAAI,QAAQ,MAAM;GAChB,QAAQ,MAAM;IAAE;IAAe;IAAS;GAAE,CAAC;GAC3C,MAAM,IAAI,MAAM,sDAAsD;EACxE;EACA,KAAK,cAAc,KAAK,IAAI;EAC5B,KAAK,cAAc,KAAK,IAAI;CAC9B;AAEJ;AAEA,SAAS,cACP,SACA,QACA,MACA;CACA,IAAI,QAAQ,SAAS,WAAW;EAC9B,OAAO,yBAAyB,QAAQ;EACxC,OAAO,yBAAyB,QAAQ;EACxC,OAAO,qBAAqB,QAAQ;EACpC,OAAO,qBAAqB,QAAQ;EACpC,OAAO,kBAAkB,QAAQ;EACjC,OAAO,oBAAoB,QAAQ;EAEnC,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,kBAAkB,QAAQ;EAC/B,KAAK,oBAAoB,QAAQ;CACnC,OAAO;EACL,OAAO,yBAAyB,QAAQ;EACxC,OAAO,yBAAyB,QAAQ;EACxC,OAAO,qBAAqB,QAAQ;EACpC,OAAO,qBAAqB,QAAQ;EACpC,OAAO,kBAAkB,KAAK,IAAI,QAAQ,WAAW,QAAQ,SAAS;EACtE,OAAO,oBAAoB,QAAQ,YAAY,QAAQ;EAEvD,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,iBAAiB,QAAQ;EAC9B,KAAK,kBAAkB,KAAK,IAAI,QAAQ,WAAW,QAAQ,SAAS;EACpE,KAAK,oBAAoB,QAAQ,YAAY,QAAQ;CACvD;AACF"}
1
+ {"version":3,"file":"resolveRegion.js","names":[],"sources":["../../src/utils/resolveRegion.ts"],"sourcesContent":["import type {\n ChangeContent,\n ContextContent,\n FileDiffMetadata,\n Hunk,\n} from '../types';\nimport {\n getHunkSideEndBoundary,\n getHunkSideStartBoundary,\n} from './getHunkSideBoundaries';\n\ninterface RegionResolutionTarget {\n hunkIndex: number;\n startContentIndex: number;\n endContentIndex: number;\n resolution: 'deletions' | 'additions' | 'both';\n indexesToDelete?: Set<number>;\n}\n\ninterface CursorState {\n nextAdditionLineIndex: number;\n nextDeletionLineIndex: number;\n nextAdditionStart: number;\n nextDeletionStart: number;\n splitLineCount: number;\n unifiedLineCount: number;\n}\n\nexport function resolveRegion(\n diff: FileDiffMetadata,\n target: RegionResolutionTarget\n): FileDiffMetadata {\n const {\n resolution,\n hunkIndex,\n startContentIndex,\n endContentIndex,\n indexesToDelete = new Set(),\n } = target;\n const currentHunk = diff.hunks[hunkIndex];\n if (currentHunk == null) {\n console.error({ diff, hunkIndex });\n throw new Error(`resolveRegion: Invalid hunk index: ${hunkIndex}`);\n }\n\n if (\n startContentIndex < 0 ||\n endContentIndex >= currentHunk.hunkContent.length ||\n startContentIndex > endContentIndex\n ) {\n throw new Error(\n `resolveRegion: Invalid content range, ${startContentIndex}, ${endContentIndex}`\n );\n }\n\n const { hunks, additionLines, deletionLines } = diff;\n const resolvedDiff: FileDiffMetadata = {\n ...diff,\n hunks: [],\n deletionLines: [],\n additionLines: [],\n deletionCharacterCount: 0,\n additionCharacterCount: 0,\n splitLineCount: 0,\n unifiedLineCount: 0,\n cacheKey:\n diff.cacheKey != null\n ? `${diff.cacheKey}:${resolution[0]}-${hunkIndex}:${startContentIndex}-${endContentIndex}`\n : undefined,\n };\n\n const cursor: CursorState = {\n nextAdditionLineIndex: 0,\n nextDeletionLineIndex: 0,\n nextAdditionStart: 1,\n nextDeletionStart: 1,\n splitLineCount: 0,\n unifiedLineCount: 0,\n };\n const updatesEOFState =\n hunkIndex === hunks.length - 1 &&\n endContentIndex === currentHunk.hunkContent.length - 1;\n const shouldProcessCollapsedContext = !diff.isPartial;\n\n for (const [index, hunk] of hunks.entries()) {\n processCollapsedContext(\n diff,\n resolvedDiff,\n cursor,\n getHunkSideStartBoundary(hunk.deletionStart, hunk.deletionCount) -\n hunk.collapsedBefore,\n getHunkSideStartBoundary(hunk.additionStart, hunk.additionCount) -\n hunk.collapsedBefore,\n hunk.collapsedBefore,\n shouldProcessCollapsedContext\n );\n\n const newHunk: Hunk = {\n ...hunk,\n hunkContent: [],\n additionStart: cursor.nextAdditionStart,\n deletionStart: cursor.nextDeletionStart,\n additionLineIndex: cursor.nextAdditionLineIndex,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n additionCount: 0,\n deletionCount: 0,\n deletionLines: 0,\n additionLines: 0,\n splitLineStart: cursor.splitLineCount,\n unifiedLineStart: cursor.unifiedLineCount,\n splitLineCount: 0,\n unifiedLineCount: 0,\n };\n\n for (const [contentIndex, content] of hunk.hunkContent.entries()) {\n // If we are outside of the targeted hunk or content region\n if (\n index !== hunkIndex ||\n contentIndex < startContentIndex ||\n contentIndex > endContentIndex\n ) {\n pushContentLinesToDiff(\n content,\n resolvedDiff,\n deletionLines,\n additionLines\n );\n const newContent = {\n ...content,\n additionLineIndex: cursor.nextAdditionLineIndex,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n };\n newHunk.hunkContent.push(newContent);\n advanceCursor(newContent, cursor, newHunk);\n }\n // If we are at an index to delete, replace with an empty context node\n else if (indexesToDelete.has(contentIndex)) {\n newHunk.hunkContent.push({\n type: 'context',\n lines: 0,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n additionLineIndex: cursor.nextAdditionLineIndex,\n });\n }\n // There's nothing to `resolve` with context nodes, so just push them as\n // they are\n else if (content.type === 'context') {\n pushContentLinesToDiff(\n content,\n resolvedDiff,\n deletionLines,\n additionLines\n );\n const newContent: ContextContent = {\n ...content,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n additionLineIndex: cursor.nextAdditionLineIndex,\n };\n newHunk.hunkContent.push(newContent);\n advanceCursor(newContent, cursor, newHunk);\n }\n // Looks like we have a change to resolve and push\n else {\n pushResolveLinesToDiff(\n resolution,\n content,\n resolvedDiff,\n deletionLines,\n additionLines\n );\n const newContent: ContextContent = {\n type: 'context',\n lines:\n resolution === 'deletions'\n ? content.deletions\n : resolution === 'additions'\n ? content.additions\n : content.deletions + content.additions,\n deletionLineIndex: cursor.nextDeletionLineIndex,\n additionLineIndex: cursor.nextAdditionLineIndex,\n };\n newHunk.hunkContent.push(newContent);\n advanceCursor(newContent, cursor, newHunk);\n }\n }\n\n if (index === hunkIndex && updatesEOFState) {\n const noEOFCR =\n resolution === 'deletions'\n ? hunk.noEOFCRDeletions\n : hunk.noEOFCRAdditions;\n newHunk.noEOFCRAdditions = noEOFCR;\n newHunk.noEOFCRDeletions = noEOFCR;\n }\n\n if (newHunk.additionCount === 0) {\n newHunk.additionStart--;\n if (!diff.isPartial) {\n newHunk.additionLineIndex--;\n }\n }\n if (newHunk.deletionCount === 0) {\n newHunk.deletionStart--;\n if (!diff.isPartial) {\n newHunk.deletionLineIndex--;\n }\n }\n\n resolvedDiff.hunks.push(newHunk);\n }\n\n const finalHunk = hunks.at(-1);\n if (finalHunk != null && !diff.isPartial) {\n const finalDeletionEnd = getHunkSideEndBoundary(\n finalHunk.deletionStart,\n finalHunk.deletionCount\n );\n const finalAdditionEnd = getHunkSideEndBoundary(\n finalHunk.additionStart,\n finalHunk.additionCount\n );\n const trailingContext = Math.min(\n deletionLines.length - finalDeletionEnd,\n additionLines.length - finalAdditionEnd\n );\n pushCollapsedContextLines(\n resolvedDiff,\n deletionLines,\n additionLines,\n finalDeletionEnd,\n finalAdditionEnd,\n trailingContext\n );\n cursor.splitLineCount += trailingContext;\n cursor.unifiedLineCount += trailingContext;\n }\n\n resolvedDiff.splitLineCount = cursor.splitLineCount;\n resolvedDiff.unifiedLineCount = cursor.unifiedLineCount;\n\n return resolvedDiff;\n}\n\nfunction pushCollapsedContextLines(\n diff: FileDiffMetadata,\n deletionLines: string[],\n additionLines: string[],\n deletionLineIndex: number,\n additionLineIndex: number,\n lineCount: number\n) {\n for (let index = 0; index < lineCount; index++) {\n const deletionLine = deletionLines[deletionLineIndex + index];\n const additionLine = additionLines[additionLineIndex + index];\n if (deletionLine == null || additionLine == null) {\n throw new Error(\n 'pushCollapsedContextLines: missing collapsed context line'\n );\n }\n pushDeletionLine(diff, deletionLine);\n pushAdditionLine(diff, additionLine);\n }\n}\n\n// Partial patches track omitted context in `collapsedBefore`, but those lines do\n// not exist in the diff's line arrays. Keep the virtual row counts and file\n// positions in sync without inventing hidden lines.\nfunction processCollapsedContext(\n sourceDiff: FileDiffMetadata,\n resolvedDiff: FileDiffMetadata,\n cursor: CursorState,\n deletionLineIndex: number,\n additionLineIndex: number,\n lineCount: number,\n shouldProcessContent: boolean\n) {\n if (lineCount <= 0) {\n return;\n }\n\n if (shouldProcessContent) {\n pushCollapsedContextLines(\n resolvedDiff,\n sourceDiff.deletionLines,\n sourceDiff.additionLines,\n deletionLineIndex,\n additionLineIndex,\n lineCount\n );\n cursor.nextAdditionLineIndex += lineCount;\n cursor.nextDeletionLineIndex += lineCount;\n }\n\n cursor.nextAdditionStart += lineCount;\n cursor.nextDeletionStart += lineCount;\n cursor.splitLineCount += lineCount;\n cursor.unifiedLineCount += lineCount;\n}\n\nfunction pushContentLinesToDiff(\n content: ContextContent | ChangeContent,\n diff: FileDiffMetadata,\n deletionLines: string[],\n additionLines: string[]\n) {\n if (content.type === 'context') {\n for (let i = 0; i < content.lines; i++) {\n const line = additionLines[content.additionLineIndex + i];\n if (line == null) {\n console.error({ additionLines, content, i });\n throw new Error('pushContentLinesToDiff: Context line does not exist');\n }\n pushDeletionLine(diff, line);\n pushAdditionLine(diff, line);\n }\n } else {\n const len = Math.max(content.deletions, content.additions);\n for (let i = 0; i < len; i++) {\n if (i < content.deletions) {\n const line = deletionLines[content.deletionLineIndex + i];\n if (line == null) {\n console.error({ deletionLines, content, i });\n throw new Error(\n 'pushContentLinesToDiff: Deletion line does not exist'\n );\n }\n pushDeletionLine(diff, line);\n }\n if (i < content.additions) {\n const line = additionLines[content.additionLineIndex + i];\n if (line == null) {\n console.error({ additionLines, content, i });\n throw new Error(\n 'pushContentLinesToDiff: Addition line does not exist'\n );\n }\n pushAdditionLine(diff, line);\n }\n }\n }\n}\n\nfunction pushResolveLinesToDiff(\n resolution: 'deletions' | 'additions' | 'both',\n content: ChangeContent,\n diff: FileDiffMetadata,\n deletionLines: string[],\n additionLines: string[]\n) {\n if (resolution === 'deletions' || resolution === 'both') {\n for (let i = 0; i < content.deletions; i++) {\n const line = deletionLines[content.deletionLineIndex + i];\n if (line == null) {\n console.error({ deletionLines, content, i });\n throw new Error('pushResolveLinesToDiff: Deletion line does not exist');\n }\n pushDeletionLine(diff, line);\n pushAdditionLine(diff, line);\n }\n }\n if (resolution === 'additions' || resolution === 'both') {\n for (let i = 0; i < content.additions; i++) {\n const line = additionLines[content.additionLineIndex + i];\n if (line == null) {\n console.error({ additionLines, content, i });\n throw new Error('pushResolveLinesToDiff: Addition line does not exist');\n }\n pushDeletionLine(diff, line);\n pushAdditionLine(diff, line);\n }\n }\n}\n\nfunction advanceCursor(\n content: ChangeContent | ContextContent,\n cursor: CursorState,\n hunk: Hunk\n) {\n if (content.type === 'context') {\n cursor.nextAdditionLineIndex += content.lines;\n cursor.nextDeletionLineIndex += content.lines;\n cursor.nextAdditionStart += content.lines;\n cursor.nextDeletionStart += content.lines;\n cursor.splitLineCount += content.lines;\n cursor.unifiedLineCount += content.lines;\n\n hunk.additionCount += content.lines;\n hunk.deletionCount += content.lines;\n hunk.splitLineCount += content.lines;\n hunk.unifiedLineCount += content.lines;\n } else {\n cursor.nextAdditionLineIndex += content.additions;\n cursor.nextDeletionLineIndex += content.deletions;\n cursor.nextAdditionStart += content.additions;\n cursor.nextDeletionStart += content.deletions;\n cursor.splitLineCount += Math.max(content.deletions, content.additions);\n cursor.unifiedLineCount += content.deletions + content.additions;\n\n hunk.deletionCount += content.deletions;\n hunk.deletionLines += content.deletions;\n hunk.additionCount += content.additions;\n hunk.additionLines += content.additions;\n hunk.splitLineCount += Math.max(content.deletions, content.additions);\n hunk.unifiedLineCount += content.deletions + content.additions;\n }\n}\n\n// Appends a line to one side of the resolved diff and keeps that side's\n// character count in sync with its line array.\nfunction pushDeletionLine(diff: FileDiffMetadata, line: string) {\n diff.deletionLines.push(line);\n diff.deletionCharacterCount += line.length;\n}\n\nfunction pushAdditionLine(diff: FileDiffMetadata, line: string) {\n diff.additionLines.push(line);\n diff.additionCharacterCount += line.length;\n}\n"],"mappings":"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"}