diff --git a/src/core/model.ts b/src/core/model.ts index f6ed6b0..2e3065a 100644 --- a/src/core/model.ts +++ b/src/core/model.ts @@ -28,6 +28,21 @@ export function createEmptyDoc(): string { * Strips all tags and checks whether any visible text remains. */ export function isContentEmpty(html: string): boolean { - const stripped = html.replace(/<[^>]*>/g, '').trim(); - return stripped.length === 0; + let i = 0; + let stripped = ''; + while (i < html.length) { + const lt = html.indexOf('<', i); + if (lt === -1) { + stripped += html.slice(i); + break; + } + stripped += html.slice(i, lt); + const gt = html.indexOf('>', lt + 1); + if (gt === -1) { + stripped += html.slice(lt); + break; + } + i = gt + 1; + } + return stripped.trim().length === 0; } diff --git a/tests/unit/core/model.test.ts b/tests/unit/core/model.test.ts index 911e211..15b431c 100644 --- a/tests/unit/core/model.test.ts +++ b/tests/unit/core/model.test.ts @@ -47,5 +47,21 @@ describe('model', () => { it('returns true for empty string', () => { expect(isContentEmpty('')).toBe(true); }); + + it('returns false when < is unclosed and there is visible text after it', () => { + expect(isContentEmpty('< world')).toBe(false); + }); + + it('returns false for a bare unclosed tag (no closing >)', () => { + expect(isContentEmpty(' { + expect(isContentEmpty('

\n\t\r\f

')).toBe(true); + }); + + it('returns true for a string with no tags that is only whitespace', () => { + expect(isContentEmpty(' \n ')).toBe(true); + }); }); });