/** * Compute the Sørensen–Dice coefficient between two strings. * Used for move detection (rename detection by content similarity). * * Returns a value between 0 (no similarity) and 1 (identical). */ export function stringSimilarity(a: string, b: string): number { if (a === b) return 1; if (a.length < 2 || b.length < 2) return 0; const bigramsA = getBigrams(a); const bigramsB = getBigrams(b); let intersection = 0; for (const [bigram, countA] of bigramsA) { const countB = bigramsB.get(bigram) ?? 0; intersection += Math.min(countA, countB); } const total = bigramsA.size + bigramsB.size; if (total === 0) return 0; return (2 * intersection) / total; } function getBigrams(str: string): Map { const bigrams = new Map(); for (let i = 0; i < str.length - 1; i++) { const bigram = str.slice(i, i + 2); bigrams.set(bigram, (bigrams.get(bigram) ?? 0) + 1); } return bigrams; }