1import { html, type TreeAdapterTypeMap, type TreeAdapter } from 'parse5'; 2 3function createFragmentContext<T extends TreeAdapterTypeMap>( 4 tagName: string | undefined, 5 treeAdapter: TreeAdapter<T> 6): T['element'] | null { 7 if (!tagName) { 8 return null; 9 } 10 11 let namespace = html.NS.HTML; 12 const parts = tagName.split(' '); 13 14 if (parts.length > 1) { 15 tagName = parts[1]; 16 17 if (parts[0] === 'svg') { 18 namespace = html.NS.SVG; 19 } else if (parts[0] === 'math') { 20 namespace = html.NS.MATHML; 21 } 22 } 23 24 return treeAdapter.createElement(tagName, namespace, []); 25} 26 27export interface DatFile<T extends TreeAdapterTypeMap> { 28 input: string; 29 expected: string; 30 expectedErrors: string[]; 31 disableEntitiesDecoding: boolean; 32 lineNum: number; 33 scriptingEnabled: boolean; 34 fragmentContext: T['element'] | null; 35} 36 37export function parseDatFile<T extends TreeAdapterTypeMap>(testSet: string, treeAdapter: TreeAdapter<T>): DatFile<T>[] { 38 const testDescrs: Record<string, number | string[]>[] = []; 39 let curDirective = ''; 40 let curDescr: Record<string, number | string[]> = {}; 41 42 for (const [idx, line] of testSet.split(/\r?\n/).entries()) { 43 if (line === '#data') { 44 curDescr = { '#line': idx + 1 }; 45 testDescrs.push(curDescr); 46 } 47 48 if (line[0] === '#') { 49 curDirective = line; 50 curDescr[curDirective] = []; 51 } else { 52 (curDescr[curDirective] as string[]).push(line); 53 } 54 } 55 56 return testDescrs.map((descr) => { 57 const fragmentContextTagName = (descr['#document-fragment'] as string[] | undefined)?.[0]; 58 59 return { 60 input: (descr['#data'] as string[]).join('\n'), 61 expected: (descr['#document'] as string[]).join('\n'), 62 expectedErrors: descr['#new-errors'] || [], 63 disableEntitiesDecoding: !!descr['#disable-html-entities-decoding'], 64 lineNum: descr['#line'], 65 scriptingEnabled: !descr['#script-off'], 66 fragmentContext: createFragmentContext<T>(fragmentContextTagName, treeAdapter), 67 } as DatFile<T>; 68 }); 69} 70