Diffine
Движок сравнения и просмотр в две колонки для текста и для изображений, выпущенные как библиотека React и как пакет Flutter. Он сопоставляет две версии построчно, а внутри изменённых строк — по словам, сравнивает два изображения попиксельно и рисует результат, удерживая обе стороны на одной высоте, так что приложению не приходится писать ни сравнение, ни выравнивание.
Об этом проекте
Diffine находит, что изменилось между двумя версиями, и выводит это на экран — для текста и для изображений, в React и во Flutter. Сравнение и отображение — одна библиотека, а не пакет различий с приделанным сверху просмотрщиком: обе половины встречаются на значении. diffText возвращает строки, изменения и счётчики, а diffImage — маску, изменённые области в виде прямоугольников и счётчики, и ни в одном из них нет ни компонента, ни виджета. Просмотр — один из потребителей этого значения, а не единственный путь к нему, поэтому то же сравнение можно напечатать в терминале, выполнить в воркере или сверить с порогом при сборке. Унифицированный патч — тоже сравнение: parsePatch превращает его в то же значение, а formatPatch записывает обратно.
Текст сопоставляется в два уровня за один проход. Сначала строки собираются в пары, а затем внутри пары, которую отредактировали, а не заменили, отмечаются слова или символы, которые действительно сдвинулись. Просмотр рисует это на двух панелях, удерживаемых на одной высоте, с перемычками через промежуток, и каждая часть вида — настройка со значением по умолчанию: номера строк, перенос, выравнивание, перемычки, объединённый вид и сворачивание строк, которые никто не правил. Режим редактора накладывает на каждую панель поле ввода и пересчитывает сравнение при каждом нажатии клавиши. Изображения сравниваются бок о бок, наложением с прозрачностью, шторкой или одной только маской, причём с допуском, без учёта сглаживания, которое оставляет рендерер, и с поиском смещения между двумя снимками, которые не совпадают по положению; diffImages сравнивает больше двух изображений сразу, а imageSimilarity отвечает одним числом. Читать без мыши получается: каждая панель — область, принимающая фокус, у кнопок перехода к следующему изменению есть подписи, а об изменениях сообщается сразу же.
Установка в вебе — это пакет и одна строка CSS, во Flutter — один импорт. У каждого пакета одна зависимость: пакет для React добавляет highlight.js для подсветки синтаксиса, причём грамматики загружаются по одной через динамический импорт, так что сравнение простого текста не скачивает из него ничего, а пакет для Flutter добавляет characters, который Flutter и так поставляет. react и react-dom объявлены как peer-зависимости, поэтому используются те копии, которые у приложения уже есть. Оба пакета используют общий движок и общую палитру вплоть до значений цветов, а тёмная тема следует системной настройке. Пакет для React собран в ESM с описаниями типов TypeScript, а его корень — только движок, просмотрщики же лежат в diffine-react/text-diff и diffine-react/image-diff, так что приложение, которому нужно только сравнение, не тянет за собой ни одного просмотрщика.
Возможности
Сайт документации
Типы TypeScript
Несколько языков
Проверено тестами
Кроссплатформенность
Доступность из коробки
Тёмная тема
Поддержка tree shaking
