diff --git a/src/Updux.ts b/src/Updux.ts index 20221a2..3a70c08 100644 --- a/src/Updux.ts +++ b/src/Updux.ts @@ -18,6 +18,7 @@ import { import { withPayload } from './actions.js'; import { AggregateActions, Dux, UnionToIntersection } from './types.js'; import { buildActions } from './buildActions.js'; +import { buildInitial } from './buildInitial.js'; type AggregateState = L; @@ -73,6 +74,8 @@ export default class Updux< #actions: AggregateActions, SUBDUXES>; + #initial: any; + constructor( config: Partial<{ initial: T_LocalState; @@ -86,6 +89,8 @@ export default class Updux< this.#subduxes = config.subduxes ?? ({} as SUBDUXES); this.#actions = buildActions(this.#localActions, this.#subduxes); + + this.#initial = buildInitial(this.#localInitial, this.#subduxes); } get actions() { @@ -94,7 +99,7 @@ export default class Updux< // TODO memoize? get initial() { - return this.#localInitial; + return this.#initial; } createStore( diff --git a/src/buildInitial.test.ts b/src/buildInitial.test.ts new file mode 100644 index 0000000..7e8767e --- /dev/null +++ b/src/buildInitial.test.ts @@ -0,0 +1,21 @@ +import { test, expect } from 'vitest'; +import { buildInitial } from './buildInitial.js'; + +test('basic', () => { + expect( + buildInitial( + { a: 1 }, + { b: { initial: { c: 2 } }, d: { initial: 'e' } }, + ), + ).toEqual({ + a: 1, + b: { c: 2 }, + d: 'e', + }); +}); + +test('throw if subduxes and initial is not an object', () => { + expect(() => { + buildInitial(3, { bar: 'foo' }); + }).toThrow(); +}); diff --git a/src/buildInitial.ts b/src/buildInitial.ts new file mode 100644 index 0000000..7e2330e --- /dev/null +++ b/src/buildInitial.ts @@ -0,0 +1,12 @@ +import u from '@yanick/updeep-remeda'; +import * as R from 'remeda'; + +export function buildInitial(localInitial, subduxes) { + if (Object.keys(subduxes).length > 0 && typeof localInitial !== 'object') { + throw new Error( + "can't have subduxes when the initial value is not an object", + ); + } + + return u(localInitial, R.mapValues(subduxes, R.pathOr(['initial'], {}))); +} diff --git a/src/initial.test.todo b/src/initial.test.todo deleted file mode 100644 index 0aa2a85..0000000 --- a/src/initial.test.todo +++ /dev/null @@ -1,46 +0,0 @@ -import { test, expect } from 'vitest'; - -import { Updux } from './Updux.js'; - -const bar = new Updux({ initial: 123 }); - -const foo = new Updux({ - initial: { root: 'abc' }, - subduxes: { - bar, - }, -}); - -test('single dux', () => { - const foo = new Updux({ - initial: { a: 1 }, - }); - - expect(foo.initial).toEqual({ a: 1 }); -}); - -test('initial value', () => { - expect(foo.initial).toEqual({ - root: 'abc', - bar: 123, - }); -}); - -test('splat initial', async () => { - const bar = new Updux({ - initial: { id: 0 }, - }); - - const foo = new Updux({ - subduxes: { '*': bar }, - }); - - expect(foo.initial).toEqual([]); - - expect( - new Updux({ - initial: 'overriden', - subduxes: { '*': bar }, - }).initial, - ).toEqual('overriden'); -}); diff --git a/src/initial.test.ts b/src/initial.test.ts index 32194e6..74ef278 100644 --- a/src/initial.test.ts +++ b/src/initial.test.ts @@ -1,5 +1,15 @@ +import { expectType } from './tutorial.test.js'; import Updux from './Updux.js'; +const bar = new Updux({ initial: 123 }); + +const foo = new Updux({ + initial: { root: 'abc' }, + subduxes: { + bar, + }, +}); + test('default', () => { const { initial } = new Updux({}); @@ -29,3 +39,60 @@ test('initial to createStore', () => { b: 4, }); }); + +test('single dux', () => { + const foo = new Updux({ + initial: { a: 1 }, + }); + + expect(foo.initial).toEqual({ a: 1 }); +}); + +// TODO add 'check for no todo eslint rule' +test.only('initial value', () => { + expect(foo.initial).toEqual({ + root: 'abc', + bar: 123, + }); + + expectType<{ + root: string; + bar: number; + }>(foo.initial); +}); + +test('no initial', () => { + const dux = new Updux({}); + expectType<{}>(dux.initial); + expect(dux.initial).toEqual({}); +}); + +test('no initial for subdux', () => { + const dux = new Updux({ + subduxes: { + bar: new Updux({}), + baz: new Updux({ initial: 'potato' }), + }, + }); + expectType<{ bar: {}; baz: string }>(dux.initial); + expect(dux.initial).toEqual({ bar: {}, baz: 'potato' }); +}); + +test('splat initial', async () => { + const bar = new Updux({ + initial: { id: 0 }, + }); + + const foo = new Updux({ + subduxes: { '*': bar }, + }); + + expect(foo.initial).toEqual([]); + + expect( + new Updux({ + initial: 'overriden', + subduxes: { '*': bar }, + }).initial, + ).toEqual('overriden'); +}); diff --git a/src/tutorial.test.ts b/src/tutorial.test.ts index 753e746..e763eb4 100644 --- a/src/tutorial.test.ts +++ b/src/tutorial.test.ts @@ -1,7 +1,7 @@ import Updux, { createAction, withPayload } from './index.js'; import u from '@yanick/updeep-remeda'; -const expectType = (value: T) => value; +export const expectType = (value: T) => value; test('initial state', () => { const initial = {