Skip to content
This repository was archived by the owner on Jun 8, 2019. It is now read-only.

Commit ff9d6d2

Browse files
authored
Merge pull request #67 from yahoo/refactor
Refactor to fix false-positive errors being thrown
2 parents 0b97375 + 939e009 commit ff9d6d2

File tree

1 file changed

+63
-55
lines changed

1 file changed

+63
-55
lines changed

src/index.js

Lines changed: 63 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@ export default function () {
2525
return opts.moduleSourceName || 'react-intl';
2626
}
2727

28-
function getMessageDescriptorKey(path) {
29-
if (path.isIdentifier() || path.isJSXIdentifier()) {
30-
return path.node.name;
31-
}
32-
28+
function evaluatePath(path) {
3329
let evaluated = path.evaluate();
3430
if (evaluated.confident) {
3531
return evaluated.value;
@@ -40,62 +36,74 @@ export default function () {
4036
);
4137
}
4238

39+
function getMessageDescriptorKey(path) {
40+
if (path.isIdentifier() || path.isJSXIdentifier()) {
41+
return path.node.name;
42+
}
43+
44+
return evaluatePath(path);
45+
}
46+
4347
function getMessageDescriptorValue(path) {
4448
if (path.isJSXExpressionContainer()) {
4549
path = path.get('expression');
4650
}
4751

48-
let evaluated = path.evaluate();
49-
if (evaluated.confident) {
50-
return evaluated.value;
51-
}
52-
53-
throw path.buildCodeFrameError(
54-
'[React Intl] Messages must be statically evaluate-able for extraction.'
55-
);
52+
// Always trim the Message Descriptor values.
53+
return evaluatePath(path).trim();
5654
}
5755

58-
function createMessageDescriptor(propPaths, options = {}) {
59-
const {isJSXSource = false} = options;
56+
function getICUMessageValue(messagePath, {isJSXSource = false} = {}) {
57+
let message = getMessageDescriptorValue(messagePath);
58+
59+
try {
60+
return printICUMessage(message);
61+
} catch (parseError) {
62+
if (isJSXSource &&
63+
messagePath.isLiteral() &&
64+
message.indexOf('\\\\') >= 0) {
65+
66+
throw messagePath.buildCodeFrameError(
67+
'[React Intl] Message failed to parse. ' +
68+
'It looks like `\\`s were used for escaping, ' +
69+
'this won\'t work with JSX string literals. ' +
70+
'Wrap with `{}`. ' +
71+
'See: http://facebook.github.io/react/docs/jsx-gotchas.html'
72+
);
73+
}
74+
75+
throw messagePath.buildCodeFrameError(
76+
'[React Intl] Message failed to parse. ' +
77+
'See: http://formatjs.io/guides/message-syntax/' +
78+
`\n${parseError}`
79+
);
80+
}
81+
}
6082

83+
function createMessageDescriptor(propPaths) {
6184
return propPaths.reduce((hash, [keyPath, valuePath]) => {
6285
let key = getMessageDescriptorKey(keyPath);
6386

64-
if (!DESCRIPTOR_PROPS.has(key)) {
65-
return hash;
87+
if (DESCRIPTOR_PROPS.has(key)) {
88+
hash[key] = valuePath;
6689
}
6790

68-
let value = getMessageDescriptorValue(valuePath).trim();
91+
return hash;
92+
}, {});
93+
}
6994

70-
if (key === 'defaultMessage') {
71-
try {
72-
hash[key] = printICUMessage(value);
73-
} catch (parseError) {
74-
if (isJSXSource &&
75-
valuePath.isLiteral() &&
76-
value.indexOf('\\\\') >= 0) {
77-
78-
throw valuePath.buildCodeFrameError(
79-
'[React Intl] Message failed to parse. ' +
80-
'It looks like `\\`s were used for escaping, ' +
81-
'this won\'t work with JSX string literals. ' +
82-
'Wrap with `{}`. ' +
83-
'See: http://facebook.github.io/react/docs/jsx-gotchas.html'
84-
);
85-
}
95+
function evaluateMessageDescriptor({...descriptor}, {isJSXSource = false} = {}) {
96+
Object.keys(descriptor).forEach((key) => {
97+
let valuePath = descriptor[key];
8698

87-
throw valuePath.buildCodeFrameError(
88-
'[React Intl] Message failed to parse. ' +
89-
'See: http://formatjs.io/guides/message-syntax/',
90-
parseError
91-
);
92-
}
99+
if (key === 'defaultMessage') {
100+
descriptor[key] = getICUMessageValue(valuePath, {isJSXSource});
93101
} else {
94-
hash[key] = value;
102+
descriptor[key] = getMessageDescriptorValue(valuePath);
95103
}
104+
});
96105

97-
return hash;
98-
}, {});
106+
return descriptor;
99107
}
100108

101109
function storeMessage({id, description, defaultMessage}, path, state) {
@@ -199,18 +207,22 @@ export default function () {
199207
attributes.map((attr) => [
200208
attr.get('name'),
201209
attr.get('value'),
202-
]),
203-
{isJSXSource: true}
210+
])
204211
);
205212

206213
// In order for a default message to be extracted when
207214
// declaring a JSX element, it must be done with standard
208215
// `key=value` attributes. But it's completely valid to
209-
// write `<FormattedMessage {...descriptor} />`, because it
210-
// will be skipped here and extracted elsewhere. When the
211-
// `defaultMessage` prop exists, the descriptor will be
212-
// checked.
216+
// write `<FormattedMessage {...descriptor} />` or
217+
// `<FormattedMessage id={dynamicId} />`, because it will be
218+
// skipped here and extracted elsewhere. The descriptor will
219+
// be extracted only if a `defaultMessage` prop exists.
213220
if (descriptor.defaultMessage) {
221+
// Evaluate the Message Descriptor values in a JSX
222+
// context, then store it.
223+
descriptor = evaluateMessageDescriptor(descriptor, {
224+
isJSXSource: true,
225+
});
214226
storeMessage(descriptor, path, state);
215227
}
216228
}
@@ -243,12 +255,8 @@ export default function () {
243255
])
244256
);
245257

246-
if (!descriptor.defaultMessage) {
247-
throw path.buildCodeFrameError(
248-
'[React Intl] Message is missing a `defaultMessage`.'
249-
);
250-
}
251-
258+
// Evaluate the Message Descriptor values, then store it.
259+
descriptor = evaluateMessageDescriptor(descriptor);
252260
storeMessage(descriptor, path, state);
253261
}
254262

0 commit comments

Comments
 (0)