import { AndRule, CharRule, type DataRef, LiteralRule, OrRule, RepetitionRule, type Rule, type RuleTestResponse, } from '@os-team/lexical-rules'; import NumberRule from './NumberRule.js'; /** * See https://www.w3.org/TR/xml/#NT-CharRef */ class CharRefRule implements Rule { private readonly rule: Rule< [string, number, string] | [string, string[], string] >; public constructor() { const numCharRefPrefixRule = new LiteralRule('&#'); // '&#' const numCharRefCodeRule = new NumberRule(); // [0-9]+ const charRefSuffixRule = new LiteralRule(';'); // ';' const numCharRefRule = new AndRule([ numCharRefPrefixRule, numCharRefCodeRule, charRefSuffixRule, ]); // '&#' [0-9]+ ';' const hexCharRefPrefixRule = new LiteralRule('&#x'); // '&#x' const hexCharRule = new CharRule({ allowed: [ ['0', '9'], ['a', 'f'], ['A', 'F'], ], }); // [0-9a-fA-F] const hexCharRefCodeRule = new RepetitionRule(hexCharRule, 1); // [0-9a-fA-F]+ const hexCharRefRule = new AndRule([ hexCharRefPrefixRule, hexCharRefCodeRule, charRefSuffixRule, ]); // '&#x' [0-9a-fA-F]+ ';' this.rule = new OrRule([numCharRefRule, hexCharRefRule]); // ('&#' [0-9]+ ';') | ('&#x' [0-9a-fA-F]+ ';') } public test(ref: DataRef, pos: number): RuleTestResponse { const [isValid, nextPos, res] = this.rule.test(ref, pos); if (!isValid || res === undefined) return [false, nextPos]; const [prefix, code, suffix] = res; const str = Array.isArray(code) ? `${prefix}${code.join('')}${suffix}` : `${prefix}${code}${suffix}`; return [true, nextPos, str]; } } export default CharRefRule;