From 48a11f8ff9535f821ed885c75f9b29c064ff87e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sta=C5=9B=20Ma=C5=82olepszy?= Date: Fri, 19 Jul 2019 15:41:40 +0200 Subject: [PATCH 1/4] Report errors from Functions --- fluent/src/builtins.js | 14 +- fluent/src/resolver.js | 8 +- fluent/test/functions_builtin_test.js | 196 ++++++++++++++++++-------- 3 files changed, 145 insertions(+), 73 deletions(-) diff --git a/fluent/src/builtins.js b/fluent/src/builtins.js index 3528bbcdf..c117a0802 100644 --- a/fluent/src/builtins.js +++ b/fluent/src/builtins.js @@ -11,7 +11,7 @@ * `FluentType`. Functions must return `FluentType` objects as well. */ -import { FluentNone, FluentNumber, FluentDateTime } from "./types.js"; +import { FluentNumber, FluentDateTime } from "./types.js"; function merge(argopts, opts) { return Object.assign({}, argopts, values(opts)); @@ -27,22 +27,18 @@ function values(opts) { export function NUMBER([arg], opts) { - if (arg instanceof FluentNone) { - return arg; - } if (arg instanceof FluentNumber) { return new FluentNumber(arg.valueOf(), merge(arg.opts, opts)); } - return new FluentNone("NUMBER()"); + + throw new TypeError("Invalid argument type to NUMBER"); } export function DATETIME([arg], opts) { - if (arg instanceof FluentNone) { - return arg; - } if (arg instanceof FluentDateTime) { return new FluentDateTime(arg.valueOf(), merge(arg.opts, opts)); } - return new FluentNone("DATETIME()"); + + throw new TypeError("Invalid argument type to DATETIME"); } diff --git a/fluent/src/resolver.js b/fluent/src/resolver.js index eb278c029..c16129a01 100644 --- a/fluent/src/resolver.js +++ b/fluent/src/resolver.js @@ -127,7 +127,7 @@ function resolveExpression(scope, expr) { function VariableReference(scope, {name}) { if (!scope.args || !scope.args.hasOwnProperty(name)) { if (scope.insideTermReference === false) { - scope.reportError(new ReferenceError(`Unknown variable: ${name}`)); + scope.reportError(new ReferenceError(`Unknown variable: $${name}`)); } return new FluentNone(`$${name}`); } @@ -151,7 +151,7 @@ function VariableReference(scope, {name}) { } default: scope.reportError( - new TypeError(`Unsupported variable type: ${name}, ${typeof arg}`) + new TypeError(`Variable type not supported: $${name}, ${typeof arg}`) ); return new FluentNone(`$${name}`); } @@ -224,8 +224,8 @@ function FunctionReference(scope, {name, args}) { try { return func(...getArguments(scope, args)); - } catch (e) { - // XXX Report errors. + } catch (err) { + scope.reportError(err); return new FluentNone(`${name}()`); } } diff --git a/fluent/test/functions_builtin_test.js b/fluent/test/functions_builtin_test.js index c72f361a8..bb7f65e93 100644 --- a/fluent/test/functions_builtin_test.js +++ b/fluent/test/functions_builtin_test.js @@ -25,20 +25,32 @@ suite('Built-in functions', function() { test('missing argument', function() { let msg; + errors = []; msg = bundle.getMessage('num-decimal'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof ReferenceError); - + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof ReferenceError); + assert.strictEqual(errors[0].message, "Unknown variable: $arg"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); + + errors = []; msg = bundle.getMessage('num-percent'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof ReferenceError); - + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof ReferenceError); + assert.strictEqual(errors[0].message, "Unknown variable: $arg"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); + + errors = []; msg = bundle.getMessage('num-bad-opt'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof ReferenceError); + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof ReferenceError); + assert.strictEqual(errors[0].message, "Unknown variable: $arg"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); }); test('number argument', function() { @@ -58,63 +70,89 @@ suite('Built-in functions', function() { assert.strictEqual(errors.length, 0); }); - // XXX Functions should report errors. - // https://github.com/projectfluent/fluent.js/issues/106 test('string argument', function() { const args = {arg: "Foo"}; let msg; + errors = []; msg = bundle.getMessage('num-decimal'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER"); + errors = []; msg = bundle.getMessage('num-percent'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER"); + errors = []; msg = bundle.getMessage('num-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER"); }); - // XXX Functions should report errors. - // https://github.com/projectfluent/fluent.js/issues/106 test('date argument', function() { const date = new Date('2016-09-29'); const args = {arg: date}; let msg; + errors = []; msg = bundle.getMessage('num-decimal'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER"); + errors = []; msg = bundle.getMessage('num-percent'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER"); + errors = []; msg = bundle.getMessage('num-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER"); }); test('invalid argument', function() { const args = {arg: []}; let msg; + errors = []; msg = bundle.getMessage('num-decimal'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof TypeError); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); + errors = []; msg = bundle.getMessage('num-percent'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof TypeError); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); + errors = []; msg = bundle.getMessage('num-bad-opt'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof TypeError); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); }); }); @@ -131,20 +169,32 @@ suite('Built-in functions', function() { test('missing argument', function() { let msg; + errors = []; msg = bundle.getMessage('dt-default'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof ReferenceError); - + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof ReferenceError); + assert.strictEqual(errors[0].message, "Unknown variable: $arg"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); + + errors = []; msg = bundle.getMessage('dt-month'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof ReferenceError); - + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof ReferenceError); + assert.strictEqual(errors[0].message, "Unknown variable: $arg"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); + + errors = []; msg = bundle.getMessage('dt-bad-opt'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof ReferenceError); + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof ReferenceError); + assert.strictEqual(errors[0].message, "Unknown variable: $arg"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); }); test('Date argument', function () { @@ -175,62 +225,88 @@ suite('Built-in functions', function() { assert.strictEqual(errors.length, 0); }); - // XXX Functions should report errors. - // https://github.com/projectfluent/fluent.js/issues/106 test('number argument', function() { let args = {arg: 1}; let msg; + errors = []; msg = bundle.getMessage('dt-default'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME"); + errors = []; msg = bundle.getMessage('dt-month'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME"); + errors = []; msg = bundle.getMessage('dt-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME"); }); - // XXX Functions should report errors. - // https://github.com/projectfluent/fluent.js/issues/106 test('string argument', function() { let args = {arg: 'Foo'}; let msg; + errors = []; msg = bundle.getMessage('dt-default'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME"); + errors = []; msg = bundle.getMessage('dt-month'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME"); + errors = []; msg = bundle.getMessage('dt-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME"); }); test('invalid argument', function() { let args = {arg: []}; let msg; + errors = []; msg = bundle.getMessage('dt-default'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof TypeError); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); + errors = []; msg = bundle.getMessage('dt-month'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof TypeError); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); + errors = []; msg = bundle.getMessage('dt-bad-opt'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}'); - assert.strictEqual(errors.length, 1); - assert.ok(errors.pop() instanceof TypeError); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); + assert.strictEqual(errors.length, 2); + assert.ok(errors[0] instanceof TypeError); + assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); + assert.ok(errors[1] instanceof TypeError); + assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); }); }); }); From c9b38d360ed7eb0ac50a109945ab900fe609a525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sta=C5=9B=20Ma=C5=82olepszy?= Date: Fri, 19 Jul 2019 15:45:59 +0200 Subject: [PATCH 2/4] Report errors from instantiating Intl objects --- fluent/src/types.js | 8 ++++---- fluent/test/functions_builtin_test.js | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/fluent/src/types.js b/fluent/src/types.js index a2805e3ca..5becb026a 100644 --- a/fluent/src/types.js +++ b/fluent/src/types.js @@ -65,8 +65,8 @@ export class FluentNumber extends FluentType { Intl.NumberFormat, this.opts ); return nf.format(this.value); - } catch (e) { - // XXX Report the error. + } catch (err) { + scope.reportError(err); return this.value; } } @@ -83,8 +83,8 @@ export class FluentDateTime extends FluentType { Intl.DateTimeFormat, this.opts ); return dtf.format(this.value); - } catch (e) { - // XXX Report the error. + } catch (err) { + scope.reportError(err); return this.value; } } diff --git a/fluent/test/functions_builtin_test.js b/fluent/test/functions_builtin_test.js index bb7f65e93..c085d7af4 100644 --- a/fluent/test/functions_builtin_test.js +++ b/fluent/test/functions_builtin_test.js @@ -67,7 +67,8 @@ suite('Built-in functions', function() { msg = bundle.getMessage('num-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '1'); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof RangeError); // Invalid option value }); test('string argument', function() { @@ -222,7 +223,8 @@ suite('Built-in functions', function() { // may vary depending on the TZ: // Thu Sep 29 2016 02:00:00 GMT+0200 (CEST) assert.strictEqual(bundle.formatPattern(msg.value, args, errors), date.toString()); - assert.strictEqual(errors.length, 0); + assert.strictEqual(errors.length, 1); + assert.ok(errors[0] instanceof RangeError); // Invalid option value }); test('number argument', function() { From 055b22281cc9b0eb9562e27c62c7fdd5a9a22b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sta=C5=9B=20Ma=C5=82olepszy?= Date: Mon, 22 Jul 2019 16:37:54 +0200 Subject: [PATCH 3/4] Check if arguments to builtins are FluentNone --- fluent/src/builtins.js | 10 +++++- fluent/test/functions_builtin_test.js | 48 +++++++-------------------- 2 files changed, 21 insertions(+), 37 deletions(-) diff --git a/fluent/src/builtins.js b/fluent/src/builtins.js index c117a0802..e54f8cb28 100644 --- a/fluent/src/builtins.js +++ b/fluent/src/builtins.js @@ -11,7 +11,7 @@ * `FluentType`. Functions must return `FluentType` objects as well. */ -import { FluentNumber, FluentDateTime } from "./types.js"; +import { FluentNone, FluentNumber, FluentDateTime } from "./types.js"; function merge(argopts, opts) { return Object.assign({}, argopts, values(opts)); @@ -27,6 +27,10 @@ function values(opts) { export function NUMBER([arg], opts) { + if (arg instanceof FluentNone) { + return new FluentNone("NUMBER()"); + } + if (arg instanceof FluentNumber) { return new FluentNumber(arg.valueOf(), merge(arg.opts, opts)); } @@ -36,6 +40,10 @@ function NUMBER([arg], opts) { export function DATETIME([arg], opts) { + if (arg instanceof FluentNone) { + return new FluentNone("DATETIME()"); + } + if (arg instanceof FluentDateTime) { return new FluentDateTime(arg.valueOf(), merge(arg.opts, opts)); } diff --git a/fluent/test/functions_builtin_test.js b/fluent/test/functions_builtin_test.js index c085d7af4..b2ba14af1 100644 --- a/fluent/test/functions_builtin_test.js +++ b/fluent/test/functions_builtin_test.js @@ -28,29 +28,23 @@ suite('Built-in functions', function() { errors = []; msg = bundle.getMessage('num-decimal'); assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); errors = []; msg = bundle.getMessage('num-percent'); assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); errors = []; msg = bundle.getMessage('num-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); }); test('number argument', function() { @@ -131,29 +125,23 @@ suite('Built-in functions', function() { errors = []; msg = bundle.getMessage('num-decimal'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); errors = []; msg = bundle.getMessage('num-percent'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); errors = []; msg = bundle.getMessage('num-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to NUMBER"); }); }); @@ -173,29 +161,23 @@ suite('Built-in functions', function() { errors = []; msg = bundle.getMessage('dt-default'); assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); errors = []; msg = bundle.getMessage('dt-month'); assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); errors = []; msg = bundle.getMessage('dt-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); }); test('Date argument', function () { @@ -286,29 +268,23 @@ suite('Built-in functions', function() { errors = []; msg = bundle.getMessage('dt-default'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); errors = []; msg = bundle.getMessage('dt-month'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); errors = []; msg = bundle.getMessage('dt-bad-opt'); assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); - assert.strictEqual(errors.length, 2); + assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); - assert.ok(errors[1] instanceof TypeError); - assert.strictEqual(errors[1].message, "Invalid argument type to DATETIME"); }); }); }); From 33f6cb2f64b8d0ae7a4f36562f8169f586552ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sta=C5=9B=20Ma=C5=82olepszy?= Date: Mon, 22 Jul 2019 17:00:34 +0200 Subject: [PATCH 4/4] Use NUMBER() as the placeable fallback --- fluent/src/builtins.js | 4 ++-- fluent/src/types.js | 6 +++--- fluent/test/functions_builtin_test.js | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fluent/src/builtins.js b/fluent/src/builtins.js index e54f8cb28..7bfa8fd12 100644 --- a/fluent/src/builtins.js +++ b/fluent/src/builtins.js @@ -28,7 +28,7 @@ function values(opts) { export function NUMBER([arg], opts) { if (arg instanceof FluentNone) { - return new FluentNone("NUMBER()"); + return new FluentNone(`NUMBER(${arg.valueOf()})`); } if (arg instanceof FluentNumber) { @@ -41,7 +41,7 @@ function NUMBER([arg], opts) { export function DATETIME([arg], opts) { if (arg instanceof FluentNone) { - return new FluentNone("DATETIME()"); + return new FluentNone(`DATETIME(${arg.valueOf()})`); } if (arg instanceof FluentDateTime) { diff --git a/fluent/src/types.js b/fluent/src/types.js index 5becb026a..ad379c8e1 100644 --- a/fluent/src/types.js +++ b/fluent/src/types.js @@ -45,12 +45,12 @@ export class FluentType { } export class FluentNone extends FluentType { - valueOf() { - return null; + constructor(value = "???") { + super(value); } toString() { - return `{${this.value || "???"}}`; + return `{${this.value}}`; } } diff --git a/fluent/test/functions_builtin_test.js b/fluent/test/functions_builtin_test.js index b2ba14af1..905992d4f 100644 --- a/fluent/test/functions_builtin_test.js +++ b/fluent/test/functions_builtin_test.js @@ -27,21 +27,21 @@ suite('Built-in functions', function() { errors = []; msg = bundle.getMessage('num-decimal'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); errors = []; msg = bundle.getMessage('num-percent'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); errors = []; msg = bundle.getMessage('num-bad-opt'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER()}'); + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); @@ -124,21 +124,21 @@ suite('Built-in functions', function() { errors = []; msg = bundle.getMessage('num-decimal'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); errors = []; msg = bundle.getMessage('num-percent'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); errors = []; msg = bundle.getMessage('num-bad-opt'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}'); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); @@ -160,21 +160,21 @@ suite('Built-in functions', function() { errors = []; msg = bundle.getMessage('dt-default'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); errors = []; msg = bundle.getMessage('dt-month'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); errors = []; msg = bundle.getMessage('dt-bad-opt'); - assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME()}'); + assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof ReferenceError); assert.strictEqual(errors[0].message, "Unknown variable: $arg"); @@ -267,21 +267,21 @@ suite('Built-in functions', function() { errors = []; msg = bundle.getMessage('dt-default'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); errors = []; msg = bundle.getMessage('dt-month'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object"); errors = []; msg = bundle.getMessage('dt-bad-opt'); - assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}'); + assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME($arg)}'); assert.strictEqual(errors.length, 1); assert.ok(errors[0] instanceof TypeError); assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object");