Skip to content

Commit c40eb5e

Browse files
authored
Merge pull request #398 from stasm/report-errors-from-functions
Report errors from Functions and Intl objects
2 parents 413a363 + 33f6cb2 commit c40eb5e

File tree

4 files changed

+119
-61
lines changed

4 files changed

+119
-61
lines changed

fluent/src/builtins.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,25 @@ function values(opts) {
2828
export
2929
function NUMBER([arg], opts) {
3030
if (arg instanceof FluentNone) {
31-
return arg;
31+
return new FluentNone(`NUMBER(${arg.valueOf()})`);
3232
}
33+
3334
if (arg instanceof FluentNumber) {
3435
return new FluentNumber(arg.valueOf(), merge(arg.opts, opts));
3536
}
36-
return new FluentNone("NUMBER()");
37+
38+
throw new TypeError("Invalid argument type to NUMBER");
3739
}
3840

3941
export
4042
function DATETIME([arg], opts) {
4143
if (arg instanceof FluentNone) {
42-
return arg;
44+
return new FluentNone(`DATETIME(${arg.valueOf()})`);
4345
}
46+
4447
if (arg instanceof FluentDateTime) {
4548
return new FluentDateTime(arg.valueOf(), merge(arg.opts, opts));
4649
}
47-
return new FluentNone("DATETIME()");
50+
51+
throw new TypeError("Invalid argument type to DATETIME");
4852
}

fluent/src/resolver.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function resolveExpression(scope, expr) {
127127
function VariableReference(scope, {name}) {
128128
if (!scope.args || !scope.args.hasOwnProperty(name)) {
129129
if (scope.insideTermReference === false) {
130-
scope.reportError(new ReferenceError(`Unknown variable: ${name}`));
130+
scope.reportError(new ReferenceError(`Unknown variable: $${name}`));
131131
}
132132
return new FluentNone(`$${name}`);
133133
}
@@ -151,7 +151,7 @@ function VariableReference(scope, {name}) {
151151
}
152152
default:
153153
scope.reportError(
154-
new TypeError(`Unsupported variable type: ${name}, ${typeof arg}`)
154+
new TypeError(`Variable type not supported: $${name}, ${typeof arg}`)
155155
);
156156
return new FluentNone(`$${name}`);
157157
}
@@ -224,8 +224,8 @@ function FunctionReference(scope, {name, args}) {
224224

225225
try {
226226
return func(...getArguments(scope, args));
227-
} catch (e) {
228-
// XXX Report errors.
227+
} catch (err) {
228+
scope.reportError(err);
229229
return new FluentNone(`${name}()`);
230230
}
231231
}

fluent/src/types.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ export class FluentType {
4545
}
4646

4747
export class FluentNone extends FluentType {
48-
valueOf() {
49-
return null;
48+
constructor(value = "???") {
49+
super(value);
5050
}
5151

5252
toString() {
53-
return `{${this.value || "???"}}`;
53+
return `{${this.value}}`;
5454
}
5555
}
5656

@@ -63,8 +63,8 @@ export class FluentNumber extends FluentType {
6363
try {
6464
const nf = scope.memoizeIntlObject(Intl.NumberFormat, this.opts);
6565
return nf.format(this.value);
66-
} catch (e) {
67-
// XXX Report the error.
66+
} catch (err) {
67+
scope.reportError(err);
6868
return this.value;
6969
}
7070
}
@@ -79,8 +79,8 @@ export class FluentDateTime extends FluentType {
7979
try {
8080
const dtf = scope.memoizeIntlObject(Intl.DateTimeFormat, this.opts);
8181
return dtf.format(this.value);
82-
} catch (e) {
83-
// XXX Report the error.
82+
} catch (err) {
83+
scope.reportError(err);
8484
return this.value;
8585
}
8686
}

fluent/test/functions_builtin_test.js

+100-46
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,26 @@ suite('Built-in functions', function() {
2525
test('missing argument', function() {
2626
let msg;
2727

28+
errors = [];
2829
msg = bundle.getMessage('num-decimal');
29-
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
30+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER($arg)}');
3031
assert.strictEqual(errors.length, 1);
31-
assert.ok(errors.pop() instanceof ReferenceError);
32+
assert.ok(errors[0] instanceof ReferenceError);
33+
assert.strictEqual(errors[0].message, "Unknown variable: $arg");
3234

35+
errors = [];
3336
msg = bundle.getMessage('num-percent');
34-
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
37+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER($arg)}');
3538
assert.strictEqual(errors.length, 1);
36-
assert.ok(errors.pop() instanceof ReferenceError);
39+
assert.ok(errors[0] instanceof ReferenceError);
40+
assert.strictEqual(errors[0].message, "Unknown variable: $arg");
3741

42+
errors = [];
3843
msg = bundle.getMessage('num-bad-opt');
39-
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
44+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{NUMBER($arg)}');
4045
assert.strictEqual(errors.length, 1);
41-
assert.ok(errors.pop() instanceof ReferenceError);
46+
assert.ok(errors[0] instanceof ReferenceError);
47+
assert.strictEqual(errors[0].message, "Unknown variable: $arg");
4248
});
4349

4450
test('number argument', function() {
@@ -55,66 +61,87 @@ suite('Built-in functions', function() {
5561

5662
msg = bundle.getMessage('num-bad-opt');
5763
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '1');
58-
assert.strictEqual(errors.length, 0);
64+
assert.strictEqual(errors.length, 1);
65+
assert.ok(errors[0] instanceof RangeError); // Invalid option value
5966
});
6067

61-
// XXX Functions should report errors.
62-
// https://github.com/projectfluent/fluent.js/issues/106
6368
test('string argument', function() {
6469
const args = {arg: "Foo"};
6570
let msg;
6671

72+
errors = [];
6773
msg = bundle.getMessage('num-decimal');
6874
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
69-
assert.strictEqual(errors.length, 0);
75+
assert.strictEqual(errors.length, 1);
76+
assert.ok(errors[0] instanceof TypeError);
77+
assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER");
7078

79+
errors = [];
7180
msg = bundle.getMessage('num-percent');
7281
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
73-
assert.strictEqual(errors.length, 0);
82+
assert.strictEqual(errors.length, 1);
83+
assert.ok(errors[0] instanceof TypeError);
84+
assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER");
7485

86+
errors = [];
7587
msg = bundle.getMessage('num-bad-opt');
7688
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
77-
assert.strictEqual(errors.length, 0);
89+
assert.strictEqual(errors.length, 1);
90+
assert.ok(errors[0] instanceof TypeError);
91+
assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER");
7892
});
7993

80-
// XXX Functions should report errors.
81-
// https://github.com/projectfluent/fluent.js/issues/106
8294
test('date argument', function() {
8395
const date = new Date('2016-09-29');
8496
const args = {arg: date};
8597
let msg;
8698

99+
errors = [];
87100
msg = bundle.getMessage('num-decimal');
88101
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
89-
assert.strictEqual(errors.length, 0);
102+
assert.strictEqual(errors.length, 1);
103+
assert.ok(errors[0] instanceof TypeError);
104+
assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER");
90105

106+
errors = [];
91107
msg = bundle.getMessage('num-percent');
92108
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
93-
assert.strictEqual(errors.length, 0);
109+
assert.strictEqual(errors.length, 1);
110+
assert.ok(errors[0] instanceof TypeError);
111+
assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER");
94112

113+
errors = [];
95114
msg = bundle.getMessage('num-bad-opt');
96115
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
97-
assert.strictEqual(errors.length, 0);
116+
assert.strictEqual(errors.length, 1);
117+
assert.ok(errors[0] instanceof TypeError);
118+
assert.strictEqual(errors[0].message, "Invalid argument type to NUMBER");
98119
});
99120

100121
test('invalid argument', function() {
101122
const args = {arg: []};
102123
let msg;
103124

125+
errors = [];
104126
msg = bundle.getMessage('num-decimal');
105-
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
127+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER($arg)}');
106128
assert.strictEqual(errors.length, 1);
107-
assert.ok(errors.pop() instanceof TypeError);
129+
assert.ok(errors[0] instanceof TypeError);
130+
assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object");
108131

132+
errors = [];
109133
msg = bundle.getMessage('num-percent');
110-
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
134+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER($arg)}');
111135
assert.strictEqual(errors.length, 1);
112-
assert.ok(errors.pop() instanceof TypeError);
136+
assert.ok(errors[0] instanceof TypeError);
137+
assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object");
113138

139+
errors = [];
114140
msg = bundle.getMessage('num-bad-opt');
115-
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
141+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER($arg)}');
116142
assert.strictEqual(errors.length, 1);
117-
assert.ok(errors.pop() instanceof TypeError);
143+
assert.ok(errors[0] instanceof TypeError);
144+
assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object");
118145
});
119146
});
120147

@@ -131,20 +158,26 @@ suite('Built-in functions', function() {
131158
test('missing argument', function() {
132159
let msg;
133160

161+
errors = [];
134162
msg = bundle.getMessage('dt-default');
135-
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
163+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME($arg)}');
136164
assert.strictEqual(errors.length, 1);
137-
assert.ok(errors.pop() instanceof ReferenceError);
165+
assert.ok(errors[0] instanceof ReferenceError);
166+
assert.strictEqual(errors[0].message, "Unknown variable: $arg");
138167

168+
errors = [];
139169
msg = bundle.getMessage('dt-month');
140-
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
170+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME($arg)}');
141171
assert.strictEqual(errors.length, 1);
142-
assert.ok(errors.pop() instanceof ReferenceError);
172+
assert.ok(errors[0] instanceof ReferenceError);
173+
assert.strictEqual(errors[0].message, "Unknown variable: $arg");
143174

175+
errors = [];
144176
msg = bundle.getMessage('dt-bad-opt');
145-
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
177+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{DATETIME($arg)}');
146178
assert.strictEqual(errors.length, 1);
147-
assert.ok(errors.pop() instanceof ReferenceError);
179+
assert.ok(errors[0] instanceof ReferenceError);
180+
assert.strictEqual(errors[0].message, "Unknown variable: $arg");
148181
});
149182

150183
test('Date argument', function () {
@@ -172,65 +205,86 @@ suite('Built-in functions', function() {
172205
// may vary depending on the TZ:
173206
// Thu Sep 29 2016 02:00:00 GMT+0200 (CEST)
174207
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), date.toString());
175-
assert.strictEqual(errors.length, 0);
208+
assert.strictEqual(errors.length, 1);
209+
assert.ok(errors[0] instanceof RangeError); // Invalid option value
176210
});
177211

178-
// XXX Functions should report errors.
179-
// https://github.com/projectfluent/fluent.js/issues/106
180212
test('number argument', function() {
181213
let args = {arg: 1};
182214
let msg;
183215

216+
errors = [];
184217
msg = bundle.getMessage('dt-default');
185218
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
186-
assert.strictEqual(errors.length, 0);
219+
assert.strictEqual(errors.length, 1);
220+
assert.ok(errors[0] instanceof TypeError);
221+
assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME");
187222

223+
errors = [];
188224
msg = bundle.getMessage('dt-month');
189225
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
190-
assert.strictEqual(errors.length, 0);
226+
assert.strictEqual(errors.length, 1);
227+
assert.ok(errors[0] instanceof TypeError);
228+
assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME");
191229

230+
errors = [];
192231
msg = bundle.getMessage('dt-bad-opt');
193232
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
194-
assert.strictEqual(errors.length, 0);
233+
assert.strictEqual(errors.length, 1);
234+
assert.ok(errors[0] instanceof TypeError);
235+
assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME");
195236
});
196237

197-
// XXX Functions should report errors.
198-
// https://github.com/projectfluent/fluent.js/issues/106
199238
test('string argument', function() {
200239
let args = {arg: 'Foo'};
201240
let msg;
202241

242+
errors = [];
203243
msg = bundle.getMessage('dt-default');
204244
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
205-
assert.strictEqual(errors.length, 0);
245+
assert.strictEqual(errors.length, 1);
246+
assert.ok(errors[0] instanceof TypeError);
247+
assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME");
206248

249+
errors = [];
207250
msg = bundle.getMessage('dt-month');
208251
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
209-
assert.strictEqual(errors.length, 0);
252+
assert.strictEqual(errors.length, 1);
253+
assert.ok(errors[0] instanceof TypeError);
254+
assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME");
210255

256+
errors = [];
211257
msg = bundle.getMessage('dt-bad-opt');
212258
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
213-
assert.strictEqual(errors.length, 0);
259+
assert.strictEqual(errors.length, 1);
260+
assert.ok(errors[0] instanceof TypeError);
261+
assert.strictEqual(errors[0].message, "Invalid argument type to DATETIME");
214262
});
215263

216264
test('invalid argument', function() {
217265
let args = {arg: []};
218266
let msg;
219267

268+
errors = [];
220269
msg = bundle.getMessage('dt-default');
221-
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
270+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME($arg)}');
222271
assert.strictEqual(errors.length, 1);
223-
assert.ok(errors.pop() instanceof TypeError);
272+
assert.ok(errors[0] instanceof TypeError);
273+
assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object");
224274

275+
errors = [];
225276
msg = bundle.getMessage('dt-month');
226-
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
277+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME($arg)}');
227278
assert.strictEqual(errors.length, 1);
228-
assert.ok(errors.pop() instanceof TypeError);
279+
assert.ok(errors[0] instanceof TypeError);
280+
assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object");
229281

282+
errors = [];
230283
msg = bundle.getMessage('dt-bad-opt');
231-
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
284+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME($arg)}');
232285
assert.strictEqual(errors.length, 1);
233-
assert.ok(errors.pop() instanceof TypeError);
286+
assert.ok(errors[0] instanceof TypeError);
287+
assert.strictEqual(errors[0].message, "Variable type not supported: $arg, object");
234288
});
235289
});
236290
});

0 commit comments

Comments
 (0)