From 8fa58e0e252abc89a2fb86f3fe60af5167a4b01f Mon Sep 17 00:00:00 2001 From: damfinkel Date: Fri, 6 Mar 2020 17:57:00 -0300 Subject: [PATCH 1/6] replaced redux for context, changed some files to ts and added request hook --- .eslintrc.js | 6 +- README.md | 8 - generators/app/constants.js | 5 +- .../app/steps/CustomizableSteps/constants.js | 31 +- .../app/steps/CustomizableSteps/copyFiles.js | 3 + generators/app/tasks/fileCreators.js | 8 +- generators/app/tasks/gitConfig.js | 2 +- generators/app/templates/.babelrc.ejs | 4 +- generators/app/templates/.eslintrc.ejs | 4 +- generators/app/templates/docs/Field.md | 34 -- generators/app/templates/docs/SearchBar.md | 33 +- generators/app/templates/docs/TextArea.md | 12 - generators/app/templates/jsconfig.json | 1 - .../src/app/components/Field/index.js | 22 -- .../app/components/ProviderWrapper/index.tsx | 24 ++ .../Routes/components/AuthenticatedRoute.tsx | 82 ----- .../Routes/components/RouteItem.tsx | 13 + .../src/app/components/Routes/constants.ts | 32 ++ .../src/app/components/Routes/i18n.ts | 9 + .../src/app/components/Routes/index.ejs | 30 -- .../src/app/components/Routes/index.tsx | 30 ++ .../src/app/components/Routes/paths.ts | 5 + generators/app/templates/src/app/context.ts | 5 + generators/app/templates/src/app/index.ejs | 24 -- generators/app/templates/src/app/index.tsx | 19 ++ generators/app/templates/src/app/reducer.ts | 48 +++ .../src/app/screens/Dashboard/index.js | 8 +- .../screens/Dashboard/screens/Home/context.ts | 5 + .../screens/Dashboard/screens/Home/index.js | 17 +- .../screens/Dashboard/screens/Home/reducer.ts | 42 +++ .../src/app/screens/Login/index.test.js | 23 ++ .../templates/src/app/screens/Login/index.tsx | 46 +-- .../src/app/screens/Login/layout.tsx | 4 +- generators/app/templates/src/config/api.js | 2 +- .../app/templates/src/config/context.ts | 26 ++ .../app/templates/src/redux/Auth/actions.js | 60 ---- .../app/templates/src/redux/Auth/reducer.js | 58 ---- generators/app/templates/src/redux/store.js | 46 --- .../src/services/AnalyticsService.js | 13 - .../app/templates/src/services/utils.ts | 110 ++++++ generators/app/templates/src/utils/types.ts | 1 + generators/app/templates/tsconfig.paths.json | 6 +- package-lock.json | 314 +++++++++++++++++- package.json | 10 +- tsconfig.json | 25 ++ 45 files changed, 805 insertions(+), 505 deletions(-) delete mode 100644 generators/app/templates/docs/Field.md delete mode 100644 generators/app/templates/src/app/components/Field/index.js create mode 100644 generators/app/templates/src/app/components/ProviderWrapper/index.tsx delete mode 100644 generators/app/templates/src/app/components/Routes/components/AuthenticatedRoute.tsx create mode 100644 generators/app/templates/src/app/components/Routes/components/RouteItem.tsx create mode 100644 generators/app/templates/src/app/components/Routes/constants.ts create mode 100644 generators/app/templates/src/app/components/Routes/i18n.ts delete mode 100644 generators/app/templates/src/app/components/Routes/index.ejs create mode 100644 generators/app/templates/src/app/components/Routes/index.tsx create mode 100644 generators/app/templates/src/app/components/Routes/paths.ts create mode 100644 generators/app/templates/src/app/context.ts delete mode 100644 generators/app/templates/src/app/index.ejs create mode 100644 generators/app/templates/src/app/index.tsx create mode 100644 generators/app/templates/src/app/reducer.ts create mode 100644 generators/app/templates/src/app/screens/Dashboard/screens/Home/context.ts create mode 100644 generators/app/templates/src/app/screens/Dashboard/screens/Home/reducer.ts create mode 100644 generators/app/templates/src/app/screens/Login/index.test.js create mode 100644 generators/app/templates/src/config/context.ts delete mode 100644 generators/app/templates/src/redux/Auth/actions.js delete mode 100644 generators/app/templates/src/redux/Auth/reducer.js delete mode 100644 generators/app/templates/src/redux/store.js delete mode 100644 generators/app/templates/src/services/AnalyticsService.js create mode 100644 generators/app/templates/src/services/utils.ts create mode 100644 generators/app/templates/src/utils/types.ts create mode 100644 tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index 9dce6bd2..d0dbf73a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,9 @@ module.exports = { - extends: ['wolox-react'], + extends: ['wolox', 'wolox-react', 'wolox-typescript'], + parser: '@typescript-eslint/parser', rules: { 'import/no-unresolved': 'off', - 'import/no-extraneous-dependencies': 'off' + 'import/no-extraneous-dependencies': 'off', + '@typescript-eslint/no-var-requires': 'off' } }; diff --git a/README.md b/README.md index ab979d3e..e5360804 100644 --- a/README.md +++ b/README.md @@ -99,15 +99,8 @@ Additional to clean libraries are added |Name|Description| |----|-----------| |[apisauce](https://github.com/infinitered/apisauce)| Talking to APIs doesn't have to be awkward anymore. -|[redux](https://redux.js.org/)| Helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. -|[react-redux](https://react-redux.js.org/)| Is the official React binding for Redux. -|[connected-react-router](https://github.com/supasate/connected-react-router)| A Redux binding for React Router v4. |[react-router-dom](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-dom)| DOM bindings for React Router. -|[redux-recompose](https://github.com/Wolox/redux-recompose)| A Redux utility belt for reducers and actions. Inspired by acdlite/recompose. -|[redux-form](https://github.com/erikras/redux-form)| A Higher Order Component using react-redux to keep form state in a Redux store. -|[redux-thunk](https://github.com/reduxjs/redux-thunk)| Middlewere for Redux. |[react-router](https://github.com/ReactTraining/react-router)| Routing for React. -|[redux-beacon](https://github.com/rangle/redux-beacon)| Analytics integration for Redux. |[seamless-immutable](https://github.com/rtfeldman/seamless-immutable)| Immutable data structures for JavaScript. |[history](https://www.npmjs.com/package/history)| Manage session history anywhere JavaScript runs. |[i18next](https://www.i18next.com/)| An internationalization-framework written in and for JavaScript. @@ -120,7 +113,6 @@ Also you can select **_optional_** libraries like |----|-----------| |[moment](https://momentjs.com/)| Parse, validate, manipulate, and display dates and times in JavaScript. |[seamless-immutable](https://github.com/rtfeldman/seamless-immutable)| Immutable data structures for JavaScript. -|[reselect](https://github.com/reduxjs/reselect)| Selector library for Redux. |[babel-module-resolver](https://github.com/tleunen/babel-plugin-module-resolver)| Custom module resolver plugin for Babel. ## Notes diff --git a/generators/app/constants.js b/generators/app/constants.js index 3fd0fb3a..74f90136 100644 --- a/generators/app/constants.js +++ b/generators/app/constants.js @@ -84,7 +84,10 @@ module.exports.FILES_TO_DESTINATION = [LINTER_IGNORE_PATH, RESCRIPTS_PATH, NPMRC module.exports.CI_CONFIG_FILE = `${CI_PATH}/config.yml`; -module.exports.BOOTSTRAP_TYPES = [{ name: 'Clean', value: false }, { name: 'Customized', value: true }]; +module.exports.BOOTSTRAP_TYPES = [ + { name: 'Clean', value: false }, + { name: 'Customized', value: true } +]; module.exports.DEV_DEPENDENCIES = [ 'eslint-plugin-import@2.18.2', diff --git a/generators/app/steps/CustomizableSteps/constants.js b/generators/app/steps/CustomizableSteps/constants.js index 4282b5e8..359747c8 100644 --- a/generators/app/steps/CustomizableSteps/constants.js +++ b/generators/app/steps/CustomizableSteps/constants.js @@ -1,7 +1,6 @@ const COMPONENTS_PATH = 'src/app/components'; const SCREENS_PATH = 'src/app/screens'; const CONFIG_PATH = 'src/config'; -const REDUX_PATH = 'src/redux'; const UTILS_PATH = 'src/utils'; const SERVICES_PATH = 'src/services'; const CONSTANTS_PATH = 'src/constants'; @@ -18,13 +17,10 @@ module.exports.NPMRC_PATH = { destination: '.npmrc' }; -module.exports.REDUX_COMPONENTS = [`${COMPONENTS_PATH}/Field/index.js`]; - module.exports.FILES = [ CONFIG_PATH, CONSTANTS_PATH, DOCS_README_PATH, - REDUX_PATH, SCREENS_PATH, UTILS_PATH, 'aws.js', @@ -32,8 +28,10 @@ module.exports.FILES = [ 'tsconfig.paths.json', 'scripts/deploy.js', 'src/react-app-env.d.ts', - `${COMPONENTS_PATH}/Routes/components/AuthenticatedRoute.tsx`, - `${COMPONENTS_PATH}/Routes/styles.module.scss`, + 'src/app/index.tsx', + 'src/app/reducer.ts', + 'src/app/context.ts', + `${COMPONENTS_PATH}/Routes`, `${COMPONENTS_PATH}/Spinner`, `${COMPONENTS_PATH}/Suspense`, `${COMPONENTS_PATH}/SearchBar`, @@ -41,8 +39,8 @@ module.exports.FILES = [ `${COMPONENTS_PATH}/TextArea`, `${COMPONENTS_PATH}/Checkbox`, `${COMPONENTS_PATH}/RadioGroup`, - `${SERVICES_PATH}/AuthServices.js`, - `${SERVICES_PATH}/AnalyticsService.js` + `${COMPONENTS_PATH}/ProviderWrapper`, + `${SERVICES_PATH}/AuthServices.js` ]; module.exports.TEMPLATE_FILES = [ @@ -50,8 +48,6 @@ module.exports.TEMPLATE_FILES = [ '.eslintrc.js', '.babelrc.js', 'src/index.tsx', - 'src/app/index.tsx', - `${COMPONENTS_PATH}/Routes/index.tsx`, `${SERVICES_PATH}/LocalStorageService.js` ]; @@ -73,7 +69,6 @@ module.exports.WITHOUT_SEAMLESS_FILES = { module.exports.OPTIONAL_DEPENDENCIES = { moment: { dependencies: ['moment@^2.23.0'] }, 'seamless-immutable': { dependencies: ['seamless-immutable@^7.1.4'] }, - reselect: { dependencies: ['reselect@^4.0.0'] }, 'babel-module-resolver': { dependencies: ['babel-plugin-module-resolver@^3.1.1'], devDependencies: ['eslint-import-resolver-babel-module@^5.0.0'] @@ -82,16 +77,8 @@ module.exports.OPTIONAL_DEPENDENCIES = { module.exports.DEPENDENCIES = [ 'apisauce@^1.0.1', - 'redux@^4.0.1', - 'react-redux@^6.0.0', - 'connected-react-router@^6.0.0', - 'react-router-dom@^4.3.1', - 'redux-recompose@^2.1.0', - 'redux-form@^8.0.4', - 'redux-thunk@^2.3.0', - 'react-router@^4.3.1', - 'redux-beacon@^2.0.3', - '@redux-beacon/google-analytics@^1.1.1', + 'react-router@^5.1.2', + 'react-router-dom@^5.1.2', 'seamless-immutable@^7.1.4', 'history@^4.7.2', 'i18next@^13.0.0', @@ -104,8 +91,8 @@ module.exports.DEV_DEPENDENCIES = [ '@types/node@^12.12.14', '@types/react@^16.9.13', '@types/react-dom@^16.9.4', - '@types/react-redux@^7.1.5', '@types/react-router@^5.1.2', + '@types/react-router@^5.1.4', '@types/react-router-dom@^5.1.3', '@types/seamless-immutable@^7.1.11', '@types/webpack-env@^1.14.1' diff --git a/generators/app/steps/CustomizableSteps/copyFiles.js b/generators/app/steps/CustomizableSteps/copyFiles.js index 12b6e32b..9f879520 100644 --- a/generators/app/steps/CustomizableSteps/copyFiles.js +++ b/generators/app/steps/CustomizableSteps/copyFiles.js @@ -7,7 +7,10 @@ const { FILES, FILES_TO_DELETE, TEMPLATE_FILES, WITHOUT_SEAMLESS_FILES } = requi module.exports = function copyAllFiles() { mkdirp(this.destinationPath(`${this.projectName}/src/app/assets/`)); + console.log('Deleting default CRA files...'); deleteFiles.bind(this)(FILES_TO_DELETE); + + console.log('Adding files...'); copyFiles.bind(this)(FILES); copyTemplateFiles.bind(this)(TEMPLATE_FILES); diff --git a/generators/app/tasks/fileCreators.js b/generators/app/tasks/fileCreators.js index aa6bc689..a0fd6a8e 100644 --- a/generators/app/tasks/fileCreators.js +++ b/generators/app/tasks/fileCreators.js @@ -4,6 +4,13 @@ const getPackageJsonAttributes = (projectName, projectVersion, repoUrl) => ({ name: projectName, title: projectName, version: projectVersion, + jest: { + moduleNameMapper: { + '~screens(.*)': '/src/app/screens/$1', + '~components(.*)': '/src/app/components/$1', + '^~(.*)/(.*)$': '/src/$1/$2' + } + }, repository: { type: 'git', url: repoUrl @@ -60,7 +67,6 @@ module.exports.createJSConfig = function createJSConfig() { '~screens/*': ['./src/app/screens/*'], '~config/*': ['./src/config/*'], '~constants/*': ['./src/constants/*'], - '~redux/*': ['./src/redux/*'], '~services/*': ['./src/services/*'], '~utils/*': ['./src/utils/*'], '~assets/*': ['./src/assets/*'] diff --git a/generators/app/tasks/gitConfig.js b/generators/app/tasks/gitConfig.js index 3a7b8555..d3f338d1 100644 --- a/generators/app/tasks/gitConfig.js +++ b/generators/app/tasks/gitConfig.js @@ -17,7 +17,7 @@ module.exports.gitInitiation = function gitInitiation() { successMessage: 'CRA README.md removed successfully', failureMessage: 'CRA README.md removing failed, no README.md found' // catching with an empty function to ignore the error - // eslint-disable-next-line no-empty-function + // eslint-disable-next-line no-empty-function, @typescript-eslint/no-empty-function }).catch(() => {}) ); }; diff --git a/generators/app/templates/.babelrc.ejs b/generators/app/templates/.babelrc.ejs index 399599d6..75498fa1 100644 --- a/generators/app/templates/.babelrc.ejs +++ b/generators/app/templates/.babelrc.ejs @@ -10,9 +10,9 @@ module.exports = { "~screens": "./src/app/screens", "~config": "./src/config", "~constants": "./src/constants", - "~redux": "./src/redux", "~services": "./src/services", - "~utils": "./src/utils" + "~utils": "./src/utils", + "~app": "./src/app" } } ]<% } %> diff --git a/generators/app/templates/.eslintrc.ejs b/generators/app/templates/.eslintrc.ejs index 9337eb60..b018f745 100644 --- a/generators/app/templates/.eslintrc.ejs +++ b/generators/app/templates/.eslintrc.ejs @@ -15,9 +15,9 @@ module.exports = { '~screens': './src/app/screens', '~config': './src/config', '~constants': './src/constants', - '~redux': './src/redux', '~services': './src/services', - '~utils': './src/utils' + '~utils': './src/utils', + "~app": './src/app' } } }<%} %> diff --git a/generators/app/templates/docs/Field.md b/generators/app/templates/docs/Field.md deleted file mode 100644 index 77e2c934..00000000 --- a/generators/app/templates/docs/Field.md +++ /dev/null @@ -1,34 +0,0 @@ -## Field - -**Props** - -| Property | Type | Required? | -|:---|:---|:---:| -| input | Object | ✓ | - -The component passes every other prop to the wrapped component. - -**input shape** - -| Property | Type | Required? | -|:---|:---|:---:| -| name | String | | -| value | String | | -| onBlur | Func | | -| onChange | Func | | -| onDragStart | Func | | -| onDrop | Func | | -| onFocus | Func | | - -**Usage** - -```jsx -input = wrapField(Input); - - -``` diff --git a/generators/app/templates/docs/SearchBar.md b/generators/app/templates/docs/SearchBar.md index 4158d8fd..9645fe4f 100644 --- a/generators/app/templates/docs/SearchBar.md +++ b/generators/app/templates/docs/SearchBar.md @@ -24,35 +24,4 @@ -``` - -If you decided to use redux-form you must add it to the component and use it in this way. - -```jsx - -
- - - -
- ``` - -If you decided to use redux-form you must add it to the component and use it in this way. - -```jsx -textArea = wrapField(TextArea); - - -``` diff --git a/generators/app/templates/jsconfig.json b/generators/app/templates/jsconfig.json index 7278d410..e63a6d89 100644 --- a/generators/app/templates/jsconfig.json +++ b/generators/app/templates/jsconfig.json @@ -11,7 +11,6 @@ "~screens/*": ["./src/app/screens/*"], "~config/*": ["./src/config/*"], "~constants/*": ["./src/constants/*"], - "~redux/*": ["./src/redux/*"], "~services/*": ["./src/services/*"], "~utils/*": ["./src/utils/*"], "~assets/*": ["./src/assets/*"] diff --git a/generators/app/templates/src/app/components/Field/index.js b/generators/app/templates/src/app/components/Field/index.js deleted file mode 100644 index eaaff0be..00000000 --- a/generators/app/templates/src/app/components/Field/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -export function wrapField(WrappedComponent) { - function Field({ input, ...props }) { - return ; - } - - Field.propTypes = { - input: PropTypes.shape({ - name: PropTypes.string, - value: PropTypes.string, - onBlur: PropTypes.func, - onChange: PropTypes.func, - onDragStart: PropTypes.func, - onDrop: PropTypes.func, - onFocus: PropTypes.func - }).isRequired - }; - - return Field; -} diff --git a/generators/app/templates/src/app/components/ProviderWrapper/index.tsx b/generators/app/templates/src/app/components/ProviderWrapper/index.tsx new file mode 100644 index 00000000..f5221fed --- /dev/null +++ b/generators/app/templates/src/app/components/ProviderWrapper/index.tsx @@ -0,0 +1,24 @@ +import React, { useReducer } from 'react'; + +interface Props { + Context: React.Context; + reducer: React.Reducer; + initialState: any; +} + +const withProvider = ({ Context, reducer, initialState }: Props) => ( + WrappedComponent: React.ComponentType +) => { + function ProviderWrapper(props: T) { + const [state, dispatch] = useReducer(reducer, initialState); + return ( + + + + ); + } + + return ProviderWrapper; +}; + +export default withProvider; diff --git a/generators/app/templates/src/app/components/Routes/components/AuthenticatedRoute.tsx b/generators/app/templates/src/app/components/Routes/components/AuthenticatedRoute.tsx deleted file mode 100644 index f62ab2d5..00000000 --- a/generators/app/templates/src/app/components/Routes/components/AuthenticatedRoute.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import React from 'react'; -import { Redirect, Route, RouteComponentProps } from 'react-router-dom'; -import { RouteProps } from 'react-router'; - -import Routes from '~constants/routes'; - -const DEFAULT_PUBLIC_ROUTE = Routes.LOGIN; -const DEFAULT_PRIVATE_ROUTE = Routes.HOME; - -interface Props extends RouteProps { - component: React.ComponentType> | React.ComponentType; - isPublicRoute?: boolean; - isPrivateRoute?: boolean; - currentUser: boolean; -} - -function AuthenticatedRoute({ - /* - * TODO Add this if you need it - * device, - */ - isPublicRoute, - isPrivateRoute, - // initialized, - currentUser, - component: Comp, - ...props -}: Props) { - return ( - { - /* - * TODO Add this if you need it - * if (device.isMobile && !device.adviceSubmitted) { - * return ; - * } - */ - if (currentUser) { - if (isPublicRoute) { - /* - * TODO Add this if you need it - * if (currentUser && isPublicRoute) { - * do not allow logged users to access public routes. redirect to app - */ - return ( - - ); - } - } else if (isPrivateRoute) { - // Do not allow unlogged users to access app. redirect to signin - return ( - - ); - } - - return ; - }} - /> - ); -} - -AuthenticatedRoute.defaultProps = { - /* - * TODO Add this if you need it - * isPublicRoute: true, - */ - currentUser: false -}; - -export default AuthenticatedRoute; diff --git a/generators/app/templates/src/app/components/Routes/components/RouteItem.tsx b/generators/app/templates/src/app/components/Routes/components/RouteItem.tsx new file mode 100644 index 00000000..e4800dbc --- /dev/null +++ b/generators/app/templates/src/app/components/Routes/components/RouteItem.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Route, Redirect, RouteComponentProps, RouteProps } from 'react-router-dom'; + +interface Props extends RouteProps { + component: React.ComponentType> | React.ComponentType; + redirectTo?: string; +} + +function RouteItem({ redirectTo, ...config }: Props) { + return redirectTo ? : ; +} + +export default RouteItem; diff --git a/generators/app/templates/src/app/components/Routes/constants.ts b/generators/app/templates/src/app/components/Routes/constants.ts new file mode 100644 index 00000000..7f2869f5 --- /dev/null +++ b/generators/app/templates/src/app/components/Routes/constants.ts @@ -0,0 +1,32 @@ +import { lazy } from 'react'; +import i18next from 'i18next'; + +import { Nullable } from '~utils/types'; +import { User } from '~app/reducer'; + +import PATHS from './paths'; + +const Home = lazy(() => import('../../screens/Dashboard')); +const Login = lazy(() => import('../../screens/Login')); + +const MAIN_PUBLIC_PATH = PATHS.login; +const MAIN_PRIVATE_PATH = PATHS.home; + +export const ROUTES = [ + { + exact: false, + path: PATHS.login, + component: Login, + title: i18next.t('Routes:loginTitle'), + description: i18next.t('Routes:loginDescription'), + redirectTo: (user: Nullable) => (user ? MAIN_PRIVATE_PATH : undefined) + }, + { + exact: false, + path: PATHS.home, + component: Home, + title: i18next.t('Routes:homeTitle'), + description: i18next.t('Routes:homeDescription'), + redirectTo: (user: Nullable) => (user ? undefined : MAIN_PUBLIC_PATH) + } +]; diff --git a/generators/app/templates/src/app/components/Routes/i18n.ts b/generators/app/templates/src/app/components/Routes/i18n.ts new file mode 100644 index 00000000..4160d421 --- /dev/null +++ b/generators/app/templates/src/app/components/Routes/i18n.ts @@ -0,0 +1,9 @@ +import i18next from 'i18next'; + +// TODO: change to improve SEO +i18next.addResources('es', 'Routes', { + homeTitle: 'Nombre de la app', + homeDescription: '', + loginTitle: 'Iniciar sesión', + loginDescription: '' +}); diff --git a/generators/app/templates/src/app/components/Routes/index.ejs b/generators/app/templates/src/app/components/Routes/index.ejs deleted file mode 100644 index 2952b0ea..00000000 --- a/generators/app/templates/src/app/components/Routes/index.ejs +++ /dev/null @@ -1,30 +0,0 @@ -import React, { lazy } from 'react'; -import { ConnectedRouter } from 'connected-react-router'; -import { Switch } from 'react-router-dom'; - -import { history } from '../../../redux/store'; -import Suspense from '../Suspense'; -import Routes from '../../../constants/routes'; - -import AuthenticatedRoute from './components/AuthenticatedRoute'; -import styles from './styles.module.scss'; - -const Home = lazy(() => import('../../screens/Dashboard')); -const Login = lazy(() => import('../../screens/Login')); -<%# TODO: Handle ConnectedRouter connection according redux feature %> -function AppRoutes() { - return ( - -
- - - - - - -
-
- ); -} - -export default AppRoutes; diff --git a/generators/app/templates/src/app/components/Routes/index.tsx b/generators/app/templates/src/app/components/Routes/index.tsx new file mode 100644 index 00000000..81d5797b --- /dev/null +++ b/generators/app/templates/src/app/components/Routes/index.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { BrowserRouter as Router, Switch } from 'react-router-dom'; + +import { useSelector } from '~app/context'; + +import Suspense from '../Suspense'; + +import { ROUTES } from './constants'; +import RouteItem from './components/RouteItem'; +import styles from './styles.module.scss'; + +function AppRoutes() { + const user = useSelector(state => state.user); + + return ( + +
+ + + {ROUTES.map(({ redirectTo, path, ...config }) => ( + + ))} + + +
+
+ ); +} + +export default AppRoutes; diff --git a/generators/app/templates/src/app/components/Routes/paths.ts b/generators/app/templates/src/app/components/Routes/paths.ts new file mode 100644 index 00000000..9fbb8cb4 --- /dev/null +++ b/generators/app/templates/src/app/components/Routes/paths.ts @@ -0,0 +1,5 @@ +export default { + home: '/', + login: '/login', + recoverPassword: '/recover_password' +}; diff --git a/generators/app/templates/src/app/context.ts b/generators/app/templates/src/app/context.ts new file mode 100644 index 00000000..e449641e --- /dev/null +++ b/generators/app/templates/src/app/context.ts @@ -0,0 +1,5 @@ +import { contextFactory } from '~config/context'; + +import { GlobalState, Action, INITIAL_STATE } from './reducer'; + +export const { useSelector, Context, useDispatch } = contextFactory(INITIAL_STATE); diff --git a/generators/app/templates/src/app/index.ejs b/generators/app/templates/src/app/index.ejs deleted file mode 100644 index 71944c8c..00000000 --- a/generators/app/templates/src/app/index.ejs +++ /dev/null @@ -1,24 +0,0 @@ -import React, { Component } from 'react'; -import { Provider } from 'react-redux'; - -import { apiSetup } from '../config/api'; -import store from '../redux/store'; - -import Routes from './components/Routes'; -import '../scss/application.scss'; - -class App extends Component { - componentDidMount() { - apiSetup(store.dispatch); - } -<%# TODO: Handle redux connection according redux feature %> - render() { - return ( - - - - ); - } -} - -export default App; diff --git a/generators/app/templates/src/app/index.tsx b/generators/app/templates/src/app/index.tsx new file mode 100644 index 00000000..79936cad --- /dev/null +++ b/generators/app/templates/src/app/index.tsx @@ -0,0 +1,19 @@ +import React, { useReducer } from 'react'; + +import '../scss/application.scss'; + +import Routes from './components/Routes'; +import { globalReducer, INITIAL_STATE } from './reducer'; +import { Context } from './context'; + +function App() { + const [state, dispatch] = useReducer(globalReducer, INITIAL_STATE); + + return ( + + + + ); +} + +export default App; diff --git a/generators/app/templates/src/app/reducer.ts b/generators/app/templates/src/app/reducer.ts new file mode 100644 index 00000000..ae4ace67 --- /dev/null +++ b/generators/app/templates/src/app/reducer.ts @@ -0,0 +1,48 @@ +import { Nullable } from '~utils/types'; + +export interface User { + id: number; +} + +export interface GlobalState { + user: Nullable; +} + +export const INITIAL_STATE = { + user: null +}; + +enum ActionTypes { + SET_USER = 'SET_USER', + RESET_USER = 'RESET_USER' +} + +export interface SetUser { + type: ActionTypes.SET_USER; + payload: User; +} + +export interface ResetUser { + type: ActionTypes.RESET_USER; +} + +export type Action = SetUser | ResetUser; + +export const actionCreators = { + setUser: (user: User) => ({ type: ActionTypes.SET_USER, payload: user }), + resetUser: () => ({ type: ActionTypes.RESET_USER }) +}; + +export const globalReducer = (state: GlobalState, action: Action): GlobalState => { + switch (action.type) { + case 'SET_USER': { + return { ...state, user: action.payload }; + } + case 'RESET_USER': { + return { ...state, user: null }; + } + default: { + return state; + } + } +}; diff --git a/generators/app/templates/src/app/screens/Dashboard/index.js b/generators/app/templates/src/app/screens/Dashboard/index.js index caca02c2..5f67a888 100644 --- a/generators/app/templates/src/app/screens/Dashboard/index.js +++ b/generators/app/templates/src/app/screens/Dashboard/index.js @@ -1,15 +1,15 @@ import React from 'react'; -import { Route, Switch, Redirect } from 'react-router-dom'; +import { Switch } from 'react-router-dom'; -import Routes from '../../../constants/routes'; +import RouteItem from '~components/Routes/components/RouteItem'; +import PATHS from '~components/Routes/paths'; import Home from './screens/Home'; function Dashboard() { return ( - - } /> + ); } diff --git a/generators/app/templates/src/app/screens/Dashboard/screens/Home/context.ts b/generators/app/templates/src/app/screens/Dashboard/screens/Home/context.ts new file mode 100644 index 00000000..2fe7c621 --- /dev/null +++ b/generators/app/templates/src/app/screens/Dashboard/screens/Home/context.ts @@ -0,0 +1,5 @@ +import { contextFactory } from '~config/context'; + +import { HomeState, Action, INITIAL_STATE } from './reducer'; + +export const { useSelector, Context, useDispatch } = contextFactory(INITIAL_STATE); diff --git a/generators/app/templates/src/app/screens/Dashboard/screens/Home/index.js b/generators/app/templates/src/app/screens/Dashboard/screens/Home/index.js index 25090e1c..9bd23a98 100644 --- a/generators/app/templates/src/app/screens/Dashboard/screens/Home/index.js +++ b/generators/app/templates/src/app/screens/Dashboard/screens/Home/index.js @@ -1,9 +1,20 @@ -import React from 'react'; +import React, { useEffect } from 'react'; + +import withProvider from '~components/ProviderWrapper'; import logo from './assets/logo.svg'; import styles from './styles.module.scss'; +import { useSelector, Context, useDispatch } from './context'; +import { reducer, INITIAL_STATE, actionCreators } from './reducer'; function Home() { + const foo = useSelector(state => state.foo); + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(actionCreators.setFoo('React')); + }, [dispatch]); + return (
@@ -12,11 +23,11 @@ function Home() { Edit src/app/index.js and save to reload.

- Learn React + Learn {foo}
); } -export default Home; +export default withProvider({ Context, reducer, initialState: INITIAL_STATE })(Home); diff --git a/generators/app/templates/src/app/screens/Dashboard/screens/Home/reducer.ts b/generators/app/templates/src/app/screens/Dashboard/screens/Home/reducer.ts new file mode 100644 index 00000000..72f6259f --- /dev/null +++ b/generators/app/templates/src/app/screens/Dashboard/screens/Home/reducer.ts @@ -0,0 +1,42 @@ +export interface HomeState { + foo: string; +} + +export const INITIAL_STATE = { + foo: '' +}; + +enum ActionTypes { + SET_FOO = 'SET_FOO', + RESET_FOO = 'RESET_FOO' +} + +export interface SetFoo { + type: ActionTypes.SET_FOO; + payload: string; +} + +export interface ResetFoo { + type: ActionTypes.RESET_FOO; +} + +export type Action = SetFoo | ResetFoo; + +export const actionCreators = { + setFoo: (foo: string) => ({ type: ActionTypes.SET_FOO, payload: foo }), + resetFoo: () => ({ type: ActionTypes.RESET_FOO }) +}; + +export const reducer = (state: HomeState, action: Action): HomeState => { + switch (action.type) { + case ActionTypes.SET_FOO: { + return { ...state, foo: action.payload }; + } + case ActionTypes.RESET_FOO: { + return { ...state, foo: '' }; + } + default: { + return state; + } + } +}; diff --git a/generators/app/templates/src/app/screens/Login/index.test.js b/generators/app/templates/src/app/screens/Login/index.test.js new file mode 100644 index 00000000..0e296b1d --- /dev/null +++ b/generators/app/templates/src/app/screens/Login/index.test.js @@ -0,0 +1,23 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import renderer from 'react-test-renderer'; + +import Login from './index'; + +describe('#Login', () => { + let component = null; + + beforeEach(() => { + component = mount(); + }); + + afterEach(() => { + component.unmount(); + }); + + describe('when mounting the application', () => { + it('matches last snapshot', () => { + expect(renderer.create(component).toJSON()).toMatchSnapshot(); + }); + }); +}); diff --git a/generators/app/templates/src/app/screens/Login/index.tsx b/generators/app/templates/src/app/screens/Login/index.tsx index aca5a2b5..d40e338d 100644 --- a/generators/app/templates/src/app/screens/Login/index.tsx +++ b/generators/app/templates/src/app/screens/Login/index.tsx @@ -1,29 +1,37 @@ -import React, { Component } from 'react'; +import React, { useCallback } from 'react'; +import { useHistory } from 'react-router-dom'; + +import { useDispatch } from '~app/context'; +import { actionCreators } from '~app/reducer'; import Login from './layout'; -class LoginContainer extends Component { - handleLogin = () => { - // TODO implement function - }; +function LoginContainer() { + const history = useHistory(); + const dispatch = useDispatch(); - handleEmailChange = () => { + const handleLogin = useCallback( + (event: React.FormEvent) => { + event.preventDefault(); + // TODO: request + const user = { id: 1, name: 'Mocked User' }; + dispatch(actionCreators.setUser(user)); + history.push('/'); + }, + [dispatch, history] + ); + + const handleEmailChange = useCallback(() => { // TODO implement function - }; + }, []); - handlePasswordChange = () => { + const handlePasswordChange = useCallback(() => { // TODO implement function - }; - - render() { - return ( - - ); - } + }, []); + + return ( + + ); } export default LoginContainer; diff --git a/generators/app/templates/src/app/screens/Login/layout.tsx b/generators/app/templates/src/app/screens/Login/layout.tsx index 2e62d3ec..242d9f1d 100644 --- a/generators/app/templates/src/app/screens/Login/layout.tsx +++ b/generators/app/templates/src/app/screens/Login/layout.tsx @@ -2,7 +2,7 @@ import React from 'react'; import i18next from 'i18next'; import InputLabel from '~components/InputLabel'; -import Routes from '~constants/routes'; +import PATHS from '~components/Routes/paths'; import { FIELDS } from './constants'; import styles from './styles.module.scss'; @@ -46,7 +46,7 @@ function Login({ onEmailChange, onPasswordChange, onLogin }: Props) { - {i18next.t('Login:forgotPassword')} + {i18next.t('Login:forgotPassword')}
); diff --git a/generators/app/templates/src/config/api.js b/generators/app/templates/src/config/api.js index 40360f21..938e7916 100644 --- a/generators/app/templates/src/config/api.js +++ b/generators/app/templates/src/config/api.js @@ -19,7 +19,7 @@ const api = create({ timeout: 15000 }); -// eslint-disable-next-line no-unused-vars, prettier/prettier +// eslint-disable-next-line no-unused-vars, prettier/prettier, @typescript-eslint/no-unused-vars export const apiSetup = dispatch => { api.addMonitor(response => { if (response.status === STATUS_CODES.unauthorized) { diff --git a/generators/app/templates/src/config/context.ts b/generators/app/templates/src/config/context.ts new file mode 100644 index 00000000..2913b5d2 --- /dev/null +++ b/generators/app/templates/src/config/context.ts @@ -0,0 +1,26 @@ +import { createContext, useContext, Dispatch } from 'react'; + +export const contextFactory = (initialState: State) => { + interface Store { + state: State; + dispatch: Dispatch; + } + + const Context = createContext({ + state: { ...initialState }, + // eslint-disable-next-line @typescript-eslint/no-empty-function, no-empty-function + dispatch: () => {} + }); + + const useSelector = (selector: (arg: State) => any) => { + const { state } = useContext(Context); + return selector(state); + }; + + const useDispatch = () => { + const { dispatch } = useContext(Context); + return dispatch; + }; + + return { useSelector, Context, useDispatch }; +}; diff --git a/generators/app/templates/src/redux/Auth/actions.js b/generators/app/templates/src/redux/Auth/actions.js deleted file mode 100644 index ddceb819..00000000 --- a/generators/app/templates/src/redux/Auth/actions.js +++ /dev/null @@ -1,60 +0,0 @@ -import { push } from 'connected-react-router'; - -import * as AuthService from '../../services/AuthServices'; -import Routes from '../../constants/routes'; -import { stringArrayToObject } from '../../utils/array'; - -/* ------------- Auth actions ------------- */ -export const actions = stringArrayToObject( - ['LOGIN', 'LOGIN_SUCCESS', 'LOGIN_FAILURE', 'LOGOUT', 'AUTH_INIT'], - '@@AUTH' -); - -const privateActionCreators = { - loginSuccess(authData) { - return { - type: actions.LOGIN_SUCCESS, - payload: { authData } - }; - }, - loginFailure(err) { - return { - type: actions.LOGIN_FAILURE, - payload: { err } - }; - } -}; - -export const actionCreators = { - init(user) { - return { - type: actions.AUTH_INIT, - payload: { user } - }; - }, - login(authData) { - return async dispatch => { - dispatch({ type: actions.LOGIN }); - try { - const response = await AuthService.login(authData); - - if (response.ok) { - await AuthService.setCurrentUser(response.data); - dispatch(privateActionCreators.loginSuccess(response.data)); - dispatch(push(Routes.HOME)); - } else { - throw new Error('Invalid credentials'); - } - } catch (e) { - dispatch(privateActionCreators.loginFailure(e)); - } - }; - }, - logout() { - return async dispatch => { - await AuthService.removeCurrentUser(); - dispatch({ type: actions.LOGOUT }); - dispatch(push(Routes.LOGIN)); - }; - } -}; diff --git a/generators/app/templates/src/redux/Auth/reducer.js b/generators/app/templates/src/redux/Auth/reducer.js deleted file mode 100644 index 3055faae..00000000 --- a/generators/app/templates/src/redux/Auth/reducer.js +++ /dev/null @@ -1,58 +0,0 @@ -import PropTypes from 'prop-types'; -import Immutable from 'seamless-immutable'; - -import { actions } from './actions'; - -/* ------------- Auth reducer ------------- */ -const defaultState = { - currentUser: null, - loading: false, - initialLoading: true -}; - -/* eslint-disable complexity */ -// eslint-disable-next-line new-cap -export function reducer(state = Immutable(defaultState), action) { - switch (action.type) { - case actions.AUTH_INIT: { - return state.merge({ - initialLoading: false, - currentUser: action.payload.user - }); - } - case actions.LOGIN: { - return state.merge({ loading: true }); - } - case actions.LOGIN_SUCCESS: { - return state.merge({ - loading: false, - currentUser: action.payload.authData - }); - } - case actions.LOGIN_FAILURE: { - return state.merge({ - loading: false, - currentUser: null, - err: action.payload.err - }); - } - case actions.LOGOUT: { - return state.merge({ loading: false, currentUser: null }); - } - default: { - return state; - } - } -} -/* eslint-enable complexity */ - -/* ------------- Auth propTypes ------------- */ -export const propTypes = { - loading: PropTypes.bool.isRequired, - initialLoading: PropTypes.bool.isRequired, - currentUser: PropTypes.shape({ - email: PropTypes.string.isRequired, - id: PropTypes.number.isRequired - // TODO: Extend user model definition - }) -}; diff --git a/generators/app/templates/src/redux/store.js b/generators/app/templates/src/redux/store.js deleted file mode 100644 index b7c2ade6..00000000 --- a/generators/app/templates/src/redux/store.js +++ /dev/null @@ -1,46 +0,0 @@ -import { connectRouter, routerMiddleware } from 'connected-react-router'; -import { createBrowserHistory } from 'history'; -import { applyMiddleware, combineReducers, compose, createStore } from 'redux'; -import { reducer as form } from 'redux-form'; -import thunk from 'redux-thunk'; - -/* - * TODO Add this if you need it - * import AnalyticsMiddleware from '../services/AnalyticsService'; - */ -import { reducer as auth } from './Auth/reducer'; - -export const history = createBrowserHistory(); - -// Add reducers here -const reducers = combineReducers({ - auth, - form, - router: connectRouter(history) -}); - -const middlewares = [thunk, routerMiddleware(history)]; -const enhancers = []; - -// TODO Add this if you need it. -/* ------------- Analytics Middleware ------------- */ -// Middlewares.push(AnalyticsMiddleware); - -/* ------------- Assemble Middleware ------------- */ -enhancers.push(applyMiddleware(...middlewares)); - -// eslint-disable-next-line no-underscore-dangle -const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; - -const rootReducer = (state, action) => - /* - * TODO Add this if you need it - * if (action.type === authActions.SIGN_OUT) { - * return reducers(getGlobalState(state), action); - * } - */ - reducers(state, action); - -const store = createStore(rootReducer, composeEnhancers(...enhancers)); - -export default store; diff --git a/generators/app/templates/src/services/AnalyticsService.js b/generators/app/templates/src/services/AnalyticsService.js deleted file mode 100644 index e7fb3ae5..00000000 --- a/generators/app/templates/src/services/AnalyticsService.js +++ /dev/null @@ -1,13 +0,0 @@ -import { createMiddleware as createAnalyticsMiddleware } from 'redux-beacon'; -import { GoogleAnalytics } from '@redux-beacon/google-analytics'; - -const pageView = action => ({ - hitType: 'pageview', - page: action.payload.pathname === '/' ? 'accountstatus' : action.payload.pathname -}); - -const eventsMap = { - '@@router/LOCATION_CHANGE': pageView -}; - -export default createAnalyticsMiddleware(eventsMap, GoogleAnalytics); diff --git a/generators/app/templates/src/services/utils.ts b/generators/app/templates/src/services/utils.ts new file mode 100644 index 00000000..ce7c8938 --- /dev/null +++ b/generators/app/templates/src/services/utils.ts @@ -0,0 +1,110 @@ +import { useState, useEffect, useCallback, useRef } from 'react'; +import { ApiErrorResponse, ApiOkResponse, PROBLEM_CODE, ApiResponse } from 'apisauce'; + +type Error = (error?: { problem: PROBLEM_CODE; errorData?: E }) => void; +type Request = (params: P) => Promise>; +type Success = (data?: D) => void; +type Failure = (error: { problem: PROBLEM_CODE; errorData?: E }) => void; +type PostFetch = (response: ApiOkResponse | ApiErrorResponse) => void; + +interface AsyncRequestHookParams { + request: Request; + payload: P; + withPostSuccess?: Success; + withPostFailure?: Failure; + initialState?: D | null; + withPostFetch?: PostFetch; + shouldExecuteFetch?: boolean; + transformResponse?: (response: D | E) => any; +} + +interface AsyncRequest { + values: P; + request: Request; + onPrefetch: () => void; + onSuccess: Success; + onError: Failure; + onPostFetch: PostFetch; +} + +const executeAsyncRequest = async ({ + values, + request, + onPrefetch, + onSuccess, + onError, + onPostFetch +}: AsyncRequest) => { + onPrefetch(); + const response = await request(values); + if (response.ok) { + onSuccess(response.data); + } else { + onError({ problem: response.problem, errorData: response.data }); + } + onPostFetch(response); +}; + +export const useAsyncRequest = ( + { + request, + payload, + withPostSuccess, + withPostFailure, + initialState = null, + withPostFetch, + shouldExecuteFetch = true, + transformResponse = response => response + }: AsyncRequestHookParams, + dependencies: [] +) => { + const [state, setState] = useState(initialState); + const [loading, setLoading] = useState(shouldExecuteFetch || false); + const [error, setError] = useState | null>(null); + const activeRequest = useRef(0); + const sendRequest = useCallback( + values => { + activeRequest.current = activeRequest.current + 1; + const requestId = activeRequest.current; + executeAsyncRequest({ + values, + request, + onPrefetch: () => { + setLoading(true); + setState(initialState); + }, + onSuccess: data => { + if (activeRequest.current === requestId) { + const transformedResponse = data ? transformResponse(data) : undefined; + setState(transformedResponse); + withPostSuccess?.(transformedResponse); + } + }, + onError: errorInfo => { + setError(() => errorInfo); + withPostFailure?.(errorInfo); + }, + onPostFetch: response => { + setLoading(false); + if (response.data) { + withPostFetch?.(transformResponse(response.data)); + } + } + }); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [initialState, request, withPostFailure, withPostSuccess, ...dependencies] + ); + + useEffect( + () => { + if (shouldExecuteFetch) { + sendRequest(payload); + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + dependencies + ); + + return [state, loading, error]; +}; diff --git a/generators/app/templates/src/utils/types.ts b/generators/app/templates/src/utils/types.ts new file mode 100644 index 00000000..aa32b2de --- /dev/null +++ b/generators/app/templates/src/utils/types.ts @@ -0,0 +1 @@ +export type Nullable = T | null; diff --git a/generators/app/templates/tsconfig.paths.json b/generators/app/templates/tsconfig.paths.json index 1f5500f6..f286e877 100644 --- a/generators/app/templates/tsconfig.paths.json +++ b/generators/app/templates/tsconfig.paths.json @@ -2,15 +2,15 @@ "compilerOptions": { "baseUrl": "src", "paths": { - "~redux/*": ["redux/*"], "~scss/*": ["scss/*"], "~constants/*": ["constants/*"], "~utils/*": ["utils/*"], "~services/*": ["services/*"], "~components/*": ["app/components/*"], "~screens/*": ["app/screens/*"], - "~config/*": ["app/config/*"], - "~schema/*": ["schema/*"] + "~config/*": ["config/*"], + "~schema/*": ["schema/*"], + "~app/*": ["app/*"] } } } diff --git a/package-lock.json b/package-lock.json index 12b49da5..e670a2a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "generator-react-bootstrap", - "version": "2.2.1", + "version": "3.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -950,7 +950,6 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.0.tgz", "integrity": "sha512-89eSBLJsxNxOERC0Op4vd+0Bqm6wRMqMbFtV3i0/fbaWw/mJ8Q3eBvgX0G4SyrOOLCtbu98HspF8o09MRT+KzQ==", - "dev": true, "requires": { "regenerator-runtime": "^0.13.2" }, @@ -958,8 +957,7 @@ "regenerator-runtime": { "version": "0.13.3", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", - "dev": true + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" } } }, @@ -1569,6 +1567,12 @@ "loader-utils": "^1.2.3" } }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", @@ -1584,6 +1588,18 @@ "@types/node": "*" } }, + "@types/history": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.5.tgz", + "integrity": "sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -1599,12 +1615,151 @@ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==" }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true + }, "@types/q": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", "dev": true }, + "@types/react": { + "version": "16.9.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.23.tgz", + "integrity": "sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" + } + }, + "@types/react-router": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.4.tgz", + "integrity": "sha512-PZtnBuyfL07sqCJvGg3z+0+kt6fobc/xmle08jBiezLS8FrmGeiGkJnuxL/8Zgy9L83ypUhniV5atZn/L8n9MQ==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*" + } + }, + "@types/react-router-dom": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.3.tgz", + "integrity": "sha512-pCq7AkOvjE65jkGS5fQwQhvUp4+4PVD9g39gXLZViP2UqFiFzsEpB3PKf0O6mdbKsewSK8N14/eegisa/0CwnA==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.22.0.tgz", + "integrity": "sha512-BvxRLaTDVQ3N+Qq8BivLiE9akQLAOUfxNHIEhedOcg8B2+jY8Rc4/D+iVprvuMX1AdezFYautuGDwr9QxqSxBQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.22.0", + "eslint-utils": "^1.4.3", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.22.0.tgz", + "integrity": "sha512-sJt1GYBe6yC0dWOQzXlp+tiuGglNhJC9eXZeC8GBVH98Zv9jtatccuhz0OF5kC/DwChqsNfghHx7OlIDQjNYAQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.22.0", + "eslint-scope": "^5.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.22.0.tgz", + "integrity": "sha512-FaZKC1X+nvD7qMPqKFUYHz3H0TAioSVFGvG29f796Nc5tBluoqfHgLbSFKsh7mKjRoeTm8J9WX2Wo9EyZWjG7w==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.22.0", + "@typescript-eslint/typescript-estree": "2.22.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.22.0.tgz", + "integrity": "sha512-2HFZW2FQc4MhIBB8WhDm9lVFaBDy6h9jGrJ4V2Uzxe/ON29HCHBTj3GkgcsgMWfsl2U5as+pTOr30Nibaw7qRQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -4155,6 +4310,12 @@ } } }, + "csstype": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz", + "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==", + "dev": true + }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -4811,6 +4972,12 @@ "integrity": "sha512-dWxgiXC828o1lxJM7O54z3V4ZWoIw3T2NyFDsTH/GUbBPJu3/ZjnENUrcenVuRWZXR9jaNABmewVLp54Xf+d6g==", "dev": true }, + "eslint-config-wolox-typescript": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-wolox-typescript/-/eslint-config-wolox-typescript-1.0.1.tgz", + "integrity": "sha512-+fjbI14Q+4VskyUAyO/yQuu3PAK5WegPaDNOl7+59Bm2EkoG9x3uBtOJ4O0Qsdl4rn1HoAAfSkliuF2HxYJ5MQ==", + "dev": true + }, "eslint-import-resolver-node": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", @@ -6752,6 +6919,11 @@ "lodash": "^4.17.2" } }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, "gzip-size": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", @@ -6868,6 +7040,19 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -7205,6 +7390,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -7840,9 +8031,9 @@ } }, "loglevel": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz", - "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.7.tgz", + "integrity": "sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A==", "dev": true }, "loglevel-colored-level-prefix": { @@ -8221,6 +8412,16 @@ "dom-walk": "^0.1.0" } }, + "mini-create-react-context": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz", + "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", + "requires": { + "@babel/runtime": "^7.4.0", + "gud": "^1.0.0", + "tiny-warning": "^1.0.2" + } + }, "mini-css-extract-plugin": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.5.tgz", @@ -9341,9 +9542,9 @@ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "dev": true }, "prettier-eslint": { @@ -9551,12 +9752,6 @@ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, "inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", @@ -10226,6 +10421,60 @@ "warning": "^4.0.3" } }, + "react-router": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.1.2.tgz", + "integrity": "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.3.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.1.2.tgz", + "integrity": "sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.1.2", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, "react-split-pane": { "version": "0.1.87", "resolved": "https://registry.npmjs.org/react-split-pane/-/react-split-pane-0.1.87.tgz", @@ -10646,6 +10895,11 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -11757,6 +12011,16 @@ "setimmediate": "^1.0.4" } }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -11832,6 +12096,15 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -12182,6 +12455,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -12294,7 +12572,7 @@ }, "acorn-jsx": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { @@ -12303,7 +12581,7 @@ "dependencies": { "acorn": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", "dev": true } diff --git a/package.json b/package.json index acaab417..4535250b 100644 --- a/package.json +++ b/package.json @@ -39,17 +39,23 @@ "ora": "^3.4.0", "react": "^16.7.0", "react-dom": "^16.7.0", + "react-router-dom": "^5.1.2", "yeoman-generator": "^4.0.1" }, "devDependencies": { "@babel/core": "^7.5.5", "@storybook/addon-actions": "^4.1.4", "@storybook/react": "^4.1.6", + "@types/react": "^16.9.23", + "@types/react-router-dom": "^5.1.3", + "@typescript-eslint/eslint-plugin": "^2.22.0", + "@typescript-eslint/parser": "^2.22.0", "babel-eslint": "^10.0.1", "babel-loader": "^8.0.5", "eslint": "5.16.0", "eslint-config-wolox": "3.0.2", "eslint-config-wolox-react": "2.0.0", + "eslint-config-wolox-typescript": "^1.0.1", "eslint-plugin-babel": "5.3.0", "eslint-plugin-import": "2.19.1", "eslint-plugin-jsx-a11y": "6.2.1", @@ -58,7 +64,7 @@ "eslint-plugin-react-hooks": "2.3.0", "eslint-plugin-react-native": "3.7.0", "husky": "^2.3.0", - "prettier": "1.18.2", - "prettier-eslint": "8.8.2" + "prettier": "^1.19.1", + "prettier-eslint": "^8.8.2" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..ea1dc74e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "isolatedModules": true, + "noEmit": true, + "jsx": "react" + }, + "include": [ + "src" + ], + "extends": "./tsconfig.paths.json" +} From 87c532edba8c7dce474c0dc6a89e1bbc82155a80 Mon Sep 17 00:00:00 2001 From: damfinkel Date: Mon, 16 Mar 2020 10:50:35 -0300 Subject: [PATCH 2/6] split request hook into two and added tests --- .eslintrc.js | 5 + generators/app/constants.js | 3 +- .../app/steps/CustomizableSteps/constants.js | 7 +- generators/app/templates/.eslintrc.ejs | 35 +- generators/app/templates/setupTests.js | 4 + .../app/components/ProviderWrapper/index.tsx | 8 +- .../components/Spinner/components/loading.tsx | 2 +- .../screens/Dashboard/screens/Home/index.js | 1 + .../src/app/screens/Login/index.test.js | 8 +- .../app/templates/src/services/utils.test.tsx | 235 +++++ .../app/templates/src/services/utils.ts | 87 +- generators/app/templates/src/utils/tests.tsx | 32 + package-lock.json | 890 +++++++++++++++++- package.json | 14 +- 14 files changed, 1228 insertions(+), 103 deletions(-) create mode 100644 generators/app/templates/src/services/utils.test.tsx create mode 100644 generators/app/templates/src/utils/tests.tsx diff --git a/.eslintrc.js b/.eslintrc.js index d0dbf73a..3ad27fc1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,5 +5,10 @@ module.exports = { 'import/no-unresolved': 'off', 'import/no-extraneous-dependencies': 'off', '@typescript-eslint/no-var-requires': 'off' + }, + settings: { + react: { + version: 'detect' + } } }; diff --git a/generators/app/constants.js b/generators/app/constants.js index 74f90136..c5eeabe8 100644 --- a/generators/app/constants.js +++ b/generators/app/constants.js @@ -94,9 +94,8 @@ module.exports.DEV_DEPENDENCIES = [ 'eslint-plugin-jsx-a11y@6.2.3', 'eslint-plugin-prettier@3.1.0', 'eslint-plugin-react@7.14.3', - 'eslint-plugin-react-native@3.7.0', 'eslint-plugin-babel@5.3.0', - 'eslint-config-wolox-react@2.0.0', + 'eslint-config-wolox-react@2.0.1', 'eslint-config-wolox@3.0.2', 'stylelint-config-wolox@1.0.7', 'stylelint-no-indistinguishable-colors@1.2.1', diff --git a/generators/app/steps/CustomizableSteps/constants.js b/generators/app/steps/CustomizableSteps/constants.js index 359747c8..b3c0ae4c 100644 --- a/generators/app/steps/CustomizableSteps/constants.js +++ b/generators/app/steps/CustomizableSteps/constants.js @@ -40,7 +40,9 @@ module.exports.FILES = [ `${COMPONENTS_PATH}/Checkbox`, `${COMPONENTS_PATH}/RadioGroup`, `${COMPONENTS_PATH}/ProviderWrapper`, - `${SERVICES_PATH}/AuthServices.js` + `${SERVICES_PATH}/AuthServices.js`, + `${SERVICES_PATH}/utils.ts`, + `${SERVICES_PATH}/utils.test.tsx` ]; module.exports.TEMPLATE_FILES = [ @@ -95,5 +97,6 @@ module.exports.DEV_DEPENDENCIES = [ '@types/react-router@^5.1.4', '@types/react-router-dom@^5.1.3', '@types/seamless-immutable@^7.1.11', - '@types/webpack-env@^1.14.1' + '@types/webpack-env@^1.14.1', + 'eslint-config-wolox-typescript' ]; diff --git a/generators/app/templates/.eslintrc.ejs b/generators/app/templates/.eslintrc.ejs index b018f745..28f473d4 100644 --- a/generators/app/templates/.eslintrc.ejs +++ b/generators/app/templates/.eslintrc.ejs @@ -1,7 +1,6 @@ module.exports = { - extends: ['wolox-react'<% if (features && features.customized) { %>, 'plugin:import/typescript'<% } %>],<% if (features && features.customized) { %> - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'],<% } %> + extends: ['wolox-react'<% if (features && features.customized) { %>, 'wolox-typescript'<% } %>],<% if (features && features.customized) { %> + parser: '@typescript-eslint/parser',<% } %> settings: { 'react': { 'version': 'detect' @@ -21,35 +20,7 @@ module.exports = { } } }<%} %> - }<% if (features && features.customized) { %>, - rules: { - 'react/jsx-filename-extension': [1, { 'extensions': ['.js', '.jsx', '.tsx'] }], - 'spaced-comment': ['error', 'always', { 'markers': ['/'] }], - '@typescript-eslint/adjacent-overload-signatures': 'error', - '@typescript-eslint/ban-types': 'error', - 'camelcase': 'off', - '@typescript-eslint/camelcase': 'error', - '@typescript-eslint/class-name-casing': 'error', - '@typescript-eslint/consistent-type-assertions': 'error', - '@typescript-eslint/member-delimiter-style': 'error', - 'no-array-constructor': 'off', - '@typescript-eslint/no-array-constructor': 'error', - 'no-empty-function': 'off', - '@typescript-eslint/no-empty-function': 'error', - '@typescript-eslint/no-empty-interface': 'error', - '@typescript-eslint/no-inferrable-types': 'error', - '@typescript-eslint/no-misused-new': 'error', - '@typescript-eslint/no-namespace': 'error', - '@typescript-eslint/no-this-alias': 'error', - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': 'error', - 'no-use-before-define': 'off', - '@typescript-eslint/no-use-before-define': 'error', - '@typescript-eslint/no-var-requires': 'error', - '@typescript-eslint/prefer-namespace-keyword': 'error', - '@typescript-eslint/triple-slash-reference': 'error', - '@typescript-eslint/type-annotation-spacing': 'error' - }<% } %><% if (features && features.jest) { %>, + }<% if (features && features.jest) { %>, env: { jest: true }<% } %> diff --git a/generators/app/templates/setupTests.js b/generators/app/templates/setupTests.js index 82edfc9e..1f705a32 100644 --- a/generators/app/templates/setupTests.js +++ b/generators/app/templates/setupTests.js @@ -2,3 +2,7 @@ import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; configure({ adapter: new Adapter() }); + +jest.mock('i18next', () => ({ + t: () => '' +})); diff --git a/generators/app/templates/src/app/components/ProviderWrapper/index.tsx b/generators/app/templates/src/app/components/ProviderWrapper/index.tsx index f5221fed..1a18efc9 100644 --- a/generators/app/templates/src/app/components/ProviderWrapper/index.tsx +++ b/generators/app/templates/src/app/components/ProviderWrapper/index.tsx @@ -1,12 +1,12 @@ import React, { useReducer } from 'react'; -interface Props { +interface Props { Context: React.Context; - reducer: React.Reducer; - initialState: any; + reducer: React.Reducer; + initialState: U; } -const withProvider = ({ Context, reducer, initialState }: Props) => ( +const withProvider = ({ Context, reducer, initialState }: Props) => ( WrappedComponent: React.ComponentType ) => { function ProviderWrapper(props: T) { diff --git a/generators/app/templates/src/app/components/Spinner/components/loading.tsx b/generators/app/templates/src/app/components/Spinner/components/loading.tsx index 349ceb5a..8ecd32bf 100644 --- a/generators/app/templates/src/app/components/Spinner/components/loading.tsx +++ b/generators/app/templates/src/app/components/Spinner/components/loading.tsx @@ -4,7 +4,7 @@ import Spinner, { SpinnerProps } from 'react-spinkit'; import { COLOR_SPINNER, SPINNER_DEFAULT } from './constants'; function Loading({ className = '', name = SPINNER_DEFAULT, color = COLOR_SPINNER, ...rest }: SpinnerProps) { - return ; + return ; } export default Loading; diff --git a/generators/app/templates/src/app/screens/Dashboard/screens/Home/index.js b/generators/app/templates/src/app/screens/Dashboard/screens/Home/index.js index 9bd23a98..e5315e2d 100644 --- a/generators/app/templates/src/app/screens/Dashboard/screens/Home/index.js +++ b/generators/app/templates/src/app/screens/Dashboard/screens/Home/index.js @@ -8,6 +8,7 @@ import { useSelector, Context, useDispatch } from './context'; import { reducer, INITIAL_STATE, actionCreators } from './reducer'; function Home() { + // Example of how to use these custom hooks const foo = useSelector(state => state.foo); const dispatch = useDispatch(); diff --git a/generators/app/templates/src/app/screens/Login/index.test.js b/generators/app/templates/src/app/screens/Login/index.test.js index 0e296b1d..bc9cb414 100644 --- a/generators/app/templates/src/app/screens/Login/index.test.js +++ b/generators/app/templates/src/app/screens/Login/index.test.js @@ -2,13 +2,19 @@ import React from 'react'; import { mount } from 'enzyme'; import renderer from 'react-test-renderer'; +import { RootComponent } from '~utils/tests'; + import Login from './index'; describe('#Login', () => { let component = null; beforeEach(() => { - component = mount(); + component = mount( + + + + ); }); afterEach(() => { diff --git a/generators/app/templates/src/services/utils.test.tsx b/generators/app/templates/src/services/utils.test.tsx new file mode 100644 index 00000000..0edf8d50 --- /dev/null +++ b/generators/app/templates/src/services/utils.test.tsx @@ -0,0 +1,235 @@ +/* eslint-disable max-nested-callbacks, @typescript-eslint/no-empty-function */ +import React, { useEffect } from 'react'; +import { mount } from 'enzyme'; +import { PROBLEM_CODE } from 'apisauce'; + +import { useRequest, useLazyRequest, Error } from '~services/utils'; +import { TestHook, testHook } from '~utils/tests'; +import { Nullable } from '~utils/types'; + +type True = true; +type False = false; + +interface FooError { + errorData: string; +} + +type HookReturnValue = [ + { + foo: string; + } | null, + boolean, + Nullable>, + (params?: any) => void +]; + +const failureResponse = { + ok: false as False, + problem: 'CLIENT_ERROR' as PROBLEM_CODE, + originalError: { config: {}, isAxiosError: false, toJSON: jest.fn(), name: '', message: '' }, + data: { errorData: 'error' }, + status: 400, + headers: {}, + config: {}, + duration: 100 +}; + +const successResponse = { + ok: true as True, + problem: null, + originalError: null, + data: { foo: 'value' }, + status: 200, + headers: {}, + config: {}, + duration: 100 +}; + +const MockService = { + fetchFoo: () => Promise.resolve(successResponse) +}; + +const LoadingMockService = { + fetchFoo: () => new Promise(() => {}) +}; + +const FailureMockService = { + fetchFoo: () => Promise.resolve(failureResponse) +}; + +let hookValues: Nullable = null; + +describe('#useRequest', () => { + beforeEach(() => { + hookValues = null; + }); + + describe('when request has failed', () => { + const component = ( + { + hookValues = useRequest({ request: FailureMockService.fetchFoo, payload: 1 }, []); + }} + /> + ); + + beforeEach(() => { + mount(component); + }); + + it('has correct error', () => { + const values = hookValues as HookReturnValue; + const [state, loading, error] = values; + expect(state).toBe(null); + expect(loading).toBe(false); + expect(error?.errorData).toBe(failureResponse.data); + }); + }); + + describe('when request returns an ok response', () => { + const component = ( + { + hookValues = useRequest({ request: MockService.fetchFoo, payload: 1 }, []); + }} + /> + ); + + beforeEach(() => { + mount(component); + }); + + it('has correct state', () => { + const values = hookValues as HookReturnValue; + const [state, loading, error] = values; + expect(state).toBe(successResponse.data); + expect(loading).toBe(false); + expect(error).toBe(null); + }); + }); + + describe('when request has failed', () => { + const component = ( + { + hookValues = useRequest({ request: FailureMockService.fetchFoo, payload: 1 }, []); + }} + /> + ); + + beforeEach(() => { + mount(component); + }); + + it('has correct error', () => { + const values = hookValues as HookReturnValue; + const [state, loading, error] = values; + expect(state).toBe(null); + expect(loading).toBe(false); + expect(error?.errorData).toBe(failureResponse.data); + }); + }); + + describe('when request is loading', () => { + const component = ( + { + hookValues = useRequest({ request: LoadingMockService.fetchFoo, payload: 1 }, []); + }} + /> + ); + + beforeEach(() => { + mount(component); + }); + + it('is loading', () => { + const values = hookValues as HookReturnValue; + const [state, loading, error] = values; + expect(state).toBe(null); + expect(loading).toBe(true); + expect(error).toBe(null); + }); + }); +}); + +describe('#useLazyRequest', () => { + describe('when request is not called', () => { + beforeEach(() => { + testHook(() => { + hookValues = useLazyRequest({ request: MockService.fetchFoo }); + }); + }); + + it('is neither loading nor has state', () => { + const values = hookValues as HookReturnValue; + const [state, loading, error] = values; + expect(state).toBe(null); + expect(loading).toBe(false); + expect(error).toBe(null); + }); + }); + + describe('when request is called and it is loading', () => { + beforeEach(() => { + testHook(() => { + hookValues = useLazyRequest({ request: LoadingMockService.fetchFoo }); + const [, , , request] = hookValues; + + useEffect(() => { + request(); + }, [request]); + }); + }); + + it('is starts loading', () => { + const values = hookValues as HookReturnValue; + const [state, loading, error] = values; + expect(state).toBe(null); + expect(loading).toBe(true); + expect(error).toBe(null); + }); + }); + + describe('when request is called and it succeeds', () => { + beforeEach(() => { + testHook(() => { + hookValues = useLazyRequest({ request: MockService.fetchFoo }); + const [, , , request] = hookValues; + + useEffect(() => { + request(); + }, [request]); + }); + }); + + it('is has the correct state', () => { + const values = hookValues as HookReturnValue; + const [state, loading, error] = values; + expect(state).toBe(successResponse.data); + expect(loading).toBe(false); + expect(error).toBe(null); + }); + }); + + describe('when request is called and it fails', () => { + beforeEach(() => { + testHook(() => { + hookValues = useLazyRequest({ request: FailureMockService.fetchFoo }); + const [, , , request] = hookValues; + + useEffect(() => { + request(); + }, [request]); + }); + }); + + it('it sets the error', () => { + const values = hookValues as HookReturnValue; + const [state, loading, error] = values; + expect(state).toBe(null); + expect(loading).toBe(false); + expect(error?.errorData).toBe(failureResponse.data); + }); + }); +}); diff --git a/generators/app/templates/src/services/utils.ts b/generators/app/templates/src/services/utils.ts index ce7c8938..35d8f601 100644 --- a/generators/app/templates/src/services/utils.ts +++ b/generators/app/templates/src/services/utils.ts @@ -1,23 +1,27 @@ -import { useState, useEffect, useCallback, useRef } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { ApiErrorResponse, ApiOkResponse, PROBLEM_CODE, ApiResponse } from 'apisauce'; -type Error = (error?: { problem: PROBLEM_CODE; errorData?: E }) => void; +import { Nullable } from '~utils/types'; + +export type Error = { problem: PROBLEM_CODE; errorData?: E }; type Request = (params: P) => Promise>; type Success = (data?: D) => void; -type Failure = (error: { problem: PROBLEM_CODE; errorData?: E }) => void; +type Failure = (error: Error) => void; type PostFetch = (response: ApiOkResponse | ApiErrorResponse) => void; interface AsyncRequestHookParams { request: Request; - payload: P; withPostSuccess?: Success; withPostFailure?: Failure; initialState?: D | null; withPostFetch?: PostFetch; - shouldExecuteFetch?: boolean; transformResponse?: (response: D | E) => any; } +interface AsyncRequestHookParamsWithPayload extends AsyncRequestHookParams { + payload: P; +} + interface AsyncRequest { values: P; request: Request; @@ -45,40 +49,33 @@ const executeAsyncRequest = async ({ onPostFetch(response); }; -export const useAsyncRequest = ( - { - request, - payload, - withPostSuccess, - withPostFailure, - initialState = null, - withPostFetch, - shouldExecuteFetch = true, - transformResponse = response => response - }: AsyncRequestHookParams, - dependencies: [] -) => { +// Returns a request to execute manually at some point, and the variables that will be updated when it does +export const useLazyRequest = ({ + request, + withPostSuccess, + withPostFailure, + initialState = null, + withPostFetch, + transformResponse = response => response +}: AsyncRequestHookParams): [Nullable, boolean, Nullable>, (params: P) => void] => { const [state, setState] = useState(initialState); - const [loading, setLoading] = useState(shouldExecuteFetch || false); - const [error, setError] = useState | null>(null); - const activeRequest = useRef(0); + const [loading, setLoading] = useState(false); + const [error, setError] = useState>>(null); + const sendRequest = useCallback( values => { - activeRequest.current = activeRequest.current + 1; - const requestId = activeRequest.current; executeAsyncRequest({ values, request, onPrefetch: () => { setLoading(true); setState(initialState); + setError(null); }, onSuccess: data => { - if (activeRequest.current === requestId) { - const transformedResponse = data ? transformResponse(data) : undefined; - setState(transformedResponse); - withPostSuccess?.(transformedResponse); - } + const transformedResponse = data ? transformResponse(data) : undefined; + setState(transformedResponse); + withPostSuccess?.(transformedResponse); }, onError: errorInfo => { setError(() => errorInfo); @@ -93,18 +90,42 @@ export const useAsyncRequest = ( }); }, // eslint-disable-next-line react-hooks/exhaustive-deps - [initialState, request, withPostFailure, withPostSuccess, ...dependencies] + [initialState, request, withPostFailure, withPostSuccess] ); + return [state, loading, error, sendRequest]; +}; + +// Executes a request each time a dependency changes and returns the values and the refetch function +// in case you want to execute it again +export const useRequest = ( + { + request, + payload, + withPostSuccess, + withPostFailure, + initialState = null, + withPostFetch, + transformResponse = response => response + }: AsyncRequestHookParamsWithPayload, + dependencies: [] +): [Nullable, boolean, Nullable>, (params: P) => void] => { + const [state, loading, error, sendRequest] = useLazyRequest({ + request, + withPostSuccess, + withPostFailure, + initialState, + withPostFetch, + transformResponse + }); + useEffect( () => { - if (shouldExecuteFetch) { - sendRequest(payload); - } + sendRequest(payload); }, // eslint-disable-next-line react-hooks/exhaustive-deps dependencies ); - return [state, loading, error]; + return [state, loading, error, sendRequest]; }; diff --git a/generators/app/templates/src/utils/tests.tsx b/generators/app/templates/src/utils/tests.tsx new file mode 100644 index 00000000..ad98f77e --- /dev/null +++ b/generators/app/templates/src/utils/tests.tsx @@ -0,0 +1,32 @@ +import React, { ReactNode, useReducer } from 'react'; +import { mount } from 'enzyme'; +import { Switch, BrowserRouter as Router } from 'react-router-dom'; + +import { globalReducer, INITIAL_STATE } from '~app/reducer'; +import { Context } from '~app/context'; + +type Hook = () => any; + +export const TestHook = ({ hook }: { hook: Hook }) => { + hook(); + return null; +}; + +export const testHook = (hook: Hook) => { + mount(); +}; + +interface Props { + children: ReactNode; +} + +export const RootComponent = ({ children }: Props) => { + const [state, dispatch] = useReducer(globalReducer, INITIAL_STATE); + return ( + + + {children} + + + ); +}; diff --git a/package-lock.json b/package-lock.json index e670a2a5..1778ef1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1127,6 +1127,70 @@ "integrity": "sha512-QsYGKdhhuDFNq7bjm2r44y0mp5xW3uO3csuTPDWZc0OIiMQv+AIY5Cqwd4mJiC5N8estVl7qlvOx1hbtOuUWbw==", "dev": true }, + "@jest/types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz", + "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -1567,6 +1631,31 @@ "loader-utils": "^1.2.3" } }, + "@types/cheerio": { + "version": "0.22.16", + "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.16.tgz", + "integrity": "sha512-bSbnU/D4yzFdzLpp3+rcDj0aQQMIRUBNJU7azPxdqMpnexjUSvGJyDuOBQBHeOZh1mMKgsJm6Dy+LLh80Ew4tQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/enzyme": { + "version": "3.10.5", + "resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.5.tgz", + "integrity": "sha512-R+phe509UuUYy9Tk0YlSbipRpfVtIzb/9BHn5pTEtjJTF5LXvUjrIQcZvNyANNEyFrd2YGs196PniNT1fgvOQA==", + "dev": true, + "requires": { + "@types/cheerio": "*", + "@types/react": "*" + } + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -1594,6 +1683,92 @@ "integrity": "sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw==", "dev": true }, + "@types/istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "25.1.4", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.1.4.tgz", + "integrity": "sha512-QDDY2uNAhCV7TMCITrxz+MRk1EizcsevzfeS6LykIlq2V1E5oO4wXG8V2ZEd9w7Snxeeagk46YbMgZ8ESHx3sw==", + "dev": true, + "requires": { + "jest-diff": "^25.1.0", + "pretty-format": "^25.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "pretty-format": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz", + "integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==", + "dev": true, + "requires": { + "@jest/types": "^25.1.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "react-is": { + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", + "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==", + "dev": true + } + } + }, "@types/json-schema": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", @@ -1658,6 +1833,21 @@ "@types/react-router": "*" } }, + "@types/yargs": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz", + "integrity": "sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "2.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.22.0.tgz", @@ -1712,15 +1902,73 @@ } }, "@typescript-eslint/parser": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.22.0.tgz", - "integrity": "sha512-FaZKC1X+nvD7qMPqKFUYHz3H0TAioSVFGvG29f796Nc5tBluoqfHgLbSFKsh7mKjRoeTm8J9WX2Wo9EyZWjG7w==", + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.23.0.tgz", + "integrity": "sha512-k61pn/Nepk43qa1oLMiyqApC6x5eP5ddPz6VUYXCAuXxbmRLqkPYzkFRKl42ltxzB2luvejlVncrEpflgQoSUg==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.22.0", - "@typescript-eslint/typescript-estree": "2.22.0", + "@typescript-eslint/experimental-utils": "2.23.0", + "@typescript-eslint/typescript-estree": "2.23.0", "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "@typescript-eslint/experimental-utils": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.23.0.tgz", + "integrity": "sha512-OswxY59RcXH3NNPmq+4Kis2CYZPurRU6mG5xPcn24CjFyfdVli5mySwZz/g/xDbJXgDsYqNGq7enV0IziWGXVQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.23.0", + "eslint-scope": "^5.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.23.0.tgz", + "integrity": "sha512-pmf7IlmvXdlEXvE/JWNNJpEvwBV59wtJqA8MLAxMKLXNKVRC3HZBXR/SlZLPWTCcwOSg9IM7GeRSV3SIerGVqw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "@typescript-eslint/typescript-estree": { @@ -2098,6 +2346,24 @@ } } }, + "apisauce": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/apisauce/-/apisauce-1.1.1.tgz", + "integrity": "sha512-xAXMRFyv+6yjhgDIEMozAhioE2qLdxMJxIDbjwT2obttZso27WUOpVGKYK0SD2T+IjlcpNQAklYj0IG0U7YKXQ==", + "dev": true, + "requires": { + "axios": "^0.19.0", + "ramda": "^0.25.0" + }, + "dependencies": { + "ramda": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz", + "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==", + "dev": true + } + } + }, "app-root-dir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", @@ -2371,6 +2637,15 @@ "postcss-value-parser": "^4.0.0" } }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "dev": true, + "requires": { + "follow-redirects": "1.5.10" + } + }, "axobject-query": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", @@ -3540,6 +3815,38 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, + "cheerio": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", + "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", + "dev": true, + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.1", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" + }, + "dependencies": { + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + } + } + }, "child-process-promise": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/child-process-promise/-/child-process-promise-2.2.1.tgz", @@ -4501,6 +4808,12 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, + "diff-sequences": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.1.0.tgz", + "integrity": "sha512-nFIfVk5B/NStCsJ+zaPO4vYuLjlzQ6uFvPxzYyHlejNZ/UGa7G/n7peOXVrVNvRuyfstt+mZQYGpjxg9Z6N8Kw==", + "dev": true + }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -4520,6 +4833,12 @@ "path-type": "^3.0.0" } }, + "discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", + "dev": true + }, "dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -4794,6 +5113,190 @@ "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", "dev": true }, + "enzyme": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.11.0.tgz", + "integrity": "sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==", + "dev": true, + "requires": { + "array.prototype.flat": "^1.2.3", + "cheerio": "^1.0.0-rc.3", + "enzyme-shallow-equal": "^1.0.1", + "function.prototype.name": "^1.1.2", + "has": "^1.0.3", + "html-element-map": "^1.2.0", + "is-boolean-object": "^1.0.1", + "is-callable": "^1.1.5", + "is-number-object": "^1.0.4", + "is-regex": "^1.0.5", + "is-string": "^1.0.5", + "is-subset": "^0.1.1", + "lodash.escape": "^4.0.1", + "lodash.isequal": "^4.5.0", + "object-inspect": "^1.7.0", + "object-is": "^1.0.2", + "object.assign": "^4.1.0", + "object.entries": "^1.1.1", + "object.values": "^1.1.1", + "raf": "^3.4.1", + "rst-selector-parser": "^2.2.3", + "string.prototype.trim": "^1.2.1" + }, + "dependencies": { + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "function.prototype.name": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.2.tgz", + "integrity": "sha512-C8A+LlHBJjB2AdcRPorc5JvJ5VUoWlXdEHLOJdCI7kjHEtGTpHQUiqMvCIKUwIsGwZX2jZJy761AXsn356bJQg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "functions-have-names": "^1.2.0" + } + }, + "functions-have-names": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.1.tgz", + "integrity": "sha512-j48B/ZI7VKs3sgeI2cZp7WXWmZXu7Iq5pl5/vptV5N2mq+DGFuS/ulaDjtaoLpYzuD6u8UgrUKHfgo7fDTSiBA==", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==", + "dev": true + }, + "object.entries": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + } + } + }, + "enzyme-shallow-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.1.tgz", + "integrity": "sha512-hGA3i1so8OrYOZSM9whlkNmVHOicJpsjgTzC+wn2JMJXhq1oO4kA4bJ5MsfzSIcC71aLDKzJ6gZpIxrqt3QTAQ==", + "dev": true, + "requires": { + "has": "^1.0.3", + "object-is": "^1.0.2" + }, + "dependencies": { + "object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==", + "dev": true + } + } + }, "errlop": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/errlop/-/errlop-1.1.2.tgz", @@ -4967,9 +5470,9 @@ "dev": true }, "eslint-config-wolox-react": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-wolox-react/-/eslint-config-wolox-react-2.0.0.tgz", - "integrity": "sha512-dWxgiXC828o1lxJM7O54z3V4ZWoIw3T2NyFDsTH/GUbBPJu3/ZjnENUrcenVuRWZXR9jaNABmewVLp54Xf+d6g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-wolox-react/-/eslint-config-wolox-react-2.0.1.tgz", + "integrity": "sha512-iOmvIQaofnSRjJMKXBaLJo2flMAVNbDMPLPNjWbgpiM5Fc3xWI9heM1HI73BGZhqZ/wXzRx/tn5y7fcGiw/z0A==", "dev": true }, "eslint-config-wolox-typescript": { @@ -5265,21 +5768,6 @@ "integrity": "sha512-gLKCa52G4ee7uXzdLiorca7JIQZPPXRAQDXV83J4bUEeUuc5pIEyZYAZ45Xnxe5IuupxEqHS+hUhSLIimK1EMw==", "dev": true }, - "eslint-plugin-react-native": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.7.0.tgz", - "integrity": "sha512-krLtQmGih/uJDPxF8DBpnU8J3kRUsDm/Dey5yEhOO8LN1I3Wesbk4PGCg8Zah57azKFU+9YtGooFjJcDJWUs+g==", - "dev": true, - "requires": { - "eslint-plugin-react-native-globals": "^0.1.1" - } - }, - "eslint-plugin-react-native-globals": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", - "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", - "dev": true - }, "eslint-rule-composer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", @@ -5968,6 +6456,32 @@ } } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -7084,6 +7598,23 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==" }, + "html-element-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.2.0.tgz", + "integrity": "sha512-0uXq8HsuG1v2TmQ8QkIhzbrqeskE4kn52Q18QJ9iAA/SnHoEKXWiUxHQtclRsCFWEUD2So34X+0+pZZu862nnw==", + "dev": true, + "requires": { + "array-filter": "^1.0.0" + }, + "dependencies": { + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", + "dev": true + } + } + }, "html-entities": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", @@ -7506,6 +8037,12 @@ "binary-extensions": "^1.0.0" } }, + "is-boolean-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.1.tgz", + "integrity": "sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==", + "dev": true + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -7624,6 +8161,12 @@ } } }, + "is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true + }, "is-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", @@ -7692,6 +8235,18 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-subset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", + "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", + "dev": true + }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -7775,6 +8330,100 @@ "textextensions": "^2.4.0" } }, + "jest-diff": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.1.0.tgz", + "integrity": "sha512-nepXgajT+h017APJTreSieh4zCqnSHEJ1iT8HDlewu630lSJ4Kjjr9KNzm+kzGwwcpsDE6Snx1GJGzzsefaEHw==", + "dev": true, + "requires": { + "chalk": "^3.0.0", + "diff-sequences": "^25.1.0", + "jest-get-type": "^25.1.0", + "pretty-format": "^25.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "pretty-format": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz", + "integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==", + "dev": true, + "requires": { + "@jest/types": "^25.1.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + } + }, + "react-is": { + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz", + "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-get-type": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.1.0.tgz", + "integrity": "sha512-yWkBnT+5tMr8ANB6V+OjmrIJufHtCAqI5ic2H40v+tRqxDmE0PGnIiTyvRWFOMtmVHYpwRqyazDbTnhpjsGvLw==", + "dev": true + }, "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", @@ -7996,6 +8645,12 @@ } } }, + "loaders.css": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/loaders.css/-/loaders.css-0.1.2.tgz", + "integrity": "sha1-Op+0NybHMzSjgUKvnQYpAZtlh0M=", + "dev": true + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -8010,6 +8665,24 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "lodash.escape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", + "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -8563,6 +9236,12 @@ "minimist": "0.0.8" } }, + "moo": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", + "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==", + "dev": true + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -8637,6 +9316,19 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "nearley": { + "version": "2.19.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.19.1.tgz", + "integrity": "sha512-xq47GIUGXxU9vQg7g/y1o1xuKnkO7ev4nRWqftmQrLkfnE/FjRqDaGOUakM8XHPn/6pW3bGjU2wgoJyId90rqg==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6", + "semver": "^5.4.1" + } + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -9167,6 +9859,15 @@ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, + "parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -9249,6 +9950,12 @@ "sha.js": "^2.4.8" } }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -10067,12 +10774,37 @@ "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", "dev": true }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dev": true, + "requires": { + "performance-now": "^2.1.0" + } + }, + "railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=", + "dev": true + }, "ramda": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz", "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=", "dev": true }, + "randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dev": true, + "requires": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + } + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -10475,6 +11207,18 @@ "tiny-warning": "^1.0.0" } }, + "react-spinkit": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-spinkit/-/react-spinkit-3.0.0.tgz", + "integrity": "sha1-Mf2vThgXd2bFfRsfMzApD4SSqFo=", + "dev": true, + "requires": { + "classnames": "^2.2.3", + "loaders.css": "^0.1.2", + "object-assign": "^4.1.0", + "prop-types": "^15.5.8" + } + }, "react-split-pane": { "version": "0.1.87", "resolved": "https://registry.npmjs.org/react-split-pane/-/react-split-pane-0.1.87.tgz", @@ -10937,6 +11681,16 @@ "inherits": "^2.0.1" } }, + "rst-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", + "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=", + "dev": true, + "requires": { + "lodash.flattendeep": "^4.4.0", + "nearley": "^2.7.10" + } + }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", @@ -11719,6 +12473,96 @@ "function-bind": "^1.0.2" } }, + "string.prototype.trim": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz", + "integrity": "sha512-MjGFEeqixw47dAMFMtgUro/I0+wNqZB5GKXGt1fFr24u3TzDXCPu7J9Buppzoe3r/LqkSDLDDJzE15RGWDGAVw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + } + } + }, "string.prototype.trimleft": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", diff --git a/package.json b/package.json index 4535250b..9b2e4809 100644 --- a/package.json +++ b/package.json @@ -46,25 +46,29 @@ "@babel/core": "^7.5.5", "@storybook/addon-actions": "^4.1.4", "@storybook/react": "^4.1.6", + "@types/enzyme": "^3.10.5", + "@types/jest": "^25.1.4", "@types/react": "^16.9.23", "@types/react-router-dom": "^5.1.3", "@typescript-eslint/eslint-plugin": "^2.22.0", - "@typescript-eslint/parser": "^2.22.0", + "@typescript-eslint/parser": "^2.23.0", + "apisauce": "^1.1.1", "babel-eslint": "^10.0.1", "babel-loader": "^8.0.5", + "enzyme": "^3.11.0", "eslint": "5.16.0", "eslint-config-wolox": "3.0.2", - "eslint-config-wolox-react": "2.0.0", - "eslint-config-wolox-typescript": "^1.0.1", + "eslint-config-wolox-react": "2.0.1", + "eslint-config-wolox-typescript": "1.0.1", "eslint-plugin-babel": "5.3.0", "eslint-plugin-import": "2.19.1", "eslint-plugin-jsx-a11y": "6.2.1", "eslint-plugin-prettier": "3.1.0", "eslint-plugin-react": "7.13.0", "eslint-plugin-react-hooks": "2.3.0", - "eslint-plugin-react-native": "3.7.0", "husky": "^2.3.0", "prettier": "^1.19.1", - "prettier-eslint": "^8.8.2" + "prettier-eslint": "^8.8.2", + "react-spinkit": "^3.0.0" } } From 0e542d0f5a4aedc0030227fa5627c61eee6278b3 Mon Sep 17 00:00:00 2001 From: damfinkel Date: Mon, 16 Mar 2020 19:02:19 -0300 Subject: [PATCH 3/6] replaces global context for N global contexts and fixed PR comments --- generators/app/steps/CustomizableSteps/constants.js | 10 +++++----- generators/app/tasks/fileCreators.js | 4 +++- generators/app/templates/.babelrc.ejs | 4 +++- generators/app/templates/.eslintrc.ejs | 5 ++++- generators/app/templates/jsconfig.json | 4 +++- .../src/app/components/ProviderWrapper/index.tsx | 2 +- .../templates/src/app/components/Routes/constants.ts | 2 +- .../app/templates/src/app/components/Routes/index.tsx | 6 +++--- generators/app/templates/src/app/index.tsx | 9 +++++---- .../src/app/screens/Dashboard/screens/Home/reducer.ts | 4 ++-- .../app/templates/src/app/screens/Login/index.tsx | 4 ++-- .../{app/context.ts => contexts/UserContext/index.ts} | 4 ++-- .../src/{app => contexts/UserContext}/reducer.ts | 8 ++++---- .../utils.test.tsx => hooks/useRequest.test.jsx} | 9 +++------ .../src/{services/utils.ts => hooks/useRequest.ts} | 0 generators/app/templates/src/utils/tests.tsx | 6 +++--- generators/app/templates/tsconfig.paths.json | 4 +++- 17 files changed, 47 insertions(+), 38 deletions(-) rename generators/app/templates/src/{app/context.ts => contexts/UserContext/index.ts} (52%) rename generators/app/templates/src/{app => contexts/UserContext}/reducer.ts (81%) rename generators/app/templates/src/{services/utils.test.tsx => hooks/useRequest.test.jsx} (97%) rename generators/app/templates/src/{services/utils.ts => hooks/useRequest.ts} (100%) diff --git a/generators/app/steps/CustomizableSteps/constants.js b/generators/app/steps/CustomizableSteps/constants.js index b3c0ae4c..127dbe6c 100644 --- a/generators/app/steps/CustomizableSteps/constants.js +++ b/generators/app/steps/CustomizableSteps/constants.js @@ -6,6 +6,8 @@ const SERVICES_PATH = 'src/services'; const CONSTANTS_PATH = 'src/constants'; const DOCS_README_PATH = 'docs'; const DEPENDENCY_SPECIFIC_PATH = 'src/dependency_specific'; +const HOOKS_PATH = 'src/hooks'; +const CONTEXT_PATH = 'src/contexts'; module.exports.RESCRIPTS_PATH = { src: 'rescriptsrc.js', @@ -23,14 +25,14 @@ module.exports.FILES = [ DOCS_README_PATH, SCREENS_PATH, UTILS_PATH, + HOOKS_PATH, + CONTEXT_PATH, 'aws.js', 'tsconfig.json', 'tsconfig.paths.json', 'scripts/deploy.js', 'src/react-app-env.d.ts', 'src/app/index.tsx', - 'src/app/reducer.ts', - 'src/app/context.ts', `${COMPONENTS_PATH}/Routes`, `${COMPONENTS_PATH}/Spinner`, `${COMPONENTS_PATH}/Suspense`, @@ -40,9 +42,7 @@ module.exports.FILES = [ `${COMPONENTS_PATH}/Checkbox`, `${COMPONENTS_PATH}/RadioGroup`, `${COMPONENTS_PATH}/ProviderWrapper`, - `${SERVICES_PATH}/AuthServices.js`, - `${SERVICES_PATH}/utils.ts`, - `${SERVICES_PATH}/utils.test.tsx` + `${SERVICES_PATH}/AuthServices.js` ]; module.exports.TEMPLATE_FILES = [ diff --git a/generators/app/tasks/fileCreators.js b/generators/app/tasks/fileCreators.js index a0fd6a8e..500dd6f1 100644 --- a/generators/app/tasks/fileCreators.js +++ b/generators/app/tasks/fileCreators.js @@ -69,7 +69,9 @@ module.exports.createJSConfig = function createJSConfig() { '~constants/*': ['./src/constants/*'], '~services/*': ['./src/services/*'], '~utils/*': ['./src/utils/*'], - '~assets/*': ['./src/assets/*'] + '~assets/*': ['./src/assets/*'], + '~hooks/*': ['./src/hooks/*'], + '~contexts/*': ['./src/contexts/*'] }; } diff --git a/generators/app/templates/.babelrc.ejs b/generators/app/templates/.babelrc.ejs index 75498fa1..53c798d4 100644 --- a/generators/app/templates/.babelrc.ejs +++ b/generators/app/templates/.babelrc.ejs @@ -12,7 +12,9 @@ module.exports = { "~constants": "./src/constants", "~services": "./src/services", "~utils": "./src/utils", - "~app": "./src/app" + "~app": "./src/app", + "~hooks": "./src/hooks", + "~contexts": "./src/contexts" } } ]<% } %> diff --git a/generators/app/templates/.eslintrc.ejs b/generators/app/templates/.eslintrc.ejs index 28f473d4..744a5c88 100644 --- a/generators/app/templates/.eslintrc.ejs +++ b/generators/app/templates/.eslintrc.ejs @@ -16,7 +16,10 @@ module.exports = { '~constants': './src/constants', '~services': './src/services', '~utils': './src/utils', - "~app": './src/app' + '~app': './src/app', + '~assets': './src/assets', + '~hooks': './src/hooks', + '~contexts': './src/contexts' } } }<%} %> diff --git a/generators/app/templates/jsconfig.json b/generators/app/templates/jsconfig.json index e63a6d89..8e75bc37 100644 --- a/generators/app/templates/jsconfig.json +++ b/generators/app/templates/jsconfig.json @@ -13,7 +13,9 @@ "~constants/*": ["./src/constants/*"], "~services/*": ["./src/services/*"], "~utils/*": ["./src/utils/*"], - "~assets/*": ["./src/assets/*"] + "~assets/*": ["./src/assets/*"], + "~hooks/*": ["./src/hooks/*"], + "~contexts/*": ["./src/contexts/*"] } }, "include": ["src"], diff --git a/generators/app/templates/src/app/components/ProviderWrapper/index.tsx b/generators/app/templates/src/app/components/ProviderWrapper/index.tsx index 1a18efc9..721a1e4c 100644 --- a/generators/app/templates/src/app/components/ProviderWrapper/index.tsx +++ b/generators/app/templates/src/app/components/ProviderWrapper/index.tsx @@ -6,7 +6,7 @@ interface Props { initialState: U; } -const withProvider = ({ Context, reducer, initialState }: Props) => ( +const withProvider = ({ Context, reducer, initialState }: Props) => ( WrappedComponent: React.ComponentType ) => { function ProviderWrapper(props: T) { diff --git a/generators/app/templates/src/app/components/Routes/constants.ts b/generators/app/templates/src/app/components/Routes/constants.ts index 7f2869f5..4c27e71f 100644 --- a/generators/app/templates/src/app/components/Routes/constants.ts +++ b/generators/app/templates/src/app/components/Routes/constants.ts @@ -2,7 +2,7 @@ import { lazy } from 'react'; import i18next from 'i18next'; import { Nullable } from '~utils/types'; -import { User } from '~app/reducer'; +import { User } from '~contexts/UserContext/reducer'; import PATHS from './paths'; diff --git a/generators/app/templates/src/app/components/Routes/index.tsx b/generators/app/templates/src/app/components/Routes/index.tsx index 81d5797b..156f8032 100644 --- a/generators/app/templates/src/app/components/Routes/index.tsx +++ b/generators/app/templates/src/app/components/Routes/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { BrowserRouter as Router, Switch } from 'react-router-dom'; -import { useSelector } from '~app/context'; +import { useSelector } from '~contexts/UserContext'; import Suspense from '../Suspense'; @@ -9,7 +9,7 @@ import { ROUTES } from './constants'; import RouteItem from './components/RouteItem'; import styles from './styles.module.scss'; -function AppRoutes() { +function Routes() { const user = useSelector(state => state.user); return ( @@ -27,4 +27,4 @@ function AppRoutes() { ); } -export default AppRoutes; +export default Routes; diff --git a/generators/app/templates/src/app/index.tsx b/generators/app/templates/src/app/index.tsx index 79936cad..562e24cd 100644 --- a/generators/app/templates/src/app/index.tsx +++ b/generators/app/templates/src/app/index.tsx @@ -2,15 +2,16 @@ import React, { useReducer } from 'react'; import '../scss/application.scss'; +import { reducer as userReducer, INITIAL_STATE } from '~contexts/UserContext/reducer'; +import { Context } from '~contexts/UserContext'; + import Routes from './components/Routes'; -import { globalReducer, INITIAL_STATE } from './reducer'; -import { Context } from './context'; function App() { - const [state, dispatch] = useReducer(globalReducer, INITIAL_STATE); + const [userState, userDispatch] = useReducer(userReducer, INITIAL_STATE); return ( - + ); diff --git a/generators/app/templates/src/app/screens/Dashboard/screens/Home/reducer.ts b/generators/app/templates/src/app/screens/Dashboard/screens/Home/reducer.ts index 72f6259f..87ad4acd 100644 --- a/generators/app/templates/src/app/screens/Dashboard/screens/Home/reducer.ts +++ b/generators/app/templates/src/app/screens/Dashboard/screens/Home/reducer.ts @@ -11,12 +11,12 @@ enum ActionTypes { RESET_FOO = 'RESET_FOO' } -export interface SetFoo { +interface SetFoo { type: ActionTypes.SET_FOO; payload: string; } -export interface ResetFoo { +interface ResetFoo { type: ActionTypes.RESET_FOO; } diff --git a/generators/app/templates/src/app/screens/Login/index.tsx b/generators/app/templates/src/app/screens/Login/index.tsx index d40e338d..596c8440 100644 --- a/generators/app/templates/src/app/screens/Login/index.tsx +++ b/generators/app/templates/src/app/screens/Login/index.tsx @@ -1,8 +1,8 @@ import React, { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; -import { useDispatch } from '~app/context'; -import { actionCreators } from '~app/reducer'; +import { useDispatch } from '~contexts/UserContext'; +import { actionCreators } from '~contexts/UserContext/reducer'; import Login from './layout'; diff --git a/generators/app/templates/src/app/context.ts b/generators/app/templates/src/contexts/UserContext/index.ts similarity index 52% rename from generators/app/templates/src/app/context.ts rename to generators/app/templates/src/contexts/UserContext/index.ts index e449641e..1efd8a0e 100644 --- a/generators/app/templates/src/app/context.ts +++ b/generators/app/templates/src/contexts/UserContext/index.ts @@ -1,5 +1,5 @@ import { contextFactory } from '~config/context'; -import { GlobalState, Action, INITIAL_STATE } from './reducer'; +import { UserState, Action, INITIAL_STATE } from './reducer'; -export const { useSelector, Context, useDispatch } = contextFactory(INITIAL_STATE); +export const { useSelector, Context, useDispatch } = contextFactory(INITIAL_STATE); diff --git a/generators/app/templates/src/app/reducer.ts b/generators/app/templates/src/contexts/UserContext/reducer.ts similarity index 81% rename from generators/app/templates/src/app/reducer.ts rename to generators/app/templates/src/contexts/UserContext/reducer.ts index ae4ace67..a9bc682e 100644 --- a/generators/app/templates/src/app/reducer.ts +++ b/generators/app/templates/src/contexts/UserContext/reducer.ts @@ -4,7 +4,7 @@ export interface User { id: number; } -export interface GlobalState { +export interface UserState { user: Nullable; } @@ -17,12 +17,12 @@ enum ActionTypes { RESET_USER = 'RESET_USER' } -export interface SetUser { +interface SetUser { type: ActionTypes.SET_USER; payload: User; } -export interface ResetUser { +interface ResetUser { type: ActionTypes.RESET_USER; } @@ -33,7 +33,7 @@ export const actionCreators = { resetUser: () => ({ type: ActionTypes.RESET_USER }) }; -export const globalReducer = (state: GlobalState, action: Action): GlobalState => { +export const reducer = (state: UserState, action: Action): UserState => { switch (action.type) { case 'SET_USER': { return { ...state, user: action.payload }; diff --git a/generators/app/templates/src/services/utils.test.tsx b/generators/app/templates/src/hooks/useRequest.test.jsx similarity index 97% rename from generators/app/templates/src/services/utils.test.tsx rename to generators/app/templates/src/hooks/useRequest.test.jsx index 0edf8d50..44f0b72b 100644 --- a/generators/app/templates/src/services/utils.test.tsx +++ b/generators/app/templates/src/hooks/useRequest.test.jsx @@ -3,13 +3,10 @@ import React, { useEffect } from 'react'; import { mount } from 'enzyme'; import { PROBLEM_CODE } from 'apisauce'; -import { useRequest, useLazyRequest, Error } from '~services/utils'; +import { useRequest, useLazyRequest, Error } from '~hooks/useRequest'; import { TestHook, testHook } from '~utils/tests'; import { Nullable } from '~utils/types'; -type True = true; -type False = false; - interface FooError { errorData: string; } @@ -24,7 +21,7 @@ type HookReturnValue = [ ]; const failureResponse = { - ok: false as False, + ok: false as false, problem: 'CLIENT_ERROR' as PROBLEM_CODE, originalError: { config: {}, isAxiosError: false, toJSON: jest.fn(), name: '', message: '' }, data: { errorData: 'error' }, @@ -35,7 +32,7 @@ const failureResponse = { }; const successResponse = { - ok: true as True, + ok: true as true, problem: null, originalError: null, data: { foo: 'value' }, diff --git a/generators/app/templates/src/services/utils.ts b/generators/app/templates/src/hooks/useRequest.ts similarity index 100% rename from generators/app/templates/src/services/utils.ts rename to generators/app/templates/src/hooks/useRequest.ts diff --git a/generators/app/templates/src/utils/tests.tsx b/generators/app/templates/src/utils/tests.tsx index ad98f77e..eff70e87 100644 --- a/generators/app/templates/src/utils/tests.tsx +++ b/generators/app/templates/src/utils/tests.tsx @@ -2,8 +2,8 @@ import React, { ReactNode, useReducer } from 'react'; import { mount } from 'enzyme'; import { Switch, BrowserRouter as Router } from 'react-router-dom'; -import { globalReducer, INITIAL_STATE } from '~app/reducer'; -import { Context } from '~app/context'; +import { Context } from '~contexts/UserContext'; +import { reducer, INITIAL_STATE } from '~contexts/UserContext/reducer'; type Hook = () => any; @@ -21,7 +21,7 @@ interface Props { } export const RootComponent = ({ children }: Props) => { - const [state, dispatch] = useReducer(globalReducer, INITIAL_STATE); + const [state, dispatch] = useReducer(reducer, INITIAL_STATE); return ( diff --git a/generators/app/templates/tsconfig.paths.json b/generators/app/templates/tsconfig.paths.json index f286e877..a248233e 100644 --- a/generators/app/templates/tsconfig.paths.json +++ b/generators/app/templates/tsconfig.paths.json @@ -10,7 +10,9 @@ "~screens/*": ["app/screens/*"], "~config/*": ["config/*"], "~schema/*": ["schema/*"], - "~app/*": ["app/*"] + "~app/*": ["app/*"], + "~hooks/*": ["./src/hooks/*"], + "~contexts/*": ["./src/contexts/*"] } } } From b8197505d3877e653a53f3c4ab878660c22d57c8 Mon Sep 17 00:00:00 2001 From: damfinkel Date: Mon, 16 Mar 2020 19:06:21 -0300 Subject: [PATCH 4/6] fixed useRequest test file suffix --- .../src/hooks/{useRequest.test.jsx => useRequest.test.tsx} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename generators/app/templates/src/hooks/{useRequest.test.jsx => useRequest.test.tsx} (99%) diff --git a/generators/app/templates/src/hooks/useRequest.test.jsx b/generators/app/templates/src/hooks/useRequest.test.tsx similarity index 99% rename from generators/app/templates/src/hooks/useRequest.test.jsx rename to generators/app/templates/src/hooks/useRequest.test.tsx index 44f0b72b..e2095651 100644 --- a/generators/app/templates/src/hooks/useRequest.test.jsx +++ b/generators/app/templates/src/hooks/useRequest.test.tsx @@ -21,7 +21,7 @@ type HookReturnValue = [ ]; const failureResponse = { - ok: false as false, + ok: false as const, problem: 'CLIENT_ERROR' as PROBLEM_CODE, originalError: { config: {}, isAxiosError: false, toJSON: jest.fn(), name: '', message: '' }, data: { errorData: 'error' }, @@ -32,7 +32,7 @@ const failureResponse = { }; const successResponse = { - ok: true as true, + ok: true as const, problem: null, originalError: null, data: { foo: 'value' }, From 2c28c49701d3f45c454caae1aff7f4032cc2a8a5 Mon Sep 17 00:00:00 2001 From: damfinkel Date: Thu, 19 Mar 2020 15:22:56 -0300 Subject: [PATCH 5/6] moved context and hooks to app folder and fixed paths --- generators/app/steps/CustomizableSteps/constants.js | 4 ++-- generators/app/tasks/fileCreators.js | 4 ++-- generators/app/templates/.babelrc.ejs | 4 ++-- generators/app/templates/.eslintrc.ejs | 4 ++-- .../app/templates/src/{ => app}/contexts/UserContext/index.ts | 0 .../templates/src/{ => app}/contexts/UserContext/reducer.ts | 0 .../app/templates/src/{ => app}/hooks/useRequest.test.tsx | 0 generators/app/templates/src/{ => app}/hooks/useRequest.ts | 0 generators/app/templates/tsconfig.paths.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) rename generators/app/templates/src/{ => app}/contexts/UserContext/index.ts (100%) rename generators/app/templates/src/{ => app}/contexts/UserContext/reducer.ts (100%) rename generators/app/templates/src/{ => app}/hooks/useRequest.test.tsx (100%) rename generators/app/templates/src/{ => app}/hooks/useRequest.ts (100%) diff --git a/generators/app/steps/CustomizableSteps/constants.js b/generators/app/steps/CustomizableSteps/constants.js index 127dbe6c..0a9cf779 100644 --- a/generators/app/steps/CustomizableSteps/constants.js +++ b/generators/app/steps/CustomizableSteps/constants.js @@ -6,8 +6,8 @@ const SERVICES_PATH = 'src/services'; const CONSTANTS_PATH = 'src/constants'; const DOCS_README_PATH = 'docs'; const DEPENDENCY_SPECIFIC_PATH = 'src/dependency_specific'; -const HOOKS_PATH = 'src/hooks'; -const CONTEXT_PATH = 'src/contexts'; +const HOOKS_PATH = 'src/app/hooks'; +const CONTEXT_PATH = 'src/app/contexts'; module.exports.RESCRIPTS_PATH = { src: 'rescriptsrc.js', diff --git a/generators/app/tasks/fileCreators.js b/generators/app/tasks/fileCreators.js index 500dd6f1..91780db9 100644 --- a/generators/app/tasks/fileCreators.js +++ b/generators/app/tasks/fileCreators.js @@ -70,8 +70,8 @@ module.exports.createJSConfig = function createJSConfig() { '~services/*': ['./src/services/*'], '~utils/*': ['./src/utils/*'], '~assets/*': ['./src/assets/*'], - '~hooks/*': ['./src/hooks/*'], - '~contexts/*': ['./src/contexts/*'] + '~hooks/*': ['./src/app/hooks/*'], + '~contexts/*': ['./src/app/contexts/*'] }; } diff --git a/generators/app/templates/.babelrc.ejs b/generators/app/templates/.babelrc.ejs index 53c798d4..9fe718d7 100644 --- a/generators/app/templates/.babelrc.ejs +++ b/generators/app/templates/.babelrc.ejs @@ -13,8 +13,8 @@ module.exports = { "~services": "./src/services", "~utils": "./src/utils", "~app": "./src/app", - "~hooks": "./src/hooks", - "~contexts": "./src/contexts" + "~hooks": "./src/app/hooks", + "~contexts": "./src/app/contexts" } } ]<% } %> diff --git a/generators/app/templates/.eslintrc.ejs b/generators/app/templates/.eslintrc.ejs index 744a5c88..bdd5eceb 100644 --- a/generators/app/templates/.eslintrc.ejs +++ b/generators/app/templates/.eslintrc.ejs @@ -18,8 +18,8 @@ module.exports = { '~utils': './src/utils', '~app': './src/app', '~assets': './src/assets', - '~hooks': './src/hooks', - '~contexts': './src/contexts' + '~hooks': './src/app/hooks', + '~contexts': './src/app/contexts' } } }<%} %> diff --git a/generators/app/templates/src/contexts/UserContext/index.ts b/generators/app/templates/src/app/contexts/UserContext/index.ts similarity index 100% rename from generators/app/templates/src/contexts/UserContext/index.ts rename to generators/app/templates/src/app/contexts/UserContext/index.ts diff --git a/generators/app/templates/src/contexts/UserContext/reducer.ts b/generators/app/templates/src/app/contexts/UserContext/reducer.ts similarity index 100% rename from generators/app/templates/src/contexts/UserContext/reducer.ts rename to generators/app/templates/src/app/contexts/UserContext/reducer.ts diff --git a/generators/app/templates/src/hooks/useRequest.test.tsx b/generators/app/templates/src/app/hooks/useRequest.test.tsx similarity index 100% rename from generators/app/templates/src/hooks/useRequest.test.tsx rename to generators/app/templates/src/app/hooks/useRequest.test.tsx diff --git a/generators/app/templates/src/hooks/useRequest.ts b/generators/app/templates/src/app/hooks/useRequest.ts similarity index 100% rename from generators/app/templates/src/hooks/useRequest.ts rename to generators/app/templates/src/app/hooks/useRequest.ts diff --git a/generators/app/templates/tsconfig.paths.json b/generators/app/templates/tsconfig.paths.json index a248233e..7928688f 100644 --- a/generators/app/templates/tsconfig.paths.json +++ b/generators/app/templates/tsconfig.paths.json @@ -11,8 +11,8 @@ "~config/*": ["config/*"], "~schema/*": ["schema/*"], "~app/*": ["app/*"], - "~hooks/*": ["./src/hooks/*"], - "~contexts/*": ["./src/contexts/*"] + "~hooks/*": ["./app/hooks/*"], + "~contexts/*": ["./app/contexts/*"] } } } From ff967132c13b9a04787105c9e8d58959a77b5acb Mon Sep 17 00:00:00 2001 From: damfinkel Date: Thu, 19 Mar 2020 15:30:22 -0300 Subject: [PATCH 6/6] removed relative path in tsconfig for hooks and context --- generators/app/templates/tsconfig.paths.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generators/app/templates/tsconfig.paths.json b/generators/app/templates/tsconfig.paths.json index 7928688f..8cd38f9b 100644 --- a/generators/app/templates/tsconfig.paths.json +++ b/generators/app/templates/tsconfig.paths.json @@ -11,8 +11,8 @@ "~config/*": ["config/*"], "~schema/*": ["schema/*"], "~app/*": ["app/*"], - "~hooks/*": ["./app/hooks/*"], - "~contexts/*": ["./app/contexts/*"] + "~hooks/*": ["app/hooks/*"], + "~contexts/*": ["app/contexts/*"] } } }