@pierre/diffs 1.3.0-beta.5 → 1.3.0-beta.6
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.
- package/README.md +9 -9
- package/dist/components/CodeView.d.ts +10 -11
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +8 -8
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +4 -5
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +32 -17
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +19 -19
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +84 -54
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/FileStream.d.ts +0 -1
- package/dist/components/FileStream.d.ts.map +1 -1
- package/dist/components/FileStream.js +4 -4
- package/dist/components/FileStream.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts +1 -2
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +3 -3
- package/dist/components/UnresolvedFile.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +0 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +19 -18
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +2 -3
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +17 -18
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.d.ts +1 -1
- package/dist/components/Virtualizer.d.ts.map +1 -1
- package/dist/components/Virtualizer.js +23 -24
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/components/VirtulizerDevelopment.d.ts.map +1 -1
- package/dist/components/web-components.d.ts.map +1 -1
- package/dist/components/web-components.js +2 -3
- package/dist/components/web-components.js.map +1 -1
- package/dist/constants.d.ts +3 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -2
- package/dist/constants.js.map +1 -1
- package/dist/editor/command.d.ts +2 -1
- package/dist/editor/command.d.ts.map +1 -1
- package/dist/editor/command.js +7 -3
- package/dist/editor/command.js.map +1 -1
- package/dist/editor/editStack.d.ts +7 -1
- package/dist/editor/editStack.d.ts.map +1 -1
- package/dist/editor/editStack.js +3 -3
- package/dist/editor/editStack.js.map +1 -1
- package/dist/editor/editor.d.ts +26 -2
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +551 -252
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +3 -3
- package/dist/editor/editor2.js.map +1 -1
- package/dist/editor/index.js +1 -2
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +2 -3
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +2 -1
- package/dist/editor/marker.d.ts.map +1 -1
- package/dist/editor/marker.js +28 -11
- package/dist/editor/marker.js.map +1 -1
- package/dist/editor/pieceTable.d.ts +4 -2
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +138 -128
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/platform.d.ts +8 -1
- package/dist/editor/platform.d.ts.map +1 -1
- package/dist/editor/platform.js +16 -5
- package/dist/editor/platform.js.map +1 -1
- package/dist/editor/searchPanel.d.ts +1 -0
- package/dist/editor/searchPanel.d.ts.map +1 -1
- package/dist/editor/searchPanel.js +75 -62
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +41 -4
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +423 -83
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/selectionAction.d.ts +4 -5
- package/dist/editor/selectionAction.d.ts.map +1 -1
- package/dist/editor/selectionAction.js +14 -64
- package/dist/editor/selectionAction.js.map +1 -1
- package/dist/editor/sprite.d.ts +2 -2
- package/dist/editor/sprite.d.ts.map +1 -1
- package/dist/editor/sprite.js +7 -14
- package/dist/editor/sprite.js.map +1 -1
- package/dist/editor/textDocument.d.ts +5 -4
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +26 -15
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textMeasure.d.ts +36 -3
- package/dist/editor/textMeasure.d.ts.map +1 -1
- package/dist/editor/textMeasure.js +79 -10
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/tokenzier.d.ts +1 -0
- package/dist/editor/tokenzier.d.ts.map +1 -1
- package/dist/editor/tokenzier.js +16 -13
- package/dist/editor/tokenzier.js.map +1 -1
- package/dist/editor/utils.d.ts +2 -1
- package/dist/editor/utils.d.ts.map +1 -1
- package/dist/editor/utils.js +6 -3
- package/dist/editor/utils.js.map +1 -1
- package/dist/highlighter/languages/areLanguagesAttached.d.ts.map +1 -1
- package/dist/highlighter/languages/areLanguagesAttached.js +1 -2
- package/dist/highlighter/languages/areLanguagesAttached.js.map +1 -1
- package/dist/highlighter/languages/attachResolvedLanguages.d.ts +0 -2
- package/dist/highlighter/languages/attachResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/attachResolvedLanguages.js +1 -2
- package/dist/highlighter/languages/attachResolvedLanguages.js.map +1 -1
- package/dist/highlighter/languages/cleanUpResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/cleanUpResolvedLanguages.js +1 -2
- package/dist/highlighter/languages/cleanUpResolvedLanguages.js.map +1 -1
- package/dist/highlighter/languages/constants.d.ts +0 -1
- package/dist/highlighter/languages/constants.d.ts.map +1 -1
- package/dist/highlighter/languages/constants.js +1 -1
- package/dist/highlighter/languages/constants.js.map +1 -1
- package/dist/highlighter/languages/getResolvedLanguages.d.ts +0 -2
- package/dist/highlighter/languages/getResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/getResolvedLanguages.js +1 -2
- package/dist/highlighter/languages/getResolvedLanguages.js.map +1 -1
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts +0 -2
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.js +1 -2
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.js.map +1 -1
- package/dist/highlighter/languages/hasResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/hasResolvedLanguages.js +1 -2
- package/dist/highlighter/languages/hasResolvedLanguages.js.map +1 -1
- package/dist/highlighter/languages/registerCustomLanguage.d.ts +0 -1
- package/dist/highlighter/languages/registerCustomLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/registerCustomLanguage.js +1 -2
- package/dist/highlighter/languages/registerCustomLanguage.js.map +1 -1
- package/dist/highlighter/languages/resolveLanguage.d.ts +0 -2
- package/dist/highlighter/languages/resolveLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/resolveLanguage.js +4 -5
- package/dist/highlighter/languages/resolveLanguage.js.map +1 -1
- package/dist/highlighter/languages/resolveLanguages.d.ts +0 -2
- package/dist/highlighter/languages/resolveLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/resolveLanguages.js +1 -2
- package/dist/highlighter/languages/resolveLanguages.js.map +1 -1
- package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
- package/dist/highlighter/shared_highlighter.js +3 -4
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/highlighter/themes/areThemesAttached.d.ts.map +1 -1
- package/dist/highlighter/themes/areThemesAttached.js +1 -2
- package/dist/highlighter/themes/areThemesAttached.js.map +1 -1
- package/dist/highlighter/themes/attachResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/attachResolvedThemes.js +1 -2
- package/dist/highlighter/themes/attachResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/cleanUpResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/cleanUpResolvedThemes.js +1 -2
- package/dist/highlighter/themes/cleanUpResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/constants.d.ts.map +1 -1
- package/dist/highlighter/themes/constants.js +1 -1
- package/dist/highlighter/themes/constants.js.map +1 -1
- package/dist/highlighter/themes/getResolvedOrResolveTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/getResolvedOrResolveTheme.js +1 -2
- package/dist/highlighter/themes/getResolvedOrResolveTheme.js.map +1 -1
- package/dist/highlighter/themes/getResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/getResolvedThemes.js +1 -2
- package/dist/highlighter/themes/getResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/hasResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/hasResolvedThemes.js +1 -2
- package/dist/highlighter/themes/hasResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.js +1 -2
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.js.map +1 -1
- package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/registerCustomTheme.js +1 -2
- package/dist/highlighter/themes/registerCustomTheme.js.map +1 -1
- package/dist/highlighter/themes/resolveTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/resolveTheme.js +1 -2
- package/dist/highlighter/themes/resolveTheme.js.map +1 -1
- package/dist/highlighter/themes/resolveThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/resolveThemes.js +1 -2
- package/dist/highlighter/themes/resolveThemes.js.map +1 -1
- package/dist/highlighter/themes/themeResolution.d.ts.map +1 -1
- package/dist/highlighter/themes/themeResolution.js +1 -2
- package/dist/highlighter/themes/themeResolution.js.map +1 -1
- package/dist/highlighter/themes/themeResolver.d.ts +2 -2
- package/dist/highlighter/themes/themeResolver.d.ts.map +1 -1
- package/dist/highlighter/themes/themeResolver.js +1 -2
- package/dist/highlighter/themes/themeResolver.js.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +2 -3
- package/dist/managers/InteractionManager.d.ts +7 -0
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/InteractionManager.js +25 -3
- package/dist/managers/InteractionManager.js.map +1 -1
- package/dist/managers/ResizeManager.d.ts.map +1 -1
- package/dist/managers/ResizeManager.js +1 -1
- package/dist/managers/ResizeManager.js.map +1 -1
- package/dist/managers/ScrollSyncManager.d.ts.map +1 -1
- package/dist/managers/ScrollSyncManager.js +1 -1
- package/dist/managers/ScrollSyncManager.js.map +1 -1
- package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
- package/dist/managers/UniversalRenderingManager.js +2 -2
- package/dist/managers/UniversalRenderingManager.js.map +1 -1
- package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts +228 -0
- package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts.map +1 -0
- package/dist/node_modules/.pnpm/@types_unist@3.0.3/node_modules/@types/unist/index.d.ts +84 -0
- package/dist/node_modules/.pnpm/@types_unist@3.0.3/node_modules/@types/unist/index.d.ts.map +1 -0
- package/dist/react/CodeView.d.ts +1 -1
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +17 -16
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/EditorContext.d.ts +0 -1
- package/dist/react/EditorContext.d.ts.map +1 -1
- package/dist/react/EditorContext.js +2 -5
- package/dist/react/EditorContext.js.map +1 -1
- package/dist/react/File.d.ts +1 -0
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +4 -6
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +1 -0
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +4 -6
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +1 -0
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +4 -6
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +1 -0
- package/dist/react/PatchDiff.d.ts.map +1 -1
- package/dist/react/PatchDiff.js +4 -6
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/UnresolvedFile.d.ts +2 -1
- package/dist/react/UnresolvedFile.d.ts.map +1 -1
- package/dist/react/UnresolvedFile.js +4 -6
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/Virtualizer.d.ts.map +1 -1
- package/dist/react/Virtualizer.js +2 -5
- package/dist/react/Virtualizer.js.map +1 -1
- package/dist/react/WorkerPoolContext.d.ts +0 -1
- package/dist/react/WorkerPoolContext.d.ts.map +1 -1
- package/dist/react/WorkerPoolContext.js +2 -5
- package/dist/react/WorkerPoolContext.js.map +1 -1
- package/dist/react/constants.d.ts.map +1 -1
- package/dist/react/constants.js +1 -1
- package/dist/react/constants.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -2
- package/dist/react/jsx.d.ts +0 -2
- package/dist/react/jsx.d.ts.map +1 -1
- package/dist/react/types.d.ts +2 -0
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.d.ts +2 -0
- package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.js +18 -11
- package/dist/react/utils/renderDiffChildren.js.map +1 -1
- package/dist/react/utils/renderFileChildren.d.ts +2 -0
- package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
- package/dist/react/utils/renderFileChildren.js +18 -11
- package/dist/react/utils/renderFileChildren.js.map +1 -1
- package/dist/react/utils/templateRender.d.ts.map +1 -1
- package/dist/react/utils/templateRender.js +1 -2
- package/dist/react/utils/templateRender.js.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +1 -3
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +1 -2
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/react/utils/useStableCallback.d.ts.map +1 -1
- package/dist/react/utils/useStableCallback.js +1 -2
- package/dist/react/utils/useStableCallback.js.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.js +10 -11
- package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +2 -3
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +30 -24
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +1 -3
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +14 -11
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts +1 -2
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.js +1 -2
- package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
- package/dist/shiki-stream/index.js +1 -2
- package/dist/shiki-stream/stream.d.ts +0 -1
- package/dist/shiki-stream/stream.d.ts.map +1 -1
- package/dist/shiki-stream/stream.js +1 -2
- package/dist/shiki-stream/stream.js.map +1 -1
- package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
- package/dist/shiki-stream/tokenizer.js +1 -1
- package/dist/shiki-stream/tokenizer.js.map +1 -1
- package/dist/shiki-stream/types.d.ts +0 -1
- package/dist/shiki-stream/types.d.ts.map +1 -1
- package/dist/sprite.d.ts.map +1 -1
- package/dist/sprite.js +1 -1
- package/dist/ssr/FileDiffReact.d.ts.map +1 -1
- package/dist/ssr/FileDiffReact.js +5 -8
- package/dist/ssr/FileDiffReact.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/index.js +1 -2
- package/dist/ssr/preloadDiffs.d.ts +1 -1
- package/dist/ssr/preloadDiffs.d.ts.map +1 -1
- package/dist/ssr/preloadDiffs.js +1 -2
- package/dist/ssr/preloadDiffs.js.map +1 -1
- package/dist/ssr/preloadFile.d.ts.map +1 -1
- package/dist/ssr/preloadFile.js +1 -2
- package/dist/ssr/preloadFile.js.map +1 -1
- package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
- package/dist/ssr/preloadPatchFile.js +2 -3
- package/dist/ssr/preloadPatchFile.js.map +1 -1
- package/dist/ssr/renderHTML.d.ts +1 -1
- package/dist/ssr/renderHTML.d.ts.map +1 -1
- package/dist/ssr/renderHTML.js +1 -2
- package/dist/ssr/renderHTML.js.map +1 -1
- package/dist/string-import.d.ts +4 -0
- package/dist/string-import.d.ts.map +1 -1
- package/dist/style.js +3 -3
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +11 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/areDiffLineAnnotationsEqual.d.ts.map +1 -1
- package/dist/utils/areDiffLineAnnotationsEqual.js +1 -1
- package/dist/utils/areDiffLineAnnotationsEqual.js.map +1 -1
- package/dist/utils/areDiffRenderOptionsEqual.d.ts.map +1 -1
- package/dist/utils/areDiffRenderOptionsEqual.js +1 -2
- package/dist/utils/areDiffRenderOptionsEqual.js.map +1 -1
- package/dist/utils/areDiffTargetsEqual.d.ts.map +1 -1
- package/dist/utils/areDiffTargetsEqual.js +1 -1
- package/dist/utils/areDiffTargetsEqual.js.map +1 -1
- package/dist/utils/areFileRenderOptionsEqual.d.ts.map +1 -1
- package/dist/utils/areFileRenderOptionsEqual.js +1 -2
- package/dist/utils/areFileRenderOptionsEqual.js.map +1 -1
- package/dist/utils/areFilesEqual.d.ts.map +1 -1
- package/dist/utils/areFilesEqual.js +1 -1
- package/dist/utils/areFilesEqual.js.map +1 -1
- package/dist/utils/areHunkDataEqual.d.ts.map +1 -1
- package/dist/utils/areHunkDataEqual.js +1 -1
- package/dist/utils/areHunkDataEqual.js.map +1 -1
- package/dist/utils/areLineAnnotationsEqual.d.ts.map +1 -1
- package/dist/utils/areLineAnnotationsEqual.js +1 -1
- package/dist/utils/areLineAnnotationsEqual.js.map +1 -1
- package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
- package/dist/utils/areManagedSnapshotsEqual.js +1 -1
- package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
- package/dist/utils/areMergeConflictActionsEqual.d.ts.map +1 -1
- package/dist/utils/areMergeConflictActionsEqual.js +1 -1
- package/dist/utils/areMergeConflictActionsEqual.js.map +1 -1
- package/dist/utils/areObjectsEqual.d.ts.map +1 -1
- package/dist/utils/areObjectsEqual.js +1 -1
- package/dist/utils/areObjectsEqual.js.map +1 -1
- package/dist/utils/areOptionsEqual.d.ts +0 -2
- package/dist/utils/areOptionsEqual.d.ts.map +1 -1
- package/dist/utils/areOptionsEqual.js +1 -2
- package/dist/utils/areOptionsEqual.js.map +1 -1
- package/dist/utils/arePrePropertiesEqual.d.ts.map +1 -1
- package/dist/utils/arePrePropertiesEqual.js +1 -1
- package/dist/utils/arePrePropertiesEqual.js.map +1 -1
- package/dist/utils/areRenderRangesEqual.d.ts.map +1 -1
- package/dist/utils/areRenderRangesEqual.js +1 -1
- package/dist/utils/areRenderRangesEqual.js.map +1 -1
- package/dist/utils/areSelectionPointsEqual.d.ts.map +1 -1
- package/dist/utils/areSelectionPointsEqual.js +1 -1
- package/dist/utils/areSelectionPointsEqual.js.map +1 -1
- package/dist/utils/areSelectionsEqual.d.ts.map +1 -1
- package/dist/utils/areSelectionsEqual.js +1 -1
- package/dist/utils/areSelectionsEqual.js.map +1 -1
- package/dist/utils/areThemesEqual.d.ts.map +1 -1
- package/dist/utils/areThemesEqual.js +1 -1
- package/dist/utils/areThemesEqual.js.map +1 -1
- package/dist/utils/areVirtualWindowSpecsEqual.d.ts.map +1 -1
- package/dist/utils/areVirtualWindowSpecsEqual.js +1 -1
- package/dist/utils/areVirtualWindowSpecsEqual.js.map +1 -1
- package/dist/utils/areWorkerStatsEqual.d.ts +0 -2
- package/dist/utils/areWorkerStatsEqual.d.ts.map +1 -1
- package/dist/utils/areWorkerStatsEqual.js +1 -1
- package/dist/utils/areWorkerStatsEqual.js.map +1 -1
- package/dist/utils/cleanLastNewline.d.ts.map +1 -1
- package/dist/utils/cleanLastNewline.js +1 -1
- package/dist/utils/cleanLastNewline.js.map +1 -1
- package/dist/utils/computeEstimatedDiffHeights.d.ts.map +1 -1
- package/dist/utils/computeEstimatedDiffHeights.js +1 -2
- package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
- package/dist/utils/computeFileOffsets.d.ts +9 -1
- package/dist/utils/computeFileOffsets.d.ts.map +1 -1
- package/dist/utils/computeFileOffsets.js +20 -2
- package/dist/utils/computeFileOffsets.js.map +1 -1
- package/dist/utils/computeVirtualFileMetrics.d.ts.map +1 -1
- package/dist/utils/computeVirtualFileMetrics.js +1 -2
- package/dist/utils/computeVirtualFileMetrics.js.map +1 -1
- package/dist/utils/createAnnotationElement.d.ts +1 -1
- package/dist/utils/createAnnotationElement.d.ts.map +1 -1
- package/dist/utils/createAnnotationElement.js +1 -2
- package/dist/utils/createAnnotationElement.js.map +1 -1
- package/dist/utils/createAnnotationWrapperNode.d.ts.map +1 -1
- package/dist/utils/createAnnotationWrapperNode.js +1 -1
- package/dist/utils/createAnnotationWrapperNode.js.map +1 -1
- package/dist/utils/createContentColumn.d.ts +1 -1
- package/dist/utils/createContentColumn.d.ts.map +1 -1
- package/dist/utils/createContentColumn.js +1 -2
- package/dist/utils/createContentColumn.js.map +1 -1
- package/dist/utils/createEmptyRowBuffer.d.ts +1 -1
- package/dist/utils/createEmptyRowBuffer.d.ts.map +1 -1
- package/dist/utils/createEmptyRowBuffer.js +1 -2
- package/dist/utils/createEmptyRowBuffer.js.map +1 -1
- package/dist/utils/createFileHeaderElement.d.ts +1 -1
- package/dist/utils/createFileHeaderElement.d.ts.map +1 -1
- package/dist/utils/createFileHeaderElement.js +6 -3
- package/dist/utils/createFileHeaderElement.js.map +1 -1
- package/dist/utils/createGutterUtilityContentNode.d.ts.map +1 -1
- package/dist/utils/createGutterUtilityContentNode.js +1 -1
- package/dist/utils/createGutterUtilityContentNode.js.map +1 -1
- package/dist/utils/createGutterUtilityElement.d.ts +1 -1
- package/dist/utils/createGutterUtilityElement.d.ts.map +1 -1
- package/dist/utils/createGutterUtilityElement.js +1 -2
- package/dist/utils/createGutterUtilityElement.js.map +1 -1
- package/dist/utils/createNoNewlineElement.d.ts +1 -1
- package/dist/utils/createNoNewlineElement.d.ts.map +1 -1
- package/dist/utils/createNoNewlineElement.js +1 -2
- package/dist/utils/createNoNewlineElement.js.map +1 -1
- package/dist/utils/createPreElement.d.ts +1 -1
- package/dist/utils/createPreElement.d.ts.map +1 -1
- package/dist/utils/createPreElement.js +1 -2
- package/dist/utils/createPreElement.js.map +1 -1
- package/dist/utils/createRowNodes.d.ts.map +1 -1
- package/dist/utils/createRowNodes.js +1 -1
- package/dist/utils/createRowNodes.js.map +1 -1
- package/dist/utils/createSeparator.d.ts +1 -1
- package/dist/utils/createSeparator.d.ts.map +1 -1
- package/dist/utils/createSeparator.js +1 -2
- package/dist/utils/createSeparator.js.map +1 -1
- package/dist/utils/createSpanNodeFromToken.d.ts.map +1 -1
- package/dist/utils/createSpanNodeFromToken.js +1 -2
- package/dist/utils/createSpanNodeFromToken.js.map +1 -1
- package/dist/utils/createStyleElement.d.ts +1 -1
- package/dist/utils/createStyleElement.d.ts.map +1 -1
- package/dist/utils/createStyleElement.js +1 -2
- package/dist/utils/createStyleElement.js.map +1 -1
- package/dist/utils/createTransformerWithState.d.ts.map +1 -1
- package/dist/utils/createTransformerWithState.js +1 -2
- package/dist/utils/createTransformerWithState.js.map +1 -1
- package/dist/utils/createUnsafeCSSStyleNode.d.ts.map +1 -1
- package/dist/utils/createUnsafeCSSStyleNode.js +1 -2
- package/dist/utils/createUnsafeCSSStyleNode.js.map +1 -1
- package/dist/utils/createWindowFromScrollPosition.d.ts.map +1 -1
- package/dist/utils/createWindowFromScrollPosition.js +5 -5
- package/dist/utils/createWindowFromScrollPosition.js.map +1 -1
- package/dist/utils/cssWrappers.d.ts.map +1 -1
- package/dist/utils/cssWrappers.js +2 -3
- package/dist/utils/cssWrappers.js.map +1 -1
- package/dist/utils/detachString.d.ts.map +1 -1
- package/dist/utils/detachString.js +1 -1
- package/dist/utils/detachString.js.map +1 -1
- package/dist/utils/diffAcceptRejectHunk.d.ts.map +1 -1
- package/dist/utils/diffAcceptRejectHunk.js +1 -2
- package/dist/utils/diffAcceptRejectHunk.js.map +1 -1
- package/dist/utils/formatCSSVariablePrefix.d.ts.map +1 -1
- package/dist/utils/formatCSSVariablePrefix.js +1 -1
- package/dist/utils/formatCSSVariablePrefix.js.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.js +1 -1
- package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
- package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
- package/dist/utils/getFileRendererOptions.js +1 -1
- package/dist/utils/getFileRendererOptions.js.map +1 -1
- package/dist/utils/getFiletypeFromFileName.d.ts.map +1 -1
- package/dist/utils/getFiletypeFromFileName.js +1 -1
- package/dist/utils/getFiletypeFromFileName.js.map +1 -1
- package/dist/utils/getHighlighterOptions.d.ts.map +1 -1
- package/dist/utils/getHighlighterOptions.js +1 -2
- package/dist/utils/getHighlighterOptions.js.map +1 -1
- package/dist/utils/getHighlighterThemeStyles.d.ts.map +1 -1
- package/dist/utils/getHighlighterThemeStyles.js +1 -2
- package/dist/utils/getHighlighterThemeStyles.js.map +1 -1
- package/dist/utils/getHunkSeparatorSlotName.d.ts.map +1 -1
- package/dist/utils/getHunkSeparatorSlotName.js +1 -1
- package/dist/utils/getHunkSeparatorSlotName.js.map +1 -1
- package/dist/utils/getIconForType.d.ts.map +1 -1
- package/dist/utils/getIconForType.js +1 -1
- package/dist/utils/getIconForType.js.map +1 -1
- package/dist/utils/getLineAnnotationName.d.ts.map +1 -1
- package/dist/utils/getLineAnnotationName.js +1 -1
- package/dist/utils/getLineAnnotationName.js.map +1 -1
- package/dist/utils/getLineEndingType.d.ts.map +1 -1
- package/dist/utils/getLineEndingType.js +1 -1
- package/dist/utils/getLineEndingType.js.map +1 -1
- package/dist/utils/getLineNodes.d.ts +1 -1
- package/dist/utils/getLineNodes.d.ts.map +1 -1
- package/dist/utils/getLineNodes.js +1 -1
- package/dist/utils/getLineNodes.js.map +1 -1
- package/dist/utils/getMergeConflictActionSlotName.d.ts.map +1 -1
- package/dist/utils/getMergeConflictActionSlotName.js +1 -1
- package/dist/utils/getMergeConflictActionSlotName.js.map +1 -1
- package/dist/utils/getMergeConflictLineTypes.d.ts.map +1 -1
- package/dist/utils/getMergeConflictLineTypes.js +1 -2
- package/dist/utils/getMergeConflictLineTypes.js.map +1 -1
- package/dist/utils/getOrCreateCodeNode.d.ts.map +1 -1
- package/dist/utils/getOrCreateCodeNode.js +1 -1
- package/dist/utils/getOrCreateCodeNode.js.map +1 -1
- package/dist/utils/getSingularPatch.d.ts.map +1 -1
- package/dist/utils/getSingularPatch.js +1 -2
- package/dist/utils/getSingularPatch.js.map +1 -1
- package/dist/utils/getThemes.d.ts.map +1 -1
- package/dist/utils/getThemes.js +1 -2
- package/dist/utils/getThemes.js.map +1 -1
- package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
- package/dist/utils/getTotalLineCountFromHunks.js +1 -1
- package/dist/utils/getTotalLineCountFromHunks.js.map +1 -1
- package/dist/utils/hast_utils.d.ts +1 -1
- package/dist/utils/hast_utils.d.ts.map +1 -1
- package/dist/utils/hast_utils.js +1 -1
- package/dist/utils/hast_utils.js.map +1 -1
- package/dist/utils/hostTheme.d.ts.map +1 -1
- package/dist/utils/hostTheme.js +1 -2
- package/dist/utils/hostTheme.js.map +1 -1
- package/dist/utils/includesFileAnnotations.d.ts.map +1 -1
- package/dist/utils/includesFileAnnotations.js +5 -5
- package/dist/utils/includesFileAnnotations.js.map +1 -1
- package/dist/utils/isDefaultRenderRange.d.ts.map +1 -1
- package/dist/utils/isDefaultRenderRange.js +1 -1
- package/dist/utils/isDefaultRenderRange.js.map +1 -1
- package/dist/utils/isDiffPlainText.d.ts.map +1 -1
- package/dist/utils/isDiffPlainText.js +1 -2
- package/dist/utils/isDiffPlainText.js.map +1 -1
- package/dist/utils/isFilePlainText.d.ts.map +1 -1
- package/dist/utils/isFilePlainText.js +1 -2
- package/dist/utils/isFilePlainText.js.map +1 -1
- package/dist/utils/isStyleNode.d.ts.map +1 -1
- package/dist/utils/isStyleNode.js +1 -1
- package/dist/utils/isStyleNode.js.map +1 -1
- package/dist/utils/isWorkerContext.d.ts.map +1 -1
- package/dist/utils/isWorkerContext.js +1 -1
- package/dist/utils/isWorkerContext.js.map +1 -1
- package/dist/utils/iterateOverDiff.d.ts.map +1 -1
- package/dist/utils/iterateOverDiff.js +44 -45
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/normalizeDiffResolution.d.ts.map +1 -1
- package/dist/utils/normalizeDiffResolution.js +1 -1
- package/dist/utils/normalizeDiffResolution.js.map +1 -1
- package/dist/utils/parseDiffDecorations.d.ts.map +1 -1
- package/dist/utils/parseDiffDecorations.js +1 -2
- package/dist/utils/parseDiffDecorations.js.map +1 -1
- package/dist/utils/parseDiffFromFile.d.ts +0 -1
- package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseDiffFromFile.js +1 -2
- package/dist/utils/parseDiffFromFile.js.map +1 -1
- package/dist/utils/parseLineType.d.ts.map +1 -1
- package/dist/utils/parseLineType.js +1 -1
- package/dist/utils/parseLineType.js.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.js +5 -5
- package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +6 -7
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/prefersReducedMotion.d.ts.map +1 -1
- package/dist/utils/prefersReducedMotion.js +1 -1
- package/dist/utils/prefersReducedMotion.js.map +1 -1
- package/dist/utils/prerenderHTMLIfNecessary.d.ts.map +1 -1
- package/dist/utils/prerenderHTMLIfNecessary.js +1 -1
- package/dist/utils/prerenderHTMLIfNecessary.js.map +1 -1
- package/dist/utils/processLine.d.ts +1 -1
- package/dist/utils/processLine.d.ts.map +1 -1
- package/dist/utils/processLine.js +1 -2
- package/dist/utils/processLine.js.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.js +4 -5
- package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
- package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderFileWithHighlighter.js +1 -2
- package/dist/utils/renderFileWithHighlighter.js.map +1 -1
- package/dist/utils/resolveConflict.d.ts.map +1 -1
- package/dist/utils/resolveConflict.js +1 -2
- package/dist/utils/resolveConflict.js.map +1 -1
- package/dist/utils/resolveRegion.d.ts.map +1 -1
- package/dist/utils/resolveRegion.js +1 -1
- package/dist/utils/resolveRegion.js.map +1 -1
- package/dist/utils/roundToDevicePixel.d.ts.map +1 -1
- package/dist/utils/roundToDevicePixel.js +1 -1
- package/dist/utils/roundToDevicePixel.js.map +1 -1
- package/dist/utils/scrollbarGutter.d.ts.map +1 -1
- package/dist/utils/scrollbarGutter.js +1 -2
- package/dist/utils/scrollbarGutter.js.map +1 -1
- package/dist/utils/setLanguageOverride.d.ts.map +1 -1
- package/dist/utils/setLanguageOverride.js +1 -1
- package/dist/utils/setLanguageOverride.js.map +1 -1
- package/dist/utils/setWrapperNodeProps.d.ts.map +1 -1
- package/dist/utils/setWrapperNodeProps.js +1 -1
- package/dist/utils/setWrapperNodeProps.js.map +1 -1
- package/dist/utils/shouldUseTokenTransformer.d.ts.map +1 -1
- package/dist/utils/shouldUseTokenTransformer.js +1 -1
- package/dist/utils/shouldUseTokenTransformer.js.map +1 -1
- package/dist/utils/splitFileContents.d.ts.map +1 -1
- package/dist/utils/splitFileContents.js +1 -2
- package/dist/utils/splitFileContents.js.map +1 -1
- package/dist/utils/trimPatchContext.d.ts.map +1 -1
- package/dist/utils/trimPatchContext.js +1 -2
- package/dist/utils/trimPatchContext.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +2 -1
- package/dist/utils/updateDiffHunks.d.ts.map +1 -1
- package/dist/utils/updateDiffHunks.js +22 -3
- package/dist/utils/updateDiffHunks.js.map +1 -1
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +1 -2
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/utils/wrapTokenFragments.d.ts +1 -1
- package/dist/utils/wrapTokenFragments.d.ts.map +1 -1
- package/dist/utils/wrapTokenFragments.js +1 -2
- package/dist/utils/wrapTokenFragments.js.map +1 -1
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +5 -5
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/getOrCreateWorkerPoolSingleton.d.ts.map +1 -1
- package/dist/worker/getOrCreateWorkerPoolSingleton.js +1 -2
- package/dist/worker/getOrCreateWorkerPoolSingleton.js.map +1 -1
- package/dist/worker/index.js +1 -2
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/wasm-B9ZqxnKj.js +8 -0
- package/dist/worker/wasm-B9ZqxnKj.js.map +1 -0
- package/dist/worker/worker-portable.js +2779 -6403
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +89 -123
- package/dist/worker/worker.js.map +1 -1
- package/package.json +13 -14
- package/dist/worker/wasm-qE0LgnY3.js +0 -10
- package/dist/worker/wasm-qE0LgnY3.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalizeDiffResolution.js","names":[],"sources":["../../src/utils/normalizeDiffResolution.ts"],"sourcesContent":["import type {\n ConflictResolverTypes,\n DiffAcceptRejectHunkConfig,\n DiffAcceptRejectHunkType,\n} from '../types';\n\n// Normalize shorthand and config-object inputs into one internal resolution\n// mode so the rest of the helper only handles the three concrete diff states.\nexport function normalizeDiffResolution(\n options:\n | DiffAcceptRejectHunkType\n | ConflictResolverTypes\n | DiffAcceptRejectHunkConfig\n): 'deletions' | 'additions' | 'both' {\n const type = (() => {\n return typeof options === 'string' ? options : options.type;\n })();\n\n return type === 'accept' || type === 'incoming'\n ? 'additions'\n : type === 'reject' || type === 'current'\n ? 'deletions'\n : 'both';\n}\n"],"mappings":";AAQA,SAAgB,wBACd,SAIoC;CACpC,MAAM,cAAc;
|
|
1
|
+
{"version":3,"file":"normalizeDiffResolution.js","names":[],"sources":["../../src/utils/normalizeDiffResolution.ts"],"sourcesContent":["import type {\n ConflictResolverTypes,\n DiffAcceptRejectHunkConfig,\n DiffAcceptRejectHunkType,\n} from '../types';\n\n// Normalize shorthand and config-object inputs into one internal resolution\n// mode so the rest of the helper only handles the three concrete diff states.\nexport function normalizeDiffResolution(\n options:\n | DiffAcceptRejectHunkType\n | ConflictResolverTypes\n | DiffAcceptRejectHunkConfig\n): 'deletions' | 'additions' | 'both' {\n const type = (() => {\n return typeof options === 'string' ? options : options.type;\n })();\n\n return type === 'accept' || type === 'incoming'\n ? 'additions'\n : type === 'reject' || type === 'current'\n ? 'deletions'\n : 'both';\n}\n"],"mappings":";AAQA,SAAgB,wBACd,SAIoC;CACpC,MAAM,cAAc;EAClB,OAAO,OAAO,YAAY,WAAW,UAAU,QAAQ;CACzD,EAAA,CAAG;CAEH,OAAO,SAAS,YAAY,SAAS,aACjC,cACA,SAAS,YAAY,SAAS,YAC5B,cACA;AACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseDiffDecorations.d.ts","names":[
|
|
1
|
+
{"version":3,"file":"parseDiffDecorations.d.ts","names":[],"sources":["../../src/utils/parseDiffDecorations.ts"],"mappings":";;;;UAIU,6BAAA;EACR,IAAA;EACA,SAAA;EACA,UAAA;AAAA;AAAA,iBAGc,wBAAA;EACd,IAAA;EACA,SAAA;EACA;AAAA,GACC,6BAAA,GAAgC,cAAA;AAAA,UASzB,mBAAA;EACR,IAAA,EAAM,YAAY;EAClB,GAAA;EACA,UAAA;EACA,SAAA;EACA,UAAA;AAAA;AAAA,iBAQc,cAAA;EACd,IAAA;EACA,GAAA;EACA,UAAA;EACA,SAAA;EACA;AAAA,GACC,mBAAA"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import "diff";
|
|
2
|
-
|
|
3
2
|
//#region src/utils/parseDiffDecorations.ts
|
|
4
3
|
function createDiffSpanDecoration({ line, spanStart, spanLength }) {
|
|
5
4
|
return {
|
|
@@ -28,7 +27,7 @@ function pushOrJoinSpan({ item, arr, enableJoin, isNeutral = false, isLastItem =
|
|
|
28
27
|
}
|
|
29
28
|
arr.push([isNeutral ? 0 : 1, item.value]);
|
|
30
29
|
}
|
|
31
|
-
|
|
32
30
|
//#endregion
|
|
33
31
|
export { createDiffSpanDecoration, pushOrJoinSpan };
|
|
32
|
+
|
|
34
33
|
//# sourceMappingURL=parseDiffDecorations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseDiffDecorations.js","names":[],"sources":["../../src/utils/parseDiffDecorations.ts"],"sourcesContent":["import { type ChangeObject } from 'diff';\n\nimport type { DecorationItem } from '../types';\n\ninterface CreateDiffSpanDecorationProps {\n line: number;\n spanStart: number;\n spanLength: number;\n}\n\nexport function createDiffSpanDecoration({\n line,\n spanStart,\n spanLength,\n}: CreateDiffSpanDecorationProps): DecorationItem {\n return {\n start: { line, character: spanStart },\n end: { line, character: spanStart + spanLength },\n properties: { 'data-diff-span': '' },\n alwaysWrap: true,\n };\n}\n\ninterface PushOrJoinSpanProps {\n item: ChangeObject<string>;\n arr: [0 | 1, string][];\n enableJoin: boolean;\n isNeutral?: boolean;\n isLastItem?: boolean;\n}\n\n// For diff decoration spans, we want to be sure that if there is a single\n// white-space gap between diffs that we join them together into a longer diff span.\n// Spans are basically just a tuple - 1 means the content should be\n// highlighted, 0 means it should not, we still need to the span data to figure\n// out span positions\nexport function pushOrJoinSpan({\n item,\n arr,\n enableJoin,\n isNeutral = false,\n isLastItem = false,\n}: PushOrJoinSpanProps): void {\n const lastItem = arr[arr.length - 1];\n if (lastItem == null || isLastItem || !enableJoin) {\n arr.push([isNeutral ? 0 : 1, item.value]);\n return;\n }\n const isLastItemNeutral = lastItem[0] === 0;\n if (\n isNeutral === isLastItemNeutral ||\n // If we have a single space neutral item, lets join it to a previous\n // space non-neutral item to avoid single space gaps\n (isNeutral && item.value.length === 1 && !isLastItemNeutral)\n ) {\n lastItem[1] += item.value;\n return;\n }\n arr.push([isNeutral ? 0 : 1, item.value]);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"parseDiffDecorations.js","names":[],"sources":["../../src/utils/parseDiffDecorations.ts"],"sourcesContent":["import { type ChangeObject } from 'diff';\n\nimport type { DecorationItem } from '../types';\n\ninterface CreateDiffSpanDecorationProps {\n line: number;\n spanStart: number;\n spanLength: number;\n}\n\nexport function createDiffSpanDecoration({\n line,\n spanStart,\n spanLength,\n}: CreateDiffSpanDecorationProps): DecorationItem {\n return {\n start: { line, character: spanStart },\n end: { line, character: spanStart + spanLength },\n properties: { 'data-diff-span': '' },\n alwaysWrap: true,\n };\n}\n\ninterface PushOrJoinSpanProps {\n item: ChangeObject<string>;\n arr: [0 | 1, string][];\n enableJoin: boolean;\n isNeutral?: boolean;\n isLastItem?: boolean;\n}\n\n// For diff decoration spans, we want to be sure that if there is a single\n// white-space gap between diffs that we join them together into a longer diff span.\n// Spans are basically just a tuple - 1 means the content should be\n// highlighted, 0 means it should not, we still need to the span data to figure\n// out span positions\nexport function pushOrJoinSpan({\n item,\n arr,\n enableJoin,\n isNeutral = false,\n isLastItem = false,\n}: PushOrJoinSpanProps): void {\n const lastItem = arr[arr.length - 1];\n if (lastItem == null || isLastItem || !enableJoin) {\n arr.push([isNeutral ? 0 : 1, item.value]);\n return;\n }\n const isLastItemNeutral = lastItem[0] === 0;\n if (\n isNeutral === isLastItemNeutral ||\n // If we have a single space neutral item, lets join it to a previous\n // space non-neutral item to avoid single space gaps\n (isNeutral && item.value.length === 1 && !isLastItemNeutral)\n ) {\n lastItem[1] += item.value;\n return;\n }\n arr.push([isNeutral ? 0 : 1, item.value]);\n}\n"],"mappings":";;AAUA,SAAgB,yBAAyB,EACvC,MACA,WACA,cACgD;CAChD,OAAO;EACL,OAAO;GAAE;GAAM,WAAW;EAAU;EACpC,KAAK;GAAE;GAAM,WAAW,YAAY;EAAW;EAC/C,YAAY,EAAE,kBAAkB,GAAG;EACnC,YAAY;CACd;AACF;AAeA,SAAgB,eAAe,EAC7B,MACA,KACA,YACA,YAAY,OACZ,aAAa,SACe;CAC5B,MAAM,WAAW,IAAI,IAAI,SAAS;CAClC,IAAI,YAAY,QAAQ,cAAc,CAAC,YAAY;EACjD,IAAI,KAAK,CAAC,YAAY,IAAI,GAAG,KAAK,KAAK,CAAC;EACxC;CACF;CACA,MAAM,oBAAoB,SAAS,OAAO;CAC1C,IACE,cAAc,qBAGb,aAAa,KAAK,MAAM,WAAW,KAAK,CAAC,mBAC1C;EACA,SAAS,MAAM,KAAK;EACpB;CACF;CACA,IAAI,KAAK,CAAC,YAAY,IAAI,GAAG,KAAK,KAAK,CAAC;AAC1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseDiffFromFile.d.ts","names":[
|
|
1
|
+
{"version":3,"file":"parseDiffFromFile.d.ts","names":[],"sources":["../../src/utils/parseDiffFromFile.ts"],"mappings":";;;;;;AAWA;;;;iBAAgB,iBAAA,CAGd,OAAA,EAAS,YAAA,EACT,OAAA,EAAS,YAAA,EACT,OAAA,GAAU,8BAAA,EACV,YAAA,aACC,gBAAA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { processFile } from "./parsePatchFiles.js";
|
|
2
2
|
import { createTwoFilesPatch } from "diff";
|
|
3
|
-
|
|
4
3
|
//#region src/utils/parseDiffFromFile.ts
|
|
5
4
|
/**
|
|
6
5
|
* Parses a diff from two file contents objects.
|
|
@@ -21,7 +20,7 @@ function parseDiffFromFile(oldFile, newFile, options, throwOnError = false) {
|
|
|
21
20
|
if (newFile.lang != null) fileData.lang = newFile.lang;
|
|
22
21
|
return fileData;
|
|
23
22
|
}
|
|
24
|
-
|
|
25
23
|
//#endregion
|
|
26
24
|
export { parseDiffFromFile };
|
|
25
|
+
|
|
27
26
|
//# sourceMappingURL=parseDiffFromFile.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseDiffFromFile.js","names":[],"sources":["../../src/utils/parseDiffFromFile.ts"],"sourcesContent":["import { type CreatePatchOptionsNonabortable, createTwoFilesPatch } from 'diff';\n\nimport type { FileContents, FileDiffMetadata } from '../types';\nimport { processFile } from './parsePatchFiles';\n\n/**\n * Parses a diff from two file contents objects.\n *\n * If both `oldFile` and `newFile` have a `cacheKey`, the resulting diff will\n * automatically get a combined cache key in the format `oldKey:newKey`.\n */\nexport function parseDiffFromFile(\n // FIXME(amadeus): oldFile/newFile should be optional to simulate new/deleted\n // files\n oldFile: FileContents,\n newFile: FileContents,\n options?: CreatePatchOptionsNonabortable,\n throwOnError = false\n): FileDiffMetadata {\n const patch = createTwoFilesPatch(\n oldFile.name,\n newFile.name,\n oldFile.contents,\n newFile.contents,\n oldFile.header,\n newFile.header,\n options\n );\n\n const fileData = processFile(patch, {\n cacheKey: (() => {\n if (oldFile.cacheKey != null && newFile.cacheKey != null) {\n return `${oldFile.cacheKey}:${newFile.cacheKey}`;\n }\n return undefined;\n })(),\n oldFile,\n newFile,\n throwOnError,\n });\n if (fileData == null) {\n throw new Error(\n 'parseDiffFrom: FileInvalid diff -- probably need to fix something -- if the files are the same maybe?'\n );\n }\n // If we've been provided an override for language in the newFile, let’s pass\n // it through to FileDiffMetadata.\n if (newFile.lang != null) {\n fileData.lang = newFile.lang;\n }\n return fileData;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"parseDiffFromFile.js","names":[],"sources":["../../src/utils/parseDiffFromFile.ts"],"sourcesContent":["import { type CreatePatchOptionsNonabortable, createTwoFilesPatch } from 'diff';\n\nimport type { FileContents, FileDiffMetadata } from '../types';\nimport { processFile } from './parsePatchFiles';\n\n/**\n * Parses a diff from two file contents objects.\n *\n * If both `oldFile` and `newFile` have a `cacheKey`, the resulting diff will\n * automatically get a combined cache key in the format `oldKey:newKey`.\n */\nexport function parseDiffFromFile(\n // FIXME(amadeus): oldFile/newFile should be optional to simulate new/deleted\n // files\n oldFile: FileContents,\n newFile: FileContents,\n options?: CreatePatchOptionsNonabortable,\n throwOnError = false\n): FileDiffMetadata {\n const patch = createTwoFilesPatch(\n oldFile.name,\n newFile.name,\n oldFile.contents,\n newFile.contents,\n oldFile.header,\n newFile.header,\n options\n );\n\n const fileData = processFile(patch, {\n cacheKey: (() => {\n if (oldFile.cacheKey != null && newFile.cacheKey != null) {\n return `${oldFile.cacheKey}:${newFile.cacheKey}`;\n }\n return undefined;\n })(),\n oldFile,\n newFile,\n throwOnError,\n });\n if (fileData == null) {\n throw new Error(\n 'parseDiffFrom: FileInvalid diff -- probably need to fix something -- if the files are the same maybe?'\n );\n }\n // If we've been provided an override for language in the newFile, let’s pass\n // it through to FileDiffMetadata.\n if (newFile.lang != null) {\n fileData.lang = newFile.lang;\n }\n return fileData;\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,kBAGd,SACA,SACA,SACA,eAAe,OACG;CAWlB,MAAM,WAAW,YAVH,oBACZ,QAAQ,MACR,QAAQ,MACR,QAAQ,UACR,QAAQ,UACR,QAAQ,QACR,QAAQ,QACR,OAG+B,GAAG;EAClC,iBAAiB;GACf,IAAI,QAAQ,YAAY,QAAQ,QAAQ,YAAY,MAClD,OAAO,GAAG,QAAQ,SAAS,GAAG,QAAQ;EAG1C,EAAA,CAAG;EACH;EACA;EACA;CACF,CAAC;CACD,IAAI,YAAY,MACd,MAAM,IAAI,MACR,uGACF;CAIF,IAAI,QAAQ,QAAQ,MAClB,SAAS,OAAO,QAAQ;CAE1B,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseLineType.d.ts","names":[
|
|
1
|
+
{"version":3,"file":"parseLineType.d.ts","names":[],"sources":["../../src/utils/parseLineType.ts"],"mappings":";;;UAEiB,UAAA;EACf,IAAA;EACA,IAAA,EAAM,OAAO,CAAC,YAAA;AAAA;AAAA,iBAGA,aAAA,CAAc,IAAA,WAAe,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseLineType.js","names":[],"sources":["../../src/utils/parseLineType.ts"],"sourcesContent":["import type { HunkLineType } from '../types';\n\nexport interface ParsedLine {\n line: string;\n type: Exclude<HunkLineType, 'expanded'>;\n}\n\nexport function parseLineType(line: string): ParsedLine | undefined {\n const firstChar = line[0];\n if (\n firstChar !== '+' &&\n firstChar !== '-' &&\n firstChar !== ' ' &&\n firstChar !== '\\\\'\n ) {\n console.error(\n `parseLineType: Invalid firstChar: \"${firstChar}\", full line: \"${line}\"`\n );\n return undefined;\n }\n const processedLine = line.substring(1);\n return {\n // NOTE(amadeus): If the line is empty, we should make it a\n // newline to force shiki to highlight the row. This should\n // only really ever apply as the last line of a hunk that was most likely\n // processed via a string and not a file since patch files will include a\n // newline here by default\n line: processedLine === '' ? '\\n' : processedLine,\n type:\n firstChar === ' '\n ? 'context'\n : firstChar === '\\\\'\n ? 'metadata'\n : firstChar === '+'\n ? 'addition'\n : 'deletion',\n };\n}\n"],"mappings":";AAOA,SAAgB,cAAc,MAAsC;CAClE,MAAM,YAAY,KAAK;
|
|
1
|
+
{"version":3,"file":"parseLineType.js","names":[],"sources":["../../src/utils/parseLineType.ts"],"sourcesContent":["import type { HunkLineType } from '../types';\n\nexport interface ParsedLine {\n line: string;\n type: Exclude<HunkLineType, 'expanded'>;\n}\n\nexport function parseLineType(line: string): ParsedLine | undefined {\n const firstChar = line[0];\n if (\n firstChar !== '+' &&\n firstChar !== '-' &&\n firstChar !== ' ' &&\n firstChar !== '\\\\'\n ) {\n console.error(\n `parseLineType: Invalid firstChar: \"${firstChar}\", full line: \"${line}\"`\n );\n return undefined;\n }\n const processedLine = line.substring(1);\n return {\n // NOTE(amadeus): If the line is empty, we should make it a\n // newline to force shiki to highlight the row. This should\n // only really ever apply as the last line of a hunk that was most likely\n // processed via a string and not a file since patch files will include a\n // newline here by default\n line: processedLine === '' ? '\\n' : processedLine,\n type:\n firstChar === ' '\n ? 'context'\n : firstChar === '\\\\'\n ? 'metadata'\n : firstChar === '+'\n ? 'addition'\n : 'deletion',\n };\n}\n"],"mappings":";AAOA,SAAgB,cAAc,MAAsC;CAClE,MAAM,YAAY,KAAK;CACvB,IACE,cAAc,OACd,cAAc,OACd,cAAc,OACd,cAAc,MACd;EACA,QAAQ,MACN,sCAAsC,UAAU,iBAAiB,KAAK,EACxE;EACA;CACF;CACA,MAAM,gBAAgB,KAAK,UAAU,CAAC;CACtC,OAAO;EAML,MAAM,kBAAkB,KAAK,OAAO;EACpC,MACE,cAAc,MACV,YACA,cAAc,OACZ,aACA,cAAc,MACZ,aACA;CACZ;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseMergeConflictDiffFromFile.d.ts","names":[
|
|
1
|
+
{"version":3,"file":"parseMergeConflictDiffFromFile.d.ts","names":[],"sources":["../../src/utils/parseMergeConflictDiffFromFile.ts"],"mappings":";;;UAkDiB,oCAAA;EACf,QAAA,EAAU,gBAAA;EACV,WAAA,EAAa,YAAA;EACb,YAAA,EAAc,YAAA;EACd,OAAA,GAAU,uBAAA;EACV,UAAA,EAAY,sBAAA;AAAA;AAAA,UAGG,uBAAA,SAAgC,uBAAuB;EAGtE,QAAA,EAAU,mBAAA;EACV,aAAA;EACA,WAAA;IACE,KAAA;IACA,IAAA;IACA,SAAA;IACA,GAAA;EAAA;AAAA;AAAA,UAIM,kCAAA;EACR,SAAA;EACA,SAAS;AAAA;AAAA,iBAqGK,4BAAA,CACd,MAAA,EAAQ,uBAAA,EACR,QAAA,EAAU,gBAAA,GACT,kCAAA;AAAA,iBAoBa,8BAAA,CACd,IAAA,EAAM,YAAA,EACN,eAAA,YACC,oCAAoC;AAAA,iBAmzBvB,4BAAA,CACd,QAAA,EAAU,gBAAA,EACV,OAAA,GAAU,uBAAA,kBACT,sBAAA"}
|
|
@@ -451,16 +451,16 @@ function buildMergeConflictMarkerRows(fileDiff, actions) {
|
|
|
451
451
|
const actionLineIndex = getLineStart(action.hunkIndex, action.startContentIndex);
|
|
452
452
|
markerRows.push(createMergeConflictMarkerRow(action, "marker-start", action.startContentIndex, action.markerLines.start, actionLineIndex));
|
|
453
453
|
if (action.baseContentIndex != null) {
|
|
454
|
-
const currentContentIndex
|
|
454
|
+
const currentContentIndex = action.currentContentIndex;
|
|
455
455
|
const incomingContentIndex = action.incomingContentIndex;
|
|
456
|
-
if (currentContentIndex
|
|
456
|
+
if (currentContentIndex == null || incomingContentIndex == null) continue;
|
|
457
457
|
const baseMarkerLine = action.markerLines.base;
|
|
458
458
|
if (baseMarkerLine == null) continue;
|
|
459
|
-
const currentChange = hunk.hunkContent[currentContentIndex
|
|
459
|
+
const currentChange = hunk.hunkContent[currentContentIndex];
|
|
460
460
|
const baseContext = hunk.hunkContent[action.baseContentIndex];
|
|
461
461
|
const incomingChange = hunk.hunkContent[incomingContentIndex];
|
|
462
462
|
if (currentChange?.type !== "change" || baseContext?.type !== "context" || incomingChange?.type !== "change") continue;
|
|
463
|
-
const currentStart = getLineStart(action.hunkIndex, currentContentIndex
|
|
463
|
+
const currentStart = getLineStart(action.hunkIndex, currentContentIndex);
|
|
464
464
|
const incomingStart = getLineStart(action.hunkIndex, incomingContentIndex);
|
|
465
465
|
markerRows.push(createMergeConflictMarkerRow(action, "marker-base", action.baseContentIndex, baseMarkerLine, currentStart + currentChange.deletions));
|
|
466
466
|
markerRows.push(createMergeConflictMarkerRow(action, "marker-separator", action.baseContentIndex, action.markerLines.separator, incomingStart), createMergeConflictMarkerRow(action, "marker-end", action.endMarkerContentIndex, action.markerLines.end, getLineEnd(action.hunkIndex, action.endMarkerContentIndex)));
|
|
@@ -494,7 +494,7 @@ function getUnifiedLineStartForContent(hunk, contentIndex) {
|
|
|
494
494
|
}
|
|
495
495
|
return lineIndex;
|
|
496
496
|
}
|
|
497
|
-
|
|
498
497
|
//#endregion
|
|
499
498
|
export { buildMergeConflictMarkerRows, getMergeConflictActionAnchor, parseMergeConflictDiffFromFile };
|
|
499
|
+
|
|
500
500
|
//# sourceMappingURL=parseMergeConflictDiffFromFile.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseMergeConflictDiffFromFile.js","names":["s: ParseState","type: FileDiffMetadata['type']","fileDiff: FileDiffMetadata","contentIndex: number","finalizedHunk: Hunk","nextBaseConflicts: Map<number, number> | undefined","markerRows: MergeConflictMarkerRow[]","hunkLineStartCache: (number[] | undefined)[]","currentContentIndex"],"sources":["../../src/utils/parseMergeConflictDiffFromFile.ts"],"sourcesContent":["// Parses a file containing git merge conflict markers (<<<<<<< / ======= / >>>>>>>)\n// into a synthetic unified diff. The core idea: treat the conflict file as though\n// \"current\" lines are deletions and \"incoming\" lines are additions. Lines outside\n// conflicts (and optional \"base\" sections from diff3) become shared context.\n//\n// The result is a standard FileDiffMetadata with hunks — identical in shape to what\n// you'd get from parsing a real unified diff — plus a parallel array of\n// MergeConflictDiffActions that anchor each conflict region to positions within the\n// hunk structure. Downstream consumers (e.g. the merge conflict UI) use these\n// anchors to overlay conflict markers onto the diff view.\n//\n// Architecture note: all helper functions are module-level (not closures inside the\n// main function) and receive a shared ParseState object by reference. This avoids\n// per-call scope-chain traversal on the hot path (~20K lines), where every line\n// triggers 2-3 helper calls.\n//\n// ---\n// NOTE: This file was nearly entirely written and optimized by AI. It has a\n// verification harness that any future changes (human or AI) should be validated\n// against:\n//\n// Snapshot tests (from packages/diffs/):\n// bun test parseMergeConflictDiffFromFile\n//\n// Performance benchmark (checksum must match 33121550):\n// moonx diffs:benchmark-parse-merge-conflict\n//\n// If you encounter a bug:\n// 1. Add a new test case in test/parseMergeConflictDiffFromFile.test.ts with\n// input that reproduces the failure. Use toMatchSnapshot() so the expected\n// output is captured automatically once fixed.\n// 2. Run `bun test parseMergeConflictDiffFromFile` from packages/diffs/ to\n// confirm the new test fails.\n// 3. Use an AI agent with extended/high thinking to fix the logic — the\n// snapshot tests and benchmark provide a tight feedback loop. The agent\n// should iterate until all snapshots pass AND the benchmark checksum\n// matches. Update snapshots with `bun test test/parseMergeConflictDiffFromFile.test.ts -u`\n// only after verifying the new output is correct.\n// ---\n\nimport type {\n FileContents,\n FileDiffMetadata,\n Hunk,\n MergeConflictMarkerRow,\n MergeConflictMarkerRowType,\n MergeConflictRegion,\n ProcessFileConflictData,\n} from '../types';\n\nexport interface ParseMergeConflictDiffFromFileResult {\n fileDiff: FileDiffMetadata;\n currentFile: FileContents;\n incomingFile: FileContents;\n actions: (MergeConflictDiffAction | undefined)[];\n markerRows: MergeConflictMarkerRow[];\n}\n\nexport interface MergeConflictDiffAction extends ProcessFileConflictData {\n // Kept for callback consumers that still need the original unresolved-region\n // source-line coordinates alongside structural hunk-content anchors.\n conflict: MergeConflictRegion;\n conflictIndex: number;\n markerLines: {\n start: string;\n base?: string;\n separator: string;\n end: string;\n };\n}\n\ninterface GetMergeConflictActionAnchorReturn {\n hunkIndex: number;\n lineIndex: number;\n}\n\n// Which section of a conflict we're currently inside while scanning lines.\n// Progresses: current → (optional) base → incoming.\ntype MergeConflictStage = 'current' | 'base' | 'incoming';\ntype MergeConflictSide = MergeConflictStage;\ntype MergeConflictMarkerType = 'start' | 'base' | 'separator' | 'end';\n\n// Controls how buffered context lines are trimmed when flushed to hunkContent:\n// 'leading' — first flush of a hunk; trim excess from the start\n// 'before-change' — flush between changes; emit all buffered lines\n// 'trailing' — last flush of a hunk; trim excess from the end\ntype ContextFlushMode = 'before-change' | 'leading' | 'trailing';\n\n// Mutable accumulator for building a single Hunk. Tracks line counts, the\n// hunkContent array (sequence of context/change groups), and a \"context buffer\"\n// that defers writing context lines until we know whether they're leading,\n// trailing, or mid-hunk context.\n//\n// The context buffer avoids eagerly committing context lines to hunkContent.\n// When a change line arrives, we flush the buffer — trimming to maxContextLines\n// if it's the leading or trailing edge of a hunk, or splitting into two hunks\n// if the gap between changes exceeds maxContextLines * 2.\ninterface HunkBuilder {\n additionStart: number;\n deletionStart: number;\n additionCount: number;\n deletionCount: number;\n additionLines: number;\n deletionLines: number;\n additionLineIndex: number;\n deletionLineIndex: number;\n hunkContent: Hunk['hunkContent'];\n // Context buffer: instead of storing per-line index arrays, we track the\n // starting indices and a count. Since context lines always push to both\n // additionLines and deletionLines consecutively, indices can be derived.\n contextBufferAdditionStart: number;\n contextBufferDeletionStart: number;\n contextBufferCount: number;\n // Sparse map of buffer-offset → conflictIndex for base-section context lines.\n // Empty for most buffers since base lines are rare.\n contextBufferBaseConflicts: Map<number, number> | undefined;\n}\n\n// Tracks an in-progress conflict as we scan through its lines. Pushed onto\n// conflictStack when we hit a <<<<<<< marker, and popped + finalized when we\n// hit the matching >>>>>>> marker. The `stage` field tells processLine which\n// section we're in so it knows whether to emit deletions, context, or additions.\ninterface ConflictFrame {\n conflictIndex: number;\n stage: MergeConflictStage;\n startLineIndex: number;\n baseMarkerLineIndex?: number;\n separatorLineIndex?: number;\n markerLines: {\n start: string;\n base?: string;\n separator?: string;\n };\n}\n\ninterface ConflictActionBuilder {\n action: MergeConflictDiffAction;\n completed: boolean;\n}\n\n// Bundles all mutable state shared across parse helper functions, replacing\n// closure-captured variables with a single object passed by reference.\n//\n// The two key arrays — deletionLines and additionLines — are the synthetic\n// \"before\" and \"after\" file contents. Context lines are pushed to both arrays\n// (identical on both sides). Current-side conflict lines go only into\n// deletionLines; incoming-side lines go only into additionLines. After parsing,\n// joining each array produces the resolved file for that side.\ninterface ParseState {\n // \"Before\" file lines (context + current-side conflict content).\n deletionLines: string[];\n // \"After\" file lines (context + incoming-side conflict content).\n additionLines: string[];\n // Stack of open conflict regions (supports nested conflicts, though rare).\n conflictStack: ConflictFrame[];\n // Parallel to actions[]; accumulates content indices during parsing.\n conflictBuilders: ConflictActionBuilder[];\n // Final output: one action per conflict, indexed by conflictIndex.\n actions: (MergeConflictDiffAction | undefined)[];\n // Finalized hunks, appended as context gaps cause hunk splits.\n hunks: Hunk[];\n nextConflictIndex: number;\n // Running line totals used to compute hunk splitLineStart/unifiedLineStart.\n splitLineCount: number;\n unifiedLineCount: number;\n // 1-based line number where the previous hunk ended (for collapsedBefore).\n lastHunkEnd: number;\n // The hunk currently being built; undefined between hunks.\n activeHunk: HunkBuilder | undefined;\n maxContextLines: number;\n // Cached maxContextLines * 2 (the threshold for splitting a hunk).\n maxContextLines2: number;\n}\n\nexport function getMergeConflictActionAnchor(\n action: MergeConflictDiffAction,\n fileDiff: FileDiffMetadata\n): GetMergeConflictActionAnchorReturn | undefined {\n const hunk = fileDiff.hunks[action.hunkIndex];\n if (hunk == null) {\n return undefined;\n }\n return {\n hunkIndex: action.hunkIndex,\n lineIndex: getUnifiedLineStartForContent(hunk, action.startContentIndex),\n };\n}\n\n// Main entry point. Walks every line of the conflict file exactly once,\n// dispatching each line through processLine which routes it to the appropriate\n// emitter (context or change). After the loop, finalizes the last hunk,\n// validates all conflicts were closed, and assembles the result.\n//\n// The three phases are:\n// 1. Line-by-line scan — builds hunks and conflict actions incrementally\n// 2. Post-loop cleanup — flushes trailing context, finalizes last hunk\n// 3. Result assembly — joins line arrays, builds marker rows for the UI\nexport function parseMergeConflictDiffFromFile(\n file: FileContents,\n maxContextLines: number = 6\n): ParseMergeConflictDiffFromFileResult {\n // Never allow maxContextLines to drop below 1 or else things break.\n maxContextLines = Math.max(maxContextLines, 1);\n\n const s: ParseState = {\n deletionLines: [],\n additionLines: [],\n conflictStack: [],\n conflictBuilders: [],\n actions: [],\n hunks: [],\n nextConflictIndex: 0,\n splitLineCount: 0,\n unifiedLineCount: 0,\n lastHunkEnd: 0,\n activeHunk: undefined,\n maxContextLines,\n maxContextLines2: maxContextLines * 2,\n };\n\n // Phase 1: Line-by-line scan. We inline the indexOf loop here (rather than\n // calling a helper with a callback) to avoid creating a closure on the hot\n // path. Each line is sliced and dispatched to processLine.\n const contents = file.contents;\n const contentLength = contents.length;\n if (contentLength > 0) {\n let lineStart = 0;\n let lineIndex = 0;\n let newlinePos = contents.indexOf('\\n', lineStart);\n while (newlinePos !== -1) {\n processLine(s, contents.slice(lineStart, newlinePos + 1), lineIndex);\n lineStart = newlinePos + 1;\n lineIndex++;\n newlinePos = contents.indexOf('\\n', lineStart);\n }\n if (lineStart < contentLength) {\n processLine(s, contents.slice(lineStart), lineIndex);\n }\n }\n\n // Phase 2: Post-loop cleanup. Any unclosed conflict is an error. If the\n // last hunk has buffered context lines, flush them as trailing context and\n // finalize the hunk.\n if (s.conflictStack.length > 0) {\n throw new Error(\n 'parseMergeConflictDiffFromFile: unfinished merge conflict marker stack'\n );\n }\n\n if (s.activeHunk != null && s.activeHunk.hunkContent.length > 0) {\n flushBufferedContext(s, s.activeHunk, 'trailing');\n finalizeActiveHunk(s);\n }\n\n for (\n let conflictIndex = 0;\n conflictIndex < s.conflictBuilders.length;\n conflictIndex++\n ) {\n const builder = s.conflictBuilders[conflictIndex];\n if (builder == null || !builder.completed) {\n throw new Error(\n `parseMergeConflictDiffFromFile: failed to build merge conflict action ${conflictIndex}`\n );\n }\n }\n\n // Phase 3: Result assembly. Account for any collapsed lines after the last\n // hunk, then join the line arrays to produce resolved file contents.\n if (\n s.hunks.length > 0 &&\n s.additionLines.length > 0 &&\n s.deletionLines.length > 0\n ) {\n const lastHunk = s.hunks[s.hunks.length - 1];\n const collapsedAfter = Math.max(\n s.additionLines.length -\n (lastHunk.additionStart + lastHunk.additionCount - 1),\n 0\n );\n s.splitLineCount += collapsedAfter;\n s.unifiedLineCount += collapsedAfter;\n }\n\n const currentContents = s.deletionLines.join('');\n const incomingContents = s.additionLines.join('');\n const currentFile = createResolvedConflictFile(\n file,\n 'current',\n currentContents\n );\n const incomingFile = createResolvedConflictFile(\n file,\n 'incoming',\n incomingContents\n );\n\n let type: FileDiffMetadata['type'] = 'change';\n if (incomingContents === '') {\n type = 'deleted';\n } else if (currentContents === '') {\n type = 'new';\n }\n\n const fileDiff: FileDiffMetadata = {\n name: file.name,\n prevName: undefined,\n type,\n hunks: s.hunks,\n splitLineCount: s.splitLineCount,\n unifiedLineCount: s.unifiedLineCount,\n isPartial: false,\n deletionLines: s.deletionLines,\n additionLines: s.additionLines,\n cacheKey:\n file.cacheKey != null\n ? `${file.cacheKey}:merge-conflict-diff`\n : undefined,\n };\n\n return {\n fileDiff,\n currentFile,\n incomingFile,\n actions: s.actions,\n markerRows: buildMergeConflictMarkerRows(fileDiff, s.actions),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Module-level parse helpers. Each receives ParseState by reference rather\n// than capturing variables via closure. The call graph from the hot path is:\n//\n// processLine\n// ├─ emitContextLine → ensureActiveHunk\n// ├─ emitChangeLine → ensureActiveHunk, splitHunkWithBufferedContext,\n// │ flushBufferedContext, appendChangeLine,\n// │ assignConflictContent\n// ├─ handleStartMarker\n// └─ finalizeConflict\n// ---------------------------------------------------------------------------\n\n// Routes a single source line to the right emitter based on whether we're\n// inside a conflict and, if so, which section (current/base/incoming).\n// Outside conflicts, only the start marker (<<<<<<< / charCode 60) can\n// change state, so we skip the full marker check for non-'<' lines.\nfunction processLine(s: ParseState, line: string, index: number): void {\n const frame = s.conflictStack[s.conflictStack.length - 1];\n\n // Outside any conflict: only start markers (<<<<<<<) can transition state.\n // Skip the full marker check for lines that can't be start markers.\n if (frame == null) {\n if (\n line.length >= 7 &&\n line.charCodeAt(0) === 60 &&\n getMergeConflictMarkerType(line) === 'start'\n ) {\n handleStartMarker(s, line, index);\n return;\n }\n emitContextLine(s, line);\n return;\n }\n\n // Inside a conflict: all marker types must be checked.\n const markerType = getMergeConflictMarkerType(line);\n\n if (markerType === 'start') {\n handleStartMarker(s, line, index);\n return;\n }\n\n if (markerType === 'base') {\n frame.stage = 'base';\n frame.baseMarkerLineIndex = index;\n frame.markerLines.base = line;\n return;\n }\n\n if (markerType === 'separator') {\n frame.stage = 'incoming';\n frame.separatorLineIndex = index;\n frame.markerLines.separator = line;\n return;\n }\n\n if (markerType === 'end') {\n const completedFrame = s.conflictStack.pop();\n if (completedFrame == null) {\n throw new Error(\n 'parseMergeConflictDiffFromFile: encountered end marker before start marker'\n );\n }\n finalizeConflict(s, completedFrame, index, line);\n return;\n }\n\n if (frame.stage === 'current') {\n emitChangeLine(s, 'deletion', line, frame.conflictIndex, 'current');\n } else if (frame.stage === 'base') {\n emitContextLine(s, line, frame.conflictIndex);\n } else {\n emitChangeLine(s, 'addition', line, frame.conflictIndex, 'incoming');\n }\n}\n\n// Lazily creates the active HunkBuilder if one doesn't exist yet. The hunk's\n// start positions are derived from the current length of the line arrays\n// (1-based, matching unified diff conventions).\nfunction ensureActiveHunk(s: ParseState): HunkBuilder {\n s.activeHunk ??= createHunkBuilder(\n s.additionLines.length + 1,\n s.deletionLines.length + 1\n );\n return s.activeHunk;\n}\n\n// \"Anchors\" a conflict to its position in the hunk's content array. Each\n// conflict needs to know which hunk it lives in (hunkIndex) and which content\n// entries correspond to its current/base/incoming sections. This is called\n// every time we emit a change or context line that belongs to a conflict, and\n// it incrementally widens the start/end content range.\nfunction assignConflictContent(\n s: ParseState,\n conflictIndex: number,\n role: MergeConflictSide,\n contentIndex: number\n): void {\n const builder = s.conflictBuilders[conflictIndex];\n if (builder == null) {\n throw new Error(\n `parseMergeConflictDiffFromFile: failed to locate conflict action ${conflictIndex}`\n );\n }\n\n const action = builder.action;\n const hunkIndex = s.hunks.length;\n if (action.hunkIndex < 0) {\n action.hunkIndex = hunkIndex;\n } else if (action.hunkIndex !== hunkIndex) {\n throw new Error(\n `parseMergeConflictDiffFromFile: conflict ${conflictIndex} spans multiple hunks and cannot be anchored`\n );\n }\n\n if (action.startContentIndex < 0) {\n action.startContentIndex = contentIndex;\n }\n action.endContentIndex = contentIndex;\n action.endMarkerContentIndex = contentIndex;\n\n if (role === 'current') {\n action.currentContentIndex ??= contentIndex;\n return;\n }\n if (role === 'base') {\n action.baseContentIndex ??= contentIndex;\n return;\n }\n action.incomingContentIndex = contentIndex;\n}\n\n// Appends a change line to the hunk's content array. If the previous entry is\n// already a 'change' group, we just bump its addition/deletion count instead\n// of creating a new entry — this keeps hunkContent compact. Returns the\n// content index so the caller can anchor the conflict to it.\nfunction appendChangeLine(\n hunk: HunkBuilder,\n lineType: 'addition' | 'deletion',\n additionLineIndex: number,\n deletionLineIndex: number\n): number {\n const hunkContent = hunk.hunkContent;\n const lastContent = hunkContent[hunkContent.length - 1];\n if (lastContent?.type === 'change') {\n if (lineType === 'addition') {\n lastContent.additions++;\n } else {\n lastContent.deletions++;\n }\n return hunkContent.length - 1;\n }\n hunkContent.push({\n type: 'change',\n additions: lineType === 'addition' ? 1 : 0,\n deletions: lineType === 'deletion' ? 1 : 0,\n additionLineIndex,\n deletionLineIndex,\n });\n return hunkContent.length - 1;\n}\n\n// Drains the hunk's context buffer into hunkContent, applying mode-dependent\n// trimming. The buffer accumulates context lines without committing them,\n// because we don't know yet whether they'll be leading context (trim start),\n// trailing context (trim end), or mid-hunk context (keep all). The mode tells\n// us which case we're in:\n//\n// 'leading' — first change in a new hunk; drop lines beyond\n// maxContextLines from the front, and shift the hunk's\n// start position forward accordingly.\n// 'trailing' — last flush before hunk finalization; keep at most\n// maxContextLines from the front of the buffer.\n// 'before-change' — mid-hunk context between two changes; emit everything.\nfunction flushBufferedContext(\n s: ParseState,\n hunk: HunkBuilder,\n mode: ContextFlushMode\n): void {\n let count = hunk.contextBufferCount;\n let addStart = hunk.contextBufferAdditionStart;\n let delStart = hunk.contextBufferDeletionStart;\n\n if (mode === 'leading' && count > s.maxContextLines) {\n const difference = count - s.maxContextLines;\n addStart += difference;\n delStart += difference;\n count = s.maxContextLines;\n hunk.additionStart += difference;\n hunk.deletionStart += difference;\n hunk.additionLineIndex += difference;\n hunk.deletionLineIndex += difference;\n }\n\n if (mode === 'trailing' && count > s.maxContextLines) {\n count = s.maxContextLines;\n }\n\n if (count === 0) {\n hunk.contextBufferCount = 0;\n hunk.contextBufferBaseConflicts = undefined;\n return;\n }\n\n // Bulk-append context: coalesce with previous context entry or create new\n // one. This avoids a per-line loop — significant when maxContextLines is\n // large.\n const hunkContent = hunk.hunkContent;\n const lastContent = hunkContent[hunkContent.length - 1];\n let contentIndex: number;\n if (lastContent?.type === 'context') {\n lastContent.lines += count;\n contentIndex = hunkContent.length - 1;\n } else {\n hunkContent.push({\n type: 'context',\n lines: count,\n additionLineIndex: addStart,\n deletionLineIndex: delStart,\n });\n contentIndex = hunkContent.length - 1;\n }\n hunk.additionCount += count;\n hunk.deletionCount += count;\n\n // Assign base-section conflict anchors (rare — only when base lines exist)\n const baseConflicts = hunk.contextBufferBaseConflicts;\n if (baseConflicts != null) {\n const bufferStartOffset = addStart - hunk.contextBufferAdditionStart;\n for (const [offset, conflictIndex] of baseConflicts) {\n if (offset >= bufferStartOffset && offset < bufferStartOffset + count) {\n assignConflictContent(s, conflictIndex, 'base', contentIndex);\n }\n }\n }\n hunk.contextBufferCount = 0;\n hunk.contextBufferBaseConflicts = undefined;\n}\n\n// Converts the mutable HunkBuilder into an immutable Hunk and pushes it onto\n// s.hunks. Computes line counts for split and unified view, the collapsed-\n// before gap (lines between the previous hunk and this one), and the hunk\n// header string (e.g. \"@@ -1,5 +1,7 @@\").\nfunction finalizeActiveHunk(s: ParseState): void {\n if (s.activeHunk == null) {\n return;\n }\n\n const hunk = s.activeHunk;\n s.activeHunk = undefined;\n if (hunk.hunkContent.length === 0) {\n return;\n }\n\n let hunkSplitLineCount = 0;\n let hunkUnifiedLineCount = 0;\n for (const content of hunk.hunkContent) {\n if (content.type === 'context') {\n hunkSplitLineCount += content.lines;\n hunkUnifiedLineCount += content.lines;\n } else {\n hunkSplitLineCount += Math.max(content.additions, content.deletions);\n hunkUnifiedLineCount += content.additions + content.deletions;\n }\n }\n\n const collapsedBefore = Math.max(hunk.additionStart - 1 - s.lastHunkEnd, 0);\n const finalizedHunk: Hunk = {\n collapsedBefore,\n additionStart: hunk.additionStart,\n additionCount: hunk.additionCount,\n additionLines: hunk.additionLines,\n additionLineIndex: hunk.additionLineIndex,\n deletionStart: hunk.deletionStart,\n deletionCount: hunk.deletionCount,\n deletionLines: hunk.deletionLines,\n deletionLineIndex: hunk.deletionLineIndex,\n hunkContent: hunk.hunkContent,\n hunkContext: undefined,\n hunkSpecs: `@@ -${formatHunkRange(hunk.deletionStart, hunk.deletionCount)} +${formatHunkRange(hunk.additionStart, hunk.additionCount)} @@\\n`,\n splitLineStart: s.splitLineCount + collapsedBefore,\n splitLineCount: hunkSplitLineCount,\n unifiedLineStart: s.unifiedLineCount + collapsedBefore,\n unifiedLineCount: hunkUnifiedLineCount,\n noEOFCRAdditions: false,\n noEOFCRDeletions: false,\n };\n\n s.hunks.push(finalizedHunk);\n s.splitLineCount += collapsedBefore + hunkSplitLineCount;\n s.unifiedLineCount += collapsedBefore + hunkUnifiedLineCount;\n s.lastHunkEnd = hunk.additionStart + hunk.additionCount - 1;\n}\n\n// Called when the context buffer between two changes exceeds maxContextLines*2.\n// This means there's a big enough gap to warrant splitting into separate hunks\n// (just like `diff -U` does). The procedure:\n// 1. Flush the first maxContextLines of the buffer as trailing context\n// 2. Finalize the current hunk\n// 3. Start a new hunk pre-seeded with the last maxContextLines as leading context\n// The middle portion of the buffer (between the two maxContextLines slices) is\n// the \"collapsed\" region — lines omitted from the diff view.\nfunction splitHunkWithBufferedContext(s: ParseState): void {\n if (s.activeHunk == null) {\n return;\n }\n\n const hunk = s.activeHunk;\n const count = hunk.contextBufferCount;\n const omittedContextLineCount = count - s.maxContextLines2;\n\n // Save trailing context start indices for the next hunk.\n const nextAddStart =\n hunk.contextBufferAdditionStart + count - s.maxContextLines;\n const nextDelStart =\n hunk.contextBufferDeletionStart + count - s.maxContextLines;\n\n // Extract base conflicts that fall within the trailing portion.\n let nextBaseConflicts: Map<number, number> | undefined;\n if (hunk.contextBufferBaseConflicts != null) {\n const tailOffset = count - s.maxContextLines;\n for (const [offset, ci] of hunk.contextBufferBaseConflicts) {\n if (offset >= tailOffset) {\n nextBaseConflicts ??= new Map();\n nextBaseConflicts.set(offset - tailOffset, ci);\n }\n }\n }\n\n flushBufferedContext(s, hunk, 'trailing');\n const emittedAdditionCount = hunk.additionCount;\n const emittedDeletionCount = hunk.deletionCount;\n finalizeActiveHunk(s);\n\n s.activeHunk = createHunkBuilder(\n hunk.additionStart + emittedAdditionCount + omittedContextLineCount,\n hunk.deletionStart + emittedDeletionCount + omittedContextLineCount\n );\n s.activeHunk.contextBufferAdditionStart = nextAddStart;\n s.activeHunk.contextBufferDeletionStart = nextDelStart;\n s.activeHunk.contextBufferCount = s.maxContextLines;\n s.activeHunk.contextBufferBaseConflicts = nextBaseConflicts;\n}\n\n// Adds a context line (identical on both sides of the diff). The line is pushed\n// to both additionLines and deletionLines, then buffered in the hunk's context\n// buffer rather than committed to hunkContent immediately. This deferred write\n// is what enables the leading/trailing trim logic in flushBufferedContext.\n//\n// For base-section lines inside a diff3 conflict, pass the conflict index so\n// the buffer can record the association; when the buffer is flushed, those\n// lines get anchored to the conflict via assignConflictContent.\nfunction emitContextLine(\n s: ParseState,\n line: string,\n baseConflictIndex: number = -1\n): void {\n const hunk = ensureActiveHunk(s);\n // Reset buffer start on first line after a flush/creation.\n if (hunk.contextBufferCount === 0) {\n hunk.contextBufferAdditionStart = s.additionLines.length;\n hunk.contextBufferDeletionStart = s.deletionLines.length;\n }\n s.additionLines.push(line);\n s.deletionLines.push(line);\n if (baseConflictIndex >= 0) {\n hunk.contextBufferBaseConflicts ??= new Map();\n hunk.contextBufferBaseConflicts.set(\n hunk.contextBufferCount,\n baseConflictIndex\n );\n }\n hunk.contextBufferCount++;\n}\n\n// Adds a change line (addition or deletion) to the current hunk. This is the\n// main \"work\" function on the hot path and orchestrates several steps:\n// 1. If there's a large context gap since the last change, split the hunk\n// 2. Flush any buffered context lines (leading trim on first change, or\n// pass-through for mid-hunk context)\n// 3. Push the line to the appropriate line array (additions or deletions)\n// 4. Append/coalesce the change into hunkContent\n// 5. Anchor the conflict action to the content index\nfunction emitChangeLine(\n s: ParseState,\n lineType: 'addition' | 'deletion',\n line: string,\n conflictIndex: number,\n role: MergeConflictSide\n): void {\n let hunk = ensureActiveHunk(s);\n // If the context gap since the last change exceeds 2x maxContextLines,\n // split into two hunks: trailing context for the old, leading for the new.\n if (\n hunk.hunkContent.length > 0 &&\n hunk.contextBufferCount > s.maxContextLines2\n ) {\n splitHunkWithBufferedContext(s);\n hunk = s.activeHunk!;\n }\n\n flushBufferedContext(\n s,\n hunk,\n hunk.hunkContent.length === 0 ? 'leading' : 'before-change'\n );\n\n const additionLineIndex = s.additionLines.length;\n const deletionLineIndex = s.deletionLines.length;\n if (lineType === 'addition') {\n s.additionLines.push(line);\n } else {\n s.deletionLines.push(line);\n }\n\n const contentIndex = appendChangeLine(\n hunk,\n lineType,\n additionLineIndex,\n deletionLineIndex\n );\n\n if (lineType === 'addition') {\n hunk.additionCount++;\n hunk.additionLines++;\n } else {\n hunk.deletionCount++;\n hunk.deletionLines++;\n }\n assignConflictContent(s, conflictIndex, role, contentIndex);\n}\n\n// Called when we hit a >>>>>>> end marker. Takes the completed ConflictFrame\n// and writes the final source-line coordinates and marker text into the\n// conflict action. Also handles empty-side conflicts: if one side had no\n// content lines, we fall back to the other side's content index so the action\n// always has valid anchors. This is what makes conflicts like \"add vs nothing\"\n// or \"nothing vs add\" representable.\nfunction finalizeConflict(\n s: ParseState,\n frame: ConflictFrame,\n endLineIndex: number,\n endMarkerLine: string\n): void {\n if (frame.separatorLineIndex == null || frame.markerLines.separator == null) {\n throw new Error(\n `parseMergeConflictDiffFromFile: conflict ${frame.conflictIndex} is missing a separator marker`\n );\n }\n\n const builder = s.conflictBuilders[frame.conflictIndex];\n if (builder == null) {\n throw new Error(\n `parseMergeConflictDiffFromFile: failed to finalize conflict ${frame.conflictIndex}`\n );\n }\n\n const action = builder.action;\n action.markerLines.separator = frame.markerLines.separator;\n action.markerLines.end = endMarkerLine;\n if (frame.markerLines.base != null) {\n action.markerLines.base = frame.markerLines.base;\n }\n\n action.conflict = {\n conflictIndex: frame.conflictIndex,\n startLineIndex: frame.startLineIndex,\n startLineNumber: frame.startLineIndex + 1,\n separatorLineIndex: frame.separatorLineIndex,\n separatorLineNumber: frame.separatorLineIndex + 1,\n endLineIndex,\n endLineNumber: endLineIndex + 1,\n baseMarkerLineIndex: frame.baseMarkerLineIndex,\n baseMarkerLineNumber:\n frame.baseMarkerLineIndex != null\n ? frame.baseMarkerLineIndex + 1\n : undefined,\n };\n\n // If one side of the conflict was empty (e.g. \"add vs nothing\"), its content\n // index will be undefined. Use the other side as a fallback so the action\n // always has a valid anchor for the UI to render.\n const fallbackContentIndex =\n action.currentContentIndex ?? action.incomingContentIndex;\n action.currentContentIndex ??= fallbackContentIndex;\n action.incomingContentIndex ??= fallbackContentIndex;\n if (action.startContentIndex < 0 && fallbackContentIndex != null) {\n action.startContentIndex = fallbackContentIndex;\n }\n if (action.endContentIndex < 0 && fallbackContentIndex != null) {\n action.endContentIndex = fallbackContentIndex;\n }\n if (action.endMarkerContentIndex < 0 && fallbackContentIndex != null) {\n action.endMarkerContentIndex = fallbackContentIndex;\n }\n\n if (\n action.hunkIndex < 0 ||\n action.startContentIndex < 0 ||\n action.endContentIndex < 0 ||\n action.endMarkerContentIndex < 0\n ) {\n throw new Error(\n `parseMergeConflictDiffFromFile: failed to anchor merge conflict ${frame.conflictIndex}`\n );\n }\n\n s.actions[action.conflictIndex] = action;\n builder.completed = true;\n}\n\n// Pushes a new ConflictFrame onto the stack and creates a placeholder\n// ConflictActionBuilder. The builder starts with sentinel values (-1 for\n// indices) that get filled in as we encounter content lines and markers.\n// The frame tracks which section we're scanning (current → base → incoming);\n// the builder accumulates the final action that downstream consumers use.\nfunction handleStartMarker(\n s: ParseState,\n line: string,\n lineIndex: number\n): void {\n const conflictIndex = s.nextConflictIndex;\n s.nextConflictIndex++;\n s.conflictStack.push({\n conflictIndex,\n stage: 'current',\n startLineIndex: lineIndex,\n markerLines: { start: line },\n });\n s.conflictBuilders[conflictIndex] = {\n completed: false,\n action: {\n conflict: {\n conflictIndex,\n startLineIndex: lineIndex,\n startLineNumber: lineIndex + 1,\n separatorLineIndex: lineIndex,\n separatorLineNumber: lineIndex + 1,\n endLineIndex: lineIndex,\n endLineNumber: lineIndex + 1,\n baseMarkerLineIndex: undefined,\n baseMarkerLineNumber: undefined,\n },\n conflictIndex,\n hunkIndex: -1,\n startContentIndex: -1,\n endContentIndex: -1,\n endMarkerContentIndex: -1,\n markerLines: {\n start: line,\n separator: '',\n end: '',\n },\n },\n };\n}\n\nfunction createHunkBuilder(\n additionStart: number,\n deletionStart: number\n): HunkBuilder {\n return {\n additionStart,\n deletionStart,\n additionCount: 0,\n deletionCount: 0,\n additionLines: 0,\n deletionLines: 0,\n additionLineIndex: Math.max(additionStart - 1, 0),\n deletionLineIndex: Math.max(deletionStart - 1, 0),\n hunkContent: [],\n contextBufferAdditionStart: Math.max(additionStart - 1, 0),\n contextBufferDeletionStart: Math.max(deletionStart - 1, 0),\n contextBufferCount: 0,\n contextBufferBaseConflicts: undefined,\n };\n}\n\nfunction formatHunkRange(start: number, count: number): string {\n return count === 1 ? `${start}` : `${start},${count}`;\n}\n\n// Detects whether a line is a merge conflict marker by inspecting the first\n// character and counting consecutive repetitions. Git conflict markers are\n// 7+ repeated characters:\n// '<' (60) = start (<<<<<<< current)\n// '|' (124) = base (||||||| base)\n// '=' (61) = separator (=======)\n// '>' (62) = end (>>>>>>> incoming)\n// The separator must be exactly '=======' with no trailing text; other markers\n// allow an optional space + label (e.g. \"<<<<<<< HEAD\").\nfunction getMergeConflictMarkerType(\n line: string\n): MergeConflictMarkerType | undefined {\n if (line.length < 7) {\n return undefined;\n }\n\n const markerCode = line.charCodeAt(0);\n if (\n markerCode !== 60 &&\n markerCode !== 62 &&\n markerCode !== 61 &&\n markerCode !== 124\n ) {\n return undefined;\n }\n\n const lineEnd = getLineContentEndIndex(line);\n if (lineEnd < 7) {\n return undefined;\n }\n\n let markerLength = 1;\n while (\n markerLength < lineEnd &&\n line.charCodeAt(markerLength) === markerCode\n ) {\n markerLength++;\n }\n\n if (markerLength < 7) {\n return undefined;\n }\n\n if (markerCode === 61) {\n return markerLength === lineEnd ? 'separator' : undefined;\n }\n\n if (\n markerLength !== lineEnd &&\n !isWhitespaceCode(line.charCodeAt(markerLength))\n ) {\n return undefined;\n }\n\n if (markerCode === 60) {\n return 'start';\n }\n if (markerCode === 62) {\n return 'end';\n }\n return 'base';\n}\n\nfunction getLineContentEndIndex(line: string): number {\n let end = line.length;\n if (end > 0 && line.charCodeAt(end - 1) === 10) {\n end--;\n }\n if (end > 0 && line.charCodeAt(end - 1) === 13) {\n end--;\n }\n return end;\n}\n\nfunction isWhitespaceCode(code: number): boolean {\n return (\n code === 9 ||\n code === 10 ||\n code === 11 ||\n code === 12 ||\n code === 13 ||\n code === 32\n );\n}\n\nfunction createResolvedConflictFile(\n file: FileContents,\n side: 'current' | 'incoming',\n contents: string\n): FileContents {\n return {\n ...file,\n contents,\n cacheKey:\n file.cacheKey != null\n ? `${file.cacheKey}:merge-conflict-${side}`\n : undefined,\n };\n}\n\n// Builds the marker row array that tells the UI where to render conflict\n// decorations (start/base/separator/end lines) in the diff view. Each marker\n// row maps a conflict marker to a specific line index in unified view.\n//\n// This is a post-processing step over the finalized hunks and actions. It\n// caches cumulative line-start positions per hunk to avoid recomputing them\n// for every marker.\nexport function buildMergeConflictMarkerRows(\n fileDiff: FileDiffMetadata,\n actions: (MergeConflictDiffAction | undefined)[]\n): MergeConflictMarkerRow[] {\n const markerRows: MergeConflictMarkerRow[] = [];\n const hunkLineStartCache: (number[] | undefined)[] = new Array(\n fileDiff.hunks.length\n );\n\n const getLineStart = (hunkIndex: number, contentIndex: number): number => {\n const hunk = fileDiff.hunks[hunkIndex];\n if (hunk == null) {\n return 0;\n }\n let starts = hunkLineStartCache[hunkIndex];\n if (starts == null) {\n starts = new Array<number>(hunk.hunkContent.length + 1);\n let lineIndex = hunk.unifiedLineStart;\n starts[0] = lineIndex;\n for (let index = 0; index < hunk.hunkContent.length; index++) {\n const content = hunk.hunkContent[index];\n lineIndex +=\n content.type === 'context'\n ? content.lines\n : content.deletions + content.additions;\n starts[index + 1] = lineIndex;\n }\n hunkLineStartCache[hunkIndex] = starts;\n }\n return starts[Math.max(contentIndex, 0)] ?? hunk.unifiedLineStart;\n };\n\n const getLineEnd = (hunkIndex: number, contentIndex: number): number => {\n const lineStart = getLineStart(hunkIndex, contentIndex);\n const starts = hunkLineStartCache[hunkIndex];\n const lineEndExclusive =\n starts?.[Math.max(contentIndex + 1, 0)] ??\n getLineStart(hunkIndex, contentIndex + 1);\n return Math.max(lineStart, lineEndExclusive - 1);\n };\n\n for (const action of actions) {\n if (action == null) {\n continue;\n }\n\n const hunk = fileDiff.hunks[action.hunkIndex];\n if (hunk == null) {\n continue;\n }\n\n const actionLineIndex = getLineStart(\n action.hunkIndex,\n action.startContentIndex\n );\n markerRows.push(\n createMergeConflictMarkerRow(\n action,\n 'marker-start',\n action.startContentIndex,\n action.markerLines.start,\n actionLineIndex\n )\n );\n\n if (action.baseContentIndex != null) {\n const currentContentIndex = action.currentContentIndex;\n const incomingContentIndex = action.incomingContentIndex;\n if (currentContentIndex == null || incomingContentIndex == null) {\n continue;\n }\n\n const baseMarkerLine = action.markerLines.base;\n if (baseMarkerLine == null) {\n continue;\n }\n\n const currentChange = hunk.hunkContent[currentContentIndex];\n const baseContext = hunk.hunkContent[action.baseContentIndex];\n const incomingChange = hunk.hunkContent[incomingContentIndex];\n if (\n currentChange?.type !== 'change' ||\n baseContext?.type !== 'context' ||\n incomingChange?.type !== 'change'\n ) {\n continue;\n }\n\n const currentStart = getLineStart(action.hunkIndex, currentContentIndex);\n const incomingStart = getLineStart(\n action.hunkIndex,\n incomingContentIndex\n );\n markerRows.push(\n createMergeConflictMarkerRow(\n action,\n 'marker-base',\n action.baseContentIndex,\n baseMarkerLine,\n currentStart + currentChange.deletions\n )\n );\n\n markerRows.push(\n createMergeConflictMarkerRow(\n action,\n 'marker-separator',\n action.baseContentIndex,\n action.markerLines.separator,\n incomingStart\n ),\n createMergeConflictMarkerRow(\n action,\n 'marker-end',\n action.endMarkerContentIndex,\n action.markerLines.end,\n getLineEnd(action.hunkIndex, action.endMarkerContentIndex)\n )\n );\n continue;\n }\n\n const currentContentIndex = action.currentContentIndex;\n if (currentContentIndex == null) {\n continue;\n }\n const content = hunk.hunkContent[currentContentIndex];\n if (content?.type !== 'change') {\n continue;\n }\n\n const contentStart = getLineStart(action.hunkIndex, currentContentIndex);\n const separatorLineIndex =\n content.deletions > 0\n ? contentStart + content.deletions\n : actionLineIndex;\n\n markerRows.push(\n createMergeConflictMarkerRow(\n action,\n 'marker-separator',\n currentContentIndex,\n action.markerLines.separator,\n separatorLineIndex\n ),\n createMergeConflictMarkerRow(\n action,\n 'marker-end',\n action.endMarkerContentIndex,\n action.markerLines.end,\n getLineEnd(action.hunkIndex, action.endMarkerContentIndex)\n )\n );\n }\n\n return markerRows;\n}\n\nfunction createMergeConflictMarkerRow(\n action: MergeConflictDiffAction,\n type: MergeConflictMarkerRowType,\n contentIndex: number,\n lineText: string,\n lineIndex: number\n): MergeConflictMarkerRow {\n return {\n type,\n hunkIndex: action.hunkIndex,\n contentIndex,\n conflictIndex: action.conflictIndex,\n lineText,\n lineIndex,\n };\n}\n\nfunction getUnifiedLineStartForContent(\n hunk: Hunk,\n contentIndex: number\n): number {\n let lineIndex = hunk.unifiedLineStart;\n for (let index = 0; index < contentIndex; index++) {\n const content = hunk.hunkContent[index];\n lineIndex +=\n content.type === 'context'\n ? content.lines\n : content.deletions + content.additions;\n }\n return lineIndex;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parseMergeConflictDiffFromFile.js","names":[],"sources":["../../src/utils/parseMergeConflictDiffFromFile.ts"],"sourcesContent":["// Parses a file containing git merge conflict markers (<<<<<<< / ======= / >>>>>>>)\n// into a synthetic unified diff. The core idea: treat the conflict file as though\n// \"current\" lines are deletions and \"incoming\" lines are additions. Lines outside\n// conflicts (and optional \"base\" sections from diff3) become shared context.\n//\n// The result is a standard FileDiffMetadata with hunks — identical in shape to what\n// you'd get from parsing a real unified diff — plus a parallel array of\n// MergeConflictDiffActions that anchor each conflict region to positions within the\n// hunk structure. Downstream consumers (e.g. the merge conflict UI) use these\n// anchors to overlay conflict markers onto the diff view.\n//\n// Architecture note: all helper functions are module-level (not closures inside the\n// main function) and receive a shared ParseState object by reference. This avoids\n// per-call scope-chain traversal on the hot path (~20K lines), where every line\n// triggers 2-3 helper calls.\n//\n// ---\n// NOTE: This file was nearly entirely written and optimized by AI. It has a\n// verification harness that any future changes (human or AI) should be validated\n// against:\n//\n// Snapshot tests (from packages/diffs/):\n// bun test parseMergeConflictDiffFromFile\n//\n// Performance benchmark (checksum must match 33121550):\n// moonx diffs:benchmark-parse-merge-conflict\n//\n// If you encounter a bug:\n// 1. Add a new test case in test/parseMergeConflictDiffFromFile.test.ts with\n// input that reproduces the failure. Use toMatchSnapshot() so the expected\n// output is captured automatically once fixed.\n// 2. Run `bun test parseMergeConflictDiffFromFile` from packages/diffs/ to\n// confirm the new test fails.\n// 3. Use an AI agent with extended/high thinking to fix the logic — the\n// snapshot tests and benchmark provide a tight feedback loop. The agent\n// should iterate until all snapshots pass AND the benchmark checksum\n// matches. Update snapshots with `bun test test/parseMergeConflictDiffFromFile.test.ts -u`\n// only after verifying the new output is correct.\n// ---\n\nimport type {\n FileContents,\n FileDiffMetadata,\n Hunk,\n MergeConflictMarkerRow,\n MergeConflictMarkerRowType,\n MergeConflictRegion,\n ProcessFileConflictData,\n} from '../types';\n\nexport interface ParseMergeConflictDiffFromFileResult {\n fileDiff: FileDiffMetadata;\n currentFile: FileContents;\n incomingFile: FileContents;\n actions: (MergeConflictDiffAction | undefined)[];\n markerRows: MergeConflictMarkerRow[];\n}\n\nexport interface MergeConflictDiffAction extends ProcessFileConflictData {\n // Kept for callback consumers that still need the original unresolved-region\n // source-line coordinates alongside structural hunk-content anchors.\n conflict: MergeConflictRegion;\n conflictIndex: number;\n markerLines: {\n start: string;\n base?: string;\n separator: string;\n end: string;\n };\n}\n\ninterface GetMergeConflictActionAnchorReturn {\n hunkIndex: number;\n lineIndex: number;\n}\n\n// Which section of a conflict we're currently inside while scanning lines.\n// Progresses: current → (optional) base → incoming.\ntype MergeConflictStage = 'current' | 'base' | 'incoming';\ntype MergeConflictSide = MergeConflictStage;\ntype MergeConflictMarkerType = 'start' | 'base' | 'separator' | 'end';\n\n// Controls how buffered context lines are trimmed when flushed to hunkContent:\n// 'leading' — first flush of a hunk; trim excess from the start\n// 'before-change' — flush between changes; emit all buffered lines\n// 'trailing' — last flush of a hunk; trim excess from the end\ntype ContextFlushMode = 'before-change' | 'leading' | 'trailing';\n\n// Mutable accumulator for building a single Hunk. Tracks line counts, the\n// hunkContent array (sequence of context/change groups), and a \"context buffer\"\n// that defers writing context lines until we know whether they're leading,\n// trailing, or mid-hunk context.\n//\n// The context buffer avoids eagerly committing context lines to hunkContent.\n// When a change line arrives, we flush the buffer — trimming to maxContextLines\n// if it's the leading or trailing edge of a hunk, or splitting into two hunks\n// if the gap between changes exceeds maxContextLines * 2.\ninterface HunkBuilder {\n additionStart: number;\n deletionStart: number;\n additionCount: number;\n deletionCount: number;\n additionLines: number;\n deletionLines: number;\n additionLineIndex: number;\n deletionLineIndex: number;\n hunkContent: Hunk['hunkContent'];\n // Context buffer: instead of storing per-line index arrays, we track the\n // starting indices and a count. Since context lines always push to both\n // additionLines and deletionLines consecutively, indices can be derived.\n contextBufferAdditionStart: number;\n contextBufferDeletionStart: number;\n contextBufferCount: number;\n // Sparse map of buffer-offset → conflictIndex for base-section context lines.\n // Empty for most buffers since base lines are rare.\n contextBufferBaseConflicts: Map<number, number> | undefined;\n}\n\n// Tracks an in-progress conflict as we scan through its lines. Pushed onto\n// conflictStack when we hit a <<<<<<< marker, and popped + finalized when we\n// hit the matching >>>>>>> marker. The `stage` field tells processLine which\n// section we're in so it knows whether to emit deletions, context, or additions.\ninterface ConflictFrame {\n conflictIndex: number;\n stage: MergeConflictStage;\n startLineIndex: number;\n baseMarkerLineIndex?: number;\n separatorLineIndex?: number;\n markerLines: {\n start: string;\n base?: string;\n separator?: string;\n };\n}\n\ninterface ConflictActionBuilder {\n action: MergeConflictDiffAction;\n completed: boolean;\n}\n\n// Bundles all mutable state shared across parse helper functions, replacing\n// closure-captured variables with a single object passed by reference.\n//\n// The two key arrays — deletionLines and additionLines — are the synthetic\n// \"before\" and \"after\" file contents. Context lines are pushed to both arrays\n// (identical on both sides). Current-side conflict lines go only into\n// deletionLines; incoming-side lines go only into additionLines. After parsing,\n// joining each array produces the resolved file for that side.\ninterface ParseState {\n // \"Before\" file lines (context + current-side conflict content).\n deletionLines: string[];\n // \"After\" file lines (context + incoming-side conflict content).\n additionLines: string[];\n // Stack of open conflict regions (supports nested conflicts, though rare).\n conflictStack: ConflictFrame[];\n // Parallel to actions[]; accumulates content indices during parsing.\n conflictBuilders: ConflictActionBuilder[];\n // Final output: one action per conflict, indexed by conflictIndex.\n actions: (MergeConflictDiffAction | undefined)[];\n // Finalized hunks, appended as context gaps cause hunk splits.\n hunks: Hunk[];\n nextConflictIndex: number;\n // Running line totals used to compute hunk splitLineStart/unifiedLineStart.\n splitLineCount: number;\n unifiedLineCount: number;\n // 1-based line number where the previous hunk ended (for collapsedBefore).\n lastHunkEnd: number;\n // The hunk currently being built; undefined between hunks.\n activeHunk: HunkBuilder | undefined;\n maxContextLines: number;\n // Cached maxContextLines * 2 (the threshold for splitting a hunk).\n maxContextLines2: number;\n}\n\nexport function getMergeConflictActionAnchor(\n action: MergeConflictDiffAction,\n fileDiff: FileDiffMetadata\n): GetMergeConflictActionAnchorReturn | undefined {\n const hunk = fileDiff.hunks[action.hunkIndex];\n if (hunk == null) {\n return undefined;\n }\n return {\n hunkIndex: action.hunkIndex,\n lineIndex: getUnifiedLineStartForContent(hunk, action.startContentIndex),\n };\n}\n\n// Main entry point. Walks every line of the conflict file exactly once,\n// dispatching each line through processLine which routes it to the appropriate\n// emitter (context or change). After the loop, finalizes the last hunk,\n// validates all conflicts were closed, and assembles the result.\n//\n// The three phases are:\n// 1. Line-by-line scan — builds hunks and conflict actions incrementally\n// 2. Post-loop cleanup — flushes trailing context, finalizes last hunk\n// 3. Result assembly — joins line arrays, builds marker rows for the UI\nexport function parseMergeConflictDiffFromFile(\n file: FileContents,\n maxContextLines: number = 6\n): ParseMergeConflictDiffFromFileResult {\n // Never allow maxContextLines to drop below 1 or else things break.\n maxContextLines = Math.max(maxContextLines, 1);\n\n const s: ParseState = {\n deletionLines: [],\n additionLines: [],\n conflictStack: [],\n conflictBuilders: [],\n actions: [],\n hunks: [],\n nextConflictIndex: 0,\n splitLineCount: 0,\n unifiedLineCount: 0,\n lastHunkEnd: 0,\n activeHunk: undefined,\n maxContextLines,\n maxContextLines2: maxContextLines * 2,\n };\n\n // Phase 1: Line-by-line scan. We inline the indexOf loop here (rather than\n // calling a helper with a callback) to avoid creating a closure on the hot\n // path. Each line is sliced and dispatched to processLine.\n const contents = file.contents;\n const contentLength = contents.length;\n if (contentLength > 0) {\n let lineStart = 0;\n let lineIndex = 0;\n let newlinePos = contents.indexOf('\\n', lineStart);\n while (newlinePos !== -1) {\n processLine(s, contents.slice(lineStart, newlinePos + 1), lineIndex);\n lineStart = newlinePos + 1;\n lineIndex++;\n newlinePos = contents.indexOf('\\n', lineStart);\n }\n if (lineStart < contentLength) {\n processLine(s, contents.slice(lineStart), lineIndex);\n }\n }\n\n // Phase 2: Post-loop cleanup. Any unclosed conflict is an error. If the\n // last hunk has buffered context lines, flush them as trailing context and\n // finalize the hunk.\n if (s.conflictStack.length > 0) {\n throw new Error(\n 'parseMergeConflictDiffFromFile: unfinished merge conflict marker stack'\n );\n }\n\n if (s.activeHunk != null && s.activeHunk.hunkContent.length > 0) {\n flushBufferedContext(s, s.activeHunk, 'trailing');\n finalizeActiveHunk(s);\n }\n\n for (\n let conflictIndex = 0;\n conflictIndex < s.conflictBuilders.length;\n conflictIndex++\n ) {\n const builder = s.conflictBuilders[conflictIndex];\n if (builder == null || !builder.completed) {\n throw new Error(\n `parseMergeConflictDiffFromFile: failed to build merge conflict action ${conflictIndex}`\n );\n }\n }\n\n // Phase 3: Result assembly. Account for any collapsed lines after the last\n // hunk, then join the line arrays to produce resolved file contents.\n if (\n s.hunks.length > 0 &&\n s.additionLines.length > 0 &&\n s.deletionLines.length > 0\n ) {\n const lastHunk = s.hunks[s.hunks.length - 1];\n const collapsedAfter = Math.max(\n s.additionLines.length -\n (lastHunk.additionStart + lastHunk.additionCount - 1),\n 0\n );\n s.splitLineCount += collapsedAfter;\n s.unifiedLineCount += collapsedAfter;\n }\n\n const currentContents = s.deletionLines.join('');\n const incomingContents = s.additionLines.join('');\n const currentFile = createResolvedConflictFile(\n file,\n 'current',\n currentContents\n );\n const incomingFile = createResolvedConflictFile(\n file,\n 'incoming',\n incomingContents\n );\n\n let type: FileDiffMetadata['type'] = 'change';\n if (incomingContents === '') {\n type = 'deleted';\n } else if (currentContents === '') {\n type = 'new';\n }\n\n const fileDiff: FileDiffMetadata = {\n name: file.name,\n prevName: undefined,\n type,\n hunks: s.hunks,\n splitLineCount: s.splitLineCount,\n unifiedLineCount: s.unifiedLineCount,\n isPartial: false,\n deletionLines: s.deletionLines,\n additionLines: s.additionLines,\n cacheKey:\n file.cacheKey != null\n ? `${file.cacheKey}:merge-conflict-diff`\n : undefined,\n };\n\n return {\n fileDiff,\n currentFile,\n incomingFile,\n actions: s.actions,\n markerRows: buildMergeConflictMarkerRows(fileDiff, s.actions),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Module-level parse helpers. Each receives ParseState by reference rather\n// than capturing variables via closure. The call graph from the hot path is:\n//\n// processLine\n// ├─ emitContextLine → ensureActiveHunk\n// ├─ emitChangeLine → ensureActiveHunk, splitHunkWithBufferedContext,\n// │ flushBufferedContext, appendChangeLine,\n// │ assignConflictContent\n// ├─ handleStartMarker\n// └─ finalizeConflict\n// ---------------------------------------------------------------------------\n\n// Routes a single source line to the right emitter based on whether we're\n// inside a conflict and, if so, which section (current/base/incoming).\n// Outside conflicts, only the start marker (<<<<<<< / charCode 60) can\n// change state, so we skip the full marker check for non-'<' lines.\nfunction processLine(s: ParseState, line: string, index: number): void {\n const frame = s.conflictStack[s.conflictStack.length - 1];\n\n // Outside any conflict: only start markers (<<<<<<<) can transition state.\n // Skip the full marker check for lines that can't be start markers.\n if (frame == null) {\n if (\n line.length >= 7 &&\n line.charCodeAt(0) === 60 &&\n getMergeConflictMarkerType(line) === 'start'\n ) {\n handleStartMarker(s, line, index);\n return;\n }\n emitContextLine(s, line);\n return;\n }\n\n // Inside a conflict: all marker types must be checked.\n const markerType = getMergeConflictMarkerType(line);\n\n if (markerType === 'start') {\n handleStartMarker(s, line, index);\n return;\n }\n\n if (markerType === 'base') {\n frame.stage = 'base';\n frame.baseMarkerLineIndex = index;\n frame.markerLines.base = line;\n return;\n }\n\n if (markerType === 'separator') {\n frame.stage = 'incoming';\n frame.separatorLineIndex = index;\n frame.markerLines.separator = line;\n return;\n }\n\n if (markerType === 'end') {\n const completedFrame = s.conflictStack.pop();\n if (completedFrame == null) {\n throw new Error(\n 'parseMergeConflictDiffFromFile: encountered end marker before start marker'\n );\n }\n finalizeConflict(s, completedFrame, index, line);\n return;\n }\n\n if (frame.stage === 'current') {\n emitChangeLine(s, 'deletion', line, frame.conflictIndex, 'current');\n } else if (frame.stage === 'base') {\n emitContextLine(s, line, frame.conflictIndex);\n } else {\n emitChangeLine(s, 'addition', line, frame.conflictIndex, 'incoming');\n }\n}\n\n// Lazily creates the active HunkBuilder if one doesn't exist yet. The hunk's\n// start positions are derived from the current length of the line arrays\n// (1-based, matching unified diff conventions).\nfunction ensureActiveHunk(s: ParseState): HunkBuilder {\n s.activeHunk ??= createHunkBuilder(\n s.additionLines.length + 1,\n s.deletionLines.length + 1\n );\n return s.activeHunk;\n}\n\n// \"Anchors\" a conflict to its position in the hunk's content array. Each\n// conflict needs to know which hunk it lives in (hunkIndex) and which content\n// entries correspond to its current/base/incoming sections. This is called\n// every time we emit a change or context line that belongs to a conflict, and\n// it incrementally widens the start/end content range.\nfunction assignConflictContent(\n s: ParseState,\n conflictIndex: number,\n role: MergeConflictSide,\n contentIndex: number\n): void {\n const builder = s.conflictBuilders[conflictIndex];\n if (builder == null) {\n throw new Error(\n `parseMergeConflictDiffFromFile: failed to locate conflict action ${conflictIndex}`\n );\n }\n\n const action = builder.action;\n const hunkIndex = s.hunks.length;\n if (action.hunkIndex < 0) {\n action.hunkIndex = hunkIndex;\n } else if (action.hunkIndex !== hunkIndex) {\n throw new Error(\n `parseMergeConflictDiffFromFile: conflict ${conflictIndex} spans multiple hunks and cannot be anchored`\n );\n }\n\n if (action.startContentIndex < 0) {\n action.startContentIndex = contentIndex;\n }\n action.endContentIndex = contentIndex;\n action.endMarkerContentIndex = contentIndex;\n\n if (role === 'current') {\n action.currentContentIndex ??= contentIndex;\n return;\n }\n if (role === 'base') {\n action.baseContentIndex ??= contentIndex;\n return;\n }\n action.incomingContentIndex = contentIndex;\n}\n\n// Appends a change line to the hunk's content array. If the previous entry is\n// already a 'change' group, we just bump its addition/deletion count instead\n// of creating a new entry — this keeps hunkContent compact. Returns the\n// content index so the caller can anchor the conflict to it.\nfunction appendChangeLine(\n hunk: HunkBuilder,\n lineType: 'addition' | 'deletion',\n additionLineIndex: number,\n deletionLineIndex: number\n): number {\n const hunkContent = hunk.hunkContent;\n const lastContent = hunkContent[hunkContent.length - 1];\n if (lastContent?.type === 'change') {\n if (lineType === 'addition') {\n lastContent.additions++;\n } else {\n lastContent.deletions++;\n }\n return hunkContent.length - 1;\n }\n hunkContent.push({\n type: 'change',\n additions: lineType === 'addition' ? 1 : 0,\n deletions: lineType === 'deletion' ? 1 : 0,\n additionLineIndex,\n deletionLineIndex,\n });\n return hunkContent.length - 1;\n}\n\n// Drains the hunk's context buffer into hunkContent, applying mode-dependent\n// trimming. The buffer accumulates context lines without committing them,\n// because we don't know yet whether they'll be leading context (trim start),\n// trailing context (trim end), or mid-hunk context (keep all). The mode tells\n// us which case we're in:\n//\n// 'leading' — first change in a new hunk; drop lines beyond\n// maxContextLines from the front, and shift the hunk's\n// start position forward accordingly.\n// 'trailing' — last flush before hunk finalization; keep at most\n// maxContextLines from the front of the buffer.\n// 'before-change' — mid-hunk context between two changes; emit everything.\nfunction flushBufferedContext(\n s: ParseState,\n hunk: HunkBuilder,\n mode: ContextFlushMode\n): void {\n let count = hunk.contextBufferCount;\n let addStart = hunk.contextBufferAdditionStart;\n let delStart = hunk.contextBufferDeletionStart;\n\n if (mode === 'leading' && count > s.maxContextLines) {\n const difference = count - s.maxContextLines;\n addStart += difference;\n delStart += difference;\n count = s.maxContextLines;\n hunk.additionStart += difference;\n hunk.deletionStart += difference;\n hunk.additionLineIndex += difference;\n hunk.deletionLineIndex += difference;\n }\n\n if (mode === 'trailing' && count > s.maxContextLines) {\n count = s.maxContextLines;\n }\n\n if (count === 0) {\n hunk.contextBufferCount = 0;\n hunk.contextBufferBaseConflicts = undefined;\n return;\n }\n\n // Bulk-append context: coalesce with previous context entry or create new\n // one. This avoids a per-line loop — significant when maxContextLines is\n // large.\n const hunkContent = hunk.hunkContent;\n const lastContent = hunkContent[hunkContent.length - 1];\n let contentIndex: number;\n if (lastContent?.type === 'context') {\n lastContent.lines += count;\n contentIndex = hunkContent.length - 1;\n } else {\n hunkContent.push({\n type: 'context',\n lines: count,\n additionLineIndex: addStart,\n deletionLineIndex: delStart,\n });\n contentIndex = hunkContent.length - 1;\n }\n hunk.additionCount += count;\n hunk.deletionCount += count;\n\n // Assign base-section conflict anchors (rare — only when base lines exist)\n const baseConflicts = hunk.contextBufferBaseConflicts;\n if (baseConflicts != null) {\n const bufferStartOffset = addStart - hunk.contextBufferAdditionStart;\n for (const [offset, conflictIndex] of baseConflicts) {\n if (offset >= bufferStartOffset && offset < bufferStartOffset + count) {\n assignConflictContent(s, conflictIndex, 'base', contentIndex);\n }\n }\n }\n hunk.contextBufferCount = 0;\n hunk.contextBufferBaseConflicts = undefined;\n}\n\n// Converts the mutable HunkBuilder into an immutable Hunk and pushes it onto\n// s.hunks. Computes line counts for split and unified view, the collapsed-\n// before gap (lines between the previous hunk and this one), and the hunk\n// header string (e.g. \"@@ -1,5 +1,7 @@\").\nfunction finalizeActiveHunk(s: ParseState): void {\n if (s.activeHunk == null) {\n return;\n }\n\n const hunk = s.activeHunk;\n s.activeHunk = undefined;\n if (hunk.hunkContent.length === 0) {\n return;\n }\n\n let hunkSplitLineCount = 0;\n let hunkUnifiedLineCount = 0;\n for (const content of hunk.hunkContent) {\n if (content.type === 'context') {\n hunkSplitLineCount += content.lines;\n hunkUnifiedLineCount += content.lines;\n } else {\n hunkSplitLineCount += Math.max(content.additions, content.deletions);\n hunkUnifiedLineCount += content.additions + content.deletions;\n }\n }\n\n const collapsedBefore = Math.max(hunk.additionStart - 1 - s.lastHunkEnd, 0);\n const finalizedHunk: Hunk = {\n collapsedBefore,\n additionStart: hunk.additionStart,\n additionCount: hunk.additionCount,\n additionLines: hunk.additionLines,\n additionLineIndex: hunk.additionLineIndex,\n deletionStart: hunk.deletionStart,\n deletionCount: hunk.deletionCount,\n deletionLines: hunk.deletionLines,\n deletionLineIndex: hunk.deletionLineIndex,\n hunkContent: hunk.hunkContent,\n hunkContext: undefined,\n hunkSpecs: `@@ -${formatHunkRange(hunk.deletionStart, hunk.deletionCount)} +${formatHunkRange(hunk.additionStart, hunk.additionCount)} @@\\n`,\n splitLineStart: s.splitLineCount + collapsedBefore,\n splitLineCount: hunkSplitLineCount,\n unifiedLineStart: s.unifiedLineCount + collapsedBefore,\n unifiedLineCount: hunkUnifiedLineCount,\n noEOFCRAdditions: false,\n noEOFCRDeletions: false,\n };\n\n s.hunks.push(finalizedHunk);\n s.splitLineCount += collapsedBefore + hunkSplitLineCount;\n s.unifiedLineCount += collapsedBefore + hunkUnifiedLineCount;\n s.lastHunkEnd = hunk.additionStart + hunk.additionCount - 1;\n}\n\n// Called when the context buffer between two changes exceeds maxContextLines*2.\n// This means there's a big enough gap to warrant splitting into separate hunks\n// (just like `diff -U` does). The procedure:\n// 1. Flush the first maxContextLines of the buffer as trailing context\n// 2. Finalize the current hunk\n// 3. Start a new hunk pre-seeded with the last maxContextLines as leading context\n// The middle portion of the buffer (between the two maxContextLines slices) is\n// the \"collapsed\" region — lines omitted from the diff view.\nfunction splitHunkWithBufferedContext(s: ParseState): void {\n if (s.activeHunk == null) {\n return;\n }\n\n const hunk = s.activeHunk;\n const count = hunk.contextBufferCount;\n const omittedContextLineCount = count - s.maxContextLines2;\n\n // Save trailing context start indices for the next hunk.\n const nextAddStart =\n hunk.contextBufferAdditionStart + count - s.maxContextLines;\n const nextDelStart =\n hunk.contextBufferDeletionStart + count - s.maxContextLines;\n\n // Extract base conflicts that fall within the trailing portion.\n let nextBaseConflicts: Map<number, number> | undefined;\n if (hunk.contextBufferBaseConflicts != null) {\n const tailOffset = count - s.maxContextLines;\n for (const [offset, ci] of hunk.contextBufferBaseConflicts) {\n if (offset >= tailOffset) {\n nextBaseConflicts ??= new Map();\n nextBaseConflicts.set(offset - tailOffset, ci);\n }\n }\n }\n\n flushBufferedContext(s, hunk, 'trailing');\n const emittedAdditionCount = hunk.additionCount;\n const emittedDeletionCount = hunk.deletionCount;\n finalizeActiveHunk(s);\n\n s.activeHunk = createHunkBuilder(\n hunk.additionStart + emittedAdditionCount + omittedContextLineCount,\n hunk.deletionStart + emittedDeletionCount + omittedContextLineCount\n );\n s.activeHunk.contextBufferAdditionStart = nextAddStart;\n s.activeHunk.contextBufferDeletionStart = nextDelStart;\n s.activeHunk.contextBufferCount = s.maxContextLines;\n s.activeHunk.contextBufferBaseConflicts = nextBaseConflicts;\n}\n\n// Adds a context line (identical on both sides of the diff). The line is pushed\n// to both additionLines and deletionLines, then buffered in the hunk's context\n// buffer rather than committed to hunkContent immediately. This deferred write\n// is what enables the leading/trailing trim logic in flushBufferedContext.\n//\n// For base-section lines inside a diff3 conflict, pass the conflict index so\n// the buffer can record the association; when the buffer is flushed, those\n// lines get anchored to the conflict via assignConflictContent.\nfunction emitContextLine(\n s: ParseState,\n line: string,\n baseConflictIndex: number = -1\n): void {\n const hunk = ensureActiveHunk(s);\n // Reset buffer start on first line after a flush/creation.\n if (hunk.contextBufferCount === 0) {\n hunk.contextBufferAdditionStart = s.additionLines.length;\n hunk.contextBufferDeletionStart = s.deletionLines.length;\n }\n s.additionLines.push(line);\n s.deletionLines.push(line);\n if (baseConflictIndex >= 0) {\n hunk.contextBufferBaseConflicts ??= new Map();\n hunk.contextBufferBaseConflicts.set(\n hunk.contextBufferCount,\n baseConflictIndex\n );\n }\n hunk.contextBufferCount++;\n}\n\n// Adds a change line (addition or deletion) to the current hunk. This is the\n// main \"work\" function on the hot path and orchestrates several steps:\n// 1. If there's a large context gap since the last change, split the hunk\n// 2. Flush any buffered context lines (leading trim on first change, or\n// pass-through for mid-hunk context)\n// 3. Push the line to the appropriate line array (additions or deletions)\n// 4. Append/coalesce the change into hunkContent\n// 5. Anchor the conflict action to the content index\nfunction emitChangeLine(\n s: ParseState,\n lineType: 'addition' | 'deletion',\n line: string,\n conflictIndex: number,\n role: MergeConflictSide\n): void {\n let hunk = ensureActiveHunk(s);\n // If the context gap since the last change exceeds 2x maxContextLines,\n // split into two hunks: trailing context for the old, leading for the new.\n if (\n hunk.hunkContent.length > 0 &&\n hunk.contextBufferCount > s.maxContextLines2\n ) {\n splitHunkWithBufferedContext(s);\n hunk = s.activeHunk!;\n }\n\n flushBufferedContext(\n s,\n hunk,\n hunk.hunkContent.length === 0 ? 'leading' : 'before-change'\n );\n\n const additionLineIndex = s.additionLines.length;\n const deletionLineIndex = s.deletionLines.length;\n if (lineType === 'addition') {\n s.additionLines.push(line);\n } else {\n s.deletionLines.push(line);\n }\n\n const contentIndex = appendChangeLine(\n hunk,\n lineType,\n additionLineIndex,\n deletionLineIndex\n );\n\n if (lineType === 'addition') {\n hunk.additionCount++;\n hunk.additionLines++;\n } else {\n hunk.deletionCount++;\n hunk.deletionLines++;\n }\n assignConflictContent(s, conflictIndex, role, contentIndex);\n}\n\n// Called when we hit a >>>>>>> end marker. Takes the completed ConflictFrame\n// and writes the final source-line coordinates and marker text into the\n// conflict action. Also handles empty-side conflicts: if one side had no\n// content lines, we fall back to the other side's content index so the action\n// always has valid anchors. This is what makes conflicts like \"add vs nothing\"\n// or \"nothing vs add\" representable.\nfunction finalizeConflict(\n s: ParseState,\n frame: ConflictFrame,\n endLineIndex: number,\n endMarkerLine: string\n): void {\n if (frame.separatorLineIndex == null || frame.markerLines.separator == null) {\n throw new Error(\n `parseMergeConflictDiffFromFile: conflict ${frame.conflictIndex} is missing a separator marker`\n );\n }\n\n const builder = s.conflictBuilders[frame.conflictIndex];\n if (builder == null) {\n throw new Error(\n `parseMergeConflictDiffFromFile: failed to finalize conflict ${frame.conflictIndex}`\n );\n }\n\n const action = builder.action;\n action.markerLines.separator = frame.markerLines.separator;\n action.markerLines.end = endMarkerLine;\n if (frame.markerLines.base != null) {\n action.markerLines.base = frame.markerLines.base;\n }\n\n action.conflict = {\n conflictIndex: frame.conflictIndex,\n startLineIndex: frame.startLineIndex,\n startLineNumber: frame.startLineIndex + 1,\n separatorLineIndex: frame.separatorLineIndex,\n separatorLineNumber: frame.separatorLineIndex + 1,\n endLineIndex,\n endLineNumber: endLineIndex + 1,\n baseMarkerLineIndex: frame.baseMarkerLineIndex,\n baseMarkerLineNumber:\n frame.baseMarkerLineIndex != null\n ? frame.baseMarkerLineIndex + 1\n : undefined,\n };\n\n // If one side of the conflict was empty (e.g. \"add vs nothing\"), its content\n // index will be undefined. Use the other side as a fallback so the action\n // always has a valid anchor for the UI to render.\n const fallbackContentIndex =\n action.currentContentIndex ?? action.incomingContentIndex;\n action.currentContentIndex ??= fallbackContentIndex;\n action.incomingContentIndex ??= fallbackContentIndex;\n if (action.startContentIndex < 0 && fallbackContentIndex != null) {\n action.startContentIndex = fallbackContentIndex;\n }\n if (action.endContentIndex < 0 && fallbackContentIndex != null) {\n action.endContentIndex = fallbackContentIndex;\n }\n if (action.endMarkerContentIndex < 0 && fallbackContentIndex != null) {\n action.endMarkerContentIndex = fallbackContentIndex;\n }\n\n if (\n action.hunkIndex < 0 ||\n action.startContentIndex < 0 ||\n action.endContentIndex < 0 ||\n action.endMarkerContentIndex < 0\n ) {\n throw new Error(\n `parseMergeConflictDiffFromFile: failed to anchor merge conflict ${frame.conflictIndex}`\n );\n }\n\n s.actions[action.conflictIndex] = action;\n builder.completed = true;\n}\n\n// Pushes a new ConflictFrame onto the stack and creates a placeholder\n// ConflictActionBuilder. The builder starts with sentinel values (-1 for\n// indices) that get filled in as we encounter content lines and markers.\n// The frame tracks which section we're scanning (current → base → incoming);\n// the builder accumulates the final action that downstream consumers use.\nfunction handleStartMarker(\n s: ParseState,\n line: string,\n lineIndex: number\n): void {\n const conflictIndex = s.nextConflictIndex;\n s.nextConflictIndex++;\n s.conflictStack.push({\n conflictIndex,\n stage: 'current',\n startLineIndex: lineIndex,\n markerLines: { start: line },\n });\n s.conflictBuilders[conflictIndex] = {\n completed: false,\n action: {\n conflict: {\n conflictIndex,\n startLineIndex: lineIndex,\n startLineNumber: lineIndex + 1,\n separatorLineIndex: lineIndex,\n separatorLineNumber: lineIndex + 1,\n endLineIndex: lineIndex,\n endLineNumber: lineIndex + 1,\n baseMarkerLineIndex: undefined,\n baseMarkerLineNumber: undefined,\n },\n conflictIndex,\n hunkIndex: -1,\n startContentIndex: -1,\n endContentIndex: -1,\n endMarkerContentIndex: -1,\n markerLines: {\n start: line,\n separator: '',\n end: '',\n },\n },\n };\n}\n\nfunction createHunkBuilder(\n additionStart: number,\n deletionStart: number\n): HunkBuilder {\n return {\n additionStart,\n deletionStart,\n additionCount: 0,\n deletionCount: 0,\n additionLines: 0,\n deletionLines: 0,\n additionLineIndex: Math.max(additionStart - 1, 0),\n deletionLineIndex: Math.max(deletionStart - 1, 0),\n hunkContent: [],\n contextBufferAdditionStart: Math.max(additionStart - 1, 0),\n contextBufferDeletionStart: Math.max(deletionStart - 1, 0),\n contextBufferCount: 0,\n contextBufferBaseConflicts: undefined,\n };\n}\n\nfunction formatHunkRange(start: number, count: number): string {\n return count === 1 ? `${start}` : `${start},${count}`;\n}\n\n// Detects whether a line is a merge conflict marker by inspecting the first\n// character and counting consecutive repetitions. Git conflict markers are\n// 7+ repeated characters:\n// '<' (60) = start (<<<<<<< current)\n// '|' (124) = base (||||||| base)\n// '=' (61) = separator (=======)\n// '>' (62) = end (>>>>>>> incoming)\n// The separator must be exactly '=======' with no trailing text; other markers\n// allow an optional space + label (e.g. \"<<<<<<< HEAD\").\nfunction getMergeConflictMarkerType(\n line: string\n): MergeConflictMarkerType | undefined {\n if (line.length < 7) {\n return undefined;\n }\n\n const markerCode = line.charCodeAt(0);\n if (\n markerCode !== 60 &&\n markerCode !== 62 &&\n markerCode !== 61 &&\n markerCode !== 124\n ) {\n return undefined;\n }\n\n const lineEnd = getLineContentEndIndex(line);\n if (lineEnd < 7) {\n return undefined;\n }\n\n let markerLength = 1;\n while (\n markerLength < lineEnd &&\n line.charCodeAt(markerLength) === markerCode\n ) {\n markerLength++;\n }\n\n if (markerLength < 7) {\n return undefined;\n }\n\n if (markerCode === 61) {\n return markerLength === lineEnd ? 'separator' : undefined;\n }\n\n if (\n markerLength !== lineEnd &&\n !isWhitespaceCode(line.charCodeAt(markerLength))\n ) {\n return undefined;\n }\n\n if (markerCode === 60) {\n return 'start';\n }\n if (markerCode === 62) {\n return 'end';\n }\n return 'base';\n}\n\nfunction getLineContentEndIndex(line: string): number {\n let end = line.length;\n if (end > 0 && line.charCodeAt(end - 1) === 10) {\n end--;\n }\n if (end > 0 && line.charCodeAt(end - 1) === 13) {\n end--;\n }\n return end;\n}\n\nfunction isWhitespaceCode(code: number): boolean {\n return (\n code === 9 ||\n code === 10 ||\n code === 11 ||\n code === 12 ||\n code === 13 ||\n code === 32\n );\n}\n\nfunction createResolvedConflictFile(\n file: FileContents,\n side: 'current' | 'incoming',\n contents: string\n): FileContents {\n return {\n ...file,\n contents,\n cacheKey:\n file.cacheKey != null\n ? `${file.cacheKey}:merge-conflict-${side}`\n : undefined,\n };\n}\n\n// Builds the marker row array that tells the UI where to render conflict\n// decorations (start/base/separator/end lines) in the diff view. Each marker\n// row maps a conflict marker to a specific line index in unified view.\n//\n// This is a post-processing step over the finalized hunks and actions. It\n// caches cumulative line-start positions per hunk to avoid recomputing them\n// for every marker.\nexport function buildMergeConflictMarkerRows(\n fileDiff: FileDiffMetadata,\n actions: (MergeConflictDiffAction | undefined)[]\n): MergeConflictMarkerRow[] {\n const markerRows: MergeConflictMarkerRow[] = [];\n const hunkLineStartCache: (number[] | undefined)[] = new Array(\n fileDiff.hunks.length\n );\n\n const getLineStart = (hunkIndex: number, contentIndex: number): number => {\n const hunk = fileDiff.hunks[hunkIndex];\n if (hunk == null) {\n return 0;\n }\n let starts = hunkLineStartCache[hunkIndex];\n if (starts == null) {\n starts = new Array<number>(hunk.hunkContent.length + 1);\n let lineIndex = hunk.unifiedLineStart;\n starts[0] = lineIndex;\n for (let index = 0; index < hunk.hunkContent.length; index++) {\n const content = hunk.hunkContent[index];\n lineIndex +=\n content.type === 'context'\n ? content.lines\n : content.deletions + content.additions;\n starts[index + 1] = lineIndex;\n }\n hunkLineStartCache[hunkIndex] = starts;\n }\n return starts[Math.max(contentIndex, 0)] ?? hunk.unifiedLineStart;\n };\n\n const getLineEnd = (hunkIndex: number, contentIndex: number): number => {\n const lineStart = getLineStart(hunkIndex, contentIndex);\n const starts = hunkLineStartCache[hunkIndex];\n const lineEndExclusive =\n starts?.[Math.max(contentIndex + 1, 0)] ??\n getLineStart(hunkIndex, contentIndex + 1);\n return Math.max(lineStart, lineEndExclusive - 1);\n };\n\n for (const action of actions) {\n if (action == null) {\n continue;\n }\n\n const hunk = fileDiff.hunks[action.hunkIndex];\n if (hunk == null) {\n continue;\n }\n\n const actionLineIndex = getLineStart(\n action.hunkIndex,\n action.startContentIndex\n );\n markerRows.push(\n createMergeConflictMarkerRow(\n action,\n 'marker-start',\n action.startContentIndex,\n action.markerLines.start,\n actionLineIndex\n )\n );\n\n if (action.baseContentIndex != null) {\n const currentContentIndex = action.currentContentIndex;\n const incomingContentIndex = action.incomingContentIndex;\n if (currentContentIndex == null || incomingContentIndex == null) {\n continue;\n }\n\n const baseMarkerLine = action.markerLines.base;\n if (baseMarkerLine == null) {\n continue;\n }\n\n const currentChange = hunk.hunkContent[currentContentIndex];\n const baseContext = hunk.hunkContent[action.baseContentIndex];\n const incomingChange = hunk.hunkContent[incomingContentIndex];\n if (\n currentChange?.type !== 'change' ||\n baseContext?.type !== 'context' ||\n incomingChange?.type !== 'change'\n ) {\n continue;\n }\n\n const currentStart = getLineStart(action.hunkIndex, currentContentIndex);\n const incomingStart = getLineStart(\n action.hunkIndex,\n incomingContentIndex\n );\n markerRows.push(\n createMergeConflictMarkerRow(\n action,\n 'marker-base',\n action.baseContentIndex,\n baseMarkerLine,\n currentStart + currentChange.deletions\n )\n );\n\n markerRows.push(\n createMergeConflictMarkerRow(\n action,\n 'marker-separator',\n action.baseContentIndex,\n action.markerLines.separator,\n incomingStart\n ),\n createMergeConflictMarkerRow(\n action,\n 'marker-end',\n action.endMarkerContentIndex,\n action.markerLines.end,\n getLineEnd(action.hunkIndex, action.endMarkerContentIndex)\n )\n );\n continue;\n }\n\n const currentContentIndex = action.currentContentIndex;\n if (currentContentIndex == null) {\n continue;\n }\n const content = hunk.hunkContent[currentContentIndex];\n if (content?.type !== 'change') {\n continue;\n }\n\n const contentStart = getLineStart(action.hunkIndex, currentContentIndex);\n const separatorLineIndex =\n content.deletions > 0\n ? contentStart + content.deletions\n : actionLineIndex;\n\n markerRows.push(\n createMergeConflictMarkerRow(\n action,\n 'marker-separator',\n currentContentIndex,\n action.markerLines.separator,\n separatorLineIndex\n ),\n createMergeConflictMarkerRow(\n action,\n 'marker-end',\n action.endMarkerContentIndex,\n action.markerLines.end,\n getLineEnd(action.hunkIndex, action.endMarkerContentIndex)\n )\n );\n }\n\n return markerRows;\n}\n\nfunction createMergeConflictMarkerRow(\n action: MergeConflictDiffAction,\n type: MergeConflictMarkerRowType,\n contentIndex: number,\n lineText: string,\n lineIndex: number\n): MergeConflictMarkerRow {\n return {\n type,\n hunkIndex: action.hunkIndex,\n contentIndex,\n conflictIndex: action.conflictIndex,\n lineText,\n lineIndex,\n };\n}\n\nfunction getUnifiedLineStartForContent(\n hunk: Hunk,\n contentIndex: number\n): number {\n let lineIndex = hunk.unifiedLineStart;\n for (let index = 0; index < contentIndex; index++) {\n const content = hunk.hunkContent[index];\n lineIndex +=\n content.type === 'context'\n ? content.lines\n : content.deletions + content.additions;\n }\n return lineIndex;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parsePatchFiles.d.ts","names":[
|
|
1
|
+
{"version":3,"file":"parsePatchFiles.d.ts","names":[],"sources":["../../src/utils/parsePatchFiles.ts"],"mappings":";;;iBA4BgB,YAAA,CACd,IAAA,UACA,cAAA,WACA,YAAA,aACC,WAAW;AAAA,UAqEJ,kBAAA;EACR,QAAA;EACA,SAAA;EACA,OAAA,GAAU,YAAA;EACV,OAAA,GAAU,YAAY;EACtB,YAAA;AAAA;AAAA,iBAGc,WAAA,CACd,cAAA,UACA,OAAA,GAAU,kBAAA,GACT,gBAAgB;;;AAhFL;AAMb;;;;;iBAwiBe,eAAA,CACd,IAAA,UACA,cAAA,WACA,YAAA,aACC,WAAW"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ALTERNATE_FILE_NAMES_GIT, COMMIT_METADATA_SPLIT, FILENAME_HEADER_REGEX, FILENAME_HEADER_REGEX_GIT, GIT_DIFF_FILE_BREAK_REGEX, INDEX_LINE_METADATA } from "../constants.js";
|
|
2
2
|
import { cleanLastNewline } from "./cleanLastNewline.js";
|
|
3
3
|
import { detachString, releaseStringDetachBuffer } from "./detachString.js";
|
|
4
|
-
|
|
5
4
|
//#region src/utils/parsePatchFiles.ts
|
|
6
5
|
function processPatch(data, cacheKeyPrefix, throwOnError) {
|
|
7
6
|
try {
|
|
@@ -85,9 +84,9 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
|
|
|
85
84
|
if (currentFile.deletionLines.length === 1 && oldFile?.contents === "") currentFile.deletionLines.length = 0;
|
|
86
85
|
for (const line of lines) {
|
|
87
86
|
if (line.startsWith("diff --git")) {
|
|
88
|
-
const filenameMatch
|
|
89
|
-
const prevName = filenameMatch
|
|
90
|
-
const name = filenameMatch
|
|
87
|
+
const filenameMatch = line.trim().match(ALTERNATE_FILE_NAMES_GIT);
|
|
88
|
+
const prevName = filenameMatch?.[1] ?? filenameMatch?.[2];
|
|
89
|
+
const name = filenameMatch?.[3] ?? filenameMatch?.[4];
|
|
91
90
|
if (prevName == null || name == null) {
|
|
92
91
|
if (throwOnError) throw Error("parsePatchContent: invalid git diff header");
|
|
93
92
|
else console.error("parsePatchContent: invalid git diff header", line);
|
|
@@ -253,9 +252,9 @@ function _processFile(fileDiffString, { cacheKey, isGitDiff = GIT_DIFF_FILE_BREA
|
|
|
253
252
|
if (throwOnError && isPartial && !isGitDiff && currentFile.hunks.length === 0) throw Error("parsePatchContent: unified file has no hunks");
|
|
254
253
|
if (currentFile.hunks.length > 0 && !isPartial && currentFile.additionLines.length > 0 && currentFile.deletionLines.length > 0) {
|
|
255
254
|
const lastHunk = currentFile.hunks[currentFile.hunks.length - 1];
|
|
256
|
-
const lastHunkEnd
|
|
255
|
+
const lastHunkEnd = lastHunk.additionStart + lastHunk.additionCount - 1;
|
|
257
256
|
const totalFileLines = currentFile.additionLines.length;
|
|
258
|
-
const collapsedAfter = Math.max(totalFileLines - lastHunkEnd
|
|
257
|
+
const collapsedAfter = Math.max(totalFileLines - lastHunkEnd, 0);
|
|
259
258
|
currentFile.splitLineCount += collapsedAfter;
|
|
260
259
|
currentFile.unifiedLineCount += collapsedAfter;
|
|
261
260
|
}
|
|
@@ -495,7 +494,7 @@ function createContentGroup(type, deletionLineIndex, additionLineIndex) {
|
|
|
495
494
|
deletionLineIndex
|
|
496
495
|
};
|
|
497
496
|
}
|
|
498
|
-
|
|
499
497
|
//#endregion
|
|
500
498
|
export { parsePatchFiles, processFile, processPatch };
|
|
499
|
+
|
|
501
500
|
//# sourceMappingURL=parsePatchFiles.js.map
|