UNPKG

messageformat

Version:

Intl.MessageFormat / Unicode MessageFormat 2 parser, runtime and polyfill

96 lines (95 loc) 3.3 kB
/** * Apply visitor functions to message nodes. * * The visitors are applied in source order, starting from the root. * Visitors for nodes that contain other nodes may return a callback function * that will be called with no arguments when exiting the node. * * If set, the `node` visitor is called for all {@link Node} values * for which an explicit visitor is not defined. * * Many visitors will be called with additional arguments * identifying some of the context for the visited node. * * @category Message Data Model */ export function visit(msg, visitors) { const { node, pattern } = visitors; const { functionRef = node, attributes = null, declaration = node, expression = node, key = node, markup = node, options = null, value = node, variant = node } = visitors; const handleOptions = (options_, context) => { if (options_) { const end = options?.(options_, context); if (value) { for (const value_ of options_.values()) { value(value_, context, 'option'); } } end?.(); } }; const handleAttributes = (attributes_, context) => { if (attributes_) { const end = attributes?.(attributes_, context); if (value) { for (const value_ of attributes_.values()) { if (value_ !== true) value(value_, context, 'attribute'); } } end?.(); } }; const handleElement = (exp, context) => { if (typeof exp === 'object') { let end; switch (exp.type) { case 'expression': { end = expression?.(exp, context); if (exp.arg) value?.(exp.arg, context, 'arg'); if (exp.functionRef) { const endA = functionRef?.(exp.functionRef, context, exp.arg); handleOptions(exp.functionRef.options, context); endA?.(); } handleAttributes(exp.attributes, context); break; } case 'markup': { end = markup?.(exp, context); handleOptions(exp.options, context); handleAttributes(exp.attributes, context); break; } } end?.(); } }; const handlePattern = (pat) => { const end = pattern?.(pat); for (const el of pat) handleElement(el, 'placeholder'); end?.(); }; for (const decl of msg.declarations) { const end = declaration?.(decl); if (decl.value) handleElement(decl.value, 'declaration'); end?.(); } if (msg.type === 'message') { handlePattern(msg.pattern); } else { if (value) for (const sel of msg.selectors) value(sel, 'selector', 'arg'); for (const vari of msg.variants) { const end = variant?.(vari); if (key) vari.keys.forEach(key); handlePattern(vari.value); end?.(); } } }