v4.1.0
🚀 NEW FEATURE: getTextDiff
import { getTextDiff } from "@donedeal0/superdiff";Compares two texts and returns a structured diff at a character, word, or sentence level.
FORMAT
Input
previousText: string | null | undefined,
currentText: string | null | undefined,
options?: {
separation?: "character" | "word" | "sentence", // "word" by default
accuracy?: "normal" | "high", // "normal" by default
detectMoves?: boolean // false by default
ignoreCase?: boolean, // false by default
ignorePunctuation?: boolean, // false by default
locale?: Intl.Locale | string // undefined by default
}previousText: the original text.currentText: the current text.optionsseparationwhether you want acharacter,wordorsentencebased diff.accuracy:normal(default): fastest mode, simple tokenization.high: slower but exact tokenization. Handles all language subtleties (Unicode, emoji, CJK scripts, locale‑aware segmentation when a locale is provided).
detectMoves:false(default): optimized for readability. Token moves are ignored so insertions don’t cascade and break equality (recommended for UI diffing).true: semantically precise, but noiser — a single insertion shifts all following tokens, breaking equality.
ignoreCase: iftrue,helloandHELLOare considered equal.ignorePunctuation: iftrue,hello!andhelloare considered equal.locale: the locale of your text. Enables locale‑aware segmentation in high accuracy mode.
Output
type TextDiff = {
type: "text";
status: "added" | "deleted" | "equal" | "updated";
diff: {
value: string;
index: number | null;
previousValue?: string;
previousIndex: number | null;
status: "added" | "deleted" | "equal" | "moved" | "updated";
}[];
};USAGE
WITHOUT MOVES DETECTION
This is the default output. Token moves are ignored so insertions don’t cascade and break equality. Updates are rendered as two entries (added + deleted). The algorithm uses longest common subsequence (LCS), similar to GitHub diffs.
Input
getTextDiff(
- "The brown fox jumped high",
+ "The orange cat has jumped",
{ detectMoves: false, separation: "word" }
);Output
{
type: "text",
+ status: "updated",
diff: [
{
value: 'The',
index: 0,
previousIndex: 0,
status: 'equal',
},
- {
- value: "brown",
- index: null,
- previousIndex: 1,
- status: "deleted",
- },
- {
- value: "fox",
- index: null,
- previousIndex: 2,
- status: "deleted",
- },
+ {
+ value: "orange",
+ index: 1,
+ previousIndex: null,
+ status: "added",
+ },
+ {
+ value: "cat",
+ index: 2,
+ previousIndex: null,
+ status: "added",
+ },
+ {
+ value: "has",
+ index: 3,
+ previousIndex: null,
+ status: "added",
+ },
{
value: "jumped",
index: 4,
previousIndex: 3,
status: "equal",
},
- {
- value: "high",
- index: null,
- previousIndex: 4,
- status: "deleted",
- }
],
}WITH MOVE DETECTION
If you prefer a semantically precise diff, activate the detectMoves option. Direct token swaps are considered updated.
Input
getTextDiff(
- "The brown fox jumped high",
+ "The orange cat has jumped",
{ detectMoves: true, separation: "word" }
);Output
{
type: "text",
+ status: "updated",
diff: [
{
value: 'The',
index: 0,
previousIndex: 0,
status: 'equal',
},
+ {
+ value: "orange",
+ index: 1,
+ previousValue: "brown",
+ previousIndex: null,
+ status: "updated",
+ },
+ {
+ value: "cat",
+ index: 2,
+ previousValue: "fox",
+ previousIndex: null,
+ status: "updated",
+ },
+ {
+ value: "has",
+ index: 3,
+ previousIndex: null,
+ status: "added",
+ },
+ {
+ value: "jumped",
+ index: 4,
+ previousIndex: 3,
+ status: "moved",
+ },
- {
- value: "high",
- index: null,
- previousIndex: 4,
- status: "deleted",
- }
],
}📊 BENCHMARK
| Scenario | Superdiff | diff |
|---|---|---|
| 10k words | 1.13 ms | 3.68 ms |
| 100k words | 21.68 ms | 45.93 ms |
| 10k sentences | 2.30 ms | 5.61 ms |
| 100k sentences | 21.95 ms | 62.03 ms |
(Superdiff uses its normal accuracy settings to match diff's behavior)