Skip to content
This repository was archived by the owner on May 4, 2020. It is now read-only.

Commit 6200573

Browse files
author
Long Ho
committed
feat(intl-messageformat): Add error type for better debugging
1 parent 4251f2f commit 6200573

File tree

3 files changed

+54
-23
lines changed

3 files changed

+54
-23
lines changed

packages/intl-messageformat/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ new IntlMessageFormat(
187187
"raw '<b>HTML</b>' with '<a>'{placeholder}'</a>'"
188188
).format({placeholder: 'some word'}); // "raw <b>HTML</b> with <a>some word</a>"
189189
```
190+
190191
5. Embedded valid HTML tag is a bit of a grey area right now since we're not supporting the full HTML/XHTML/XML spec.
191192

192193
### `getAst` Method
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export const enum ErrorCode {
2+
// When we have a placeholder but no value to format
3+
MISSING_VALUE,
4+
// When value supplied is invalid
5+
INVALID_VALUE,
6+
// When we need specific Intl API but it's not available
7+
MISSING_INTL_API,
8+
}
9+
10+
export class FormatError extends Error {
11+
public readonly code: ErrorCode;
12+
constructor(msg: string, code: ErrorCode) {
13+
super(msg);
14+
this.code = code;
15+
}
16+
public toString() {
17+
return `[formatjs Error: ${this.code}] ${this.message}`;
18+
}
19+
}
20+
21+
export class InvalidValueError extends FormatError {
22+
constructor(variableId: string, value: any, options: string[]) {
23+
super(
24+
`Invalid values for "${variableId}": "${value}". Options are "${Object.keys(
25+
options
26+
).join('", "')}"`,
27+
ErrorCode.INVALID_VALUE
28+
);
29+
}
30+
}
31+
32+
export class MissingValueError extends FormatError {
33+
constructor(variableId: string, originalMessage?: string) {
34+
super(
35+
`The intl string context variable "${variableId}" was not provided to the string "${originalMessage}"`,
36+
ErrorCode.MISSING_VALUE
37+
);
38+
}
39+
}

packages/intl-messageformat/src/formatters.ts

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ import {
1414
parseDateTimeSkeleton,
1515
isTagElement,
1616
} from 'intl-messageformat-parser';
17+
import {
18+
MissingValueError,
19+
InvalidValueError,
20+
ErrorCode,
21+
FormatError,
22+
} from './error';
1723

1824
export interface Formats {
1925
number: Record<string, Intl.NumberFormatOptions>;
@@ -58,14 +64,6 @@ export type MessageFormatPart<T> = LiteralPart | ObjectPart<T>;
5864

5965
export type PrimitiveType = string | number | boolean | null | undefined | Date;
6066

61-
class FormatError extends Error {
62-
public readonly variableId?: string;
63-
constructor(msg?: string, variableId?: string) {
64-
super(msg);
65-
this.variableId = variableId;
66-
}
67-
}
68-
6967
function mergeLiteral<T>(
7068
parts: MessageFormatPart<T>[]
7169
): MessageFormatPart<T>[] {
@@ -139,9 +137,7 @@ export function formatToParts<T>(
139137

140138
// Enforce that all required values are provided by the caller.
141139
if (!(values && varName in values)) {
142-
throw new FormatError(
143-
`The intl string context variable "${varName}" was not provided to the string "${originalMessage}"`
144-
);
140+
throw new MissingValueError(varName, originalMessage);
145141
}
146142

147143
let value = values[varName];
@@ -235,11 +231,7 @@ export function formatToParts<T>(
235231
if (isSelectElement(el)) {
236232
const opt = el.options[value as string] || el.options.other;
237233
if (!opt) {
238-
throw new RangeError(
239-
`Invalid values for "${
240-
el.value
241-
}": "${value}". Options are "${Object.keys(el.options).join('", "')}"`
242-
);
234+
throw new InvalidValueError(el.value, value, Object.keys(el.options));
243235
}
244236
result.push(
245237
...formatToParts(opt.value, locales, formatters, formats, values)
@@ -250,21 +242,20 @@ export function formatToParts<T>(
250242
let opt = el.options[`=${value}`];
251243
if (!opt) {
252244
if (!Intl.PluralRules) {
253-
throw new FormatError(`Intl.PluralRules is not available in this environment.
245+
throw new FormatError(
246+
`Intl.PluralRules is not available in this environment.
254247
Try polyfilling it using "@formatjs/intl-pluralrules"
255-
`);
248+
`,
249+
ErrorCode.MISSING_INTL_API
250+
);
256251
}
257252
const rule = formatters
258253
.getPluralRules(locales, {type: el.pluralType})
259254
.select((value as number) - (el.offset || 0));
260255
opt = el.options[rule] || el.options.other;
261256
}
262257
if (!opt) {
263-
throw new RangeError(
264-
`Invalid values for "${
265-
el.value
266-
}": "${value}". Options are "${Object.keys(el.options).join('", "')}"`
267-
);
258+
throw new InvalidValueError(el.value, value, Object.keys(el.options));
268259
}
269260
result.push(
270261
...formatToParts(

0 commit comments

Comments
 (0)