or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

array-diffing.mdcharacter-diffing.mdcss-diffing.mdcustom-diffing.mdformat-conversion.mdindex.mdjson-diffing.mdline-diffing.mdpatch-application.mdpatch-creation.mdpatch-utilities.mdsentence-diffing.mdword-diffing.md
tile.json

patch-creation.mddocs/

Patch Creation

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.

Capabilities

createPatch Function

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

createTwoFilesPatch Function

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

structuredPatch Function

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

formatPatch Function

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

Options and Types

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
}

Usage Examples

Basic Patch Creation

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 World

Two Files Comparison

import { 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 timestamps

Structured Patch Manipulation

import { 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);

Advanced Usage

Custom Context Size

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

Version Control Integration

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");

Multiple File Patches

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"
  }
]);

Async Patch Creation

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

Whitespace Handling

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

Build System Integration

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

Patch Analysis

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