messageformat
Version:
Intl.MessageFormat / Unicode MessageFormat 2 parser, runtime and polyfill
55 lines (54 loc) • 2.14 kB
JavaScript
import { MessageError, MessageResolutionError } from "../errors.js";
import { fallback } from "../functions/fallback.js";
import { BIDI_ISOLATE } from "../message-value.js";
import { MessageFunctionContext } from "./function-context.js";
import { getValueSource, resolveValue } from "./resolve-value.js";
export function resolveFunctionRef(ctx, operand, { name, options }) {
const fnSource = `:${name}`;
const source = getValueSource(operand) ?? fnSource;
try {
const fnInput = operand ? [resolveValue(ctx, operand)] : [];
const rf = ctx.functions[name];
if (!rf) {
throw new MessageResolutionError('unknown-function', `Unknown function ${fnSource}`, source);
}
const msgCtx = new MessageFunctionContext(ctx, source, options);
const opt = resolveOptions(ctx, options);
const res = rf(msgCtx, opt, ...fnInput);
if (res === null ||
typeof res !== 'object' ||
typeof res.type !== 'string') {
throw new MessageResolutionError('bad-function-result', `Function ${fnSource} did not return a MessageValue`, source);
}
const override = { source };
if (msgCtx.dir) {
override.dir = msgCtx.dir;
override[BIDI_ISOLATE] = true;
}
if (msgCtx.id && typeof res.toParts === 'function') {
override.toParts = () => {
const parts = res.toParts();
for (const part of parts)
part.id = msgCtx.id;
return parts;
};
}
return { ...res, ...override };
}
catch (error) {
ctx.onError(error instanceof MessageError
? error
: new MessageResolutionError('bad-function-result', String(error), source, error));
return fallback(source);
}
}
function resolveOptions(ctx, options) {
const opt = Object.create(null);
if (options) {
for (const [name, value] of Object.entries(options)) {
if (!name.startsWith('u:'))
opt[name] = resolveValue(ctx, value);
}
}
return opt;
}