import { DocumentParser } from '../../markdown'; import { Input, Recursion } from './context'; import { Parser, Result, List, Node } from '../combinator/parser'; import { always, force, recursion } from '../combinator'; import { build } from './parser'; import { parser as segment } from './segment'; import { block } from './block'; import { unwrap, randomID } from './util'; import { figure } from '../processor/figure'; import { note } from '../processor/note'; import { frag, html } from 'typed-dom/dom'; export const document: DocumentParser = (() => { interface Memory { readonly interpolation: boolean; readonly references: HTMLOListElement; orphan?: boolean; doc?: DocumentFragment; } const document = build(segment, block); return always>>([ (input, output) => { input.id = input.id === '' ? '' : input.local ? randomID() : input.id; input.memory = { interpolation: !input.notes, references: input.notes?.references ?? html('ol', { class: 'references' }), }; output.push(); output.labels.push(new List()); output.annotations.push(new List()); output.references.push(new List()); return output.context; }, recursion(Recursion.document, force(() => document)), (input, output) => { assert(input.position === input.source.length); const { memory } = input; const doc = memory.doc = frag(unwrap(output.pop())); output.append(new Node(doc)); assert(input.id !== '' || !doc.querySelector('[id], .index[href], .label[href], .annotation > a[href], .reference > a[href]')); if (input.test && !input.local) { output.labels.at(-2)!.import(output.labels.pop()!); output.annotations.at(-2)!.import(output.annotations.pop()!); output.references.at(-2)!.import(output.references.pop()!); return Result.skip; } memory.orphan = !memory.references.parentNode; memory.orphan && doc.appendChild(memory.references); return output.context; }, (input, output) => conv(figure(input.memory.doc!, output.labels.pop()!, input.memory, input)), (input, output) => conv(note(input.memory.doc!, { annotations: output.annotations.pop()!, references: output.references.pop()!, }, input.memory, input)), (input, output) => { const { memory } = input; memory.orphan && !memory.interpolation && memory.references.remove(); return output.context; }, ]); })(); function conv(iterable: Iterable): Result { const iter = iterable[Symbol.iterator](); const cont: Result = [ (_, output) => iter.next().done ? output.context : cont, ]; return cont; }