| import { createTwoFilesPatch } from 'diff'; |
| import type { FileMap } from '~/lib/stores/files'; |
| import { MODIFICATIONS_TAG_NAME, WORK_DIR } from './constants'; |
|
|
| export const modificationsRegex = new RegExp( |
| `^<${MODIFICATIONS_TAG_NAME}>[\\s\\S]*?<\\/${MODIFICATIONS_TAG_NAME}>\\s+`, |
| 'g', |
| ); |
|
|
| interface ModifiedFile { |
| type: 'diff' | 'file'; |
| content: string; |
| } |
|
|
| type FileModifications = Record<string, ModifiedFile>; |
|
|
| export function computeFileModifications(files: FileMap, modifiedFiles: Map<string, string>) { |
| const modifications: FileModifications = {}; |
|
|
| let hasModifiedFiles = false; |
|
|
| for (const [filePath, originalContent] of modifiedFiles) { |
| const file = files[filePath]; |
|
|
| if (file?.type !== 'file') { |
| continue; |
| } |
|
|
| const unifiedDiff = diffFiles(filePath, originalContent, file.content); |
|
|
| if (!unifiedDiff) { |
| |
| continue; |
| } |
|
|
| hasModifiedFiles = true; |
|
|
| if (unifiedDiff.length > file.content.length) { |
| |
| modifications[filePath] = { type: 'file', content: file.content }; |
| } else { |
| |
| modifications[filePath] = { type: 'diff', content: unifiedDiff }; |
| } |
| } |
|
|
| if (!hasModifiedFiles) { |
| return undefined; |
| } |
|
|
| return modifications; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function diffFiles(fileName: string, oldFileContent: string, newFileContent: string) { |
| let unifiedDiff = createTwoFilesPatch(fileName, fileName, oldFileContent, newFileContent); |
|
|
| const patchHeaderEnd = `--- ${fileName}\n+++ ${fileName}\n`; |
| const headerEndIndex = unifiedDiff.indexOf(patchHeaderEnd); |
|
|
| if (headerEndIndex >= 0) { |
| unifiedDiff = unifiedDiff.slice(headerEndIndex + patchHeaderEnd.length); |
| } |
|
|
| if (unifiedDiff === '') { |
| return undefined; |
| } |
|
|
| return unifiedDiff; |
| } |
|
|
| const regex = new RegExp(`^${WORK_DIR}\/`); |
|
|
| |
| |
| |
| export function extractRelativePath(filePath: string) { |
| return filePath.replace(regex, ''); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function fileModificationsToHTML(modifications: FileModifications) { |
| const entries = Object.entries(modifications); |
|
|
| if (entries.length === 0) { |
| return undefined; |
| } |
|
|
| const result: string[] = [`<${MODIFICATIONS_TAG_NAME}>`]; |
|
|
| for (const [filePath, { type, content }] of entries) { |
| result.push(`<${type} path=${JSON.stringify(filePath)}>`, content, `</${type}>`); |
| } |
|
|
| result.push(`</${MODIFICATIONS_TAG_NAME}>`); |
|
|
| return result.join('\n'); |
| } |
|
|