Skip to content

Commit f4b8b00

Browse files
committed
Throw the first error if errors is not defined
1 parent 5bea9d1 commit f4b8b00

File tree

4 files changed

+105
-52
lines changed

4 files changed

+105
-52
lines changed

fluent/src/bundle.js

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -207,30 +207,35 @@ export default class FluentBundle {
207207
* // [<ReferenceError: Unknown variable: name>]
208208
* }
209209
*
210+
* If `errors` is omitted, the first encountered error will be thrown.
211+
*
210212
* @param {string|Array} pattern
211213
* @param {?Object} args
212214
* @param {?Array} errors
213215
* @returns {string}
214216
*/
215217
formatPattern(pattern, args, errors) {
216-
// Resolve a simple pattern without creating a scope.
218+
// Resolve a simple pattern without creating a scope. No error handling is
219+
// required; by definition simple patterns don't have placeables.
217220
if (typeof pattern === "string") {
218221
return this._transform(pattern);
219222
}
220223

221224
// Resolve a complex pattern.
222-
if (Array.isArray(pattern)) {
223-
let scope = this._createScope(args, errors);
224-
try {
225-
let value = resolveComplexPattern(scope, pattern);
226-
return value.toString(scope);
227-
} catch (err) {
228-
scope.errors.push(err);
229-
return new FluentNone().toString(scope);
230-
}
225+
let scope = this._createScope(args, errors);
226+
let value;
227+
try {
228+
value = resolveComplexPattern(scope, pattern).toString(scope);
229+
} catch (err) {
230+
scope.errors.push(err);
231+
value = new FluentNone().toString(scope);
232+
}
233+
234+
if (!errors && scope.errors.length > 0) {
235+
throw scope.errors[0];
231236
}
232237

233-
throw new TypeError("Invalid Pattern type");
238+
return value;
234239
}
235240

236241
_createScope(args, errors = []) {

fluent/test/functions_builtin_test.js

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import ftl from "@fluent/dedent";
66
import FluentBundle from '../src/bundle';
77

88
suite('Built-in functions', function() {
9-
let bundle;
9+
let bundle, errors;
10+
11+
setup(function () {
12+
errors = [];
13+
});
1014

1115
suite('NUMBER', function(){
1216
suiteSetup(function() {
@@ -22,70 +26,93 @@ suite('Built-in functions', function() {
2226
let msg;
2327

2428
msg = bundle.getMessage('num-decimal');
25-
assert.strictEqual(bundle.formatPattern(msg.value), '{$arg}');
29+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
30+
assert.strictEqual(errors.length, 1);
31+
assert.ok(errors.pop() instanceof ReferenceError);
2632

2733
msg = bundle.getMessage('num-percent');
28-
assert.strictEqual(bundle.formatPattern(msg.value), '{$arg}');
34+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
35+
assert.strictEqual(errors.length, 1);
36+
assert.ok(errors.pop() instanceof ReferenceError);
2937

3038
msg = bundle.getMessage('num-bad-opt');
31-
assert.strictEqual(bundle.formatPattern(msg.value), '{$arg}');
39+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
40+
assert.strictEqual(errors.length, 1);
41+
assert.ok(errors.pop() instanceof ReferenceError);
3242
});
3343

3444
test('number argument', function() {
3545
const args = {arg: 1};
3646
let msg;
3747

3848
msg = bundle.getMessage('num-decimal');
39-
assert.strictEqual(bundle.formatPattern(msg.value, args), '1');
49+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '1');
50+
assert.strictEqual(errors.length, 0);
4051

4152
msg = bundle.getMessage('num-percent');
42-
assert.strictEqual(bundle.formatPattern(msg.value, args), '100%');
53+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '100%');
54+
assert.strictEqual(errors.length, 0);
4355

4456
msg = bundle.getMessage('num-bad-opt');
45-
assert.strictEqual(bundle.formatPattern(msg.value, args), '1');
57+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '1');
58+
assert.strictEqual(errors.length, 0);
4659
});
4760

61+
// XXX Functions should report errors.
4862
test('string argument', function() {
4963
const args = {arg: "Foo"};
5064
let msg;
5165

5266
msg = bundle.getMessage('num-decimal');
53-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{NUMBER()}');
67+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
68+
assert.strictEqual(errors.length, 0);
5469

5570
msg = bundle.getMessage('num-percent');
56-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{NUMBER()}');
71+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
72+
assert.strictEqual(errors.length, 0);
5773

5874
msg = bundle.getMessage('num-bad-opt');
59-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{NUMBER()}');
75+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
76+
assert.strictEqual(errors.length, 0);
6077
});
6178

79+
// XXX Functions should report errors.
6280
test('date argument', function() {
6381
const date = new Date('2016-09-29');
6482
const args = {arg: date};
6583
let msg;
6684

6785
msg = bundle.getMessage('num-decimal');
68-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{NUMBER()}');
86+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
87+
assert.strictEqual(errors.length, 0);
6988

7089
msg = bundle.getMessage('num-percent');
71-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{NUMBER()}');
90+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
91+
assert.strictEqual(errors.length, 0);
7292

7393
msg = bundle.getMessage('num-bad-opt');
74-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{NUMBER()}');
94+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{NUMBER()}');
95+
assert.strictEqual(errors.length, 0);
7596
});
7697

7798
test('invalid argument', function() {
7899
const args = {arg: []};
79100
let msg;
80101

81102
msg = bundle.getMessage('num-decimal');
82-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{$arg}');
103+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
104+
assert.strictEqual(errors.length, 1);
105+
assert.ok(errors.pop() instanceof TypeError);
83106

84107
msg = bundle.getMessage('num-percent');
85-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{$arg}');
108+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
109+
assert.strictEqual(errors.length, 1);
110+
assert.ok(errors.pop() instanceof TypeError);
86111

87112
msg = bundle.getMessage('num-bad-opt');
88-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{$arg}');
113+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
114+
assert.strictEqual(errors.length, 1);
115+
assert.ok(errors.pop() instanceof TypeError);
89116
});
90117
});
91118

@@ -103,13 +130,19 @@ suite('Built-in functions', function() {
103130
let msg;
104131

105132
msg = bundle.getMessage('dt-default');
106-
assert.strictEqual(bundle.formatPattern(msg.value), '{$arg}');
133+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
134+
assert.strictEqual(errors.length, 1);
135+
assert.ok(errors.pop() instanceof ReferenceError);
107136

108137
msg = bundle.getMessage('dt-month');
109-
assert.strictEqual(bundle.formatPattern(msg.value), '{$arg}');
138+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
139+
assert.strictEqual(errors.length, 1);
140+
assert.ok(errors.pop() instanceof ReferenceError);
110141

111142
msg = bundle.getMessage('dt-bad-opt');
112-
assert.strictEqual(bundle.formatPattern(msg.value), '{$arg}');
143+
assert.strictEqual(bundle.formatPattern(msg.value, {}, errors), '{$arg}');
144+
assert.strictEqual(errors.length, 1);
145+
assert.ok(errors.pop() instanceof ReferenceError);
113146
});
114147

115148
test('Date argument', function () {
@@ -124,59 +157,76 @@ suite('Built-in functions', function() {
124157
let msg;
125158

126159
msg = bundle.getMessage('dt-default');
127-
assert.strictEqual(bundle.formatPattern(msg.value, args), expectedDefault);
160+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), expectedDefault);
161+
assert.strictEqual(errors.length, 0);
128162

129163
msg = bundle.getMessage('dt-month');
130-
assert.strictEqual(bundle.formatPattern(msg.value, args), expectedMonth);
164+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), expectedMonth);
165+
assert.strictEqual(errors.length, 0);
131166

132167
msg = bundle.getMessage('dt-bad-opt');
133168
// The argument value will be coerced into a string by the join operation
134169
// in FluentBundle.format. The result looks something like this; it
135170
// may vary depending on the TZ:
136171
// Thu Sep 29 2016 02:00:00 GMT+0200 (CEST)
137-
assert.strictEqual(bundle.formatPattern(msg.value, args), date.toString());
172+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), date.toString());
173+
assert.strictEqual(errors.length, 0);
138174
});
139175

176+
// XXX Functions should report errors.
140177
test('number argument', function() {
141178
let args = {arg: 1};
142179
let msg;
143180

144181
msg = bundle.getMessage('dt-default');
145-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{DATETIME()}');
182+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
183+
assert.strictEqual(errors.length, 0);
146184

147185
msg = bundle.getMessage('dt-month');
148-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{DATETIME()}');
186+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
187+
assert.strictEqual(errors.length, 0);
149188

150189
msg = bundle.getMessage('dt-bad-opt');
151-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{DATETIME()}');
190+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
191+
assert.strictEqual(errors.length, 0);
152192
});
153193

194+
// XXX Functions should report errors.
154195
test('string argument', function() {
155196
let args = {arg: 'Foo'};
156197
let msg;
157198

158199
msg = bundle.getMessage('dt-default');
159-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{DATETIME()}');
200+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
201+
assert.strictEqual(errors.length, 0);
160202

161203
msg = bundle.getMessage('dt-month');
162-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{DATETIME()}');
204+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
205+
assert.strictEqual(errors.length, 0);
163206

164207
msg = bundle.getMessage('dt-bad-opt');
165-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{DATETIME()}');
208+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{DATETIME()}');
209+
assert.strictEqual(errors.length, 0);
166210
});
167211

168212
test('invalid argument', function() {
169213
let args = {arg: []};
170214
let msg;
171215

172216
msg = bundle.getMessage('dt-default');
173-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{$arg}');
217+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
218+
assert.strictEqual(errors.length, 1);
219+
assert.ok(errors.pop() instanceof TypeError);
174220

175221
msg = bundle.getMessage('dt-month');
176-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{$arg}');
222+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
223+
assert.strictEqual(errors.length, 1);
224+
assert.ok(errors.pop() instanceof TypeError);
177225

178226
msg = bundle.getMessage('dt-bad-opt');
179-
assert.strictEqual(bundle.formatPattern(msg.value, args), '{$arg}');
227+
assert.strictEqual(bundle.formatPattern(msg.value, args, errors), '{$arg}');
228+
assert.strictEqual(errors.length, 1);
229+
assert.ok(errors.pop() instanceof TypeError);
180230
});
181231
});
182232
});

fluent/test/patterns_test.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,11 @@ suite('Patterns', function(){
8484
`);
8585
});
8686

87-
test('throws when trying to format a null value', function(){
87+
test('returns {???} when trying to format a null value', function(){
8888
const msg = bundle.getMessage('foo');
89-
assert.throws(
90-
() => bundle.formatPattern(msg.value, args, errs),
91-
/Invalid Pattern type/
92-
);
89+
const val = bundle.formatPattern(msg.value, args, errs);
90+
assert.strictEqual(val, '{???}');
91+
assert.strictEqual(errs.length, 1);
9392
});
9493

9594
test('formats the attribute', function(){

fluent/test/values_format_test.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,11 @@ suite('Formatting values', function(){
5959
assert.strictEqual(errs.length, 1);
6060
});
6161

62-
test('throws when trying to format a null value', function(){
62+
test('returns {???} when trying to format a null value', function(){
6363
const msg = bundle.getMessage('key5');
64-
assert.throws(
65-
() => bundle.formatPattern(msg.value, args, errs),
66-
/Invalid Pattern type/
67-
);
64+
const val = bundle.formatPattern(msg.value, args, errs);
65+
assert.strictEqual(val, '{???}');
66+
assert.strictEqual(errs.length, 1);
6867
});
6968

7069
test('allows to pass traits directly to bundle.formatPattern', function(){

0 commit comments

Comments
 (0)