From e902941f09202b312affca2b3d87cb7e1fd798c8 Mon Sep 17 00:00:00 2001 From: lukasz_brainhub Date: Mon, 18 Sep 2017 16:00:06 +0200 Subject: [PATCH] Readme updates, updated defaultPlugin, added immutablyCopyValue tool, small cody style fixes --- README.MD | 4 ---- docs/defaultPlugin.md | 5 +++-- docs/gettingStarted.md | 2 +- src/defaultPlugin.js | 16 ++++++++++++---- src/index.js | 10 +++++++++- src/tools.js | 12 ++++++++++++ test/reduxBreeze.js | 32 +++++++++++++------------------- 7 files changed, 50 insertions(+), 31 deletions(-) diff --git a/README.MD b/README.MD index f56f9b0..e90765c 100644 --- a/README.MD +++ b/README.MD @@ -103,10 +103,6 @@ All pull requests are appreciated as long as the code is well tested, documented You may grab a thing from todo (see below) or write plugins for your use-case. ## Todo - * make readme great again: - * document config (not a big thing ;) ) - * add basic usage tutorial - * add plugins tutorial * add tests to default plugin * write action definitions validation (by default only checking for 'type' field, but make it plugin enabled) * add more plugins: diff --git a/docs/defaultPlugin.md b/docs/defaultPlugin.md index 8924964..4f038d4 100644 --- a/docs/defaultPlugin.md +++ b/docs/defaultPlugin.md @@ -122,8 +122,9 @@ And it's just the beginning! :) - **initialValue** *any* value that is going to be used in initial state in *targetPath* - **defaultValue** *any* value that is going to be used when not provided in the action - **result**: *string|array<{sourcePath: string, targetPath: string, initialValue: any, defaultValue, any, result: string}>* type of the result; if 'list' then initialValue will be emtpy string by default; if 'entity' default initial value will be null; - - **sourcePath** *string* path from action the data is going to be taken from, can be nested e.g. 'payload.someField.someSubField' - - **targetPath** *string* path in reducer's state, the data is going to be saved in, can be nested e.g. 'someField.someSubField' + - **sourcePath** *string|function(action)* path from action the data is going to be taken from, can be nested e.g. 'payload.someField.someSubField', or function that returns that path + - **targetPath** *string|function(action)* path in reducer's state, the data is going to be saved in, can be nested e.g. 'someField.someSubField' or function that returns that path - **initialValue** *any* value that is going to be used in initial state in *targetPath* - **defaultValue** *any* value that is going to be used when not provided in the action - **result** *string* when initialValue not provided, it will be based on *result*; if 'list' the initialValue is going to be empty array; if 'entity' the initialValue is going to be null + - **value** *function(action, currentValue)|any* function that gets an action object and current state value (based on targetPath) and returns value to be saved, or hardcoded value to be set diff --git a/docs/gettingStarted.md b/docs/gettingStarted.md index c9face1..fe35c3a 100644 --- a/docs/gettingStarted.md +++ b/docs/gettingStarted.md @@ -19,7 +19,7 @@ Change this code: import { createStore, combineReducers } from 'redux'; import myCustomReducers from 'myCustomReducers.js'; -const store = createStore(combineReducer(myCustomRedcuers)); +const store = createStore(combineReducer(myCustomReducers)); ``` to this: diff --git a/src/defaultPlugin.js b/src/defaultPlugin.js index 4670a0f..db3b2d1 100644 --- a/src/defaultPlugin.js +++ b/src/defaultPlugin.js @@ -37,12 +37,16 @@ const createDefaultPlugin = ({ createActionType, immutableSet }, config) => ({ } ) => { // setting default value if one has not been provided and defaultValue is defined - if (!(defaultValue instanceof hasNotBeenDefined) && _.isUndefined(_.get(action, sourcePath))) { - accu[targetPath] = defaultValue; + if ( + !(defaultValue instanceof hasNotBeenDefined) + && _.isUndefined(_.get(action, sourcePath)) + && value instanceof hasNotBeenDefined + ) { + accu[targetPath] = _.isFunction(defaultValue) ? defaultValue(action) : defaultValue; // setting value based on sourcePath } else if (value instanceof hasNotBeenDefined) { - accu[targetPath] = _.get(action, sourcePath); + accu[targetPath] = _.get(action, _.isFunction(sourcePath) ? sourcePath(action) : sourcePath); // setting value calculated by a 'value' function } else if (_.isFunction(value)) { @@ -62,7 +66,11 @@ const createDefaultPlugin = ({ createActionType, immutableSet }, config) => ({ const resultName = actionDefinition.resultName || actionName; // setting default value if one has not been provided and defaultValue is defined - if (!_.has(actionDefinition, 'defaultValue') && _.isUndefined(action.payload)) { + if ( + _.has(actionDefinition, 'defaultValue') + && _.isUndefined(action.payload) + && _.has() + ) { resultsAssignments = { [resultName]: actionDefinition.defaultValue }; } else if (!_.has(actionDefinition, 'value')) { resultsAssignments = { [resultName]: action.payload }; diff --git a/src/index.js b/src/index.js index d20f877..fe82fe8 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,13 @@ import _ from 'lodash'; import { combineReducers } from 'redux'; -import { immutableSet, createActionType, chainReducers, mergePlugins, checkConflicts } from './tools'; +import { + immutableSet, + createActionType, + chainReducers, + mergePlugins, + checkConflicts, + immutablyCopyValue, +} from './tools'; import createDefaultPlugin from './defaultPlugin'; const defaultConfig = { @@ -24,6 +31,7 @@ export const tools = { chainReducers, mergePlugins, checkConflicts, + immutablyCopyValue, }; const createReduxBreezeInstance = (actionDefinitions, userConfig = defaultConfig, ...plugins) => { diff --git a/src/tools.js b/src/tools.js index 87688b2..0478286 100644 --- a/src/tools.js +++ b/src/tools.js @@ -156,3 +156,15 @@ export const immutableSet = (object, path, value = null, delimiter = '.') => { [pathSplit[0]]: immutableSet(childObject, _.tail(pathSplit).join(delimiter), value, delimiter), }; }; + +/** + * Copy value from fromPath in fromObject and create new object from toObject with that value saved in toPath + * @param {object} fromObject object which you get the value from + * @param {string} fromPath path in fromObject where you get tha value from + * @param {object} toObject object where you save the value to + * @param {string} toPath path in toObject where you save the value + * @return {object} new object created from values in toObject + */ +export const immutablyCopyValue = (fromObject, fromPath, toObject, toPath) => { + return immutableSet(toObject, toPath, _.get(fromObject, fromPath)); +}; diff --git a/test/reduxBreeze.js b/test/reduxBreeze.js index 0c17490..99a49d4 100644 --- a/test/reduxBreeze.js +++ b/test/reduxBreeze.js @@ -16,12 +16,10 @@ const testPlugin = ({ createActionType, immutableSet }) => ({ */ actionAdapter: { test(definition, actionName) { - return (params) => { - return { - params, - somethingMore: 'someMoreValue', - }; - }; + return params => ({ + params, + somethingMore: 'someMoreValue', + }); }, }, @@ -57,9 +55,8 @@ const testPlugin = ({ createActionType, immutableSet }) => ({ }); - describe('reduxBreeze', () => { - let nativeConsoleWarn = console.warn; + const nativeConsoleWarn = console.warn; before(() => { console.warn = () => {}; }); @@ -197,9 +194,7 @@ describe('reduxBreeze', () => { const plugin1 = () => plugin1Value; const plugin2 = () => plugin2Value; - const mapActionTypes = (actionType, pluginName, adapterType) => { - return pluginName === 'plugin2' ? `plugin2${actionType}` : actionType; - }; + const mapActionTypes = (actionType, pluginName, adapterType) => pluginName === 'plugin2' ? `plugin2${actionType}` : actionType; const reduxBreezeInstance = createReduxBreezeInstance({}, { useDefaultPlugin: false, mapActionTypes }, plugin1, plugin2); expect(reduxBreezeInstance.getMergedPlugin()).to.nested.include({ @@ -224,7 +219,7 @@ describe('reduxBreeze', () => { someOtherAction: { type: 'test', }, - } + }, }; const expectedInitialState = { exampleReducer: { @@ -234,7 +229,7 @@ describe('reduxBreeze', () => { exampleReducer2: { someOtherAction: null, field: 1, - } + }, }; const reduxBreezeInstance = createReduxBreezeInstance(actionDefinitions, { useDefaultPlugin: false }, testPlugin); @@ -249,11 +244,10 @@ describe('reduxBreeze', () => { exampleReducer2: { someOtherAction: 'SOMETHING', field: 2, - } + }, }); }); it('should merge generated reducers with custom ones with combineReducer function with argument', () => { - const actionDefinitions = { exampleReducer: { someAction: { @@ -264,7 +258,7 @@ describe('reduxBreeze', () => { someOtherAction: { type: 'test', }, - } + }, }; const customInitialState = { customField: 1, @@ -278,7 +272,7 @@ describe('reduxBreeze', () => { exampleReducer2: { someOtherAction: null, field: 1, - } + }, }; const customReducer = (state = customInitialState, action) => { @@ -306,7 +300,7 @@ describe('reduxBreeze', () => { exampleReducer2: { someOtherAction: 'SOMETHING', field: 2, - } + }, }); }); it('should throw an error when provided with action that cannot be handled by applied plugins', () => { @@ -320,7 +314,7 @@ describe('reduxBreeze', () => { unhandledAction: { type: 'unhandled', }, - } + }, }; const reduxBreezeInstance = createReduxBreezeInstance(actionDefinitions, { useDefaultPlugin: false }, testPlugin);