From 6d7ba2541735e22c709ac4af76e40a1f12d0ddc3 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Tue, 5 Feb 2019 12:40:57 +0600 Subject: [PATCH 01/33] Added react-i18next and configured, deleted i18n service --- npm-shrinkwrap.json | 53 ++++++++++++++ package.json | 4 ++ src/client.tsx | 8 +-- src/core/App.tsx | 7 +- src/core/configurationI18n.ts | 35 +++++++++ src/core/configureApp.ts | 3 +- src/core/constants.ts | 4 +- .../DemoTranslations/DemoTranslations.tsx | 12 ++-- src/services/i18n/constants.ts | 24 ------- src/services/i18n/index.ts | 5 -- src/services/i18n/namespace.ts | 18 ----- .../i18n/view/I18nProvider/I18nProvider.tsx | 71 ------------------- src/services/i18n/view/withI18n/withI18n.tsx | 27 ------- .../buildTranslationKeys.test.ts | 0 .../helpers/buildTranslationKeys/index.ts | 0 src/{services/i18n => shared}/locales/en.ts | 5 +- .../i18n => shared}/locales/index.ts | 0 src/{services/i18n => shared}/locales/ru.ts | 6 +- src/shared/types/app.ts | 2 +- .../LanguageSelector/LanguageSelector.tsx | 16 ++--- src/shared/view/components/index.ts | 1 + 21 files changed, 125 insertions(+), 176 deletions(-) create mode 100644 src/core/configurationI18n.ts delete mode 100644 src/services/i18n/constants.ts delete mode 100644 src/services/i18n/index.ts delete mode 100644 src/services/i18n/namespace.ts delete mode 100644 src/services/i18n/view/I18nProvider/I18nProvider.tsx delete mode 100644 src/services/i18n/view/withI18n/withI18n.tsx rename src/{services/i18n => shared}/helpers/buildTranslationKeys/buildTranslationKeys.test.ts (100%) rename src/{services/i18n => shared}/helpers/buildTranslationKeys/index.ts (100%) rename src/{services/i18n => shared}/locales/en.ts (64%) rename src/{services/i18n => shared}/locales/index.ts (100%) rename src/{services/i18n => shared}/locales/ru.ts (63%) rename src/{services/i18n/view => shared/view/components}/LanguageSelector/LanguageSelector.tsx (59%) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 4f078699..4d51e6b6 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -701,6 +701,11 @@ "@types/node": "*" } }, + "@types/i18next-browser-languagedetector": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/i18next-browser-languagedetector/-/i18next-browser-languagedetector-2.0.1.tgz", + "integrity": "sha512-9TwP0tw0PSXUtBtM12PFUjBsl9sP5bNHd54qdSXBrrZ4HJmtVdqbKvmXLH4Qd3KQzIS2g/Z7HhLhygL2LUSb8w==" + }, "@types/jest": { "version": "23.3.9", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.9.tgz", @@ -8645,6 +8650,14 @@ } } }, + "html-parse-stringify2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz", + "integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=", + "requires": { + "void-elements": "^2.0.1" + } + }, "html-tags": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", @@ -9106,6 +9119,16 @@ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz", "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=" }, + "i18next": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-14.0.1.tgz", + "integrity": "sha512-wsKfQuYsy4RdCaqqN71eDjWMhizhTfQSIBGttEA7vcboQrUfpQlCezrSzrtmoW9F9tmVyNs38iBgLYLMhRSeIQ==" + }, + "i18next-browser-languagedetector": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-2.2.4.tgz", + "integrity": "sha512-wPbtH18FdOuB245I8Bhma5/XSDdN/HpYlX+wga1eMy+slhaFQSnrWX6fp+aYSL2eEuj0RlfHeEVz6Fo/lxAj6A==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -15412,6 +15435,31 @@ } } }, + "react-i18next": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-9.0.10.tgz", + "integrity": "sha512-xpeCWNut7ylQLs3Qqyo7dT13kgZbML1CdftbdnswLCv0RbRT16bRP16ma59iLe1KHIbn92VJo0Q8LSKYoXVNvg==", + "requires": { + "@babel/runtime": "^7.3.1", + "hoist-non-react-statics": "3.2.1", + "html-parse-stringify2": "2.0.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz", + "integrity": "sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, "react-input-autosize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz", @@ -20399,6 +20447,11 @@ "indexof": "0.0.1" } }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + }, "w3c-hr-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", diff --git a/package.json b/package.json index e6e2c687..388a5991 100644 --- a/package.json +++ b/package.json @@ -202,6 +202,7 @@ "@types/compression": "0.0.36", "@types/cookie-parser": "^1.4.1", "@types/google-maps": "^3.2.0", + "@types/i18next-browser-languagedetector": "^2.0.1", "@types/node-polyglot": "^0.4.31", "@types/prop-types": "^15.5.6", "@types/ramda": "^0.25.29", @@ -240,6 +241,8 @@ "file-loader": "^2.0.0", "final-form": "^4.11.0", "gh-pages": "^1.2.0", + "i18next": "^14.0.1", + "i18next-browser-languagedetector": "^2.2.4", "inversify": "^5.0.1", "inversify-inject-decorators": "^3.1.0", "jss": "^9.8.3", @@ -260,6 +263,7 @@ "react-final-form": "^4.0.2", "react-geosuggest": "^2.5.0", "react-helmet": "^5.2.0", + "react-i18next": "^9.0.10", "react-jss": "^8.6.1", "react-number-format": "^4.0.6", "react-redux": "^5.1.1", diff --git a/src/client.tsx b/src/client.tsx index b194d5ec..15484442 100644 --- a/src/client.tsx +++ b/src/client.tsx @@ -1,13 +1,13 @@ import 'reflect-metadata'; import 'babel-polyfill'; -import { App } from 'core/App'; +import { AppContainer } from 'react-hot-loader'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import * as bootstrapper from 'react-async-bootstrapper'; -import configureApp from 'core/configureApp'; -import { AppContainer } from 'react-hot-loader'; -import getEnvParams from './core/getEnvParams'; +import configureApp from 'core/configureApp'; +import { App } from 'core/App'; +import getEnvParams from 'core/getEnvParams'; const { appVersion } = getEnvParams(); diff --git a/src/core/App.tsx b/src/core/App.tsx index ff85dea8..7d82279a 100644 --- a/src/core/App.tsx +++ b/src/core/App.tsx @@ -8,7 +8,6 @@ import { IAppData, IModule, IJssDependencies } from 'shared/types/app'; import { JssProvider, SheetsRegistry } from 'shared/styles'; import createRoutes from './routes'; -import { I18nProvider } from 'services/i18n'; interface IAppProps { jssDeps: IJssDependencies; @@ -57,11 +56,7 @@ function renderSharedPart( disableStylesGeneration={disableStylesGeneration} > - - {/* */} - {createRoutes(modules)} - {/* */} - + {createRoutes(modules)} ); diff --git a/src/core/configurationI18n.ts b/src/core/configurationI18n.ts new file mode 100644 index 00000000..6c4005b9 --- /dev/null +++ b/src/core/configurationI18n.ts @@ -0,0 +1,35 @@ +import { default as i18n } from 'i18next'; +import { reactI18nextModule, withNamespaces as withI18n, WithNamespaces as ITranslateProps } from 'react-i18next'; +import { default as languageDetector } from 'i18next-browser-languagedetector'; + +import { en, ru } from 'shared/locales'; +import buildTranslationKeys from 'shared/helpers/buildTranslationKeys'; + +import { FALLBACK_LANGUAGE } from './constants'; + +const tKeys = buildTranslationKeys(en); +const resources = { + en: { + translation: en, + }, + ru: { + translation: ru, + }, +}; + +i18n + .use(languageDetector) + .use(reactI18nextModule) + .init({ + resources, + fallbackLng: FALLBACK_LANGUAGE, + interpolation: { + format: (value, format, _lng) => { + if (format === 'uppercase') { return value.toUpperCase(); } + return value; + }, + }, + }); + +export { tKeys, withI18n, ITranslateProps }; +export default i18n; diff --git a/src/core/configureApp.ts b/src/core/configureApp.ts index 747bd6c9..8a2dc4cb 100644 --- a/src/core/configureApp.ts +++ b/src/core/configureApp.ts @@ -1,9 +1,10 @@ import configureDeps from './configureDeps'; import { TYPES, container } from './configureIoc'; import configureStore, { createReducer } from './configureStore'; +import { configureJss } from './configureJss'; +import './configurationI18n'; import { DemoModule } from 'modules'; -import { configureJss } from 'core/configureJss'; import { ReducersMap } from 'shared/types/redux'; import { reduxEntry as themeProviderRE } from 'services/theme'; import { IAppData, IModule, RootSaga, IAppReduxState, IReduxEntry } from 'shared/types/app'; diff --git a/src/core/constants.ts b/src/core/constants.ts index 8337712e..e7fa0d4a 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -1 +1,3 @@ -// +import { Lang } from 'shared/types/app'; + +export const FALLBACK_LANGUAGE: Lang = 'en'; diff --git a/src/modules/Demo/view/DemoTranslations/DemoTranslations.tsx b/src/modules/Demo/view/DemoTranslations/DemoTranslations.tsx index 0cdf4121..54da39b2 100644 --- a/src/modules/Demo/view/DemoTranslations/DemoTranslations.tsx +++ b/src/modules/Demo/view/DemoTranslations/DemoTranslations.tsx @@ -1,23 +1,23 @@ import * as React from 'react'; - -import { withI18n, ITranslateProps, tKeys, LanguageSelector } from 'services/i18n'; +import { withI18n, tKeys, ITranslateProps } from 'core/configurationI18n'; +import { LanguageSelector } from 'shared/view/components'; function DemoTranslations(props: ITranslateProps) { - const { locale, t } = props; + const { t, lng } = props; return (
-

{t(tKeys.demo.selectedLang.getKey(), { locale })}

+

{t(tKeys.demo.selectedLang.getKey(), { lng })}

{t(tKeys.demo.selectorLabel.getKey())}

{t(tKeys.demo.somethingText.getKey())}

{t(tKeys.demo.pluralLabel.getKey())}

); } -export default withI18n(DemoTranslations); +export default withI18n()(DemoTranslations); diff --git a/src/services/i18n/constants.ts b/src/services/i18n/constants.ts deleted file mode 100644 index f0545ea0..00000000 --- a/src/services/i18n/constants.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from 'react'; -import * as Polyglot from 'node-polyglot'; - -import buildTranslationKeys from './helpers/buildTranslationKeys'; - -import { Lang, ITranslateFunction, ITranslateProps } from './namespace'; -import { en, phrasesByLocale } from './locales'; - -export const LANGUAGES: Lang[] = Object.keys(phrasesByLocale) as Lang[]; - -export const DEFAULT_LANGUAGE: Lang = 'en'; - -export const tKeys = buildTranslationKeys(en); - -const polyglot: Polyglot = new Polyglot({ - locale: DEFAULT_LANGUAGE, - phrases: phrasesByLocale[DEFAULT_LANGUAGE], -}); - -export const I18nContext = React.createContext({ - t: polyglot.t.bind(polyglot) as ITranslateFunction, - locale: DEFAULT_LANGUAGE, - changeLanguage: () => null, -}); diff --git a/src/services/i18n/index.ts b/src/services/i18n/index.ts deleted file mode 100644 index 36b4550e..00000000 --- a/src/services/i18n/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { default as I18nProvider } from './view/I18nProvider/I18nProvider'; -export { ITranslateProps, ITranslateFunction, ITranslateKey } from './namespace'; -export { withI18n } from './view/withI18n/withI18n'; -export { default as LanguageSelector } from './view/LanguageSelector/LanguageSelector'; -export { tKeys, I18nContext } from './constants'; diff --git a/src/services/i18n/namespace.ts b/src/services/i18n/namespace.ts deleted file mode 100644 index fbe87e69..00000000 --- a/src/services/i18n/namespace.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as Polyglot from 'node-polyglot'; - -type CustomTranslateFunction = (phrase: IPhraseWithOptions) => string; -interface IPhraseWithOptions { - key: string; - params: Record; -} - -export type ITranslateFunction = Polyglot['t'] & CustomTranslateFunction; -export type ITranslateKey = string | IPhraseWithOptions; - -export type Lang = 'en' | 'ru'; - -export interface ITranslateProps { - locale: Lang; - t: ITranslateFunction; - changeLanguage(lang: Lang): void; -} diff --git a/src/services/i18n/view/I18nProvider/I18nProvider.tsx b/src/services/i18n/view/I18nProvider/I18nProvider.tsx deleted file mode 100644 index 920f70cb..00000000 --- a/src/services/i18n/view/I18nProvider/I18nProvider.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import * as React from 'react'; -import { bind } from 'decko'; -import * as Polyglot from 'node-polyglot'; - -import { withProps } from 'shared/helpers/react'; - -import { ITranslateFunction, Lang, ITranslateKey } from '../../namespace'; -import { DEFAULT_LANGUAGE, I18nContext } from '../../constants'; -import { phrasesByLocale as phrases } from '../../locales'; - -interface IOwnProps { - phrasesByLocale: typeof phrases; -} - -interface IState { - locale: Lang; - translator: ITranslateFunction; - changeLanguage(lang: Lang): void; -} - -type IProps = IOwnProps; - -class I18nProvider extends React.Component { - public polyglot: Polyglot = new Polyglot({ - locale: DEFAULT_LANGUAGE, - phrases: this.props.phrasesByLocale[DEFAULT_LANGUAGE], - }); - - public state: IState = { - locale: DEFAULT_LANGUAGE, - translator: this.makeTranslator(this.polyglot), - changeLanguage: this.changeLanguage, - }; - - public componentDidUpdate(prevProps: IProps, prevState: IState) { - const { phrasesByLocale } = this.props; - const { locale } = this.state; - if (prevState.locale !== locale || prevProps.phrasesByLocale !== phrasesByLocale) { - this.polyglot.locale(locale); - this.polyglot.replace(phrasesByLocale[locale]); - this.setState({ translator: this.makeTranslator(this.polyglot) }); - } - } - - public render() { - const { children } = this.props; - const { locale, translator, changeLanguage } = this.state; - return ( - - {children} - - ); - } - - @bind - private changeLanguage(value: Lang) { - this.setState({ locale: value }); - } - - @bind - private makeTranslator(polyglot: Polyglot): ITranslateFunction { - return (phrase: ITranslateKey, smartCountOrInterpolationOptions?: number | Polyglot.InterpolationOptions) => { - if (typeof phrase === 'string') { - return polyglot.t(phrase, smartCountOrInterpolationOptions as any); - } - return polyglot.t(phrase.key, phrase.params); - }; - } -} - -export default withProps(I18nProvider, { phrasesByLocale: phrases }); diff --git a/src/services/i18n/view/withI18n/withI18n.tsx b/src/services/i18n/view/withI18n/withI18n.tsx deleted file mode 100644 index 955739a7..00000000 --- a/src/services/i18n/view/withI18n/withI18n.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as React from 'react'; -import { Omit } from '_helpers'; - -import { ITranslateProps } from '../../namespace'; -import { I18nContext } from '../../constants'; - -function withI18n( - WrappedComponent: React.ComponentType, -): React.ComponentClass> { - const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; - - class I18nConnector extends React.Component { - public static displayName: string = `I18nConnect(${wrappedComponentName})`; - - public render() { - return ( - - {(contextProps) => } - - ); - } - } - - return I18nConnector; -} - -export { withI18n }; diff --git a/src/services/i18n/helpers/buildTranslationKeys/buildTranslationKeys.test.ts b/src/shared/helpers/buildTranslationKeys/buildTranslationKeys.test.ts similarity index 100% rename from src/services/i18n/helpers/buildTranslationKeys/buildTranslationKeys.test.ts rename to src/shared/helpers/buildTranslationKeys/buildTranslationKeys.test.ts diff --git a/src/services/i18n/helpers/buildTranslationKeys/index.ts b/src/shared/helpers/buildTranslationKeys/index.ts similarity index 100% rename from src/services/i18n/helpers/buildTranslationKeys/index.ts rename to src/shared/helpers/buildTranslationKeys/index.ts diff --git a/src/services/i18n/locales/en.ts b/src/shared/locales/en.ts similarity index 64% rename from src/services/i18n/locales/en.ts rename to src/shared/locales/en.ts index b12f86b3..88a63aa6 100644 --- a/src/services/i18n/locales/en.ts +++ b/src/shared/locales/en.ts @@ -5,10 +5,11 @@ export default { documents: {}, modules: {}, demo: { - selectedLang: 'Selected language is %{locale}', + selectedLang: 'Selected language is {{lng, uppercase}}', selectorLabel: 'Language selector:', somethingText: 'Something text', pluralLabel: 'Pluralize demonstration:', - pluralTest: '%{smart_count} object |||| %{smart_count} objects', + pluralTest: '{{count}} object', + pluralTest_plural: '{{count}} objects', }, }; diff --git a/src/services/i18n/locales/index.ts b/src/shared/locales/index.ts similarity index 100% rename from src/services/i18n/locales/index.ts rename to src/shared/locales/index.ts diff --git a/src/services/i18n/locales/ru.ts b/src/shared/locales/ru.ts similarity index 63% rename from src/services/i18n/locales/ru.ts rename to src/shared/locales/ru.ts index 17e4f690..e0636f0b 100644 --- a/src/services/i18n/locales/ru.ts +++ b/src/shared/locales/ru.ts @@ -6,10 +6,12 @@ export default { modules: {}, modules1: {}, demo: { - selectedLang: 'Выбран язык %{locale}', + selectedLang: 'Выбран язык {{lng, uppercase}}', selectorLabel: 'Селектор языка:', somethingText: 'Какой-то текст', pluralLabel: 'Демонстрация множественных переводов:', - pluralTest: '%{smart_count} объект |||| %{smart_count} объекта |||| %{smart_count} объектов', + pluralTest: '{{count}} объект', + pluralTest_1: '{{count}} объекта', + pluralTest_2: '{{count}} объектов', }, }; diff --git a/src/shared/types/app.ts b/src/shared/types/app.ts index 7009d0e8..d6bffc79 100644 --- a/src/shared/types/app.ts +++ b/src/shared/types/app.ts @@ -54,7 +54,7 @@ export interface IAppReduxState { export type RootSaga = (deps: IDependencies) => () => SagaIterator; -export type Lang = 'en' | 'he'; +export type Lang = 'en' | 'ru'; export type Uid = number; diff --git a/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx b/src/shared/view/components/LanguageSelector/LanguageSelector.tsx similarity index 59% rename from src/services/i18n/view/LanguageSelector/LanguageSelector.tsx rename to src/shared/view/components/LanguageSelector/LanguageSelector.tsx index 97f79ee6..6008664f 100644 --- a/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx +++ b/src/shared/view/components/LanguageSelector/LanguageSelector.tsx @@ -1,26 +1,25 @@ import * as React from 'react'; import { bind } from 'decko'; - -import { Lang, ITranslateProps } from '../../namespace'; -import { withI18n } from '../withI18n/withI18n'; +import { withNamespaces as withI18n, WithNamespaces } from 'react-i18next'; +import { Lang } from 'shared/types/app'; interface IOption { value: Lang; label: string; } -class LanguageSelector extends React.PureComponent { +class LanguageSelector extends React.PureComponent { public static options: IOption[] = [ { value: 'en', label: 'en' }, { value: 'ru', label: 'ru' }, ]; public render() { - const { locale } = this.props; + const { lng } = this.props; return (
- {LanguageSelector.options.map(({ value, label }, i) => ( ))} @@ -31,8 +30,9 @@ class LanguageSelector extends React.PureComponent { @bind private changeLanguage({ target: { value } }: React.ChangeEvent) { - this.props.changeLanguage(value as Lang); + const { i18n } = this.props; + i18n.changeLanguage(value); } } -export default withI18n(LanguageSelector); +export default withI18n()(LanguageSelector); diff --git a/src/shared/view/components/index.ts b/src/shared/view/components/index.ts index a071b251..52a853cb 100644 --- a/src/shared/view/components/index.ts +++ b/src/shared/view/components/index.ts @@ -1,2 +1,3 @@ export { default as Header } from './Header/Header'; export { default as Footer } from './Footer/Footer'; +export { default as LanguageSelector } from './LanguageSelector/LanguageSelector'; From 5af28dc2847a222e050ccb12bd11a3f53a5273af Mon Sep 17 00:00:00 2001 From: clicktronix Date: Tue, 5 Feb 2019 13:05:39 +0600 Subject: [PATCH 02/33] Shrinkwrap updated --- npm-shrinkwrap.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index b1d4237a..8eaffa7e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -14872,14 +14872,6 @@ } } }, - "react-input-autosize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz", - "integrity": "sha512-3+K4CD13iE4lQQ2WlF8PuV5htfmTRLH6MDnfndHM6LuBRszuXnuyIfE7nhSKt8AzRBZ50bu0sAhkNMeS5pxQQA==", - "requires": { - "prop-types": "^15.5.8" - } - }, "react-is": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.1.tgz", From 6d93ac94e970f47fe074b755dc4c10869486bbe7 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sat, 9 Feb 2019 13:40:59 +0600 Subject: [PATCH 03/33] react-i18next moved at /services, react updated --- npm-shrinkwrap.json | 67 +++++++++++-------- package.json | 16 ++--- src/core/configurationI18n.ts | 35 ---------- src/core/configureApp.ts | 3 +- src/core/constants.ts | 4 +- .../DemoTranslations/DemoTranslations.tsx | 11 ++- src/services/i18n/constants.ts | 6 ++ .../buildTranslationKeys.test.ts | 0 .../helpers/buildTranslationKeys/index.ts | 0 src/services/i18n/i18nContainer.ts | 31 +++++++++ src/services/i18n/index.ts | 6 ++ src/{shared => services/i18n}/locales/en.ts | 2 +- .../i18n}/locales/index.ts | 0 src/{shared => services/i18n}/locales/ru.ts | 2 +- .../LanguageSelector/LanguageSelector.tsx | 11 +-- src/shared/view/components/index.ts | 1 - 16 files changed, 107 insertions(+), 88 deletions(-) delete mode 100644 src/core/configurationI18n.ts create mode 100644 src/services/i18n/constants.ts rename src/{shared => services/i18n}/helpers/buildTranslationKeys/buildTranslationKeys.test.ts (100%) rename src/{shared => services/i18n}/helpers/buildTranslationKeys/index.ts (100%) create mode 100644 src/services/i18n/i18nContainer.ts create mode 100644 src/services/i18n/index.ts rename src/{shared => services/i18n}/locales/en.ts (83%) rename src/{shared => services/i18n}/locales/index.ts (100%) rename src/{shared => services/i18n}/locales/ru.ts (87%) rename src/{shared/view/components => services/i18n/view}/LanguageSelector/LanguageSelector.tsx (68%) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 8eaffa7e..a1f29c81 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -750,18 +750,18 @@ "integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw==" }, "@types/react": { - "version": "16.7.20", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.7.20.tgz", - "integrity": "sha512-Qd5RWkwl6SL7R2XzLk/cicjVQm1Mhc6HqXY5Ei4pWd1Vi8Fkbd5O0sA398x8fRSTPAuHdDYD9nrWmJMYTJI0vQ==", + "version": "16.8.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.2.tgz", + "integrity": "sha512-6mcKsqlqkN9xADrwiUz2gm9Wg4iGnlVGciwBRYFQSMWG6MQjhOZ/AVnxn+6v8nslFgfYTV8fNdE6XwKu6va5PA==", "requires": { "@types/prop-types": "*", "csstype": "^2.2.0" } }, "@types/react-dom": { - "version": "16.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.0.11.tgz", - "integrity": "sha512-x6zUx9/42B5Kl2Vl9HlopV8JF64wLpX3c+Pst9kc1HgzrsH+mkehe/zmHMQTplIrR48H2gpU7ZqurQolYu8XBA==", + "version": "16.8.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.8.0.tgz", + "integrity": "sha512-Jp4ufcEEjVJEB0OHq2MCZcE1u3KYUKO6WnSuiU/tZeYeiZxUoQavfa/TZeiIT+1XoN6l0lQVNM30VINZFDeolQ==", "requires": { "@types/react": "*" } @@ -8568,9 +8568,9 @@ "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=" }, "i18next": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-14.0.1.tgz", - "integrity": "sha512-wsKfQuYsy4RdCaqqN71eDjWMhizhTfQSIBGttEA7vcboQrUfpQlCezrSzrtmoW9F9tmVyNs38iBgLYLMhRSeIQ==" + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-14.1.1.tgz", + "integrity": "sha512-HItn9RHLyrDqe6pw6qXMYHGPHNc3y1FZndJfBlD6k4sRS0FAlYLvqCDVIWFc1XultBgsv348TtvL/lleG6JgBg==" }, "i18next-browser-languagedetector": { "version": "2.2.4", @@ -14726,20 +14726,20 @@ } }, "react": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz", - "integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==", + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.1.tgz", + "integrity": "sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.12.0" + "scheduler": "^0.13.1" }, "dependencies": { "scheduler": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", - "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.1.tgz", + "integrity": "sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -14756,20 +14756,20 @@ } }, "react-dom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.7.0.tgz", - "integrity": "sha512-D0Ufv1ExCAmF38P2Uh1lwpminZFRXEINJe53zRAbm4KPwSyd6DY/uDoS0Blj9jvPpn1+wivKpZYc8aAAN/nAkg==", + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.1.tgz", + "integrity": "sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "scheduler": "^0.12.0" + "scheduler": "^0.13.1" }, "dependencies": { "scheduler": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", - "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.1.tgz", + "integrity": "sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -14848,12 +14848,12 @@ } }, "react-i18next": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-9.0.10.tgz", - "integrity": "sha512-xpeCWNut7ylQLs3Qqyo7dT13kgZbML1CdftbdnswLCv0RbRT16bRP16ma59iLe1KHIbn92VJo0Q8LSKYoXVNvg==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-10.0.2.tgz", + "integrity": "sha512-J8iKjJhdoeKFugf7oZU0w43MZ43LFjDUj0bYVPmz4I1nZlQZXTpvxMZaR3bzFQT7Uprmwv9av4OYkSunv/mDrA==", "requires": { "@babel/runtime": "^7.3.1", - "hoist-non-react-statics": "3.2.1", + "hoist-non-react-statics": "3.3.0", "html-parse-stringify2": "2.0.1" }, "dependencies": { @@ -14865,6 +14865,19 @@ "regenerator-runtime": "^0.12.0" } }, + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + } + }, + "react-is": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.1.tgz", + "integrity": "sha512-ioMCzVDWvCvKD8eeT+iukyWrBGrA3DiFYkXfBsVYIRdaREZuBjENG+KjrikavCLasozqRWTwFUagU/O4vPpRMA==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", diff --git a/package.json b/package.json index 261d658f..bc7686f6 100644 --- a/package.json +++ b/package.json @@ -198,11 +198,11 @@ "@types/classnames": "^2.2.6", "@types/compression": "0.0.36", "@types/cookie-parser": "^1.4.1", - "@types/node-polyglot": "^0.4.31", "@types/i18next-browser-languagedetector": "^2.0.1", + "@types/node-polyglot": "^0.4.31", "@types/ramda": "^0.25.29", - "@types/react": "^16.7.20", - "@types/react-dom": "^16.0.11", + "@types/react": "^16.8.2", + "@types/react-dom": "^16.8.0", "@types/react-helmet": "^5.0.7", "@types/react-hot-loader": "^4.1.0", "@types/react-redux": "^7.0.0", @@ -233,9 +233,9 @@ "favicons-webpack-plugin": "0.0.9", "file-loader": "^2.0.0", "final-form": "^4.11.0", - "inversify": "^5.0.1", - "i18next": "^14.0.1", + "i18next": "^14.1.1", "i18next-browser-languagedetector": "^2.2.4", + "inversify": "^5.0.1", "inversify-inject-decorators": "^3.1.0", "jss": "^9.8.3", "jss-compose": "^5.0.0", @@ -248,12 +248,12 @@ "postcss-reporter": "^6.0.0", "postcss-scss": "^2.0.0", "ramda": "^0.25.0", - "react": "^16.7.0", + "react": "^16.8.1", "react-async-bootstrapper": "^2.1.0", - "react-dom": "^16.7.0", + "react-dom": "^16.8.1", "react-final-form": "^4.0.2", "react-helmet": "^5.2.0", - "react-i18next": "^9.0.10", + "react-i18next": "^10.0.2", "react-jss": "^8.6.1", "react-number-format": "^4.0.6", "react-redux": "^6.0.0", diff --git a/src/core/configurationI18n.ts b/src/core/configurationI18n.ts deleted file mode 100644 index 6c4005b9..00000000 --- a/src/core/configurationI18n.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { default as i18n } from 'i18next'; -import { reactI18nextModule, withNamespaces as withI18n, WithNamespaces as ITranslateProps } from 'react-i18next'; -import { default as languageDetector } from 'i18next-browser-languagedetector'; - -import { en, ru } from 'shared/locales'; -import buildTranslationKeys from 'shared/helpers/buildTranslationKeys'; - -import { FALLBACK_LANGUAGE } from './constants'; - -const tKeys = buildTranslationKeys(en); -const resources = { - en: { - translation: en, - }, - ru: { - translation: ru, - }, -}; - -i18n - .use(languageDetector) - .use(reactI18nextModule) - .init({ - resources, - fallbackLng: FALLBACK_LANGUAGE, - interpolation: { - format: (value, format, _lng) => { - if (format === 'uppercase') { return value.toUpperCase(); } - return value; - }, - }, - }); - -export { tKeys, withI18n, ITranslateProps }; -export default i18n; diff --git a/src/core/configureApp.ts b/src/core/configureApp.ts index 8a2dc4cb..a0361625 100644 --- a/src/core/configureApp.ts +++ b/src/core/configureApp.ts @@ -2,11 +2,11 @@ import configureDeps from './configureDeps'; import { TYPES, container } from './configureIoc'; import configureStore, { createReducer } from './configureStore'; import { configureJss } from './configureJss'; -import './configurationI18n'; import { DemoModule } from 'modules'; import { ReducersMap } from 'shared/types/redux'; import { reduxEntry as themeProviderRE } from 'services/theme'; +import { makeI18nInstance } from 'services/i18n'; import { IAppData, IModule, RootSaga, IAppReduxState, IReduxEntry } from 'shared/types/app'; function configureApp(data?: IAppData): IAppData { @@ -36,6 +36,7 @@ function configureApp(data?: IAppData): IAppData { const dependencies = configureDeps(store); const jssDeps = configureJss(); + makeI18nInstance(); sharedReduxEntries.forEach(connectEntryToStore); modules.forEach((module: IModule) => { diff --git a/src/core/constants.ts b/src/core/constants.ts index e7fa0d4a..8337712e 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -1,3 +1 @@ -import { Lang } from 'shared/types/app'; - -export const FALLBACK_LANGUAGE: Lang = 'en'; +// diff --git a/src/modules/Demo/view/DemoTranslations/DemoTranslations.tsx b/src/modules/Demo/view/DemoTranslations/DemoTranslations.tsx index 54da39b2..176f73a9 100644 --- a/src/modules/Demo/view/DemoTranslations/DemoTranslations.tsx +++ b/src/modules/Demo/view/DemoTranslations/DemoTranslations.tsx @@ -1,12 +1,11 @@ import * as React from 'react'; -import { withI18n, tKeys, ITranslateProps } from 'core/configurationI18n'; -import { LanguageSelector } from 'shared/view/components'; +import { useTranslation, tKeys, LanguageSelector } from 'services/i18n'; -function DemoTranslations(props: ITranslateProps) { - const { t, lng } = props; +function DemoTranslations() { + const { t, i18n: { language } } = useTranslation(); return (
-

{t(tKeys.demo.selectedLang.getKey(), { lng })}

+

{t(tKeys.demo.selectedLang.getKey(), { language })}

{t(tKeys.demo.selectorLabel.getKey())}

{t(tKeys.demo.somethingText.getKey())}

@@ -20,4 +19,4 @@ function DemoTranslations(props: ITranslateProps) { ); } -export default withI18n()(DemoTranslations); +export default DemoTranslations; diff --git a/src/services/i18n/constants.ts b/src/services/i18n/constants.ts new file mode 100644 index 00000000..0739f26d --- /dev/null +++ b/src/services/i18n/constants.ts @@ -0,0 +1,6 @@ +import { Lang } from 'shared/types/app'; +import buildTranslationKeys from './helpers/buildTranslationKeys'; +import { en } from './locales'; + +export const FALLBACK_LANGUAGE: Lang = 'en'; +export const tKeys = buildTranslationKeys(en); diff --git a/src/shared/helpers/buildTranslationKeys/buildTranslationKeys.test.ts b/src/services/i18n/helpers/buildTranslationKeys/buildTranslationKeys.test.ts similarity index 100% rename from src/shared/helpers/buildTranslationKeys/buildTranslationKeys.test.ts rename to src/services/i18n/helpers/buildTranslationKeys/buildTranslationKeys.test.ts diff --git a/src/shared/helpers/buildTranslationKeys/index.ts b/src/services/i18n/helpers/buildTranslationKeys/index.ts similarity index 100% rename from src/shared/helpers/buildTranslationKeys/index.ts rename to src/services/i18n/helpers/buildTranslationKeys/index.ts diff --git a/src/services/i18n/i18nContainer.ts b/src/services/i18n/i18nContainer.ts new file mode 100644 index 00000000..79974e1c --- /dev/null +++ b/src/services/i18n/i18nContainer.ts @@ -0,0 +1,31 @@ +import { default as i18n } from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import { default as languageDetector } from 'i18next-browser-languagedetector'; + +import { FALLBACK_LANGUAGE } from './constants'; +import { en, ru } from './locales'; + +const resources = { + en: { + translation: en, + }, + ru: { + translation: ru, + }, +}; + +export const makeI18nInstance = () => { + i18n + .use(languageDetector) + .use(initReactI18next) + .init({ + resources, + fallbackLng: FALLBACK_LANGUAGE, + interpolation: { + format: (value, format, _lng) => { + if (format === 'uppercase') { return value.toUpperCase(); } + return value; + }, + }, + }); +}; diff --git a/src/services/i18n/index.ts b/src/services/i18n/index.ts new file mode 100644 index 00000000..246b09ee --- /dev/null +++ b/src/services/i18n/index.ts @@ -0,0 +1,6 @@ +import { withTranslation, WithTranslation, useTranslation } from 'react-i18next'; +import { tKeys } from './constants'; +import { makeI18nInstance } from './i18nContainer'; +import { default as LanguageSelector } from './view/LanguageSelector/LanguageSelector'; + +export { tKeys, withTranslation, WithTranslation, useTranslation, makeI18nInstance, LanguageSelector }; diff --git a/src/shared/locales/en.ts b/src/services/i18n/locales/en.ts similarity index 83% rename from src/shared/locales/en.ts rename to src/services/i18n/locales/en.ts index 88a63aa6..09a24ede 100644 --- a/src/shared/locales/en.ts +++ b/src/services/i18n/locales/en.ts @@ -5,7 +5,7 @@ export default { documents: {}, modules: {}, demo: { - selectedLang: 'Selected language is {{lng, uppercase}}', + selectedLang: 'Selected language is {{language, uppercase}}', selectorLabel: 'Language selector:', somethingText: 'Something text', pluralLabel: 'Pluralize demonstration:', diff --git a/src/shared/locales/index.ts b/src/services/i18n/locales/index.ts similarity index 100% rename from src/shared/locales/index.ts rename to src/services/i18n/locales/index.ts diff --git a/src/shared/locales/ru.ts b/src/services/i18n/locales/ru.ts similarity index 87% rename from src/shared/locales/ru.ts rename to src/services/i18n/locales/ru.ts index e0636f0b..fe2c8e8d 100644 --- a/src/shared/locales/ru.ts +++ b/src/services/i18n/locales/ru.ts @@ -6,7 +6,7 @@ export default { modules: {}, modules1: {}, demo: { - selectedLang: 'Выбран язык {{lng, uppercase}}', + selectedLang: 'Выбран язык {{language, uppercase}}', selectorLabel: 'Селектор языка:', somethingText: 'Какой-то текст', pluralLabel: 'Демонстрация множественных переводов:', diff --git a/src/shared/view/components/LanguageSelector/LanguageSelector.tsx b/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx similarity index 68% rename from src/shared/view/components/LanguageSelector/LanguageSelector.tsx rename to src/services/i18n/view/LanguageSelector/LanguageSelector.tsx index 6008664f..fe33cf4e 100644 --- a/src/shared/view/components/LanguageSelector/LanguageSelector.tsx +++ b/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { bind } from 'decko'; -import { withNamespaces as withI18n, WithNamespaces } from 'react-i18next'; +import { WithTranslation, withTranslation } from 'react-i18next'; + import { Lang } from 'shared/types/app'; interface IOption { @@ -8,18 +9,18 @@ interface IOption { label: string; } -class LanguageSelector extends React.PureComponent { +class LanguageSelector extends React.PureComponent { public static options: IOption[] = [ { value: 'en', label: 'en' }, { value: 'ru', label: 'ru' }, ]; public render() { - const { lng } = this.props; + const { i18n: { language } } = this.props; return (
- {LanguageSelector.options.map(({ value, label }, i) => ( ))} @@ -35,4 +36,4 @@ class LanguageSelector extends React.PureComponent { } } -export default withI18n()(LanguageSelector); +export default withTranslation()(LanguageSelector); diff --git a/src/shared/view/components/index.ts b/src/shared/view/components/index.ts index 52a853cb..a071b251 100644 --- a/src/shared/view/components/index.ts +++ b/src/shared/view/components/index.ts @@ -1,3 +1,2 @@ export { default as Header } from './Header/Header'; export { default as Footer } from './Footer/Footer'; -export { default as LanguageSelector } from './LanguageSelector/LanguageSelector'; From 3f3916f126e93391ad07e0713f7af42ea1c1b893 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sat, 9 Feb 2019 15:03:06 +0600 Subject: [PATCH 04/33] Fixed reat hot loader flow for i18n --- npm-shrinkwrap.json | 31 +++++++++++++++++++----------- package.json | 2 +- src/core/configureApp.ts | 3 +-- src/services/i18n/i18nContainer.ts | 28 +++++++++++++-------------- src/services/i18n/index.ts | 4 ++-- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index a1f29c81..8ab8387f 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -11140,9 +11140,9 @@ } }, "just-extend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-3.0.0.tgz", - "integrity": "sha512-Fu3T6pKBuxjWT/p4DkqGHFRsysc8OauWr4ZRTY9dIx07Y9O0RkoR5jcv28aeD1vuAwhm3nLkDurwLXoALp4DpQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", + "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", "dev": true }, "kew": { @@ -12125,18 +12125,27 @@ "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==" }, "nise": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.6.tgz", - "integrity": "sha512-1GedetLKzmqmgwabuMSqPsT7oumdR77SBpDfNNJhADRIeA3LN/2RVqR4fFqwvzhAqcTef6PPCzQwITE/YQ8S8A==", + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.8.tgz", + "integrity": "sha512-kGASVhuL4tlAV0tvA34yJYZIVihrUt/5bDwpp4tTluigxUr2bBlJeDXmivb6NuEdFkqvdv/Ybb9dm16PSKUhtw==", "dev": true, "requires": { - "@sinonjs/formatio": "3.0.0", - "just-extend": "^3.0.0", + "@sinonjs/formatio": "^3.1.0", + "just-extend": "^4.0.2", "lolex": "^2.3.2", "path-to-regexp": "^1.7.0", "text-encoding": "^0.6.4" }, "dependencies": { + "@sinonjs/formatio": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz", + "integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==", + "dev": true, + "requires": { + "@sinonjs/samsam": "^2 || ^3" + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -14817,9 +14826,9 @@ } }, "react-hot-loader": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.6.3.tgz", - "integrity": "sha512-FUvRO8dwbeLnc3mgLn8ARuSh8NnLBYJyiRjFn+grY/5GupSyPqv0U7ixgwXro77hwDplhm8z9wU7FlJ8kZqiAQ==", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.6.5.tgz", + "integrity": "sha512-ZPAJEWVd8KDdm6dcK0iWrnJiGHruLrcbkIpqn/wQmNjnROpsm2nzrWh23Yh3I/XAjB+35pMa/ZgariwGqwFD9A==", "dev": true, "requires": { "fast-levenshtein": "^2.0.6", diff --git a/package.json b/package.json index bc7686f6..2542eed9 100644 --- a/package.json +++ b/package.json @@ -167,7 +167,7 @@ "html-webpack-plugin": "^3.2.0", "jest": "^23.6.0", "mini-css-extract-plugin": "^0.4.5", - "react-hot-loader": "^4.6.3", + "react-hot-loader": "^4.6.5", "redux-devtools-extension": "^2.13.5", "sinon": "^7.1.1", "style-loader": "^0.21.0", diff --git a/src/core/configureApp.ts b/src/core/configureApp.ts index a0361625..6b854809 100644 --- a/src/core/configureApp.ts +++ b/src/core/configureApp.ts @@ -6,8 +6,8 @@ import { configureJss } from './configureJss'; import { DemoModule } from 'modules'; import { ReducersMap } from 'shared/types/redux'; import { reduxEntry as themeProviderRE } from 'services/theme'; -import { makeI18nInstance } from 'services/i18n'; import { IAppData, IModule, RootSaga, IAppReduxState, IReduxEntry } from 'shared/types/app'; +import 'services/i18n/i18nContainer'; function configureApp(data?: IAppData): IAppData { /* Prepare main app elements */ @@ -36,7 +36,6 @@ function configureApp(data?: IAppData): IAppData { const dependencies = configureDeps(store); const jssDeps = configureJss(); - makeI18nInstance(); sharedReduxEntries.forEach(connectEntryToStore); modules.forEach((module: IModule) => { diff --git a/src/services/i18n/i18nContainer.ts b/src/services/i18n/i18nContainer.ts index 79974e1c..83fc2f88 100644 --- a/src/services/i18n/i18nContainer.ts +++ b/src/services/i18n/i18nContainer.ts @@ -14,18 +14,18 @@ const resources = { }, }; -export const makeI18nInstance = () => { - i18n - .use(languageDetector) - .use(initReactI18next) - .init({ - resources, - fallbackLng: FALLBACK_LANGUAGE, - interpolation: { - format: (value, format, _lng) => { - if (format === 'uppercase') { return value.toUpperCase(); } - return value; - }, +i18n + .use(languageDetector) + .use(initReactI18next) + .init({ + resources, + fallbackLng: FALLBACK_LANGUAGE, + interpolation: { + format: (value, format, _lng) => { + if (format === 'uppercase') { return value.toUpperCase(); } + return value; }, - }); -}; + }, + }); + +export default i18n; diff --git a/src/services/i18n/index.ts b/src/services/i18n/index.ts index 246b09ee..c9eb06c0 100644 --- a/src/services/i18n/index.ts +++ b/src/services/i18n/index.ts @@ -1,6 +1,6 @@ import { withTranslation, WithTranslation, useTranslation } from 'react-i18next'; import { tKeys } from './constants'; -import { makeI18nInstance } from './i18nContainer'; +import { default as i18n } from './i18nContainer'; import { default as LanguageSelector } from './view/LanguageSelector/LanguageSelector'; -export { tKeys, withTranslation, WithTranslation, useTranslation, makeI18nInstance, LanguageSelector }; +export { tKeys, withTranslation, WithTranslation, useTranslation, i18n, LanguageSelector }; From 7e5b9aeff28d19315fc811e40670159a463b8dda Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sat, 9 Feb 2019 15:36:59 +0600 Subject: [PATCH 05/33] Deleted i18n export --- src/services/i18n/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/services/i18n/index.ts b/src/services/i18n/index.ts index c9eb06c0..3f2a3ead 100644 --- a/src/services/i18n/index.ts +++ b/src/services/i18n/index.ts @@ -1,6 +1,5 @@ import { withTranslation, WithTranslation, useTranslation } from 'react-i18next'; import { tKeys } from './constants'; -import { default as i18n } from './i18nContainer'; import { default as LanguageSelector } from './view/LanguageSelector/LanguageSelector'; -export { tKeys, withTranslation, WithTranslation, useTranslation, i18n, LanguageSelector }; +export { tKeys, withTranslation, WithTranslation, useTranslation, LanguageSelector }; From 3c93486301419c5d6c4217f9d8f363f82822889d Mon Sep 17 00:00:00 2001 From: clicktronix Date: Thu, 28 Mar 2019 16:33:27 +0300 Subject: [PATCH 06/33] Dirty commit --- npm-shrinkwrap.json | 2137 ++++++++++++++++++++++++++----------------- package.json | 4 +- 2 files changed, 1318 insertions(+), 823 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 92c18856..ea94ab24 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -14,45 +14,51 @@ } }, "@babel/core": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz", - "integrity": "sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.0.tgz", + "integrity": "sha512-Dzl7U0/T69DFOTwqz/FJdnOSWS57NpjNfCwMKHABr589Lg8uX1RrlBIJ7L5Dubt/xkLsx0xH5EBFzlBVes1ayA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.1.2", - "@babel/helpers": "^7.1.2", - "@babel/parser": "^7.1.2", - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.1.2", + "@babel/generator": "^7.4.0", + "@babel/helpers": "^7.4.0", + "@babel/parser": "^7.4.0", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.0", + "@babel/types": "^7.4.0", "convert-source-map": "^1.1.0", - "debug": "^3.1.0", - "json5": "^0.5.0", - "lodash": "^4.17.10", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "ms": "^2.1.1" } }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "minimist": "^1.2.0" } }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -68,22 +74,22 @@ } }, "@babel/generator": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.3.tgz", - "integrity": "sha512-ZoCZGcfIJFJuZBqxcY9OjC1KW2lWK64qrX1o4UYL3yshVhwKFYgzpWZ0vvtGMNJdTlvkw0W+HR1VnYN8q3QPFQ==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz", + "integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==", "dev": true, "requires": { - "@babel/types": "^7.1.3", + "@babel/types": "^7.4.0", "jsesc": "^2.5.1", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "source-map": "^0.5.0", "trim-right": "^1.0.1" }, "dependencies": { "jsesc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", - "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true } } @@ -109,23 +115,23 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", - "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz", + "integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.4.0" } }, "@babel/helpers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz", - "integrity": "sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.2.tgz", + "integrity": "sha512-gQR1eQeroDzFBikhrCccm5Gs2xBjZ57DNjGbqTaHo911IpmSxflOQWMAHPw/TXk8L3isv7s9lYzUkexOeTQUYg==", "dev": true, "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.1.2" + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.0", + "@babel/types": "^7.4.0" } }, "@babel/highlight": { @@ -183,9 +189,9 @@ } }, "@babel/parser": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.3.tgz", - "integrity": "sha512-gqmspPZOMW3MIRb9HlrnbZHXI1/KHTOroBwN1NcLL6pWxzqzEKGvRTq0W/PxS45OtQGbaFikSQpkS5zbnsQm2w==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.2.tgz", + "integrity": "sha512-9fJTDipQFvlfSVdD/JBtkiY0br9BtfvW2R8wo6CX/Ej2eMuV0gWPk1M67Mt3eggQvBqYW1FCEk8BN7WvGm/g5g==", "dev": true }, "@babel/runtime": { @@ -204,57 +210,37 @@ } }, "@babel/template": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz", - "integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz", + "integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.1.2", - "@babel/types": "^7.1.2" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - } + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0" } }, "@babel/traverse": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.4.tgz", - "integrity": "sha512-my9mdrAIGdDiSVBuMjpn/oXYpva0/EZwWL3sm3Wcy/AVWO2eXnsoZruOT9jOGNRXU8KbCIu5zsKnXcAJ6PcV6Q==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.0.tgz", + "integrity": "sha512-/DtIHKfyg2bBKnIN+BItaIlEg5pjAnzHOIQe5w+rHAw/rg9g0V7T4rqPX8BJPfW11kt3koyjAnTNwCzb28Y1PA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.1.3", + "@babel/generator": "^7.4.0", "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.1.3", - "@babel/types": "^7.1.3", - "debug": "^3.1.0", + "@babel/helper-split-export-declaration": "^7.4.0", + "@babel/parser": "^7.4.0", + "@babel/types": "^7.4.0", + "debug": "^4.1.0", "globals": "^11.1.0", - "lodash": "^4.17.10" + "lodash": "^4.17.11" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -269,13 +255,13 @@ } }, "@babel/types": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz", - "integrity": "sha512-RpPOVfK+yatXyn8n4PB1NW6k9qjinrXrRR8ugBN8fD6hCy5RXI6PSbVqpOJBO9oSaY7Nom4ohj35feb0UR9hSA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz", + "integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==", "dev": true, "requires": { "esutils": "^2.0.2", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "to-fast-properties": "^2.0.0" }, "dependencies": { @@ -631,6 +617,17 @@ "@types/range-parser": "*" } }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, "@types/history": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.2.tgz", @@ -719,6 +716,12 @@ "@types/webpack": "*" } }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, "@types/node": { "version": "10.12.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.9.tgz", @@ -878,6 +881,12 @@ } } }, + "@types/unist": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", + "dev": true + }, "@types/uuid": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz", @@ -886,6 +895,27 @@ "@types/node": "*" } }, + "@types/vfile": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/vfile/-/vfile-3.0.2.tgz", + "integrity": "sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/unist": "*", + "@types/vfile-message": "*" + } + }, + "@types/vfile-message": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-1.0.1.tgz", + "integrity": "sha512-mlGER3Aqmq7bqR1tTTIVHq8KSAFFRyGbrxuM8C/H82g6k7r2fS+IMEkIu3D7JHzG10NvPdR8DNx0jr0pwpp4dA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/unist": "*" + } + }, "@types/webpack": { "version": "4.4.23", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.4.23.tgz", @@ -2552,6 +2582,12 @@ "integrity": "sha512-1X8CnjFVQ+a+KW36uBNMTU5s8+v5FzeqrP7hTG5aTb4aPreSbZJlhwPon9VKMuEVgV++JM+SQrALY3kr7eswdg==", "dev": true }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", @@ -3379,6 +3415,24 @@ "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", "dev": true }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, "callsites": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", @@ -3704,12 +3758,6 @@ "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.0.2.tgz", "integrity": "sha512-oC7/DVAyfcY3UWKm0sN/oVoDedQDQiw/vIiAnuTWTpE5s0zWf7l3WY417Xw/Fbi/QbAjctAkxgMiS9P0s3zkmA==" }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -4158,9 +4206,9 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", + "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -4782,37 +4830,6 @@ } } }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - }, - "dependencies": { - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -5256,6 +5273,12 @@ "integrity": "sha512-kUlSC06PVvvjlMRpNIl3kR1NRXLEe86VQ7N0bQeaCZb2g+InShCeHQp/JvyYNTugMnRN2NvJhHlc3q12MWbbpg==", "dev": true }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", @@ -5495,12 +5518,6 @@ "estraverse": "^4.1.1" } }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", @@ -6359,13 +6376,12 @@ } }, "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-4.0.0.tgz", + "integrity": "sha512-AVSwsnbV8vH/UVbvgEhf3saVQXORNv0ZzSkvkhQIaia5Tia+JhGTaa/ePUSVoPHQyGayQNmYfkzFi3WZV5zcpA==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "^2.0.1" } }, "file-loader": { @@ -6578,17 +6594,56 @@ } }, "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "dev": true + }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", @@ -7178,8 +7233,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": false, - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "optional": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { "version": "1.2.0", @@ -7200,14 +7254,12 @@ "balanced-match": { "version": "1.0.0", "resolved": false, - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7222,20 +7274,17 @@ "code-point-at": { "version": "1.1.0", "resolved": false, - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "optional": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "concat-map": { "version": "0.0.1", "resolved": false, - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", "resolved": false, - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "optional": true + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", @@ -7352,8 +7401,7 @@ "inherits": { "version": "2.0.3", "resolved": false, - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "optional": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -7365,7 +7413,6 @@ "version": "1.0.0", "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7380,7 +7427,6 @@ "version": "3.0.4", "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7388,14 +7434,12 @@ "minimist": { "version": "0.0.8", "resolved": false, - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minipass": { "version": "2.2.4", "resolved": false, "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -7414,7 +7458,6 @@ "version": "0.5.1", "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, "requires": { "minimist": "0.0.8" } @@ -7495,8 +7538,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": false, - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "optional": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", @@ -7508,7 +7550,6 @@ "version": "1.4.0", "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "optional": true, "requires": { "wrappy": "1" } @@ -7594,8 +7635,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": false, - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "optional": true + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "safer-buffer": { "version": "2.1.2", @@ -7631,7 +7671,6 @@ "version": "1.0.2", "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7651,7 +7690,6 @@ "version": "3.0.1", "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7695,14 +7733,12 @@ "wrappy": { "version": "1.0.2", "resolved": false, - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "optional": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "yallist": { "version": "3.0.2", "resolved": false, - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "optional": true + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" } } }, @@ -7971,12 +8007,55 @@ "ini": "^1.3.4" } }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, "global-modules-path": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/global-modules-path/-/global-modules-path-2.3.0.tgz", "integrity": "sha512-HchvMJNYh9dGSCy8pOQ2O8u/hoXaL+0XhnrwH0RyLiSXMMTl9W3N6KUU73+JFOg5PGjtzl6VZzUQsnrpm7Szag==", "dev": true }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "global-tunnel-ng": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.6.0.tgz", @@ -7990,9 +8069,9 @@ } }, "globals": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", - "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", "dev": true }, "globby": { @@ -8024,9 +8103,9 @@ } }, "gonzales-pe": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.2.3.tgz", - "integrity": "sha512-Kjhohco0esHQnOiqqdJeNz/5fyPkOMD/d6XVjwTAoPGUFh0mCollPUTUTa2OZy4dYNAqlPIQdTiNzJTWdd9Htw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.2.4.tgz", + "integrity": "sha512-v0Ts/8IsSbh9n1OJRnSfa7Nlxi4AkXIsWB6vPept8FDbL4bXn3FNuxjYtO/nmBGu7GDkL9MFeGebeSu6l55EPQ==", "dev": true, "requires": { "minimist": "1.1.x" @@ -9026,6 +9105,24 @@ "import-from": "^2.1.0" } }, + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, "import-from": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", @@ -11191,9 +11288,9 @@ "integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII=" }, "js-base64": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz", - "integrity": "sha1-8OgK4DmkvWVLXygfyT8EqRSn/M4=" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", + "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==" }, "js-tokens": { "version": "3.0.1", @@ -11201,13 +11298,21 @@ "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc=" }, "js-yaml": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", - "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", + "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", "dev": true, "requires": { "argparse": "^1.0.7", - "esprima": "^2.6.0" + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } } }, "jsbn": { @@ -11543,9 +11648,9 @@ "dev": true }, "known-css-properties": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.8.0.tgz", - "integrity": "sha512-pku5zscbIr9YsA6lFU1nhFGSAXsdJtEQ2WilCL40d0YCoDofBlNohMUq32wyt7tpiiaZ09GKyLZFrB1ijx6+WA==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.11.0.tgz", + "integrity": "sha512-bEZlJzXo5V/ApNNa5z375mJC6Nrz4vG43UgcSCrg2OHC+yuB6j0iDSrY7RQ/+PRofFB03wNIIt9iXIVLr4wc7w==", "dev": true }, "latest-version": { @@ -11741,9 +11846,9 @@ "dev": true }, "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash.assign": { "version": "4.2.0", @@ -11879,16 +11984,62 @@ "integrity": "sha1-nDdwlHqCHsaXipNXHhphea/Nf8g=", "dev": true }, - "loglevel": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", - "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", - "dev": true - }, - "lolex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.0.0.tgz", - "integrity": "sha512-hcnW80h3j2lbUfFdMArd5UPA/vxZJ+G8vobd+wg3nVEQA0EigStbYcrG030FJxL6xiDDPEkoMatV9xIh5OecQQ==", + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "dev": true + }, + "lolex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.0.0.tgz", + "integrity": "sha512-hcnW80h3j2lbUfFdMArd5UPA/vxZJ+G8vobd+wg3nVEQA0EigStbYcrG030FJxL6xiDDPEkoMatV9xIh5OecQQ==", "dev": true }, "longest-streak": { @@ -12791,15 +12942,6 @@ } } }, - "node-releases": { - "version": "1.0.0-alpha.15", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.0.0-alpha.15.tgz", - "integrity": "sha512-hKG6hd/g6a9OV/ARt2qrxbRhe/4WEMFohTLOB9PNyTYvvI59gICZFzt9/mMgpYUTts06qXlN8H6UjfbIRdnW8A==", - "dev": true, - "requires": { - "semver": "^5.3.0" - } - }, "node-rest-client": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/node-rest-client/-/node-rest-client-1.8.0.tgz", @@ -12825,9 +12967,9 @@ } }, "node-sass": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.2.tgz", - "integrity": "sha512-LdxoJLZutx0aQXHtWIYwJKMj+9pTjneTcLWJgzf2XbGu0q5pRNqW5QvFCEdm3mc5rJOdru/mzln5d0EZLacf6g==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", + "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==", "requires": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -12842,12 +12984,146 @@ "meow": "^3.7.0", "mkdirp": "^0.5.1", "nan": "^2.10.0", - "node-gyp": "^3.3.1", + "node-gyp": "^3.8.0", "npmlog": "^4.0.0", - "request": "2.87.0", + "request": "^2.88.0", "sass-graph": "^2.2.4", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" + }, + "dependencies": { + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "requires": { + "mime-db": "~1.38.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + } } }, "nomnom": { @@ -13547,9 +13823,9 @@ } }, "parse-entities": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.0.tgz", - "integrity": "sha512-XXtDdOPLSB0sHecbEapQi6/58U/ODj/KWfIXmmMCJF/eRn8laX6LZbOyioMoETOOJoWRW8/qTSl5VQkUIfKM5g==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.1.tgz", + "integrity": "sha512-NBWYLQm1KSoDKk7GAHyioLTvCZ5QjdH/ASBBQTD3iLiAWJXS5bg1jEWI8nIJ+vgVvsceBVBcDGRWSo0KVQBvvg==", "dev": true, "requires": { "character-entities": "^1.0.0", @@ -13910,15 +14186,68 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "postcss": { - "version": "5.2.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.16.tgz", - "integrity": "sha1-cysxAAAPn/g3mkilODntCXN2rVc=", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz", + "integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==", "dev": true, "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "postcss-easy-import": { @@ -13990,14 +14319,20 @@ } }, "postcss-html": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.34.0.tgz", - "integrity": "sha512-BIW982Kbf9/RikInNhNS3/GA6x/qY/+jhVS9KumqXZtU9ss8Yq15HhPJ6mnaXcU5bFq2ULxpOv96mHPAErpGMQ==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz", + "integrity": "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==", "dev": true, "requires": { - "htmlparser2": "^3.9.2" + "htmlparser2": "^3.10.0" }, "dependencies": { + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", @@ -14008,23 +14343,23 @@ } }, "htmlparser2": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.0.tgz", - "integrity": "sha512-J1nEUGv+MkXS0weHNWVKJJ+UrLfePxRWpN3C9bEi9fLxL2+ggW94DQvgYVXsaT30PGwYRIZKNZXuyMhp3Di4bQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", "dev": true, "requires": { - "domelementtype": "^1.3.0", + "domelementtype": "^1.3.1", "domhandler": "^2.3.0", "domutils": "^1.5.1", "entities": "^1.1.1", "inherits": "^2.0.1", - "readable-stream": "^3.0.6" + "readable-stream": "^3.1.1" } }, "readable-stream": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.0.6.tgz", - "integrity": "sha512-9E1oLoOWfhSXHGv6QlwXJim7uNzd9EVlWK+21tCU9Ju/kR0/p2AZYPz4qSchgO8PlLIH4FpZYfzwS+rEksZjIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -14039,9 +14374,9 @@ "dev": true }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14110,22 +14445,21 @@ } }, "postcss-jsx": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/postcss-jsx/-/postcss-jsx-0.34.0.tgz", - "integrity": "sha512-UJISlEGWH/LeMYudAwq9GeqfyPW9AeRq87GHOlbquxOIakKr0Aqu6l9Cx0Fg20f3A9bKJcX1NGX4/xzIs7PlZQ==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/postcss-jsx/-/postcss-jsx-0.36.0.tgz", + "integrity": "sha512-/lWOSXSX5jlITCKFkuYU2WLFdrncZmjSVyNpHAunEgirZXLwI8RjU556e3Uz4mv0WVHnJA9d3JWb36lK9Yx99g==", "dev": true, "requires": { - "@babel/core": "^7.0.0", - "postcss-styled": ">=0.34.0" + "@babel/core": ">=7.1.0" } }, "postcss-less": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-2.0.0.tgz", - "integrity": "sha512-pPNsVnpCB13nBMOcl5GVh8JGmB0JGFjqkLUDzKdVpptFFKEe9wFdEzvh2j4lD2AD+7qcrUfw9Ta+oi5+Fw7jjQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz", + "integrity": "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==", "dev": true, "requires": { - "postcss": "^5.2.16" + "postcss": "^7.0.14" } }, "postcss-load-config": { @@ -14207,12 +14541,12 @@ } }, "postcss-markdown": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/postcss-markdown/-/postcss-markdown-0.34.0.tgz", - "integrity": "sha512-cKPggF9OMOKPoqDm5YpYszCqMsImFh78FK6P8p6IsEKZB6IkUJYKz0/QgadYy4jLb60jcFIHJ6v6jsMH7/ZQrA==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/postcss-markdown/-/postcss-markdown-0.36.0.tgz", + "integrity": "sha512-rl7fs1r/LNSB2bWRhyZ+lM/0bwKv9fhl38/06gF6mKMo/NPnp55+K1dSTosSVjFZc0e1ppBlu+WT91ba0PMBfQ==", "dev": true, "requires": { - "remark": "^9.0.0", + "remark": "^10.0.1", "unist-util-find-all-after": "^1.0.2" } }, @@ -14527,6 +14861,24 @@ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", "dev": true, + "requires": { + "postcss": "^7.0.0" + } + }, + "postcss-sass": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.3.5.tgz", + "integrity": "sha512-B5z2Kob4xBxFjcufFnhQ2HqJQ2y/Zs/ic5EZbCywCkxKd756Q40cIQ/veRDwSrw1BF6+4wUgmpm0sBASqVi65A==", + "dev": true, + "requires": { + "gonzales-pe": "^4.2.3", + "postcss": "^7.0.1" + } + }, + "postcss-scss": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.0.0.tgz", + "integrity": "sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug==", "requires": { "postcss": "^7.0.0" }, @@ -14535,7 +14887,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -14544,7 +14895,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -14554,14 +14904,12 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "postcss": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.5.tgz", "integrity": "sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ==", - "dev": true, "requires": { "chalk": "^2.4.1", "source-map": "^0.6.1", @@ -14571,28 +14919,37 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } } } }, - "postcss-sass": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.3.3.tgz", - "integrity": "sha512-uoRhfwZJHDRI8p2KQniTx4UwzYwKgQUhmFNJ7aysL3+tgFUfmv5TPX8UPnlE5gfrq6KHUUwPJ/nISFtzwxr7iQ==", + "postcss-selector-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", + "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "dev": true, "requires": { - "gonzales-pe": "^4.2.3", - "postcss": "^7.0.1" + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "postcss-sorting": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-4.0.0.tgz", + "integrity": "sha512-rN1USjy86i8rpr98PLVA0sYU4iZ+D1kU5vW/kKy6sZJTOm0O1HRD1JrX9KFyCtzU35XB9u3sMtLUoslKssIEoQ==", + "dev": true, + "requires": { + "lodash": "^4.17.4", + "postcss": "^7.0.0" }, "dependencies": { "ansi-styles": { @@ -14649,136 +15006,10 @@ } } }, - "postcss-scss": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.0.0.tgz", - "integrity": "sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "postcss": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.5.tgz", - "integrity": "sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.5.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-sorting": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-4.0.0.tgz", - "integrity": "sha512-rN1USjy86i8rpr98PLVA0sYU4iZ+D1kU5vW/kKy6sZJTOm0O1HRD1JrX9KFyCtzU35XB9u3sMtLUoslKssIEoQ==", - "dev": true, - "requires": { - "lodash": "^4.17.4", - "postcss": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "postcss": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.5.tgz", - "integrity": "sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.5.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "postcss-styled": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/postcss-styled/-/postcss-styled-0.34.0.tgz", - "integrity": "sha512-Uaeetr/xOiQWGJgzPFOr32/Bwykpfh9TVE26OpmwDb8eEN205TS/gqkt9ri+C6otQzQKXqbMfeZNbKYi7QpeNA==", - "dev": true - }, "postcss-syntax": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.34.0.tgz", - "integrity": "sha512-L36NZwq2UK743US+vl1CRMdBRZCBmFYfThP9n9jCFhX1Wfk6BqnRSgt0Fy8q44IwxPee/GCzlo7T1c1JIeUDlQ==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz", + "integrity": "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==", "dev": true }, "postcss-value-parser": { @@ -14920,6 +15151,11 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" + }, "public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -15791,20 +16027,20 @@ "dev": true }, "remark": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/remark/-/remark-9.0.0.tgz", - "integrity": "sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-10.0.1.tgz", + "integrity": "sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ==", "dev": true, "requires": { - "remark-parse": "^5.0.0", - "remark-stringify": "^5.0.0", - "unified": "^6.0.0" + "remark-parse": "^6.0.0", + "remark-stringify": "^6.0.0", + "unified": "^7.0.0" } }, "remark-parse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz", - "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-6.0.3.tgz", + "integrity": "sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg==", "dev": true, "requires": { "collapse-white-space": "^1.0.2", @@ -15825,9 +16061,9 @@ } }, "remark-stringify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-5.0.0.tgz", - "integrity": "sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-6.0.4.tgz", + "integrity": "sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg==", "dev": true, "requires": { "ccount": "^1.0.0", @@ -16879,14 +17115,25 @@ "dev": true }, "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" }, "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -17337,9 +17584,9 @@ "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" }, "stdout-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", - "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "requires": { "readable-stream": "^2.0.1" } @@ -17596,9 +17843,9 @@ "dev": true }, "stylelint": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-9.6.0.tgz", - "integrity": "sha512-Q0UcbFPRiC+3FejNyIBAWbMuKwZNAC0kvZtGQbjwA9LMKDod6xMlBsiIigQxmE3ywpmTeFj3mkG5Jj36EfC7XA==", + "version": "9.10.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-9.10.1.tgz", + "integrity": "sha512-9UiHxZhOAHEgeQ7oLGwrwoDR8vclBKlSX7r4fH0iuu0SfPwFaLkb1c7Q2j1cqg9P7IDXeAV2TvQML/fRQzGBBQ==", "dev": true, "requires": { "autoprefixer": "^9.0.0", @@ -17607,52 +17854,59 @@ "cosmiconfig": "^5.0.0", "debug": "^4.0.0", "execall": "^1.0.0", - "file-entry-cache": "^2.0.0", + "file-entry-cache": "^4.0.0", "get-stdin": "^6.0.0", - "globby": "^8.0.0", + "global-modules": "^2.0.0", + "globby": "^9.0.0", "globjoin": "^0.1.4", "html-tags": "^2.0.0", - "ignore": "^4.0.0", + "ignore": "^5.0.4", "import-lazy": "^3.1.0", "imurmurhash": "^0.1.4", - "known-css-properties": "^0.8.0", + "known-css-properties": "^0.11.0", "leven": "^2.1.0", "lodash": "^4.17.4", "log-symbols": "^2.0.0", "mathml-tag-names": "^2.0.1", "meow": "^5.0.0", - "micromatch": "^2.3.11", + "micromatch": "^3.1.10", "normalize-selector": "^0.2.0", "pify": "^4.0.0", - "postcss": "^7.0.0", - "postcss-html": "^0.34.0", - "postcss-jsx": "^0.34.0", - "postcss-less": "^2.0.0", - "postcss-markdown": "^0.34.0", + "postcss": "^7.0.13", + "postcss-html": "^0.36.0", + "postcss-jsx": "^0.36.0", + "postcss-less": "^3.1.0", + "postcss-markdown": "^0.36.0", "postcss-media-query-parser": "^0.2.3", "postcss-reporter": "^6.0.0", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^4.0.0", - "postcss-sass": "^0.3.0", + "postcss-sass": "^0.3.5", "postcss-scss": "^2.0.0", "postcss-selector-parser": "^3.1.0", - "postcss-styled": "^0.34.0", - "postcss-syntax": "^0.34.0", + "postcss-syntax": "^0.36.2", "postcss-value-parser": "^3.3.0", "resolve-from": "^4.0.0", "signal-exit": "^3.0.2", + "slash": "^2.0.0", "specificity": "^0.4.1", - "string-width": "^2.1.0", + "string-width": "^3.0.0", "style-search": "^0.1.0", "sugarss": "^2.0.0", "svg-tags": "^1.0.0", "table": "^5.0.0" }, "dependencies": { + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "ansi-styles": { @@ -17664,43 +17918,51 @@ "color-convert": "^1.9.0" } }, - "autoprefixer": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.3.1.tgz", - "integrity": "sha512-DY9gOh8z3tnCbJ13JIWaeQsoYncTGdsrgCceBaQSIL4nvdrLxgbRSBPevg2XbX7u4QCSfLheSJEEIUUSlkbx6Q==", - "dev": true, - "requires": { - "browserslist": "^4.3.3", - "caniuse-lite": "^1.0.30000898", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.5", - "postcss-value-parser": "^3.3.1" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, - "browserslist": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.3.tgz", - "integrity": "sha512-6h84UD1mmHeuQ9IucX6yzBc+KBYcBBTLYt2CXtY7GYCra6iE5kOm7oM+zuGw/0tjGtbJxjm58OvxSBmogEMCRQ==", + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000898", - "electron-to-chromium": "^1.3.81", - "node-releases": "^1.0.0-alpha.15" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, "camelcase": { @@ -17720,16 +17982,10 @@ "quick-lru": "^1.0.0" } }, - "caniuse-lite": { - "version": "1.0.30000899", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000899.tgz", - "integrity": "sha512-enC3zKfUCJxxwvUIsBkbHd54CtJw1KtIWvrK0JZxWD/fEN2knHaai45lndJ4xXAkyRAPyk60J3yagkKDWhfeMA==", - "dev": true - }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -17738,95 +17994,290 @@ } }, "cosmiconfig": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.6.tgz", - "integrity": "sha512-6DWfizHriCrFWURP1/qyhsiFvYdlJzbCzmtFWh744+KyWsJo5+kPzUZZaMRSSItoYc0pxFX7gEO7ZC1/gN/7AQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.1.0.tgz", + "integrity": "sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q==", "dev": true, "requires": { + "import-fresh": "^2.0.0", "is-directory": "^0.3.1", "js-yaml": "^3.9.0", + "lodash.get": "^4.4.2", "parse-json": "^4.0.0" } }, "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, - "electron-to-chromium": { - "version": "1.3.82", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz", - "integrity": "sha512-NI4nB2IWGcU4JVT1AE8kBb/dFor4zjLHMLsOROPahppeHrR0FG5uslxMmkp/thO1MvPjM2xhlKoY29/I60s0ew==", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "path-type": "^3.0.0" } }, - "globby": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", - "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fast-glob": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", + "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globby": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.1.0.tgz", + "integrity": "sha512-VtYjhHr7ncls724Of5W6Kaahz0ag7dB4G62/2HsN+xEKG6SrPzM1AJMerGxQTwJGnN9reeyxdvXbuZYpfssCvg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.1", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + } + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -17834,9 +18285,9 @@ "dev": true }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.0.6.tgz", + "integrity": "sha512-/+hp3kUf/Csa32ktIaj0OlRqQxrgs30n62M90UBpNd9k+ENEch5S+hmbW3DtcJGz3sYFTh4F3A6fQ0q7KWsp4w==", "dev": true }, "import-lazy": { @@ -17851,22 +18302,73 @@ "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", "dev": true }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -17887,15 +18389,6 @@ } } }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, "map-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", @@ -17919,6 +18412,33 @@ "yargs-parser": "^10.0.0" } }, + "merge2": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -17967,49 +18487,6 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, - "postcss": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.5.tgz", - "integrity": "sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.5.0" - } - }, - "postcss-reporter": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.0.tgz", - "integrity": "sha512-5xQXm1UPWuFObjbtyQzWvQaupru8yFcFi4HUlm6OPo1o2bUszYASuqRJ7bVArb3svGCdbYtqdMBKrqR1Aoy+tw==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "lodash": "^4.17.4", - "log-symbols": "^2.0.0", - "postcss": "^7.0.2" - } - }, - "postcss-scss": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.0.0.tgz", - "integrity": "sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", - "dev": true, - "requires": { - "dot-prop": "^4.1.1", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -18041,29 +18518,30 @@ "strip-indent": "^2.0.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } }, "strip-bom": { @@ -18249,60 +18727,6 @@ "dev": true, "requires": { "postcss": "^7.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "postcss": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.5.tgz", - "integrity": "sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.5.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "supports-color": { @@ -18358,21 +18782,21 @@ "dev": true }, "table": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz", - "integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", + "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", "dev": true, "requires": { - "ajv": "^6.5.3", - "lodash": "^4.17.10", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" }, "dependencies": { "ajv": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz", - "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -18382,9 +18806,9 @@ } }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "fast-deep-equal": { @@ -18412,22 +18836,23 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } }, "uri-js": { @@ -19146,24 +19571,33 @@ "dev": true }, "true-case-path": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", - "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "requires": { - "glob": "^6.0.4" + "glob": "^7.1.2" }, "dependencies": { "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "requires": { + "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "2 || 3", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -19854,16 +20288,18 @@ } }, "unified": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz", - "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-7.1.0.tgz", + "integrity": "sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw==", "dev": true, "requires": { + "@types/unist": "^2.0.0", + "@types/vfile": "^3.0.0", "bail": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^1.1.0", "trough": "^1.0.0", - "vfile": "^2.0.0", + "vfile": "^3.0.0", "x-is-string": "^0.1.0" } }, @@ -20321,17 +20757,23 @@ } }, "vfile": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz", - "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-3.0.1.tgz", + "integrity": "sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ==", "dev": true, "requires": { - "is-buffer": "^1.1.4", + "is-buffer": "^2.0.0", "replace-ext": "1.0.0", "unist-util-stringify-position": "^1.0.0", "vfile-message": "^1.0.0" }, "dependencies": { + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + }, "replace-ext": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", @@ -20341,15 +20783,15 @@ } }, "vfile-location": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.3.tgz", - "integrity": "sha512-zM5/l4lfw1CBoPx3Jimxoc5RNDAHHpk6AM6LM0pTIkm5SUSsx8ZekZ0PVdf0WEZ7kjlhSt7ZlqbRL6Cd6dBs6A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.4.tgz", + "integrity": "sha512-KRL5uXQPoUKu+NGvQVL4XLORw45W62v4U4gxJ3vRlDfI9QsT4ZN1PNXn/zQpKUulqGDpYuT0XDfp5q9O87/y/w==", "dev": true }, "vfile-message": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.0.1.tgz", - "integrity": "sha512-vSGCkhNvJzO6VcWC6AlJW4NtYOVtS+RgCaqFIYUjoGIlHnFL+i0LbtYvonDWOMcB97uTPT4PRsyYY7REWC9vug==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", + "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", "dev": true, "requires": { "unist-util-stringify-position": "^1.1.1" @@ -21771,9 +22213,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" @@ -22156,6 +22598,165 @@ } } }, + "yeoman-environment": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.3.4.tgz", + "integrity": "sha512-KLxE5ft/74Qj7h3AsQZv8G6MEEHYJwmD5F99nfOVaep3rBzCtbrJKkdqWc7bDV141Nr8UZZsIXmzc3IcCm6E2w==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "debug": "^3.1.0", + "diff": "^3.5.0", + "escape-string-regexp": "^1.0.2", + "globby": "^8.0.1", + "grouped-queue": "^0.3.3", + "inquirer": "^6.0.0", + "is-scoped": "^1.0.0", + "lodash": "^4.17.10", + "log-symbols": "^2.2.0", + "mem-fs": "^1.1.0", + "strip-ansi": "^4.0.0", + "text-table": "^0.2.0", + "untildify": "^3.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "yn": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", @@ -22199,12 +22800,6 @@ "yosay": "^2.0.2" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -22247,21 +22842,6 @@ "which": "^1.2.9" } }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -22271,35 +22851,6 @@ "locate-path": "^3.0.0" } }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globby": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", - "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - } - }, "got": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", @@ -22353,30 +22904,6 @@ "path-exists": "^3.0.0" } }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, "p-limit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", @@ -22465,15 +22992,6 @@ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "dev": true }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -22488,29 +23006,6 @@ "requires": { "has-flag": "^3.0.0" } - }, - "yeoman-environment": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.3.3.tgz", - "integrity": "sha512-HBpXdNw8V66EwqIFt01rNhSgX33BOzgVb9CxpIvESvCI4ELeOSniB6gV6RXwrBur8kmHZCIAkYQYpib7Qxx8FQ==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "diff": "^3.5.0", - "escape-string-regexp": "^1.0.2", - "globby": "^8.0.1", - "grouped-queue": "^0.3.3", - "inquirer": "^6.0.0", - "is-scoped": "^1.0.0", - "lodash": "^4.17.10", - "log-symbols": "^2.2.0", - "mem-fs": "^1.1.0", - "strip-ansi": "^4.0.0", - "text-table": "^0.2.0", - "untildify": "^3.0.3" - } } } }, diff --git a/package.json b/package.json index e5f7b4ac..c5141415 100644 --- a/package.json +++ b/package.json @@ -184,7 +184,7 @@ "redux-devtools-extension": "^2.13.5", "sinon": "^7.1.1", "style-loader": "^0.21.0", - "stylelint": "^9.6.0", + "stylelint": "^9.10.1", "stylelint-config-standard": "^18.2.0", "stylelint-order": "^1.0.0", "stylelint-scss": "^3.3.2", @@ -254,7 +254,7 @@ "jss": "^9.8.3", "jss-compose": "^5.0.0", "node-polyglot": "^2.3.0", - "node-sass": "^4.9.2", + "node-sass": "^4.11.0", "normalize.css": "^8.0.0", "normalizr": "^2.3.1", "postcss-easy-import": "^3.0.0", From ebf04438d6a5cb011ae7c409628ae68dd530bc8b Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sun, 31 Mar 2019 16:36:24 +0300 Subject: [PATCH 07/33] Added translations for components --- .../containers/ProfileEdit/ProfileEdit.tsx | 33 ++++++--- .../ProfilePreview/ProfilePreview.tsx | 13 ++-- .../RepositoriesSearchForm.tsx | 11 +-- .../RepositoriesSearchSettings.tsx | 11 +-- .../containers/UserDetails/UserDetails.tsx | 31 ++++++--- .../UsersSearchForm/UsersSearchForm.tsx | 9 ++- .../UsersSearchSettings.tsx | 27 +++++--- .../ProfileLayout/ProfileLayout.tsx | 5 +- .../RepositoriesSearchLayout.tsx | 6 +- .../UsersSearchLayout/UsersSearchLayout.tsx | 6 +- src/modules/shared/Layout/Layout.tsx | 39 ++++++----- .../LayoutHeaderMenu/LayoutHeaderMenu.tsx | 17 +++-- src/services/i18n/index.ts | 6 +- src/services/i18n/locales/en.ts | 63 ++++++++++++++--- src/services/i18n/locales/ru.ts | 67 +++++++++++++++---- .../view/components/SearchForm/SearchForm.tsx | 13 ++-- .../SearchSettingsDialog.tsx | 13 +++- 17 files changed, 267 insertions(+), 103 deletions(-) diff --git a/src/features/profile/view/containers/ProfileEdit/ProfileEdit.tsx b/src/features/profile/view/containers/ProfileEdit/ProfileEdit.tsx index a9d1eec1..eb831b0b 100644 --- a/src/features/profile/view/containers/ProfileEdit/ProfileEdit.tsx +++ b/src/features/profile/view/containers/ProfileEdit/ProfileEdit.tsx @@ -4,6 +4,7 @@ import { connect } from 'react-redux'; import { Form, FormRenderProps } from 'react-final-form'; import { bind } from 'decko'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import { TextInputField, NumberInputField } from 'shared/view/form'; import { Button } from 'shared/view/elements'; import { IAppReduxState } from 'shared/types/app'; @@ -23,7 +24,7 @@ interface IStateProps { type IActionProps = typeof mapDispatch; -type IProps = IStateProps & IActionProps; +type IProps = IStateProps & IActionProps & WithTranslation; function mapState(state: IAppReduxState): IStateProps { return { @@ -37,6 +38,7 @@ const mapDispatch = { }; const b = block('profile-edit'); +const { profile: profileT } = tKeys.features; class ProfileEdit extends React.PureComponent { public render() { @@ -53,7 +55,7 @@ class ProfileEdit extends React.PureComponent { @bind private renderForm({ handleSubmit }: FormRenderProps) { - const { profile: { avatarURL } } = this.props; + const { profile: { avatarURL }, t } = this.props; return (
@@ -61,19 +63,29 @@ class ProfileEdit extends React.PureComponent {
- +
- +
- +
- +
- +
@@ -82,10 +94,11 @@ class ProfileEdit extends React.PureComponent { @bind private handleFormSubmit(values: IProfileEditFormFields) { - const { saveProfile, setNotification } = this.props; + const { saveProfile, setNotification, t } = this.props; saveProfile(values); - setNotification({ kind: 'info', text: 'User data was saved.' }); + setNotification({ kind: 'info', text: t(tKeys.shared.notifications.saved.getKey()) }); } } -export default connect(mapState, mapDispatch)(ProfileEdit); +const connectedComponent = connect(mapState, mapDispatch)(ProfileEdit); +export default withTranslation()(connectedComponent); diff --git a/src/features/profile/view/containers/ProfilePreview/ProfilePreview.tsx b/src/features/profile/view/containers/ProfilePreview/ProfilePreview.tsx index ef966f3a..38a3824e 100644 --- a/src/features/profile/view/containers/ProfilePreview/ProfilePreview.tsx +++ b/src/features/profile/view/containers/ProfilePreview/ProfilePreview.tsx @@ -3,6 +3,7 @@ import block from 'bem-cn'; import { connect } from 'react-redux'; import { bind } from 'decko'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import { IAppReduxState } from 'shared/types/app'; import { IProfile } from 'shared/types/models'; import { Popover } from 'shared/view/components'; @@ -23,9 +24,10 @@ interface IStateProps { profile: IProfile; } -type IProps = IOwnProps & IStateProps; +type IProps = IOwnProps & IStateProps & WithTranslation; const b = block('profile-preview'); +const { profile } = tKeys.features; function mapState(state: IAppReduxState): IStateProps { return { @@ -41,7 +43,7 @@ class ProfilePreview extends React.PureComponent { private blockRef = React.createRef(); public render() { - const { profile: { avatarURL, name, nickname, age, bio }, onEditClick } = this.props; + const { profile: { avatarURL, name, nickname, age, bio }, onEditClick, t } = this.props; const { isOpen } = this.state; return (
@@ -64,7 +66,7 @@ class ProfilePreview extends React.PureComponent { {nickname}
- {age} y.o. + {age + ' ' + t(profile.yearsOld.getKey())}
@@ -72,7 +74,7 @@ class ProfilePreview extends React.PureComponent { {bio}
- Edit + {t(profile.edit.getKey())}
@@ -92,4 +94,5 @@ class ProfilePreview extends React.PureComponent { } -export default connect(mapState)(ProfilePreview); +const connectedComponent = connect(mapState)(ProfilePreview); +export default withTranslation()(connectedComponent); diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx index 50e5f787..a3c7a747 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx @@ -2,10 +2,11 @@ import React from 'react'; import { connect } from 'react-redux'; import { bind } from 'decko'; +import { withTranslation, WithTranslation } from 'services/i18n'; import { IAppReduxState } from 'shared/types/app'; import { SearchForm } from 'shared/view/components'; -import RepositoriesSearchSettings from './RepositoriesSearchSettings/RepositoriesSearchSettings'; +import RepositoriesSearchSettings from './RepositoriesSearchSettings/RepositoriesSearchSettings'; import { selectors, actions } from './../../../redux'; import { IRepositoriesSearchFormFields } from '../../../namespace'; import { fieldNames } from './constants'; @@ -20,7 +21,7 @@ interface IStateProps { type IActionProps = typeof mapDispatch; -type IProps = IOwnProps & IStateProps & IActionProps; +type IProps = IOwnProps & IStateProps & IActionProps & WithTranslation; const mapDispatch = { searchRepositories: actions.searchRepositories, @@ -35,9 +36,10 @@ function mapState(state: IAppReduxState): IStateProps { class RepositoriesSearchForm extends React.PureComponent { public render() { - const { isRepositoriesSearchRequesting, resetSearchResults } = this.props; + const { isRepositoriesSearchRequesting, resetSearchResults, t } = this.props; return ( + t={t} searchInputName={fieldNames.searchString} isSearchRequesting={isRepositoriesSearchRequesting} onSubmit={this.handleFormSubmit} @@ -55,4 +57,5 @@ class RepositoriesSearchForm extends React.PureComponent { } } -export default connect(mapState, mapDispatch)(RepositoriesSearchForm); +const connectedComponent = connect(mapState, mapDispatch)(RepositoriesSearchForm); +export default withTranslation()(connectedComponent); diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchSettings/RepositoriesSearchSettings.tsx b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchSettings/RepositoriesSearchSettings.tsx index 029c1972..048af357 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchSettings/RepositoriesSearchSettings.tsx +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchSettings/RepositoriesSearchSettings.tsx @@ -1,27 +1,30 @@ import React from 'react'; import block from 'bem-cn'; +import { useTranslation, tKeys } from 'services/i18n'; import { TextInputField, NumberInputField } from 'shared/view/form'; import { fieldNames } from '../constants'; import './RepositoriesSearchSettings.scss'; const b = block('repositories-search-settings'); +const { repositoriesSearch } = tKeys.features; function RepositoriesSearchSettings() { + const { t } = useTranslation(); return (
@@ -29,11 +32,11 @@ function RepositoriesSearchSettings() {
- +
diff --git a/src/features/usersSearch/view/containers/UserDetails/UserDetails.tsx b/src/features/usersSearch/view/containers/UserDetails/UserDetails.tsx index 35ef69f8..f07859ac 100644 --- a/src/features/usersSearch/view/containers/UserDetails/UserDetails.tsx +++ b/src/features/usersSearch/view/containers/UserDetails/UserDetails.tsx @@ -7,6 +7,7 @@ import { IAppReduxState } from 'shared/types/app'; import { IDetailedGithubUser } from 'shared/types/models'; import { Dialog } from 'shared/view/components'; import { Typography, Preloader } from 'shared/view/elements'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import { UserAttribute } from '../../components'; import { injectSizeToAvatarURL } from '../../../helpers'; @@ -25,7 +26,7 @@ interface IStateProps { type IActionProps = typeof mapDispatch; -type IProps = IStateProps & IActionProps & IOwnProps; +type IProps = IStateProps & IActionProps & IOwnProps & WithTranslation; function mapState(state: IAppReduxState): IStateProps { return { @@ -39,16 +40,17 @@ const mapDispatch = { }; const b = block('user-details'); +const { userSearch } = tKeys.features; class UserDetails extends React.Component { private avatarSize = 230; public render() { - const { isLoadUserDetailsRequesting } = this.props; + const { isLoadUserDetailsRequesting, t } = this.props; return ( @@ -63,7 +65,7 @@ class UserDetails extends React.Component { } private renderContent() { - const { userDetails } = this.props; + const { userDetails, t } = this.props; if (userDetails) { const { htmlURL, avatarURL, realName, username, location, @@ -81,9 +83,21 @@ class UserDetails extends React.Component { {location && {location}}
- - - + + +
); @@ -105,4 +119,5 @@ class UserDetails extends React.Component { } } -export default connect(mapState, mapDispatch)(UserDetails); +const connectedComponent = connect(mapState, mapDispatch)(UserDetails); +export default withTranslation()(connectedComponent); diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx index 4814ed91..221bbd62 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { bind } from 'decko'; +import { withTranslation, WithTranslation } from 'services/i18n'; import { IAppReduxState } from 'shared/types/app'; import { SearchForm } from 'shared/view/components'; @@ -20,7 +21,7 @@ interface IStateProps { type IActionProps = typeof mapDispatch; -type IProps = IOwnProps & IStateProps & IActionProps; +type IProps = IOwnProps & IStateProps & IActionProps & WithTranslation; const mapDispatch = { searchUser: actions.searchUser, @@ -35,9 +36,10 @@ function mapState(state: IAppReduxState): IStateProps { class UsersSearchForm extends React.PureComponent { public render() { - const { isUsersSearchRequesting, resetSearchResults } = this.props; + const { isUsersSearchRequesting, resetSearchResults, t } = this.props; return ( + t={t} isSearchRequesting={isUsersSearchRequesting} searchInputName={fieldNames.searchString} onSubmit={this.handleFormSubmit} @@ -56,4 +58,5 @@ class UsersSearchForm extends React.PureComponent { } } -export default connect(mapState, mapDispatch)(UsersSearchForm); +const connectedComponent = connect(mapState, mapDispatch)(UsersSearchForm); +export default withTranslation()(connectedComponent); diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx index 7e023c84..a859d89e 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx @@ -3,56 +3,63 @@ import block from 'bem-cn'; import { FormLabel } from 'shared/view/elements'; import { TextInputField, SelectField, NumberInputField, RadioField } from 'shared/view/form'; +import { useTranslation, tKeys } from 'services/i18n'; import { searchByOptions, perPageOptions, fieldNames } from '../constants'; import './UsersSearchSettings.scss'; const b = block('users-search-settings'); +const { userSearch } = tKeys.features; function UsersSearchSettings() { + const { t } = useTranslation(); return (
- +
- +
- Search type + {t(userSearch.searchType.getKey())}
- - - + + +
- Repositories number + {t(userSearch.repositoriesNumber.getKey())}
- +
diff --git a/src/modules/Profile/view/components/ProfileLayout/ProfileLayout.tsx b/src/modules/Profile/view/components/ProfileLayout/ProfileLayout.tsx index 3fe5b0e5..5e4a56c0 100644 --- a/src/modules/Profile/view/components/ProfileLayout/ProfileLayout.tsx +++ b/src/modules/Profile/view/components/ProfileLayout/ProfileLayout.tsx @@ -4,6 +4,7 @@ import block from 'bem-cn'; import * as features from 'features'; import { featureConnect } from 'core'; import Layout from 'modules/shared/Layout/Layout'; +import { useTranslation, tKeys } from 'services/i18n'; import './ProfileLayout.scss'; @@ -18,8 +19,10 @@ const b = block('profile-layout'); function ProfileLayout(props: IProps) { const { profileFeatureEntry: { containers } } = props; const { ProfileEdit } = containers; + const { t } = useTranslation(); + return ( - +
diff --git a/src/modules/Search/view/components/RepositoriesSearchLayout/RepositoriesSearchLayout.tsx b/src/modules/Search/view/components/RepositoriesSearchLayout/RepositoriesSearchLayout.tsx index bd39b719..dbc06b54 100644 --- a/src/modules/Search/view/components/RepositoriesSearchLayout/RepositoriesSearchLayout.tsx +++ b/src/modules/Search/view/components/RepositoriesSearchLayout/RepositoriesSearchLayout.tsx @@ -3,6 +3,7 @@ import block from 'bem-cn'; import * as features from 'features'; import featureConnect from 'core/FeatureConnector'; +import { useTranslation, tKeys } from 'services/i18n'; import Layout from 'modules/shared/Layout/Layout'; import './RepositoriesSearchLayout.scss'; @@ -20,12 +21,13 @@ function RepositoriesSearchLayout(props: IProps) { const { RepositoriesSearchForm, RepositoriesSearchResults } = containers; const [lastSubmittedFormState, setLastSubmittedFormState] = useState(null); + const { t } = useTranslation(); return ( - +
- +
{lastSubmittedFormState && diff --git a/src/modules/Search/view/components/UsersSearchLayout/UsersSearchLayout.tsx b/src/modules/Search/view/components/UsersSearchLayout/UsersSearchLayout.tsx index c4733cf3..943f84b3 100644 --- a/src/modules/Search/view/components/UsersSearchLayout/UsersSearchLayout.tsx +++ b/src/modules/Search/view/components/UsersSearchLayout/UsersSearchLayout.tsx @@ -2,9 +2,10 @@ import React, { useState } from 'react'; import block from 'bem-cn'; import * as features from 'features'; +import { useTranslation, tKeys } from 'services/i18n'; import featureConnect from 'core/FeatureConnector'; - import Layout from 'modules/shared/Layout/Layout'; + import './UsersSearchLayout.scss'; interface IFeatureProps { @@ -21,9 +22,10 @@ function UsersSearchLayout(props: IProps) { const { usersSearchFeatureEntry: { containers } } = props; const { UsersSearchForm, UsersSearchResults } = containers; + const { t } = useTranslation(); return ( - +
diff --git a/src/modules/shared/Layout/Layout.tsx b/src/modules/shared/Layout/Layout.tsx index 6453f7af..94cd9130 100644 --- a/src/modules/shared/Layout/Layout.tsx +++ b/src/modules/shared/Layout/Layout.tsx @@ -5,6 +5,7 @@ import { bind } from 'decko'; import { featureConnect } from 'core'; import * as features from 'features'; +import { LanguageSelector, withTranslation, WithTranslation, tKeys } from 'services/i18n'; import LayoutHeaderMenu, { IHeaderMenuItem } from './LayoutHeaderMenu/LayoutHeaderMenu'; import routes from '../../routes'; @@ -18,33 +19,36 @@ interface IFeatureProps { profileFeatureEntry: features.profile.Entry; } -type IProps = IOwnProps & IFeatureProps & RouteComponentProps & React.ComponentProps<'div'>; +type IProps = IOwnProps & IFeatureProps & RouteComponentProps & React.ComponentProps<'div'> & WithTranslation; const b = block('layout'); +const { header, footer } = tKeys.shared; class Layout extends React.Component { - private menuItems: IHeaderMenuItem[] = [ - { - path: routes.search.users.getRoutePath(), - title: 'Users', - }, - { - path: routes.search.repositories.getRoutePath(), - title: 'Repositories', - }, - ]; - public render() { - const { children, title, profileFeatureEntry: { containers } } = this.props; + const { children, title, profileFeatureEntry: { containers }, t } = this.props; const { ProfilePreview } = containers; + const menuItems: IHeaderMenuItem[] = [ + { + path: routes.search.users.getRoutePath(), + title: this.props.t(header.users.getKey()), + }, + { + path: routes.search.repositories.getRoutePath(), + title: this.props.t(header.repositories.getKey()), + }, + ]; return (
- + +
+
+ +
-
@@ -56,7 +60,7 @@ class Layout extends React.Component { @@ -71,6 +75,7 @@ class Layout extends React.Component { } } +const wrappedComponent = withTranslation()(withRouter(Layout)); export default featureConnect({ profileFeatureEntry: features.profile.loadEntry, -})(withRouter(Layout)); +})(wrappedComponent); diff --git a/src/modules/shared/Layout/LayoutHeaderMenu/LayoutHeaderMenu.tsx b/src/modules/shared/Layout/LayoutHeaderMenu/LayoutHeaderMenu.tsx index 4712f485..8cc706b9 100644 --- a/src/modules/shared/Layout/LayoutHeaderMenu/LayoutHeaderMenu.tsx +++ b/src/modules/shared/Layout/LayoutHeaderMenu/LayoutHeaderMenu.tsx @@ -5,6 +5,7 @@ import { Link } from 'react-router-dom'; import { MenuIcon } from 'shared/view/elements'; import { ClickAwayListener } from 'shared/view/components'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import './LayoutHeaderMenu.scss'; @@ -13,15 +14,17 @@ interface IMenuItem { title: string; } -interface IState { - isMenuOpen: boolean; +interface IOwnProps { + menuItems: IMenuItem[]; } -interface IProps { - menuItems: IMenuItem[]; +interface IState { + isMenuOpen: boolean; } +type IProps = WithTranslation & IOwnProps; const b = block('layout-header-menu'); +const { header } = tKeys.shared; class LayoutHeaderMenu extends React.PureComponent { public state: IState = { @@ -29,8 +32,8 @@ class LayoutHeaderMenu extends React.PureComponent { }; public render() { + const { menuItems, t } = this.props; const { isMenuOpen } = this.state; - const { menuItems } = this.props; return (
{ >
- Search for: + {t(header.searchFor.getKey())} { } export { IMenuItem as IHeaderMenuItem }; -export default LayoutHeaderMenu; +export default withTranslation()(LayoutHeaderMenu); diff --git a/src/services/i18n/index.ts b/src/services/i18n/index.ts index 3f2a3ead..c89413f9 100644 --- a/src/services/i18n/index.ts +++ b/src/services/i18n/index.ts @@ -1,5 +1,9 @@ +import i18next from 'i18next'; import { withTranslation, WithTranslation, useTranslation } from 'react-i18next'; import { tKeys } from './constants'; import { default as LanguageSelector } from './view/LanguageSelector/LanguageSelector'; -export { tKeys, withTranslation, WithTranslation, useTranslation, LanguageSelector }; +type TranslateFunction = i18next.TFunction; +export { + tKeys, withTranslation, WithTranslation, useTranslation, LanguageSelector, TranslateFunction, +}; diff --git a/src/services/i18n/locales/en.ts b/src/services/i18n/locales/en.ts index 09a24ede..cbdade66 100644 --- a/src/services/i18n/locales/en.ts +++ b/src/services/i18n/locales/en.ts @@ -1,15 +1,58 @@ // tslint:disable:max-line-length export default { - shared: {}, - features: {}, + shared: { + ok: 'Ok', + save: 'Save', + search: 'Search', + settings: 'Settings', + searchSettings: 'Search settings', + header: { + searchFor: 'Search for:', + users: 'Users', + repositories: 'Repositories', + }, + footer: { + fsd: 'Fullstack Development', + }, + notifications: { + saved: 'User data was saved.', + }, + }, + features: { + profile: { + name: 'Name', + nickname: 'Nickname', + age: 'Age', + bio: 'Bio', + editProfile: 'Edit profile', + yearsOld: 'y.o.', + edit: 'Edit', + }, + repositoriesSearch: { + minStars: 'Min stars', + minForks: 'Min forks', + repositoriesLanguage: 'Repositories language', + owner: 'Owner', + }, + userSearch: { + usersSearch: 'GitHub users search', + repositoriesSearch: 'GitHub repositories search', + user: 'User', + organizations: 'Organizations', + both: 'Both', + followers: 'Followers', + following: 'Following', + repositories: 'Repositories', + userDetails: 'User details', + min: 'min', + max: 'max', + searchBy: 'Search by', + searchType: 'Search type', + repositoriesLanguage: 'Repositories language', + resultsPerPage: 'Results per page', + repositoriesNumber: 'Repositories number', + }, + }, documents: {}, modules: {}, - demo: { - selectedLang: 'Selected language is {{language, uppercase}}', - selectorLabel: 'Language selector:', - somethingText: 'Something text', - pluralLabel: 'Pluralize demonstration:', - pluralTest: '{{count}} object', - pluralTest_plural: '{{count}} objects', - }, }; diff --git a/src/services/i18n/locales/ru.ts b/src/services/i18n/locales/ru.ts index fe2c8e8d..496dba8d 100644 --- a/src/services/i18n/locales/ru.ts +++ b/src/services/i18n/locales/ru.ts @@ -1,17 +1,60 @@ // tslint:disable:max-line-length export default { - shared: {}, - features: {}, + shared: { + ok: 'Ok', + save: 'Сохранить', + search: 'Поиск', + settings: 'Настройки', + searchSettings: 'Настройки поиска', + header: { + searchFor: 'Поиск', + users: 'Пользователи', + repositories: 'Репозитории', + }, + footer: { + fsd: 'Fullstack Development', + }, + notifications: { + saved: 'Данные пользователя сохранены.', + }, + }, + features: { + profile: { + name: 'Имя', + nickname: 'Псевдоним', + age: 'Возраст', + bio: 'Биография', + editProfile: 'Редактировать профиль', + yearsOld: 'лет', + yearsOld_1: 'года', + yearsOld_2: 'год', + edit: 'Редактировать', + }, + repositoriesSearch: { + minStars: 'Минимальное кол-во звезд', + minForks: 'Минимальное кол-во форков', + repositoriesLanguage: 'Язык репозиториев', + owner: 'Разработчик', + }, + userSearch: { + usersSearch: 'Поиск пользователя GitHub', + repositoriesSearch: 'Поиск репозитория GitHub', + user: 'Пользователь', + organizations: 'Организация', + both: 'Оба', + followers: 'Подписчики', + following: 'Подписки', + repositories: 'Репозитории', + userDetails: 'Данные пользователя', + min: 'минимум', + max: 'максимум', + searchBy: 'Поиск по', + searchType: 'Тип поиска', + repositoriesLanguage: 'Язык репозитория', + resultsPerPage: 'Количество результатов на странице', + repositoriesNumber: 'Количество репозиториев', + }, + }, documents: {}, modules: {}, - modules1: {}, - demo: { - selectedLang: 'Выбран язык {{language, uppercase}}', - selectorLabel: 'Селектор языка:', - somethingText: 'Какой-то текст', - pluralLabel: 'Демонстрация множественных переводов:', - pluralTest: '{{count}} объект', - pluralTest_1: '{{count}} объекта', - pluralTest_2: '{{count}} объектов', - }, }; diff --git a/src/shared/view/components/SearchForm/SearchForm.tsx b/src/shared/view/components/SearchForm/SearchForm.tsx index 7d531495..0e289353 100644 --- a/src/shared/view/components/SearchForm/SearchForm.tsx +++ b/src/shared/view/components/SearchForm/SearchForm.tsx @@ -4,6 +4,7 @@ import block from 'bem-cn'; import { bind } from 'decko'; import { isRequired } from 'shared/validators'; +import { TranslateFunction, tKeys } from 'services/i18n'; import { TextInputField } from 'shared/view/form'; import { Button } from 'shared/view/elements'; @@ -15,7 +16,8 @@ interface IState { isSettingsDialogOpen: boolean; } -interface IProps { +interface IOwnProps { + t: TranslateFunction; isSearchRequesting: boolean; searchInputName: string; initialValues?: Partial; @@ -24,7 +26,10 @@ interface IProps { renderSettings?(): React.ReactChild; } +type IProps = IOwnProps; + const b = block('search-form'); +const { search, settings } = tKeys.shared; class SearchForm extends React.PureComponent, IState> { public state: IState = { @@ -49,7 +54,7 @@ class SearchForm extends React.PureComponent, IState @bind private renderForm({ handleSubmit }: FormRenderProps) { - const { isSearchRequesting, renderSettings, searchInputName } = this.props; + const { isSearchRequesting, renderSettings, searchInputName, t } = this.props; const { isSettingsDialogOpen } = this.state; return (
@@ -60,7 +65,7 @@ class SearchForm extends React.PureComponent, IState variant="outlined" disabled={isSearchRequesting} > - Search + {t(search.getKey())} {renderSettings !== void 0 &&
@@ -69,7 +74,7 @@ class SearchForm extends React.PureComponent, IState onClick={this.handleSettingsButtonClick} disabled={isSearchRequesting} > - Settings + {t(settings.getKey())} @@ -20,7 +25,9 @@ function SearchSettingsDialog(props: IProps) { {renderContent()} - +
); From 4dd615dd463928976426e32c0dad9acf506e2fe3 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sun, 31 Mar 2019 23:23:25 +0300 Subject: [PATCH 08/33] Added styles for selector, added plural translates --- .../ProfilePreview/ProfilePreview.tsx | 2 +- src/modules/shared/Layout/Layout.scss | 21 ++++++++++++++++++- src/modules/shared/Layout/Layout.tsx | 6 +++--- src/services/i18n/locales/en.ts | 2 +- src/services/i18n/locales/ru.ts | 6 +++--- .../LanguageSelector/LanguageSelector.tsx | 4 ++-- 6 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/features/profile/view/containers/ProfilePreview/ProfilePreview.tsx b/src/features/profile/view/containers/ProfilePreview/ProfilePreview.tsx index 38a3824e..7a54f313 100644 --- a/src/features/profile/view/containers/ProfilePreview/ProfilePreview.tsx +++ b/src/features/profile/view/containers/ProfilePreview/ProfilePreview.tsx @@ -66,7 +66,7 @@ class ProfilePreview extends React.PureComponent { {nickname}
- {age + ' ' + t(profile.yearsOld.getKey())} + {t(profile.yearsOld.getKey(), { count: age })}
diff --git a/src/modules/shared/Layout/Layout.scss b/src/modules/shared/Layout/Layout.scss index 44403ac6..c3793175 100644 --- a/src/modules/shared/Layout/Layout.scss +++ b/src/modules/shared/Layout/Layout.scss @@ -36,10 +36,15 @@ } } - &__menu { + &__left-menu { line-height: $header-footer-height; } + &__right-menu { + display: flex; + align-items: center; + } + &__content { display: flex; flex-direction: column; @@ -72,4 +77,18 @@ &__company-link { color: #eaeaea; } + + &__language-selector { + margin: 0 1rem; + + & select { + border: none; + background: none; + color: white; + font-weight: 400; + font-size: 0.9rem; + font-family: inherit; + cursor: pointer; + } + } } diff --git a/src/modules/shared/Layout/Layout.tsx b/src/modules/shared/Layout/Layout.tsx index 94cd9130..410670b4 100644 --- a/src/modules/shared/Layout/Layout.tsx +++ b/src/modules/shared/Layout/Layout.tsx @@ -42,12 +42,12 @@ class Layout extends React.Component {
-
+
-
+
- +
diff --git a/src/services/i18n/locales/en.ts b/src/services/i18n/locales/en.ts index cbdade66..b1c3be64 100644 --- a/src/services/i18n/locales/en.ts +++ b/src/services/i18n/locales/en.ts @@ -25,7 +25,7 @@ export default { age: 'Age', bio: 'Bio', editProfile: 'Edit profile', - yearsOld: 'y.o.', + yearsOld: '{{count}} y.o.', edit: 'Edit', }, repositoriesSearch: { diff --git a/src/services/i18n/locales/ru.ts b/src/services/i18n/locales/ru.ts index 496dba8d..46c13ff9 100644 --- a/src/services/i18n/locales/ru.ts +++ b/src/services/i18n/locales/ru.ts @@ -25,9 +25,9 @@ export default { age: 'Возраст', bio: 'Биография', editProfile: 'Редактировать профиль', - yearsOld: 'лет', - yearsOld_1: 'года', - yearsOld_2: 'год', + yearsOld: '{{count}} лет', + yearsOld_1: '{{count}} года', + yearsOld_2: '{{count}} год', edit: 'Редактировать', }, repositoriesSearch: { diff --git a/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx b/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx index 21bed807..1808c628 100644 --- a/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx +++ b/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx @@ -11,8 +11,8 @@ interface IOption { class LanguageSelector extends React.PureComponent { public static options: IOption[] = [ - { value: 'en', label: 'en' }, - { value: 'ru', label: 'ru' }, + { value: 'en', label: 'English' }, + { value: 'ru', label: 'Русский' }, ]; public render() { From 8298d8e25641112cba641cce6eddd71c79151270 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sun, 31 Mar 2019 23:33:06 +0300 Subject: [PATCH 09/33] Translates added --- .../view/components/UsersSearchLayout/UsersSearchLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/Search/view/components/UsersSearchLayout/UsersSearchLayout.tsx b/src/modules/Search/view/components/UsersSearchLayout/UsersSearchLayout.tsx index c93c41b0..e5723ac4 100644 --- a/src/modules/Search/view/components/UsersSearchLayout/UsersSearchLayout.tsx +++ b/src/modules/Search/view/components/UsersSearchLayout/UsersSearchLayout.tsx @@ -27,7 +27,7 @@ class UsersSearchLayout extends React.PureComponent { }; public render() { - const { usersSearchFeatureEntry: { containers } } = this.props; + const { usersSearchFeatureEntry: { containers }, t } = this.props; const { UsersSearchForm, UsersSearchResults } = containers; const { lastSubmittedFormState } = this.state; From d0395a9b23a4d0b56c9ad2f4820028340ab43735 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Mon, 1 Apr 2019 14:27:02 +0300 Subject: [PATCH 10/33] Imports changed at client --- src/client.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client.tsx b/src/client.tsx index 9b413325..07528ca0 100644 --- a/src/client.tsx +++ b/src/client.tsx @@ -1,8 +1,8 @@ import 'reflect-metadata'; import 'babel-polyfill'; -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; -import * as bootstrapper from 'react-async-bootstrapper'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import bootstrapper from 'react-async-bootstrapper'; import configureApp from 'core/configureApp'; import { App } from 'core/App'; From b152c95f6f53a674aa45e1c346505e861da944cd Mon Sep 17 00:00:00 2001 From: clicktronix Date: Mon, 1 Apr 2019 20:39:22 +0300 Subject: [PATCH 11/33] Tests fixed for new localization --- .../ProfileEdit/__tests__/index.test.ts | 3 +- .../ProfilePreview/__tests__/index.test.ts | 3 +- .../__tests__/index.test.ts | 3 +- .../UserDetails/__tests__/index.test.ts | 3 +- .../UsersSearchForm/__tests__/index.test.ts | 3 +- .../__tests__/index.test.ts | 3 +- .../UsersSearchLayout/__tests__/index.test.ts | 3 +- .../LayoutHeaderMenu/LayoutHeaderMenu.tsx | 2 +- .../LayoutHeaderMenu/__tests__/index.test.ts | 5 +- .../shared/Layout/__tests__/index.test.ts | 3 +- src/shared/helpers/tests/index.ts | 2 + .../{tests.tsx => tests/makeRenderers.tsx} | 6 +-- src/shared/helpers/tests/mockLocaleProps.ts | 54 +++++++++++++++++++ .../SearchForm/__tests__/index.test.ts | 4 +- 14 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 src/shared/helpers/tests/index.ts rename src/shared/helpers/{tests.tsx => tests/makeRenderers.tsx} (80%) create mode 100644 src/shared/helpers/tests/mockLocaleProps.ts diff --git a/src/features/profile/view/containers/ProfileEdit/__tests__/index.test.ts b/src/features/profile/view/containers/ProfileEdit/__tests__/index.test.ts index 193939f2..d767b907 100644 --- a/src/features/profile/view/containers/ProfileEdit/__tests__/index.test.ts +++ b/src/features/profile/view/containers/ProfileEdit/__tests__/index.test.ts @@ -1,6 +1,6 @@ import { Form } from 'react-final-form'; -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { profile } from 'shared/mocks'; import { ProfileEdit, IProfileEditProps } from '../ProfileEdit'; @@ -9,6 +9,7 @@ const props: IProfileEditProps = { profile, setNotification: jest.fn(), saveProfile: jest.fn(), + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(ProfileEdit, props); diff --git a/src/features/profile/view/containers/ProfilePreview/__tests__/index.test.ts b/src/features/profile/view/containers/ProfilePreview/__tests__/index.test.ts index a6985516..63bf2648 100644 --- a/src/features/profile/view/containers/ProfilePreview/__tests__/index.test.ts +++ b/src/features/profile/view/containers/ProfilePreview/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { Popover } from 'shared/view/components'; import { profile } from 'shared/mocks'; @@ -7,6 +7,7 @@ import { ProfilePreview, IProfilePreviewProps } from '../ProfilePreview'; const props: IProfilePreviewProps = { onEditClick: jest.fn(), profile, + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(ProfilePreview, props); diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/__tests__/index.test.ts b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/__tests__/index.test.ts index d2dab9ef..22a33b0f 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/__tests__/index.test.ts +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { SearchForm } from 'shared/view/components'; import { RepositoriesSearchForm, IRepositoriesSearchFormProps } from '../RepositoriesSearchForm'; @@ -8,6 +8,7 @@ const props: IRepositoriesSearchFormProps = { searchRepositories: jest.fn(), resetSearchResults: jest.fn(), isRepositoriesSearchRequesting: false, + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(RepositoriesSearchForm, props); diff --git a/src/features/usersSearch/view/containers/UserDetails/__tests__/index.test.ts b/src/features/usersSearch/view/containers/UserDetails/__tests__/index.test.ts index 9c7ba1d2..18657014 100644 --- a/src/features/usersSearch/view/containers/UserDetails/__tests__/index.test.ts +++ b/src/features/usersSearch/view/containers/UserDetails/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { detailedGithubUser } from 'shared/mocks'; import { Preloader } from 'shared/view/elements'; import { Dialog } from 'shared/view/components'; @@ -11,6 +11,7 @@ const props: IUserDetailsProps = { loadUserDetails: jest.fn(), onClose: jest.fn(), username: 'the user', + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(UserDetails, props); diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/__tests__/index.test.ts b/src/features/usersSearch/view/containers/UsersSearchForm/__tests__/index.test.ts index 44489cbf..18e45959 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/__tests__/index.test.ts +++ b/src/features/usersSearch/view/containers/UsersSearchForm/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { SearchForm } from 'shared/view/components'; import { UsersSearchForm, IUsersSearchFormProps } from '../UsersSearchForm'; @@ -8,6 +8,7 @@ const props: IUsersSearchFormProps = { searchUsers: jest.fn(), resetSearchResults: jest.fn(), isUsersSearchRequesting: false, + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(UsersSearchForm, props); diff --git a/src/modules/Search/view/components/RepositoriesSearchLayout/__tests__/index.test.ts b/src/modules/Search/view/components/RepositoriesSearchLayout/__tests__/index.test.ts index b496e727..0f1d85b5 100644 --- a/src/modules/Search/view/components/RepositoriesSearchLayout/__tests__/index.test.ts +++ b/src/modules/Search/view/components/RepositoriesSearchLayout/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { makeMockEntry, makeMockComponent } from 'shared/mocks'; import { RepositoriesSearchLayout, IRepositoriesSearchLayoutProps } from '../RepositoriesSearchLayout'; @@ -8,6 +8,7 @@ const props: IRepositoriesSearchLayoutProps = { RepositoriesSearchForm: makeMockComponent('RepositoriesSearchForm'), RepositoriesSearchResults: makeMockComponent('RepositoriesSearchResults'), }), + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(RepositoriesSearchLayout, props); diff --git a/src/modules/Search/view/components/UsersSearchLayout/__tests__/index.test.ts b/src/modules/Search/view/components/UsersSearchLayout/__tests__/index.test.ts index f3276410..d077a894 100644 --- a/src/modules/Search/view/components/UsersSearchLayout/__tests__/index.test.ts +++ b/src/modules/Search/view/components/UsersSearchLayout/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { makeMockEntry, makeMockComponent } from 'shared/mocks'; import { UsersSearchLayout, IUsersSearchLayoutProps } from '../UsersSearchLayout'; @@ -8,6 +8,7 @@ const props: IUsersSearchLayoutProps = { UsersSearchForm: makeMockComponent('UsersSearchForm'), UsersSearchResults: makeMockComponent('UsersSearchResults'), }), + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(UsersSearchLayout, props); diff --git a/src/modules/shared/Layout/LayoutHeaderMenu/LayoutHeaderMenu.tsx b/src/modules/shared/Layout/LayoutHeaderMenu/LayoutHeaderMenu.tsx index 8931b215..6ad2d8dc 100644 --- a/src/modules/shared/Layout/LayoutHeaderMenu/LayoutHeaderMenu.tsx +++ b/src/modules/shared/Layout/LayoutHeaderMenu/LayoutHeaderMenu.tsx @@ -86,5 +86,5 @@ class LayoutHeaderMenu extends React.PureComponent { } } -export { IMenuItem as IHeaderMenuItem, IProps as IHeaderMenuProps, IState as IHeaderMenuState }; +export { LayoutHeaderMenu, IMenuItem as IHeaderMenuItem, IProps as IHeaderMenuProps, IState as IHeaderMenuState }; export default withTranslation()(LayoutHeaderMenu); diff --git a/src/modules/shared/Layout/LayoutHeaderMenu/__tests__/index.test.ts b/src/modules/shared/Layout/LayoutHeaderMenu/__tests__/index.test.ts index c25d1a19..3bc233cb 100644 --- a/src/modules/shared/Layout/LayoutHeaderMenu/__tests__/index.test.ts +++ b/src/modules/shared/Layout/LayoutHeaderMenu/__tests__/index.test.ts @@ -1,8 +1,8 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { makeMockEvent } from 'shared/mocks'; import { ClickAwayListener } from 'shared/view/components'; -import LayoutHeaderMenu, { IHeaderMenuProps } from '../LayoutHeaderMenu'; +import { LayoutHeaderMenu, IHeaderMenuProps } from '../LayoutHeaderMenu'; const props: IHeaderMenuProps = { menuItems: [ @@ -15,6 +15,7 @@ const props: IHeaderMenuProps = { title: 'Title2', }, ], + ...getMockedLocaleProps(), }; const clickEvent = makeMockEvent('click'); diff --git a/src/modules/shared/Layout/__tests__/index.test.ts b/src/modules/shared/Layout/__tests__/index.test.ts index aec70835..6e8f7266 100644 --- a/src/modules/shared/Layout/__tests__/index.test.ts +++ b/src/modules/shared/Layout/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { makeMockEntry, makeMockComponent, withRouterProps } from 'shared/mocks'; import { Layout, ILayoutProps } from '../Layout'; @@ -10,6 +10,7 @@ const props: ILayoutProps = { ProfilePreview: makeMockComponent('ProfilePreview'), }), ...withRouterProps, + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(Layout, props); diff --git a/src/shared/helpers/tests/index.ts b/src/shared/helpers/tests/index.ts new file mode 100644 index 00000000..d790a221 --- /dev/null +++ b/src/shared/helpers/tests/index.ts @@ -0,0 +1,2 @@ +export * from './mockLocaleProps'; +export * from './makeRenderers'; diff --git a/src/shared/helpers/tests.tsx b/src/shared/helpers/tests/makeRenderers.tsx similarity index 80% rename from src/shared/helpers/tests.tsx rename to src/shared/helpers/tests/makeRenderers.tsx index 40ed68bd..eddf0498 100644 --- a/src/shared/helpers/tests.tsx +++ b/src/shared/helpers/tests/makeRenderers.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { shallow, mount, ShallowWrapper, ReactWrapper } from 'enzyme'; -function makeShallowRenderer( +export function makeShallowRenderer( Component: React.ComponentClass | React.FunctionComponent, defaultProps: Props, ) { return (props: Partial = {}): ShallowWrapper => ( @@ -9,12 +9,10 @@ function makeShallowRenderer( ); } -function makeMountRenderer( +export function makeMountRenderer( Component: React.ComponentClass | React.FunctionComponent, defaultProps: Props, ) { return (props: Partial = {}): ReactWrapper => ( mount() ); } - -export { makeShallowRenderer, makeMountRenderer }; diff --git a/src/shared/helpers/tests/mockLocaleProps.ts b/src/shared/helpers/tests/mockLocaleProps.ts new file mode 100644 index 00000000..e252332b --- /dev/null +++ b/src/shared/helpers/tests/mockLocaleProps.ts @@ -0,0 +1,54 @@ +import { WithTranslation } from 'services/i18n'; + +export const getMockedLocaleProps: () => WithTranslation = () => ({ + t: jest.fn(), + i18n: { + isInitialized: true, + language: 'en', + languages: ['en', 'ru'], + options: {}, + services: { + backendConnector: {}, + i18nFormat: {}, + interpolator: {}, + languageDetector: {}, + languageUtils: {}, + logger: {}, + pluralResolver: {}, + resourceStore: { + en: { + translationNamespace: { + translateMock: 'translateMock', + }, + }, + }, + }, + modules: { + external: [], + }, + use: jest.fn(), + format: jest.fn(), + exists: jest.fn(), + addResource: jest.fn(), + addResourceBundle: jest.fn(), + addResources: jest.fn(), + changeLanguage: jest.fn(), + cloneInstance: jest.fn(), + createInstance: jest.fn(), + getFixedT: jest.fn(), + dir: jest.fn(), + getResource: jest.fn(), + getResourceBundle: jest.fn(), + hasResourceBundle: jest.fn(), + init: jest.fn(), + loadLanguages: jest.fn(), + loadResources: jest.fn(), + loadNamespaces: jest.fn(), + off: jest.fn(), + on: jest.fn(), + reloadResources: jest.fn(), + removeResourceBundle: jest.fn(), + setDefaultNamespace: jest.fn(), + t: jest.fn(), + }, +}); diff --git a/src/shared/view/components/SearchForm/__tests__/index.test.ts b/src/shared/view/components/SearchForm/__tests__/index.test.ts index 89449940..f769cfa5 100644 --- a/src/shared/view/components/SearchForm/__tests__/index.test.ts +++ b/src/shared/view/components/SearchForm/__tests__/index.test.ts @@ -1,5 +1,6 @@ -import { makeMountRenderer } from 'shared/helpers'; +import { makeMountRenderer, getMockedLocaleProps } from 'shared/helpers'; import { Button } from 'shared/view/elements'; + import SearchSettingsDialog from '../SearchSettingsDialog/SearchSettingsDialog'; import SearchForm, { ISearchFormProps } from '../SearchForm'; @@ -15,6 +16,7 @@ const props: ISearchFormProps = { initialValues: { search: 'abc', }, + ...getMockedLocaleProps(), }; const getComponent = makeMountRenderer(SearchForm, props); From 410b2fd4e0046dd39cad7e574a986a58bbb1d777 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Fri, 5 Apr 2019 21:52:51 +0300 Subject: [PATCH 12/33] Changed SearchForm props for localization --- .../RepositoriesSearchForm/RepositoriesSearchForm.tsx | 5 +++-- .../containers/UsersSearchForm/UsersSearchForm.tsx | 5 +++-- src/shared/view/components/SearchForm/SearchForm.tsx | 11 +++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx index 3d4cba6a..7f103f0b 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { bind } from 'decko'; -import { withTranslation, WithTranslation } from 'services/i18n'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import { IAppReduxState } from 'shared/types/app'; import { SearchForm } from 'shared/view/components'; @@ -39,9 +39,10 @@ class RepositoriesSearchForm extends React.PureComponent { const { isRepositoriesSearchRequesting, resetSearchResults, t } = this.props; return ( - t={t} searchInputName={fieldNames.searchString} isSearchRequesting={isRepositoriesSearchRequesting} + submitButtonText={t(tKeys.shared.search.getKey())} + settingsButtonText={t(tKeys.shared.settings.getKey())} onSubmit={this.handleFormSubmit} resetSearchResults={resetSearchResults} renderSettings={RepositoriesSearchSettings} diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx index 693d2fcd..8111a943 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { bind } from 'decko'; -import { withTranslation, WithTranslation } from 'services/i18n'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import { IAppReduxState } from 'shared/types/app'; import { SearchForm } from 'shared/view/components'; @@ -39,10 +39,11 @@ class UsersSearchForm extends React.PureComponent { const { isUsersSearchRequesting, resetSearchResults, t } = this.props; return ( - t={t} isSearchRequesting={isUsersSearchRequesting} searchInputName={fieldNames.searchString} onSubmit={this.handleFormSubmit} + submitButtonText={t(tKeys.shared.search.getKey())} + settingsButtonText={t(tKeys.shared.settings.getKey())} initialValues={formInitialValues} renderSettings={UsersSearchSettings} resetSearchResults={resetSearchResults} diff --git a/src/shared/view/components/SearchForm/SearchForm.tsx b/src/shared/view/components/SearchForm/SearchForm.tsx index c3e1d96a..99c61ef2 100644 --- a/src/shared/view/components/SearchForm/SearchForm.tsx +++ b/src/shared/view/components/SearchForm/SearchForm.tsx @@ -4,7 +4,6 @@ import block from 'bem-cn'; import { bind } from 'decko'; import { isRequired } from 'shared/validators'; -import { TranslateFunction, tKeys } from 'services/i18n'; import { TextInputField } from 'shared/view/form'; import { Button } from 'shared/view/elements'; @@ -17,10 +16,11 @@ interface IState { } interface IOwnProps { - t: TranslateFunction; isSearchRequesting: boolean; searchInputName: string; initialValues?: Partial; + submitButtonText: string; + settingsButtonText: string; onSubmit(values: FormFields): void; resetSearchResults(): void; renderSettings?(): React.ReactChild; @@ -29,7 +29,6 @@ interface IOwnProps { type IProps = IOwnProps; const b = block('search-form'); -const { search, settings } = tKeys.shared; class SearchForm extends React.PureComponent, IState> { public state: IState = { @@ -54,7 +53,7 @@ class SearchForm extends React.PureComponent, IState @bind private renderForm({ handleSubmit }: FormRenderProps) { - const { isSearchRequesting, renderSettings, searchInputName, t } = this.props; + const { isSearchRequesting, renderSettings, searchInputName, submitButtonText, settingsButtonText } = this.props; const { isSettingsDialogOpen } = this.state; return ( @@ -65,7 +64,7 @@ class SearchForm extends React.PureComponent, IState variant="outlined" disabled={isSearchRequesting} > - {t(search.getKey())} + {submitButtonText} {renderSettings !== void 0 &&
@@ -74,7 +73,7 @@ class SearchForm extends React.PureComponent, IState onClick={this.handleSettingsButtonClick} disabled={isSearchRequesting} > - {t(settings.getKey())} + {settingsButtonText} Date: Fri, 5 Apr 2019 21:56:02 +0300 Subject: [PATCH 13/33] Tests fixed --- .../view/components/SearchForm/__tests__/index.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shared/view/components/SearchForm/__tests__/index.test.ts b/src/shared/view/components/SearchForm/__tests__/index.test.ts index f769cfa5..faf35e39 100644 --- a/src/shared/view/components/SearchForm/__tests__/index.test.ts +++ b/src/shared/view/components/SearchForm/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeMountRenderer, getMockedLocaleProps } from 'shared/helpers'; +import { makeMountRenderer } from 'shared/helpers'; import { Button } from 'shared/view/elements'; import SearchSettingsDialog from '../SearchSettingsDialog/SearchSettingsDialog'; @@ -9,6 +9,8 @@ interface IFormFields { } const props: ISearchFormProps = { + settingsButtonText: 'settings', + submitButtonText: 'submit', isSearchRequesting: false, searchInputName: 'search', onSubmit: jest.fn(), @@ -16,7 +18,6 @@ const props: ISearchFormProps = { initialValues: { search: 'abc', }, - ...getMockedLocaleProps(), }; const getComponent = makeMountRenderer(SearchForm, props); From a16adcee735f54b19b4c94b6058027091eeb0c31 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Fri, 5 Apr 2019 22:12:32 +0300 Subject: [PATCH 14/33] Added memo menu items --- src/modules/shared/Layout/Layout.tsx | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/modules/shared/Layout/Layout.tsx b/src/modules/shared/Layout/Layout.tsx index a0488963..04cf61ab 100644 --- a/src/modules/shared/Layout/Layout.tsx +++ b/src/modules/shared/Layout/Layout.tsx @@ -1,5 +1,6 @@ import React from 'react'; import block from 'bem-cn'; +import * as R from 'ramda'; import { withRouter, RouteComponentProps } from 'react-router-dom'; import { bind } from 'decko'; @@ -28,22 +29,25 @@ class Layout extends React.Component { public render() { const { children, title, profileFeatureEntry: { containers }, t } = this.props; const { ProfilePreview } = containers; - const menuItems: IHeaderMenuItem[] = [ - { - path: routes.search.users.getRoutePath(), - title: this.props.t(header.users.getKey()), - }, - { - path: routes.search.repositories.getRoutePath(), - title: this.props.t(header.repositories.getKey()), - }, - ]; + const getMemoMenuItems = R.memoizeWith(R.identity, (): IHeaderMenuItem[] => ( + [ + { + path: routes.search.users.getRoutePath(), + title: this.props.t(header.users.getKey()), + }, + { + path: routes.search.repositories.getRoutePath(), + title: this.props.t(header.repositories.getKey()), + }, + ] + )); + return (
- +
From b91a7d3a5a47ea16e24b7edb3412f1d25f0d9f7e Mon Sep 17 00:00:00 2001 From: clicktronix Date: Fri, 5 Apr 2019 23:05:27 +0300 Subject: [PATCH 15/33] Changed Lang type value --- src/services/i18n/constants.ts | 2 +- .../i18n/view/LanguageSelector/LanguageSelector.tsx | 9 +++++++-- src/shared/types/app.ts | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/services/i18n/constants.ts b/src/services/i18n/constants.ts index 0739f26d..f3c44fd4 100644 --- a/src/services/i18n/constants.ts +++ b/src/services/i18n/constants.ts @@ -2,5 +2,5 @@ import { Lang } from 'shared/types/app'; import buildTranslationKeys from './helpers/buildTranslationKeys'; import { en } from './locales'; -export const FALLBACK_LANGUAGE: Lang = 'en'; +export const FALLBACK_LANGUAGE: Lang = 'en-US'; export const tKeys = buildTranslationKeys(en); diff --git a/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx b/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx index 1808c628..fb909967 100644 --- a/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx +++ b/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx @@ -11,8 +11,8 @@ interface IOption { class LanguageSelector extends React.PureComponent { public static options: IOption[] = [ - { value: 'en', label: 'English' }, - { value: 'ru', label: 'Русский' }, + { value: 'en-US', label: 'English' }, + { value: 'ru-RU', label: 'Русский' }, ]; public render() { @@ -34,6 +34,11 @@ class LanguageSelector extends React.PureComponent { const { i18n } = this.props; i18n.changeLanguage(value); } + + // private parseToShortLang(value: string) { + // return value.slice(0, value.indexOf('-')); + // } } +export { LanguageSelector }; export default withTranslation()(LanguageSelector); diff --git a/src/shared/types/app.ts b/src/shared/types/app.ts index d6fea4a4..3988ab25 100644 --- a/src/shared/types/app.ts +++ b/src/shared/types/app.ts @@ -54,7 +54,7 @@ export interface IAppReduxState { export type RootSaga = (deps: IDependencies) => () => SagaIterator; -export type Lang = 'en' | 'ru'; +export type Lang = 'en-US' | 'ru-RU'; export type Uid = number; From e828e62728235fd027aeb313c9922673ef0a5e7e Mon Sep 17 00:00:00 2001 From: clicktronix Date: Fri, 5 Apr 2019 23:28:44 +0300 Subject: [PATCH 16/33] Translates updated --- .../RepositoriesSearchSettings.tsx | 2 +- src/services/i18n/locales/ru.ts | 22 ++++++------ .../LanguageSelector/LanguageSelector.tsx | 4 --- .../LanguageSelector/__tests__/index.test.ts | 34 +++++++++++++++++++ 4 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 src/services/i18n/view/LanguageSelector/__tests__/index.test.ts diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchSettings/RepositoriesSearchSettings.tsx b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchSettings/RepositoriesSearchSettings.tsx index a867418a..978dead3 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchSettings/RepositoriesSearchSettings.tsx +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchSettings/RepositoriesSearchSettings.tsx @@ -30,7 +30,7 @@ function RepositoriesSearchSettings() {
- +
{ const { i18n } = this.props; i18n.changeLanguage(value); } - - // private parseToShortLang(value: string) { - // return value.slice(0, value.indexOf('-')); - // } } export { LanguageSelector }; diff --git a/src/services/i18n/view/LanguageSelector/__tests__/index.test.ts b/src/services/i18n/view/LanguageSelector/__tests__/index.test.ts new file mode 100644 index 00000000..3a0bc432 --- /dev/null +++ b/src/services/i18n/view/LanguageSelector/__tests__/index.test.ts @@ -0,0 +1,34 @@ +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; +import { WithTranslation } from 'services/i18n'; + +import { LanguageSelector } from '../LanguageSelector'; + +const props: WithTranslation = { + ...getMockedLocaleProps(), +}; + +const getComponent = makeShallowRenderer(LanguageSelector, props); + +describe('(services/i18n) LanguageSelector component', () => { + it('should render select', () => { + const component = getComponent(); + expect(component.find('select').length).toEqual(1); + }); + + it('should call changeLanguage', () => { + const changeLanguage = jest.fn(); + const newProps = { + ...props, + i18n: { + ...props.i18n, + changeLanguage, + }, + }; + const component = getComponent(newProps); + + component.find('select').simulate('change', { target: { value: 'ru' } }); + + expect(changeLanguage).toBeCalledTimes(1); + expect(changeLanguage).toBeCalledWith('ru'); + }); +}); From 5ae5065c994f6d43fce8a78b2ca6bd4657e48c19 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sat, 6 Apr 2019 00:09:20 +0300 Subject: [PATCH 17/33] Updated translations --- .../RepositoryPreview/RepositoryPreview.tsx | 17 +++++++++++------ .../RepositoryPreview/__tests__/index.test.ts | 3 ++- .../UsersSearchSettings/UsersSearchSettings.tsx | 12 ++++++++++-- .../containers/UsersSearchForm/constants.ts | 9 +-------- src/services/i18n/locales/en.ts | 7 +++++++ src/services/i18n/locales/ru.ts | 7 +++++++ src/shared/view/elements/Select/Select.tsx | 2 +- 7 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/features/repositoriesSearch/view/components/RepositoryPreview/RepositoryPreview.tsx b/src/features/repositoriesSearch/view/components/RepositoryPreview/RepositoryPreview.tsx index e931d9bb..3ffa2bb3 100644 --- a/src/features/repositoriesSearch/view/components/RepositoryPreview/RepositoryPreview.tsx +++ b/src/features/repositoriesSearch/view/components/RepositoryPreview/RepositoryPreview.tsx @@ -4,20 +4,25 @@ import { bind } from 'decko'; import { IRepository } from 'shared/types/models'; import { StarIcon, Card, Link } from 'shared/view/elements'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import RepositoryAttribute from '../RepositoryAttribute/RepositoryAttribute'; import './RepositoryPreview.scss'; -interface IProps { +interface IOwnProps { repository: IRepository; onOwnerClick(username: string): void; } +type IProps = IOwnProps & WithTranslation; + const b = block('repository-preview'); +const { repositoriesSearch } = tKeys.features; class RepositoryPreview extends React.PureComponent { public render() { const { + t, repository: { name, starsNumber, htmlURL, description, updatedAt, owner, forksNumber, openIssuesNumber, language, @@ -47,21 +52,21 @@ class RepositoryPreview extends React.PureComponent {
{ } export { IProps as IRepositoryPreviewProps, RepositoryPreview }; -export default RepositoryPreview; +export default withTranslation()(RepositoryPreview); diff --git a/src/features/repositoriesSearch/view/components/RepositoryPreview/__tests__/index.test.ts b/src/features/repositoriesSearch/view/components/RepositoryPreview/__tests__/index.test.ts index b589ff22..52929ad0 100644 --- a/src/features/repositoriesSearch/view/components/RepositoryPreview/__tests__/index.test.ts +++ b/src/features/repositoriesSearch/view/components/RepositoryPreview/__tests__/index.test.ts @@ -1,6 +1,6 @@ import { ShallowWrapper } from 'enzyme'; -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { repository } from 'shared/mocks'; import RepositoryAttribute, { IRepositoryAttributeProps } from '../../RepositoryAttribute/RepositoryAttribute'; @@ -9,6 +9,7 @@ import { RepositoryPreview, IRepositoryPreviewProps } from '../RepositoryPreview const props: IRepositoryPreviewProps = { repository, onOwnerClick: jest.fn(), + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(RepositoryPreview, props); diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx index 79fd5b03..f0803e41 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx @@ -1,11 +1,12 @@ import React from 'react'; import block from 'bem-cn'; -import { FormLabel } from 'shared/view/elements'; +import { FormLabel, ISelectOption } from 'shared/view/elements'; import { useTranslation, tKeys } from 'services/i18n'; import { SelectField, NumberInputField, RadioField, LanguageInputField } from 'shared/view/form'; +import { IUsersSearchFilters } from 'shared/types/githubSearch'; -import { searchByOptions, perPageOptions, fieldNames } from '../constants'; +import { perPageOptions, fieldNames } from '../constants'; import './UsersSearchSettings.scss'; const b = block('users-search-settings'); @@ -13,6 +14,13 @@ const { userSearch } = tKeys.features; function UsersSearchSettings() { const { t } = useTranslation(); + const searchByOptions: Array> = [ + { value: 'username-email', label: t(userSearch.usernameAndEmail.getKey()) || 'Username & email' }, + { value: 'login', label: t(userSearch.username.getKey()) || 'Username' }, + { value: 'email', label: t(userSearch.email.getKey()) || 'Email' }, + { value: 'fullname', label: t(userSearch.fullName.getKey()) || 'Full name' }, + ]; + return (
diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/constants.ts b/src/features/usersSearch/view/containers/UsersSearchForm/constants.ts index 527c52c0..5ae6b224 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/constants.ts +++ b/src/features/usersSearch/view/containers/UsersSearchForm/constants.ts @@ -3,13 +3,6 @@ import { IUsersSearchFilters } from 'shared/types/githubSearch'; import { FormFieldNames } from 'shared/types/form'; import { IUsersSearchFormFields } from '../../../namespace'; -export const searchByOptions: Array> = [ - { value: 'username-email', label: 'Username & email' }, - { value: 'login', label: 'Username' }, - { value: 'email', label: 'Email' }, - { value: 'fullname', label: 'Full name' }, -]; - export const perPageOptions: Array> = [ { value: 30, label: 30 }, { value: 50, label: 50 }, @@ -17,7 +10,7 @@ export const perPageOptions: Array ]; export const formInitialValues: IUsersSearchFormFields = { - searchString: '', searchBy: searchByOptions[0].value, searchType: 'both', perPage: perPageOptions[0].value, + searchString: '', searchBy: 'username-email', searchType: 'both', perPage: perPageOptions[0].value, }; export const fieldNames: FormFieldNames = { diff --git a/src/services/i18n/locales/en.ts b/src/services/i18n/locales/en.ts index b1c3be64..7523b4ef 100644 --- a/src/services/i18n/locales/en.ts +++ b/src/services/i18n/locales/en.ts @@ -33,10 +33,17 @@ export default { minForks: 'Min forks', repositoriesLanguage: 'Repositories language', owner: 'Owner', + forks: 'Forks', + openIssues: 'Open issues', + lastUpdated: 'Last updated', }, userSearch: { usersSearch: 'GitHub users search', repositoriesSearch: 'GitHub repositories search', + usernameAndEmail: 'Username & email', + username: 'Username', + email: 'Email', + fullName: 'Full name', user: 'User', organizations: 'Organizations', both: 'Both', diff --git a/src/services/i18n/locales/ru.ts b/src/services/i18n/locales/ru.ts index 76ae3ff1..e825ce8b 100644 --- a/src/services/i18n/locales/ru.ts +++ b/src/services/i18n/locales/ru.ts @@ -35,12 +35,19 @@ export default { minForks: 'мин. форков', repositoriesLanguage: 'Язык репозиториев', owner: 'Владелец', + forks: 'Форки', + openIssues: 'Открытые задачи', + lastUpdated: 'Последнее обновление', }, userSearch: { usersSearch: 'Поиск пользователя GitHub', repositoriesSearch: 'Поиск репозитория GitHub', user: 'Пользователей', organizations: 'Организации', + usernameAndEmail: 'Никнейму и почте', + username: 'Никнейму', + email: 'Почта', + fullName: 'Полное имя', both: 'Пользователей и организации', followers: 'Подписчики', following: 'Подписки', diff --git a/src/shared/view/elements/Select/Select.tsx b/src/shared/view/elements/Select/Select.tsx index 856bad9e..b510f1a0 100644 --- a/src/shared/view/elements/Select/Select.tsx +++ b/src/shared/view/elements/Select/Select.tsx @@ -4,7 +4,7 @@ import MenuItem from '@material-ui/core/MenuItem'; interface IOption { value: T; - label: string | number; + label: string | number | object; } interface IProps extends StandardTextFieldProps { From 2bbe72cd9be791eda5acb126d1ae854f980a43cd Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sat, 6 Apr 2019 17:04:22 +0300 Subject: [PATCH 18/33] Labels translations moved from constants --- .../RepositoriesSearchForm.tsx | 12 ++++- .../RepositoriesSearchForm/constants.ts | 8 --- .../RepositoriesSearchResults.tsx | 13 +++-- .../__tests__/index.test.ts | 3 +- .../UsersSearchForm/UsersSearchForm.tsx | 49 ++++++++++++++----- .../UsersSearchSettings.tsx | 18 ++++--- .../containers/UsersSearchForm/constants.ts | 22 --------- .../UsersSearchResults/UsersSearchResults.tsx | 12 +++-- .../__tests__/index.test.ts | 3 +- src/services/i18n/locales/en.ts | 8 ++- src/services/i18n/locales/ru.ts | 8 ++- .../TotalSearchResults/TotalSearchResults.tsx | 5 +- 12 files changed, 94 insertions(+), 67 deletions(-) diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx index 25277ace..b6fdc567 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx @@ -8,10 +8,11 @@ import { IAppReduxState } from 'shared/types/app'; import { SearchForm } from 'shared/view/components'; import { replaceObjectKeys } from 'shared/helpers'; +import { IRepositoriesSearchFilters } from 'shared/types/githubSearch'; import RepositoriesSearchSettings from './RepositoriesSearchSettings/RepositoriesSearchSettings'; import { selectors, actions } from './../../../redux'; import { IRepositoriesSearchFormFields } from '../../../namespace'; -import { fieldNames, filtersLabels } from './constants'; +import { fieldNames } from './constants'; interface IOwnProps { onSubmit(formValues: IRepositoriesSearchFormFields): void; @@ -36,6 +37,8 @@ function mapState(state: IAppReduxState): IStateProps { }; } +const { repositoriesSearch } = tKeys.features; + class RepositoriesSearchForm extends React.PureComponent { public render() { const { isRepositoriesSearchRequesting, resetSearchResults, t } = this.props; @@ -55,7 +58,14 @@ class RepositoriesSearchForm extends React.PureComponent { @bind private getFilters(formValues: IRepositoriesSearchFormFields) { + const { t } = this.props; const filters = R.omit([fieldNames.searchString], formValues); + const filtersLabels: Record = { + starsNumber: t(repositoriesSearch.starsNumber.getKey()), + forksNumber: t(repositoriesSearch.forksNumber.getKey()), + language: t(repositoriesSearch.language.getKey()), + owner: t(repositoriesSearch.owner.getKey()), + }; return replaceObjectKeys(filters, filtersLabels); } diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/constants.ts b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/constants.ts index 7819830e..43e2b55e 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/constants.ts +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/constants.ts @@ -1,5 +1,4 @@ import { FormFieldNames } from 'shared/types/form'; -import { IRepositoriesSearchFilters } from 'shared/types/githubSearch'; import { IRepositoriesSearchFormFields } from '../../../namespace'; export const fieldNames: FormFieldNames = { @@ -9,10 +8,3 @@ export const fieldNames: FormFieldNames = { language: 'language', owner: 'owner', }; - -export const filtersLabels: Record = { - starsNumber: 'Stars number', - forksNumber: 'Forks number', - language: 'Language', - owner: 'Owner', -}; diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchResults/RepositoriesSearchResults.tsx b/src/features/repositoriesSearch/view/containers/RepositoriesSearchResults/RepositoriesSearchResults.tsx index 8399e735..8257a204 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchResults/RepositoriesSearchResults.tsx +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchResults/RepositoriesSearchResults.tsx @@ -9,6 +9,7 @@ import { IRepository } from 'shared/types/models'; import { IPaginationState } from 'shared/types/common'; import { PaginationControls } from 'shared/view/components'; import { TotalSearchResults } from 'shared/view/elements'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import { IRepositoriesSearchFormFields } from '../../../namespace'; import { actions, selectors } from './../../../redux'; @@ -35,7 +36,7 @@ interface IContainerProps { UserDetails: IContainerTypes['UserDetails']; } -type IProps = IOwnProps & IStateProps & IActionProps & IContainerProps; +type IProps = IOwnProps & IStateProps & IActionProps & IContainerProps & WithTranslation; function mapState(state: IAppReduxState): IStateProps { return { @@ -57,11 +58,11 @@ class RepositoriesSearchResults extends React.PureComponent { }; public render() { - const { repositories, UserDetails, paginationState: { totalPages, page }, totalResults } = this.props; + const { repositories, UserDetails, paginationState: { totalPages, page }, totalResults, t } = this.props; const { displayedRepositoryOwner } = this.state; return (
- + {repositories.map(this.renderRepositoryPreview)}
{ private renderRepositoryPreview(repository: IRepository) { return (
- +
); } @@ -103,9 +104,11 @@ class RepositoriesSearchResults extends React.PureComponent { } } +const connectedComponent = connect(mapState, mapDispatch)(RepositoriesSearchResults); + export { RepositoriesSearchResults, IProps as IRepositoriesSearchResultsProps, IState as IRepositoriesSearchResultsState, }; -export default connect(mapState, mapDispatch)(containersProvider(['UserDetails'])(RepositoriesSearchResults)); +export default withTranslation()(containersProvider(['UserDetails'])(connectedComponent)); diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchResults/__tests__/index.test.ts b/src/features/repositoriesSearch/view/containers/RepositoriesSearchResults/__tests__/index.test.ts index dd9f3ceb..faa62567 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchResults/__tests__/index.test.ts +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchResults/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { makeMockComponent, repository } from 'shared/mocks'; import { PaginationControls } from 'shared/view/components'; @@ -19,6 +19,7 @@ const props: IRepositoriesSearchResultsProps = { searchRepositories: jest.fn(), UserDetails: makeMockComponent('UserDetails'), totalResults: 1, + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(RepositoriesSearchResults, props); diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx index bd770efa..52506d76 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx @@ -10,10 +10,11 @@ import { import { IAppReduxState } from 'shared/types/app'; import { IUsersSearchFilters } from 'shared/types/githubSearch'; import { SearchForm } from 'shared/view/components'; +import { ISelectOption } from 'shared/types/form'; import { selectors, actions } from './../../../redux'; import { IUsersSearchFormFields } from '../../../namespace'; -import { formInitialValues, fieldNames, searchByOptions, searchForLabels, filtersLabels } from './constants'; +import { formInitialValues, fieldNames } from './constants'; import UsersSearchSettings from './UsersSearchSettings/UsersSearchSettings'; interface IOwnProps { @@ -24,6 +25,7 @@ interface IStateProps { isUsersSearchRequesting: boolean; } +type OptionType = Array>; type IActionProps = typeof mapDispatch; type IProps = IOwnProps & IStateProps & IActionProps & WithTranslation; @@ -39,14 +41,27 @@ function mapState(state: IAppReduxState): IStateProps { }; } -class UsersSearchForm extends React.PureComponent { - private filtersValuesFormattersMap: KeysToValuesFormattersMap = { - searchBy: x => getSelectValuesToLabelsMap(searchByOptions)[x].toLowerCase(), - searchFor: x => ({ ...searchForLabels, both: 'users & organizations' })[x].toLowerCase(), - }; +const { userSearch } = tKeys.features; +class UsersSearchForm extends React.PureComponent { public render() { const { isUsersSearchRequesting, resetSearchResults, t } = this.props; + const getMemoOptions: () => OptionType = R.memoizeWith<() => OptionType>(R.identity, () => [ + { value: 'username-email', label: t(userSearch.usernameAndEmail.getKey()) }, + { value: 'login', label: t(userSearch.username.getKey()) }, + { value: 'email', label: t(userSearch.email.getKey()) }, + { value: 'fullname', label: t(userSearch.fullName.getKey()) }, + ]); + const getMemoLabels: () => Record = R.memoizeWith(R.identity, () => ({ + both: t(userSearch.usersAndOrganizations.getKey()), + org: t(userSearch.organizations.getKey()), + user: t(userSearch.users.getKey()), + })); + const filtersValuesFormattersMap: KeysToValuesFormattersMap = { + searchBy: x => getSelectValuesToLabelsMap(getMemoOptions())[x].toLowerCase(), + searchFor: x => (getMemoLabels())[x].toLowerCase(), + }; + return ( isSearchRequesting={isUsersSearchRequesting} @@ -57,17 +72,27 @@ class UsersSearchForm extends React.PureComponent { initialValues={formInitialValues} renderSettings={UsersSearchSettings} resetSearchResults={resetSearchResults} - getFilters={this.getFilters} + getFilters={this.makeFiltersGetter(filtersValuesFormattersMap)} /> ); } @bind - private getFilters(formFields: IUsersSearchFormFields) { - const filters = R.omit([fieldNames.searchString], formFields); - const filtersWithFormattedValues = replaceObjectValues(filters, this.filtersValuesFormattersMap); - const labels = { ...filtersLabels, minRepos: 'Min repositories', maxRepos: 'Max repositories' }; - return replaceObjectKeys(filtersWithFormattedValues, labels); + private makeFiltersGetter(filtersValuesFormattersMap: KeysToValuesFormattersMap) { + return (formFields: IUsersSearchFormFields) => { + const { t } = this.props; + const filters = R.omit([fieldNames.searchString], formFields); + const filtersLabels: Record = { + searchBy: t(userSearch.searchBy.getKey()), + searchFor: t(userSearch.searchFor.getKey()), + perPage: t(userSearch.resultsPerPage.getKey()), + reposLanguage: t(userSearch.repositoriesLanguage.getKey()), + minRepos: t(userSearch.min.getKey()), + maxRepos: t(userSearch.max.getKey()), + }; + const filtersWithFormattedValues = replaceObjectValues(filters, filtersValuesFormattersMap); + return replaceObjectKeys(filtersWithFormattedValues, filtersLabels); + }; } @bind diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx index ee7299ba..0c8eee94 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx @@ -1,5 +1,6 @@ import React from 'react'; import block from 'bem-cn'; +import * as R from 'ramda'; import { FormLabel } from 'shared/view/elements'; import { useTranslation, tKeys } from 'services/i18n'; @@ -12,21 +13,22 @@ import './UsersSearchSettings.scss'; const b = block('users-search-settings'); const { userSearch } = tKeys.features; +type OptionType = Array>; function UsersSearchSettings() { const { t } = useTranslation(); - const searchByOptions: Array> = [ - { value: 'username-email', label: t(userSearch.usernameAndEmail.getKey()) || 'Username & email' }, - { value: 'login', label: t(userSearch.username.getKey()) || 'Username' }, - { value: 'email', label: t(userSearch.email.getKey()) || 'Email' }, - { value: 'fullname', label: t(userSearch.fullName.getKey()) || 'Full name' }, - ]; + const getMemoOptions: () => OptionType = R.memoizeWith<() => OptionType>(R.identity, () => [ + { value: 'username-email', label: t(userSearch.usernameAndEmail.getKey()) }, + { value: 'login', label: t(userSearch.username.getKey()) }, + { value: 'email', label: t(userSearch.email.getKey()) }, + { value: 'fullname', label: t(userSearch.fullName.getKey()) }, + ]); return (
- +
- {t(userSearch.searchType.getKey())} + {t(userSearch.searchFor.getKey())}
diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/constants.ts b/src/features/usersSearch/view/containers/UsersSearchForm/constants.ts index 5aa0c3e2..cf740720 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/constants.ts +++ b/src/features/usersSearch/view/containers/UsersSearchForm/constants.ts @@ -2,28 +2,6 @@ import { IUsersSearchFilters } from 'shared/types/githubSearch'; import { FormFieldNames, ISelectOption } from 'shared/types/form'; import { IUsersSearchFormFields } from '../../../namespace'; -export const searchByOptions: Array> = [ - { value: 'username-email', label: 'Username & email' }, - { value: 'login', label: 'Username' }, - { value: 'email', label: 'Email' }, - { value: 'fullname', label: 'Full name' }, -]; - -export const filtersLabels: Record = { - searchBy: 'Search by', - searchFor: 'Search for', - perPage: 'Results per page', - reposLanguage: 'Repositories language', - minRepos: 'min', - maxRepos: 'max', -}; - -export const searchForLabels: Record = { - both: 'Both', - org: 'Organizations', - user: 'Users', -}; - export const perPageOptions: Array> = [ { value: 30, label: '30' }, { value: 50, label: '50' }, diff --git a/src/features/usersSearch/view/containers/UsersSearchResults/UsersSearchResults.tsx b/src/features/usersSearch/view/containers/UsersSearchResults/UsersSearchResults.tsx index 2f9a0463..5e391f22 100644 --- a/src/features/usersSearch/view/containers/UsersSearchResults/UsersSearchResults.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchResults/UsersSearchResults.tsx @@ -3,6 +3,7 @@ import { connect } from 'react-redux'; import block from 'bem-cn'; import { bind } from 'decko'; +import { withTranslation, WithTranslation, tKeys } from 'services/i18n'; import { IAppReduxState } from 'shared/types/app'; import { IGithubUser } from 'shared/types/models'; import { IPaginationState } from 'shared/types/common'; @@ -31,7 +32,7 @@ interface IStateProps { type IActionProps = typeof mapDispatch; -type IProps = IOwnProps & IStateProps & IActionProps; +type IProps = IOwnProps & IStateProps & IActionProps & WithTranslation; function mapState(state: IAppReduxState): IStateProps { return { @@ -53,11 +54,11 @@ class UsersSearchResults extends React.PureComponent { }; public render() { - const { users, paginationState: { page, totalPages }, totalResults } = this.props; + const { users, paginationState: { page, totalPages }, totalResults, t } = this.props; const { displayedUser } = this.state; return (
- +
{ onPageRequest={this.handlePageRequest} />
- {displayedUser && } + {displayedUser && }
); } @@ -88,5 +89,6 @@ class UsersSearchResults extends React.PureComponent { } } +const connectedComponent = connect(mapState, mapDispatch)(UsersSearchResults); export { UsersSearchResults, IProps as IUsersSearchResultsProps }; -export default connect(mapState, mapDispatch)(UsersSearchResults); +export default withTranslation()(connectedComponent); diff --git a/src/features/usersSearch/view/containers/UsersSearchResults/__tests__/index.test.ts b/src/features/usersSearch/view/containers/UsersSearchResults/__tests__/index.test.ts index 7638d4b8..5d400f92 100644 --- a/src/features/usersSearch/view/containers/UsersSearchResults/__tests__/index.test.ts +++ b/src/features/usersSearch/view/containers/UsersSearchResults/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { makeShallowRenderer } from 'shared/helpers'; +import { makeShallowRenderer, getMockedLocaleProps } from 'shared/helpers'; import { githubUser } from 'shared/mocks'; import { PaginationControls } from 'shared/view/components'; @@ -20,6 +20,7 @@ const props: IUsersSearchResultsProps = { }, searchUsers: jest.fn(), totalResults: 1, + ...getMockedLocaleProps(), }; const getComponent = makeShallowRenderer(UsersSearchResults, props); diff --git a/src/services/i18n/locales/en.ts b/src/services/i18n/locales/en.ts index 7523b4ef..746c33d4 100644 --- a/src/services/i18n/locales/en.ts +++ b/src/services/i18n/locales/en.ts @@ -6,6 +6,7 @@ export default { search: 'Search', settings: 'Settings', searchSettings: 'Search settings', + totalResults: 'Total results:', header: { searchFor: 'Search for:', users: 'Users', @@ -31,6 +32,9 @@ export default { repositoriesSearch: { minStars: 'Min stars', minForks: 'Min forks', + starsNumber: 'Stars number', + forksNumber: 'Forks number', + language: 'Language', repositoriesLanguage: 'Repositories language', owner: 'Owner', forks: 'Forks', @@ -45,6 +49,8 @@ export default { email: 'Email', fullName: 'Full name', user: 'User', + users: 'Users', + usersAndOrganizations: 'Users & organizations', organizations: 'Organizations', both: 'Both', followers: 'Followers', @@ -54,7 +60,7 @@ export default { min: 'min', max: 'max', searchBy: 'Search by', - searchType: 'Search type', + searchFor: 'Search for', repositoriesLanguage: 'Repositories language', resultsPerPage: 'Results per page', repositoriesNumber: 'Repositories number', diff --git a/src/services/i18n/locales/ru.ts b/src/services/i18n/locales/ru.ts index e825ce8b..57fc2010 100644 --- a/src/services/i18n/locales/ru.ts +++ b/src/services/i18n/locales/ru.ts @@ -6,6 +6,7 @@ export default { search: 'Поиск', settings: 'Настройки', searchSettings: 'Настройки поиска', + totalResults: 'Количество результатов:', header: { searchFor: 'Искать:', users: 'Пользователей', @@ -35,6 +36,9 @@ export default { minForks: 'мин. форков', repositoriesLanguage: 'Язык репозиториев', owner: 'Владелец', + starsNumber: 'Кол-во звезд', + forksNumber: 'Кол-во форков', + language: 'Язык', forks: 'Форки', openIssues: 'Открытые задачи', lastUpdated: 'Последнее обновление', @@ -43,7 +47,9 @@ export default { usersSearch: 'Поиск пользователя GitHub', repositoriesSearch: 'Поиск репозитория GitHub', user: 'Пользователей', + users: 'Пользователей', organizations: 'Организации', + usersAndOrganizations: 'Пользователей и организации', usernameAndEmail: 'Никнейму и почте', username: 'Никнейму', email: 'Почта', @@ -56,7 +62,7 @@ export default { min: 'минимум', max: 'максимум', searchBy: 'Поиск по', - searchType: 'Искать', + searchFor: 'Искать', repositoriesLanguage: 'Язык репозиториев', resultsPerPage: 'Результ. на страницу', repositoriesNumber: 'Количество репозиториев', diff --git a/src/shared/view/elements/TotalSearchResults/TotalSearchResults.tsx b/src/shared/view/elements/TotalSearchResults/TotalSearchResults.tsx index 78fd5636..c5155262 100644 --- a/src/shared/view/elements/TotalSearchResults/TotalSearchResults.tsx +++ b/src/shared/view/elements/TotalSearchResults/TotalSearchResults.tsx @@ -3,17 +3,18 @@ import block from 'bem-cn'; import './TotalSearchResults.scss'; interface IProps { + title: string; totalResults: number; } const b = block('total-search-results'); function TotalSearchResults(props: IProps) { - const { totalResults } = props; + const { title, totalResults } = props; return totalResults > 0 ? (
- {'Total results: '} + {title} {totalResults} From 87054882c329ac25a245a713f7f3b9ae7457922e Mon Sep 17 00:00:00 2001 From: clicktronix Date: Sun, 7 Apr 2019 21:25:10 +0300 Subject: [PATCH 19/33] Lang selector tested --- jest.config.js | 1 - .../LanguageSelector/__tests__/index.test.ts | 28 +++++++++++++++++-- src/shared/helpers/tests/mockLocaleProps.ts | 13 ++++++--- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/jest.config.js b/jest.config.js index d72e51f1..04eb64c7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -21,7 +21,6 @@ module.exports = { 'ContainersProvider\.tsx$': '/src/core/__mocks__/fileMock.ts', }, - mapCoverage: true, coverageDirectory: '/coverage', collectCoverageFrom: [ '**/src/**/*.{ts,tsx}', diff --git a/src/services/i18n/view/LanguageSelector/__tests__/index.test.ts b/src/services/i18n/view/LanguageSelector/__tests__/index.test.ts index 3a0bc432..24cabe6e 100644 --- a/src/services/i18n/view/LanguageSelector/__tests__/index.test.ts +++ b/src/services/i18n/view/LanguageSelector/__tests__/index.test.ts @@ -26,9 +26,33 @@ describe('(services/i18n) LanguageSelector component', () => { }; const component = getComponent(newProps); - component.find('select').simulate('change', { target: { value: 'ru' } }); + component.find('select').simulate('change', { target: { value: 'ru-RU' } }); expect(changeLanguage).toBeCalledTimes(1); - expect(changeLanguage).toBeCalledWith('ru'); + expect(changeLanguage).toBeCalledWith('ru-RU'); + }); + + it('should render select with en-US default language', () => { + const component = getComponent(); + + expect(component.find('select').props().value).toEqual('en-US'); + }); + + it('should render right options value', () => { + const component = getComponent(); + const options = component.find('option'); + + expect(options.length).toEqual(2); + expect(options.at(0).props().value).toEqual('en-US'); + expect(options.at(1).props().value).toEqual('ru-RU'); + }); + + it('should render right labels', () => { + const component = getComponent(); + const options = component.find('option'); + + expect(options.length).toEqual(2); + expect(options.at(0).props().children).toEqual('English'); + expect(options.at(1).props().children).toEqual('Русский'); }); }); diff --git a/src/shared/helpers/tests/mockLocaleProps.ts b/src/shared/helpers/tests/mockLocaleProps.ts index e252332b..c91cb6ba 100644 --- a/src/shared/helpers/tests/mockLocaleProps.ts +++ b/src/shared/helpers/tests/mockLocaleProps.ts @@ -4,8 +4,8 @@ export const getMockedLocaleProps: () => WithTranslation = () => ({ t: jest.fn(), i18n: { isInitialized: true, - language: 'en', - languages: ['en', 'ru'], + language: 'en-US', + languages: ['en-US', 'ru-RU'], options: {}, services: { backendConnector: {}, @@ -16,9 +16,14 @@ export const getMockedLocaleProps: () => WithTranslation = () => ({ logger: {}, pluralResolver: {}, resourceStore: { - en: { + 'en-US': { translationNamespace: { - translateMock: 'translateMock', + translateMock: 'translate mock', + }, + }, + 'ru-RU': { + translationNamespace: { + translateMock: 'заглушка перевода', }, }, }, From 71466edddab87beb8728c5425c758d5de135edae Mon Sep 17 00:00:00 2001 From: clicktronix Date: Mon, 8 Apr 2019 09:27:52 +0300 Subject: [PATCH 20/33] Memoization fixed --- .../UsersSearchForm/UsersSearchForm.tsx | 19 ++++++++------ .../UsersSearchSettings.tsx | 11 +++++--- src/modules/shared/Layout/Layout.tsx | 25 +++++++++---------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx index 52506d76..05143c87 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx @@ -25,9 +25,9 @@ interface IStateProps { isUsersSearchRequesting: boolean; } -type OptionType = Array>; +type OptionType = ISelectOption; +type LabelsType = Record; type IActionProps = typeof mapDispatch; - type IProps = IOwnProps & IStateProps & IActionProps & WithTranslation; const mapDispatch = { @@ -46,20 +46,23 @@ const { userSearch } = tKeys.features; class UsersSearchForm extends React.PureComponent { public render() { const { isUsersSearchRequesting, resetSearchResults, t } = this.props; - const getMemoOptions: () => OptionType = R.memoizeWith<() => OptionType>(R.identity, () => [ + const options: OptionType[] = [ { value: 'username-email', label: t(userSearch.usernameAndEmail.getKey()) }, { value: 'login', label: t(userSearch.username.getKey()) }, { value: 'email', label: t(userSearch.email.getKey()) }, { value: 'fullname', label: t(userSearch.fullName.getKey()) }, - ]); - const getMemoLabels: () => Record = R.memoizeWith(R.identity, () => ({ + ]; + const labels: LabelsType = { both: t(userSearch.usersAndOrganizations.getKey()), org: t(userSearch.organizations.getKey()), user: t(userSearch.users.getKey()), - })); + }; + const getMemoOptions = R.memoizeWith(R.identity, (x: OptionType[]) => x); + const getMemoLabels = R.memoizeWith(R.identity, (x: LabelsType) => x); + const filtersValuesFormattersMap: KeysToValuesFormattersMap = { - searchBy: x => getSelectValuesToLabelsMap(getMemoOptions())[x].toLowerCase(), - searchFor: x => (getMemoLabels())[x].toLowerCase(), + searchBy: x => getSelectValuesToLabelsMap(getMemoOptions(options))[x].toLowerCase(), + searchFor: x => (getMemoLabels(labels))[x].toLowerCase(), }; return ( diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx index 0c8eee94..eb17b563 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx @@ -17,18 +17,23 @@ type OptionType = Array>; function UsersSearchSettings() { const { t } = useTranslation(); - const getMemoOptions: () => OptionType = R.memoizeWith<() => OptionType>(R.identity, () => [ + const options: OptionType = [ { value: 'username-email', label: t(userSearch.usernameAndEmail.getKey()) }, { value: 'login', label: t(userSearch.username.getKey()) }, { value: 'email', label: t(userSearch.email.getKey()) }, { value: 'fullname', label: t(userSearch.fullName.getKey()) }, - ]); + ]; + const getMemoOptions = R.memoizeWith(R.identity, (x: OptionType) => x); return (
- +
{ public render() { const { children, title, profileFeatureEntry: { containers }, t } = this.props; const { ProfilePreview } = containers; - const getMemoMenuItems = R.memoizeWith(R.identity, (): IHeaderMenuItem[] => ( - [ - { - path: routes.search.users.getRoutePath(), - title: this.props.t(header.users.getKey()), - }, - { - path: routes.search.repositories.getRoutePath(), - title: this.props.t(header.repositories.getKey()), - }, - ] - )); + const menuItems: IHeaderMenuItem[] = [ + { + path: routes.search.users.getRoutePath(), + title: this.props.t(header.users.getKey()), + }, + { + path: routes.search.repositories.getRoutePath(), + title: this.props.t(header.repositories.getKey()), + }, + ]; + const getMemoMenuItems = R.memoizeWith(R.identity, (x: IHeaderMenuItem[]): IHeaderMenuItem[] => x); return (
- +
From baeac917119a6d5e1f0774bb6c3773ee1dc73d65 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Mon, 8 Apr 2019 10:12:32 +0300 Subject: [PATCH 21/33] Translates updated --- .../RepositoriesSearchForm.tsx | 4 ++-- .../UsersSearchForm/UsersSearchForm.tsx | 3 ++- .../UsersSearchSettings.tsx | 19 ++++++++---------- src/services/i18n/locales/en.ts | 8 +++----- src/services/i18n/locales/ru.ts | 20 +++++++++---------- 5 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx index b6fdc567..930a2e6a 100644 --- a/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx +++ b/src/features/repositoriesSearch/view/containers/RepositoriesSearchForm/RepositoriesSearchForm.tsx @@ -61,8 +61,8 @@ class RepositoriesSearchForm extends React.PureComponent { const { t } = this.props; const filters = R.omit([fieldNames.searchString], formValues); const filtersLabels: Record = { - starsNumber: t(repositoriesSearch.starsNumber.getKey()), - forksNumber: t(repositoriesSearch.forksNumber.getKey()), + starsNumber: t(repositoriesSearch.minStars.getKey()), + forksNumber: t(repositoriesSearch.minForks.getKey()), language: t(repositoriesSearch.language.getKey()), owner: t(repositoriesSearch.owner.getKey()), }; diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx index 05143c87..2a087345 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchForm.tsx @@ -64,6 +64,7 @@ class UsersSearchForm extends React.PureComponent { searchBy: x => getSelectValuesToLabelsMap(getMemoOptions(options))[x].toLowerCase(), searchFor: x => (getMemoLabels(labels))[x].toLowerCase(), }; + const renderUsersSearchSettings = () => ; return ( @@ -73,7 +74,7 @@ class UsersSearchForm extends React.PureComponent { submitButtonText={t(tKeys.shared.search.getKey())} settingsButtonText={t(tKeys.shared.settings.getKey())} initialValues={formInitialValues} - renderSettings={UsersSearchSettings} + renderSettings={renderUsersSearchSettings} resetSearchResults={resetSearchResults} getFilters={this.makeFiltersGetter(filtersValuesFormattersMap)} /> diff --git a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx index eb17b563..35548a33 100644 --- a/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx +++ b/src/features/usersSearch/view/containers/UsersSearchForm/UsersSearchSettings/UsersSearchSettings.tsx @@ -11,26 +11,23 @@ import { IUsersSearchFilters } from 'shared/types/githubSearch'; import { perPageOptions, fieldNames } from '../constants'; import './UsersSearchSettings.scss'; +interface IProps { + options: Array>; +} + const b = block('users-search-settings'); const { userSearch } = tKeys.features; -type OptionType = Array>; -function UsersSearchSettings() { +function UsersSearchSettings(props: IProps) { const { t } = useTranslation(); - const options: OptionType = [ - { value: 'username-email', label: t(userSearch.usernameAndEmail.getKey()) }, - { value: 'login', label: t(userSearch.username.getKey()) }, - { value: 'email', label: t(userSearch.email.getKey()) }, - { value: 'fullname', label: t(userSearch.fullName.getKey()) }, - ]; - const getMemoOptions = R.memoizeWith(R.identity, (x: OptionType) => x); + const getMemoOptions = R.memoizeWith(R.identity, (x: Array>) => x); return (
@@ -48,7 +45,7 @@ function UsersSearchSettings() { {t(userSearch.searchFor.getKey())}
- +
diff --git a/src/services/i18n/locales/en.ts b/src/services/i18n/locales/en.ts index 746c33d4..d711ccf8 100644 --- a/src/services/i18n/locales/en.ts +++ b/src/services/i18n/locales/en.ts @@ -6,7 +6,7 @@ export default { search: 'Search', settings: 'Settings', searchSettings: 'Search settings', - totalResults: 'Total results:', + totalResults: 'Total results: ', header: { searchFor: 'Search for:', users: 'Users', @@ -32,8 +32,6 @@ export default { repositoriesSearch: { minStars: 'Min stars', minForks: 'Min forks', - starsNumber: 'Stars number', - forksNumber: 'Forks number', language: 'Language', repositoriesLanguage: 'Repositories language', owner: 'Owner', @@ -57,8 +55,8 @@ export default { following: 'Following', repositories: 'Repositories', userDetails: 'User details', - min: 'min', - max: 'max', + min: 'Min repos', + max: 'Max repos', searchBy: 'Search by', searchFor: 'Search for', repositoriesLanguage: 'Repositories language', diff --git a/src/services/i18n/locales/ru.ts b/src/services/i18n/locales/ru.ts index 57fc2010..b610c28b 100644 --- a/src/services/i18n/locales/ru.ts +++ b/src/services/i18n/locales/ru.ts @@ -6,7 +6,7 @@ export default { search: 'Поиск', settings: 'Настройки', searchSettings: 'Настройки поиска', - totalResults: 'Количество результатов:', + totalResults: 'Количество результатов: ', header: { searchFor: 'Искать:', users: 'Пользователей', @@ -32,35 +32,33 @@ export default { edit: 'Редактировать', }, repositoriesSearch: { - minStars: 'мин. звезд', - minForks: 'мин. форков', + minStars: 'Мин. звезд', + minForks: 'Мин. форков', repositoriesLanguage: 'Язык репозиториев', owner: 'Владелец', - starsNumber: 'Кол-во звезд', - forksNumber: 'Кол-во форков', language: 'Язык', forks: 'Форки', openIssues: 'Открытые задачи', lastUpdated: 'Последнее обновление', }, userSearch: { - usersSearch: 'Поиск пользователя GitHub', - repositoriesSearch: 'Поиск репозитория GitHub', + usersSearch: 'Поиск пользователей GitHub', + repositoriesSearch: 'Поиск репозиториев GitHub', user: 'Пользователей', users: 'Пользователей', organizations: 'Организации', usersAndOrganizations: 'Пользователей и организации', usernameAndEmail: 'Никнейму и почте', username: 'Никнейму', - email: 'Почта', - fullName: 'Полное имя', + email: 'Почте', + fullName: 'Полному имени', both: 'Пользователей и организации', followers: 'Подписчики', following: 'Подписки', repositories: 'Репозитории', userDetails: 'Данные пользователя', - min: 'минимум', - max: 'максимум', + min: 'Мин. реп.', + max: 'Макс. реп.', searchBy: 'Поиск по', searchFor: 'Искать', repositoriesLanguage: 'Язык репозиториев', From 3a0ec63ab9d43a801348d4fa3482ddb5c03a6160 Mon Sep 17 00:00:00 2001 From: clicktronix Date: Mon, 8 Apr 2019 16:15:03 +0300 Subject: [PATCH 22/33] Replaced lang selector by mui --- .../LanguageSelector/LanguageSelector.scss | 9 +++++++++ .../view/LanguageSelector/LanguageSelector.tsx | 18 ++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 src/services/i18n/view/LanguageSelector/LanguageSelector.scss diff --git a/src/services/i18n/view/LanguageSelector/LanguageSelector.scss b/src/services/i18n/view/LanguageSelector/LanguageSelector.scss new file mode 100644 index 00000000..812677b7 --- /dev/null +++ b/src/services/i18n/view/LanguageSelector/LanguageSelector.scss @@ -0,0 +1,9 @@ +.select { + & div { + color: white; + } + + & svg { + fill: white; + } +} diff --git a/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx b/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx index 7543ef7f..c99d8929 100644 --- a/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx +++ b/src/services/i18n/view/LanguageSelector/LanguageSelector.tsx @@ -1,14 +1,20 @@ import React from 'react'; import { bind } from 'decko'; import { WithTranslation, withTranslation } from 'react-i18next'; +import block from 'bem-cn'; import { Lang } from 'shared/types/app'; +import { Select } from 'shared/view/elements'; + +import './LanguageSelector.scss'; interface IOption { value: Lang; label: string; } +const b = block('select'); + class LanguageSelector extends React.PureComponent { public static options: IOption[] = [ { value: 'en-US', label: 'English' }, @@ -19,12 +25,12 @@ class LanguageSelector extends React.PureComponent { const { i18n: { language } } = this.props; return ( -
- +
+ -
+