/** * The HTML a repository's markdown is allowed to keep. * * The tags belong to whoever wrote the repository and the result is put * straight into the document. Every test here asks one of two questions: does * the tag a README needs survive, and does everything else go. */ import { describe, expect, it } from 'vitest'; import { escapeAttribute, escapeText, sanitizeHtml, scanHtml, } from '../src/lib/html.js'; /** Addresses as the markdown renderer supplies them. */ const ctx = { link: (href) => href.startsWith('javascript:') ? null : { href, external: href.startsWith('https:') }, image: (src) => src.startsWith('javascript:') ? null : { 'data-repo-path': src }, }; const clean = (raw) => sanitizeHtml(raw, ctx); describe('the tags a README needs', () => { it('keeps a row of sized images', () => { expect( clean('

'), ).toBe( '

', ); }); it('keeps a table with its spans and its alignment', () => { expect( clean('
x
'), ).toBe('
x
'); }); it('keeps a collapsed section', () => { expect(clean('
whybecause
')).toBe( '
whybecause
', ); }); it('keeps a list that starts partway through', () => { expect(clean('
  1. x
')).toBe( '
  1. x
', ); }); it('writes no closing tag for a tag that takes none', () => { expect(clean('a
b
c
')).toBe('a
b
c'); }); it('leaves an entity in the text as one character', () => { expect(clean('

a & b < c

')).toBe('

a & b < c

'); }); it('escapes an angle bracket that opens nothing', () => { expect(clean('

1 < 2 > 0

')).toBe('

1 < 2 > 0

'); }); }); describe('the tags the page refuses', () => { it('drops a tag that is not on the list and keeps its words', () => { expect(clean('
go
')).toBe('go'); }); it('drops an opaque tag along with its text', () => { expect(clean('ab')).toBe('ab'); expect(clean('ab')).toBe('ab'); expect(clean('ab')).toBe('ab'); }); it('drops everything after an opaque tag that never closes', () => { expect(clean('a