Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

text-diff-patch

CI

Zero-dependency line-based diff and patch for TypeScript/JavaScript: Myers O(ND) diff producing unified-diff-style hunks, fuzzy patch application with reject reporting, and a word-level intra-line diff highlighter.

Why

Most diff libraries either only diff or only apply, and few report why a hunk failed to apply against a shifted file. This package does both directions with zero runtime dependencies, strict TypeScript, and an explicit fuzz tolerance for applying patches against slightly-moved text — the case agents hit constantly when re-applying an edit to a file that changed underneath them.

Install

npm install @ferrow/text-diff-patch

Quickstart

import { createPatch, applyPatch, highlightWordDiff } from "text-diff-patch";

const patch = createPatch(oldText, newText, { oldFile: "a", newFile: "b" });
console.log(patch); // unified-diff-style string

const { result, applied, rejects } = applyPatch(oldText, patch, { fuzz: 3 });
// applied: number of hunks applied; rejects: hunks that couldn't be placed

highlightWordDiff("hello world", "hello there");
// "hello {-world-}{+there+}"

API

myersDiff(a: string[], b: string[]): DiffOp[]

Raw Myers O(ND) line-array diff. DiffOp = { type: "equal"|"delete"|"insert", value: string }.

toLines(text: string): string[]

Splits text into lines (""[]).

buildHunks(ops: DiffOp[], context = 3): Hunk[]

Groups a DiffOp[] into unified-diff hunks with context lines of surrounding unchanged text; adjacent changes within 2 * context lines merge into one hunk.

createPatch(oldText: string, newText: string, options?: CreatePatchOptions): string

Full unified-diff text. CreatePatchOptions = { context?: number; oldFile?: string; newFile?: string }.

parsePatch(patchText: string): Hunk[]

Parses a unified-diff string back into Hunk[] ({ oldStart, oldLines, newStart, newLines, lines }).

applyPatch(text: string, patch: string | Hunk[], options?: ApplyOptions): ApplyResult

Applies hunks to text. ApplyOptions = { fuzz?: number } — with fuzz > 0, a hunk whose exact recorded line is off is retried at nearby offsets (±1..±fuzz) before being rejected. ApplyResult = { result: string; applied: number; rejects: RejectedHunk[] }, RejectedHunk = { hunk: Hunk; reason: string }.

tokenizeWords(line: string): string[]

Splits a line into word/whitespace tokens, exactly reconstructible via join("").

diffWords(a: string, b: string): DiffOp[]

Word-level Myers diff over tokenized lines.

highlightWordDiff(a: string, b: string, options?: HighlightOptions): string

Renders a word-diff as one string with insertions/deletions wrapped in markers. HighlightOptions = { insertOpen?, insertClose?, deleteOpen?, deleteClose? } (defaults: {+...+} / {-...-}).

Limits

  • Line-based only — myersDiff/createPatch operate on \n-split lines, not characters (use diffWords for intra-line detail).
  • applyPatch's fuzz search is a bounded ±N-line offset retry per hunk, not a general approximate-matching algorithm — very large shifts or heavily edited context will still reject.
  • No binary-file support; input is always treated as text.
  • parsePatch expects hunk bodies to use exactly one leading ' '/'+'/'-' per line (standard unified-diff shape) — it does not tolerate tab-indented or CRLF-mixed patches.

Part of the ferrow-toolkit collection · Sponsored by Ferrow

About

Zero-dependency Myers line diff, unified-diff hunks, fuzzy patch apply with reject reporting, word-level highlighting

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages