A dependency-free TypeScript CLI that diffs two text files using a from-scratch implementation of Myers' O(ND) shortest-edit-script algorithm, and renders the result as a colorized unified diff, a side-by-side view, or a stats summary.
Most people reach for diff -u and never think about how it decides which
lines changed when many different edit sequences could turn file A into file
B. seamwright implements Eugene Myers' 1986 algorithm itself — no diff
binary, no npm diff library — including the classic O(ND) frontier search,
backtracking through the trace to recover the actual edit script, and
grouping the result into @@ ... @@ hunks with configurable context, the
same way real unified diffs do.
Requires Node.js 18+.
npm install
npm run build
node dist/src/cli.js <fileA> <fileB> [options]Or try the bundled demo (builds, then diffs examples/before.txt against
examples/after.txt):
npm run demo--mode <unified|side-by-side|stats> output mode (default: unified)
--context <n> context lines for unified mode (default: 3)
--width <n> column width for side-by-side mode (default: 40)
--no-color disable ANSI colors
-h, --help show help
Exit code is 0 if the files are identical, 1 otherwise (handy for
scripting).
$ node dist/src/cli.js examples/before.txt examples/after.txt --no-color
@@ -1,10 +1,15 @@
function greet(name) {
- console.log("Hello, " + name);
+ console.log(`Hello, ${name}!`);
}
+ function shout(name) {
+ console.log(name.toUpperCase());
+ }
+
function farewell(name) {
console.log("Goodbye, " + name);
}
greet("world");
+ shout("world");
farewell("world");Same diff, side by side:
$ node dist/src/cli.js examples/before.txt examples/after.txt --mode side-by-side --no-color
function greet(name) { │ function greet(name) {
console.log("Hello, " + name); │
│ console.log(`Hello, ${name}!`);
} │ }Or just the numbers:
$ node dist/src/cli.js examples/before.txt examples/after.txt --mode stats --no-color
similarity: 72.0%
unchanged: 9
insertions: +6
deletions: -1
edit distance: 7src/myers.ts— the diff engine. It walks the "edit graph" (a grid where moving right deletes from A, moving down inserts from B, and moving diagonally means the lines matched) outward by increasing edit distanced, tracking only the furthest-reaching x-coordinate reached on each diagonalk = x - yfor eachd. That frontier search is what makes the algorithm O(ND) instead of the naive O(N·M) dynamic-programming table. Once the search reaches the bottom-right corner, it backtracks through the recorded frontiers (the "trace") to recover the actual sequence of equal/insert/delete operations — the shortest edit script.src/render.ts— turns the flat op list into adiff -u-style unified view (grouping changes into@@ @@hunks and collapsing long unchanged runs beyond the context window), a two-column side-by-side view, or a stats summary (similarity %, insertions, deletions, edit distance).src/cli.ts— argument parsing and file I/O.
test/test.ts exercises the diff engine directly: it checks that replaying
the returned op list reconstructs both the original and target sequences
exactly, across identical inputs, empty inputs, pure insertions/deletions,
full replacements, and a mixed case — plus a known-optimal edit-distance
check for a single substitution.
npm testMIT © neverlone