Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fluent-bundle/src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export type Variant = {
export type NamedArgument = {
type: "narg";
name: string;
value: Literal;
value: Literal | VariableReference;
};

export type Literal = StringLiteral | NumberLiteral;
Expand Down
2 changes: 1 addition & 1 deletion fluent-bundle/src/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export class FluentBundle {
return value.toString(scope);
} catch (err) {
if (scope.errors && err instanceof Error) {
scope.errors.push(err);
scope.errors.unshift(err);
return new FluentNone().toString(scope);
}
throw err;
Expand Down
34 changes: 20 additions & 14 deletions fluent-bundle/src/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ function resolveVariableReference(
switch (typeof arg) {
case "string":
return arg;
case "boolean":
return String(arg);
case "number":
return new FluentNumber(arg);
case "object":
Expand All @@ -195,8 +197,16 @@ function resolveVariableReference(
/** Resolve a reference to another message. */
function resolveMessageReference(
scope: Scope,
{ name, attr }: MessageReference
ref: MessageReference
): FluentValue {
const { name, attr } = ref;

if (scope.dirty.has(ref)) {
scope.reportError(new RangeError("Cyclic reference"));
return new FluentNone(name);
}
scope.dirty.add(ref);

const message = scope.bundle._messages.get(name);
if (!message) {
scope.reportError(new ReferenceError(`Unknown message: ${name}`));
Expand All @@ -221,11 +231,16 @@ function resolveMessageReference(
}

/** Resolve a call to a Term with key-value arguments. */
function resolveTermReference(
scope: Scope,
{ name, attr, args }: TermReference
): FluentValue {
function resolveTermReference(scope: Scope, ref: TermReference): FluentValue {
const { name, attr, args } = ref;
const id = `-${name}`;

if (scope.dirty.has(ref)) {
scope.reportError(new RangeError("Cyclic reference"));
return new FluentNone(id);
}
scope.dirty.add(ref);

const term = scope.bundle._terms.get(id);
if (!term) {
scope.reportError(new ReferenceError(`Unknown term: ${id}`));
Expand Down Expand Up @@ -304,13 +319,6 @@ export function resolveComplexPattern(
scope: Scope,
ptn: ComplexPattern
): FluentValue {
if (scope.dirty.has(ptn)) {
scope.reportError(new RangeError("Cyclic reference"));
return new FluentNone();
}

// Tag the pattern as dirty for the purpose of the current resolution.
scope.dirty.add(ptn);
const result = [];

// Wrap interpolations with Directional Isolate Formatting characters
Expand All @@ -325,7 +333,6 @@ export function resolveComplexPattern(

scope.placeables++;
if (scope.placeables > MAX_PLACEABLES) {
scope.dirty.delete(ptn);
// This is a fatal error which causes the resolver to instantly bail out
// on this pattern. The length check protects against excessive memory
// usage, and throwing protects against eating up the CPU when long
Expand All @@ -347,7 +354,6 @@ export function resolveComplexPattern(
}
}

scope.dirty.delete(ptn);
return result.join("");
}

Expand Down
Loading