messageformat
Advanced tools
Comparing version 4.0.0-3.cf to 4.0.0-4
import type { MessageSyntaxError } from './errors'; | ||
import type { Junk, Literal, PatternElement, Placeholder, VariableRef } from './pattern'; | ||
import type { Junk, Literal, PatternElement, Expression, VariableRef } from './pattern'; | ||
/** | ||
@@ -25,3 +25,3 @@ * The representation of a single message. | ||
* A message may declare any number of local variables or aliases, | ||
* each with a value defined by a placeholder. | ||
* each with a value defined by an expression. | ||
* The order of the declarations is not relevant, | ||
@@ -34,3 +34,3 @@ * but a valid message may not include a dependency loop amond them. | ||
target: VariableRef | Junk; | ||
value: Placeholder | Junk; | ||
value: Expression | Junk; | ||
} | ||
@@ -52,3 +52,3 @@ /** | ||
* and selection between them is made according to | ||
* the values of a corresponding number of placeholders. | ||
* the values of a corresponding number of expressions. | ||
* Selection iterates among the `variants` in order, | ||
@@ -55,0 +55,0 @@ * and terminates when all of the Variant keys match. |
export declare class MessageError extends Error { | ||
type: 'junk-element' | 'missing-func' | 'unresolved-var' | typeof MessageSyntaxError.prototype.type; | ||
type: 'junk-element' | 'missing-func' | 'reserved' | 'unresolved-var' | typeof MessageSyntaxError.prototype.type; | ||
constructor(type: typeof MessageError.prototype.type, message: string); | ||
@@ -4,0 +4,0 @@ } |
@@ -7,3 +7,3 @@ "use strict"; | ||
for (const part of parts) { | ||
if ((0, pattern_1.isExpression)(part)) { | ||
if ((0, pattern_1.isFunctionRef)(part) && part.kind === 'value') { | ||
if (typeof runtime[part.name] !== 'function') { | ||
@@ -10,0 +10,0 @@ throw new ReferenceError(`Runtime function not available: ${part.name}`); |
@@ -6,5 +6,5 @@ export { asMessageValue } from './as-message-value'; | ||
export { MessageLiteral } from './message-literal'; | ||
export { MessageMarkupStart, MessageMarkupEnd } from './message-markup'; | ||
export { MessageMarkup } from './message-markup'; | ||
export { MessageNumber } from './message-number'; | ||
export { MessageValue, Meta } from './message-value'; | ||
export { ResolvedMessage } from './resolved-message'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ResolvedMessage = exports.MessageValue = exports.MessageNumber = exports.MessageMarkupEnd = exports.MessageMarkupStart = exports.MessageLiteral = exports.MessageFallback = exports.MessageDateTime = exports.extendLocaleContext = exports.asMessageValue = void 0; | ||
exports.ResolvedMessage = exports.MessageValue = exports.MessageNumber = exports.MessageMarkup = exports.MessageLiteral = exports.MessageFallback = exports.MessageDateTime = exports.extendLocaleContext = exports.asMessageValue = void 0; | ||
var as_message_value_1 = require("./as-message-value"); | ||
@@ -15,4 +15,3 @@ Object.defineProperty(exports, "asMessageValue", { enumerable: true, get: function () { return as_message_value_1.asMessageValue; } }); | ||
var message_markup_1 = require("./message-markup"); | ||
Object.defineProperty(exports, "MessageMarkupStart", { enumerable: true, get: function () { return message_markup_1.MessageMarkupStart; } }); | ||
Object.defineProperty(exports, "MessageMarkupEnd", { enumerable: true, get: function () { return message_markup_1.MessageMarkupEnd; } }); | ||
Object.defineProperty(exports, "MessageMarkup", { enumerable: true, get: function () { return message_markup_1.MessageMarkup; } }); | ||
var message_number_1 = require("./message-number"); | ||
@@ -19,0 +18,0 @@ Object.defineProperty(exports, "MessageNumber", { enumerable: true, get: function () { return message_number_1.MessageNumber; } }); |
@@ -8,6 +8,9 @@ import type { LocaleContextArg } from './locale-context'; | ||
*/ | ||
export declare class MessageMarkupStart extends MessageValue<string> { | ||
export declare class MessageMarkup extends MessageValue<string> { | ||
options: Record<string, unknown>; | ||
constructor(locale: LocaleContextArg, name: string, { meta, options, source }: { | ||
operand?: MessageValue; | ||
constructor(locale: LocaleContextArg, name: string, { kind, meta, operand, options, source }: { | ||
kind: 'open' | 'close'; | ||
meta?: Readonly<Meta>; | ||
operand?: MessageValue; | ||
options?: Readonly<Record<string, unknown>>; | ||
@@ -19,14 +22,1 @@ source?: string; | ||
} | ||
/** | ||
* A child class of {@link MessageValue} for ending markup elements. | ||
* | ||
* @beta | ||
*/ | ||
export declare class MessageMarkupEnd extends MessageValue<string> { | ||
constructor(locale: LocaleContextArg, name: string, options: { | ||
meta?: Readonly<Meta>; | ||
source?: string; | ||
}); | ||
selectKey(): null; | ||
toString(): string; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.MessageMarkupEnd = exports.MessageMarkupStart = void 0; | ||
exports.MessageMarkup = void 0; | ||
const message_value_1 = require("./message-value"); | ||
@@ -12,6 +12,9 @@ const MARKUP_START = 'markup-start'; | ||
*/ | ||
class MessageMarkupStart extends message_value_1.MessageValue { | ||
constructor(locale, name, { meta, options, source }) { | ||
super(MARKUP_START, locale, name, { meta, source }); | ||
class MessageMarkup extends message_value_1.MessageValue { | ||
constructor(locale, name, { kind, meta, operand, options, source }) { | ||
const type = kind === 'open' ? MARKUP_START : MARKUP_END; | ||
super(type, locale, name, { meta, source }); | ||
this.options = { ...options }; | ||
if (operand) | ||
this.operand = operand; | ||
} | ||
@@ -22,22 +25,6 @@ selectKey() { | ||
toString() { | ||
return `{+${this.value}}`; | ||
const sigil = this.type === MARKUP_START ? '+' : '-'; | ||
return `{${sigil}${this.value}}`; | ||
} | ||
} | ||
exports.MessageMarkupStart = MessageMarkupStart; | ||
/** | ||
* A child class of {@link MessageValue} for ending markup elements. | ||
* | ||
* @beta | ||
*/ | ||
class MessageMarkupEnd extends message_value_1.MessageValue { | ||
constructor(locale, name, options) { | ||
super(MARKUP_END, locale, name, options); | ||
} | ||
selectKey() { | ||
return null; | ||
} | ||
toString() { | ||
return `{-${this.value}}`; | ||
} | ||
} | ||
exports.MessageMarkupEnd = MessageMarkupEnd; | ||
exports.MessageMarkup = MessageMarkup; |
@@ -31,3 +31,3 @@ import { Message } from './data-model'; | ||
resolvedOptions(): { | ||
localeMatcher: "best fit" | "lookup"; | ||
localeMatcher: "lookup" | "best fit"; | ||
locales: string[]; | ||
@@ -34,0 +34,0 @@ message: Message; |
import type { CatchallKey, Declaration, JunkMessage, Pattern, PatternMessage, SelectMessage, Variant } from '../data-model'; | ||
import type { MessageSyntaxError } from '../errors'; | ||
import type { Expression, Junk, Literal, MarkupEnd, MarkupStart, Option, Text, VariableRef } from '../pattern'; | ||
import type { Expression, FunctionRef, Junk, Literal, Option, Reserved, Text, VariableRef } from '../pattern'; | ||
export type MessageParsed = PatternMessageParsed | SelectMessageParsed | JunkMessageParsed; | ||
@@ -14,3 +14,3 @@ export interface PatternMessageParsed extends PatternMessage { | ||
declarations: DeclarationParsed[]; | ||
selectors: PlaceholderParsed[]; | ||
selectors: ExpressionParsed[]; | ||
variants: VariantParsed[]; | ||
@@ -30,3 +30,3 @@ errors: MessageSyntaxError[]; | ||
target: VariableRefParsed | JunkParsed; | ||
value: PlaceholderParsed | JunkParsed; | ||
value: ExpressionParsed | JunkParsed; | ||
} | ||
@@ -37,3 +37,3 @@ export interface VariantParsed extends Variant { | ||
end: number; | ||
keys: Array<LiteralParsed | NmtokenParsed | CatchallKeyParsed>; | ||
keys: Array<LiteralParsed | LiteralParsed | CatchallKeyParsed>; | ||
value: PatternParsed; | ||
@@ -52,3 +52,3 @@ } | ||
end: number; | ||
body: Array<TextParsed | PlaceholderParsed>; | ||
body: Array<TextParsed | ExpressionParsed>; | ||
} | ||
@@ -61,4 +61,4 @@ export interface TextParsed extends Text { | ||
} | ||
export interface PlaceholderParsed { | ||
type: 'placeholder'; | ||
export interface ExpressionParsed extends Expression { | ||
type: 'expression'; | ||
/** position of the `{` */ | ||
@@ -68,3 +68,3 @@ start: number; | ||
end: number; | ||
body: LiteralParsed | VariableRefParsed | ExpressionParsed | MarkupStartParsed | MarkupEndParsed | JunkParsed; | ||
body: LiteralParsed | VariableRefParsed | FunctionRefParsed | ReservedParsed | JunkParsed; | ||
} | ||
@@ -79,2 +79,3 @@ export interface JunkParsed extends Junk { | ||
type: 'literal'; | ||
quoted: boolean; | ||
/** position of the initial `|` */ | ||
@@ -93,6 +94,7 @@ start: number; | ||
} | ||
export interface ExpressionParsed extends Expression { | ||
type: 'expression'; | ||
export interface FunctionRefParsed extends FunctionRef { | ||
type: 'function'; | ||
kind: 'open' | 'close' | 'value'; | ||
operand: LiteralParsed | VariableRefParsed | undefined; | ||
/** position of the `:`, so `operand.start` may be earlier */ | ||
/** position of the `:`/`+`/`-`, so `operand.start` may be earlier */ | ||
start: number; | ||
@@ -103,17 +105,11 @@ end: number; | ||
} | ||
export interface MarkupStartParsed extends MarkupStart { | ||
type: 'markup-start'; | ||
/** position of the `+` */ | ||
export interface ReservedParsed extends Reserved { | ||
type: 'reserved'; | ||
sigil: '!' | '@' | '#' | '%' | '^' | '&' | '*' | '<' | '>' | '?' | '~'; | ||
operand: Literal | VariableRef | undefined; | ||
source: string; | ||
/** position of the sigil, so `operand.start` may be earlier */ | ||
start: number; | ||
end: number; | ||
name: string; | ||
options: OptionParsed[]; | ||
} | ||
export interface MarkupEndParsed extends MarkupEnd { | ||
type: 'markup-end'; | ||
/** position of the `-` */ | ||
start: number; | ||
end: number; | ||
name: string; | ||
} | ||
export interface OptionParsed extends Option { | ||
@@ -124,10 +120,3 @@ /** position at the start of the name */ | ||
name: string; | ||
value: LiteralParsed | NmtokenParsed | VariableRefParsed; | ||
value: LiteralParsed | LiteralParsed | VariableRefParsed; | ||
} | ||
export interface NmtokenParsed extends Literal { | ||
type: 'nmtoken'; | ||
/** position at the start of the value */ | ||
start: number; | ||
end: number; | ||
value: string; | ||
} |
@@ -1,6 +0,6 @@ | ||
import { MessageSyntaxError } from '../errors.js'; | ||
import type { DeclarationParsed } from './data-model.js'; | ||
export declare function parseDeclarations(src: string, errors: MessageSyntaxError[]): { | ||
import type { ParseContext } from './message.js'; | ||
export declare function parseDeclarations(ctx: ParseContext): { | ||
declarations: DeclarationParsed[]; | ||
end: number; | ||
}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseDeclarations = void 0; | ||
const errors_js_1 = require("../errors.js"); | ||
const placeholder_js_1 = require("./placeholder.js"); | ||
const expression_js_1 = require("./expression.js"); | ||
const util_js_1 = require("./util.js"); | ||
const values_js_1 = require("./values.js"); | ||
// Declaration ::= 'let' WhiteSpace Variable '=' '{' Expression '}' | ||
function parseDeclarations(src, errors) { | ||
let pos = (0, util_js_1.whitespaces)(src, 0); | ||
function parseDeclarations(ctx) { | ||
let pos = (0, util_js_1.whitespaces)(ctx.source, 0); | ||
const declarations = []; | ||
while (src.startsWith('let', pos)) { | ||
const decl = parseDeclaration(src, pos, errors); | ||
while (ctx.source.startsWith('let', pos)) { | ||
const decl = parseDeclaration(ctx, pos); | ||
declarations.push(decl); | ||
pos = decl.end; | ||
pos += (0, util_js_1.whitespaces)(src, pos); | ||
pos += (0, util_js_1.whitespaces)(ctx.source, pos); | ||
} | ||
checkLocalVarReferences(declarations, errors); | ||
checkLocalVarReferences(ctx, declarations); | ||
return { declarations, end: pos }; | ||
} | ||
exports.parseDeclarations = parseDeclarations; | ||
function parseDeclaration(src, start, errors) { | ||
// declaration = let s variable [s] "=" [s] expression | ||
// let = %x6C.65.74 ; "let" | ||
function parseDeclaration(ctx, start) { | ||
let pos = start + 3; // 'let' | ||
const ws = (0, util_js_1.whitespaces)(src, pos); | ||
const ws = (0, util_js_1.whitespaces)(ctx.source, pos); | ||
pos += ws; | ||
if (ws === 0) | ||
errors.push(new errors_js_1.MissingCharError(pos, ' ')); | ||
ctx.onError('missing-char', pos, ' '); | ||
let target; | ||
if (src[pos] === '$') { | ||
target = (0, values_js_1.parseVariable)(src, pos, errors); | ||
if (ctx.source[pos] === '$') { | ||
target = (0, values_js_1.parseVariable)(ctx, pos); | ||
pos = target.end; | ||
@@ -35,4 +35,4 @@ } | ||
const junkStart = pos; | ||
const junkEndOffset = src.substring(pos).search(/[\t\n\r ={}]/); | ||
pos = junkEndOffset === -1 ? src.length : pos + junkEndOffset; | ||
const junkEndOffset = ctx.source.substring(pos).search(/[\t\n\r ={}]/); | ||
pos = junkEndOffset === -1 ? ctx.source.length : pos + junkEndOffset; | ||
target = { | ||
@@ -42,15 +42,15 @@ type: 'junk', | ||
end: pos, | ||
source: src.substring(junkStart, pos) | ||
source: ctx.source.substring(junkStart, pos) | ||
}; | ||
errors.push(new errors_js_1.MissingCharError(junkStart, '$')); | ||
ctx.onError('missing-char', junkStart, '$'); | ||
} | ||
pos += (0, util_js_1.whitespaces)(src, pos); | ||
if (src[pos] === '=') | ||
pos += (0, util_js_1.whitespaces)(ctx.source, pos); | ||
if (ctx.source[pos] === '=') | ||
pos += 1; | ||
else | ||
errors.push(new errors_js_1.MissingCharError(pos, '=')); | ||
ctx.onError('missing-char', pos, '='); | ||
let value; | ||
pos += (0, util_js_1.whitespaces)(src, pos); | ||
if (src[pos] === '{') { | ||
value = (0, placeholder_js_1.parsePlaceholder)(src, pos, errors); | ||
pos += (0, util_js_1.whitespaces)(ctx.source, pos); | ||
if (ctx.source[pos] === '{') { | ||
value = (0, expression_js_1.parseExpression)(ctx, pos); | ||
pos = value.end; | ||
@@ -60,6 +60,6 @@ } | ||
const junkStart = pos; | ||
const junkEndOffset = src | ||
const junkEndOffset = ctx.source | ||
.substring(pos) | ||
.search(/\blet|\bmatch|\bwhen|[${}]/); | ||
pos = junkEndOffset === -1 ? src.length : pos + junkEndOffset; | ||
pos = junkEndOffset === -1 ? ctx.source.length : pos + junkEndOffset; | ||
value = { | ||
@@ -69,5 +69,5 @@ type: 'junk', | ||
end: pos, | ||
source: src.substring(junkStart, pos) | ||
source: ctx.source.substring(junkStart, pos) | ||
}; | ||
errors.push(new errors_js_1.MissingCharError(junkStart, '{')); | ||
ctx.onError('missing-char', junkStart, '{'); | ||
} | ||
@@ -77,6 +77,6 @@ return { start, end: pos, target, value }; | ||
/** Local variable declarations can't refer to later ones */ | ||
function checkLocalVarReferences(declarations, errors) { | ||
function checkLocalVarReferences(ctx, declarations) { | ||
const check = (name, ref) => { | ||
if (ref.name === name) { | ||
errors.push(new errors_js_1.MessageSyntaxError('bad-local-var', ref.start, ref.end)); | ||
ctx.onError('bad-local-var', ref.start, ref.end); | ||
} | ||
@@ -90,6 +90,6 @@ }; | ||
const ph = declarations[j].value; | ||
if (ph.type === 'placeholder') { | ||
if (ph.type === 'expression') { | ||
const exp = ph.body; | ||
switch (exp.type) { | ||
case 'expression': | ||
case 'function': | ||
if (exp.operand?.type === 'variable') | ||
@@ -96,0 +96,0 @@ check(name, exp.operand); |
@@ -0,2 +1,13 @@ | ||
import { MessageSyntaxError } from '../errors.js'; | ||
import type { MessageParsed } from './data-model.js'; | ||
export declare class ParseContext { | ||
readonly errors: MessageSyntaxError[]; | ||
readonly resource: boolean; | ||
readonly source: string; | ||
constructor(source: string, opt?: { | ||
resource?: boolean; | ||
}); | ||
onError(type: Exclude<typeof MessageSyntaxError.prototype.type, 'missing-char'>, start: number, end: number): void; | ||
onError(type: 'missing-char', start: number, char: string): void; | ||
} | ||
/** | ||
@@ -8,2 +19,4 @@ * Parse the string syntax representation of a message into | ||
*/ | ||
export declare function parseMessage(src: string): MessageParsed; | ||
export declare function parseMessage(source: string, opt?: { | ||
resource?: boolean; | ||
}): MessageParsed; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseMessage = void 0; | ||
exports.parseMessage = exports.ParseContext = void 0; | ||
const errors_js_1 = require("../errors.js"); | ||
const declarations_js_1 = require("./declarations.js"); | ||
const names_js_1 = require("./names.js"); | ||
const placeholder_js_1 = require("./placeholder.js"); | ||
const expression_js_1 = require("./expression.js"); | ||
const util_js_1 = require("./util.js"); | ||
const values_js_1 = require("./values.js"); | ||
// Message ::= Declaration* ( Pattern | Selector Variant+ ) | ||
// Selector ::= 'match' ( '{' Expression '}' )+ | ||
class ParseContext { | ||
constructor(source, opt) { | ||
this.errors = []; | ||
this.resource = opt?.resource ?? false; | ||
this.source = source; | ||
} | ||
onError(type, start, end) { | ||
let err; | ||
switch (type) { | ||
case 'key-mismatch': | ||
case 'missing-fallback': | ||
err = new errors_js_1.MessageDataModelError(type, start, Number(end)); | ||
break; | ||
case 'missing-char': | ||
err = new errors_js_1.MissingCharError(start, String(end)); | ||
break; | ||
default: | ||
err = new errors_js_1.MessageSyntaxError(type, start, Number(end)); | ||
} | ||
this.errors.push(err); | ||
} | ||
} | ||
exports.ParseContext = ParseContext; | ||
// message = [s] *(declaration [s]) body [s] | ||
// body = pattern / (selectors 1*([s] variant)) | ||
// selectors = match 1*([s] expression) | ||
/** | ||
@@ -18,34 +41,34 @@ * Parse the string syntax representation of a message into | ||
*/ | ||
function parseMessage(src) { | ||
const errors = []; | ||
const { declarations, end: pos } = (0, declarations_js_1.parseDeclarations)(src, errors); | ||
if (src.startsWith('match', pos)) { | ||
return parseSelectMessage(src, pos, declarations, errors); | ||
function parseMessage(source, opt) { | ||
const ctx = new ParseContext(source, opt); | ||
const { declarations, end: pos } = (0, declarations_js_1.parseDeclarations)(ctx); | ||
if (source.startsWith('match', pos)) { | ||
return parseSelectMessage(ctx, pos, declarations); | ||
} | ||
else if (src[pos] === '{') { | ||
return parsePatternMessage(src, pos, declarations, errors); | ||
else if (source[pos] === '{') { | ||
return parsePatternMessage(ctx, pos, declarations); | ||
} | ||
else { | ||
errors.push(new errors_js_1.MessageSyntaxError('parse-error', pos, src.length)); | ||
return { type: 'junk', declarations, errors, source: src }; | ||
ctx.onError('parse-error', pos, source.length); | ||
return { type: 'junk', declarations, errors: ctx.errors, source }; | ||
} | ||
} | ||
exports.parseMessage = parseMessage; | ||
function parsePatternMessage(src, start, declarations, errors) { | ||
const pattern = parsePattern(src, start, errors); | ||
function parsePatternMessage(ctx, start, declarations) { | ||
const pattern = parsePattern(ctx, start); | ||
let pos = pattern.end; | ||
pos += (0, util_js_1.whitespaces)(src, pos); | ||
if (pos < src.length) { | ||
errors.push(new errors_js_1.MessageSyntaxError('extra-content', pos, src.length)); | ||
pos += (0, util_js_1.whitespaces)(ctx.source, pos); | ||
if (pos < ctx.source.length) { | ||
ctx.onError('extra-content', pos, ctx.source.length); | ||
} | ||
return { type: 'message', declarations, pattern, errors }; | ||
return { type: 'message', declarations, pattern, errors: ctx.errors }; | ||
} | ||
function parseSelectMessage(src, start, declarations, errors) { | ||
function parseSelectMessage(ctx, start, declarations) { | ||
let pos = start + 5; // 'match' | ||
pos += (0, util_js_1.whitespaces)(src, pos); | ||
pos += (0, util_js_1.whitespaces)(ctx.source, pos); | ||
const selectors = []; | ||
while (src[pos] === '{') { | ||
const ph = (0, placeholder_js_1.parsePlaceholder)(src, pos, errors); | ||
while (ctx.source[pos] === '{') { | ||
const ph = (0, expression_js_1.parseExpression)(ctx, pos); | ||
switch (ph.body.type) { | ||
case 'expression': | ||
case 'function': | ||
case 'literal': | ||
@@ -56,3 +79,3 @@ case 'variable': | ||
const { start, end } = ph.body; | ||
errors.push(new errors_js_1.MessageSyntaxError('bad-selector', start, end)); | ||
ctx.onError('bad-selector', start, end); | ||
} | ||
@@ -62,44 +85,42 @@ } | ||
pos = ph.end; | ||
pos += (0, util_js_1.whitespaces)(src, pos); | ||
pos += (0, util_js_1.whitespaces)(ctx.source, pos); | ||
} | ||
if (selectors.length === 0) { | ||
errors.push(new errors_js_1.MessageSyntaxError('empty-token', pos, pos + 1)); | ||
ctx.onError('empty-token', pos, pos + 1); | ||
} | ||
const variants = []; | ||
pos += (0, util_js_1.whitespaces)(src, pos); | ||
while (src.startsWith('when', pos)) { | ||
const variant = parseVariant(src, pos, selectors.length, errors); | ||
pos += (0, util_js_1.whitespaces)(ctx.source, pos); | ||
while (ctx.source.startsWith('when', pos)) { | ||
const variant = parseVariant(ctx, pos, selectors.length); | ||
variants.push(variant); | ||
pos = variant.end; | ||
pos += (0, util_js_1.whitespaces)(src, pos); | ||
pos += (0, util_js_1.whitespaces)(ctx.source, pos); | ||
} | ||
if (pos < src.length) { | ||
errors.push(new errors_js_1.MessageSyntaxError('extra-content', pos, src.length)); | ||
if (pos < ctx.source.length) { | ||
ctx.onError('extra-content', pos, ctx.source.length); | ||
} | ||
return { type: 'select', declarations, selectors, variants, errors }; | ||
return { | ||
type: 'select', | ||
declarations, | ||
selectors, | ||
variants, | ||
errors: ctx.errors | ||
}; | ||
} | ||
// Variant ::= 'when' ( WhiteSpace VariantKey )+ Pattern | ||
// VariantKey ::= Literal | Nmtoken | '*' | ||
function parseVariant(src, start, selCount, errors) { | ||
// variant = when 1*(s key) [s] pattern | ||
// key = literal / "*" | ||
function parseVariant(ctx, start, selCount) { | ||
let pos = start + 4; // 'when' | ||
const keys = []; | ||
while (pos < src.length) { | ||
const ws = (0, util_js_1.whitespaces)(src, pos); | ||
while (pos < ctx.source.length) { | ||
const ws = (0, util_js_1.whitespaces)(ctx.source, pos); | ||
pos += ws; | ||
const ch = src[pos]; | ||
const ch = ctx.source[pos]; | ||
if (ch === '{') | ||
break; | ||
if (ws === 0) | ||
errors.push(new errors_js_1.MissingCharError(pos, ' ')); | ||
let key; | ||
switch (ch) { | ||
case '*': | ||
key = { type: '*', start: pos, end: pos + 1 }; | ||
break; | ||
case '|': | ||
key = (0, values_js_1.parseLiteral)(src, pos, errors); | ||
break; | ||
default: | ||
key = (0, names_js_1.parseNmtoken)(src, pos, errors); | ||
} | ||
ctx.onError('missing-char', pos, ' '); | ||
const key = ch === '*' | ||
? ({ type: '*', start: pos, end: pos + 1 }) | ||
: (0, values_js_1.parseLiteral)(ctx, pos, true); | ||
if (key.end === pos) | ||
@@ -112,11 +133,11 @@ break; // error; reported in pattern.errors | ||
const end = keys.length === 0 ? pos : keys[keys.length - 1].end; | ||
errors.push(new errors_js_1.MessageDataModelError('key-mismatch', start, end)); | ||
ctx.onError('key-mismatch', start, end); | ||
} | ||
const value = parsePattern(src, pos, errors); | ||
const value = parsePattern(ctx, pos); | ||
return { start, end: value.end, keys, value }; | ||
} | ||
// Pattern ::= '{' (Text | Placeholder)* '}' /* ws: explicit */ | ||
function parsePattern(src, start, errors) { | ||
if (src[start] !== '{') { | ||
errors.push(new errors_js_1.MissingCharError(start, '{')); | ||
// pattern = "{" *(text / expression) "}" | ||
function parsePattern(ctx, start) { | ||
if (ctx.source[start] !== '{') { | ||
ctx.onError('missing-char', start, '{'); | ||
return { start, end: start, body: [] }; | ||
@@ -126,6 +147,6 @@ } | ||
const body = []; | ||
loop: while (pos < src.length) { | ||
switch (src[pos]) { | ||
loop: while (pos < ctx.source.length) { | ||
switch (ctx.source[pos]) { | ||
case '{': { | ||
const ph = (0, placeholder_js_1.parsePlaceholder)(src, pos, errors); | ||
const ph = (0, expression_js_1.parseExpression)(ctx, pos); | ||
body.push(ph); | ||
@@ -138,3 +159,3 @@ pos = ph.end; | ||
default: { | ||
const tx = (0, values_js_1.parseText)(src, pos, errors); | ||
const tx = (0, values_js_1.parseText)(ctx, pos); | ||
body.push(tx); | ||
@@ -145,7 +166,7 @@ pos = tx.end; | ||
} | ||
if (src[pos] === '}') | ||
if (ctx.source[pos] === '}') | ||
pos += 1; | ||
else | ||
errors.push(new errors_js_1.MissingCharError(pos, '}')); | ||
ctx.onError('missing-char', pos, '}'); | ||
return { start, end: pos, body }; | ||
} |
@@ -1,5 +0,4 @@ | ||
import { MessageSyntaxError } from '../errors.js'; | ||
import type { NmtokenParsed } from './data-model.js'; | ||
export declare function isValidNmtoken(str: string): boolean; | ||
import type { ParseContext } from './message.js'; | ||
export declare function isValidUnquotedLiteral(str: string): boolean; | ||
export declare function parseNameValue(src: string, start: number): string; | ||
export declare function parseNmtoken(src: string, start: number, errors: MessageSyntaxError[]): NmtokenParsed; | ||
export declare function parseUnquotedLiteralValue(ctx: ParseContext, start: number): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseNmtoken = exports.parseNameValue = exports.isValidNmtoken = void 0; | ||
const errors_js_1 = require("../errors.js"); | ||
// NameStart ::= [a-zA-Z] | "_" | ||
// | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | ||
// | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | ||
// | [#x2070-#x218F] | ||
// | [#x2C00-#x2FEF] | ||
// | [#x3001-#xD7FF] | ||
// | [#xF900-#xFDCF] | ||
// | [#xFDF0-#xFFFD] | ||
// | [#x10000-#xEFFFF] | ||
exports.parseUnquotedLiteralValue = exports.parseNameValue = exports.isValidUnquotedLiteral = void 0; | ||
// name-start = ALPHA / "_" | ||
// / %xC0-D6 / %xD8-F6 / %xF8-2FF | ||
// / %x370-37D / %x37F-1FFF / %x200C-200D | ||
// / %x2070-218F / %x2C00-2FEF / %x3001-D7FF | ||
// / %xF900-FDCF / %xFDF0-FFFD / %x10000-EFFFF | ||
const isNameStartCode = (cc) => (cc >= 0x41 && cc <= 0x5a) || // A-Z | ||
@@ -29,6 +24,5 @@ cc === 0x5f || // _ | ||
(cc >= 0x10000 && cc <= 0xeffff); | ||
// NameChar ::= NameStart | [0-9] | "-" | "." | #xB7 | ||
// | [#x0300-#x036F] | [#x203F-#x2040] | ||
const isNameCharCode = (cc) => isNameStartCode(cc) || | ||
cc === 0x2d || // - | ||
// unquoted-start = name-start / DIGIT / "." | ||
// / %xB7 / %x300-36F / %x203F-2040 | ||
const isUnquotedStartCharCode = (cc) => isNameStartCode(cc) || | ||
cc === 0x2e || // . | ||
@@ -40,4 +34,9 @@ (cc >= 0x30 && cc <= 0x39) || // 0-9 | ||
cc === 0x2040; // ⁀ | ||
function isValidNmtoken(str) { | ||
for (let i = 0; i < str.length; ++i) { | ||
// name-char = name-start / DIGIT / "-" / "." / ":" | ||
// / %xB7 / %x300-36F / %x203F-2040 | ||
const isNameCharCode = (cc) => isUnquotedStartCharCode(cc) || cc === 0x2d || cc === 0x3a; // - : | ||
function isValidUnquotedLiteral(str) { | ||
if (!isUnquotedStartCharCode(str.charCodeAt(0))) | ||
return false; | ||
for (let i = 1; i < str.length; ++i) { | ||
const cc = str.charCodeAt(i); | ||
@@ -49,4 +48,4 @@ if (!isNameCharCode(cc)) | ||
} | ||
exports.isValidNmtoken = isValidNmtoken; | ||
// Name ::= NameStart NameChar* /* ws: explicit */ | ||
exports.isValidUnquotedLiteral = isValidUnquotedLiteral; | ||
// name = name-start *name-char | ||
function parseNameValue(src, start) { | ||
@@ -61,13 +60,12 @@ if (!isNameStartCode(src.charCodeAt(start))) | ||
exports.parseNameValue = parseNameValue; | ||
// Nmtoken ::= NameChar+ /* ws: explicit */ | ||
function parseNmtoken(src, start, errors) { | ||
// unquoted = unquoted-start *name-char | ||
function parseUnquotedLiteralValue(ctx, start) { | ||
let pos = start; | ||
while (isNameCharCode(src.charCodeAt(pos))) | ||
if (isUnquotedStartCharCode(ctx.source.charCodeAt(pos))) { | ||
pos += 1; | ||
const value = src.substring(start, pos); | ||
if (!value) { | ||
errors.push(new errors_js_1.MessageSyntaxError('empty-token', start, start + 1)); | ||
while (isNameCharCode(ctx.source.charCodeAt(pos))) | ||
pos += 1; | ||
} | ||
return { type: 'nmtoken', start, end: pos, value }; | ||
return ctx.source.substring(start, pos); | ||
} | ||
exports.parseNmtoken = parseNmtoken; | ||
exports.parseUnquotedLiteralValue = parseUnquotedLiteralValue; |
@@ -1,5 +0,7 @@ | ||
import { MessageSyntaxError } from '../errors.js'; | ||
import type { LiteralParsed, TextParsed, VariableRefParsed } from './data-model.js'; | ||
export declare function parseText(src: string, start: number, errors: MessageSyntaxError[]): TextParsed; | ||
export declare function parseLiteral(src: string, start: number, errors: MessageSyntaxError[]): LiteralParsed; | ||
export declare function parseVariable(src: string, start: number, errors: MessageSyntaxError[]): VariableRefParsed; | ||
import type { ParseContext } from './message.js'; | ||
export declare function parseText(ctx: ParseContext, start: number): TextParsed; | ||
export declare function parseLiteral(ctx: ParseContext, start: number, required: true): LiteralParsed; | ||
export declare function parseLiteral(ctx: ParseContext, start: number, required: boolean): LiteralParsed | undefined; | ||
export declare function parseQuotedLiteral(ctx: ParseContext, start: number): LiteralParsed; | ||
export declare function parseVariable(ctx: ParseContext, start: number): VariableRefParsed; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseVariable = exports.parseLiteral = exports.parseText = void 0; | ||
const errors_js_1 = require("../errors.js"); | ||
exports.parseVariable = exports.parseQuotedLiteral = exports.parseLiteral = exports.parseText = void 0; | ||
const names_js_1 = require("./names.js"); | ||
@@ -11,18 +10,15 @@ // Text ::= (TextChar | TextEscape)+ | ||
// TextEscape ::= Esc Esc | Esc '{' | Esc '}' | ||
function parseText(src, start, errors) { | ||
function parseText(ctx, start) { | ||
let value = ''; | ||
let pos = start; | ||
let i = start; | ||
loop: for (; i < src.length; ++i) { | ||
switch (src[i]) { | ||
loop: for (; i < ctx.source.length; ++i) { | ||
switch (ctx.source[i]) { | ||
case '\\': { | ||
const esc = src[i + 1]; | ||
if (esc !== '\\' && esc !== '{' && esc !== '}') { | ||
errors.push(new errors_js_1.MessageSyntaxError('bad-escape', i, i + 2)); | ||
const esc = parseEscape(ctx, 'text', i); | ||
if (esc) { | ||
value += ctx.source.substring(pos, i) + esc.value; | ||
i += esc.length; | ||
pos = i + 1; | ||
} | ||
else { | ||
value += src.slice(pos, i); | ||
i += 1; | ||
pos = i; | ||
} | ||
break; | ||
@@ -33,48 +29,148 @@ } | ||
break loop; | ||
case '\n': | ||
if (ctx.resource) { | ||
const nl = i; | ||
let next = ctx.source[i + 1]; | ||
while (next === ' ' || next === '\t') { | ||
i += 1; | ||
next = ctx.source[i + 1]; | ||
} | ||
if (i > nl) { | ||
value += ctx.source.substring(pos, nl + 1); | ||
pos = i + 1; | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
value += src.slice(pos, i); | ||
value += ctx.source.substring(pos, i); | ||
return { type: 'text', start, end: i, value }; | ||
} | ||
exports.parseText = parseText; | ||
// Literal ::= '(' (LiteralChar | LiteralEscape)* ')' /* ws: explicit */ | ||
// Esc ::= '\' | ||
// LiteralChar ::= AnyChar - ('|' | Esc) | ||
// LiteralEscape ::= Esc Esc | Esc '|' | ||
function parseLiteral(src, start, errors) { | ||
function parseLiteral(ctx, start, required) { | ||
if (ctx.source[start] === '|') | ||
return parseQuotedLiteral(ctx, start); | ||
const value = (0, names_js_1.parseUnquotedLiteralValue)(ctx, start); | ||
if (!value) { | ||
if (required) | ||
ctx.onError('empty-token', start, start); | ||
else | ||
return undefined; | ||
} | ||
const end = start + value.length; | ||
return { type: 'literal', quoted: false, start, end, value }; | ||
} | ||
exports.parseLiteral = parseLiteral; | ||
// quoted = "|" *(quoted-char / quoted-escape) "|" | ||
// quoted-char = %x0-5B ; omit \ | ||
// / %x5D-7B ; omit | | ||
// / %x7D-D7FF ; omit surrogates | ||
// / %xE000-10FFFF | ||
// quoted-escape = backslash ( backslash / "|" ) | ||
// backslash = %x5C ; U+005C REVERSE SOLIDUS "\" | ||
function parseQuotedLiteral(ctx, start) { | ||
let value = ''; | ||
let pos = start + 1; | ||
for (let i = pos; i < src.length; ++i) { | ||
switch (src[i]) { | ||
for (let i = pos; i < ctx.source.length; ++i) { | ||
switch (ctx.source[i]) { | ||
case '\\': { | ||
const esc = src[i + 1]; | ||
if (esc !== '\\' && esc !== '|') { | ||
errors.push(new errors_js_1.MessageSyntaxError('bad-escape', i, i + 2)); | ||
const esc = parseEscape(ctx, 'literal', i); | ||
if (esc) { | ||
value += ctx.source.substring(pos, i) + esc.value; | ||
i += esc.length; | ||
pos = i + 1; | ||
} | ||
else { | ||
value += src.substring(pos, i); | ||
i += 1; | ||
pos = i; | ||
} | ||
break; | ||
} | ||
case '|': | ||
value += src.substring(pos, i); | ||
return { type: 'literal', start, end: i + 1, value }; | ||
value += ctx.source.substring(pos, i); | ||
return { type: 'literal', quoted: true, start, end: i + 1, value }; | ||
case '\n': | ||
if (ctx.resource) { | ||
const nl = i; | ||
let next = ctx.source[i + 1]; | ||
while (next === ' ' || next === '\t') { | ||
i += 1; | ||
next = ctx.source[i + 1]; | ||
} | ||
if (i > nl) { | ||
value += ctx.source.substring(pos, nl + 1); | ||
pos = i + 1; | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
value += src.substring(pos); | ||
errors.push(new errors_js_1.MissingCharError(src.length, '|')); | ||
return { type: 'literal', start, end: src.length, value }; | ||
value += ctx.source.substring(pos); | ||
ctx.onError('missing-char', ctx.source.length, '|'); | ||
return { | ||
type: 'literal', | ||
quoted: true, | ||
start, | ||
end: ctx.source.length, | ||
value | ||
}; | ||
} | ||
exports.parseLiteral = parseLiteral; | ||
exports.parseQuotedLiteral = parseQuotedLiteral; | ||
// Variable ::= '$' Name /* ws: explicit */ | ||
function parseVariable(src, start, errors) { | ||
function parseVariable(ctx, start) { | ||
const pos = start + 1; | ||
const name = (0, names_js_1.parseNameValue)(src, pos); | ||
const name = (0, names_js_1.parseNameValue)(ctx.source, pos); | ||
const end = pos + name.length; | ||
if (!name) | ||
errors.push(new errors_js_1.MessageSyntaxError('empty-token', pos, pos + 1)); | ||
ctx.onError('empty-token', pos, pos + 1); | ||
return { type: 'variable', start, end, name }; | ||
} | ||
exports.parseVariable = parseVariable; | ||
function parseEscape(ctx, scope, start) { | ||
const raw = ctx.source[start + 1]; | ||
switch (raw) { | ||
case '\\': | ||
return { value: raw, length: 1 }; | ||
case '{': | ||
case '}': | ||
if (scope === 'text') | ||
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 | ||
}; | ||
} | ||
} | ||
} | ||
} | ||
ctx.onError('bad-escape', start, start + 2); | ||
return null; | ||
} |
import type { Context } from '../format-context'; | ||
import type { MessageValue } from '../message-value'; | ||
import { Expression } from './expression'; | ||
import { FunctionRef } from './function-ref'; | ||
import { Junk } from './junk'; | ||
import { Literal, Text } from './literal'; | ||
import { MarkupEnd, MarkupStart } from './markup'; | ||
import { Reserved } from './reserved'; | ||
import { VariableRef } from './variable-ref'; | ||
export { isExpression, Expression, Option } from './expression'; | ||
export { isFunctionRef, FunctionRef, Option } from './function-ref'; | ||
export { isJunk, Junk } from './junk'; | ||
export { isLiteral, isText, Literal, Text } from './literal'; | ||
export { isMarkupEnd, isMarkupStart, MarkupEnd, MarkupStart } from './markup'; | ||
export { isReserved, Reserved } from './reserved'; | ||
export { isVariableRef, VariableRef } from './variable-ref'; | ||
@@ -18,12 +18,12 @@ /** | ||
*/ | ||
export interface Placeholder { | ||
type: 'placeholder'; | ||
body: Literal | VariableRef | Expression | MarkupStart | MarkupEnd | Junk; | ||
export interface Expression { | ||
type: 'expression'; | ||
body: Literal | VariableRef | FunctionRef | Reserved | Junk; | ||
} | ||
/** | ||
* Type guard for {@link Placeholder} pattern elements | ||
* Type guard for {@link Expression} pattern elements | ||
* | ||
* @beta | ||
*/ | ||
export declare const isPlaceholder: (part: any) => part is Placeholder; | ||
export declare const isExpression: (part: any) => part is Expression; | ||
/** | ||
@@ -36,8 +36,8 @@ * The contents of a message are a sequence of pattern elements, which may be | ||
* @remarks | ||
* Depending on the syntax, pattern elements may be wrapped within a Placeholder. | ||
* Depending on the syntax, pattern elements may be wrapped within an Expression. | ||
* | ||
* @beta | ||
*/ | ||
export type PatternElement = Expression | Junk | Literal | MarkupEnd | MarkupStart | Placeholder | Text | VariableRef; | ||
export type PatternElement = Expression | FunctionRef | Junk | Literal | Reserved | Text | VariableRef; | ||
/** @internal */ | ||
export declare function resolvePatternElement(ctx: Context, elem: PatternElement): MessageValue; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.resolvePatternElement = exports.isPlaceholder = exports.isVariableRef = exports.isMarkupStart = exports.isMarkupEnd = exports.isText = exports.isLiteral = exports.isJunk = exports.isExpression = void 0; | ||
const expression_1 = require("./expression"); | ||
exports.resolvePatternElement = exports.isExpression = exports.isVariableRef = exports.isReserved = exports.isText = exports.isLiteral = exports.isJunk = exports.isFunctionRef = void 0; | ||
const function_ref_1 = require("./function-ref"); | ||
const junk_1 = require("./junk"); | ||
const literal_1 = require("./literal"); | ||
const markup_1 = require("./markup"); | ||
const reserved_1 = require("./reserved"); | ||
const variable_ref_1 = require("./variable-ref"); | ||
var expression_2 = require("./expression"); | ||
Object.defineProperty(exports, "isExpression", { enumerable: true, get: function () { return expression_2.isExpression; } }); | ||
var function_ref_2 = require("./function-ref"); | ||
Object.defineProperty(exports, "isFunctionRef", { enumerable: true, get: function () { return function_ref_2.isFunctionRef; } }); | ||
var junk_2 = require("./junk"); | ||
@@ -16,9 +16,8 @@ Object.defineProperty(exports, "isJunk", { enumerable: true, get: function () { return junk_2.isJunk; } }); | ||
Object.defineProperty(exports, "isText", { enumerable: true, get: function () { return literal_2.isText; } }); | ||
var markup_2 = require("./markup"); | ||
Object.defineProperty(exports, "isMarkupEnd", { enumerable: true, get: function () { return markup_2.isMarkupEnd; } }); | ||
Object.defineProperty(exports, "isMarkupStart", { enumerable: true, get: function () { return markup_2.isMarkupStart; } }); | ||
var reserved_2 = require("./reserved"); | ||
Object.defineProperty(exports, "isReserved", { enumerable: true, get: function () { return reserved_2.isReserved; } }); | ||
var variable_ref_2 = require("./variable-ref"); | ||
Object.defineProperty(exports, "isVariableRef", { enumerable: true, get: function () { return variable_ref_2.isVariableRef; } }); | ||
/** | ||
* Type guard for {@link Placeholder} pattern elements | ||
* Type guard for {@link Expression} pattern elements | ||
* | ||
@@ -28,4 +27,4 @@ * @beta | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const isPlaceholder = (part) => !!part && typeof part === 'object' && part.type === 'placeholder'; | ||
exports.isPlaceholder = isPlaceholder; | ||
const isExpression = (part) => !!part && typeof part === 'object' && part.type === 'expression'; | ||
exports.isExpression = isExpression; | ||
/** @internal */ | ||
@@ -35,15 +34,12 @@ function resolvePatternElement(ctx, elem) { | ||
case 'literal': | ||
case 'nmtoken': | ||
case 'text': | ||
return (0, literal_1.resolveLiteral)(elem); | ||
case 'placeholder': | ||
case 'expression': | ||
return resolvePatternElement(ctx, elem.body); | ||
case 'variable': | ||
return (0, variable_ref_1.resolveVariableRef)(ctx, elem); | ||
case 'expression': | ||
return (0, expression_1.resolveExpression)(ctx, elem); | ||
case 'markup-start': | ||
return (0, markup_1.resolveMarkupStart)(ctx, elem); | ||
case 'markup-end': | ||
return (0, markup_1.resolveMarkupEnd)(ctx, elem); | ||
case 'function': | ||
return (0, function_ref_1.resolveFunctionRef)(ctx, elem); | ||
case 'reserved': | ||
return (0, reserved_1.resolveReserved)(ctx, elem); | ||
case 'junk': | ||
@@ -50,0 +46,0 @@ return (0, junk_1.resolveJunk)(ctx, elem); |
@@ -13,3 +13,4 @@ import { MessageLiteral } from '../message-value'; | ||
export interface Literal { | ||
type: 'literal' | 'nmtoken'; | ||
type: 'literal'; | ||
quoted: boolean; | ||
value: string; | ||
@@ -16,0 +17,0 @@ } |
@@ -11,5 +11,3 @@ "use strict"; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const isLiteral = (part) => !!part && | ||
typeof part === 'object' && | ||
(part.type === 'literal' || part.type === 'nmtoken'); | ||
const isLiteral = (part) => !!part && typeof part === 'object' && part.type === 'literal'; | ||
exports.isLiteral = isLiteral; | ||
@@ -16,0 +14,0 @@ /** |
@@ -25,3 +25,3 @@ import { MessageValue } from '../message-value'; | ||
/** | ||
* The runtime function registry available when resolving {@link Expression} elements. | ||
* The runtime function registry available when resolving {@link FunctionRef} elements. | ||
* | ||
@@ -28,0 +28,0 @@ * @beta |
@@ -8,2 +8,3 @@ "use strict"; | ||
const pattern_1 = require("../pattern"); | ||
const function_ref_1 = require("../pattern/function-ref"); | ||
/** | ||
@@ -26,3 +27,3 @@ * Stringify a message using its syntax representation. | ||
for (const sel of msg.selectors) | ||
res += ' ' + stringifyPlaceholder(sel); | ||
res += ' ' + stringifyExpression(sel); | ||
for (const { keys, value } of msg.variants) { | ||
@@ -46,8 +47,8 @@ res += '\nwhen '; | ||
: stringifyJunk(target); | ||
const valueStr = (0, pattern_1.isPlaceholder)(value) | ||
? stringifyPlaceholder(value) | ||
const valueStr = (0, pattern_1.isExpression)(value) | ||
? stringifyExpression(value) | ||
: stringifyJunk(value); | ||
return `let ${targetStr} = ${valueStr}\n`; | ||
} | ||
function stringifyExpression({ name, operand, options }) { | ||
function stringifyFunctionRef({ kind, name, operand, options }) { | ||
let res; | ||
@@ -63,3 +64,3 @@ if ((0, pattern_1.isLiteral)(operand)) { | ||
} | ||
res += `:${name}`; | ||
res += (0, function_ref_1.functionRefSourceName)(kind, name); | ||
if (options) | ||
@@ -73,19 +74,8 @@ for (const opt of options) | ||
} | ||
function stringifyLiteral(lit) { | ||
if (lit.type === 'nmtoken' && (0, names_1.isValidNmtoken)(lit.value)) { | ||
return lit.value; | ||
} | ||
const esc = lit.value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|'); | ||
function stringifyLiteral({ quoted, value }) { | ||
if (!quoted && (0, names_1.isValidUnquotedLiteral)(value)) | ||
return value; | ||
const esc = value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|'); | ||
return `|${esc}|`; | ||
} | ||
function stringifyMarkupEnd(end) { | ||
return `-${end.name}`; | ||
} | ||
function stringifyMarkupStart({ name, options }) { | ||
let res = `+${name}`; | ||
if (options) | ||
for (const opt of options) | ||
res += ' ' + stringifyOption(opt); | ||
return res; | ||
} | ||
function stringifyOption(opt) { | ||
@@ -100,12 +90,12 @@ const valueStr = (0, pattern_1.isVariableRef)(opt.value) | ||
for (const el of body) { | ||
res += (0, pattern_1.isText)(el) ? el.value : stringifyPlaceholder(el); | ||
res += (0, pattern_1.isText)(el) ? el.value : stringifyExpression(el); | ||
} | ||
return `{${res}}`; | ||
} | ||
function stringifyPlaceholder(ph) { | ||
const body = (0, pattern_1.isPlaceholder)(ph) ? ph.body : ph; | ||
function stringifyExpression(ph) { | ||
const body = (0, pattern_1.isExpression)(ph) ? ph.body : ph; | ||
let res; | ||
switch (body.type) { | ||
case 'expression': | ||
res = stringifyExpression(body); | ||
case 'function': | ||
res = stringifyFunctionRef(body); | ||
break; | ||
@@ -118,8 +108,2 @@ case 'junk': | ||
break; | ||
case 'markup-end': | ||
res = stringifyMarkupEnd(body); | ||
break; | ||
case 'markup-start': | ||
res = stringifyMarkupStart(body); | ||
break; | ||
case 'variable': | ||
@@ -129,3 +113,3 @@ res = stringifyVariableRef(body); | ||
default: | ||
res = ''; // bad placeholder | ||
res = ''; // bad expression | ||
} | ||
@@ -132,0 +116,0 @@ return `{${res}}`; |
{ | ||
"name": "messageformat", | ||
"version": "4.0.0-3.cf", | ||
"version": "4.0.0-4", | ||
"description": "Intl.MessageFormat / Unicode MessageFormat 2 parser, runtime and polyfill", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
116525
70
2765