Skip to content

Commit 760cf08

Browse files
committed
feat: support customize component
1 parent 4a00b8b commit 760cf08

File tree

8 files changed

+82
-24
lines changed

8 files changed

+82
-24
lines changed

index.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export interface Message {
2424
}
2525

2626
// This is the only JSX element we can extract messages from:
27-
type ElementName = "FormattedMessage";
27+
type ElementName = "FormattedMessage" | string;
2828
// These are the two methods we can extract messages from:
2929
type MethodName = "defineMessages" | "formatMessage";
3030
// MessageExtracter defines a function type which can extract zero or more
@@ -171,11 +171,16 @@ function findMethodCallsWithName(
171171
});
172172
return messages;
173173
}
174-
174+
export interface Options {
175+
tagNames: string[];
176+
}
175177
/**
176178
* Parse tsx files
177179
*/
178-
function main(contents: string): Message[] {
180+
function main(
181+
contents: string,
182+
options: Options = { tagNames: [] },
183+
): Message[] {
179184
const sourceFile = ts.createSourceFile(
180185
"file.ts",
181186
contents,
@@ -184,25 +189,38 @@ function main(contents: string): Message[] {
184189
ts.ScriptKind.TSX,
185190
);
186191

187-
const elements = findJsxOpeningLikeElementsWithName(
188-
sourceFile,
189-
"FormattedMessage",
190-
);
191192
const dm = findMethodCallsWithName(
192193
sourceFile,
193194
"defineMessages",
194195
extractMessagesForDefineMessages,
195196
);
197+
196198
// TODO formatMessage might not be the initializer for a VarDecl
197199
// eg console.log(formatMessage(...))
198200
const fm = findMethodCallsWithName(
199201
sourceFile,
200202
"formatMessage",
201203
extractMessagesForFormatMessage,
202204
);
205+
const results: Message[] = [];
203206

204-
// convert JsxOpeningLikeElements to Message maps
205-
const jsxMessages = elements
207+
const tagNames = ["FormattedMessage"].concat(options.tagNames);
208+
tagNames.forEach((tagName) => {
209+
const elements = findJsxOpeningLikeElementsWithName(sourceFile, tagName);
210+
// convert JsxOpeningLikeElements to Message maps
211+
const jsxMessages = getElementsMessages(elements);
212+
results.push(...jsxMessages);
213+
});
214+
215+
return results.concat(dm).concat(fm);
216+
}
217+
218+
/**
219+
* convert JsxOpeningLikeElements to Message maps
220+
* @param elements
221+
*/
222+
function getElementsMessages(elements: ts.JsxOpeningLikeElement[]) {
223+
return elements
206224
.map((element) => {
207225
const msg: Partial<Message> = {};
208226
if (element.attributes) {
@@ -238,8 +256,6 @@ function main(contents: string): Message[] {
238256
return isValidMessage(msg) ? msg : null;
239257
})
240258
.filter(notNull);
241-
242-
return jsxMessages.concat(dm).concat(fm);
243259
}
244260

245261
function notNull<T>(value: T | null): value is T {

lib/index.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ export interface Message {
66
description?: string;
77
id: string;
88
}
9+
export interface Options {
10+
tagNames: string[];
11+
}
912
/**
1013
* Parse tsx files
1114
*/
12-
declare function main(contents: string): Message[];
15+
declare function main(contents: string, options?: Options): Message[];
1316
export default main;

lib/index.js

Lines changed: 18 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/app/anotherText.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "react";
2+
import { FormattedMessage } from "react-intl";
3+
export class AnotherText extends React.Component<FormattedMessage.Props,{}> {
4+
// tslint:disable-next-line:member-access
5+
render() {
6+
return <FormattedMessage {...this.props}>
7+
{
8+
text => <span>{text}</span>
9+
}
10+
</FormattedMessage>;
11+
}
12+
}

test/app/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import React from "react";
22
import { FormattedMessage } from "react-intl";
3+
import { AnotherText } from "./anotherText";
34
import messages from "./defineMessages";
5+
import { MyComponent } from "./myComponent";
46

57
export class App extends React.Component<any, any> {
68
render() {
79
return (
810
<div>
11+
<MyComponent id='my.component' defaultMessage='my messages'/>
12+
<AnotherText id='another.text' defaultMessage='another messages'/>
913
<FormattedMessage id="app" defaultMessage="the defualt message" />
1014
<FormattedMessage {...messages.intro} />
1115
<FormattedMessage id="expr" defaultMessage={"a jsx expression"} />

test/app/myComponent.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "react";
2+
import { FormattedMessage } from "react-intl";
3+
export class MyComponent extends React.Component<FormattedMessage.Props,{}> {
4+
// tslint:disable-next-line:member-access
5+
render() {
6+
return <FormattedMessage {...this.props}>
7+
{
8+
text => <span>{text}</span>
9+
}
10+
</FormattedMessage>;
11+
}
12+
}

test/index.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var fs = require("fs");
77
test("<FormattedMessage/>", (t) => {
88
var content = fs.readFileSync(__dirname + "/app/index.tsx");
99

10-
var res = p(content.toString());
10+
var res = p(content.toString(), { tagNames: ["MyComponent", "AnotherText"] });
1111
console.log(res);
1212
var expected = [
1313
{
@@ -23,13 +23,11 @@ test("<FormattedMessage/>", (t) => {
2323
defaultMessage:
2424
"The installer has detected {numDrives, number} {numDrives, plural,\n one {drive}\n other {drives}\n } and determined {numDrives, plural,\n one {its}\n other {their}\n } best configuration.\n If this is not the intended use of {numDrives, plural,\n one {this drive}\n other {these drives}\n }, please change the configuration to your preferences.",
2525
},
26-
// {
27-
// id: "concat",
28-
// defaultMessage: "concatenated strings"
29-
// }
26+
{ id: "my.component", defaultMessage: "my messages" },
27+
{ id: 'another.text', defaultMessage: 'another messages' }
3028
];
3129

32-
t.is(res.length, 3);
30+
t.is(res.length, 5);
3331

3432
t.deepEqual(res, expected);
3533
});

0 commit comments

Comments
 (0)