wip
This commit is contained in:
parent
bb5218d2f6
commit
3aac2e092e
@ -63,7 +63,7 @@ import Updux from 'updux';
|
||||
const updux = new Updux({
|
||||
initial: { counter: 0 },
|
||||
mutations: {
|
||||
add: (inc=1) => state => { counter: counter + inc }
|
||||
add: (inc=1) => state => ({ counter: state.counter + inc })
|
||||
}
|
||||
});
|
||||
|
||||
@ -74,7 +74,7 @@ Converting it to Immer would look like:
|
||||
|
||||
```
|
||||
import Updux from 'updux';
|
||||
import { produce } from 'Immer';
|
||||
import { produce } from 'immer';
|
||||
|
||||
const updux = new Updux({
|
||||
initial: { counter: 0 },
|
||||
@ -91,7 +91,7 @@ can be used to wrap all mutations with it:
|
||||
|
||||
```
|
||||
import Updux from 'updux';
|
||||
import { produce } from 'Immer';
|
||||
import { produce } from 'immer';
|
||||
|
||||
const updux = new Updux({
|
||||
initial: { counter: 0 },
|
||||
|
@ -1,7 +1,9 @@
|
||||
{
|
||||
"type": "module",
|
||||
"types": "./dist",
|
||||
"dependencies": {
|
||||
"@yanick/updeep": "link:../updeep",
|
||||
"lodash": "^4.17.15",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moize": "^6.1.0",
|
||||
"redux": "^4.0.5",
|
||||
@ -39,10 +41,10 @@
|
||||
"ts-node": "^8.10.2",
|
||||
"tsd": "^0.17.0",
|
||||
"typedoc": "0.22.5",
|
||||
"typescript": "^4.4.3"
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "src/index.js",
|
||||
"main": "dist/index.js",
|
||||
"name": "updux",
|
||||
"description": "Updeep-friendly Redux helper framework",
|
||||
"scripts": {
|
||||
@ -66,7 +68,6 @@
|
||||
"url": "https://github.com/yanick/updux/issues"
|
||||
},
|
||||
"homepage": "https://github.com/yanick/updux#readme",
|
||||
"types": "./dist/index.d.ts",
|
||||
"prettier": {
|
||||
"tabWidth": 4,
|
||||
"singleQuote": true,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Updux } from './Updux';
|
||||
import { action } from './actions';
|
||||
import { Updux } from './Updux.js';
|
||||
import { action } from './actions.js';
|
||||
|
||||
test('basic state', () => {
|
||||
const alpha = new Updux({
|
||||
@ -96,8 +96,8 @@ test('basic selectors', () => {
|
||||
test('mutations', () => {
|
||||
const alpha = new Updux({
|
||||
initial: { quux: 3 },
|
||||
actions: { add: (x:number)=>x },
|
||||
});
|
||||
alpha.setAction('add');
|
||||
alpha.setMutation('add', (toAdd) => (state) => ({
|
||||
quux: state.quux + toAdd,
|
||||
}));
|
||||
@ -108,8 +108,10 @@ test('mutations', () => {
|
||||
bar: 4,
|
||||
},
|
||||
subduxes: { alpha },
|
||||
actions: {
|
||||
subtract: ()=>{},
|
||||
}
|
||||
});
|
||||
dux.setAction('subtract');
|
||||
dux.setMutation('add', (toAdd) => (state) => ({
|
||||
...state,
|
||||
foo: state.foo + toAdd,
|
||||
|
69
src/Updux.ts
69
src/Updux.ts
@ -1,15 +1,19 @@
|
||||
/* TODO change * for leftovers to +, change subscriptions to reactions */
|
||||
import moize from 'moize';
|
||||
import u from '@yanick/updeep';
|
||||
import u from 'updeep';
|
||||
import { createStore as reduxCreateStore, applyMiddleware } from 'redux';
|
||||
import { get, map, mapValues, merge, difference } from 'lodash';
|
||||
import { get, map, mapValues, merge, difference } from 'lodash-es';
|
||||
|
||||
import { buildInitial } from './buildInitial';
|
||||
import { buildActions } from './buildActions';
|
||||
import { buildSelectors } from './buildSelectors';
|
||||
import { action } from './actions';
|
||||
import { buildUpreducer } from './buildUpreducer';
|
||||
import { buildMiddleware, augmentMiddlewareApi } from './buildMiddleware';
|
||||
import { buildInitial } from './buildInitial/index.js';
|
||||
import { buildActions } from './buildActions/index.js';
|
||||
import { buildSelectors } from './buildSelectors/index.js';
|
||||
import { action } from './actions.js';
|
||||
import { buildUpreducer } from './buildUpreducer.js';
|
||||
import {
|
||||
buildMiddleware,
|
||||
augmentMiddlewareApi,
|
||||
effectToMiddleware,
|
||||
} from './buildMiddleware/index.js';
|
||||
|
||||
import {
|
||||
AggregateDuxActions,
|
||||
@ -18,7 +22,9 @@ import {
|
||||
ItemsOf,
|
||||
Reducer,
|
||||
Upreducer,
|
||||
} from './types';
|
||||
} from './types.js';
|
||||
|
||||
type Mutation<TState,TAction extends { payload?: any }> = (payload:TAction['payload'], action:TAction) => (state: TState) => TState;
|
||||
|
||||
/**
|
||||
* Configuration object typically passed to the constructor of the class Updux.
|
||||
@ -99,6 +105,8 @@ export interface UpduxConfig<
|
||||
AggregateDuxState<TState, TSubduxes>,
|
||||
ItemsOf<AggregateDuxActions<TActions, TSubduxes>>
|
||||
>;
|
||||
|
||||
middlewareWrapper?: Function;
|
||||
}
|
||||
|
||||
export class Updux<
|
||||
@ -121,7 +129,11 @@ export class Updux<
|
||||
#mappedReaction = undefined;
|
||||
#upreducerWrapper = undefined;
|
||||
|
||||
constructor(config: UpduxConfig<TState, TActions, TSelectors, TSubduxes>) {
|
||||
#middlewareWrapper = undefined;
|
||||
|
||||
constructor(
|
||||
config: UpduxConfig<TState, TActions, TSelectors, TSubduxes>
|
||||
) {
|
||||
this.#initial = config.initial ?? {};
|
||||
this.#subduxes = config.subduxes ?? {};
|
||||
|
||||
@ -165,6 +177,8 @@ export class Updux<
|
||||
this.#mappedReaction = config.mappedReaction;
|
||||
|
||||
this.#upreducerWrapper = config.upreducerWrapper;
|
||||
|
||||
this.#middlewareWrapper = config.middlewareWrapper;
|
||||
}
|
||||
|
||||
#memoInitial = moize(buildInitial);
|
||||
@ -185,10 +199,16 @@ export class Updux<
|
||||
this.#effects,
|
||||
this.actions,
|
||||
this.selectors,
|
||||
this.#subduxes
|
||||
this.#subduxes,
|
||||
this.#middlewareWrapper,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
setMiddlewareWrapper(wrapper: Function) {
|
||||
this.#middlewareWrapper = wrapper;
|
||||
}
|
||||
|
||||
/** @member { unknown } */
|
||||
get initial(): AggregateDuxState<TState, TSubduxes> {
|
||||
return this.#memoInitial(this.#initial, this.#subduxes);
|
||||
@ -206,6 +226,8 @@ export class Updux<
|
||||
);
|
||||
}
|
||||
|
||||
get subduxes() { return this.#subduxes }
|
||||
|
||||
get upreducer(): Upreducer<
|
||||
AggregateDuxState<TState, TSubduxes>,
|
||||
ItemsOf<AggregateDuxActions<TActions, TSubduxes>>
|
||||
@ -229,6 +251,11 @@ export class Updux<
|
||||
this.#reactions = [...this.#reactions, subscription];
|
||||
}
|
||||
|
||||
addReaction(reaction) {
|
||||
this.#reactions = [...this.#reactions, reaction];
|
||||
}
|
||||
|
||||
|
||||
setAction(type, payloadFunc?: (...args: any) => any) {
|
||||
const theAction = action(type, payloadFunc);
|
||||
|
||||
@ -246,7 +273,8 @@ export class Updux<
|
||||
return func;
|
||||
}
|
||||
|
||||
setMutation(name, mutation) {
|
||||
setMutation<TAction extends keyof AggregateDuxActions<TActions,TSubduxes>>(name: TAction, mutation: Mutation<AggregateDuxState<TState, TSubduxes>,
|
||||
ReturnType<AggregateDuxActions<TActions,TSubduxes>[TAction]>>) {
|
||||
if (typeof name === 'function') name = name.type;
|
||||
|
||||
this.#mutations = {
|
||||
@ -257,11 +285,15 @@ export class Updux<
|
||||
return mutation;
|
||||
}
|
||||
|
||||
addEffect(action, effect) {
|
||||
addEffect<TType, E>(action: TType, effect: E): E {
|
||||
this.#effects = [...this.#effects, [action, effect]];
|
||||
return effect;
|
||||
}
|
||||
|
||||
augmentMiddlewareApi(api) {
|
||||
return augmentMiddlewareApi(api, this.actions, this.selectors);
|
||||
}
|
||||
|
||||
splatSubscriber(store, inner, splatReaction) {
|
||||
const cache = {};
|
||||
|
||||
@ -366,9 +398,12 @@ export class Updux<
|
||||
|
||||
return {
|
||||
unsub: () => results.forEach(({ unsub }) => unsub()),
|
||||
subscriber: () => results.forEach(({ subscriber }) => subscriber()),
|
||||
subscriber: () =>
|
||||
results.forEach(({ subscriber }) => subscriber()),
|
||||
subscriberRaw: (...args) =>
|
||||
results.forEach(({ subscriberRaw }) => subscriberRaw(...args)),
|
||||
results.forEach(({ subscriberRaw }) =>
|
||||
subscriberRaw(...args)
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@ -415,4 +450,8 @@ export class Updux<
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
effectToMiddleware(effect) {
|
||||
return effectToMiddleware(effect, this.actions, this.selectors);
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { action } from './actions';
|
||||
|
||||
test('action generators', () => {
|
||||
const foo = action('foo');
|
||||
|
||||
expect(foo.type).toEqual('foo');
|
||||
expect(foo()).toMatchObject({ type: 'foo' });
|
||||
|
||||
const bar = action('bar');
|
||||
|
||||
expect(bar.type).toEqual('bar');
|
||||
expect(bar()).toMatchObject({ type: 'bar' });
|
||||
});
|
34
src/actions.test.ts
Normal file
34
src/actions.test.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { action } from './actions.js';
|
||||
import u from 'updeep';
|
||||
|
||||
test('action generators', () => {
|
||||
const foo = action('foo');
|
||||
|
||||
expect(foo.type).toEqual('foo');
|
||||
expect(foo()).toMatchObject({ type: 'foo' });
|
||||
|
||||
const bar = action('bar');
|
||||
|
||||
expect(bar.type).toEqual('bar');
|
||||
expect(bar()).toMatchObject({ type: 'bar' });
|
||||
|
||||
const action3 = action('a3', (x:number) => x);
|
||||
|
||||
expect(action3(12)).toMatchObject({
|
||||
type: 'a3',
|
||||
payload: 12,
|
||||
});
|
||||
|
||||
const action4 = action('a4', undefined, u.updateIn('meta.x','yay'));
|
||||
|
||||
expect(action4(13)).toMatchObject({
|
||||
type: 'a4',
|
||||
payload: 13,
|
||||
meta: {x:'yay'},
|
||||
});
|
||||
|
||||
expect(action4.type).toEqual('a4');
|
||||
|
||||
|
||||
|
||||
});
|
@ -37,7 +37,7 @@ export function action<
|
||||
payloadFunction?: TPayload,
|
||||
transformer?: Function
|
||||
): ActionGenerator<TType, TPayload> {
|
||||
const generator = function (...payloadArg) {
|
||||
let generator : any= function (...payloadArg) {
|
||||
const result: Action = { type };
|
||||
|
||||
if (payloadFunction) {
|
||||
@ -49,11 +49,12 @@ export function action<
|
||||
return result;
|
||||
};
|
||||
|
||||
if(transformer) {
|
||||
const orig = generator;
|
||||
generator = (...args: any) => transformer(orig(...args), args);
|
||||
}
|
||||
|
||||
generator.type = type;
|
||||
|
||||
return (
|
||||
transformer
|
||||
? (...args: any) => transformer(generator(...args), args)
|
||||
: generator
|
||||
) as any;
|
||||
return generator;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { isPlainObject, mapValues } from 'lodash';
|
||||
import { mapValues } from 'lodash-es';
|
||||
import isPlainObject from 'lodash/isPlainObject.js';
|
||||
import u from 'updeep';
|
||||
|
||||
export function buildInitial(initial, subduxes = {}) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { buildInitial } from '.';
|
||||
import { buildInitial } from './index.js';
|
||||
|
||||
test('basic', () => {
|
||||
expect(buildInitial({ a: 1 }, { b: { initial: { c: 2 } } })).toMatchObject({
|
||||
|
@ -1,6 +1,5 @@
|
||||
import u from 'updeep';
|
||||
import { mapValues, map, get } from 'lodash';
|
||||
import { Updux } from '../Updux.js';
|
||||
import { mapValues, map, get } from 'lodash-es';
|
||||
|
||||
const middlewareFor = (type, middleware) => (api) => (next) => (action) => {
|
||||
if (type !== '*' && action.type !== type) return next(action);
|
||||
@ -66,7 +65,9 @@ export function buildMiddleware(
|
||||
effects = [],
|
||||
actions = {},
|
||||
selectors = {},
|
||||
sub = {}
|
||||
sub = {},
|
||||
wrapper = undefined,
|
||||
dux = undefined,
|
||||
) {
|
||||
let inner = map(sub, ({ middleware }, slice) =>
|
||||
slice !== '*' && middleware ? sliceMw(slice, middleware) : undefined
|
||||
@ -76,7 +77,9 @@ export function buildMiddleware(
|
||||
effectToMiddleware(effect, actions, selectors)
|
||||
);
|
||||
|
||||
const mws = [...local, ...inner];
|
||||
let mws = [...local, ...inner];
|
||||
|
||||
if( wrapper ) mws = wrapper(mws,dux);
|
||||
|
||||
return composeMw(mws);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { map, mapValues, merge } from 'lodash';
|
||||
import { map, mapValues, merge } from 'lodash-es';
|
||||
|
||||
export function buildSelectors(
|
||||
localSelectors,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import u from 'updeep';
|
||||
import { mapValues } from 'lodash';
|
||||
import { mapValues } from 'lodash-es';
|
||||
|
||||
export function buildUpreducer(
|
||||
initial,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import u from 'updeep';
|
||||
import add from 'lodash/fp/add.js';
|
||||
|
||||
import { Updux } from '.';
|
||||
import { Updux } from './index.js';
|
||||
|
||||
test('README.md', () => {
|
||||
const otherDux = new Updux({});
|
||||
|
@ -1,2 +0,0 @@
|
||||
export { Updux } from './Updux';
|
||||
export { action } from './actions';
|
3
src/index.ts
Normal file
3
src/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export { Updux, UpduxConfig } from './Updux.js';
|
||||
export { action } from './actions.js';
|
||||
export { AggregateDuxActions, AggregateDuxState } from './types.js';
|
@ -1,4 +1,4 @@
|
||||
import { Updux } from './Updux';
|
||||
import { Updux } from './Updux.js';
|
||||
|
||||
test('initial', () => {
|
||||
const foo = new Updux({
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { difference, omit } from 'lodash';
|
||||
import { difference, omit } from 'lodash-es';
|
||||
|
||||
import { Updux } from './Updux';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Updux } from './Updux';
|
||||
import { Action, action, ActionGenerator } from './actions';
|
||||
import { Updux } from './Updux.js';
|
||||
import { Action, action, ActionGenerator } from './actions.js';
|
||||
import { expectAssignable, expectType, expectNotType } from 'tsd';
|
||||
|
||||
type SimplePayload = (x: number) => number;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Action, ActionGenerator } from './actions';
|
||||
import { Action, ActionGenerator } from './actions.js';
|
||||
|
||||
export type Dict<T> = Record<string, T>;
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"target": "es2020",
|
||||
"target": "es2015",
|
||||
"lib": ["es2020"],
|
||||
"module": "ES2020",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "Node",
|
||||
"strict": false,
|
||||
"sourceMap": true,
|
||||
|
Loading…
Reference in New Issue
Block a user