diff --git a/src/Updux.js b/src/Updux.js index bf49936..3fe50fe 100644 --- a/src/Updux.js +++ b/src/Updux.js @@ -1,6 +1,7 @@ import R from 'remeda'; import { createStore as reduxCreateStore } from 'redux'; +import { buildSelectors } from './selectors.js'; import { action } from './actions.js'; function isActionGen(action) { @@ -19,6 +20,7 @@ export class Updux { #actions; #mutations = {}; #config = {}; + #selectors = {}; constructor(config = {}) { this.#config = config; @@ -31,6 +33,8 @@ export class Updux { Object.entries(this.#subduxes).forEach(([slice, sub]) => this.#addSubduxActions(slice, sub), ); + + this.#selectors = buildSelectors( config.selectors, config.splatSelectors, this.#subduxes ); } #addSubduxActions(_slice, subdux) { @@ -46,6 +50,10 @@ export class Updux { }); } + get selectors() { + return this.#selectors; + } + get actions() { return this.#actions; } @@ -119,3 +127,5 @@ export class Updux { return store; } } + +export const dux = (config) => new Updux(config); diff --git a/src/createStore.test.js b/src/createStore.test.js index e2a6524..161822b 100644 --- a/src/createStore.test.js +++ b/src/createStore.test.js @@ -13,7 +13,5 @@ test('basic createStore', async () => { expect(store.getState()).toEqual({ a: 1 }); - console.log(store.actions.a1); - expect(store.actions.a1).toBeTypeOf('function'); }); diff --git a/src/dux-selectors.test.js b/src/dux-selectors.test.js new file mode 100644 index 0000000..fdf40c7 --- /dev/null +++ b/src/dux-selectors.test.js @@ -0,0 +1,26 @@ +import { test, expect } from 'vitest'; + +import { dux } from './Updux.js'; + +test( "basic selectors", () => { + + const foo = dux({ + initial: { + x: 1, + }, + selectors: { + getX: ({x}) => x, + }, + subduxes: { + bar: { + initial: { y: 2 }, + selectors: { + getY: ({y}) => y + } + } + } + }); + + expect( foo.selectors.getY({bar:{y:3}} ) ).toBe(3); + +} ); diff --git a/src/selectors.js b/src/selectors.js new file mode 100644 index 0000000..dce582d --- /dev/null +++ b/src/selectors.js @@ -0,0 +1,37 @@ +import R from 'remeda'; + +export function buildSelectors( + localSelectors, + splatSelector = {}, + subduxes = {} +) { + const subSelectors = Object.entries(subduxes).map(([slice,{ selectors }]) => { + if (!selectors) return {}; + if (slice === '*') return {}; + + return R.mapValues( + selectors, + (func) => (state) => func(state[slice]) + ); + }); + + let splat = {}; + + for (const name in splatSelector) { + splat[name] = + (state) => + (...args) => { + const value = splatSelector[name](state)(...args); + + const res = () => value; + return merge( + res, + mapValues( + subduxes['*'].selectors, + (selector) => () => selector(value) + ) + ); + }; + } + return R.mergeAll([ ...subSelectors, localSelectors, splat ]); +}