UNPKG

nhb-toolbox

Version:

A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.

159 lines (158 loc) 5.26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.computeTextDiff = computeTextDiff; exports.getCharacterDifferences = getCharacterDifferences; const helpers_1 = require("./helpers"); function computeTextDiff(originalText, modifiedText) { const originalLines = originalText.split('\n'); const modifiedLines = modifiedText.split('\n'); const originalLen = originalLines.length; const modifiedLen = modifiedLines.length; const lcs = Array(originalLen + 1) .fill(null) .map(() => Array(modifiedLen + 1).fill(0)); for (let i = 1; i <= originalLen; i++) { for (let j = 1; j <= modifiedLen; j++) { if (originalLines[i - 1] === modifiedLines[j - 1]) { lcs[i][j] = lcs[i - 1][j - 1] + 1; } else { lcs[i][j] = Math.max(lcs[i - 1][j], lcs[i][j - 1]); } } } const diffLines = []; let i = originalLen; let j = modifiedLen; while (i > 0 || j > 0) { if (i > 0 && j > 0 && originalLines[i - 1] === modifiedLines[j - 1]) { diffLines.unshift({ type: 'unchanged', original: originalLines[i - 1], modified: modifiedLines[j - 1], originalLineNum: i, modifiedLineNum: j, }); i--; j--; } else if (j > 0 && (i === 0 || lcs[i][j - 1] >= lcs[i - 1][j])) { diffLines.unshift({ type: 'added', modified: modifiedLines[j - 1], modifiedLineNum: j, }); j--; } else if (i > 0) { diffLines.unshift({ type: 'removed', original: originalLines[i - 1], originalLineNum: i, }); i--; } } const processedLines = []; const usedIndices = new Set(); const SIMILARITY_THRESHOLD = 0.6; for (let idx = 0; idx < diffLines.length; idx++) { if (usedIndices.has(idx)) continue; const line = diffLines[idx]; if (line.type === 'removed') { for (let jdx = idx + 1; jdx < diffLines.length; jdx++) { if (usedIndices.has(jdx)) continue; const nextLine = diffLines[jdx]; if (nextLine.type === 'added') { const similarity = (0, helpers_1._calculateSimilarity)(line.original || '', nextLine.modified || ''); if (similarity >= SIMILARITY_THRESHOLD) { processedLines.push({ type: 'modified', original: line.original, modified: nextLine.modified, originalLineNum: line.originalLineNum, modifiedLineNum: nextLine.modifiedLineNum, }); usedIndices.add(idx); usedIndices.add(jdx); break; } } } if (!usedIndices.has(idx)) { processedLines.push(line); usedIndices.add(idx); } } else if (line.type !== 'added' || !usedIndices.has(idx)) { if (line.type !== 'added' || !usedIndices.has(idx)) { processedLines.push(line); usedIndices.add(idx); } } } let linesAdded = 0; let linesRemoved = 0; let linesChanged = 0; let linesUnchanged = 0; for (const line of processedLines) { if (line.type === 'added') { linesAdded++; } else if (line.type === 'removed') { linesRemoved++; } else if (line.type === 'modified') { linesChanged++; } else if (line.type === 'unchanged') { linesUnchanged++; } } return { lines: processedLines, stats: { linesAdded, linesRemoved, linesChanged, linesUnchanged, }, }; } function getCharacterDifferences(original, modified) { const result = { original: [], modified: [], }; if (!original && !modified) return result; if (!original) { return { original: [], modified: modified.split('').map((text) => ({ text, highlighted: true })), }; } if (!modified) { return { original: original.split('').map((text) => ({ text, highlighted: true })), modified: [], }; } const lcsTable = (0, helpers_1._buildCharLcsTable)(original, modified); const [origMatched, modMatched] = (0, helpers_1._getLcsIndices)(original, modified, lcsTable); for (let i = 0; i < original.length; i++) { result.original.push({ text: original[i], highlighted: !origMatched.has(i), }); } for (let j = 0; j < modified.length; j++) { result.modified.push({ text: modified[j], highlighted: !modMatched.has(j), }); } return result; }