Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

messageformat

Package Overview
Dependencies
Maintainers
2
Versions
52
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

messageformat - npm Package Compare versions

Comparing version 4.0.0-7 to 4.0.0-8

lib/data-model/resolve-function-ref.d.ts

2

lib/cst/declarations.d.ts
import type { ParseContext } from './parse-cst.js';
import type * as CST from './types.js';
export declare function parseDeclarations(ctx: ParseContext): {
export declare function parseDeclarations(ctx: ParseContext, start: number): {
declarations: CST.Declaration[];
end: number;
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseDeclarations = void 0;
const names_js_1 = require("./names.js");
const expression_js_1 = require("./expression.js");
const util_js_1 = require("./util.js");
const values_js_1 = require("./values.js");
function parseDeclarations(ctx) {
function parseDeclarations(ctx, start) {
const { source } = ctx;
let pos = (0, util_js_1.whitespaces)(source, 0);
let pos = start;
const declarations = [];
loop: while (source[pos] === '.') {
const keyword = (0, names_js_1.parseNameValue)(source, pos + 1);
const keyword = source.substr(pos, 6);
let decl;
switch (keyword) {
case '':
case 'match':
case '.match':
break loop;
case 'input':
case '.input':
decl = parseInputDeclaration(ctx, pos);
break;
case 'local':
case '.local':
decl = parseLocalDeclaration(ctx, pos);
break;
default:
decl = parseReservedStatement(ctx, pos, '.' + keyword);
decl = parseDeclarationJunk(ctx, pos);
}
declarations.push(decl);
pos = decl.end;
pos += (0, util_js_1.whitespaces)(source, pos);
pos = (0, util_js_1.whitespaces)(source, decl.end).end;
}

@@ -39,3 +36,3 @@ return { declarations, end: pos };

const keyword = { start, end: pos, value: '.input' };
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
pos = (0, util_js_1.whitespaces)(ctx.source, pos).end;
const value = parseDeclarationValue(ctx, pos);

@@ -54,4 +51,4 @@ if (value.type === 'expression') {

const ws = (0, util_js_1.whitespaces)(source, pos);
pos += ws;
if (ws === 0)
pos = ws.end;
if (!ws.hasWS)
ctx.onError('missing-syntax', pos, ' ');

@@ -75,3 +72,3 @@ let target;

}
pos += (0, util_js_1.whitespaces)(source, pos);
pos = (0, util_js_1.whitespaces)(source, pos).end;
let equals;

@@ -85,3 +82,3 @@ if (source[pos] === '=') {

}
pos += (0, util_js_1.whitespaces)(source, pos);
pos = (0, util_js_1.whitespaces)(source, pos).end;
const value = parseDeclarationValue(ctx, pos);

@@ -98,36 +95,21 @@ return {

}
function parseReservedStatement(ctx, start, keyword) {
let pos = start + keyword.length;
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
const body = (0, expression_js_1.parseReservedBody)(ctx, pos);
let end = body.end;
pos = end + (0, util_js_1.whitespaces)(ctx.source, end);
const values = [];
while (ctx.source[pos] === '{') {
if (ctx.source.startsWith('{{', pos))
break;
const value = (0, expression_js_1.parseExpression)(ctx, pos);
values.push(value);
end = value.end;
pos = end + (0, util_js_1.whitespaces)(ctx.source, end);
}
if (values.length === 0)
ctx.onError('missing-syntax', end, '{');
return {
type: 'reserved-statement',
start,
end,
keyword: { start, end: keyword.length, value: keyword },
body,
values
};
function parseDeclarationValue(ctx, start) {
return ctx.source[start] === '{'
? (0, expression_js_1.parseExpression)(ctx, start)
: parseDeclarationJunk(ctx, start);
}
function parseDeclarationValue(ctx, start) {
function parseDeclarationJunk(ctx, start) {
const { source } = ctx;
if (source[start] === '{')
return (0, expression_js_1.parseExpression)(ctx, start);
const junkEndOffset = source.substring(start).search(/\.[a-z]|{{/);
const end = junkEndOffset === -1 ? source.length : start + junkEndOffset;
const junkEndOffset = source.substring(start + 1).search(/\.[a-z]|{{/);
let end;
if (junkEndOffset === -1) {
end = source.length;
}
else {
end = start + 1 + junkEndOffset;
while (/\s/.test(source[end - 1]))
end -= 1;
}
ctx.onError('missing-syntax', start, '{');
return { type: 'junk', start, end, source: source.substring(start, end) };
}
import type { ParseContext } from './parse-cst.js';
import type * as CST from './types.js';
export declare function parseExpression(ctx: ParseContext, start: number): CST.Expression;
export declare function parseReservedBody(ctx: ParseContext, start: number): CST.Syntax<string>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseReservedBody = exports.parseExpression = void 0;
exports.parseExpression = void 0;
const errors_js_1 = require("../errors.js");

@@ -11,3 +11,3 @@ const names_js_1 = require("./names.js");

let pos = start + 1; // '{'
pos += (0, util_js_1.whitespaces)(source, pos);
pos = (0, util_js_1.whitespaces)(source, pos).end;
const arg = source[pos] === '$'

@@ -19,8 +19,8 @@ ? (0, values_js_1.parseVariable)(ctx, pos)

const ws = (0, util_js_1.whitespaces)(source, pos);
if (ws === 0 && source[pos] !== '}') {
if (!ws.hasWS && source[pos] !== '}') {
ctx.onError('missing-syntax', pos, ' ');
}
pos += ws;
pos = ws.end;
}
let annotation;
let functionRef;
let markup;

@@ -30,4 +30,4 @@ let junkError;

case ':':
annotation = parseFunctionRefOrMarkup(ctx, pos, 'function');
pos = annotation.end;
functionRef = parseFunctionRefOrMarkup(ctx, pos, 'function');
pos = functionRef.end;
break;

@@ -41,15 +41,2 @@ case '#':

break;
case '!':
case '%':
case '^':
case '&':
case '*':
case '+':
case '<':
case '>':
case '?':
case '~':
annotation = parseReservedAnnotation(ctx, pos);
pos = annotation.end;
break;
case '@':

@@ -63,3 +50,3 @@ case '}':

const end = pos + 1;
annotation = { type: 'junk', start: pos, end, source: source[pos] };
functionRef = { type: 'junk', start: pos, end, source: source[pos] };
junkError = new errors_js_1.MessageSyntaxError('parse-error', start, end);

@@ -70,8 +57,8 @@ ctx.errors.push(junkError);

const attributes = [];
let reqWS = Boolean(annotation || markup);
let reqWS = Boolean(functionRef || markup);
let ws = (0, util_js_1.whitespaces)(source, pos);
while (source[pos + ws] === '@') {
if (reqWS && ws === 0)
while (source[ws.end] === '@') {
if (reqWS && !ws.hasWS)
ctx.onError('missing-syntax', pos, ' ');
pos += ws;
pos = ws.end;
const attr = parseAttribute(ctx, pos);

@@ -83,3 +70,3 @@ attributes.push(attr);

}
pos += ws;
pos = ws.end;
const open = { start, end: start + 1, value: '{' };

@@ -95,5 +82,5 @@ let close;

pos += 1;
if (annotation?.type === 'junk') {
annotation.end = pos;
annotation.source = source.substring(annotation.start, pos);
if (functionRef?.type === 'junk') {
functionRef.end = pos;
functionRef.source = source.substring(functionRef.start, pos);
if (junkError)

@@ -115,3 +102,11 @@ junkError.end = pos;

? { type: 'expression', start, end, braces, markup, attributes }
: { type: 'expression', start, end, braces, arg, annotation, attributes };
: {
type: 'expression',
start,
end,
braces,
arg,
functionRef,
attributes
};
}

@@ -127,16 +122,16 @@ exports.parseExpression = parseExpression;

let ws = (0, util_js_1.whitespaces)(source, pos);
const next = source[pos + ws];
const next = source[ws.end];
if (next === '@' || next === '}')
break;
if (next === '/' && source[start] === '#') {
pos += ws + 1;
pos = ws.end + 1;
close = { start: pos - 1, end: pos, value: '/' };
ws = (0, util_js_1.whitespaces)(source, pos);
if (ws > 0)
ctx.onError('extra-content', pos, pos + ws);
if (ws.hasWS)
ctx.onError('extra-content', pos, ws.end);
break;
}
if (ws === 0)
if (!ws.hasWS)
ctx.onError('missing-syntax', pos, ' ');
pos += ws;
pos = ws.end;
const opt = parseOption(ctx, pos);

@@ -159,4 +154,3 @@ if (opt.end === pos)

const id = parseIdentifier(ctx, start);
let pos = id.end;
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
let pos = (0, util_js_1.whitespaces)(ctx.source, id.end).end;
let equals;

@@ -170,3 +164,3 @@ if (ctx.source[pos] === '=') {

}
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
pos = (0, util_js_1.whitespaces)(ctx.source, pos).end;
const value = ctx.source[pos] === '$'

@@ -179,9 +173,9 @@ ? (0, values_js_1.parseVariable)(ctx, pos)

const { source } = ctx;
const str0 = (0, names_js_1.parseNameValue)(source, start);
if (!str0) {
const name0 = (0, names_js_1.parseNameValue)(source, start);
if (!name0) {
ctx.onError('empty-token', start, start + 1);
return { parts: [{ start, end: start, value: '' }], end: start };
}
let pos = start + str0.length;
const id0 = { start, end: pos, value: str0 };
let pos = name0.end;
const id0 = { start, end: pos, value: name0.value };
if (source[pos] !== ':')

@@ -191,7 +185,6 @@ return { parts: [id0], end: pos };

pos += 1;
const str1 = (0, names_js_1.parseNameValue)(source, pos);
if (str1) {
const end = pos + str1.length;
const id1 = { start: pos, end, value: str1 };
return { parts: [id0, sep, id1], end };
const name1 = (0, names_js_1.parseNameValue)(source, pos);
if (name1) {
const id1 = { start: pos, end: name1.end, value: name1.value };
return { parts: [id0, sep, id1], end: name1.end };
}

@@ -203,60 +196,2 @@ else {

}
function parseReservedAnnotation(ctx, start) {
const open = {
start,
end: start + 1,
value: ctx.source[start]
};
const source = parseReservedBody(ctx, start + 1); // skip sigil
return {
type: 'reserved-annotation',
start,
end: source.end,
open,
source
};
}
function parseReservedBody(ctx, start) {
let pos = start;
loop: while (pos < ctx.source.length) {
const ch = ctx.source[pos];
switch (ch) {
case '\\': {
switch (ctx.source[pos + 1]) {
case '\\':
case '{':
case '|':
case '}':
break;
default:
ctx.onError('bad-escape', pos, pos + 2);
}
pos += 2;
break;
}
case '|':
pos = (0, values_js_1.parseQuotedLiteral)(ctx, pos).end;
break;
case '@':
case '{':
case '}':
break loop;
default: {
const cc = ch.charCodeAt(0);
if (cc >= 0xd800 && cc < 0xe000) {
// surrogates are invalid here
ctx.onError('parse-error', pos, pos + 1);
}
pos += 1;
}
}
}
let prev = ctx.source[pos - 1];
while (pos > start && util_js_1.whitespaceChars.includes(prev)) {
pos -= 1;
prev = ctx.source[pos - 1];
}
return { start, end: pos, value: ctx.source.substring(start, pos) };
}
exports.parseReservedBody = parseReservedBody;
function parseAttribute(ctx, start) {

@@ -269,10 +204,7 @@ const { source } = ctx;

let value;
if (source[pos + ws] === '=') {
pos += ws + 1;
if (source[ws.end] === '=') {
pos = ws.end + 1;
equals = { start: pos - 1, end: pos, value: '=' };
pos += (0, util_js_1.whitespaces)(source, pos);
value =
source[pos] === '$'
? (0, values_js_1.parseVariable)(ctx, pos)
: (0, values_js_1.parseLiteral)(ctx, pos, true);
pos = (0, util_js_1.whitespaces)(source, pos).end;
value = (0, values_js_1.parseLiteral)(ctx, pos, true);
pos = value.end;

@@ -279,0 +211,0 @@ }

@@ -1,3 +0,6 @@

export declare function parseNameValue(src: string, start: number): string;
export declare function parseNameValue(src: string, start: number): {
value: string;
end: number;
} | null;
export declare function isValidUnquotedLiteral(str: string): boolean;
export declare function parseUnquotedLiteralValue(source: string, start: number): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseUnquotedLiteralValue = exports.isValidUnquotedLiteral = exports.parseNameValue = void 0;
const bidiChars = new Set([
0x061c, // ALM
0x200e, // LRM
0x200f, // RLM
0x2066, // LRI
0x2067, // RLI
0x2068, // FSI
0x2069 // PDI
]);
const isNameStartCode = (cc) => (cc >= 0x41 && cc <= 0x5a) || // A-Z

@@ -30,8 +39,19 @@ cc === 0x5f || // _

function parseNameValue(src, start) {
if (!isNameStartCode(src.charCodeAt(start)))
return '';
let pos = start + 1;
while (isNameCharCode(src.charCodeAt(pos)))
let pos = start;
let nameStart = start;
let cc = src.charCodeAt(start);
if (bidiChars.has(cc)) {
pos += 1;
return src.substring(start, pos);
nameStart += 1;
cc = src.charCodeAt(pos);
}
if (!isNameStartCode(cc))
return null;
cc = src.charCodeAt(++pos);
while (isNameCharCode(cc))
cc = src.charCodeAt(++pos);
const name = src.substring(nameStart, pos);
if (bidiChars.has(cc))
pos += 1;
return { value: name, end: pos };
}

@@ -38,0 +58,0 @@ exports.parseNameValue = parseNameValue;

@@ -38,10 +38,13 @@ "use strict";

const ctx = new ParseContext(source, opt);
if (source.startsWith('.')) {
const { declarations, end: pos } = (0, declarations_js_1.parseDeclarations)(ctx);
return source.startsWith('.match', pos)
? parseSelectMessage(ctx, pos, declarations)
: parsePatternMessage(ctx, pos, declarations, true);
const pos = (0, util_js_1.whitespaces)(source, 0).end;
if (source.startsWith('.', pos)) {
const { declarations, end } = (0, declarations_js_1.parseDeclarations)(ctx, pos);
return source.startsWith('.match', end)
? parseSelectMessage(ctx, end, declarations)
: parsePatternMessage(ctx, end, declarations, true);
}
else {
return parsePatternMessage(ctx, 0, [], source.startsWith('{{'));
return source.startsWith('{{', pos)
? parsePatternMessage(ctx, pos, [], true)
: parsePatternMessage(ctx, 0, [], false);
}

@@ -52,4 +55,3 @@ }

const pattern = parsePattern(ctx, start, complex);
let pos = pattern.end;
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
const pos = (0, util_js_1.whitespaces)(ctx.source, pattern.end).end;
if (pos < ctx.source.length) {

@@ -65,24 +67,29 @@ ctx.onError('extra-content', pos, ctx.source.length);

const match = { start, end: pos, value: '.match' };
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
let ws = (0, util_js_1.whitespaces)(ctx.source, pos);
if (!ws.hasWS)
ctx.onError('missing-syntax', pos, "' '");
pos = ws.end;
const selectors = [];
while (ctx.source[pos] === '{') {
const sel = (0, expression_js_1.parseExpression)(ctx, pos);
const body = sel.markup ?? sel.annotation;
if (body && body.type !== 'function') {
ctx.onError('bad-selector', body.start, body.end);
}
while (ctx.source[pos] === '$') {
const sel = (0, values_js_1.parseVariable)(ctx, pos);
selectors.push(sel);
pos = sel.end;
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
ws = (0, util_js_1.whitespaces)(ctx.source, pos);
if (!ws.hasWS)
ctx.onError('missing-syntax', pos, "' '");
pos = ws.end;
}
if (selectors.length === 0) {
if (selectors.length === 0)
ctx.onError('empty-token', pos, pos + 1);
}
const variants = [];
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
while (pos < ctx.source.length) {
const variant = parseVariant(ctx, pos);
variants.push(variant);
pos = variant.end;
pos += (0, util_js_1.whitespaces)(ctx.source, pos);
if (variant.end > pos) {
variants.push(variant);
pos = variant.end;
}
else {
pos += 1;
}
pos = (0, util_js_1.whitespaces)(ctx.source, pos).end;
}

@@ -106,7 +113,7 @@ if (pos < ctx.source.length) {

const ws = (0, util_js_1.whitespaces)(ctx.source, pos);
pos += ws;
pos = ws.end;
const ch = ctx.source[pos];
if (ch === '{')
break;
if (pos > start && ws === 0)
if (pos > start && !ws.hasWS)
ctx.onError('missing-syntax', pos, "' '");

@@ -113,0 +120,0 @@ const key = ch === '*'

@@ -14,5 +14,5 @@ "use strict";

for (const decl of cst.declarations) {
const kw = decl.keyword.value;
switch (decl.type) {
case 'input': {
const kw = decl.keyword.value;
const val = stringifyExpression(decl.value);

@@ -23,2 +23,3 @@ str += `${kw} ${val}\n`;

case 'local': {
const kw = decl.keyword.value;
const tgt = stringifyValue(decl.target);

@@ -30,11 +31,5 @@ const eq = decl.equals?.value ?? '=';

}
case 'reserved-statement': {
str += kw;
if (decl.body.value)
str += ' ' + decl.body.value;
for (const exp of decl.values)
str += ' ' + stringifyExpression(exp);
str += '\n';
case 'junk':
str += decl.source + '\n';
break;
}
}

@@ -46,3 +41,3 @@ }

for (const sel of cst.selectors)
str += ' ' + stringifyExpression(sel);
str += ' ' + stringifyValue(sel);
for (const { keys, value } of cst.variants) {

@@ -76,3 +71,3 @@ str += '\n';

return exp?.source ?? '';
const { braces, arg, annotation, markup, attributes } = exp;
const { braces, arg, functionRef, markup, attributes } = exp;
let str = braces[0]?.value ?? '{';

@@ -91,16 +86,13 @@ if (markup) {

str += stringifyValue(arg);
if (annotation)
if (functionRef)
str += ' ';
}
switch (annotation?.type) {
switch (functionRef?.type) {
case 'function':
str += annotation.open.value + stringifyIdentifier(annotation.name);
for (const opt of annotation.options)
str += functionRef.open.value + stringifyIdentifier(functionRef.name);
for (const opt of functionRef.options)
str += stringifyOption(opt);
break;
case 'reserved-annotation':
str += annotation.open.value + annotation.source.value;
break;
case 'junk':
str += annotation.source;
str += functionRef.source;
break;

@@ -107,0 +99,0 @@ }

@@ -23,3 +23,3 @@ import type { MessageSyntaxError } from '../errors.js';

match: Syntax<'.match'>;
selectors: Expression[];
selectors: VariableRef[];
variants: Variant[];

@@ -29,3 +29,3 @@ errors: MessageSyntaxError[];

/** @beta */
export type Declaration = InputDeclaration | LocalDeclaration | ReservedStatement;
export type Declaration = InputDeclaration | LocalDeclaration | Junk;
/** @beta */

@@ -50,11 +50,2 @@ export interface InputDeclaration {

/** @beta */
export interface ReservedStatement {
type: 'reserved-statement';
start: number;
end: number;
keyword: Syntax<string>;
body: Syntax<string>;
values: Expression[];
}
/** @beta */
export interface Variant {

@@ -94,3 +85,3 @@ start: number;

arg?: Literal | VariableRef;
annotation?: FunctionRef | ReservedAnnotation | Junk;
functionRef?: FunctionRef | Junk;
markup?: Markup;

@@ -135,10 +126,2 @@ attributes: Attribute[];

/** @beta */
export interface ReservedAnnotation {
type: 'reserved-annotation';
open: Syntax<'!' | '%' | '^' | '&' | '*' | '+' | '<' | '>' | '?' | '~'>;
source: Syntax<string>;
start: number;
end: number;
}
/** @beta */
export interface Markup {

@@ -170,3 +153,3 @@ type: 'markup';

equals?: Syntax<'='>;
value?: Literal | VariableRef;
value?: Literal;
}

@@ -173,0 +156,0 @@ /** @beta */

@@ -1,2 +0,4 @@

export declare const whitespaceChars: string[];
export declare function whitespaces(src: string, start: number): number;
export declare function whitespaces(src: string, start: number): {
hasWS: boolean;
end: number;
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.whitespaces = exports.whitespaceChars = void 0;
exports.whitespaceChars = ['\t', '\n', '\r', ' ', '\u3000'];
exports.whitespaces = void 0;
const bidiChars = new Set('\u061C\u200E\u200F\u2066\u2067\u2068\u2069');
const whitespaceChars = new Set('\t\n\r \u3000');
function whitespaces(src, start) {
let length = 0;
let ch = src[start];
while (exports.whitespaceChars.includes(ch)) {
length += 1;
ch = src[start + length];
let hasWS = false;
let pos = start;
let ch = src[pos];
while (bidiChars.has(ch))
ch = src[++pos];
while (whitespaceChars.has(ch)) {
hasWS = true;
ch = src[++pos];
}
return length;
while (bidiChars.has(ch) || whitespaceChars.has(ch))
ch = src[++pos];
return { hasWS, end: pos };
}
exports.whitespaces = whitespaces;

@@ -6,3 +6,2 @@ import type { ParseContext } from './parse-cst.js';

export declare function parseLiteral(ctx: ParseContext, start: number, required: boolean): CST.Literal | undefined;
export declare function parseQuotedLiteral(ctx: ParseContext, start: number): CST.Literal;
export declare function parseVariable(ctx: ParseContext, start: number): CST.VariableRef;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseVariable = exports.parseQuotedLiteral = exports.parseLiteral = exports.parseText = void 0;
exports.parseVariable = exports.parseLiteral = exports.parseText = void 0;
const names_js_1 = require("./names.js");

@@ -17,3 +17,3 @@ // Text ::= (TextChar | TextEscape)+

case '\\': {
const esc = parseEscape(ctx, 'text', i);
const esc = parseEscape(ctx, i);
if (esc) {

@@ -70,3 +70,3 @@ value += ctx.source.substring(pos, i) + esc.value;

case '\\': {
const esc = parseEscape(ctx, 'literal', i);
const esc = parseEscape(ctx, i);
if (esc) {

@@ -118,3 +118,2 @@ value += ctx.source.substring(pos, i) + esc.value;

}
exports.parseQuotedLiteral = parseQuotedLiteral;
function parseVariable(ctx, start) {

@@ -124,56 +123,45 @@ const pos = start + 1;

const name = (0, names_js_1.parseNameValue)(ctx.source, pos);
const end = pos + name.length;
if (!name)
if (!name) {
ctx.onError('empty-token', pos, pos + 1);
return { type: 'variable', start, end, open, name };
return { type: 'variable', start, end: pos, open, name: '' };
}
return { type: 'variable', start, end: name.end, open, name: name.value };
}
exports.parseVariable = parseVariable;
function parseEscape(ctx, scope, start) {
function parseEscape(ctx, start) {
const raw = ctx.source[start + 1];
switch (raw) {
case '\\':
return { value: raw, length: 1 };
case '{':
case '}':
if (scope === 'text')
if ('\\{|}'.includes(raw))
return { value: raw, length: 1 };
if (ctx.resource) {
let hexLen = 0;
switch (raw) {
case '\t':
case ' ':
return { value: raw, length: 1 };
break;
case '|':
if (scope === 'literal')
return { value: raw, length: 1 };
break;
default:
if (ctx.resource) {
let hexLen = 0;
switch (raw) {
case '\t':
case ' ':
return { value: raw, length: 1 };
case 'n':
return { value: '\n', length: 1 };
case 'r':
return { value: '\r', length: 1 };
case 't':
return { value: '\t', length: 1 };
case 'u':
hexLen = 4;
break;
case 'U':
hexLen = 6;
break;
case 'x':
hexLen = 2;
break;
}
if (hexLen > 0) {
const h0 = start + 2;
const raw = ctx.source.substring(h0, h0 + hexLen);
if (raw.length === hexLen && /^[0-9A-Fa-f]+$/.test(raw)) {
return {
value: String.fromCharCode(parseInt(raw, 16)),
length: 1 + hexLen
};
}
}
case 'n':
return { value: '\n', length: 1 };
case 'r':
return { value: '\r', length: 1 };
case 't':
return { value: '\t', length: 1 };
case 'u':
hexLen = 4;
break;
case 'U':
hexLen = 6;
break;
case 'x':
hexLen = 2;
break;
}
if (hexLen > 0) {
const h0 = start + 2;
const raw = ctx.source.substring(h0, h0 + hexLen);
if (raw.length === hexLen && /^[0-9A-Fa-f]+$/.test(raw)) {
return {
value: String.fromCharCode(parseInt(raw, 16)),
length: 1 + hexLen
};
}
}
}

@@ -180,0 +168,0 @@ ctx.onError('bad-escape', start, start + 2);

@@ -8,5 +8,5 @@ "use strict";

const part = { type: 'markup', kind, source, name };
if (options?.length) {
if (options?.size) {
part.options = {};
for (const { name, value } of options) {
for (const [name, value] of options) {
let rv = (0, resolve_value_js_1.resolveValue)(ctx, value);

@@ -13,0 +13,0 @@ if (typeof rv === 'object' && typeof rv?.valueOf === 'function') {

@@ -27,3 +27,3 @@ "use strict";

declarations,
selectors: msg.selectors.map(sel => asExpression(sel, false)),
selectors: msg.selectors.map(sel => asValue(sel)),
variants: msg.variants.map(variant => ({

@@ -70,9 +70,3 @@ keys: variant.keys.map(key => key.type === '*' ? { type: '*', [exports.cst]: key } : asValue(key)),

default:
return {
type: 'unsupported-statement',
keyword: (decl.keyword?.value ?? '').substring(1),
body: decl.body?.value || undefined,
expressions: decl.values?.map(dv => asExpression(dv, true)) ?? [],
[exports.cst]: decl
};
throw new errors_js_1.MessageSyntaxError('parse-error', decl.start, decl.end);
}

@@ -83,5 +77,2 @@ }

if (exp.type === 'expression') {
const attributes = exp.attributes.length
? exp.attributes.map(asAttribute)
: undefined;
if (allowMarkup && exp.markup) {

@@ -93,5 +84,6 @@ const cm = exp.markup;

if (cm.options.length)
markup.options = cm.options.map(asOption);
if (attributes)
markup.attributes = attributes;
markup.options = asOptions(cm.options);
if (exp.attributes.length) {
markup.attributes = asAttributes(exp.attributes);
}
markup[exports.cst] = exp;

@@ -101,20 +93,13 @@ return markup;

const arg = exp.arg ? asValue(exp.arg) : undefined;
let annotation;
const ca = exp.annotation;
let functionRef;
const ca = exp.functionRef;
if (ca) {
switch (ca.type) {
case 'function':
annotation = { type: 'function', name: asName(ca.name) };
if (ca.options.length)
annotation.options = ca.options.map(asOption);
break;
case 'reserved-annotation':
annotation = {
type: 'unsupported-annotation',
source: ca.open.value + ca.source.value
};
break;
default:
throw new errors_js_1.MessageSyntaxError('parse-error', exp.start, exp.end);
if (ca.type === 'function') {
functionRef = { type: 'function', name: asName(ca.name) };
if (ca.options.length)
functionRef.options = asOptions(ca.options);
}
else {
throw new errors_js_1.MessageSyntaxError('parse-error', exp.start, exp.end);
}
}

@@ -124,12 +109,13 @@ let expression = arg

: undefined;
if (annotation) {
annotation[exports.cst] = ca;
if (functionRef) {
functionRef[exports.cst] = ca;
if (expression)
expression.annotation = annotation;
expression.functionRef = functionRef;
else
expression = { type: 'expression', annotation };
expression = { type: 'expression', functionRef: functionRef };
}
if (expression) {
if (attributes)
expression.attributes = attributes;
if (exp.attributes.length) {
expression.attributes = asAttributes(exp.attributes);
}
expression[exports.cst] = exp;

@@ -141,13 +127,24 @@ return expression;

}
const asOption = (option) => ({
name: asName(option.name),
value: asValue(option.value),
[exports.cst]: option
});
function asAttribute(attr) {
const name = asName(attr.name);
return attr.value
? { name, value: asValue(attr.value), [exports.cst]: attr }
: { name, [exports.cst]: attr };
function asOptions(options) {
const map = new Map();
for (const opt of options) {
const name = asName(opt.name);
if (map.has(name)) {
throw new errors_js_1.MessageSyntaxError('duplicate-option-name', opt.start, opt.end);
}
map.set(name, asValue(opt.value));
}
return map;
}
function asAttributes(attributes) {
const map = new Map();
for (const attr of attributes) {
const name = asName(attr.name);
if (map.has(name)) {
throw new errors_js_1.MessageSyntaxError('duplicate-attribute', attr.start, attr.end);
}
map.set(name, attr.value ? asValue(attr.value) : true);
}
return map;
}
function asName(id) {

@@ -154,0 +151,0 @@ switch (id.length) {

import type * as Model from './types.js';
export type MessageParserOptions = {
/**
* Parse a private annotation starting with `^` or `&`.
* By default, private annotations are parsed as unsupported annotations.
*
* @returns `pos` as the position at the end of the `annotation`,
* not including any trailing whitespace.
*/
privateAnnotation?: (source: string, pos: number) => {
pos: number;
annotation: any;
};
};
/**

@@ -22,2 +9,2 @@ * A MessageFormat 2 parser for message formatting.

*/
export declare function parseMessage(source: string, opt?: MessageParserOptions): Model.Message;
export declare function parseMessage(source: string): Model.Message;

@@ -6,7 +6,7 @@ "use strict";

const errors_js_1 = require("../errors.js");
const whitespaceChars = ['\t', '\n', '\r', ' ', '\u3000'];
const bidiChars = new Set('\u061C\u200E\u200F\u2066\u2067\u2068\u2069');
const whitespaceChars = new Set('\t\n\r \u3000');
//// Parser State ////
let pos;
let source;
let opt;
//// Utilities & Error Wrappers ////

@@ -26,6 +26,5 @@ // These indirections allow for the function names to be mangled,

}
function parseMessage(source_, opt_ = {}) {
function parseMessage(source_) {
pos = 0;
source = source_;
opt = opt_;
const decl = declarations();

@@ -35,2 +34,4 @@ if (source.startsWith('.match', pos))

const quoted = decl.length > 0 || source.startsWith('{{', pos);
if (!quoted && pos > 0)
pos = 0;
const pattern_ = pattern(quoted);

@@ -48,7 +49,7 @@ if (quoted) {

pos += 6; // '.match'
ws();
ws(true);
const selectors = [];
while (source[pos] === '{') {
selectors.push(expression(false));
ws();
while (source[pos] === '$') {
selectors.push(variable());
ws(true);
}

@@ -114,17 +115,16 @@ if (selectors.length === 0)

const declarations = [];
ws();
loop: while (source[pos] === '.') {
const keyword = (0, names_js_1.parseNameValue)(source, pos + 1);
const keyword = source.substr(pos, 6);
switch (keyword) {
case 'input':
case '.input':
declarations.push(inputDeclaration());
break;
case 'local':
case '.local':
declarations.push(localDeclaration());
break;
case 'match':
case '.match':
break loop;
case '':
default:
throw SyntaxError('parse-error', pos);
default:
declarations.push(unsupportedStatement(keyword));
}

@@ -159,17 +159,2 @@ ws();

}
function unsupportedStatement(keyword) {
pos += 1 + keyword.length; // '.' + keyword
ws('{');
const body = reservedBody();
const expressions = [];
while (source[pos] === '{') {
if (source.startsWith('{{', pos))
break;
expressions.push(expression(false));
ws();
}
if (expressions.length === 0)
throw SyntaxError('empty-token', pos);
return { type: 'unsupported-statement', keyword, body, expressions };
}
function expression(allowMarkup) {

@@ -183,3 +168,3 @@ const start = pos;

const sigil = source[pos];
let annotation;
let functionRef;
let markup;

@@ -192,6 +177,6 @@ switch (sigil) {

pos += 1; // ':'
annotation = { type: 'function', name: identifier() };
functionRef = { type: 'function', name: identifier() };
const options_ = options();
if (options_.length)
annotation.options = options_;
if (options_)
functionRef.options = options_;
break;

@@ -207,25 +192,10 @@ }

const options_ = options();
if (options_.length)
if (options_)
markup.options = options_;
break;
}
case '^':
case '&':
annotation = privateAnnotation(sigil);
break;
case '!':
case '%':
case '*':
case '+':
case '<':
case '>':
case '?':
case '~':
annotation = unsupportedAnnotation(sigil);
break;
default:
throw SyntaxError('parse-error', pos);
}
while (source[pos] === '@')
attribute();
const attributes_ = attributes();
if (markup?.kind === 'open' && source[pos] === '/') {

@@ -236,12 +206,20 @@ markup.kind = 'standalone';

expect('}', true);
if (annotation) {
return arg
? { type: 'expression', arg, annotation }
: { type: 'expression', annotation };
if (functionRef) {
const exp = arg
? { type: 'expression', arg, functionRef: functionRef }
: { type: 'expression', functionRef: functionRef };
if (attributes_)
exp.attributes = attributes_;
return exp;
}
if (markup)
if (markup) {
if (attributes_)
markup.attributes = attributes_;
return markup;
}
if (!arg)
throw SyntaxError('empty-token', start, pos);
return { type: 'expression', arg };
return attributes_
? { type: 'expression', arg, attributes: attributes_ }
: { type: 'expression', arg };
}

@@ -251,3 +229,4 @@ /** Requires and consumes leading and trailing whitespace. */

ws('/}');
const options = [];
const options = new Map();
let isEmpty = true;
while (pos < source.length) {

@@ -257,75 +236,39 @@ const next = source[pos];

break;
const start = pos;
const name_ = identifier();
if (options.has(name_)) {
throw SyntaxError('duplicate-option-name', start, pos);
}
ws();
expect('=', true);
ws();
options.push({ name: name_, value: value(true) });
options.set(name_, value(true));
isEmpty = false;
ws('/}');
}
return options;
return isEmpty ? null : options;
}
function attribute() {
pos += 1; // '@'
identifier(); // name
ws('=/}');
if (source[pos] === '=') {
pos += 1; // '='
ws();
value(true); // value
ws('/}');
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function privateAnnotation(sigil) {
if (opt.privateAnnotation) {
const res = opt.privateAnnotation(source, pos);
pos = res.pos;
ws('}');
return res.annotation;
}
return unsupportedAnnotation(sigil);
}
function unsupportedAnnotation(sigil) {
pos += 1; // sigil
return { type: 'unsupported-annotation', source: sigil + reservedBody() };
}
function reservedBody() {
const start = pos;
loop: while (pos < source.length) {
const next = source[pos];
switch (next) {
case '\\': {
switch (source[pos + 1]) {
case '\\':
case '{':
case '|':
case '}':
break;
default:
throw SyntaxError('bad-escape', pos, pos + 2);
}
pos += 2;
break;
}
case '|':
quotedLiteral();
break;
case '@':
pos -= 1;
ws(true);
break loop;
case '{':
case '}':
break loop;
default: {
const cc = next.charCodeAt(0);
if (cc >= 0xd800 && cc < 0xe000) {
// surrogates are invalid here
throw SyntaxError('parse-error', pos);
}
pos += 1;
}
function attributes() {
const attributes = new Map();
let isEmpty = true;
while (source[pos] === '@') {
const start = pos;
pos += 1; // '@'
const name_ = identifier();
if (attributes.has(name_)) {
throw SyntaxError('duplicate-attribute', start, pos);
}
ws('=/}');
if (source[pos] === '=') {
pos += 1; // '='
ws();
attributes.set(name_, literal(true));
ws('/}');
}
else {
attributes.set(name_, true);
}
isEmpty = false;
}
return source.substring(start, pos).trimEnd();
return isEmpty ? null : attributes;
}

@@ -339,5 +282,4 @@ function text() {

const esc = source[i + 1];
if (esc !== '\\' && esc !== '{' && esc !== '}') {
if (!'\\{|}'.includes(esc))
throw SyntaxError('bad-escape', i, i + 2);
}
value += source.substring(pos, i) + esc;

@@ -358,10 +300,8 @@ i += 1;

function value(required) {
if (source[pos] === '$') {
pos += 1; // '$'
return { type: 'variable', name: name() };
}
else {
return literal(required);
}
return source[pos] === '$' ? variable() : literal(required);
}
function variable() {
pos += 1; // '$'
return { type: 'variable', name: name() };
}
function literal(required) {

@@ -387,5 +327,4 @@ if (source[pos] === '|')

const esc = source[i + 1];
if (esc !== '\\' && esc !== '|') {
if (!'\\{|}'.includes(esc))
throw SyntaxError('bad-escape', i, i + 2);
}
value += source.substring(pos, i) + esc;

@@ -416,16 +355,21 @@ i += 1;

throw SyntaxError('empty-token', pos);
pos += name.length;
return name;
pos = name.end;
return name.value;
}
function ws(req = false) {
let length = 0;
let next = source[pos];
while (whitespaceChars.includes(next)) {
length += 1;
next = source[pos + length];
let hasWS = false;
if (req) {
while (bidiChars.has(next))
next = source[++pos];
while (whitespaceChars.has(next)) {
next = source[++pos];
hasWS = true;
}
}
pos += length;
if (req && !length && (req === true || !req.includes(source[pos]))) {
while (bidiChars.has(next) || whitespaceChars.has(next))
next = source[++pos];
if (req && !hasWS && (req === true || !req.includes(source[pos]))) {
throw MissingSyntax(pos, "' '");
}
}
import type { Context } from '../format-context.js';
import type { MessageValue } from '../functions/index.js';
import type { Expression } from './types.js';
export declare function resolveExpression(ctx: Context, { arg, annotation }: Expression): MessageValue;
export declare function resolveExpression(ctx: Context, { arg, functionRef }: Expression): MessageValue;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveExpression = void 0;
const resolve_function_annotation_js_1 = require("./resolve-function-annotation.js");
const resolve_function_ref_js_1 = require("./resolve-function-ref.js");
const resolve_literal_js_1 = require("./resolve-literal.js");
const resolve_unsupported_annotation_js_1 = require("./resolve-unsupported-annotation.js");
const resolve_variable_js_1 = require("./resolve-variable.js");
function resolveExpression(ctx, { arg, annotation }) {
if (annotation) {
return annotation.type === 'function'
? (0, resolve_function_annotation_js_1.resolveFunctionAnnotation)(ctx, arg, annotation)
: (0, resolve_unsupported_annotation_js_1.resolveUnsupportedAnnotation)(ctx, arg, annotation);
function resolveExpression(ctx, { arg, functionRef }) {
if (functionRef) {
return (0, resolve_function_ref_js_1.resolveFunctionRef)(ctx, arg, functionRef);
}

@@ -14,0 +11,0 @@ switch (arg?.type) {

@@ -25,3 +25,3 @@ "use strict";

exports.UnresolvedExpression = UnresolvedExpression;
const isScope = (scope) => scope instanceof Object;
const isScope = (scope) => scope !== null && (typeof scope === 'object' || typeof scope === 'function');
/**

@@ -59,3 +59,3 @@ * Looks for the longest matching `.` delimited starting substring of name.

const msg = `Variable not available: ${source}`;
ctx.onError(new errors_js_1.MessageResolutionError('unresolved-var', msg, source));
ctx.onError(new errors_js_1.MessageResolutionError('unresolved-variable', msg, source));
}

@@ -62,0 +62,0 @@ else if (value instanceof UnresolvedExpression) {

@@ -1,2 +0,1 @@

import { MessageFormat } from '../messageformat.js';
import type { Message } from './types.js';

@@ -8,2 +7,2 @@ /**

*/
export declare function stringifyMessage(msg: Message | MessageFormat): string;
export declare function stringifyMessage(msg: Message): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringifyMessage = void 0;
const messageformat_js_1 = require("../messageformat.js");
const names_js_1 = require("../cst/names.js");

@@ -13,4 +12,2 @@ const type_guards_js_1 = require("./type-guards.js");

function stringifyMessage(msg) {
if (msg instanceof messageformat_js_1.MessageFormat)
msg = msg.resolvedOptions().message;
let res = '';

@@ -25,3 +22,3 @@ for (const decl of msg.declarations)

for (const sel of msg.selectors)
res += ' ' + stringifyExpression(sel);
res += ' ' + stringifyVariableRef(sel);
for (const { keys, value } of msg.variants) {

@@ -44,13 +41,2 @@ res += '\n';

return `.local $${decl.name} = ${stringifyExpression(decl.value)}\n`;
case 'unsupported-statement': {
const parts = [`.${decl.keyword}`];
if (decl.body)
parts.push(decl.body);
for (const exp of decl.expressions) {
parts.push(exp.type === 'expression'
? stringifyExpression(exp)
: stringifyMarkup(exp));
}
return parts.join(' ');
}
}

@@ -60,7 +46,9 @@ // @ts-expect-error Guard against non-TS users with bad data

}
function stringifyFunctionAnnotation({ name, options }) {
function stringifyFunctionRef({ name, options }) {
let res = `:${name}`;
if (options)
for (const opt of options)
res += ' ' + stringifyOption(opt);
if (options) {
for (const [key, value] of options) {
res += ' ' + stringifyOption(key, value);
}
}
return res;

@@ -71,8 +59,11 @@ }

res += name;
if (options)
for (const opt of options)
res += ' ' + stringifyOption(opt);
if (options) {
for (const [name, value] of options) {
res += ' ' + stringifyOption(name, value);
}
}
if (attributes) {
for (const attr of attributes)
res += ' ' + stringifyAttribute(attr);
for (const [name, value] of attributes) {
res += ' ' + stringifyAttribute(name, value);
}
}

@@ -88,3 +79,3 @@ res += kind === 'standalone' ? ' /}' : '}';

}
function stringifyOption({ name, value }) {
function stringifyOption(name, value) {
const valueStr = (0, type_guards_js_1.isVariableRef)(value)

@@ -95,13 +86,8 @@ ? stringifyVariableRef(value)

}
function stringifyAttribute({ name, value }) {
if (!value)
return `@${name}`;
const valueStr = (0, type_guards_js_1.isVariableRef)(value)
? stringifyVariableRef(value)
: stringifyLiteral(value);
return `@${name}=${valueStr}`;
function stringifyAttribute(name, value) {
return value === true ? `@${name}` : `@${name}=${stringifyLiteral(value)}`;
}
function stringifyPattern(pattern, quoted) {
let res = '';
if (!quoted && typeof pattern[0] === 'string' && pattern[0][0] === '.') {
if (!quoted && typeof pattern[0] === 'string' && /^\s*\./.test(pattern[0])) {
quoted = true;

@@ -111,3 +97,3 @@ }

if (typeof el === 'string')
res += el;
res += stringifyString(el, quoted);
else if (el.type === 'markup')

@@ -120,3 +106,7 @@ res += stringifyMarkup(el);

}
function stringifyExpression({ arg, annotation, attributes }) {
function stringifyString(str, quoted) {
const esc = quoted ? /[\\|]/g : /[\\{}]/g;
return str.replace(esc, '\\$&');
}
function stringifyExpression({ arg, attributes, functionRef }) {
let res;

@@ -133,13 +123,11 @@ switch (arg?.type) {

}
if (annotation) {
if (functionRef) {
if (res)
res += ' ';
res +=
annotation.type === 'function'
? stringifyFunctionAnnotation(annotation)
: annotation.source ?? '�';
res += stringifyFunctionRef(functionRef);
}
if (attributes) {
for (const attr of attributes)
res += ' ' + stringifyAttribute(attr);
for (const [name, value] of attributes) {
res += ' ' + stringifyAttribute(name, value);
}
}

@@ -146,0 +134,0 @@ return `{${res}}`;

@@ -1,2 +0,2 @@

import type { CatchallKey, Expression, FunctionAnnotation, Literal, Markup, Message, PatternMessage, SelectMessage, UnsupportedAnnotation, VariableRef } from './types.js';
import type { CatchallKey, Expression, FunctionRef, Literal, Markup, Message, PatternMessage, SelectMessage, VariableRef } from './types.js';
/** @beta */

@@ -7,3 +7,3 @@ export declare const isCatchallKey: (key: any) => key is CatchallKey;

/** @beta */
export declare const isFunctionAnnotation: (part: any) => part is FunctionAnnotation;
export declare const isFunctionRef: (part: any) => part is FunctionRef;
/** @beta */

@@ -20,4 +20,2 @@ export declare const isLiteral: (part: any) => part is Literal;

/** @beta */
export declare const isUnsupportedAnnotation: (part: any) => part is UnsupportedAnnotation;
/** @beta */
export declare const isVariableRef: (part: any) => part is VariableRef;
"use strict";
/* eslint-disable @typescript-eslint/no-explicit-any */
Object.defineProperty(exports, "__esModule", { value: true });
exports.isVariableRef = exports.isUnsupportedAnnotation = exports.isSelectMessage = exports.isPatternMessage = exports.isMessage = exports.isMarkup = exports.isLiteral = exports.isFunctionAnnotation = exports.isExpression = exports.isCatchallKey = void 0;
exports.isVariableRef = exports.isSelectMessage = exports.isPatternMessage = exports.isMessage = exports.isMarkup = exports.isLiteral = exports.isFunctionRef = exports.isExpression = exports.isCatchallKey = void 0;
/** @beta */

@@ -12,4 +12,4 @@ const isCatchallKey = (key) => !!key && typeof key === 'object' && key.type === '*';

/** @beta */
const isFunctionAnnotation = (part) => !!part && typeof part === 'object' && part.type === 'function';
exports.isFunctionAnnotation = isFunctionAnnotation;
const isFunctionRef = (part) => !!part && typeof part === 'object' && part.type === 'function';
exports.isFunctionRef = isFunctionRef;
/** @beta */

@@ -33,6 +33,3 @@ const isLiteral = (part) => !!part && typeof part === 'object' && part.type === 'literal';

/** @beta */
const isUnsupportedAnnotation = (part) => !!part && typeof part === 'object' && part.type === 'unsupported-annotation';
exports.isUnsupportedAnnotation = isUnsupportedAnnotation;
/** @beta */
const isVariableRef = (part) => !!part && typeof part === 'object' && part.type === 'variable';
exports.isVariableRef = isVariableRef;

@@ -8,3 +8,3 @@ import type * as CST from '../cst/types.js';

*/
export type MessageNode = Declaration | Variant | CatchallKey | Expression | Literal | VariableRef | FunctionAnnotation | UnsupportedAnnotation | Markup | Option | Attribute;
export type MessageNode = Declaration | Variant | CatchallKey | Expression | Literal | VariableRef | FunctionRef | Markup;
/**

@@ -37,3 +37,3 @@ * The representation of a single message.

*/
export type Declaration = InputDeclaration | LocalDeclaration | UnsupportedStatement;
export type Declaration = InputDeclaration | LocalDeclaration;
/** @beta */

@@ -53,12 +53,2 @@ export interface InputDeclaration {

}
/** @beta */
export interface UnsupportedStatement {
type: 'unsupported-statement';
keyword: string;
name?: never;
value?: never;
body?: string;
expressions: (Expression | Markup)[];
[cst]?: CST.Declaration;
}
/**

@@ -79,3 +69,3 @@ * SelectMessage generalises the plural, selectordinal and select

declarations: Declaration[];
selectors: Expression[];
selectors: VariableRef[];
variants: Variant[];

@@ -112,19 +102,17 @@ comment?: string;

* Expressions are used in declarations, as selectors, and as placeholders.
* Each must include at least an `arg` or an `annotation`, or both.
* Each must include at least an `arg` or a `functionRef`, or both.
*
* @beta
*/
export type Expression<A extends Literal | VariableRef | undefined = Literal | VariableRef | undefined> = A extends Literal | VariableRef ? {
export type Expression<A extends Literal | VariableRef | undefined = Literal | VariableRef | undefined> = {
type: 'expression';
attributes?: Attributes;
[cst]?: CST.Expression;
} & (A extends Literal | VariableRef ? {
arg: A;
annotation?: FunctionAnnotation | UnsupportedAnnotation;
attributes?: Attribute[];
[cst]?: CST.Expression;
functionRef?: FunctionRef;
} : {
type: 'expression';
arg?: never;
annotation: FunctionAnnotation | UnsupportedAnnotation;
attributes?: Attribute[];
[cst]?: CST.Expression;
};
functionRef: FunctionRef;
});
/**

@@ -164,3 +152,3 @@ * An immediately defined value.

/**
* To resolve a FunctionAnnotation, an externally defined function is called.
* To resolve a FunctionRef, an externally defined function is called.
*

@@ -176,26 +164,9 @@ * @remarks

*/
export interface FunctionAnnotation {
export interface FunctionRef {
type: 'function';
name: string;
options?: Option[];
options?: Options;
[cst]?: CST.FunctionRef;
}
/**
* When the parser encounters an expression with reserved syntax,
* it emits an UnsupportedAnnotation to represent it.
*
* @remarks
* As the meaning of this syntax is not supported,
* it will always resolve with a fallback representation and emit an error.
*
* @beta
*/
export interface UnsupportedAnnotation {
type: 'unsupported-annotation';
source: string;
name?: never;
options?: never;
[cst]?: CST.ReservedAnnotation;
}
/**
* Markup placeholders can span ranges of other pattern elements,

@@ -217,29 +188,17 @@ * or represent other inline elements.

name: string;
options?: Option[];
attributes?: Attribute[];
options?: Options;
attributes?: Attributes;
[cst]?: CST.Expression;
}
/**
* The options of {@link FunctionAnnotation} and {@link Markup}
* are expressed as `key`/`value` pairs to allow their order to be maintained.
* The options of {@link FunctionRef} and {@link Markup}.
*
* @beta
*/
export interface Option {
type?: never;
name: string;
value: Literal | VariableRef;
[cst]?: CST.Option;
}
export type Options = Map<string, Literal | VariableRef>;
/**
* The attributes of {@link Expression} and {@link Markup}
* are expressed as `key`/`value` pairs to allow their order to be maintained.
* The attributes of {@link Expression} and {@link Markup}.
*
* @beta
*/
export interface Attribute {
type?: never;
name: string;
value?: Literal | VariableRef;
[cst]?: CST.Attribute;
}
export type Attributes = Map<string, true | Literal>;

@@ -16,5 +16,4 @@ import { MessageDataModelError } from '../errors.js';

* - **Missing Selector Annotation**:
* A _selector_ does not have an _annotation_,
* or contains a _variable_ that does not directly or indirectly
* reference a _declaration_ with an _annotation_.
* A _selector_ does not contains a _variable_ that directly or indirectly
* reference a _declaration_ with a _function_.
*

@@ -27,4 +26,4 @@ * - **Duplicate Declaration**:

*
* - **Duplicate Option Name**:
* The same _identifier_ appears as the name of more than one _option_ in the same _expression_.
* - **Duplicate Variant**:
* The same list of _keys_ is used for more than one _variant_.
*

@@ -31,0 +30,0 @@ * @returns The sets of runtime `functions` and `variables` used by the message.

@@ -19,5 +19,4 @@ "use strict";

* - **Missing Selector Annotation**:
* A _selector_ does not have an _annotation_,
* or contains a _variable_ that does not directly or indirectly
* reference a _declaration_ with an _annotation_.
* A _selector_ does not contains a _variable_ that directly or indirectly
* reference a _declaration_ with a _function_.
*

@@ -30,4 +29,4 @@ * - **Duplicate Declaration**:

*
* - **Duplicate Option Name**:
* The same _identifier_ appears as the name of more than one _option_ in the same _expression_.
* - **Duplicate Variant**:
* The same list of _keys_ is used for more than one _variant_.
*

@@ -49,2 +48,3 @@ * @returns The sets of runtime `functions` and `variables` used by the message.

const variables = new Set();
const variants = new Set();
let setArgAsDeclared = true;

@@ -56,3 +56,3 @@ (0, visit_js_1.visit)(msg, {

return undefined;
if (decl.value.annotation ||
if (decl.value.functionRef ||
(decl.type === 'local' &&

@@ -73,32 +73,24 @@ decl.value.arg?.type === 'variable' &&

},
expression(expression, context) {
const { arg, annotation } = expression;
if (annotation?.type === 'function')
functions.add(annotation.name);
if (context === 'selector') {
selectorCount += 1;
missingFallback = expression;
if (!annotation &&
(arg?.type !== 'variable' || !annotated.has(arg.name))) {
onError('missing-selector-annotation', expression);
}
}
expression({ functionRef }) {
if (functionRef)
functions.add(functionRef.name);
},
option({ name }, index, options) {
for (let j = index + 1; j < options.length; ++j) {
if (options[j].name === name) {
onError('duplicate-option', options[j]);
value(value, context, position) {
if (value.type !== 'variable')
return;
variables.add(value.name);
switch (context) {
case 'declaration':
if (position !== 'arg' || setArgAsDeclared) {
declared.add(value.name);
}
break;
}
case 'selector':
selectorCount += 1;
missingFallback = value;
if (!annotated.has(value.name)) {
onError('missing-selector-annotation', value);
}
}
},
value(value, context, position) {
if (value.type === 'variable') {
variables.add(value.name);
if (context === 'declaration' &&
(position !== 'arg' || setArgAsDeclared)) {
declared.add(value.name);
}
}
},
variant(variant) {

@@ -108,2 +100,7 @@ const { keys } = variant;

onError('key-mismatch', variant);
const strKeys = JSON.stringify(keys.map(key => (key.type === 'literal' ? key.value : 0)));
if (variants.has(strKeys))
onError('duplicate-variant', variant);
else
variants.add(strKeys);
missingFallback &&= keys.every(key => key.type === '*') ? null : variant;

@@ -110,0 +107,0 @@ }

@@ -1,2 +0,2 @@

import type { Attribute, CatchallKey, Declaration, Expression, FunctionAnnotation, Literal, Markup, Message, MessageNode, Option, Pattern, UnsupportedAnnotation, VariableRef, Variant } from './types.js';
import type { Attributes, CatchallKey, Declaration, Expression, FunctionRef, Literal, Markup, Message, MessageNode, Options, Pattern, VariableRef, Variant } from './types.js';
/**

@@ -19,10 +19,10 @@ * Apply visitor functions to message nodes.

export declare function visit(msg: Message, visitors: {
annotation?: (annotation: FunctionAnnotation | UnsupportedAnnotation, context: 'declaration' | 'selector' | 'placeholder', argument: Literal | VariableRef | undefined) => (() => void) | void;
attribute?: (attr: Attribute, index: number, attributes: Attribute[], context: 'declaration' | 'selector' | 'placeholder') => (() => void) | void;
attributes?: (attributes: Attributes, context: 'declaration' | 'placeholder') => (() => void) | void;
declaration?: (declaration: Declaration) => (() => void) | void;
expression?: (expression: Expression, context: 'declaration' | 'selector' | 'placeholder') => (() => void) | void;
expression?: (expression: Expression, context: 'declaration' | 'placeholder') => (() => void) | void;
functionRef?: (functionRef: FunctionRef, context: 'declaration' | 'placeholder', argument: Literal | VariableRef | undefined) => (() => void) | void;
key?: (key: Literal | CatchallKey, index: number, keys: (Literal | CatchallKey)[]) => void;
markup?: (markup: Markup, context: 'declaration' | 'placeholder') => (() => void) | void;
node?: (node: MessageNode, ...rest: unknown[]) => void;
option?: (option: Option, index: number, options: Option[], context: 'declaration' | 'selector' | 'placeholder') => (() => void) | void;
options?: (options: Options, context: 'declaration' | 'placeholder') => (() => void) | void;
pattern?: (pattern: Pattern) => (() => void) | void;

@@ -29,0 +29,0 @@ value?: (value: Literal | VariableRef, context: 'declaration' | 'selector' | 'placeholder', position: 'arg' | 'option' | 'attribute') => void;

@@ -22,22 +22,24 @@ "use strict";

const { node, pattern } = visitors;
const { annotation = node, attribute = node, declaration = node, expression = node, key = node, markup = node, option = node, value = node, variant = node } = visitors;
const handleOptions = (options, context) => {
if (options) {
for (let i = 0; i < options.length; ++i) {
const opt = options[i];
const end = option?.(opt, i, options, context);
value?.(opt.value, context, 'option');
end?.();
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) {
for (let i = 0; i < attributes.length; ++i) {
const attr = attributes[i];
const end = attribute?.(attr, i, attributes, context);
if (attr.value)
value?.(attr.value, context, 'attribute');
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?.();
}

@@ -53,5 +55,5 @@ };

value?.(exp.arg, context, 'arg');
if (exp.annotation) {
const endA = annotation?.(exp.annotation, context, exp.arg);
handleOptions(exp.annotation.options, context);
if (exp.functionRef) {
const endA = functionRef?.(exp.functionRef, context, exp.arg);
handleOptions(exp.functionRef.options, context);
endA?.();

@@ -63,3 +65,3 @@ }

case 'markup': {
end = context !== 'selector' ? markup?.(exp, context) : undefined;
end = markup?.(exp, context);
handleOptions(exp.options, context);

@@ -83,5 +85,2 @@ handleAttributes(exp.attributes, context);

handleElement(decl.value, 'declaration');
else
for (const exp of decl.expressions)
handleElement(exp, 'declaration');
end?.();

@@ -93,4 +92,5 @@ }

else {
for (const sel of msg.selectors)
handleElement(sel, 'selector');
if (value)
for (const sel of msg.selectors)
value(sel, 'selector', 'arg');
for (const vari of msg.variants) {

@@ -97,0 +97,0 @@ const end = variant?.(vari);

@@ -8,3 +8,3 @@ import { type MessageNode } from './data-model/types.js';

export declare class MessageError extends Error {
type: 'missing-func' | 'not-formattable' | typeof MessageResolutionError.prototype.type | typeof MessageSelectionError.prototype.type | typeof MessageSyntaxError.prototype.type;
type: 'not-formattable' | 'unknown-function' | typeof MessageResolutionError.prototype.type | typeof MessageSelectionError.prototype.type | typeof MessageSyntaxError.prototype.type;
constructor(type: typeof MessageError.prototype.type, message: string);

@@ -18,3 +18,3 @@ }

export declare class MessageSyntaxError extends MessageError {
type: 'empty-token' | 'bad-escape' | 'bad-input-expression' | 'bad-selector' | 'duplicate-declaration' | 'duplicate-option' | 'extra-content' | 'key-mismatch' | 'parse-error' | 'missing-fallback' | 'missing-selector-annotation' | 'missing-syntax';
type: 'empty-token' | 'bad-escape' | 'bad-input-expression' | 'duplicate-attribute' | 'duplicate-declaration' | 'duplicate-option-name' | 'duplicate-variant' | 'extra-content' | 'key-mismatch' | 'parse-error' | 'missing-fallback' | 'missing-selector-annotation' | 'missing-syntax';
start: number;

@@ -30,3 +30,3 @@ end: number;

export declare class MessageDataModelError extends MessageSyntaxError {
type: 'duplicate-declaration' | 'duplicate-option' | 'key-mismatch' | 'missing-fallback' | 'missing-selector-annotation';
type: 'duplicate-declaration' | 'duplicate-variant' | 'key-mismatch' | 'missing-fallback' | 'missing-selector-annotation';
constructor(type: typeof MessageDataModelError.prototype.type, node: MessageNode);

@@ -40,3 +40,3 @@ }

export declare class MessageResolutionError extends MessageError {
type: 'bad-input' | 'bad-option' | 'unresolved-var' | 'unsupported-annotation' | 'unsupported-statement';
type: 'bad-function-result' | 'bad-operand' | 'bad-option' | 'unresolved-variable';
source: string;

@@ -51,4 +51,5 @@ constructor(type: typeof MessageResolutionError.prototype.type, message: string, source: string);

export declare class MessageSelectionError extends MessageError {
type: 'no-match' | 'not-selectable';
constructor(type: typeof MessageSelectionError.prototype.type);
type: 'bad-selector' | 'no-match';
cause?: unknown;
constructor(type: typeof MessageSelectionError.prototype.type, cause?: unknown);
}

@@ -67,6 +67,9 @@ "use strict";

class MessageSelectionError extends MessageError {
constructor(type) {
cause;
constructor(type, cause) {
super(type, `Selection error: ${type}`);
if (cause !== undefined)
this.cause = cause;
}
}
exports.MessageSelectionError = MessageSelectionError;

@@ -46,3 +46,3 @@ "use strict";

if (Object.keys(res).length <= 1) {
res.dateStyle = 'short';
res.dateStyle = 'medium';
res.timeStyle = 'short';

@@ -59,3 +59,3 @@ }

const date = (ctx, options, input) => dateTimeImplementation(ctx, options, input, res => {
const ds = options.style ?? res.dateStyle ?? 'short';
const ds = options.style ?? res.dateStyle ?? 'medium';
for (const name of Object.keys(res)) {

@@ -65,3 +65,9 @@ if (!localeOptions.includes(name))

}
res.dateStyle = (0, utils_js_1.asString)(ds);
try {
res.dateStyle = (0, utils_js_1.asString)(ds);
}
catch {
const msg = `Value ${ds} is not valid for :date style option`;
throw new errors_js_1.MessageResolutionError('bad-option', msg, ctx.source);
}
});

@@ -81,3 +87,9 @@ exports.date = date;

}
res.timeStyle = (0, utils_js_1.asString)(ts);
try {
res.timeStyle = (0, utils_js_1.asString)(ts);
}
catch {
const msg = `Value ${ts} is not valid for :time style option`;
throw new errors_js_1.MessageResolutionError('bad-option', msg, ctx.source);
}
});

@@ -105,5 +117,5 @@ exports.time = time;

}
if (!(value instanceof Date)) {
if (!(value instanceof Date) || isNaN(value.getTime())) {
const msg = 'Input is not a date';
throw new errors_js_1.MessageResolutionError('bad-input', msg, source);
throw new errors_js_1.MessageResolutionError('bad-operand', msg, source);
}

@@ -110,0 +122,0 @@ parseOptions(opt);

@@ -6,3 +6,3 @@ "use strict";

const utils_js_1 = require("./utils.js");
const NotFormattable = Symbol('not-formattable');
const INT = Symbol('INT');
/**

@@ -18,65 +18,59 @@ * `number` accepts a number, BigInt or string representing a JSON number as input

function number({ localeMatcher, locales, source }, options, input) {
let value;
const opt = {
localeMatcher
};
switch (typeof input) {
case 'bigint':
case 'number':
value = input;
break;
case 'object':
if (typeof input?.valueOf === 'function') {
value = input.valueOf();
if ('options' in input)
Object.assign(opt, input.options);
}
break;
case 'string':
try {
value = JSON.parse(input);
}
catch {
// handled below
}
let value = input;
if (typeof value === 'object') {
const valueOf = value?.valueOf;
if (typeof valueOf === 'function') {
Object.assign(opt, value.options);
value = valueOf.call(value);
}
}
if (typeof value === 'string') {
try {
value = JSON.parse(value);
}
catch {
// handled below
}
}
if (typeof value !== 'bigint' && typeof value !== 'number') {
const msg = 'Input is not numeric';
throw new errors_js_1.MessageResolutionError('bad-input', msg, source);
throw new errors_js_1.MessageResolutionError('bad-operand', msg, source);
}
if (options) {
for (const [name, value] of Object.entries(options)) {
if (value === undefined)
continue;
try {
switch (name) {
case 'locale':
case 'type': // used internally by Intl.PluralRules, but called 'select' here
break;
case 'minimumIntegerDigits':
case 'minimumFractionDigits':
case 'maximumFractionDigits':
case 'minimumSignificantDigits':
case 'maximumSignificantDigits':
case 'roundingIncrement':
// @ts-expect-error TS types don't know about roundingIncrement
opt[name] = (0, utils_js_1.asPositiveInteger)(value);
break;
case 'useGrouping':
opt[name] = (0, utils_js_1.asBoolean)(value);
break;
default:
// @ts-expect-error Unknown options will be ignored
opt[name] = (0, utils_js_1.asString)(value);
}
for (const [name, optval] of Object.entries(options)) {
if (optval === undefined)
continue;
try {
switch (name) {
case 'locale':
case 'type': // used internally by Intl.PluralRules, but called 'select' here
break;
case 'minimumIntegerDigits':
case 'minimumFractionDigits':
case 'maximumFractionDigits':
case 'minimumSignificantDigits':
case 'maximumSignificantDigits':
case 'roundingIncrement':
// @ts-expect-error TS types don't know about roundingIncrement
opt[name] = (0, utils_js_1.asPositiveInteger)(optval);
break;
case 'useGrouping':
opt[name] = (0, utils_js_1.asBoolean)(optval);
break;
default:
// @ts-expect-error Unknown options will be ignored
opt[name] = (0, utils_js_1.asString)(optval);
}
catch {
const msg = `Value ${value} is not valid for :number option ${name}`;
throw new errors_js_1.MessageResolutionError('bad-option', msg, source);
}
}
catch {
const msg = `Value ${optval} is not valid for :number option ${name}`;
throw new errors_js_1.MessageResolutionError('bad-option', msg, source);
}
}
const formattable = !options[NotFormattable];
const num = Number.isFinite(value) && options[INT]
? Math.round(value)
: value;
const lc = (0, utils_js_1.mergeLocales)(locales, input, options);
const num = value;
let locale;

@@ -108,17 +102,13 @@ let nf;

},
toParts: formattable
? () => {
nf ??= new Intl.NumberFormat(lc, opt);
const parts = nf.formatToParts(num);
locale ??= nf.resolvedOptions().locale;
return [{ type: 'number', source, locale, parts }];
}
: undefined,
toString: formattable
? () => {
nf ??= new Intl.NumberFormat(lc, opt);
str ??= nf.format(num);
return str;
}
: undefined,
toParts() {
nf ??= new Intl.NumberFormat(lc, opt);
const parts = nf.formatToParts(num);
locale ??= nf.resolvedOptions().locale;
return [{ type: 'number', source, locale, parts }];
},
toString() {
nf ??= new Intl.NumberFormat(lc, opt);
str ??= nf.format(num);
return str;
},
valueOf: () => num

@@ -139,3 +129,3 @@ };

*/
const integer = (ctx, options, input) => number(ctx, { ...options, maximumFractionDigits: 0, style: 'decimal' }, input);
const integer = (ctx, options, input) => number(ctx, { ...options, maximumFractionDigits: 0, style: 'decimal', [INT]: true }, input);
exports.integer = integer;

@@ -8,5 +8,5 @@ import type * as CST from './cst/types.js';

export { messageFromCST, cst } from './data-model/from-cst.js';
export { type MessageParserOptions, parseMessage } from './data-model/parse.js';
export { parseMessage } from './data-model/parse.js';
export { stringifyMessage } from './data-model/stringify.js';
export { isCatchallKey, isExpression, isFunctionAnnotation, isLiteral, isMarkup, isMessage, isPatternMessage, isSelectMessage, isUnsupportedAnnotation, isVariableRef } from './data-model/type-guards.js';
export { isCatchallKey, isExpression, isFunctionRef, isLiteral, isMarkup, isMessage, isPatternMessage, isSelectMessage, isVariableRef } from './data-model/type-guards.js';
export { validate } from './data-model/validate.js';

@@ -13,0 +13,0 @@ export { visit } from './data-model/visit.js';

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageFormat = exports.MessageSyntaxError = exports.MessageSelectionError = exports.MessageResolutionError = exports.MessageError = exports.MessageDataModelError = exports.visit = exports.validate = exports.isVariableRef = exports.isUnsupportedAnnotation = exports.isSelectMessage = exports.isPatternMessage = exports.isMessage = exports.isMarkup = exports.isLiteral = exports.isFunctionAnnotation = exports.isExpression = exports.isCatchallKey = exports.stringifyMessage = exports.parseMessage = exports.cst = exports.messageFromCST = exports.stringifyCST = exports.parseCST = void 0;
exports.MessageFormat = exports.MessageSyntaxError = exports.MessageSelectionError = exports.MessageResolutionError = exports.MessageError = exports.MessageDataModelError = exports.visit = exports.validate = exports.isVariableRef = exports.isSelectMessage = exports.isPatternMessage = exports.isMessage = exports.isMarkup = exports.isLiteral = exports.isFunctionRef = exports.isExpression = exports.isCatchallKey = exports.stringifyMessage = exports.parseMessage = exports.cst = exports.messageFromCST = exports.stringifyCST = exports.parseCST = void 0;
var parse_cst_js_1 = require("./cst/parse-cst.js");

@@ -18,3 +18,3 @@ Object.defineProperty(exports, "parseCST", { enumerable: true, get: function () { return parse_cst_js_1.parseCST; } });

Object.defineProperty(exports, "isExpression", { enumerable: true, get: function () { return type_guards_js_1.isExpression; } });
Object.defineProperty(exports, "isFunctionAnnotation", { enumerable: true, get: function () { return type_guards_js_1.isFunctionAnnotation; } });
Object.defineProperty(exports, "isFunctionRef", { enumerable: true, get: function () { return type_guards_js_1.isFunctionRef; } });
Object.defineProperty(exports, "isLiteral", { enumerable: true, get: function () { return type_guards_js_1.isLiteral; } });

@@ -25,3 +25,2 @@ Object.defineProperty(exports, "isMarkup", { enumerable: true, get: function () { return type_guards_js_1.isMarkup; } });

Object.defineProperty(exports, "isSelectMessage", { enumerable: true, get: function () { return type_guards_js_1.isSelectMessage; } });
Object.defineProperty(exports, "isUnsupportedAnnotation", { enumerable: true, get: function () { return type_guards_js_1.isUnsupportedAnnotation; } });
Object.defineProperty(exports, "isVariableRef", { enumerable: true, get: function () { return type_guards_js_1.isVariableRef; } });

@@ -28,0 +27,0 @@ var validate_js_1 = require("./data-model/validate.js");

@@ -6,3 +6,3 @@ import type { MessageFunctionContext } from './data-model/function-context.js';

/**
* The runtime function registry available when resolving {@link FunctionAnnotation} elements.
* The runtime function registry available when resolving {@link FunctionRef} elements.
*

@@ -38,3 +38,3 @@ * @beta

#private;
constructor(source: string | Message, locales?: string | string[], options?: MessageFormatOptions);
constructor(locales: string | string[] | undefined, source: string | Message, options?: MessageFormatOptions);
format(msgParams?: Record<string, unknown>, onError?: (error: unknown) => void): string;

@@ -45,6 +45,4 @@ formatToParts(msgParams?: Record<string, unknown>, onError?: (error: unknown) => void): MessagePart[];

localeMatcher: "lookup" | "best fit";
locales: string[];
message: Readonly<Message>;
};
private createContext;
}

@@ -30,3 +30,3 @@ "use strict";

#functions;
constructor(source, locales, options) {
constructor(locales, source, options) {
this.#localeMatcher = options?.localeMatcher ?? 'best fit';

@@ -106,5 +106,3 @@ this.#locales = Array.isArray(locales)

functions: Object.freeze(this.#functions),
localeMatcher: this.#localeMatcher,
locales: this.#locales.slice(),
message: Object.freeze(this.#message)
localeMatcher: this.#localeMatcher
};

@@ -123,15 +121,3 @@ }

for (const decl of this.#message.declarations) {
switch (decl.type) {
case 'input':
scope[decl.name] = new resolve_variable_js_1.UnresolvedExpression(decl.value, msgParams);
break;
case 'local':
scope[decl.name] = new resolve_variable_js_1.UnresolvedExpression(decl.value);
break;
default: {
const source = decl.keyword ?? '�';
const msg = `Reserved ${source} annotation is not supported`;
onError(new errors_js_1.MessageResolutionError('unsupported-statement', msg, source));
}
}
scope[decl.name] = new resolve_variable_js_1.UnresolvedExpression(decl.value, decl.type === 'input' ? msgParams ?? {} : undefined);
}

@@ -138,0 +124,0 @@ const ctx = {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.selectPattern = void 0;
const resolve_expression_js_1 = require("./data-model/resolve-expression.js");
const resolve_variable_js_1 = require("./data-model/resolve-variable.js");
const errors_js_1 = require("./errors.js");

@@ -12,3 +12,3 @@ function selectPattern(context, message) {

const ctx = message.selectors.map(sel => {
const selector = (0, resolve_expression_js_1.resolveExpression)(context, sel);
const selector = (0, resolve_variable_js_1.resolveVariableRef)(context, sel);
let selectKey;

@@ -19,3 +19,3 @@ if (typeof selector.selectKey === 'function') {

else {
context.onError(new errors_js_1.MessageSelectionError('not-selectable'));
context.onError(new errors_js_1.MessageSelectionError('bad-selector'));
selectKey = () => null;

@@ -42,3 +42,10 @@ }

}
sc.best = sc.keys.size ? sc.selectKey(sc.keys) : null;
try {
sc.best = sc.keys.size ? sc.selectKey(sc.keys) : null;
}
catch (error) {
context.onError(new errors_js_1.MessageSelectionError('bad-selector', error));
sc.selectKey = () => null;
sc.best = null;
}
// Leave out all candidate variants that aren't the best,

@@ -78,3 +85,3 @@ // or only the catchall ones, if nothing else matches.

default:
context.onError(new errors_js_1.MessageSelectionError('not-selectable'));
context.onError(new errors_js_1.MessageSelectionError('bad-selector'));
return [];

@@ -81,0 +88,0 @@ }

{
"name": "messageformat",
"version": "4.0.0-7",
"version": "4.0.0-8",
"description": "Intl.MessageFormat / Unicode MessageFormat 2 parser, runtime and polyfill",

@@ -21,3 +21,3 @@ "keywords": [

"type": "git",
"url": "https://github.com/messageformat/messageformat.git",
"url": "git+https://github.com/messageformat/messageformat.git",
"directory": "packages/mf2-messageformat"

@@ -24,0 +24,0 @@ },

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc