import { AndRule, type DataRef, LiteralRule, MaybeRule, type Rule, type RuleTestResponse, } from '@os-team/lexical-rules'; import type { Parser } from './Parser.js'; import ExternalIDParser, { type ExternalID } from './ExternalIDParser.js'; import IntSubsetParser, { type IntSubset } from './IntSubsetParser.js'; import SRule from '../rules/SRule.js'; import NameRule from '../rules/NameRule.js'; export interface DoctypeDecl { name: string; externalID?: ExternalID; intSubset?: IntSubset; } /** * The document type definition. * See https://www.w3.org/TR/xml/#NT-doctypedecl */ class DoctypeDeclParser implements Parser { private readonly externalIDParser: ExternalIDParser; private readonly intSubsetParser: IntSubsetParser; private readonly rule: Rule< [ string, undefined, string, [undefined, ExternalID] | undefined, undefined, [string, IntSubset, string, undefined] | undefined, string, ] >; public constructor() { const prefixRule = new LiteralRule(''); // '>' this.rule = new AndRule([ prefixRule, sRule, nameRule, maybeSAndExternalIDRule, anySRule, maybeIntSubsetInBrackets, suffixRule, ]); // '' } public test(ref: DataRef, pos: number): RuleTestResponse { const [isValid, nextPos, res] = this.rule.test(ref, pos); if (!isValid || res === undefined) return [false, nextPos]; const [, , name, rawExternalID, , rawIntSubset] = res; const [, externalID] = rawExternalID || []; const [, intSubset] = rawIntSubset || []; const doctypeDecl: DoctypeDecl = { name }; if (rawExternalID) doctypeDecl.externalID = externalID; if (rawIntSubset) doctypeDecl.intSubset = intSubset; return [true, nextPos, doctypeDecl]; } public build(data: DoctypeDecl) { const externalID = data.externalID ? ` ${this.externalIDParser.build(data.externalID)}` : ''; const intSubset = data.intSubset ? ` [${this.intSubsetParser.build(data.intSubset)}]` : ''; return ``; } } export default DoctypeDeclParser;