UNPKG

messageformat

Version:

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

82 lines (81 loc) 2.92 kB
import { MessageResolutionError } from "./errors.js"; import { resolveVariableRef } from "./resolve/resolve-variable.js"; export function selectPattern(context, message) { if (message.type === 'message') return message.pattern; // message.type === 'select' const ctx = message.selectors.map(sel => { const selector = resolveVariableRef(context, sel); let selectKey; if (typeof selector.selectKey === 'function') { selectKey = selector.selectKey.bind(selector); } else { const msg = 'Selector does not support selection'; context.onError(new MessageResolutionError('bad-selector', msg, selector.source)); selectKey = () => null; } return { selectKey, source: selector.source, best: null, keys: null }; }); let candidates = message.variants; loop: for (let i = 0; i < ctx.length; ++i) { const sc = ctx[i]; if (!sc.keys) { sc.keys = new Set(); for (const { keys } of candidates) { const key = keys[i]; if (!key) break loop; // key-mismatch error if (key.type !== '*') sc.keys.add(key.value); } } try { sc.best = sc.keys.size ? sc.selectKey(sc.keys) : null; } catch (error) { const msg = 'Selection failed'; context.onError(new MessageResolutionError('bad-selector', msg, sc.source, error)); sc.selectKey = () => null; sc.best = null; } // Leave out all candidate variants that aren't the best, // or only the catchall ones, if nothing else matches. candidates = candidates.filter(v => { const k = v.keys[i]; if (k.type === '*') return sc.best == null; return sc.best === k.value; }); // If we've run out of candidates, // drop the previous best key of the preceding selector, // reset all subsequent key sets, // and restart the loop. if (candidates.length === 0) { if (i === 0) break; // No match; should not happen const prev = ctx[i - 1]; if (prev.best == null) prev.keys?.clear(); else prev.keys?.delete(prev.best); for (let j = i; j < ctx.length; ++j) ctx[j].keys = null; candidates = message.variants; i = -1; } } const res = candidates[0]; if (!res) { // This should not be possible with a valid message. const msg = 'No variant was selected!?'; context.onError(new MessageResolutionError('no-match', msg, '.match')); return []; } return res.value; }