Create unified diff patches from text comparisons with full context control. Generates standard Unix diff format patches that can be applied with the patch command or the library's own apply functions.
Creates a unified diff patch for a single file with before and after content.
/**
* Create a unified diff patch for a single file
* @param fileName - Name of the file being patched
* @param oldStr - Original content
* @param newStr - New content
* @param oldHeader - Optional header for old file (e.g., timestamp)
* @param newHeader - Optional header for new file (e.g., timestamp)
* @param options - Configuration options
* @returns String containing the unified diff patch
*/
function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options);Creates a unified diff patch comparing two different files.
/**
* Create a unified diff patch for two different files
* @param oldFileName - Name of the original file
* @param newFileName - Name of the new file
* @param oldStr - Original content
* @param newStr - New content
* @param oldHeader - Optional header for old file
* @param newHeader - Optional header for new file
* @param options - Configuration options
* @returns String containing the unified diff patch
*/
function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);Creates a structured patch object instead of a formatted string, useful for programmatic manipulation.
/**
* Create a structured patch object
* @param oldFileName - Name of the original file
* @param newFileName - Name of the new file
* @param oldStr - Original content
* @param newStr - New content
* @param oldHeader - Optional header for old file
* @param newHeader - Optional header for new file
* @param options - Configuration options
* @returns Structured patch object
*/
function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);Formats a structured patch object (or array of patches) into unified diff string format.
/**
* Format structured patch to unified diff string
* @param patch - Structured patch object or array of patches
* @returns String containing formatted unified diff
*/
function formatPatch(patch);interface PatchCreationOptions {
context?: number; // Lines of context around changes (default: 4)
ignoreWhitespace?: boolean; // Ignore whitespace in line comparisons
stripTrailingCr?: boolean; // Remove \r characters before \n
callback?: (patch: any) => void; // Async callback
maxEditLength?: number; // Limit computation complexity
timeout?: number; // Timeout in milliseconds
}
interface StructuredPatch {
oldFileName: string;
newFileName: string;
oldHeader?: string;
newHeader?: string;
hunks: Hunk[];
}
interface Hunk {
oldStart: number; // Starting line in old file
oldLines: number; // Number of lines in old file
newStart: number; // Starting line in new file
newLines: number; // Number of lines in new file
lines: string[]; // Diff lines with +/- prefixes
}import { createPatch } from "diff";
// Simple file patch
const patch = createPatch(
"hello.txt",
"Hello World\nGoodbye World",
"Hello Universe\nGoodbye World"
);
console.log(patch);
// Output:
// Index: hello.txt
// ===================================================================
// --- hello.txt
// +++ hello.txt
// @@ -1,2 +1,2 @@
// -Hello World
// +Hello Universe
// Goodbye Worldimport { createTwoFilesPatch } from "diff";
// Compare different files
const patch = createTwoFilesPatch(
"old-config.json",
"new-config.json",
'{\n "version": "1.0",\n "debug": true\n}',
'{\n "version": "1.1",\n "debug": false,\n "feature": "enabled"\n}',
"2023-01-01 10:00:00",
"2023-01-02 10:00:00"
);
console.log(patch);
// Includes file headers and timestampsimport { structuredPatch, formatPatch } from "diff";
// Create structured patch
const structured = structuredPatch(
"file.txt",
"file.txt",
"line1\nline2\nline3",
"line1\nmodified\nline3"
);
console.log("Hunks:", structured.hunks.length);
console.log("Changes:", structured.hunks[0].lines);
// Convert back to string format
const formatted = formatPatch(structured);
console.log("Formatted patch:", formatted);import { createPatch } from "diff";
// Minimal context
const minimalPatch = createPatch(
"file.txt",
oldContent,
newContent,
null,
null,
{ context: 1 }
);
// Maximum context (entire file)
const fullPatch = createPatch(
"file.txt",
oldContent,
newContent,
null,
null,
{ context: Number.MAX_SAFE_INTEGER }
);
// No context
const noContextPatch = createPatch(
"file.txt",
oldContent,
newContent,
null,
null,
{ context: 0 }
);import { createTwoFilesPatch } from "diff";
import fs from "fs";
function createCommitPatch(filePath, oldCommit, newCommit) {
const oldContent = fs.readFileSync(`${oldCommit}/${filePath}`, 'utf8');
const newContent = fs.readFileSync(`${newCommit}/${filePath}`, 'utf8');
return createTwoFilesPatch(
`a/${filePath}`,
`b/${filePath}`,
oldContent,
newContent,
oldCommit,
newCommit,
{ context: 3 }
);
}
// Usage
const commitDiff = createCommitPatch("src/main.js", "abc123", "def456");import { structuredPatch, formatPatch } from "diff";
function createMultiFilePatch(fileChanges) {
const patches = fileChanges.map(change =>
structuredPatch(
change.oldPath,
change.newPath,
change.oldContent,
change.newContent,
change.oldHeader,
change.newHeader
)
);
return formatPatch(patches);
}
// Usage
const multiPatch = createMultiFilePatch([
{
oldPath: "file1.txt",
newPath: "file1.txt",
oldContent: "old content 1",
newContent: "new content 1"
},
{
oldPath: "file2.txt",
newPath: "file2.txt",
oldContent: "old content 2",
newContent: "new content 2"
}
]);import { createPatch } from "diff";
function createLargePatch(oldContent, newContent, callback) {
createPatch(
"large-file.txt",
oldContent,
newContent,
null,
null,
{
context: 5,
callback: (patch) => {
if (patch) {
callback(null, patch);
} else {
callback(new Error("Patch creation timed out or exceeded limits"));
}
},
timeout: 30000,
maxEditLength: 20000
}
);
}
// Usage
createLargePatch(largeOldFile, largeNewFile, (error, patch) => {
if (error) {
console.error("Patch creation failed:", error);
} else {
console.log("Patch created successfully");
fs.writeFileSync("changes.patch", patch);
}
});import { createPatch } from "diff";
// Ignore whitespace changes
const noWhitespacePatch = createPatch(
"code.js",
"function hello() {\n return 'world';\n}",
"function hello() {\n return 'world';\n}",
null,
null,
{
ignoreWhitespace: true,
context: 2
}
);
// Cross-platform line endings
const crossPlatformPatch = createPatch(
"text.txt",
"line1\r\nline2\r\n", // Windows
"line1\nline2\n", // Unix
null,
null,
{ stripTrailingCr: true }
);import { createTwoFilesPatch } from "diff";
import { execSync } from "child_process";
function generateBuildDiff(sourceFile) {
const originalContent = fs.readFileSync(sourceFile, 'utf8');
// Run build process
execSync('npm run build');
const builtContent = fs.readFileSync(`dist/${path.basename(sourceFile)}`, 'utf8');
return createTwoFilesPatch(
sourceFile,
`dist/${path.basename(sourceFile)}`,
originalContent,
builtContent,
"source",
"built",
{ context: 1 }
);
}import { structuredPatch } from "diff";
function analyzePatch(oldContent, newContent) {
const patch = structuredPatch("file", "file", oldContent, newContent);
const analysis = {
hunks: patch.hunks.length,
linesAdded: 0,
linesRemoved: 0,
linesContext: 0,
changeBlocks: []
};
patch.hunks.forEach((hunk, hunkIndex) => {
const blockAnalysis = {
hunkIndex,
oldStart: hunk.oldStart,
newStart: hunk.newStart,
changes: []
};
hunk.lines.forEach(line => {
if (line.startsWith('+')) {
analysis.linesAdded++;
blockAnalysis.changes.push({ type: 'add', content: line.slice(1) });
} else if (line.startsWith('-')) {
analysis.linesRemoved++;
blockAnalysis.changes.push({ type: 'remove', content: line.slice(1) });
} else if (line.startsWith(' ')) {
analysis.linesContext++;
}
});
analysis.changeBlocks.push(blockAnalysis);
});
return analysis;
}
// Usage
const patchAnalysis = analyzePatch(oldCode, newCode);
console.log(`Changes: +${patchAnalysis.linesAdded} -${patchAnalysis.linesRemoved}`);