diff --git a/src/js/compare/engine/compare-content.ts b/src/js/compare/engine/compare-content.ts index 2bd8155..64d9209 100644 --- a/src/js/compare/engine/compare-content.ts +++ b/src/js/compare/engine/compare-content.ts @@ -41,8 +41,16 @@ export function diffAnnotations( baseId: number ): CompareTextChange[] { const changes: CompareTextChange[] = []; - const beforeMap = new Map(before.map((a) => [annotationKey(a), a])); - const afterMap = new Map(after.map((a) => [annotationKey(a), a])); + const beforeMap = new Map( + before + .filter(shouldCompareAnnotation) + .map((annotation) => [annotationKey(annotation), annotation]) + ); + const afterMap = new Map( + after + .filter(shouldCompareAnnotation) + .map((annotation) => [annotationKey(annotation), annotation]) + ); let idx = baseId; for (const [key, ann] of beforeMap) { @@ -51,8 +59,7 @@ export function diffAnnotations( id: `annotation-removed-${idx++}`, type: 'removed', category: 'annotation', - description: - `Removed ${ann.subtype} annotation: "${ann.contents || ann.title || ''}"`.trim(), + description: formatAnnotationDescription('Removed', ann), beforeText: ann.contents || ann.title || '', afterText: '', beforeRects: [ann.rect], @@ -67,8 +74,7 @@ export function diffAnnotations( id: `annotation-added-${idx++}`, type: 'added', category: 'annotation', - description: - `Added ${ann.subtype} annotation: "${ann.contents || ann.title || ''}"`.trim(), + description: formatAnnotationDescription('Added', ann), beforeText: '', afterText: ann.contents || ann.title || '', beforeRects: [], @@ -80,6 +86,26 @@ export function diffAnnotations( return changes; } +function shouldCompareAnnotation(annotation: CompareAnnotation): boolean { + if (annotation.subtype !== 'Highlight') { + return true; + } + + return Boolean(annotation.contents || annotation.title); +} + +function formatAnnotationDescription( + action: 'Added' | 'Removed', + annotation: CompareAnnotation +): string { + const label = annotation.contents || annotation.title; + if (!label) { + return `${action} ${annotation.subtype} annotation`; + } + + return `${action} ${annotation.subtype} annotation: "${label}"`; +} + function annotationKey(ann: CompareAnnotation): string { return `${ann.subtype}|${ann.contents}|${Math.round(ann.rect.x)},${Math.round(ann.rect.y)}`; } diff --git a/src/tests/compare/diff-text-runs.test.ts b/src/tests/compare/diff-text-runs.test.ts index 1ab723e..7e51412 100644 --- a/src/tests/compare/diff-text-runs.test.ts +++ b/src/tests/compare/diff-text-runs.test.ts @@ -7,6 +7,7 @@ import { sortCompareTextItems, } from '@/js/compare/engine/extract-page-model.ts'; import type { + CompareAnnotation, ComparePageModel, CompareTextItem, CompareWordToken, @@ -23,7 +24,8 @@ function makeItem(id: string, text: string): CompareTextItem { function makePage( pageNumber: number, - textItems: CompareTextItem[] + textItems: CompareTextItem[], + overrides: Partial = {} ): ComparePageModel { return { pageNumber, @@ -33,6 +35,22 @@ function makePage( plainText: textItems.map((item) => item.normalizedText).join(' '), hasText: textItems.length > 0, source: 'pdfjs', + ...overrides, + }; +} + +function makeAnnotation( + subtype: string, + overrides: Partial = {} +): CompareAnnotation { + return { + id: `${subtype}-1`, + subtype, + rect: { x: 0, y: 0, width: 10, height: 10 }, + contents: '', + title: '', + color: '', + ...overrides, }; } @@ -137,6 +155,25 @@ describe('comparePageModels', () => { expect(result.summary.removed).toBe(1); expect(result.changes[0].type).toBe('page-removed'); }); + + it('ignores empty highlight annotations in annotation diff output', () => { + const result = comparePageModels( + makePage(1, [makeItem('a', 'Original')], { + annotations: [makeAnnotation('Highlight')], + }), + makePage(1, [makeItem('b', 'Updated')], { + annotations: [makeAnnotation('Highlight', { id: 'highlight-2' })], + }) + ); + + expect( + result.changes.some( + (change) => + change.category === 'annotation' && + change.description.includes('Highlight annotation') + ) + ).toBe(false); + }); }); describe('sortCompareTextItems', () => {