import { AndRule, type DataRef, LiteralRule, OrRule, RepetitionRule, type Rule, type RuleTestResponse, } from '@os-team/lexical-rules'; import type { Parser } from './Parser.js'; import SRule from '../rules/SRule.js'; import NameRule from '../rules/NameRule.js'; export interface Mixed { type: 'MIXED'; items?: string[]; } /** * The mixed-content declaration. * See https://www.w3.org/TR/xml/#NT-Mixed */ class MixedParser implements Parser { private readonly rule: Rule< | [ string, undefined, string, Array<[undefined, string, undefined, string]>, undefined, string, ] | [string, undefined, string, undefined, string] >; public constructor() { const prefixRule = new LiteralRule('('); // '(' const anySRule = new SRule('*'); // S? const pcDataRule = new LiteralRule('#PCDATA'); // '#PCDATA' const separatorRule = new LiteralRule('|'); // '|' const nameRule = new NameRule(); // Name const suffixWithAsteriskRule = new LiteralRule(')*'); // ')*' const nameItemRule = new AndRule([ anySRule, separatorRule, anySRule, nameRule, ]); // S? '|' S? Name const anyNameItemRule = new RepetitionRule(nameItemRule, 0); // (S? '|' S? Name)* const withNameRule = new AndRule([ prefixRule, anySRule, pcDataRule, anyNameItemRule, anySRule, suffixWithAsteriskRule, ]); // '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' const suffixRule = new LiteralRule(')'); // ')' const withoutNameRule = new AndRule([ prefixRule, anySRule, pcDataRule, anySRule, suffixRule, ]); // '(' S? '#PCDATA' S? ')' this.rule = new OrRule([withNameRule, withoutNameRule]); // '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' } public test(ref: DataRef, pos: number): RuleTestResponse { const [isValid, nextPos, res] = this.rule.test(ref, pos); if (!isValid || res === undefined) return [false, nextPos]; const mixed: Mixed = { type: 'MIXED' }; if (res.length === 6) { const [, , , rawNames] = res; mixed.items = rawNames.map((item) => item[3]); } return [true, nextPos, mixed]; } public build(data: Mixed) { return data.items && data.items.length > 0 ? `(#PCDATA|${data.items.join('|')})*` : `(#PCDATA)`; } } export default MixedParser;