Skip to content

Commit bcac5d1

Browse files
authored
feat: implement caching results feature (#75)
* feat: implement caching results feature * test: add cache tests
1 parent 4b68e77 commit bcac5d1

File tree

6 files changed

+142
-7
lines changed

6 files changed

+142
-7
lines changed

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
"prepublish": "npm run build",
2121
"build": "tsc",
2222
"lint": "eslint src/**/*.ts --fix --cache",
23-
"test": "jest"
23+
"pretest": "rimraf .test-cache",
24+
"test": "jest",
25+
"posttest": "rimraf .test-cache"
2426
},
2527
"bin": {
2628
"extract-react-intl-messages": "dist/cli.js",
@@ -41,6 +43,7 @@
4143
"dependencies": {
4244
"@babel/core": "^7.9.0",
4345
"babel-plugin-react-intl": "^7.0.0",
46+
"file-entry-cache": "^5.0.1",
4447
"flat": "^5.0.0",
4548
"glob": "^7.1.6",
4649
"js-yaml": "^3.13.1",
@@ -61,6 +64,7 @@
6164
"@babel/preset-env": "^7.9.0",
6265
"@babel/preset-flow": "^7.9.0",
6366
"@babel/preset-react": "^7.9.1",
67+
"@types/file-entry-cache": "^5.0.0",
6468
"@types/flat": "^5.0.0",
6569
"@types/glob": "^7.1.1",
6670
"@types/jest": "^25.1.4",
@@ -81,6 +85,7 @@
8185
"prettier": "^2.0.2",
8286
"react": "^16.13.1",
8387
"react-intl": "^4.2.2",
88+
"rimraf": "^3.0.2",
8489
"temp-write": "^4.0.0",
8590
"tempy": "^0.5.0",
8691
"ts-jest": "^25.2.1",

src/cli.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const cli = meow(
1515
-d, --default-locale default locale
1616
--overwriteDefault [default: true]
1717
--flat json [default: true] | yaml [default: false]
18+
--cache [default: false]
19+
--cacheLocation [default: .extract-react-intl-messages-cache]
1820
1921
Example
2022
$ extract-messages --locales=ja,en --output app/translations 'app/**/*.js'

src/extract-react-intl/index.ts

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from '@babel/core'
1212
import readBabelrcUp from 'read-babelrc-up'
1313
import babelPluginReactIntl from 'babel-plugin-react-intl'
14+
import fileEntryCache, { FileDescriptor } from 'file-entry-cache'
1415

1516
type LocaleMap = Record<string, Record<string, {}>>
1617

@@ -67,6 +68,8 @@ type Options = {
6768
[key: string]: unknown
6869
defaultLocale?: string
6970
cwd?: string
71+
cache?: boolean
72+
cacheLocation?: string
7073
withDescriptions?: boolean
7174
}
7275

@@ -76,6 +79,17 @@ type Message = {
7679
description: string
7780
}
7881

82+
type CacheData = {
83+
defaultLocale: string
84+
localeMap: LocaleMap
85+
}
86+
87+
type File = FileDescriptor & {
88+
meta: {
89+
data: CacheData
90+
}
91+
}
92+
7993
// eslint-disable-next-line max-lines-per-function
8094
export default async (
8195
locales: string[],
@@ -84,6 +98,8 @@ export default async (
8498
defaultLocale = 'en',
8599
withDescriptions = false,
86100
cwd = process.cwd(),
101+
cache: cacheEnabled = false,
102+
cacheLocation = '.extract-react-intl-messages-cache',
87103
...pluginOptions
88104
}: Options = {}
89105
) => {
@@ -122,6 +138,19 @@ export default async (
122138
})
123139
}
124140

141+
const files: string[] = await pify(glob)(pattern)
142+
if (files.length === 0) {
143+
throw new Error(`File not found (${pattern})`)
144+
}
145+
146+
const cachePath = path.resolve(cacheLocation)
147+
const cacheDirname = path.dirname(cachePath)
148+
const cacheBasename = path.basename(cachePath)
149+
150+
const cache = cacheEnabled
151+
? fileEntryCache.create(cacheBasename, cacheDirname)
152+
: null
153+
125154
const extractFromFile = async (file: string) => {
126155
const babelOpts = {
127156
presets: resolvePresets(presets, babelrcDir),
@@ -131,7 +160,6 @@ export default async (
131160
const localeObj = localeMap(locales)
132161
const result = metadata['react-intl'].messages as Message[]
133162
for (const { id, defaultMessage, description } of result) {
134-
// eslint-disable-next-line no-unused-vars
135163
for (const locale of locales) {
136164
const message = defaultLocale === locale ? defaultMessage : ''
137165
localeObj[locale][id] = withDescriptions
@@ -142,10 +170,36 @@ export default async (
142170
return localeObj
143171
}
144172

145-
const files: string[] = await pify(glob)(pattern)
146-
if (files.length === 0) {
147-
throw new Error(`File not found (${pattern})`)
173+
const extractFromCache = async (file: string) => {
174+
if (cache === null) {
175+
return extractFromFile(file)
176+
}
177+
178+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
179+
const cachedLocaleObj = cache?.getFileDescriptor(file) as File | undefined
180+
const changed = cachedLocaleObj?.changed
181+
const data = cachedLocaleObj?.meta.data
182+
183+
if (changed === false && data?.defaultLocale === defaultLocale) {
184+
return data.localeMap
185+
}
186+
187+
const localeObj = await extractFromFile(file)
188+
189+
if (cachedLocaleObj) {
190+
cachedLocaleObj.meta.data = { defaultLocale, localeMap: localeObj }
191+
}
192+
193+
return localeObj
148194
}
149-
const arr = await Promise.all(files.map(extractFromFile))
195+
196+
const extract = cacheEnabled ? extractFromCache : extractFromFile
197+
198+
const arr = await Promise.all(files.map(extract))
199+
200+
if (cache) {
201+
cache.reconcile()
202+
}
203+
150204
return arr.reduce((h, obj) => merge(h, obj), localeMap(locales))
151205
}

src/extract-react-intl/test/__snapshots__/test.ts.snap

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,52 @@ Object {
3131
}
3232
`;
3333

34+
exports[`extract from file by enabling cache and extract from cache 1`] = `
35+
Object {
36+
"en": Object {
37+
"components.App.1248161314": "Submit button",
38+
"components.App.hello": "hello",
39+
"components.App.world": "world",
40+
"components/Greeting/welcome": "
41+
Welcome {name}, you have received {unreadCount, plural,
42+
=0 {no new messages}
43+
one {{formattedUnreadCount} new message}
44+
other {{formattedUnreadCount} new messages}
45+
} since {formattedLastLoginTime}.
46+
",
47+
},
48+
"ja": Object {
49+
"components.App.1248161314": "",
50+
"components.App.hello": "",
51+
"components.App.world": "",
52+
"components/Greeting/welcome": "",
53+
},
54+
}
55+
`;
56+
57+
exports[`extract from file by enabling cache and extract from cache 2`] = `
58+
Object {
59+
"en": Object {
60+
"components.App.1248161314": "Submit button",
61+
"components.App.hello": "hello",
62+
"components.App.world": "world",
63+
"components/Greeting/welcome": "
64+
Welcome {name}, you have received {unreadCount, plural,
65+
=0 {no new messages}
66+
one {{formattedUnreadCount} new message}
67+
other {{formattedUnreadCount} new messages}
68+
} since {formattedLastLoginTime}.
69+
",
70+
},
71+
"ja": Object {
72+
"components.App.1248161314": "",
73+
"components.App.hello": "",
74+
"components.App.world": "",
75+
"components/Greeting/welcome": "",
76+
},
77+
}
78+
`;
79+
3480
exports[`extract from file with descriptions 1`] = `
3581
Object {
3682
"en": Object {

src/extract-react-intl/test/test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,27 @@ test('extract from file', async () => {
1313
expect(x).toMatchSnapshot()
1414
})
1515

16+
test('extract from file by enabling cache and extract from cache', async () => {
17+
process.env.BABEL_ENV = 'react-intl'
18+
const x = await m(locales, pattern, {
19+
defaultLocale: 'en',
20+
cwd: `${__dirname}/fixtures`,
21+
extractFromFormatMessageCall: true,
22+
cache: true,
23+
cacheLocation: '.test-cache'
24+
})
25+
expect(x).toMatchSnapshot()
26+
27+
const y = await m(locales, pattern, {
28+
defaultLocale: 'en',
29+
cwd: `${__dirname}/fixtures`,
30+
extractFromFormatMessageCall: true,
31+
cache: true,
32+
cacheLocation: '.test-cache'
33+
})
34+
expect(y).toMatchSnapshot()
35+
})
36+
1637
// TODO: fix
1738
test.skip('babelrc path resolution', async () => {
1839
const x = await m(['en'], './extract-react-intl/test/resolution/**/*.js', {

yarn.lock

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,13 @@
11651165
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
11661166
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
11671167

1168+
"@types/file-entry-cache@^5.0.0":
1169+
version "5.0.0"
1170+
resolved "https://registry.yarnpkg.com/@types/file-entry-cache/-/file-entry-cache-5.0.0.tgz#84dced293b3b80485afd454696eb4c420c7591ae"
1171+
integrity sha512-K1Q4O4PwDaMG3hOfvnWNtmjbUHHRkxeYfMlUCoT1abxeaYM0H8aDLE5wFcI29PNWhBdcES9VtACAMnAM8IerOQ==
1172+
dependencies:
1173+
"@types/node" "*"
1174+
11681175
"@types/flat@^5.0.0":
11691176
version "5.0.0"
11701177
resolved "https://registry.yarnpkg.com/@types/flat/-/flat-5.0.0.tgz#de18742aea57ce3dd2c093c7d2ba8fd3a4135b53"
@@ -5262,7 +5269,7 @@ rimraf@2.6.3:
52625269
dependencies:
52635270
glob "^7.1.3"
52645271

5265-
rimraf@^3.0.0:
5272+
rimraf@^3.0.0, rimraf@^3.0.2:
52665273
version "3.0.2"
52675274
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
52685275
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==

0 commit comments

Comments
 (0)