From 06537faad1c8d02e2bd9b14f7c6fcda348adc5be Mon Sep 17 00:00:00 2001 From: akameco Date: Sat, 24 Aug 2019 19:56:07 +0900 Subject: [PATCH] feat: rewrite TypeScript (#46) --- .eslintrc | 5 +- .gitignore | 2 + cli.js | 6 +- index.js | 125 +-------------- jest.config.js | 12 ++ package.json | 22 ++- readme.md | 8 - src/babel__core.d.ts | 6 + .../extract-react-intl/index.ts | 88 +++++++---- .../extract-react-intl}/readme.md | 0 .../test/__snapshots__/test.ts.snap | 10 +- .../test/fixtures/.babelrc | 2 +- .../test/fixtures/components/App/index.js | 0 .../test/fixtures/components/App/messages.js | 0 .../fixtures/components/Greeting/index.js | 0 .../fixtures/components/Greeting/messages.js | 0 .../components/LanguageProvider/index.js | 0 .../test/fixtures/index.html | 0 .../test/fixtures/index.js | 0 .../test/pluginOrdering/.babelrc | 0 .../test/pluginOrdering/messages.js | 0 .../test/resolution/.babelrc | 0 .../test/resolution/messages.js | 0 .../extract-react-intl/test/test.ts | 12 +- src/global.d.ts | 5 + src/index.ts | 130 +++++++++++++++ .../test}/fixtures/custom/a/messages.js | 0 .../test}/fixtures/custom/b/messages.js | 0 {test => src/test}/fixtures/custom/i18n.js | 0 .../test}/fixtures/default/a/messages.js | 0 .../test}/fixtures/default/b/messages.js | 0 .../test}/fixtures/removed/a/messages.js | 0 .../test}/fixtures/removed/b/messages.js | 0 .../test}/fixtures/unsorted/a/messages.js | 0 .../test}/fixtures/unsorted/b/messages.js | 0 .../test/json/__snapshots__/test.ts.snap | 0 test/json/test.js => src/test/json/test.ts | 31 ++-- test/test.js => src/test/test.ts | 5 +- .../test/yaml/__snapshots__/test.ts.snap | 0 test/yaml/test.js => src/test/yaml/test.ts | 37 +++-- tsconfig.json | 7 + yarn.lock | 149 +++++++++++++++--- 42 files changed, 429 insertions(+), 233 deletions(-) create mode 100644 jest.config.js create mode 100644 src/babel__core.d.ts rename extract-react-intl/index.js => src/extract-react-intl/index.ts (52%) rename {extract-react-intl => src/extract-react-intl}/readme.md (100%) rename extract-react-intl/test/__snapshots__/test.js.snap => src/extract-react-intl/test/__snapshots__/test.ts.snap (91%) rename {extract-react-intl => src/extract-react-intl}/test/fixtures/.babelrc (87%) rename {extract-react-intl => src/extract-react-intl}/test/fixtures/components/App/index.js (100%) rename {extract-react-intl => src/extract-react-intl}/test/fixtures/components/App/messages.js (100%) rename {extract-react-intl => src/extract-react-intl}/test/fixtures/components/Greeting/index.js (100%) rename {extract-react-intl => src/extract-react-intl}/test/fixtures/components/Greeting/messages.js (100%) rename {extract-react-intl => src/extract-react-intl}/test/fixtures/components/LanguageProvider/index.js (100%) rename {extract-react-intl => src/extract-react-intl}/test/fixtures/index.html (100%) rename {extract-react-intl => src/extract-react-intl}/test/fixtures/index.js (100%) rename {extract-react-intl => src/extract-react-intl}/test/pluginOrdering/.babelrc (100%) rename {extract-react-intl => src/extract-react-intl}/test/pluginOrdering/messages.js (100%) rename {extract-react-intl => src/extract-react-intl}/test/resolution/.babelrc (100%) rename {extract-react-intl => src/extract-react-intl}/test/resolution/messages.js (100%) rename extract-react-intl/test/test.js => src/extract-react-intl/test/test.ts (77%) create mode 100644 src/global.d.ts create mode 100644 src/index.ts rename {test => src/test}/fixtures/custom/a/messages.js (100%) rename {test => src/test}/fixtures/custom/b/messages.js (100%) rename {test => src/test}/fixtures/custom/i18n.js (100%) rename {test => src/test}/fixtures/default/a/messages.js (100%) rename {test => src/test}/fixtures/default/b/messages.js (100%) rename {test => src/test}/fixtures/removed/a/messages.js (100%) rename {test => src/test}/fixtures/removed/b/messages.js (100%) rename {test => src/test}/fixtures/unsorted/a/messages.js (100%) rename {test => src/test}/fixtures/unsorted/b/messages.js (100%) rename test/json/__snapshots__/test.js.snap => src/test/json/__snapshots__/test.ts.snap (100%) rename test/json/test.js => src/test/json/test.ts (70%) rename test/test.js => src/test/test.ts (78%) rename test/yaml/__snapshots__/test.js.snap => src/test/yaml/__snapshots__/test.ts.snap (100%) rename test/yaml/test.js => src/test/yaml/test.ts (54%) create mode 100644 tsconfig.json diff --git a/.eslintrc b/.eslintrc index 986d8cc..a11d5ca 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,6 @@ { - "extends": ["precure/oss"], + "extends": ["precure/auto"], + "rules": { + "@typescript-eslint/explicit-function-return-type": "off" + } } diff --git a/.gitignore b/.gitignore index 14eff2e..6a1b4fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules lib example/i18n +dist +.eslintcache diff --git a/cli.js b/cli.js index df84382..fc42b16 100755 --- a/cli.js +++ b/cli.js @@ -1,5 +1,5 @@ #!/usr/bin/env node -/* eslint-disable no-console */ +/* eslint-disable no-console, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ 'use strict' const meow = require('meow') const fn = require('.') @@ -16,7 +16,6 @@ const cli = meow( -f, --format json | yaml [default: json] -d, --default-locale default locale --flat json [default: true] | yaml [default: false] - --module-name module source name from where components are imported Example $ extract-messages --locales=ja,en --output app/translations 'app/**/*.js' @@ -44,9 +43,6 @@ const cli = meow( type: 'string', alias: 'd' }, - 'module-name': { - type: 'string' - }, withDescriptions: { type: 'boolean', default: false diff --git a/index.js b/index.js index 7eacd72..d855b9a 100644 --- a/index.js +++ b/index.js @@ -1,123 +1,4 @@ -/* eslint-disable no-unused-vars */ -'use strict' -const path = require('path') -const fs = require('fs') -const mkdirp = require('mkdirp') -const pick = require('lodash.pick') -const yaml = require('js-yaml') -const pify = require('pify') -const { flatten, unflatten } = require('flat') -const loadJsonFile = require('load-json-file') -const writeJsonFile = require('write-json-file') -const sortKeys = require('sort-keys') -const extractReactIntl = require('./extract-react-intl') +// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires +const fn = require('./dist').default -const writeJson = (outputPath, obj) => { - return writeJsonFile(`${outputPath}.json`, obj, { indent: 2 }) -} - -const writeYaml = (outputPath, obj) => { - return pify(fs.writeFile)(`${outputPath}.yml`, yaml.safeDump(obj), 'utf8') -} - -const isJson = ext => ext === 'json' - -function loadLocaleFiles(locales, buildDir, ext) { - const oldLocaleMaps = {} - - try { - mkdirp.sync(buildDir) - } catch (error) {} - - for (const locale of locales) { - const file = path.resolve(buildDir, `${locale}.${ext}`) - // Initialize json file - try { - const output = isJson(ext) ? JSON.stringify({}) : yaml.safeDump({}) - fs.writeFileSync(file, output, { flag: 'wx' }) - } catch (error) { - if (error.code !== 'EEXIST') { - throw error - } - } - - let messages = isJson(ext) - ? loadJsonFile.sync(file) - : yaml.safeLoad(fs.readFileSync(file, 'utf8'), { json: true }) - - messages = flatten(messages) - - oldLocaleMaps[locale] = {} - for (const messageKey of Object.keys(messages)) { - const message = messages[messageKey] - if (message && typeof message === 'string' && message !== '') { - oldLocaleMaps[locale][messageKey] = messages[messageKey] - } - } - } - - return oldLocaleMaps -} - -// eslint-disable-next-line max-lines-per-function -module.exports = async (locales, pattern, buildDir, opts) => { - if (!Array.isArray(locales)) { - throw new TypeError(`Expected a Array, got ${typeof locales}`) - } - - if (typeof pattern !== 'string') { - throw new TypeError(`Expected a string, got ${typeof pattern}`) - } - - if (typeof buildDir !== 'string') { - throw new TypeError(`Expected a string, got ${typeof buildDir}`) - } - - const jsonOpts = { format: 'json', flat: true } - const yamlOpts = { format: 'yaml', flat: false } - const defautlOpts = - opts && opts.format && !isJson(opts.format) ? yamlOpts : jsonOpts - - opts = { defaultLocale: 'en', ...defautlOpts, ...opts } - - const ext = isJson(opts.format) ? 'json' : 'yml' - - const { defaultLocale, moduleName } = opts - - const oldLocaleMaps = loadLocaleFiles(locales, buildDir, ext) - - delete opts.defaultLocale - - const extractorOptions = { defaultLocale, ...opts } - - if (moduleName) { - extractorOptions.moduleSourceName = moduleName - } - - const newLocaleMaps = await extractReactIntl( - locales, - pattern, - extractorOptions - ) - - return Promise.all( - locales.map(locale => { - // If the default locale, overwrite the origin file - let localeMap = - locale === defaultLocale - ? // Create a clone so we can use only current valid messages below - { ...oldLocaleMaps[locale], ...newLocaleMaps[locale] } - : { ...newLocaleMaps[locale], ...oldLocaleMaps[locale] } - // Only keep existing keys - localeMap = pick(localeMap, Object.keys(newLocaleMaps[locale])) - - const fomattedLocaleMap = opts.flat - ? sortKeys(localeMap, { deep: true }) - : unflatten(sortKeys(localeMap), { object: true }) - - const fn = isJson(opts.format) ? writeJson : writeYaml - - return fn(path.resolve(buildDir, locale), fomattedLocaleMap) - }) - ) -} +module.exports = fn diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..210ddfb --- /dev/null +++ b/jest.config.js @@ -0,0 +1,12 @@ +module.exports = { + testPathIgnorePatterns: [ + '[/\\\\](dist|compiled|node_modules)[/\\\\]' + ], + testEnvironment: 'node', + preset: 'ts-jest', + globals: { + 'ts-jest': { + diagnostics: false + } + } +} diff --git a/package.json b/package.json index 5231a84..924bef6 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "add-contributor": "all-contributors add", "fmt": "prettier --write '**/*.{json,js,md}'", "example": "./cli.js -l=en,ja -o example/i18n -d en 'example/**/*.js'", - "lint": "eslint index.js cli.js ./extract-react-intl/index.js", + "build": "tsc", + "lint": "eslint src/**/*.ts --fix --cache", "test": "npm run lint && jest" }, "bin": { @@ -24,7 +25,7 @@ "extract-messages": "cli.js" }, "files": [ - "extract-react-intl/index.js", + "dist", "index.js", "cli.js" ], @@ -56,10 +57,21 @@ "write-json-file": "^4.1.1" }, "devDependencies": { + "@akameco/tsconfig": "^0.3.0", "@babel/plugin-proposal-class-properties": "^7.5.5", "@babel/preset-env": "^7.5.5", "@babel/preset-flow": "^7.0.0", "@babel/preset-react": "^7.0.0", + "@types/flat": "^0.0.28", + "@types/jest": "^24.0.18", + "@types/js-yaml": "^3.12.1", + "@types/lodash.merge": "^4.6.6", + "@types/lodash.mergewith": "^4.6.6", + "@types/lodash.pick": "^4.4.6", + "@types/mkdirp": "^0.5.2", + "@types/pify": "^3.0.2", + "@types/temp-write": "^4.0.0", + "@types/tempy": "^0.3.0", "all-contributors-cli": "^6.8.1", "babel-core": "7.0.0-bridge.0", "babel-jest": "^24.8.0", @@ -71,9 +83,11 @@ "lint-staged": "^9.2.1", "prettier": "^1.18.2", "react": "^16.8.6", - "react-intl": "^3.1.10", + "react-intl": "^3.1.11", "temp-write": "^4.0.0", - "tempy": "^0.3.0" + "tempy": "^0.3.0", + "ts-jest": "^24.0.2", + "typescript": "^3.5.3" }, "lint-staged": { "*.{js}": [ diff --git a/readme.md b/readme.md index 2aa00c0..9c17f71 100644 --- a/readme.md +++ b/readme.md @@ -99,7 +99,6 @@ $ extract-messages --help -f, --format json|yaml [default: json] --flat json [default: true] | yaml [default: false] --default-locale default locale [default: en] - --module-name module source name from where components are imported [default: react-intl] Example $ extract-messages --locales=ja,en --output app/translations 'app/**/*.js' @@ -171,13 +170,6 @@ If format is `yaml`, set to `false`. Be careful if `false`. See [this issue](https://github.com/akameco/extract-react-intl-messages/issues/3). -##### moduleName - -Type: `string`
-Default: `react-intl` - -Set from where _defineMessages_, `` and `` are imported. - ##### babel-plugin-react-intl's Options See https://github.com/formatjs/formatjs/tree/master/packages/babel-plugin-react-intl#options diff --git a/src/babel__core.d.ts b/src/babel__core.d.ts new file mode 100644 index 0000000..65fef2e --- /dev/null +++ b/src/babel__core.d.ts @@ -0,0 +1,6 @@ +import babel from '@babel/core' + +declare module '@babel/core' { + function resolvePlugin(name: string, dirname: string): string | null + function resolvePreset(name: string, dirname: string): string | null +} diff --git a/extract-react-intl/index.js b/src/extract-react-intl/index.ts similarity index 52% rename from extract-react-intl/index.js rename to src/extract-react-intl/index.ts index 92d4f5d..a9e5db6 100644 --- a/extract-react-intl/index.js +++ b/src/extract-react-intl/index.ts @@ -1,32 +1,40 @@ -'use strict' -const path = require('path') -const glob = require('glob') -const pify = require('pify') -const merge = require('lodash.merge') -const mergeWith = require('lodash.mergewith') -const { resolvePlugin, resolvePreset, transformFile } = require('@babel/core') -const readBabelrcUp = require('read-babelrc-up') - -const localeMap = arr => - arr.reduce((obj, x) => { +import path from 'path' +import glob from 'glob' +import pify from 'pify' +import merge from 'lodash.merge' +import mergeWith from 'lodash.mergewith' +import { + resolvePlugin, + resolvePreset, + transformFile, + PluginItem +} from '@babel/core' +import readBabelrcUp from 'read-babelrc-up' + +type LocaleMap = Record> + +const localeMap = (arr: string[]): LocaleMap => + arr.reduce((obj: Record, x: string) => { obj[x] = {} return obj }, {}) -const concatArray = (obj, src) => { +const concatArray = (obj: string[], src: string) => { if (Array.isArray(obj)) { return obj.concat(src) } return undefined } -const createResolveList = fn => (list, cwd) => +const createResolveList = ( + fn: (name: string, dirname: string) => string | null +) => (list: PluginItem[], cwd: string) => list.map(x => (typeof x === 'string' ? fn(x, cwd) : x)) const resolvePresets = createResolveList(resolvePreset) const resolvePlugins = createResolveList(resolvePlugin) -const getBabelrc = cwd => { +const getBabelrc = (cwd: string) => { try { const babelrc = readBabelrcUp.sync({ cwd }).babel if (!babelrc.env) { @@ -41,10 +49,33 @@ const getBabelrc = cwd => { } } -const getBabelrcDir = cwd => path.dirname(readBabelrcUp.sync({ cwd }).path) +const getBabelrcDir = (cwd: string) => + path.dirname(readBabelrcUp.sync({ cwd }).path) + +type Options = { + defaultLocale?: string + cwd?: string + withDescriptions?: boolean + [key: string]: unknown +} + +type Message = { + id: string + defaultMessage: string + description: string +} // eslint-disable-next-line max-lines-per-function -module.exports = async (locales, pattern, opts = {}) => { +export default async ( + locales: string[], + pattern: string, + { + defaultLocale = 'en', + withDescriptions = false, + cwd = process.cwd(), + ...pluginOptions + }: Options = {} +) => { if (!Array.isArray(locales)) { throw new TypeError(`Expected a Array, got ${typeof locales}`) } @@ -53,35 +84,26 @@ module.exports = async (locales, pattern, opts = {}) => { throw new TypeError(`Expected a string, got ${typeof pattern}`) } - const defaultLocale = opts.defaultLocale || 'en' - const cwd = opts.cwd || process.cwd() - const withDescriptions = opts.withDescriptions || false - const babelrc = getBabelrc(cwd) || {} const babelrcDir = getBabelrcDir(cwd) - delete opts.cwd - delete opts.defaultLocale - - const pluginOptions = opts - - const { presets = [], plugins = [] } = babelrc + const presets = babelrc.presets || [] + const plugins = babelrc.plugins || [] presets.unshift({ - // eslint-disable-next-line global-require + // eslint-disable-next-line global-require, @typescript-eslint/no-require-imports plugins: [[require('babel-plugin-react-intl'), pluginOptions]] }) - const extractFromFile = async file => { + const extractFromFile = async (file: string) => { const babelOpts = { presets: resolvePresets(presets, babelrcDir), plugins: resolvePlugins(plugins, babelrcDir) } - const { metadata: result } = await pify(transformFile)(file, babelOpts) + const { metadata } = await pify(transformFile)(file, babelOpts) const localeObj = localeMap(locales) - // eslint-disable-next-line no-unused-vars - for (const { id, defaultMessage, description } of result['react-intl'] - .messages) { + const result = metadata['react-intl'].messages as Message[] + for (const { id, defaultMessage, description } of result) { // eslint-disable-next-line no-unused-vars for (const locale of locales) { const message = defaultLocale === locale ? defaultMessage : '' @@ -93,7 +115,7 @@ module.exports = async (locales, pattern, opts = {}) => { return localeObj } - const files = await pify(glob)(pattern) + const files: string[] = await pify(glob)(pattern) if (files.length === 0) { throw new Error(`File not found (${pattern})`) } diff --git a/extract-react-intl/readme.md b/src/extract-react-intl/readme.md similarity index 100% rename from extract-react-intl/readme.md rename to src/extract-react-intl/readme.md diff --git a/extract-react-intl/test/__snapshots__/test.js.snap b/src/extract-react-intl/test/__snapshots__/test.ts.snap similarity index 91% rename from extract-react-intl/test/__snapshots__/test.js.snap rename to src/extract-react-intl/test/__snapshots__/test.ts.snap index ca4e056..f7d89ce 100644 --- a/extract-react-intl/test/__snapshots__/test.js.snap +++ b/src/extract-react-intl/test/__snapshots__/test.ts.snap @@ -3,15 +3,7 @@ exports[`babel plugin execution order 1`] = ` Object { "en": Object { - "extract-react-intl.test.pluginOrdering.test": "auto", - }, -} -`; - -exports[`babelrc path resolution 1`] = ` -Object { - "en": Object { - "test": "test", + "src.extract-react-intl.test.pluginOrdering.test": "auto", }, } `; diff --git a/extract-react-intl/test/fixtures/.babelrc b/src/extract-react-intl/test/fixtures/.babelrc similarity index 87% rename from extract-react-intl/test/fixtures/.babelrc rename to src/extract-react-intl/test/fixtures/.babelrc index ddd9ced..0467cb0 100644 --- a/extract-react-intl/test/fixtures/.babelrc +++ b/src/extract-react-intl/test/fixtures/.babelrc @@ -23,7 +23,7 @@ [ "react-intl-auto", { - "removePrefix": "extract-react-intl.test.fixtures" + "removePrefix": "src.extract-react-intl.test.fixtures" } ] ] diff --git a/extract-react-intl/test/fixtures/components/App/index.js b/src/extract-react-intl/test/fixtures/components/App/index.js similarity index 100% rename from extract-react-intl/test/fixtures/components/App/index.js rename to src/extract-react-intl/test/fixtures/components/App/index.js diff --git a/extract-react-intl/test/fixtures/components/App/messages.js b/src/extract-react-intl/test/fixtures/components/App/messages.js similarity index 100% rename from extract-react-intl/test/fixtures/components/App/messages.js rename to src/extract-react-intl/test/fixtures/components/App/messages.js diff --git a/extract-react-intl/test/fixtures/components/Greeting/index.js b/src/extract-react-intl/test/fixtures/components/Greeting/index.js similarity index 100% rename from extract-react-intl/test/fixtures/components/Greeting/index.js rename to src/extract-react-intl/test/fixtures/components/Greeting/index.js diff --git a/extract-react-intl/test/fixtures/components/Greeting/messages.js b/src/extract-react-intl/test/fixtures/components/Greeting/messages.js similarity index 100% rename from extract-react-intl/test/fixtures/components/Greeting/messages.js rename to src/extract-react-intl/test/fixtures/components/Greeting/messages.js diff --git a/extract-react-intl/test/fixtures/components/LanguageProvider/index.js b/src/extract-react-intl/test/fixtures/components/LanguageProvider/index.js similarity index 100% rename from extract-react-intl/test/fixtures/components/LanguageProvider/index.js rename to src/extract-react-intl/test/fixtures/components/LanguageProvider/index.js diff --git a/extract-react-intl/test/fixtures/index.html b/src/extract-react-intl/test/fixtures/index.html similarity index 100% rename from extract-react-intl/test/fixtures/index.html rename to src/extract-react-intl/test/fixtures/index.html diff --git a/extract-react-intl/test/fixtures/index.js b/src/extract-react-intl/test/fixtures/index.js similarity index 100% rename from extract-react-intl/test/fixtures/index.js rename to src/extract-react-intl/test/fixtures/index.js diff --git a/extract-react-intl/test/pluginOrdering/.babelrc b/src/extract-react-intl/test/pluginOrdering/.babelrc similarity index 100% rename from extract-react-intl/test/pluginOrdering/.babelrc rename to src/extract-react-intl/test/pluginOrdering/.babelrc diff --git a/extract-react-intl/test/pluginOrdering/messages.js b/src/extract-react-intl/test/pluginOrdering/messages.js similarity index 100% rename from extract-react-intl/test/pluginOrdering/messages.js rename to src/extract-react-intl/test/pluginOrdering/messages.js diff --git a/extract-react-intl/test/resolution/.babelrc b/src/extract-react-intl/test/resolution/.babelrc similarity index 100% rename from extract-react-intl/test/resolution/.babelrc rename to src/extract-react-intl/test/resolution/.babelrc diff --git a/extract-react-intl/test/resolution/messages.js b/src/extract-react-intl/test/resolution/messages.js similarity index 100% rename from extract-react-intl/test/resolution/messages.js rename to src/extract-react-intl/test/resolution/messages.js diff --git a/extract-react-intl/test/test.js b/src/extract-react-intl/test/test.ts similarity index 77% rename from extract-react-intl/test/test.js rename to src/extract-react-intl/test/test.ts index 21574be..e5f4c9b 100644 --- a/extract-react-intl/test/test.js +++ b/src/extract-react-intl/test/test.ts @@ -1,11 +1,12 @@ -const m = require('..') +import m from '..' -const pattern = 'extract-react-intl/test/fixtures/**/*.js' +const pattern = 'src/extract-react-intl/test/fixtures/**/*.js' const locales = ['en', 'ja'] test('extract from file', async () => { process.env.BABEL_ENV = 'react-intl' const x = await m(locales, pattern, { + defaultLocale: 'en', cwd: `${__dirname}/fixtures`, extractFromFormatMessageCall: true }) @@ -15,6 +16,7 @@ test('extract from file', async () => { // TODO: fix test.skip('babelrc path resolution', async () => { const x = await m(['en'], './extract-react-intl/test/resolution/**/*.js', { + defaultLocale: 'en', cwd: `${__dirname}/resolution` }) expect(x).toMatchSnapshot() @@ -23,8 +25,8 @@ test.skip('babelrc path resolution', async () => { test('babel plugin execution order', async () => { const x = await m( ['en'], - './extract-react-intl/test/pluginOrdering/**/*.js', - { cwd: `${__dirname}/pluginOrdering` } + 'src/extract-react-intl/test/pluginOrdering/**/*.js', + { defaultLocale: 'en', cwd: `${__dirname}/pluginOrdering` } ) expect(x).toMatchSnapshot() }) @@ -32,6 +34,7 @@ test('babel plugin execution order', async () => { test('error', async () => { expect.assertions(1) await m(locales, 'notfound', { + defaultLocale: 'en', cwd: `${__dirname}/fixtures` }).catch(error => { expect(error.message).toMatch('File not found') @@ -41,6 +44,7 @@ test('error', async () => { test('extract from file with descriptions', async () => { process.env.BABEL_ENV = 'react-intl' const x = await m(locales, pattern, { + defaultLocale: 'en', cwd: './test/fixtures', withDescriptions: true }) diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..fce0599 --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,5 @@ +declare module 'read-babelrc-up' { + function sync(opts: { + cwd: string + }): { path: string; babel: import('@babel/core').TransformOptions } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..adf3169 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,130 @@ +import path from 'path' +import fs from 'fs' +import mkdirp from 'mkdirp' +import pick from 'lodash.pick' +import yaml from 'js-yaml' +import pify from 'pify' +import { flatten, unflatten } from 'flat' +import loadJsonFile from 'load-json-file' +import writeJsonFile from 'write-json-file' +import sortKeys from 'sort-keys' +import extractReactIntl from './extract-react-intl' + +const writeJson = (outputPath: string, obj: object) => { + return writeJsonFile(`${outputPath}.json`, obj, { indent: 2 }) +} + +const writeYaml = (outputPath: string, obj: object) => { + return pify(fs.writeFile)(`${outputPath}.yml`, yaml.safeDump(obj), 'utf8') +} + +const isJson = (ext: string) => ext === 'json' + +function loadLocaleFiles(locales: string[], buildDir: string, ext: string) { + const oldLocaleMaps: Record> = {} + + try { + mkdirp.sync(buildDir) + } catch (error) {} + + for (const locale of locales) { + const file = path.resolve(buildDir, `${locale}.${ext}`) + // Initialize json file + try { + const output = isJson(ext) ? JSON.stringify({}) : yaml.safeDump({}) + fs.writeFileSync(file, output, { flag: 'wx' }) + } catch (error) { + if (error.code !== 'EEXIST') { + throw error + } + } + + let messages = isJson(ext) + ? loadJsonFile.sync(file) + : yaml.safeLoad(fs.readFileSync(file, 'utf8'), { json: true }) + + messages = flatten(messages) + + oldLocaleMaps[locale] = {} + for (const messageKey of Object.keys(messages)) { + const message = messages[messageKey] + if (message && typeof message === 'string' && message !== '') { + oldLocaleMaps[locale][messageKey] = messages[messageKey] + } + } + } + + return oldLocaleMaps +} + +type Opts = { + defaultLocale: string + format?: string + flat?: boolean + [key: string]: unknown +} + +// eslint-disable-next-line max-lines-per-function +export default async ( + locales: string[], + pattern: string, + buildDir: string, + { + format = 'json', + flat = isJson(format), + defaultLocale = 'en', + ...opts + }: Opts = { + defaultLocale: 'en' + } +) => { + if (!Array.isArray(locales)) { + throw new TypeError(`Expected a Array, got ${typeof locales}`) + } + + if (typeof pattern !== 'string') { + throw new TypeError(`Expected a string, got ${typeof pattern}`) + } + + if (typeof buildDir !== 'string') { + throw new TypeError(`Expected a string, got ${typeof buildDir}`) + } + + const ext = isJson(format) ? 'json' : 'yml' + + const oldLocaleMaps = loadLocaleFiles(locales, buildDir, ext) + + const extractorOptions = { + defaultLocale, + withDescriptions: false, + cwd: process.cwd(), + ...opts + } + + const newLocaleMaps = await extractReactIntl( + locales, + pattern, + extractorOptions + ) + + return Promise.all( + locales.map(locale => { + // If the default locale, overwrite the origin file + let localeMap = + locale === defaultLocale + ? // Create a clone so we can use only current valid messages below + { ...oldLocaleMaps[locale], ...newLocaleMaps[locale] } + : { ...newLocaleMaps[locale], ...oldLocaleMaps[locale] } + // Only keep existing keys + localeMap = pick(localeMap, Object.keys(newLocaleMaps[locale])) + + const fomattedLocaleMap: object = flat + ? sortKeys(localeMap, { deep: true }) + : unflatten(sortKeys(localeMap), { object: true }) + + const fn = isJson(format) ? writeJson : writeYaml + + return fn(path.resolve(buildDir, locale), fomattedLocaleMap) + }) + ) +} diff --git a/test/fixtures/custom/a/messages.js b/src/test/fixtures/custom/a/messages.js similarity index 100% rename from test/fixtures/custom/a/messages.js rename to src/test/fixtures/custom/a/messages.js diff --git a/test/fixtures/custom/b/messages.js b/src/test/fixtures/custom/b/messages.js similarity index 100% rename from test/fixtures/custom/b/messages.js rename to src/test/fixtures/custom/b/messages.js diff --git a/test/fixtures/custom/i18n.js b/src/test/fixtures/custom/i18n.js similarity index 100% rename from test/fixtures/custom/i18n.js rename to src/test/fixtures/custom/i18n.js diff --git a/test/fixtures/default/a/messages.js b/src/test/fixtures/default/a/messages.js similarity index 100% rename from test/fixtures/default/a/messages.js rename to src/test/fixtures/default/a/messages.js diff --git a/test/fixtures/default/b/messages.js b/src/test/fixtures/default/b/messages.js similarity index 100% rename from test/fixtures/default/b/messages.js rename to src/test/fixtures/default/b/messages.js diff --git a/test/fixtures/removed/a/messages.js b/src/test/fixtures/removed/a/messages.js similarity index 100% rename from test/fixtures/removed/a/messages.js rename to src/test/fixtures/removed/a/messages.js diff --git a/test/fixtures/removed/b/messages.js b/src/test/fixtures/removed/b/messages.js similarity index 100% rename from test/fixtures/removed/b/messages.js rename to src/test/fixtures/removed/b/messages.js diff --git a/test/fixtures/unsorted/a/messages.js b/src/test/fixtures/unsorted/a/messages.js similarity index 100% rename from test/fixtures/unsorted/a/messages.js rename to src/test/fixtures/unsorted/a/messages.js diff --git a/test/fixtures/unsorted/b/messages.js b/src/test/fixtures/unsorted/b/messages.js similarity index 100% rename from test/fixtures/unsorted/b/messages.js rename to src/test/fixtures/unsorted/b/messages.js diff --git a/test/json/__snapshots__/test.js.snap b/src/test/json/__snapshots__/test.ts.snap similarity index 100% rename from test/json/__snapshots__/test.js.snap rename to src/test/json/__snapshots__/test.ts.snap diff --git a/test/json/test.js b/src/test/json/test.ts similarity index 70% rename from test/json/test.js rename to src/test/json/test.ts index 4ab1324..9f2b75c 100644 --- a/test/json/test.js +++ b/src/test/json/test.ts @@ -1,11 +1,11 @@ -const fs = require('fs') -const path = require('path') -const tempy = require('tempy') -const m = require('../..') +import fs from 'fs' +import path from 'path' +import tempy from 'tempy' +import m from '../..' test('export json', async () => { const tmp = tempy.directory() - await m(['en', 'ja'], 'test/fixtures/default/**/*.js', tmp) + await m(['en', 'ja'], 'src/test/fixtures/default/**/*.js', tmp) const en = JSON.parse(fs.readFileSync(path.resolve(tmp, 'en.json'), 'utf8')) const ja = JSON.parse(fs.readFileSync(path.resolve(tmp, 'ja.json'), 'utf8')) expect(en).toMatchSnapshot() @@ -14,7 +14,7 @@ test('export json', async () => { test('export json with removed messages', async () => { const tmp = tempy.directory() - await m(['en', 'ja'], 'test/fixtures/default/**/*.js', tmp) + await m(['en', 'ja'], 'src/test/fixtures/default/**/*.js', tmp) const enBefore = JSON.parse( fs.readFileSync(path.resolve(tmp, 'en.json'), 'utf8') ) @@ -23,7 +23,7 @@ test('export json with removed messages', async () => { ) expect(enBefore).toMatchSnapshot() expect(jaBefore).toMatchSnapshot() - await m(['en', 'ja'], 'test/fixtures/removed/**/*.js', tmp) + await m(['en', 'ja'], 'src/test/fixtures/removed/**/*.js', tmp) const en = JSON.parse(fs.readFileSync(path.resolve(tmp, 'en.json'), 'utf8')) const ja = JSON.parse(fs.readFileSync(path.resolve(tmp, 'ja.json'), 'utf8')) expect(en).toMatchSnapshot() @@ -32,7 +32,10 @@ test('export json with removed messages', async () => { test('export json - nest', async () => { const tmp = tempy.directory() - await m(['en', 'ja'], 'test/fixtures/default/**/*.js', tmp, { flat: false }) + await m(['en', 'ja'], 'src/test/fixtures/default/**/*.js', tmp, { + defaultLocale: 'en', + flat: false + }) const en = JSON.parse(fs.readFileSync(path.resolve(tmp, 'en.json'), 'utf8')) const ja = JSON.parse(fs.readFileSync(path.resolve(tmp, 'ja.json'), 'utf8')) expect(en).toMatchSnapshot() @@ -44,9 +47,9 @@ test('sort keys', async () => { const enPath = path.resolve(tmp, 'en.json') const jaPath = path.resolve(tmp, 'ja.json') - await m(['en', 'ja'], 'test/fixtures/unsorted/**/*.js', tmp) - const en = JSON.parse(fs.readFileSync(enPath)) - const ja = JSON.parse(fs.readFileSync(jaPath)) + await m(['en', 'ja'], 'src/test/fixtures/unsorted/**/*.js', tmp) + const en = JSON.parse(fs.readFileSync(enPath, 'utf8')) + const ja = JSON.parse(fs.readFileSync(jaPath, 'utf8')) expect(Object.keys(en)).toMatchSnapshot() expect(Object.keys(ja)).toMatchSnapshot() @@ -54,8 +57,10 @@ test('sort keys', async () => { test('export using custom module', async () => { const tmp = tempy.directory() - const opts = { moduleName: '../i18n' } - await m(['en', 'ja'], 'test/fixtures/custom/**/*.js', tmp, opts) + await m(['en', 'ja'], 'src/test/fixtures/custom/**/*.js', tmp, { + defaultLocale: 'en', + moduleSourceName: '../i18n' + }) const en = JSON.parse(fs.readFileSync(path.resolve(tmp, 'en.json'), 'utf8')) const ja = JSON.parse(fs.readFileSync(path.resolve(tmp, 'ja.json'), 'utf8')) expect(en).toMatchSnapshot() diff --git a/test/test.js b/src/test/test.ts similarity index 78% rename from test/test.js rename to src/test/test.ts index 43f6a15..269184d 100644 --- a/test/test.js +++ b/src/test/test.ts @@ -1,7 +1,10 @@ -const m = require('..') +import m from '..' test('errors', async () => { + // @ts-ignore await expect(m('hello')).rejects.toThrow('Expected a Array') + // @ts-ignore await expect(m(['en', 'ja'], 2)).rejects.toThrow('Expected a string') + // @ts-ignore await expect(m(['en', 'ja'], 'app/', 2)).rejects.toThrow('Expected a string') }) diff --git a/test/yaml/__snapshots__/test.js.snap b/src/test/yaml/__snapshots__/test.ts.snap similarity index 100% rename from test/yaml/__snapshots__/test.js.snap rename to src/test/yaml/__snapshots__/test.ts.snap diff --git a/test/yaml/test.js b/src/test/yaml/test.ts similarity index 54% rename from test/yaml/test.js rename to src/test/yaml/test.ts index 0d352d6..5c5b51a 100644 --- a/test/yaml/test.js +++ b/src/test/yaml/test.ts @@ -1,18 +1,22 @@ -const fs = require('fs') -const path = require('path') -const tempy = require('tempy') -const tempWrite = require('temp-write') -const yaml = require('js-yaml') -const m = require('../..') - -const fixturesPath = 'test/fixtures/default/**/*.js' - -const yamlLoad = (tmp, file = '') => +import fs from 'fs' +import path from 'path' +// eslint-disable-next-line import/no-extraneous-dependencies +import tempy from 'tempy' +// eslint-disable-next-line import/no-extraneous-dependencies +import tempWrite from 'temp-write' +import yaml from 'js-yaml' +import m from '../..' + +const fixturesPath = 'src/test/fixtures/default/**/*.js' + +const yamlLoad = (tmp: string, file = '') => yaml.safeLoad(fs.readFileSync(path.resolve(tmp, file), 'utf8')) +const defaultLocale = 'en' + test('export yaml', async () => { const tmp = tempy.directory() - await m(['en', 'ja'], fixturesPath, tmp, { format: 'yaml' }) + await m(['en', 'ja'], fixturesPath, tmp, { defaultLocale, format: 'yaml' }) expect(yamlLoad(tmp, 'en.yml')).toMatchSnapshot() expect(yamlLoad(tmp, 'ja.yml')).toMatchSnapshot() @@ -21,6 +25,7 @@ test('export yaml', async () => { test('export yaml - flat', async () => { const tmp = tempy.directory() await m(['en', 'ja'], fixturesPath, tmp, { + defaultLocale, format: 'yaml', flat: true }) @@ -33,11 +38,17 @@ test('exsit yaml', async () => { const x = { a: { hello: 'hello2' } } const tmpEn = tempWrite.sync(yaml.safeDump(x), 'en.yml') - await m(['en'], fixturesPath, path.dirname(tmpEn), { format: 'yaml' }) + await m(['en'], fixturesPath, path.dirname(tmpEn), { + defaultLocale, + format: 'yaml' + }) expect(yaml.safeLoad(fs.readFileSync(tmpEn, 'utf8'))).toMatchSnapshot() const tmpJa = tempWrite.sync(yaml.safeDump(x), 'ja.yml') - await m(['ja'], fixturesPath, path.dirname(tmpJa), { format: 'yaml' }) + await m(['ja'], fixturesPath, path.dirname(tmpJa), { + defaultLocale, + format: 'yaml' + }) expect(yaml.safeLoad(fs.readFileSync(tmpJa, 'utf8'))).toMatchSnapshot() }) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..be0d574 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@akameco/tsconfig", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src"] +} diff --git a/yarn.lock b/yarn.lock index d62062a..1fd85b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@akameco/tsconfig@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@akameco/tsconfig/-/tsconfig-0.3.0.tgz#1ddcda03bbde652e376ad300f3057560f1d5dcd5" + integrity sha512-TjhWxLlfBMYxHTUZiGPvAuU53ksGPBKv4fjDBw0qdJxIV67G7N2jq9xuXPUDJVy2Qldr7Iuh/ngYGIdvN7grMg== + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" @@ -978,6 +983,11 @@ resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== +"@types/flat@^0.0.28": + version "0.0.28" + resolved "https://registry.yarnpkg.com/@types/flat/-/flat-0.0.28.tgz#5c788149d85a6cf8ff5f5f000acdd912cdea4274" + integrity sha1-XHiBSdhabPj/X18ACs3ZEs3qQnQ= + "@types/glob@^7.1.1": version "7.1.1" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" @@ -1020,16 +1030,66 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/jest-diff@*": + version "20.0.1" + resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89" + integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA== + +"@types/jest@^24.0.18": + version "24.0.18" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.18.tgz#9c7858d450c59e2164a8a9df0905fc5091944498" + integrity sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ== + dependencies: + "@types/jest-diff" "*" + +"@types/js-yaml@^3.12.1": + version "3.12.1" + resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.1.tgz#5c6f4a1eabca84792fbd916f0cb40847f123c656" + integrity sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA== + "@types/json-schema@^7.0.3": version "7.0.3" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== +"@types/lodash.merge@^4.6.6": + version "4.6.6" + resolved "https://registry.yarnpkg.com/@types/lodash.merge/-/lodash.merge-4.6.6.tgz#b84b403c1d31bc42d51772d1cd5557fa008cd3d6" + integrity sha512-IB90krzMf7YpfgP3u/EvZEdXVvm4e3gJbUvh5ieuI+o+XqiNEt6fCzqNRaiLlPVScLI59RxIGZMQ3+Ko/DJ8vQ== + dependencies: + "@types/lodash" "*" + +"@types/lodash.mergewith@^4.6.6": + version "4.6.6" + resolved "https://registry.yarnpkg.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz#c4698f5b214a433ff35cb2c75ee6ec7f99d79f10" + integrity sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg== + dependencies: + "@types/lodash" "*" + +"@types/lodash.pick@^4.4.6": + version "4.4.6" + resolved "https://registry.yarnpkg.com/@types/lodash.pick/-/lodash.pick-4.4.6.tgz#ae4e8f109e982786313bb6aac4b1a73aefa6e9be" + integrity sha512-u8bzA16qQ+8dY280z3aK7PoWb3fzX5ATJ0rJB6F+uqchOX2VYF02Aqa+8aYiHiHgPzQiITqCgeimlyKFy4OA6g== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.137" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.137.tgz#8a4804937dc6462274ffcc088df8f14fc1b368e2" + integrity sha512-g4rNK5SRKloO+sUGbuO7aPtwbwzMgjK+bm9BBhLD7jGUiGR7zhwYEhSln/ihgYQBeIJ5j7xjyaYzrWTcu3UotQ== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/mkdirp@^0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f" + integrity sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg== + dependencies: + "@types/node" "*" + "@types/node@*": version "12.7.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44" @@ -1040,6 +1100,11 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== +"@types/pify@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/pify/-/pify-3.0.2.tgz#1bc75dac43e31dba981c37e0a08edddc1b49cd39" + integrity sha512-a5AKF1/9pCU3HGMkesgY6LsBdXHUY3WU+I2qgpU0J+I8XuJA1aFr59eS84/HP0+dxsyBSNbt+4yGI2adUpHwSg== + "@types/prop-types@*": version "15.7.1" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" @@ -1058,6 +1123,20 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/temp-write@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/temp-write/-/temp-write-4.0.0.tgz#983237bb6dbcac883137dba8189b8c6177e8a04d" + integrity sha512-BNcDNG/ujXmzR49TeVxcWMbglOO55YQbe1ij3LE6WoZdLtZvclSEl5GAmmlfsr0Y5kM9mLIE1wk3r3pzQz62gQ== + dependencies: + temp-write "*" + +"@types/tempy@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@types/tempy/-/tempy-0.3.0.tgz#e6076cfd5f4ad51b716a26b312a8911825668b0a" + integrity sha512-graSgBSy4TEsenfAasXh28mxfdrLkgrFlXU8QFShFVNHEGHCg5IfO5LBlZjq2SAUnCm/VdxvuQKlp2buPR/YwA== + dependencies: + tempy "*" + "@types/yargs-parser@*": version "13.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.0.0.tgz#453743c5bbf9f1bed61d959baab5b06be029b2d0" @@ -1809,6 +1888,13 @@ browserslist@^4.6.0, browserslist@^4.6.6: electron-to-chromium "^1.3.191" node-releases "^1.1.25" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.0.tgz#65fc784bf7f87c009b973c12db6546902fa9c7b5" @@ -1816,7 +1902,7 @@ bser@^2.0.0: dependencies: node-int64 "^0.4.0" -buffer-from@^1.0.0: +buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -3110,7 +3196,7 @@ fast-glob@^3.0.3: merge2 "^1.2.3" micromatch "^4.0.2" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= @@ -4551,6 +4637,13 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json5@2.x, json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + dependencies: + minimist "^1.2.0" + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -4558,13 +4651,6 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== - dependencies: - minimist "^1.2.0" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -4908,6 +4994,11 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +make-error@1.x: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" @@ -5125,7 +5216,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@0.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -5990,10 +6081,10 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-intl@^3.1.10: - version "3.1.10" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-3.1.10.tgz#52ffb8dda6de09c7a7b8b451d99b22d5d3aec467" - integrity sha512-Fr5klqJB/wH3Jyc/RlLsAXFEQew2BzzmVtCf6NacEdisgHDvc2JZnI241Y6fOz2rI1rmgiEmgwj+OF0gQElueg== +react-intl@^3.1.11: + version "3.1.11" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-3.1.11.tgz#cdbd003408886e013d09a8b41133109e4d9aded5" + integrity sha512-hnsdhje7IrvyCyW6sdQD7FcVmdkzm9SdFrb+cnwnj5J4QHjZ8X7oVqGPB05sK482Ja1FLUgw1fHheaWRqPAKRA== dependencies: "@formatjs/intl-relativetimeformat" "^2.8.0" "@types/hoist-non-react-statics" "^3.3.1" @@ -6299,7 +6390,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.3.2, resolve@^1.5.0: +resolve@1.x, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.3.2, resolve@^1.5.0: version "1.12.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== @@ -6453,7 +6544,7 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -6944,7 +7035,7 @@ temp-dir@^1.0.0: resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= -temp-write@^4.0.0: +temp-write@*, temp-write@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== @@ -6955,7 +7046,7 @@ temp-write@^4.0.0: temp-dir "^1.0.0" uuid "^3.3.2" -tempy@^0.3.0: +tempy@*, tempy@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.3.0.tgz#6f6c5b295695a16130996ad5ab01a8bd726e8bf8" integrity sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ== @@ -7115,6 +7206,21 @@ trim-right@^1.0.1: resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= +ts-jest@^24.0.2: + version "24.0.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.0.2.tgz#8dde6cece97c31c03e80e474c749753ffd27194d" + integrity sha512-h6ZCZiA1EQgjczxq+uGLXQlNgeg02WWJBbeT8j6nyIBRQdglqbvzDoHahTEIiS6Eor6x8mK6PfZ7brQ9Q6tzHw== + dependencies: + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + json5 "2.x" + make-error "1.x" + mkdirp "0.x" + resolve "1.x" + semver "^5.5" + yargs-parser "10.x" + tslib@^1.8.1, tslib@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" @@ -7178,6 +7284,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" + integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== + uglify-js@^3.1.4: version "3.6.0" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" @@ -7560,7 +7671,7 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== -yargs-parser@^10.0.0: +yargs-parser@10.x, yargs-parser@^10.0.0: version "10.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==