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

Commit ed5dd00

Browse files
authored
Hoist state to file level (#96)
This fixes issues without writing the extracted messages out to the filesystem when multiple instances of the plugin are being applied. This also removes the CLI usage docs which say to use `--plugins` option because this is not useful for this plugin since it needs to be configured via `.babelrc` or use via Babel's API. Fixes #92
1 parent ef4ef93 commit ed5dd00

File tree

2 files changed

+49
-54
lines changed

2 files changed

+49
-54
lines changed

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,6 @@ If a message descriptor has a `description`, it'll be removed from the source af
4242

4343
- **`moduleSourceName`**: The ES6 module source name of the React Intl package. Defaults to: `"react-intl"`, but can be changed to another name/path to React Intl.
4444

45-
### Via CLI
46-
47-
```sh
48-
$ babel --plugins react-intl script.js
49-
```
50-
5145
### Via Node API
5246

5347
The extract message descriptors are available via the `metadata` property on the object returned from Babel's `transform()` API:

src/index.js

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@ const FUNCTION_NAMES = [
2020

2121
const DESCRIPTOR_PROPS = new Set(['id', 'description', 'defaultMessage']);
2222

23-
const EXTRACTED_TAG = Symbol('ReactIntlExtracted');
23+
const EXTRACTED = Symbol('ReactIntlExtracted');
24+
const MESSAGES = Symbol('ReactIntlMessages');
2425

2526
export default function ({types: t}) {
2627
function getModuleSourceName(opts) {
2728
return opts.moduleSourceName || 'react-intl';
2829
}
2930

3031
function evaluatePath(path) {
31-
let evaluated = path.evaluate();
32+
const evaluated = path.evaluate();
3233
if (evaluated.confident) {
3334
return evaluated.value;
3435
}
@@ -62,7 +63,7 @@ export default function ({types: t}) {
6263
}
6364

6465
function getICUMessageValue(messagePath, {isJSXSource = false} = {}) {
65-
let message = getMessageDescriptorValue(messagePath);
66+
const message = getMessageDescriptorValue(messagePath);
6667

6768
try {
6869
return printICUMessage(message);
@@ -90,7 +91,7 @@ export default function ({types: t}) {
9091

9192
function createMessageDescriptor(propPaths) {
9293
return propPaths.reduce((hash, [keyPath, valuePath]) => {
93-
let key = getMessageDescriptorKey(keyPath);
94+
const key = getMessageDescriptorKey(keyPath);
9495

9596
if (DESCRIPTOR_PROPS.has(key)) {
9697
hash[key] = valuePath;
@@ -102,7 +103,7 @@ export default function ({types: t}) {
102103

103104
function evaluateMessageDescriptor({...descriptor}, {isJSXSource = false} = {}) {
104105
Object.keys(descriptor).forEach((key) => {
105-
let valuePath = descriptor[key];
106+
const valuePath = descriptor[key];
106107

107108
if (key === 'defaultMessage') {
108109
descriptor[key] = getICUMessageValue(valuePath, {isJSXSource});
@@ -115,16 +116,17 @@ export default function ({types: t}) {
115116
}
116117

117118
function storeMessage({id, description, defaultMessage}, path, state) {
118-
const {file, opts, reactIntl} = state;
119+
const {file, opts} = state;
119120

120121
if (!(id && defaultMessage)) {
121122
throw path.buildCodeFrameError(
122123
'[React Intl] Message Descriptors require an `id` and `defaultMessage`.'
123124
);
124125
}
125126

126-
if (reactIntl.messages.has(id)) {
127-
let existing = reactIntl.messages.get(id);
127+
const messages = file.get(MESSAGES);
128+
if (messages.has(id)) {
129+
const existing = messages.get(id);
128130

129131
if (description !== existing.description ||
130132
defaultMessage !== existing.defaultMessage) {
@@ -155,7 +157,7 @@ export default function ({types: t}) {
155157
};
156158
}
157159

158-
reactIntl.messages.set(id, {id, description, defaultMessage, ...loc});
160+
messages.set(id, {id, description, defaultMessage, ...loc});
159161
}
160162

161163
function referencesImport(path, mod, importedNames) {
@@ -167,51 +169,50 @@ export default function ({types: t}) {
167169
}
168170

169171
function tagAsExtracted(path) {
170-
path.node[EXTRACTED_TAG] = true;
172+
path.node[EXTRACTED] = true;
171173
}
172174

173175
function wasExtracted(path) {
174-
return !!path.node[EXTRACTED_TAG];
176+
return !!path.node[EXTRACTED];
175177
}
176178

177179
return {
178-
visitor: {
179-
Program: {
180-
enter(path, state) {
181-
state.reactIntl = {
182-
messages: new Map(),
183-
};
184-
},
185-
186-
exit(path, state) {
187-
const {file, opts, reactIntl} = state;
188-
const {basename, filename} = file.opts;
189-
190-
let descriptors = [...reactIntl.messages.values()];
191-
file.metadata['react-intl'] = {messages: descriptors};
192-
193-
if (opts.messagesDir && descriptors.length > 0) {
194-
// Make sure the relative path is "absolute" before
195-
// joining it with the `messagesDir`.
196-
let relativePath = p.join(
197-
p.sep,
198-
p.relative(process.cwd(), filename)
199-
);
180+
pre(file) {
181+
if (!file.has(MESSAGES)) {
182+
file.set(MESSAGES, new Map());
183+
}
184+
},
200185

201-
let messagesFilename = p.join(
202-
opts.messagesDir,
203-
p.dirname(relativePath),
204-
basename + '.json'
205-
);
186+
post(file) {
187+
const {opts} = this;
188+
const {basename, filename} = file.opts;
206189

207-
let messagesFile = JSON.stringify(descriptors, null, 2);
190+
const messages = file.get(MESSAGES);
191+
const descriptors = [...messages.values()];
192+
file.metadata['react-intl'] = {messages: descriptors};
208193

209-
mkdirpSync(p.dirname(messagesFilename));
210-
writeFileSync(messagesFilename, messagesFile);
211-
}
212-
},
213-
},
194+
if (opts.messagesDir && descriptors.length > 0) {
195+
// Make sure the relative path is "absolute" before
196+
// joining it with the `messagesDir`.
197+
const relativePath = p.join(
198+
p.sep,
199+
p.relative(process.cwd(), filename)
200+
);
214201

202+
const messagesFilename = p.join(
203+
opts.messagesDir,
204+
p.dirname(relativePath),
205+
basename + '.json'
206+
);
207+
208+
const messagesFile = JSON.stringify(descriptors, null, 2);
209+
210+
mkdirpSync(p.dirname(messagesFilename));
211+
writeFileSync(messagesFilename, messagesFile);
212+
}
213+
},
214+
215+
visitor: {
215216
JSXOpeningElement(path, state) {
216217
if (wasExtracted(path)) {
217218
return;
@@ -232,7 +233,7 @@ export default function ({types: t}) {
232233
}
233234

234235
if (referencesImport(name, moduleSourceName, COMPONENT_NAMES)) {
235-
let attributes = path.get('attributes')
236+
const attributes = path.get('attributes')
236237
.filter((attr) => attr.isJSXAttribute());
237238

238239
let descriptor = createMessageDescriptor(
@@ -260,7 +261,7 @@ export default function ({types: t}) {
260261

261262
// Remove description since it's not used at runtime.
262263
attributes.some((attr) => {
263-
let ketPath = attr.get('name');
264+
const ketPath = attr.get('name');
264265
if (getMessageDescriptorKey(ketPath) === 'description') {
265266
attr.remove();
266267
return true;
@@ -295,7 +296,7 @@ export default function ({types: t}) {
295296
return;
296297
}
297298

298-
let properties = messageObj.get('properties');
299+
const properties = messageObj.get('properties');
299300

300301
let descriptor = createMessageDescriptor(
301302
properties.map((prop) => [
@@ -325,7 +326,7 @@ export default function ({types: t}) {
325326
}
326327

327328
if (referencesImport(callee, moduleSourceName, FUNCTION_NAMES)) {
328-
let messagesObj = path.get('arguments')[0];
329+
const messagesObj = path.get('arguments')[0];
329330

330331
assertObjectExpression(messagesObj);
331332

0 commit comments

Comments
 (0)