import { AndRule, type DataRef, MaybeRule, OrRule, type Rule, type RuleTestResponse, } from '@os-team/lexical-rules'; import ExternalIDParser, { type ExternalID } from './ExternalIDParser.js'; import type { Parser } from './Parser.js'; import EntityValueRule from '../rules/EntityValueRule.js'; import NDataDeclParser from './NDataDeclParser.js'; export type EntityDef = string | (ExternalID & { nData?: string }); /** * See https://www.w3.org/TR/xml/#NT-EntityDef */ class EntityDefParser implements Parser { private readonly externalIDParser: ExternalIDParser; private readonly nDataDeclParser: NDataDeclParser; private readonly rule: Rule; public constructor() { const entityValueRule = new EntityValueRule(); // EntityValue this.externalIDParser = new ExternalIDParser(); // ExternalID this.nDataDeclParser = new NDataDeclParser(); // NDataDecl const maybeNDataDeclRule = new MaybeRule(this.nDataDeclParser); // NDataDecl? const externalIDAndMaybeNDataDeclRule = new AndRule([ this.externalIDParser, maybeNDataDeclRule, ]); // ExternalID NDataDecl? this.rule = new OrRule([entityValueRule, externalIDAndMaybeNDataDeclRule]); // EntityValue | (ExternalID NDataDecl?) } public test(ref: DataRef, pos: number): RuleTestResponse { const [isValid, nextPos, res] = this.rule.test(ref, pos); if (!isValid || res === undefined) return [false, nextPos]; let entityDef: EntityDef; if (Array.isArray(res)) { const [externalID, nData] = res; entityDef = { ...externalID }; if (nData) entityDef.nData = nData; } else { entityDef = res; } return [true, nextPos, entityDef]; } public build(data: EntityDef) { if (typeof data === 'string') return `"${data.replaceAll('"', "'")}"`; const externalID = this.externalIDParser.build(data); const nData = data.nData ? this.nDataDeclParser.build(data.nData) : ''; return `${externalID}${nData}`; } } export default EntityDefParser;