updated design

This commit is contained in:
SinachPat
2026-04-25 22:52:30 +01:00
parent df79ae0bca
commit e836ac6d2b
22 changed files with 3480 additions and 781 deletions
@@ -0,0 +1,73 @@
import { describe, it, expect } from 'vitest';
import { computeEditScript } from '../src/myers.js';
describe('computeEditScript', () => {
it('returns empty for two empty arrays', () => {
expect(computeEditScript([], [])).toEqual([]);
});
it('returns all-insert for empty before', () => {
const ops = computeEditScript([], ['a', 'b']);
expect(ops).toEqual([{ type: 'insert', lines: ['a', 'b'] }]);
});
it('returns all-delete for empty after', () => {
const ops = computeEditScript(['a', 'b'], []);
expect(ops).toEqual([{ type: 'delete', lines: ['a', 'b'] }]);
});
it('returns all-equal for identical arrays', () => {
const ops = computeEditScript(['a', 'b', 'c'], ['a', 'b', 'c']);
expect(ops).toEqual([{ type: 'equal', lines: ['a', 'b', 'c'] }]);
});
it('detects a single changed line', () => {
const ops = computeEditScript(['a', 'b', 'c'], ['a', 'X', 'c']);
const types = ops.map(o => o.type);
expect(types).toContain('delete');
expect(types).toContain('insert');
const deleted = ops.filter(o => o.type === 'delete').flatMap(o => o.lines);
const inserted = ops.filter(o => o.type === 'insert').flatMap(o => o.lines);
expect(deleted).toContain('b');
expect(inserted).toContain('X');
});
it('detects inserted lines at end', () => {
const ops = computeEditScript(['a'], ['a', 'b', 'c']);
const inserted = ops.filter(o => o.type === 'insert').flatMap(o => o.lines);
expect(inserted).toEqual(['b', 'c']);
});
it('detects deleted lines at start', () => {
const ops = computeEditScript(['x', 'y', 'a'], ['a']);
const deleted = ops.filter(o => o.type === 'delete').flatMap(o => o.lines);
expect(deleted).toEqual(['x', 'y']);
});
it('merges consecutive ops of same type', () => {
const ops = computeEditScript(['a', 'b'], ['c', 'd']);
// Should have merged deletes and inserts, not one-op-per-line
const delOp = ops.find(o => o.type === 'delete');
const insOp = ops.find(o => o.type === 'insert');
expect(delOp?.lines.length).toBeGreaterThanOrEqual(1);
expect(insOp?.lines.length).toBeGreaterThanOrEqual(1);
});
it('round-trip: applying ops to before yields after', () => {
const before = ['prop: 1', 'style: red', 'size: md'];
const after = ['prop: 1', 'style: blue', 'size: lg', 'weight: 600'];
const ops = computeEditScript(before, after);
const result: string[] = [];
for (const op of ops) {
if (op.type === 'equal' || op.type === 'insert') result.push(...op.lines);
}
expect(result).toEqual(after);
});
it('handles single-element change', () => {
const ops = computeEditScript(['x'], ['y']);
expect(ops.some(o => o.type === 'delete' && o.lines.includes('x'))).toBe(true);
expect(ops.some(o => o.type === 'insert' && o.lines.includes('y'))).toBe(true);
});
});