messageformat
Version:
Intl.MessageFormat / Unicode MessageFormat 2 parser, runtime and polyfill
107 lines (106 loc) • 3.33 kB
JavaScript
import { parseExpression } from "./expression.js";
import { whitespaces } from "./util.js";
import { parseVariable } from "./values.js";
export function parseDeclarations(ctx, start) {
const { source } = ctx;
let pos = start;
const declarations = [];
loop: while (source[pos] === '.') {
const keyword = source.substr(pos, 6);
let decl;
switch (keyword) {
case '.match':
break loop;
case '.input':
decl = parseInputDeclaration(ctx, pos);
break;
case '.local':
decl = parseLocalDeclaration(ctx, pos);
break;
default:
decl = parseDeclarationJunk(ctx, pos);
}
declarations.push(decl);
pos = whitespaces(source, decl.end).end;
}
return { declarations, end: pos };
}
function parseInputDeclaration(ctx, start) {
//
let pos = start + 6; // '.input'
const keyword = { start, end: pos, value: '.input' };
pos = whitespaces(ctx.source, pos).end;
const value = parseDeclarationValue(ctx, pos);
if (value.type === 'expression') {
if (value.markup || value.arg?.type !== 'variable') {
ctx.onError('bad-input-expression', value.start, value.end);
}
}
return { type: 'input', start, end: value.end, keyword, value };
}
function parseLocalDeclaration(ctx, start) {
const { source } = ctx;
let pos = start + 6; // '.local'
const keyword = { start, end: pos, value: '.local' };
const ws = whitespaces(source, pos);
pos = ws.end;
if (!ws.hasWS)
ctx.onError('missing-syntax', pos, ' ');
let target;
if (source[pos] === '$') {
target = parseVariable(ctx, pos);
pos = target.end;
}
else {
const junkStart = pos;
const junkEndOffset = source.substring(pos).search(/[\t\n\r ={}]/);
pos = junkEndOffset === -1 ? source.length : pos + junkEndOffset;
target = {
type: 'junk',
start: junkStart,
end: pos,
source: source.substring(junkStart, pos)
};
ctx.onError('missing-syntax', junkStart, '$');
}
pos = whitespaces(source, pos).end;
let equals;
if (source[pos] === '=') {
equals = { start: pos, end: pos + 1, value: '=' };
pos += 1;
}
else {
ctx.onError('missing-syntax', pos, '=');
}
pos = whitespaces(source, pos).end;
const value = parseDeclarationValue(ctx, pos);
return {
type: 'local',
start,
end: value.end,
keyword,
target,
equals,
value
};
}
function parseDeclarationValue(ctx, start) {
return ctx.source[start] === '{'
? parseExpression(ctx, start)
: parseDeclarationJunk(ctx, start);
}
function parseDeclarationJunk(ctx, start) {
const { source } = ctx;
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) };
}