import assert from 'node:assert/strict'; import { test } from 'node:test'; import { applyChanges, minimalChange, normalizeEol, offsetOf, positionOf } from '../src/util/textDiff'; test('minimalChange keeps the common start and end', () => { assert.equal(minimalChange('abc', 'abc'), undefined); assert.deepEqual(minimalChange('label: SQL', 'lable: SQL'), { from: 3, to: 5, insert: 'le' }); assert.deepEqual(minimalChange('a\nb\n', 'a\nx\nb\n'), { from: 2, to: 2, insert: 'x\n' }); assert.deepEqual(minimalChange('aaa', 'aa'), { from: 2, to: 3, insert: '' }); assert.deepEqual(minimalChange('', 'new'), { from: 0, to: 0, insert: 'new' }); }); test('minimalChange round-trips through applyChanges', () => { const pairs = [['schema_version: 1\nmeta:\n title: A\n', 'schema_version: 1\nmeta:\n title: B\n output: b.html\n'], ['x', ''], ['', 'y'], ['abab', 'ab']]; for (const [before, after] of pairs) { const change = minimalChange(before, after)!; assert.equal(applyChanges(before, [change]), after); } }); test('applyChanges takes several changes in the coordinates of the original text', () => { assert.equal(applyChanges('one two three', [{ from: 0, to: 3, insert: '1' }, { from: 8, to: 13, insert: '3' }]), '1 two 3'); }); test('positions and offsets in "\\n" text', () => { const text = 'ab\ncde\n\nf'; assert.deepEqual(positionOf(text, 0), { line: 0, character: 0 }); assert.deepEqual(positionOf(text, 4), { line: 1, character: 1 }); assert.deepEqual(positionOf(text, 7), { line: 2, character: 0 }); assert.deepEqual(positionOf(text, 99), { line: 3, character: 1 }); for (let offset = 0; offset <= text.length; offset++) { const { line, character } = positionOf(text, offset); assert.equal(offsetOf(text, line, character), offset); } assert.equal(offsetOf(text, 0, 50), 2, 'clamped to the end of the line'); assert.equal(offsetOf(text, 9, 0), text.length); }); test('normalizeEol', () => { assert.equal(normalizeEol('a\r\nb\nc\r\n'), 'a\nb\nc\n'); });