import { AndRule, type DataRef, OrRule, type Rule, type RuleTestResponse, } from '@os-team/lexical-rules'; import type { Parser } from './Parser.js'; import ChoiceParser, { type Choice } from './ChoiceParser.js'; import SeqParser, { type Seq } from './SeqParser.js'; import QuantifierRule, { type Quantifier } from '../rules/QuantifierRule.js'; type ChildrenContent = Choice | Seq; export type Children = ChildrenContent | [ChildrenContent, '?' | '*' | '+']; /** * The custom content of an element. * See https://www.w3.org/TR/xml/#NT-children */ class ChildrenParser implements Parser { private readonly choiceParser: ChoiceParser; private readonly seqParser: SeqParser; private readonly rule: Rule<[Choice | Seq, Quantifier]>; public constructor() { this.choiceParser = new ChoiceParser(); // choice this.seqParser = new SeqParser(); // seq const choiceOrSeqRule = new OrRule([this.choiceParser, this.seqParser]); // choice | seq const quantifierRule = new QuantifierRule(); // ('?' | '*' | '+')? this.rule = new AndRule([choiceOrSeqRule, quantifierRule]); // (choice | seq) ('?' | '*' | '+')? } public test(ref: DataRef, pos: number): RuleTestResponse { const [isValid, nextPos, res] = this.rule.test(ref, pos); if (!isValid || res === undefined) return [false, nextPos]; const [content, quantifier] = res; const children: Children = quantifier ? [content, quantifier] : content; return [true, nextPos, children]; } public build(data: Children) { const [content, quantifier = ''] = Array.isArray(data) ? data : [data]; const strContent = content.type === 'CHOICE' ? this.choiceParser.build(content) : this.seqParser.build(content); return `${strContent}${quantifier}`; } } export default ChildrenParser;