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

Commit 843d82b

Browse files
feat(@formatjs/cli): Add option to ignore a glob of files (#564)
Co-authored-by: Donovan Hiland <[email protected]>
1 parent dafa46b commit 843d82b

File tree

10 files changed

+198
-13
lines changed

10 files changed

+198
-13
lines changed

.all-contributorsrc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@
2626
"test",
2727
"code"
2828
]
29+
},
30+
{
31+
"login": "donovanhiland",
32+
"name": "Donovan Hiland",
33+
"avatar_url": "https://avatars2.githubusercontent.com/u/17991396?v=4",
34+
"profile": "https://github.com/donovanhiland",
35+
"contributions": [
36+
"code",
37+
"test",
38+
]
2939
}
3040
],
3141
"contributorsPerLine": 7,

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
44

5-
[![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-)
5+
[![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg?style=flat-square)](#contributors-)
66

77
<!-- ALL-CONTRIBUTORS-BADGE:END -->
88

@@ -62,6 +62,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
6262
<tr>
6363
<td align="center"><a href="https://github.com/pyrocat101"><img src="https://avatars0.githubusercontent.com/u/541540?v=4" width="100px;" alt=""/><br /><sub><b>Linjie Ding</b></sub></a><br /><a href="#infra-pyrocat101" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/formatjs/formatjs/commits?author=pyrocat101" title="Tests">⚠️</a> <a href="https://github.com/formatjs/formatjs/commits?author=pyrocat101" title="Code">💻</a></td>
6464
<td align="center"><a href="https://medium.com/@longho"><img src="https://avatars1.githubusercontent.com/u/198255?v=4" width="100px;" alt=""/><br /><sub><b>Long Ho</b></sub></a><br /><a href="#infra-longlho" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/formatjs/formatjs/commits?author=longlho" title="Tests">⚠️</a> <a href="https://github.com/formatjs/formatjs/commits?author=longlho" title="Code">💻</a></td>
65+
<td align="center"><a href="https://github.com/donovanhiland"><img src="https://avatars2.githubusercontent.com/u/17991396?v=4" width="100px;" alt=""/><br /><sub><b>Donovan Hiland</b></sub></a><br /><a href="https://github.com/formatjs/formatjs/commits?author=donovanhiland" title="Code">💻</a><a href="https://github.com/formatjs/formatjs/commits?author=longlho" title="Tests">⚠️</a></td>
6566
</tr>
6667
</table>
6768

packages/cli/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@ Options:
4141
restrictions, e.g: has to be called with object literal such as
4242
`intl.formatMessage({ id: 'foo', defaultMessage: 'bar',
4343
description: 'baz'})` (default: false)
44+
--ignore List of glob paths to **not** extract translations from.
4445
-h, --help output usage information
4546
```

packages/cli/src/cli.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,21 @@ async function main(argv: string[]) {
9898
].join(''),
9999
false
100100
)
101+
.option(
102+
'--ignore <files>',
103+
'List of glob paths to **not** extract translations from.'
104+
)
101105
.action(async (files: readonly string[], cmdObj: ExtractCLIOptions) => {
102-
files = files.reduce(
103-
(all: string[], f) =>
104-
all.concat(
105-
globSync(f, {
106-
cwd: process.cwd(),
107-
})
108-
),
109-
[]
110-
);
111-
await extract(files, {
106+
const processedFiles = [];
107+
for (const f of files) {
108+
processedFiles.push(
109+
...globSync(f, {
110+
cwd: process.cwd(),
111+
ignore: cmdObj.ignore,
112+
})
113+
);
114+
}
115+
await extract(processedFiles, {
112116
outFile: cmdObj.outFile,
113117
idInterpolationPattern:
114118
cmdObj.idInterpolationPattern || '[contenthash:5]',

packages/cli/src/extract.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import {warn, getStdinAsString} from './console_utils';
55
import keyBy from 'lodash/keyBy';
66
import {outputJSONSync} from 'fs-extra';
77
import {interpolateName} from 'loader-utils';
8+
import {IOptions as GlobOptions} from 'glob';
89

910
export type ExtractCLIOptions = Omit<OptionsSchema, 'overrideIdFn'> & {
1011
outFile?: string;
1112
idInterpolationPattern?: string;
13+
ignore?: GlobOptions['ignore'];
1214
};
1315

1416
function getBabelConfig(

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

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
exports[`[glob] basic case: defineMessages -> stdout 1`] = `
44
Array [
5+
Object {
6+
"defaultMessage": "ignore",
7+
"id": "ignore",
8+
},
59
Object {
610
"defaultMessage": "Hello World!",
711
"description": "The default message",
@@ -128,10 +132,90 @@ Options:
128132
--remove-default-message Remove \`defaultMessage\` field in generated js after extraction (default: false)
129133
--additional-component-names <comma-separated-names> Additional component names to extract messages from, e.g: \`['FormattedFooBarMessage']\`. **NOTE**: By default we check for the fact that \`FormattedMessage\` & \`FormattedHTMLMessage\` are imported from \`moduleSourceName\` to make sure variable alias works. This option does not do that so it's less safe.
130134
--extract-from-format-message-call Opt-in to extract from \`intl.formatMessage\` call with the same restrictions, e.g: has to be called with object literal such as \`intl.formatMessage({ id: 'foo', defaultMessage: 'bar', description: 'baz'})\` (default: false)
135+
--ignore <files> List of glob paths to **not** extract translations from.
131136
-h, --help output usage information
132137
"
133138
`;
134139
140+
exports[`ignore -> stdout 1`] = `
141+
Array [
142+
Object {
143+
"defaultMessage": "Hello World!",
144+
"description": "The default message",
145+
"id": "foo.bar.baz",
146+
},
147+
Object {
148+
"defaultMessage": "Hello Nurse!",
149+
"description": "Another message",
150+
"id": "foo.bar.biff",
151+
},
152+
Object {
153+
"defaultMessage": "{count, plural, =0 {😭} one {# kitten} other {# kittens}}",
154+
"description": "Counts kittens",
155+
"id": "app.home.kittens",
156+
},
157+
Object {
158+
"defaultMessage": " Some whitespace ",
159+
"description": "Whitespace",
160+
"id": "trailing.ws",
161+
},
162+
Object {
163+
"defaultMessage": "A quoted value ''{value}'",
164+
"description": "Escaped apostrophe",
165+
"id": "escaped.apostrophe",
166+
},
167+
Object {
168+
"defaultMessage": "No ID",
169+
"description": "no ID",
170+
"id": "ae494",
171+
},
172+
Object {
173+
"defaultMessage": "formatted message",
174+
"description": "foo",
175+
"id": "inline",
176+
},
177+
]
178+
`;
179+
180+
exports[`ignore -> stdout 2`] = `
181+
Array [
182+
Object {
183+
"defaultMessage": "ignore",
184+
"id": "ignore",
185+
},
186+
Object {
187+
"defaultMessage": "Hello World!",
188+
"description": "The default message",
189+
"id": "foo.bar.baz",
190+
},
191+
Object {
192+
"defaultMessage": "Hello Nurse!",
193+
"description": "Another message",
194+
"id": "foo.bar.biff",
195+
},
196+
Object {
197+
"defaultMessage": "{count, plural, =0 {😭} one {# kitten} other {# kittens}}",
198+
"description": "Counts kittens",
199+
"id": "app.home.kittens",
200+
},
201+
Object {
202+
"defaultMessage": " Some whitespace ",
203+
"description": "Whitespace",
204+
"id": "trailing.ws",
205+
},
206+
Object {
207+
"defaultMessage": "A quoted value ''{value}'",
208+
"description": "Escaped apostrophe",
209+
"id": "escaped.apostrophe",
210+
},
211+
Object {
212+
"defaultMessage": "No ID",
213+
"description": "no ID",
214+
"id": "ae494",
215+
},
216+
]
217+
`;
218+
135219
exports[`typescript -> stdout 1`] = `
136220
Array [
137221
Object {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React, {Component} from 'react';
2+
import {defineMessages, FormattedMessage} from 'react-intl';
3+
4+
const msgs = defineMessages({
5+
test: {
6+
id: 'ignore',
7+
defaultMessage: 'ignore',
8+
},
9+
});
10+
11+
export default class Foo extends Component {
12+
render() {
13+
return (
14+
<div>
15+
<h1>
16+
<FormattedMessage {...msgs.test} />
17+
</h1>
18+
</div>
19+
);
20+
}
21+
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,25 @@ test('typescript -> stdout', async () => {
5959
expect(JSON.parse(stdout)).toMatchSnapshot();
6060
expect(stderr).toBe('');
6161
}, 10000);
62+
63+
test('ignore -> stdout', async () => {
64+
const ignore = "--ignore '*.ignore.*'";
65+
66+
const tsResult = await exec(
67+
`${BIN_PATH} extract ${path.join(
68+
__dirname,
69+
'typescript/actual.tsx'
70+
)} ${ignore}`
71+
);
72+
expect(JSON.parse(tsResult.stdout)).toMatchSnapshot();
73+
expect(tsResult.stderr).toBe('');
74+
75+
const jsResult = await exec(
76+
`${BIN_PATH} extract ${path.join(
77+
__dirname,
78+
'defineMessages/*.js'
79+
)} ${ignore}`
80+
);
81+
expect(JSON.parse(jsResult.stdout)).toMatchSnapshot();
82+
expect(jsResult.stderr).toBe('');
83+
}, 10000);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React, {Component} from 'react';
2+
import {defineMessages, FormattedMessage} from 'react-intl';
3+
4+
const msgs = defineMessages({
5+
test: {
6+
id: 'ignore',
7+
defaultMessage: 'ignore',
8+
},
9+
});
10+
11+
export default class Foo extends Component {
12+
render() {
13+
return (
14+
<div>
15+
<h1>
16+
<FormattedMessage {...msgs.test} />
17+
</h1>
18+
</div>
19+
);
20+
}
21+
}

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import cliMain from '../../src/cli';
22
import {OptionsSchema} from 'babel-plugin-react-intl/dist/options';
3+
const glob = require('glob');
4+
const babel = require('@babel/core');
35

46
jest.mock('@babel/core', () => {
57
const mockBabelResult = {
@@ -13,13 +15,12 @@ jest.mock('@babel/core', () => {
1315
transformFileSync: jest.fn().mockReturnValue(mockBabelResult),
1416
};
1517
});
16-
const babel = require('@babel/core');
1718

1819
// Commander.js will call this.
1920
jest.spyOn(process, 'exit').mockImplementation((() => null) as any);
2021

2122
jest.mock('glob', () => ({
22-
sync: (p: string) => [p],
23+
sync: jest.fn((p: string) => [p]),
2324
}));
2425

2526
beforeEach(() => {
@@ -38,6 +39,7 @@ test('it passes camelCase-converted arguments to babel API', () => {
3839
'--extract-from-format-message-call',
3940
'--additional-component-names',
4041
'Foo,Bar',
42+
'--ignore=file3.ts',
4143
'file1.js',
4244
'file2.tsx',
4345
]);
@@ -81,3 +83,20 @@ test('it passes camelCase-converted arguments to babel API', () => {
8183
})
8284
);
8385
});
86+
87+
test('it passes ignore argument to glob sync', () => {
88+
cliMain([
89+
'node',
90+
'path/to/formatjs-cli',
91+
'extract',
92+
'--ignore=ignore-1.ts',
93+
'include-1.js',
94+
]);
95+
96+
expect(glob.sync).toHaveBeenCalled();
97+
expect(glob.sync).toHaveBeenNthCalledWith(
98+
1,
99+
'include-1.js',
100+
expect.objectContaining({ignore: 'ignore-1.ts'})
101+
);
102+
});

0 commit comments

Comments
 (0)