import moize from 'moize'; import u from '@yanick/updeep'; 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'; /** * @public * `Updux` is a way to minimize and simplify the boilerplate associated with the * creation of a `Redux` store. It takes a shorthand configuration * object, and generates the appropriate reducer, actions, middleware, etc. * In true `Redux`-like fashion, upduxes can be made of sub-upduxes (`subduxes` for short) for different slices of the root state. */ export class Updux { #initial = {}; #subduxes = {}; /** @type Record */ #actions = {}; #selectors = {}; #mutations = {}; constructor(config) { this.#initial = config.initial ?? {}; this.#subduxes = config.subduxes ?? {}; this.#actions = config.actions ?? {}; this.#selectors = config.selectors ?? {}; this.#mutations = config.mutations ?? {}; Object.keys(this.#mutations) .filter((action) => action !== '*') .filter((action) => !this.actions.hasOwnProperty(action)) .forEach((action) => { throw new Error(`action '${action}' is not defined`); }); } #memoInitial = moize(buildInitial); #memoActions = moize(buildActions); #memoSelectors = moize(buildSelectors); #memoUpreducer = moize(buildUpreducer); get initial() { return this.#memoInitial(this.#initial, this.#subduxes); } /** * @return {Record} */ get actions() { return this.#memoActions(this.#actions, this.#subduxes); } get selectors() { return this.#memoSelectors(this.#selectors, this.#subduxes); } get upreducer() { return this.#memoUpreducer( this.initial, this.#mutations, this.#subduxes ); } get reducer() { return (state, action) => this.upreducer(action)(state); } addAction(type, payloadFunc) { const theAction = action(type, payloadFunc); this.#actions = u({ [type]: theAction }, this.#actions); return theAction; } addSelector(name, func) { this.#selectors[name] = func; return func; } addMutation(name, mutation) { if (typeof name === 'function') name = name.type; this.#mutations = { ...this.#mutations, [name]: mutation, }; return this; } }