| | 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'); |
| | } |
| |
|