Tweaks to flow types
This commit is contained in:
parent
69a0d3c616
commit
00087c751d
60
src/index.js
60
src/index.js
|
@ -1,5 +1,5 @@
|
|||
import { buildReducers } from './redux-arg/buildReducers';
|
||||
import { createStore, compose } from 'redux';
|
||||
import { createStore, compose, combineReducers } from 'redux';
|
||||
import { Types } from './redux-arg/structure';
|
||||
|
||||
const exampleReducer = {
|
||||
|
@ -30,26 +30,62 @@ const exampleReducer = {
|
|||
arrayTest: Types.reducer(Types.arrayOf(
|
||||
Types.number(),
|
||||
[1,3,4]
|
||||
))
|
||||
)),
|
||||
primitiveTest: Types.reducer(Types.number(4)),
|
||||
})
|
||||
};
|
||||
|
||||
const exampleReducer2 = {
|
||||
screen: Types.reducer(Types.shape({
|
||||
handlerIsCBS: Types.boolean(true),
|
||||
handlerIsENG: Types.boolean(true),
|
||||
invoices: Types.arrayOf(Types.string()),
|
||||
activeInvoice: Types.number(-1),
|
||||
deleteInvoiceModalActive: Types.boolean(),
|
||||
suppInvoiceModalActive: Types.boolean(),
|
||||
paymentModalActive: Types.boolean(),
|
||||
resetModalActive: Types.boolean(),
|
||||
reinstateModalActive: Types.boolean(),
|
||||
})),
|
||||
delete: Types.reducer(Types.shape({
|
||||
invoiceSequence: Types.number(),
|
||||
vehicleSequence: Types.number(),
|
||||
deleteReason: Types.string(),
|
||||
})),
|
||||
supp: Types.reducer(Types.shape({
|
||||
invoiceSequence: Types.number(),
|
||||
vehicleSequence: Types.number(),
|
||||
mode: Types.string(),
|
||||
amount: Types.string(),
|
||||
})),
|
||||
};
|
||||
|
||||
const test = buildReducers('example', exampleReducer);
|
||||
const test2 = buildReducers('invoices', exampleReducer2);
|
||||
|
||||
const store = createStore(
|
||||
test.reducers,
|
||||
combineReducers({
|
||||
example: test.reducers,
|
||||
invoices: test2.reducers,
|
||||
}),
|
||||
compose(window.devToolsExtension ? window.devToolsExtension() : f => f)
|
||||
);
|
||||
|
||||
store.dispatch(test.actionsObject.example.form2.update({ lowerLevel: 2, lowerLevel2: 'Rawrg', lowerLevelArray: [3, 'foo'] }));
|
||||
store.dispatch(test.actionsObject.example.form2.reset());
|
||||
store.dispatch(test.actionsObject.example.form2.replace({ toast: 'nommyNom' }));
|
||||
store.dispatch(test.actionsObject.example.form2.reset());
|
||||
store.dispatch(test.actions.example.form2.update({ lowerLevel: 2, lowerLevel2: 'Rawrg', lowerLevelArray: [3, 'foo'] }));
|
||||
store.dispatch(test.actions.example.form2.reset());
|
||||
store.dispatch(test.actions.example.form2.replace({ toast: 'nommyNom' }));
|
||||
store.dispatch(test.actions.example.form2.reset());
|
||||
|
||||
console.log(111, test.selectorsObject.example.form2(store.getState()));
|
||||
console.log(222, test.actionsObject);
|
||||
console.log(111, test.selectors.example.form2(store.getState()));
|
||||
console.log(222, test.actions);
|
||||
console.log(333, test.selectors);
|
||||
console.log(444, test.selectors.example.primitiveTest(store.getState()));
|
||||
console.log(555, test2.selectors, test2.actions);
|
||||
console.log(666, test2.selectors.screen(store.getState()));
|
||||
|
||||
store.dispatch(test.actionsObject.example.arrayTest.replace([1,2,3]));
|
||||
store.dispatch(test.actionsObject.example.arrayTest.updateAtIndex(5, 0));
|
||||
store.dispatch(test.actionsObject.example.arrayTest.updateAtIndex('foo', 0));
|
||||
store.dispatch(test.actions.example.arrayTest.replace([1,2,3]));
|
||||
store.dispatch(test.actions.example.arrayTest.updateAtIndex(5, 0));
|
||||
store.dispatch(test.actions.example.arrayTest.updateAtIndex('foo', 0));
|
||||
|
||||
store.dispatch(test.actions.example.primitiveTest.update(5));
|
||||
store.dispatch(test.actions.example.primitiveTest.reset());
|
||||
|
|
|
@ -10,8 +10,9 @@ import { reduce, find } from 'lodash';
|
|||
import { createReducer } from './reducers';
|
||||
import { PROP_TYPES } from './structure';
|
||||
|
||||
|
||||
export function buildReducers(name: string, structure: any, {
|
||||
baseSelector = state => state,
|
||||
baseSelector = state => state[name],
|
||||
locationString = '',
|
||||
}: {
|
||||
baseSelector: any,
|
||||
|
@ -24,8 +25,8 @@ export function buildReducers(name: string, structure: any, {
|
|||
//returned to the call site for use in the rest of the application.
|
||||
const temp = reduce(structure, processStructure, {
|
||||
reducers: {},
|
||||
actionsObject: {},
|
||||
selectorsObject: {},
|
||||
actions: {},
|
||||
selectors: {},
|
||||
});
|
||||
|
||||
//The Redux 'combineReducers' helper function is used here to save a little bit of boilerplate.
|
||||
|
@ -63,13 +64,13 @@ export function buildReducers(name: string, structure: any, {
|
|||
...memo.reducers,
|
||||
[propName]: childReducer.reducers,
|
||||
},
|
||||
actionsObject: {
|
||||
...memo.actionsObject,
|
||||
[propName]: childReducer.actionsObject,
|
||||
actions: {
|
||||
...memo.actions,
|
||||
[propName]: childReducer.actions,
|
||||
},
|
||||
selectorsObject: {
|
||||
...memo.selectorsObject,
|
||||
[propName]: containsReducers ? childReducer.selectorsObject : state => baseSelector(state)[propName],
|
||||
selectors: {
|
||||
...memo.selectors,
|
||||
[propName]: containsReducers ? childReducer.selectors : state => baseSelector(state)[propName],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,10 +12,12 @@ import type {
|
|||
//==============================
|
||||
export type PartialReducer = {
|
||||
reducers: { [key: string]: any },
|
||||
actionsObject: { [key: string]: any },
|
||||
selectorsObject?: { [key: string]: any },
|
||||
actions: { [key: string]: any },
|
||||
selectors: { [key: string]: any },
|
||||
};
|
||||
|
||||
export type Selector = (state: Object) => any;
|
||||
|
||||
import {
|
||||
PROP_TYPES,
|
||||
} from './structure';
|
||||
|
@ -23,6 +25,7 @@ import { compose } from 'ramda';
|
|||
import { reduce } from 'lodash';
|
||||
import { createObjectReducer } from './reducers/objectReducer';
|
||||
import { createArrayReducer } from './reducers/arrayReducer';
|
||||
import { createPrimitiveReducer } from './reducers/primitiveReducer';
|
||||
|
||||
|
||||
function determineReducerType(reducerDescriptor, {
|
||||
|
@ -31,9 +34,9 @@ function determineReducerType(reducerDescriptor, {
|
|||
const REDUCERS = {
|
||||
[PROP_TYPES._shape]: createObjectReducer,
|
||||
[PROP_TYPES._array]: createArrayReducer,
|
||||
[PROP_TYPES._boolean]: () => {},
|
||||
[PROP_TYPES._string]: () => {},
|
||||
[PROP_TYPES._number]: () => {},
|
||||
[PROP_TYPES._boolean]: createPrimitiveReducer,
|
||||
[PROP_TYPES._string]: createPrimitiveReducer,
|
||||
[PROP_TYPES._number]: createPrimitiveReducer,
|
||||
};
|
||||
const { structure } = reducerDescriptor();
|
||||
const { type } = structure();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//==============================
|
||||
// Flow imports
|
||||
//==============================
|
||||
import type { StructureType, ArrayStructureType } from '../structure';
|
||||
import type { ArrayStructureType } from '../structure';
|
||||
|
||||
//==============================
|
||||
// Flow types
|
||||
|
@ -100,7 +100,7 @@ export function createArrayReducer(arrayTypeDescription: ArrayStructureType, {
|
|||
}: ArrayReducerOptions = {}) {
|
||||
return {
|
||||
reducers: createReducer(arrayTypeDescription, createReducerBehaviors(DEFAULT_ARRAY_BEHAVIORS, locationString)),
|
||||
actionsObject: createActions(DEFAULT_ARRAY_BEHAVIORS, locationString, {}),
|
||||
actions: createActions(DEFAULT_ARRAY_BEHAVIORS, locationString, {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ function createActions(behaviorsConfig: ArrayReducerBehaviorsConfig, locationStr
|
|||
...memo,
|
||||
[name]: (value: Array<any>, index: ?number) => ({
|
||||
type: `${locationString}.${name}`,
|
||||
payload: (behavior.action || (() => value))(value) || [],
|
||||
payload: (behavior.action || (() => value))(value),
|
||||
index,
|
||||
})
|
||||
}), {});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//==============================
|
||||
// Flow imports
|
||||
//==============================
|
||||
import type { ShapeStructure, StructureType } from '../structure';
|
||||
import type { StructureType } from '../structure';
|
||||
|
||||
//==============================
|
||||
// Flow types
|
||||
|
@ -11,7 +11,6 @@ export type ObjectReducerAction = {
|
|||
type: string,
|
||||
payload: Object,
|
||||
};
|
||||
export type ObjectReducerFactory = (reducerStructure: ShapeStructure) => ObjectReducer;
|
||||
export type ObjectReducer = (state: Object, action: ObjectReducerAction) => Object;
|
||||
export type ObjectReducerBehavior = (state: Object, payload: Object | void, initialState: Object) => Object;
|
||||
export type ObjectReducerBehaviorsConfig = {
|
||||
|
@ -31,7 +30,6 @@ export type ObjectReducerOptions = {
|
|||
behaviorsConfig: ObjectReducerBehaviorsConfig,
|
||||
locationString: string,
|
||||
};
|
||||
export type ObjectSelector = (state: Object) => Object;
|
||||
|
||||
//==============================
|
||||
// JS imports
|
||||
|
@ -66,7 +64,7 @@ export function createObjectReducer(reducerShape: StructureType, {
|
|||
}: ObjectReducerOptions = {}) {
|
||||
return {
|
||||
reducers: createReducer(reducerShape, createReducerBehaviors(DEFAULT_OBJECT_BEHAVIORS, locationString)),
|
||||
actionsObject: createActions(DEFAULT_OBJECT_BEHAVIORS, locationString, {}),
|
||||
actions: createActions(DEFAULT_OBJECT_BEHAVIORS, locationString, {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -100,7 +98,7 @@ function createActions(behaviorsConfig: ObjectReducerBehaviorsConfig, locationSt
|
|||
...memo,
|
||||
[name]: (value: Object) => ({
|
||||
type: `${locationString}.${name}`,
|
||||
payload: (behavior.action || (() => defaultPayload))(value) || {}
|
||||
payload: (behavior.action || (() => defaultPayload))(value),
|
||||
})
|
||||
}), {});
|
||||
}
|
||||
|
|
|
@ -1 +1,92 @@
|
|||
//@flow
|
||||
//==============================
|
||||
// Flow imports
|
||||
//==============================
|
||||
import type { PrimitiveType } from '../structure';
|
||||
|
||||
//==============================
|
||||
// Flow types
|
||||
//==============================
|
||||
export type PrimitiveReducerAction = {
|
||||
type: string,
|
||||
payload: mixed,
|
||||
};
|
||||
export type PrimitiveReducer = (state: mixed, action: PrimitiveReducerAction) => mixed;
|
||||
export type PrimitiveReducerBehavior = (state: mixed, payload: mixed | void, initialState: mixed) => mixed;
|
||||
export type PrimitiveReducerBehaviorsConfig = {
|
||||
[key: string]: {
|
||||
action?: (value: mixed) => mixed,
|
||||
reducer: PrimitiveReducerBehavior,
|
||||
}
|
||||
};
|
||||
export type PrimitiveReducerBehaviors = {
|
||||
[key: string]: PrimitiveReducerBehavior,
|
||||
};
|
||||
export type PrimitiveAction = (value: mixed) => { type: string, payload: mixed };
|
||||
export type PrimitiveActions = {
|
||||
[key: string]: PrimitiveAction
|
||||
};
|
||||
export type PrimitiveReducerOptions = {
|
||||
behaviorsConfig: PrimitiveReducerBehaviorsConfig,
|
||||
locationString: string,
|
||||
};
|
||||
|
||||
//==============================
|
||||
// JS imports
|
||||
//==============================
|
||||
import { reduce } from 'lodash';
|
||||
import { validatePrimitive } from '../validatePayload';
|
||||
import { createReducerBehaviors } from '../reducers';
|
||||
|
||||
const DEFAULT_PRIMITIVE_BEHAVIORS: PrimitiveReducerBehaviorsConfig = {
|
||||
update: {
|
||||
action(value) { return value },
|
||||
reducer(state, payload) {
|
||||
if (payload === undefined) return state;
|
||||
return payload;
|
||||
}
|
||||
},
|
||||
reset: {
|
||||
reducer(state, payload, initialState) {
|
||||
return initialState;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
export function createPrimitiveReducer(primitiveType: PrimitiveType, {
|
||||
locationString
|
||||
}: PrimitiveReducerOptions = {}) {
|
||||
return {
|
||||
reducers: createReducer(primitiveType, createReducerBehaviors(DEFAULT_PRIMITIVE_BEHAVIORS, locationString)),
|
||||
actions: createActions(DEFAULT_PRIMITIVE_BEHAVIORS, locationString, {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function createReducer(primitiveType: PrimitiveType, behaviors: PrimitiveReducerBehaviors): PrimitiveReducer {
|
||||
const initialState: mixed = validatePrimitive(primitiveType, primitiveType().defaultValue);
|
||||
return (state = initialState, { type, payload }: PrimitiveReducerAction) => {
|
||||
//If the action type does not match any of the specified behaviors, just return the current state.
|
||||
if (!behaviors[type]) return state;
|
||||
|
||||
//Sanitize the payload using the reducer shape, then apply the sanitized
|
||||
//payload to the state using the behavior linked to this action type.
|
||||
return behaviors[type](state, validatePrimitive(primitiveType, payload), initialState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function createActions(behaviorsConfig: PrimitiveReducerBehaviorsConfig, locationString: string, defaultPayload: any): PrimitiveActions {
|
||||
//Take a reducer behavior config object, and create actions using the location string
|
||||
return reduce(behaviorsConfig, (memo, behavior, name) => ({
|
||||
...memo,
|
||||
[name]: (value: mixed) => ({
|
||||
type: `${locationString}.${name}`,
|
||||
payload: (behavior.action || (() => defaultPayload))(value),
|
||||
})
|
||||
}), {});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Flow types
|
||||
//==============================
|
||||
export type ShapeStructure = {
|
||||
[key: string]: StructureType | PrimitiveType,
|
||||
[key: string]: StructureType | PrimitiveType | ArrayStructureType,
|
||||
}
|
||||
export type StructureType = () => {
|
||||
type: string,
|
||||
|
|
Loading…
Reference in New Issue