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

Commit 54a7aea

Browse files
authored
fix(@formatjs/cli): do not read from stdin if glob pattern is pr… (#632)
1 parent ff09a5f commit 54a7aea

File tree

6 files changed

+81
-107
lines changed

6 files changed

+81
-107
lines changed

packages/cli/package-lock.json

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

packages/cli/src/cli.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ async function main(argv: string[]) {
118118
\`\`\`
119119
// @intl-meta project:my-custom-project
120120
import {FormattedMessage} from 'react-intl';
121-
121+
122122
<FormattedMessage defaultMessage="foo" id="bar" />;
123123
\`\`\`
124-
124+
125125
and with option \`{pragma: "@intl-meta"}\`, we'll parse out \`// @intl-meta project:my-custom-project\` into \`{project: 'my-custom-project'}\` in the result file.`
126126
)
127127
.action(async (files: readonly string[], cmdObj: ExtractCLIOptions) => {
@@ -146,6 +146,9 @@ async function main(argv: string[]) {
146146
extractFromFormatMessageCall: cmdObj.extractFromFormatMessageCall,
147147
outputEmptyJson: cmdObj.outputEmptyJson,
148148
pragma: cmdObj.pragma,
149+
// It is possible that the glob pattern does NOT match anything.
150+
// But so long as the glob pattern is provided, don't read from stdin.
151+
readFromStdin: files.length === 0,
149152
});
150153
process.exit(0);
151154
});

packages/cli/src/extract.ts

Lines changed: 63 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type ExtractCLIOptions = Omit<ExtractOptions, 'overrideIdFn'> & {
1313
export type ExtractOptions = OptionsSchema & {
1414
throws?: boolean;
1515
idInterpolationPattern?: string;
16+
readFromStdin?: boolean;
1617
};
1718

1819
function getBabelConfig(
@@ -62,69 +63,71 @@ function getBabelConfig(
6263

6364
export async function extract(
6465
files: readonly string[],
65-
{idInterpolationPattern, throws, ...babelOpts}: ExtractOptions
66-
) {
67-
if (files.length > 0) {
68-
const results = await Promise.all(
69-
files.map(filename => {
70-
if (!babelOpts.overrideIdFn && idInterpolationPattern) {
71-
babelOpts = {
72-
...babelOpts,
73-
overrideIdFn: (id, defaultMessage, description) =>
74-
id ||
75-
interpolateName(
76-
{
77-
resourcePath: filename,
78-
} as any,
79-
idInterpolationPattern,
80-
{content: `${defaultMessage}#${description}`}
81-
),
82-
};
83-
}
84-
const promise = babel.transformFileAsync(
85-
filename,
86-
getBabelConfig(babelOpts, {filename: filename})
87-
);
88-
return throws ? promise : promise.catch(e => warn(e));
89-
})
66+
{idInterpolationPattern, throws, readFromStdin, ...babelOpts}: ExtractOptions
67+
): Promise<ExtractionResult[]> {
68+
if (readFromStdin) {
69+
// Read from stdin
70+
if (process.stdin.isTTY) {
71+
warn('Reading source file from TTY.');
72+
}
73+
if (!babelOpts.overrideIdFn && idInterpolationPattern) {
74+
babelOpts = {
75+
...babelOpts,
76+
overrideIdFn: (id, defaultMessage, description) =>
77+
id ||
78+
interpolateName(
79+
{
80+
resourcePath: 'dummy',
81+
} as any,
82+
idInterpolationPattern,
83+
{content: `${defaultMessage}#${description}`}
84+
),
85+
};
86+
}
87+
const stdinSource = await getStdinAsString();
88+
const babelResult = babel.transformSync(
89+
stdinSource,
90+
getBabelConfig(babelOpts)
9091
);
91-
return results
92-
.filter(r => r && r.metadata)
93-
.map(
94-
r =>
95-
((r as babel.BabelFileResult).metadata as any)[
96-
'react-intl'
97-
] as ExtractionResult
98-
);
99-
}
100-
if (files.length === 0 && process.stdin.isTTY) {
101-
warn('Reading source file from TTY.');
102-
}
103-
if (!babelOpts.overrideIdFn && idInterpolationPattern) {
104-
babelOpts = {
105-
...babelOpts,
106-
overrideIdFn: (id, defaultMessage, description) =>
107-
id ||
108-
interpolateName(
109-
{
110-
resourcePath: 'dummy',
111-
} as any,
112-
idInterpolationPattern,
113-
{content: `${defaultMessage}#${description}`}
114-
),
115-
};
92+
93+
return [
94+
((babelResult as babel.BabelFileResult).metadata as any)[
95+
'react-intl'
96+
] as ExtractionResult,
97+
];
11698
}
117-
const stdinSource = await getStdinAsString();
118-
const babelResult = babel.transformSync(
119-
stdinSource,
120-
getBabelConfig(babelOpts)
121-
);
12299

123-
return [
124-
((babelResult as babel.BabelFileResult).metadata as any)[
125-
'react-intl'
126-
] as ExtractionResult,
127-
];
100+
const results = await Promise.all(
101+
files.map(filename => {
102+
if (!babelOpts.overrideIdFn && idInterpolationPattern) {
103+
babelOpts = {
104+
...babelOpts,
105+
overrideIdFn: (id, defaultMessage, description) =>
106+
id ||
107+
interpolateName(
108+
{
109+
resourcePath: filename,
110+
} as any,
111+
idInterpolationPattern,
112+
{content: `${defaultMessage}#${description}`}
113+
),
114+
};
115+
}
116+
const promise = babel.transformFileAsync(
117+
filename,
118+
getBabelConfig(babelOpts, {filename: filename})
119+
);
120+
return throws ? promise : promise.catch(e => warn(e));
121+
})
122+
);
123+
return results
124+
.filter(r => r && r.metadata)
125+
.map(
126+
r =>
127+
((r as babel.BabelFileResult).metadata as any)[
128+
'react-intl'
129+
] as ExtractionResult
130+
);
128131
}
129132

130133
export default async function extractAndWrite(

packages/cli/tests/extract/integration_tests/__snapshots__/index.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,10 @@ Options:
235235
\`\`\`
236236
// @intl-meta project:my-custom-project
237237
import {FormattedMessage} from 'react-intl';
238-
238+
239239
<FormattedMessage defaultMessage=\\"foo\\" id=\\"bar\\" />;
240240
\`\`\`
241-
241+
242242
and with option \`{pragma: \\"@intl-meta\\"}\`, we'll parse out \`// @intl-meta project:my-custom-project\` into \`{project: 'my-custom-project'}\` in the result file.
243243
-h, --help display help for command
244244
"

packages/cli/tests/extract/unit.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,11 @@ test('it passes ignore argument to glob sync', () => {
107107
expect.objectContaining({ignore: 'ignore-1.ts'})
108108
);
109109
});
110+
111+
test('does not read from stdin when the glob pattern does NOT match anything', async () => {
112+
// Does not match anything
113+
jest.spyOn(glob, 'sync').mockImplementation(() => []);
114+
// This should not hang
115+
await cliMain(['node', 'path/to/formatjs-cli', 'extract', '*.doesnotexist']);
116+
expect(babel.transformFileAsync).not.toHaveBeenCalled();
117+
}, 500); // 500ms timeout

packages/intl-unified-numberformat/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
"benchmark": "ts-node --project ./tsconfig.cjs.json tests/benchmark",
3737
"build": "npm run cldr && npm run compile && npm run rollup ",
3838
"cldr": "NODE_OPTIONS=--max-old-space-size=8192 ts-node --project tsconfig.cjs.json scripts/cldr",
39-
"clean": "rimraf dist dist-es6 lib",
40-
"compile": "tsc && tsc -p tsconfig.cjs.json && tsc -p tsconfig.es6.json && api-extractor run --local",
39+
"clean": "rimraf dist dist-es6 lib src/locales.ts",
40+
"compile": "NODE_OPTIONS=--max-old-space-size=8192 tsc && tsc -p tsconfig.cjs.json && tsc -p tsconfig.es6.json && api-extractor run --local",
4141
"jest": "cross-env NODE_ICU_DATA=../../node_modules/full-icu TS_NODE_PROJECT=tsconfig.cjs.json cross-env NODE_ENV=test jest",
4242
"rollup": "NODE_OPTIONS=--max-old-space-size=8192 rollup -c rollup.config.js",
4343
"test": "npm run jest",

0 commit comments

Comments
 (0)