├── .npmignore ├── src ├── variables │ ├── states.js │ └── actions.js ├── combineEntities.js ├── index.js └── configureDataEntity.js ├── .babelrc ├── docs ├── plans.md └── api.md ├── package.json ├── LICENSE ├── .gitignore ├── index.js.flow ├── readme.md └── yarn.lock /.npmignore: -------------------------------------------------------------------------------- 1 | .babelrc 2 | .eslintrc.js 3 | .flowconfig 4 | .travis.yml 5 | .idea -------------------------------------------------------------------------------- /src/variables/states.js: -------------------------------------------------------------------------------- 1 | const States = { 2 | START: 'START', 3 | SUCCESS: 'SUCCESS', 4 | FAIL: 'FAIL', 5 | } 6 | export const { 7 | START, 8 | SUCCESS, 9 | FAIL, 10 | } = States -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2017", 4 | "es2015" 5 | ], 6 | "plugins": [ 7 | "transform-class-properties", 8 | "transform-object-rest-spread", 9 | "transform-flow-strip-types" 10 | ] 11 | } -------------------------------------------------------------------------------- /src/combineEntities.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | export default function combineEntities(entities) { 4 | return _.reduce(entities, (combined, value, key) => ({ 5 | ...combined, 6 | [value.getConfig().reducerName]: value.getReducer(), 7 | }), {}) 8 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import configureDataEntity from './configureDataEntity' 2 | import combineEntities from './combineEntities' 3 | import * as Actions from './variables/actions' 4 | import * as States from './variables/states' 5 | 6 | export { configureDataEntity, combineEntities, Actions, States } -------------------------------------------------------------------------------- /src/variables/actions.js: -------------------------------------------------------------------------------- 1 | const Actions = { 2 | CREATE_ONE: 'CREATE_ONE', 3 | READ_ONE: 'READ_ONE', 4 | UPDATE_ONE: 'UPDATE_ONE', 5 | DELETE_ONE: 'DELETE_ONE', 6 | CREATE_MANY: 'CREATE_MANY', 7 | READ_MANY: 'READ_MANY', 8 | UPDATE_MANY: 'UPDATE_MANY', 9 | DELETE_MANY: 'DELETE_MANY', 10 | CLEAR: 'CLEAR', 11 | } 12 | export const { 13 | CREATE_ONE, 14 | READ_ONE, 15 | UPDATE_ONE, 16 | DELETE_ONE, 17 | CREATE_MANY, 18 | READ_MANY, 19 | UPDATE_MANY, 20 | DELETE_MANY, 21 | CLEAR, 22 | } = Actions -------------------------------------------------------------------------------- /docs/plans.md: -------------------------------------------------------------------------------- 1 | ### General plans 2 | - ~~Write additional library to support redux-offline~~ (Completed [redux-data-entity-offline](https://github.com/iamawebgeek/redux-data-entity-offline)) 3 | - Release processing engine library for Firebase Storage Database (On the way [redux-data-entity-firebase](https://github.com/iamawebgeek/redux-data-entity-firebase)) 4 | - Create an example app using this library, [redux-data-entity-offline](https://github.com/iamawebgeek/redux-data-entity-offline) and [redux-data-entity-firebase](https://github.com/iamawebgeek/redux-data-entity-firebase) 5 | - Typescript support 6 | 7 | ### For next minor release 8 | - Write tests covering all the project 9 | - ~~Write full API documentation~~ (Completed) 10 | - Fix bugs 11 | 12 | ### For release 13 | - Make stable API -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-data-entity", 3 | "version": "0.1.1", 4 | "description": "Redux plugin for working with data much easier way", 5 | "author": { 6 | "name": "iamawebgeek", 7 | "url": "https://github.com/iamawebgeek" 8 | }, 9 | "keywords": [ 10 | "immutable", 11 | "reducer", 12 | "redux bolierplate", 13 | "rest", 14 | "data entity", 15 | "redux crud", 16 | "redux api" 17 | ], 18 | "repository": "https://github.com/iamawebgeek/redux-data-entity", 19 | "main": "lib/index.js", 20 | "scripts": { 21 | "build": "babel src --out-dir lib", 22 | "prepublish": "npm run build" 23 | }, 24 | "license": "MIT", 25 | "dependencies": { 26 | "lodash": "^4.17.4", 27 | "uniqid": "^4.1.1" 28 | }, 29 | "devDependencies": { 30 | "babel-core": "^6.18.2", 31 | "babel-preset-es2015": "^6.24.1", 32 | "babel-preset-es2017": "^6.24.1", 33 | "babel-plugin-transform-class-properties": "^6.24.1", 34 | "babel-plugin-transform-flow-strip-types": "^6.22.0", 35 | "babel-plugin-transform-object-rest-spread": "^6.26.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled js 2 | lib 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (http://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # Typescript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | -------------------------------------------------------------------------------- /index.js.flow: -------------------------------------------------------------------------------- 1 | // @flow 2 | type DataEntityConfig = { 3 | reducerName?: string, 4 | process?: (action: DataEntityAction, config: DataEntityActionConfig, dataEntityConfig: DataEntityConfig) => ?Promise, 5 | reducerDefault?: Array | Object, 6 | keyExtractor?: (unit: Object) => string | number, 7 | keyGenerator?: () => string, 8 | valueExtractor?: (unit: Object) => T 9 | responseValidityTime?: ?number | Object, 10 | } 11 | 12 | type DataEntityActionConfig = { 13 | optimistic?: boolean, 14 | force?: boolean, 15 | data?: any, 16 | keys?: Array, 17 | params?: any, 18 | } 19 | 20 | type DataEntityAction = 'CREATE_ONE' | 'READ_ONE' | 'UPDATE_ONE' | 'DELETE_ONE' | 21 | 'CREATE_MANY' | 'READ_MANY' | 'UPDATE_MANY' | 'DELETE_MANY' | 'CLEAR' 22 | type DataEntityState = 'START' | 'SUCCESS' | 'FAIL' 23 | 24 | declare class DataEntity { 25 | isPerforming: (action: DataEntityAction, config?: DataEntityActionConfig) => boolean, 26 | isOptimistic: (key: string) => boolean, 27 | shouldRequest: (action: DataEntityAction, config?: DataEntityActionConfig) => boolean, 28 | getActionHandler: (dispatch: Function) => (action: DataEntityAction, config?: DataEntityActionConfig, callback?: ?Function, meta?: Object) => number 29 | getCacheCleaner: (dispatch: Function) => () => void, 30 | getLastError: (action: DataEntityAction, config?: DataEntityActionConfig) => ?Error, 31 | getReducer: () => Function, 32 | getConst: (action: DataEntityAction, state?: DataEntityState) => string, 33 | getConfig: () => object, 34 | getActionConfig: () => object, 35 | parseAction: (type: string) => ?string, 36 | parseState: (type: string, action?: string) => ?string, 37 | } 38 | 39 | declare function combineEntities(entities: Object): Object 40 | declare function createDataEntityInstance(entities: Array | Object): Object 41 | declare function configureDataEntity(globalConfig: DataEntityConfig, globalActionConfig: DataEntityActionConfig): createDataEntityInstance 42 | 43 | export { 44 | configureDataEntity, 45 | combineEntities, 46 | } 47 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # redux-data-entity 2 | A library that helps to manage data in easier way with redux 3 | 4 | ## Features 5 | - No actions, reducers and constants declaration 6 | - Caching requests 7 | - Prevents repetitive requests 8 | - Optimistic creates, updates and deletes 9 | - Zero config integration (no store modification) 10 | 11 | ## Plans for future work 12 | Check it out [here](docs/plans.md) 13 | 14 | ## Installation 15 | Installing using node package manager. 16 | Type the following in your console inside your project directory: 17 | ``` 18 | npm install redux-data-entity --save 19 | ``` 20 | 21 | With yarn: 22 | ``` 23 | yarn add redux-data-entity 24 | ``` 25 | 26 | Inline HTML including 27 | coming soon... 28 | 29 | ## Usage 30 | 31 | Full API reference [here](docs/api.md) 32 | 33 | ### Creating new data entity instance 34 | ```js 35 | // e.g. entities/index.js 36 | import { 37 | configureDataEntity, 38 | Actions, 39 | } from 'redux-data-entity' 40 | import { fetchMyData } from './localUtils' 41 | 42 | const createDataEntities = configureDataEntity( 43 | { 44 | process: (action, config, instanceConfig) => { 45 | const API = `http://localhost/${instanceConfig.endpoint}` 46 | switch (action) { 47 | case Actions.READ_MANY: 48 | return fetchMyData(`${API}`, { 49 | method: 'GET', 50 | params: config.params, 51 | }) 52 | case Actions.READ_ONE: 53 | return fetchMyData(`${API}/${config.keys[0]}`, { 54 | method: 'GET', 55 | params: config.params, 56 | }) 57 | case Actions.CREATE_ONE: 58 | return fetchMyData(`${API}`, { 59 | method: 'POST', 60 | data: config.data, 61 | }) 62 | case Actions.UPDATE_ONE: 63 | return fetchMyData(`${API}/${config.keys[0]}`, { 64 | method: 'PUT', 65 | data: config.data, 66 | }) 67 | case Actions.DELETE_ONE: 68 | return fetchMyData(`${API}/${config.keys[0]}`, { 69 | method: 'DELETE', 70 | optimistic: true, 71 | }) 72 | } 73 | return null 74 | }, 75 | } 76 | ) 77 | export default createDataEntities({ 78 | users: { 79 | endpoint: 'v1/user', 80 | }, 81 | posts: { 82 | endpoint: 'v1/posts', 83 | }, 84 | comments: { 85 | endpoint: 'v2/comments', 86 | } 87 | }) 88 | ``` 89 | ### Combine with other reducers 90 | ```js 91 | // e.g reducers/index.js 92 | import { combineDataEntities } from 'redux-data-entity' 93 | 94 | import entities from '../entities' 95 | 96 | export default combineReducers( 97 | ...combineEntities(entities), 98 | { 99 | // other reducers 100 | }, 101 | ) 102 | ``` 103 | ### Using inside component 104 | ```js 105 | // e.g. components/SomeDataComponent.js 106 | import { Actions } from 'redux-data-entity' 107 | import _ from 'lodash' 108 | 109 | import entities from '../entities' 110 | 111 | class SomeDataComponent extends Component { 112 | componentDidMount() { 113 | this.props.userActions(Actions.READ_MANY, {}, (error, response) => { 114 | // use callback function to chain requests 115 | if (error === null) { 116 | this.props.commentActions(Actions.READ_MANY, { 117 | params: { 118 | // handle these properly inside process function 119 | filter: { 120 | user_id: response.map((user) => user.id) 121 | }, 122 | }, 123 | }) 124 | } 125 | }) 126 | } 127 | renderLoader() { 128 | return ( 129 | 130 | ) 131 | } 132 | renderContent() { 133 | const error = entities.users.getLastError(Actions.READ_MANY) 134 | if (error !== null) { 135 | return ( 136 |
137 |

{error.message}

138 | 139 |
140 | ) 141 | } 142 | return ( 143 |
144 | {_.map(this.props.users).map((user, key) => ( 145 | {user.name} 146 | ))} 147 |
148 | ) 149 | } 150 | render() { 151 | return ( 152 | this.props.isLoadingUsers ? this.renderLoader() : this.renderContent() 153 | ) 154 | } 155 | } 156 | 157 | const mapStateToProps = (state) => ({ 158 | users: state.users, 159 | // note: any loading state getters are recommended to include inside state to props mapper or props merging function 160 | isLoadingUsers: entities.users.isPerforming(Actions.READ_MANY), 161 | }) 162 | 163 | const mapDispatchToProps = (dispatch) => ({ 164 | userActions: entities.users.getActionHandler(dispatch), 165 | commentActions: entities.comments.getActionHandler(dispatch), 166 | }) 167 | 168 | export default connect(mapStateToProps, mapDispatchToProps)(SomeDataComponent) 169 | ``` -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | ## Redux Data Entity API 2 | 3 | ### `Actions` 4 | Enum containing all these actions: 5 | 6 | - `READ_MANY` Use this to load an array of data unit 7 | - `READ_ONE` Use this to load a data unit object 8 | - `CREATE_MANY` Use this to create an array of data units, **array** of objects should be passed only via `data` property of `config` parameter of action handler function 9 | - `CREATE_ONE` Use this to create single data unit, **an object** should be passed only via `data` property of `config` parameter of action handler function 10 | - `UPDATE_MANY` Use this to update an array of data units, **array** of objects AND **array** of keys should be passed only via `data` AND `keys` properties of `config` parameter of action handler function in respective order 11 | - `UPDATE_ONE` Use this to update single data unit, **an object** AND its **key (in an array)** should be passed only via `data` AND **keys** property of `config` parameter of action handler function 12 | - `DELETE_MANY` Use this to delete an array of data units, **keys** of data units to be deleted should be passed as an array 13 | - `DELETE_ONE` Works the same as `DELETE_MANY` 14 | - `CLEAR` Use this to fully clear requests cache and reducer state 15 | 16 | ### `Action` 17 | One of the actions from `Actions` enum. List given above 18 | 19 | ### `ActionConfig` 20 | Object containing configuration of an action 21 | - *data*: Data to be processed by `process` function 22 | - *keys*: Array of a key/keys of processed data units 23 | - *params*: Additional params (e.g server api query parameters) 24 | - *optimistic*: If an action is optimistic. Works with creates, updates and deletes. Passed `data` is processed in reducer when an actual request starts, defaults to false. 25 | - *force*: Run action even if similar one is already running, defaults to false. 26 | 27 | ### `States` 28 | Enum containing request states: 29 | 30 | - `START` 31 | - `SUCCESS` 32 | - `FAIL` 33 | 34 | ### `combineDataEntities(entities)` 35 | Function that extracts reducers from entities 36 | 37 | ### `configureDataEntity(config)` 38 | Returns a new function for creating `data entity` with given global options. 39 | 40 | - *config*: Configuration of a new DataEntity instance with some required keys 41 | - *reducerName* (required): Name of your reducer to access data later (should be unique) 42 | - *process* (required): Function that would accept action and passed action configuration and return Promise, which would get your data 43 | - *reducerDefault*: Default state of the reducer 44 | - *keyExtractor*: Function that extracts key of a data unit. Defaults to id property getter 45 | - *keyGenerator*: Function that would generate a key for new optimistic data units. Defaults to `uniqid` module id generation `time` method 46 | - *responseValidityTime*: Duration (in microseconds) of requests validity, if given object, checks property of necessary action 47 | 48 | #### `getActionConfig()` 49 | Returns default action config 50 | 51 | #### `getActionHandler(dispatch): actionHandlerFunction` 52 | Gets a redux store dispatcher function and returns a new function for handling given actions 53 | 54 | ##### `actionHandlerFunction(action, config, callback, meta)` 55 | - *action* (required): Refer `Action` 56 | - *config*: Refer `ActionConfig` 57 | - *callback*: Function that would be called when request has finished 58 | - *meta*: Meta that should be passed for dispatched actions 59 | 60 | #### `getCacheCleaner(dispatch): cacheCleanerFunction` 61 | Gets a redux store dispatcher function and returns a new function for clearing instance requests cache 62 | 63 | #### `getConfig()` 64 | Returns instance config 65 | 66 | #### `getConst(action, state)` 67 | Returns redux action type for given action and config e.g. `RDE/reducerName/READ_MANY_SUCCESS` 68 | - *action* (required): Refer `Action` 69 | - *state*: Refer `States` 70 | 71 | #### `getLastError(action, config)` 72 | Returns `Error` or `null` based on last finished request for given parameters 73 | - *action* (required): Refer `Action` 74 | - *config*: Refer `ActionConfig` 75 | 76 | #### `getReducer()` 77 | Returns reducer function. Used by `combineDataEntities` function 78 | 79 | #### `isPerforming(action, config)` 80 | Returns if request with given parameter is active 81 | - *action* (required): Refer `Action` 82 | - *config*: Refer `ActionConfig` 83 | 84 | #### `isOptimistic(key)` 85 | Returns whether given data unit key is optimistic or not 86 | - *key* (required): Data unit string key 87 | 88 | #### `parseAction(constant)` 89 | Returns `Action` or null if constant is not recognized 90 | - *constant* (required): Redux action type string 91 | 92 | #### `parseState(constant, action)` 93 | Returns `State` or null if constant is not recognized 94 | - *constant* (required): Redux action type string 95 | - *action*: Refer `Action` (used to skip some checks, fully optional) 96 | 97 | #### `shouldRequest(action, config)` 98 | Returns whether request with given parameter is active or its response is still valid 99 | - *action* (required): Refer `Action` 100 | - *config*: Refer `ActionConfig` 101 | -------------------------------------------------------------------------------- /src/configureDataEntity.js: -------------------------------------------------------------------------------- 1 | import uniqid from 'uniqid' 2 | import _ from 'lodash' 3 | 4 | import * as Actions from './variables/actions' 5 | import * as States from './variables/states' 6 | 7 | export default function configureDataEntity(globalEntityConfig = {}, globalActionConfig = {}) { 8 | const defaultEntityConfig = { 9 | keyExtractor: (unit) => unit.id, 10 | keyGenerator: (unit) => uniqid.time(), 11 | valueExtractor: (unit) => unit, 12 | reducerDefault: [], 13 | responseValidityTime: null, 14 | ...globalEntityConfig, 15 | } 16 | const defaultActionConfig = { 17 | optimistic: false, 18 | force: false, 19 | ...globalActionConfig, 20 | } 21 | function createDataEntityInstance(reducerName, config = {}) { 22 | const instanceConfig = { 23 | reducerName, 24 | ...defaultEntityConfig, 25 | ...config, 26 | } 27 | let requests = [] 28 | let optimisticKeys = [] 29 | 30 | if (typeof instanceConfig.reducerName !== 'string') { 31 | throw new Error( 32 | 'Data entity reducer name has to be a string. ' + 33 | `Instead specified ${instanceConfig.reducerName}` 34 | ) 35 | } 36 | if (typeof instanceConfig.process !== 'function') { 37 | throw new Error( 38 | 'Data entity config process property has to be a function' 39 | ) 40 | } 41 | 42 | function parseAction(type) { 43 | for (let action in Actions) { 44 | if (type.startsWith(`RDE/${instanceConfig.reducerName}/${action}`)) { 45 | return action 46 | } 47 | } 48 | return null 49 | } 50 | 51 | function parseState(type, action = this.parseAction(type)) { 52 | if (action !== null) { 53 | for (let state in States) { 54 | if (type === `RDE/${instanceConfig.reducerName}/${action}_${state}`) { 55 | return state 56 | } 57 | } 58 | } 59 | return null 60 | } 61 | 62 | function sortByFinishTime(completed) { 63 | return completed.sort((request1, request2) => 64 | request1.finishTime < request2.finishTime ? -1 : +(request1.finishTime > request2.finishTime) 65 | ) 66 | } 67 | 68 | function addUnit(items, unit) { 69 | return { 70 | ...items, 71 | [instanceConfig.keyExtractor(unit)]: instanceConfig.valueExtractor(unit), 72 | } 73 | } 74 | 75 | function removeUnit(items, key) { 76 | return _.omit(items, key) 77 | } 78 | 79 | function addOptimisticUnit(items, unit) { 80 | const optimisticKey = instanceConfig.keyExtractor(unit) || instanceConfig.keyGenerator(unit) 81 | optimisticKeys.push(optimisticKey) 82 | return { 83 | ...items, 84 | [optimisticKey]: unit, 85 | } 86 | } 87 | 88 | function newState() { 89 | let items = {} 90 | let { optimistic, succeeded } = requests.reduce((requestObj, request) => { 91 | const key = typeof request.finishTime === 'undefined' ? 'optimistic' : 'succeeded' 92 | if ((key === 'optimistic' && !request.config.optimistic) || request.error) { 93 | return requestObj 94 | } 95 | return { 96 | ...requestObj, 97 | [key]: requestObj[key].concat(request), 98 | } 99 | }, { optimistic: [], succeeded: [] }) 100 | if (!Array.isArray(instanceConfig.reducerDefault)) { 101 | items = instanceConfig.reducerDefault 102 | } 103 | else { 104 | instanceConfig.reducerDefault.forEach((item) => { 105 | addUnit(items, item) 106 | }) 107 | } 108 | succeeded = sortByFinishTime(succeeded) 109 | succeeded.forEach(({ action, result, config }) => { 110 | switch (action) { 111 | case Actions.READ_ONE: 112 | case Actions.CREATE_ONE: 113 | case Actions.UPDATE_ONE: 114 | result = [result] 115 | case Actions.READ_MANY: 116 | case Actions.CREATE_MANY: 117 | case Actions.UPDATE_MANY: 118 | result.forEach((unit) => { 119 | items = addUnit(items, unit) 120 | }) 121 | break 122 | case Actions.DELETE_ONE: 123 | case Actions.DELETE_MANY: 124 | config.keys.forEach((key) => { 125 | items = removeUnit(items, key) 126 | }) 127 | break 128 | } 129 | }) 130 | optimistic.forEach(({ action, config: { data, keys } }) => { 131 | switch (action) { 132 | case Actions.CREATE_ONE: 133 | data = _.castArray(data) 134 | case Actions.CREATE_MANY: 135 | data.forEach((unit) => { 136 | items = addOptimisticUnit(items, unit) 137 | }) 138 | break 139 | case Actions.UPDATE_ONE: 140 | data = _.castArray(data) 141 | case Actions.UPDATE_MANY: 142 | keys.forEach((key, index) => { 143 | items[key] = { ...items[key], ...data[index] } 144 | }) 145 | break 146 | case Actions.DELETE_ONE: 147 | case Actions.DELETE_MANY: 148 | keys.forEach((key) => { 149 | items = removeUnit(items, key) 150 | }) 151 | break 152 | } 153 | }) 154 | return items 155 | } 156 | 157 | function getReducer() { 158 | return function (state, { type, payload, meta: { dataEntity } = {} }) { 159 | const action = parseAction(type) 160 | const requestState = parseState(type, action) 161 | if (action === Actions.CLEAR) { 162 | requests = [] 163 | optimisticKeys = [] 164 | state = undefined 165 | } 166 | let modified = _.isUndefined(state) 167 | if (action !== null && requestState !== null) { 168 | if (requestState === States.START) { 169 | dataEntity.startTime = +Date.now() 170 | dataEntity.action = action 171 | requests.push(dataEntity) 172 | modified = dataEntity.config.optimistic 173 | } 174 | else { 175 | const oldLength = requests.length 176 | const keysToMatch = ['config', 'action'] 177 | requests = requests.filter((request) => { 178 | let request1 = _.pick(request, keysToMatch) 179 | let request2 = _.pick(dataEntity, keysToMatch) 180 | return !(request !== dataEntity && _.isEqual(request1, request2)); 181 | }) 182 | dataEntity.finishTime = +Date.now() 183 | dataEntity[requestState === States.FAIL ? 'error' : 'result'] = payload 184 | modified = requests.indexOf(dataEntity) !== -1 || oldLength !== requests.length 185 | } 186 | if (!modified) { 187 | state = { ...state } 188 | } 189 | } 190 | return modified ? newState() : state 191 | } 192 | } 193 | 194 | function getConfig() { 195 | return { ...instanceConfig } 196 | } 197 | 198 | function getActionConfig() { 199 | return { ...defaultActionConfig } 200 | } 201 | 202 | function cacheIsValid(action, req) { 203 | if (instanceConfig.responseValidityTime !== null) { 204 | let duration = _.isPlainObject(instanceConfig.responseValidityTime) 205 | ? instanceConfig.responseValidityTime[action] 206 | : instanceConfig.responseValidityTime 207 | if (!_.isNumber(duration)) { 208 | return false 209 | } 210 | return +Date.now() - req.finishTime < duration 211 | } 212 | return false 213 | } 214 | 215 | function shouldRequest(action, config) { 216 | let valid = false 217 | let active = requestHas(action, config, (req) => { 218 | if (_.isNumber(req.finishTime)) { 219 | if (_.isUndefined(req.error) && cacheIsValid(action, req)) { 220 | valid = true 221 | } 222 | return false 223 | } 224 | return true 225 | }) 226 | return !active && !valid 227 | } 228 | 229 | function isOptimistic(key) { 230 | return optimisticKeys.indexOf(key) !== -1 231 | } 232 | 233 | function getActionHandler(dispatch) { 234 | return function (action, config, callback, meta = {}) { 235 | function onFinish(error, result) { 236 | if (_.isFunction(callback)) { 237 | callback(error, result) 238 | } 239 | } 240 | config = { ...defaultActionConfig, ...config } 241 | if (config.force || shouldRequest(action, config)) { 242 | const dataEntity = { config } 243 | dispatch({ type: getConst(action, States.START), meta: { ...meta, dataEntity } }) 244 | const actionRequest = instanceConfig.process(action, dataEntity.config, getConfig()) 245 | if (actionRequest !== null) { 246 | actionRequest.then( 247 | (result) => { 248 | dispatch({ type: getConst(action, States.SUCCESS), meta: { ...meta, dataEntity }, payload: result }) 249 | onFinish(null, result) 250 | }, 251 | (error) => { 252 | dispatch({ type: getConst(action, States.FAIL), meta: { ...meta, dataEntity }, payload: error }) 253 | onFinish(error) 254 | }, 255 | ) 256 | } 257 | else { 258 | onFinish(null) 259 | } 260 | } 261 | } 262 | } 263 | 264 | function getCacheCleaner(dispatch) { 265 | return function () { 266 | dispatch({ type: this.getConst(Actions.CLEAR) }) 267 | } 268 | } 269 | 270 | function getConst(action, state = null) { 271 | return `RDE/${instanceConfig.reducerName}/${action}${state !== null ? '_' + state : ''}` 272 | } 273 | 274 | function requestHas(action, config, matches) { 275 | return [...requests].reverse().some((request) => { 276 | if (request.action !== action) { 277 | return false 278 | } 279 | if (!config) { 280 | return matches(request) 281 | } 282 | return _.isEqual(request.config, { ...defaultActionConfig, ...config }) ? matches(request) : false 283 | }) 284 | } 285 | 286 | function isPerforming(action, config) { 287 | return requestHas(action, config, (req) => _.isUndefined(req.finishTime)) 288 | } 289 | 290 | function getLastError(action, config) { 291 | let lastError = null 292 | requestHas(action, config, (req) => { 293 | if (req.error) { 294 | lastError = req.error 295 | } 296 | return req.error 297 | }) 298 | return lastError === null || lastError instanceof Error ? lastError : new Error(lastError) 299 | } 300 | 301 | return { 302 | isPerforming, 303 | isOptimistic, 304 | shouldRequest, 305 | getCacheCleaner, 306 | getActionHandler, 307 | getReducer, 308 | getConst, 309 | getConfig, 310 | getActionConfig, 311 | getLastError, 312 | parseState, 313 | parseAction, 314 | } 315 | } 316 | return function (entities) { 317 | let entityKeys = entities 318 | if (!Array.isArray(entities)) { 319 | entityKeys = Object.keys(entities) 320 | } 321 | return entityKeys.reduce((entitiesObject, key) => ({ 322 | ...entitiesObject, 323 | [key]: createDataEntityInstance(key, entities[key]), 324 | }), {}) 325 | } 326 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ansi-regex@^2.0.0: 6 | version "2.1.1" 7 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 8 | 9 | ansi-styles@^2.2.1: 10 | version "2.2.1" 11 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 12 | 13 | babel-code-frame@^6.26.0: 14 | version "6.26.0" 15 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" 16 | dependencies: 17 | chalk "^1.1.3" 18 | esutils "^2.0.2" 19 | js-tokens "^3.0.2" 20 | 21 | babel-core@^6.18.2, babel-core@^6.26.0: 22 | version "6.26.0" 23 | resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" 24 | dependencies: 25 | babel-code-frame "^6.26.0" 26 | babel-generator "^6.26.0" 27 | babel-helpers "^6.24.1" 28 | babel-messages "^6.23.0" 29 | babel-register "^6.26.0" 30 | babel-runtime "^6.26.0" 31 | babel-template "^6.26.0" 32 | babel-traverse "^6.26.0" 33 | babel-types "^6.26.0" 34 | babylon "^6.18.0" 35 | convert-source-map "^1.5.0" 36 | debug "^2.6.8" 37 | json5 "^0.5.1" 38 | lodash "^4.17.4" 39 | minimatch "^3.0.4" 40 | path-is-absolute "^1.0.1" 41 | private "^0.1.7" 42 | slash "^1.0.0" 43 | source-map "^0.5.6" 44 | 45 | babel-generator@^6.26.0: 46 | version "6.26.0" 47 | resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" 48 | dependencies: 49 | babel-messages "^6.23.0" 50 | babel-runtime "^6.26.0" 51 | babel-types "^6.26.0" 52 | detect-indent "^4.0.0" 53 | jsesc "^1.3.0" 54 | lodash "^4.17.4" 55 | source-map "^0.5.6" 56 | trim-right "^1.0.1" 57 | 58 | babel-helper-call-delegate@^6.24.1: 59 | version "6.24.1" 60 | resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" 61 | dependencies: 62 | babel-helper-hoist-variables "^6.24.1" 63 | babel-runtime "^6.22.0" 64 | babel-traverse "^6.24.1" 65 | babel-types "^6.24.1" 66 | 67 | babel-helper-define-map@^6.24.1: 68 | version "6.26.0" 69 | resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" 70 | dependencies: 71 | babel-helper-function-name "^6.24.1" 72 | babel-runtime "^6.26.0" 73 | babel-types "^6.26.0" 74 | lodash "^4.17.4" 75 | 76 | babel-helper-function-name@^6.24.1: 77 | version "6.24.1" 78 | resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" 79 | dependencies: 80 | babel-helper-get-function-arity "^6.24.1" 81 | babel-runtime "^6.22.0" 82 | babel-template "^6.24.1" 83 | babel-traverse "^6.24.1" 84 | babel-types "^6.24.1" 85 | 86 | babel-helper-get-function-arity@^6.24.1: 87 | version "6.24.1" 88 | resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" 89 | dependencies: 90 | babel-runtime "^6.22.0" 91 | babel-types "^6.24.1" 92 | 93 | babel-helper-hoist-variables@^6.24.1: 94 | version "6.24.1" 95 | resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" 96 | dependencies: 97 | babel-runtime "^6.22.0" 98 | babel-types "^6.24.1" 99 | 100 | babel-helper-optimise-call-expression@^6.24.1: 101 | version "6.24.1" 102 | resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" 103 | dependencies: 104 | babel-runtime "^6.22.0" 105 | babel-types "^6.24.1" 106 | 107 | babel-helper-regex@^6.24.1: 108 | version "6.26.0" 109 | resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" 110 | dependencies: 111 | babel-runtime "^6.26.0" 112 | babel-types "^6.26.0" 113 | lodash "^4.17.4" 114 | 115 | babel-helper-remap-async-to-generator@^6.24.1: 116 | version "6.24.1" 117 | resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" 118 | dependencies: 119 | babel-helper-function-name "^6.24.1" 120 | babel-runtime "^6.22.0" 121 | babel-template "^6.24.1" 122 | babel-traverse "^6.24.1" 123 | babel-types "^6.24.1" 124 | 125 | babel-helper-replace-supers@^6.24.1: 126 | version "6.24.1" 127 | resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" 128 | dependencies: 129 | babel-helper-optimise-call-expression "^6.24.1" 130 | babel-messages "^6.23.0" 131 | babel-runtime "^6.22.0" 132 | babel-template "^6.24.1" 133 | babel-traverse "^6.24.1" 134 | babel-types "^6.24.1" 135 | 136 | babel-helpers@^6.24.1: 137 | version "6.24.1" 138 | resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" 139 | dependencies: 140 | babel-runtime "^6.22.0" 141 | babel-template "^6.24.1" 142 | 143 | babel-messages@^6.23.0: 144 | version "6.23.0" 145 | resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" 146 | dependencies: 147 | babel-runtime "^6.22.0" 148 | 149 | babel-plugin-check-es2015-constants@^6.22.0: 150 | version "6.22.0" 151 | resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" 152 | dependencies: 153 | babel-runtime "^6.22.0" 154 | 155 | babel-plugin-syntax-async-functions@^6.8.0: 156 | version "6.13.0" 157 | resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" 158 | 159 | babel-plugin-syntax-class-properties@^6.8.0: 160 | version "6.13.0" 161 | resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" 162 | 163 | babel-plugin-syntax-flow@^6.18.0: 164 | version "6.18.0" 165 | resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" 166 | 167 | babel-plugin-syntax-object-rest-spread@^6.8.0: 168 | version "6.13.0" 169 | resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" 170 | 171 | babel-plugin-syntax-trailing-function-commas@^6.22.0: 172 | version "6.22.0" 173 | resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" 174 | 175 | babel-plugin-transform-async-to-generator@^6.24.1: 176 | version "6.24.1" 177 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" 178 | dependencies: 179 | babel-helper-remap-async-to-generator "^6.24.1" 180 | babel-plugin-syntax-async-functions "^6.8.0" 181 | babel-runtime "^6.22.0" 182 | 183 | babel-plugin-transform-class-properties@^6.24.1: 184 | version "6.24.1" 185 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" 186 | dependencies: 187 | babel-helper-function-name "^6.24.1" 188 | babel-plugin-syntax-class-properties "^6.8.0" 189 | babel-runtime "^6.22.0" 190 | babel-template "^6.24.1" 191 | 192 | babel-plugin-transform-es2015-arrow-functions@^6.22.0: 193 | version "6.22.0" 194 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" 195 | dependencies: 196 | babel-runtime "^6.22.0" 197 | 198 | babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: 199 | version "6.22.0" 200 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" 201 | dependencies: 202 | babel-runtime "^6.22.0" 203 | 204 | babel-plugin-transform-es2015-block-scoping@^6.24.1: 205 | version "6.26.0" 206 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" 207 | dependencies: 208 | babel-runtime "^6.26.0" 209 | babel-template "^6.26.0" 210 | babel-traverse "^6.26.0" 211 | babel-types "^6.26.0" 212 | lodash "^4.17.4" 213 | 214 | babel-plugin-transform-es2015-classes@^6.24.1: 215 | version "6.24.1" 216 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" 217 | dependencies: 218 | babel-helper-define-map "^6.24.1" 219 | babel-helper-function-name "^6.24.1" 220 | babel-helper-optimise-call-expression "^6.24.1" 221 | babel-helper-replace-supers "^6.24.1" 222 | babel-messages "^6.23.0" 223 | babel-runtime "^6.22.0" 224 | babel-template "^6.24.1" 225 | babel-traverse "^6.24.1" 226 | babel-types "^6.24.1" 227 | 228 | babel-plugin-transform-es2015-computed-properties@^6.24.1: 229 | version "6.24.1" 230 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" 231 | dependencies: 232 | babel-runtime "^6.22.0" 233 | babel-template "^6.24.1" 234 | 235 | babel-plugin-transform-es2015-destructuring@^6.22.0: 236 | version "6.23.0" 237 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" 238 | dependencies: 239 | babel-runtime "^6.22.0" 240 | 241 | babel-plugin-transform-es2015-duplicate-keys@^6.24.1: 242 | version "6.24.1" 243 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" 244 | dependencies: 245 | babel-runtime "^6.22.0" 246 | babel-types "^6.24.1" 247 | 248 | babel-plugin-transform-es2015-for-of@^6.22.0: 249 | version "6.23.0" 250 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" 251 | dependencies: 252 | babel-runtime "^6.22.0" 253 | 254 | babel-plugin-transform-es2015-function-name@^6.24.1: 255 | version "6.24.1" 256 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" 257 | dependencies: 258 | babel-helper-function-name "^6.24.1" 259 | babel-runtime "^6.22.0" 260 | babel-types "^6.24.1" 261 | 262 | babel-plugin-transform-es2015-literals@^6.22.0: 263 | version "6.22.0" 264 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" 265 | dependencies: 266 | babel-runtime "^6.22.0" 267 | 268 | babel-plugin-transform-es2015-modules-amd@^6.24.1: 269 | version "6.24.1" 270 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" 271 | dependencies: 272 | babel-plugin-transform-es2015-modules-commonjs "^6.24.1" 273 | babel-runtime "^6.22.0" 274 | babel-template "^6.24.1" 275 | 276 | babel-plugin-transform-es2015-modules-commonjs@^6.24.1: 277 | version "6.26.0" 278 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" 279 | dependencies: 280 | babel-plugin-transform-strict-mode "^6.24.1" 281 | babel-runtime "^6.26.0" 282 | babel-template "^6.26.0" 283 | babel-types "^6.26.0" 284 | 285 | babel-plugin-transform-es2015-modules-systemjs@^6.24.1: 286 | version "6.24.1" 287 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" 288 | dependencies: 289 | babel-helper-hoist-variables "^6.24.1" 290 | babel-runtime "^6.22.0" 291 | babel-template "^6.24.1" 292 | 293 | babel-plugin-transform-es2015-modules-umd@^6.24.1: 294 | version "6.24.1" 295 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" 296 | dependencies: 297 | babel-plugin-transform-es2015-modules-amd "^6.24.1" 298 | babel-runtime "^6.22.0" 299 | babel-template "^6.24.1" 300 | 301 | babel-plugin-transform-es2015-object-super@^6.24.1: 302 | version "6.24.1" 303 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" 304 | dependencies: 305 | babel-helper-replace-supers "^6.24.1" 306 | babel-runtime "^6.22.0" 307 | 308 | babel-plugin-transform-es2015-parameters@^6.24.1: 309 | version "6.24.1" 310 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" 311 | dependencies: 312 | babel-helper-call-delegate "^6.24.1" 313 | babel-helper-get-function-arity "^6.24.1" 314 | babel-runtime "^6.22.0" 315 | babel-template "^6.24.1" 316 | babel-traverse "^6.24.1" 317 | babel-types "^6.24.1" 318 | 319 | babel-plugin-transform-es2015-shorthand-properties@^6.24.1: 320 | version "6.24.1" 321 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" 322 | dependencies: 323 | babel-runtime "^6.22.0" 324 | babel-types "^6.24.1" 325 | 326 | babel-plugin-transform-es2015-spread@^6.22.0: 327 | version "6.22.0" 328 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" 329 | dependencies: 330 | babel-runtime "^6.22.0" 331 | 332 | babel-plugin-transform-es2015-sticky-regex@^6.24.1: 333 | version "6.24.1" 334 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" 335 | dependencies: 336 | babel-helper-regex "^6.24.1" 337 | babel-runtime "^6.22.0" 338 | babel-types "^6.24.1" 339 | 340 | babel-plugin-transform-es2015-template-literals@^6.22.0: 341 | version "6.22.0" 342 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" 343 | dependencies: 344 | babel-runtime "^6.22.0" 345 | 346 | babel-plugin-transform-es2015-typeof-symbol@^6.22.0: 347 | version "6.23.0" 348 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" 349 | dependencies: 350 | babel-runtime "^6.22.0" 351 | 352 | babel-plugin-transform-es2015-unicode-regex@^6.24.1: 353 | version "6.24.1" 354 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" 355 | dependencies: 356 | babel-helper-regex "^6.24.1" 357 | babel-runtime "^6.22.0" 358 | regexpu-core "^2.0.0" 359 | 360 | babel-plugin-transform-flow-strip-types@^6.22.0: 361 | version "6.22.0" 362 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" 363 | dependencies: 364 | babel-plugin-syntax-flow "^6.18.0" 365 | babel-runtime "^6.22.0" 366 | 367 | babel-plugin-transform-object-rest-spread@^6.26.0: 368 | version "6.26.0" 369 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" 370 | dependencies: 371 | babel-plugin-syntax-object-rest-spread "^6.8.0" 372 | babel-runtime "^6.26.0" 373 | 374 | babel-plugin-transform-regenerator@^6.24.1: 375 | version "6.26.0" 376 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" 377 | dependencies: 378 | regenerator-transform "^0.10.0" 379 | 380 | babel-plugin-transform-strict-mode@^6.24.1: 381 | version "6.24.1" 382 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" 383 | dependencies: 384 | babel-runtime "^6.22.0" 385 | babel-types "^6.24.1" 386 | 387 | babel-preset-es2015@^6.24.1: 388 | version "6.24.1" 389 | resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" 390 | dependencies: 391 | babel-plugin-check-es2015-constants "^6.22.0" 392 | babel-plugin-transform-es2015-arrow-functions "^6.22.0" 393 | babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" 394 | babel-plugin-transform-es2015-block-scoping "^6.24.1" 395 | babel-plugin-transform-es2015-classes "^6.24.1" 396 | babel-plugin-transform-es2015-computed-properties "^6.24.1" 397 | babel-plugin-transform-es2015-destructuring "^6.22.0" 398 | babel-plugin-transform-es2015-duplicate-keys "^6.24.1" 399 | babel-plugin-transform-es2015-for-of "^6.22.0" 400 | babel-plugin-transform-es2015-function-name "^6.24.1" 401 | babel-plugin-transform-es2015-literals "^6.22.0" 402 | babel-plugin-transform-es2015-modules-amd "^6.24.1" 403 | babel-plugin-transform-es2015-modules-commonjs "^6.24.1" 404 | babel-plugin-transform-es2015-modules-systemjs "^6.24.1" 405 | babel-plugin-transform-es2015-modules-umd "^6.24.1" 406 | babel-plugin-transform-es2015-object-super "^6.24.1" 407 | babel-plugin-transform-es2015-parameters "^6.24.1" 408 | babel-plugin-transform-es2015-shorthand-properties "^6.24.1" 409 | babel-plugin-transform-es2015-spread "^6.22.0" 410 | babel-plugin-transform-es2015-sticky-regex "^6.24.1" 411 | babel-plugin-transform-es2015-template-literals "^6.22.0" 412 | babel-plugin-transform-es2015-typeof-symbol "^6.22.0" 413 | babel-plugin-transform-es2015-unicode-regex "^6.24.1" 414 | babel-plugin-transform-regenerator "^6.24.1" 415 | 416 | babel-preset-es2017@^6.24.1: 417 | version "6.24.1" 418 | resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.24.1.tgz#597beadfb9f7f208bcfd8a12e9b2b29b8b2f14d1" 419 | dependencies: 420 | babel-plugin-syntax-trailing-function-commas "^6.22.0" 421 | babel-plugin-transform-async-to-generator "^6.24.1" 422 | 423 | babel-register@^6.26.0: 424 | version "6.26.0" 425 | resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" 426 | dependencies: 427 | babel-core "^6.26.0" 428 | babel-runtime "^6.26.0" 429 | core-js "^2.5.0" 430 | home-or-tmp "^2.0.0" 431 | lodash "^4.17.4" 432 | mkdirp "^0.5.1" 433 | source-map-support "^0.4.15" 434 | 435 | babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: 436 | version "6.26.0" 437 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" 438 | dependencies: 439 | core-js "^2.4.0" 440 | regenerator-runtime "^0.11.0" 441 | 442 | babel-template@^6.24.1, babel-template@^6.26.0: 443 | version "6.26.0" 444 | resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" 445 | dependencies: 446 | babel-runtime "^6.26.0" 447 | babel-traverse "^6.26.0" 448 | babel-types "^6.26.0" 449 | babylon "^6.18.0" 450 | lodash "^4.17.4" 451 | 452 | babel-traverse@^6.24.1, babel-traverse@^6.26.0: 453 | version "6.26.0" 454 | resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" 455 | dependencies: 456 | babel-code-frame "^6.26.0" 457 | babel-messages "^6.23.0" 458 | babel-runtime "^6.26.0" 459 | babel-types "^6.26.0" 460 | babylon "^6.18.0" 461 | debug "^2.6.8" 462 | globals "^9.18.0" 463 | invariant "^2.2.2" 464 | lodash "^4.17.4" 465 | 466 | babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: 467 | version "6.26.0" 468 | resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" 469 | dependencies: 470 | babel-runtime "^6.26.0" 471 | esutils "^2.0.2" 472 | lodash "^4.17.4" 473 | to-fast-properties "^1.0.3" 474 | 475 | babylon@^6.18.0: 476 | version "6.18.0" 477 | resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" 478 | 479 | balanced-match@^1.0.0: 480 | version "1.0.0" 481 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 482 | 483 | brace-expansion@^1.1.7: 484 | version "1.1.8" 485 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" 486 | dependencies: 487 | balanced-match "^1.0.0" 488 | concat-map "0.0.1" 489 | 490 | chalk@^1.1.3: 491 | version "1.1.3" 492 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 493 | dependencies: 494 | ansi-styles "^2.2.1" 495 | escape-string-regexp "^1.0.2" 496 | has-ansi "^2.0.0" 497 | strip-ansi "^3.0.0" 498 | supports-color "^2.0.0" 499 | 500 | concat-map@0.0.1: 501 | version "0.0.1" 502 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 503 | 504 | convert-source-map@^1.5.0: 505 | version "1.5.0" 506 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" 507 | 508 | core-js@^2.4.0, core-js@^2.5.0: 509 | version "2.5.1" 510 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" 511 | 512 | debug@^2.6.8: 513 | version "2.6.8" 514 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 515 | dependencies: 516 | ms "2.0.0" 517 | 518 | detect-indent@^4.0.0: 519 | version "4.0.0" 520 | resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" 521 | dependencies: 522 | repeating "^2.0.0" 523 | 524 | escape-string-regexp@^1.0.2: 525 | version "1.0.5" 526 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 527 | 528 | esutils@^2.0.2: 529 | version "2.0.2" 530 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 531 | 532 | globals@^9.18.0: 533 | version "9.18.0" 534 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" 535 | 536 | has-ansi@^2.0.0: 537 | version "2.0.0" 538 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 539 | dependencies: 540 | ansi-regex "^2.0.0" 541 | 542 | home-or-tmp@^2.0.0: 543 | version "2.0.0" 544 | resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" 545 | dependencies: 546 | os-homedir "^1.0.0" 547 | os-tmpdir "^1.0.1" 548 | 549 | invariant@^2.2.2: 550 | version "2.2.2" 551 | resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" 552 | dependencies: 553 | loose-envify "^1.0.0" 554 | 555 | is-finite@^1.0.0: 556 | version "1.0.2" 557 | resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" 558 | dependencies: 559 | number-is-nan "^1.0.0" 560 | 561 | js-tokens@^3.0.0, js-tokens@^3.0.2: 562 | version "3.0.2" 563 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 564 | 565 | jsesc@^1.3.0: 566 | version "1.3.0" 567 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" 568 | 569 | jsesc@~0.5.0: 570 | version "0.5.0" 571 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" 572 | 573 | json5@^0.5.1: 574 | version "0.5.1" 575 | resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" 576 | 577 | lodash@^4.17.4: 578 | version "4.17.4" 579 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 580 | 581 | loose-envify@^1.0.0: 582 | version "1.3.1" 583 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" 584 | dependencies: 585 | js-tokens "^3.0.0" 586 | 587 | macaddress@^0.2.8: 588 | version "0.2.8" 589 | resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" 590 | 591 | minimatch@^3.0.4: 592 | version "3.0.4" 593 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 594 | dependencies: 595 | brace-expansion "^1.1.7" 596 | 597 | minimist@0.0.8: 598 | version "0.0.8" 599 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 600 | 601 | mkdirp@^0.5.1: 602 | version "0.5.1" 603 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 604 | dependencies: 605 | minimist "0.0.8" 606 | 607 | ms@2.0.0: 608 | version "2.0.0" 609 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 610 | 611 | number-is-nan@^1.0.0: 612 | version "1.0.1" 613 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 614 | 615 | os-homedir@^1.0.0: 616 | version "1.0.2" 617 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 618 | 619 | os-tmpdir@^1.0.1: 620 | version "1.0.2" 621 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 622 | 623 | path-is-absolute@^1.0.1: 624 | version "1.0.1" 625 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 626 | 627 | private@^0.1.6, private@^0.1.7: 628 | version "0.1.7" 629 | resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" 630 | 631 | regenerate@^1.2.1: 632 | version "1.3.2" 633 | resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" 634 | 635 | regenerator-runtime@^0.11.0: 636 | version "0.11.0" 637 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" 638 | 639 | regenerator-transform@^0.10.0: 640 | version "0.10.1" 641 | resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" 642 | dependencies: 643 | babel-runtime "^6.18.0" 644 | babel-types "^6.19.0" 645 | private "^0.1.6" 646 | 647 | regexpu-core@^2.0.0: 648 | version "2.0.0" 649 | resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" 650 | dependencies: 651 | regenerate "^1.2.1" 652 | regjsgen "^0.2.0" 653 | regjsparser "^0.1.4" 654 | 655 | regjsgen@^0.2.0: 656 | version "0.2.0" 657 | resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" 658 | 659 | regjsparser@^0.1.4: 660 | version "0.1.5" 661 | resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" 662 | dependencies: 663 | jsesc "~0.5.0" 664 | 665 | repeating@^2.0.0: 666 | version "2.0.1" 667 | resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" 668 | dependencies: 669 | is-finite "^1.0.0" 670 | 671 | slash@^1.0.0: 672 | version "1.0.0" 673 | resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" 674 | 675 | source-map-support@^0.4.15: 676 | version "0.4.18" 677 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" 678 | dependencies: 679 | source-map "^0.5.6" 680 | 681 | source-map@^0.5.6: 682 | version "0.5.7" 683 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 684 | 685 | strip-ansi@^3.0.0: 686 | version "3.0.1" 687 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 688 | dependencies: 689 | ansi-regex "^2.0.0" 690 | 691 | supports-color@^2.0.0: 692 | version "2.0.0" 693 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 694 | 695 | to-fast-properties@^1.0.3: 696 | version "1.0.3" 697 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" 698 | 699 | trim-right@^1.0.1: 700 | version "1.0.1" 701 | resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" 702 | 703 | uniqid@^4.1.1: 704 | version "4.1.1" 705 | resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" 706 | dependencies: 707 | macaddress "^0.2.8" 708 | --------------------------------------------------------------------------------