Skip to content

Commit 6384d26

Browse files
Merge pull request cerebral#29 from cerebral/namespaces
feat(overmind): namespaces as functions for isolated modules
2 parents 090d06a + 1129842 commit 6384d26

File tree

4 files changed

+105
-44
lines changed

4 files changed

+105
-44
lines changed

packages/node_modules/overmind/src/compose.ts

Lines changed: 0 additions & 38 deletions
This file was deleted.

packages/node_modules/overmind/src/index.test.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import App, { compose } from './'
1+
import App, { namespaces, Namespace, IAction } from './'
22

33
describe('Overmind', () => {
44
test('should instantiate app with state', () => {
@@ -19,8 +19,8 @@ describe('Overmind', () => {
1919
})
2020
expect(app.actions.foo('bah')).toEqual('bah')
2121
})
22-
test('should instantiate app with composed state and actions', () => {
23-
const config = compose({
22+
test('should instantiate app with namespaces', () => {
23+
const config = namespaces({
2424
foo: {
2525
state: {
2626
foo: 'bar',
@@ -45,6 +45,37 @@ describe('Overmind', () => {
4545
expect(app.actions.foo.foo('mip')).toEqual('mip')
4646
expect(app.actions.bar.bar('bop')).toEqual('bop')
4747
})
48+
test('should allow namespaced modules to be functions', () => {
49+
const fooNamespace = (namespace: Namespace) => {
50+
type State = {
51+
foo: string
52+
}
53+
type NamespacedState = {
54+
[namespace]: State
55+
}
56+
const state: State = {
57+
foo: 'bar',
58+
}
59+
60+
type Action = IAction<NamespacedState, { state: NamespacedState }>
61+
62+
return {
63+
state,
64+
actions: (action: Action) => ({
65+
foo: action<string>().map(
66+
(value, { state }) => value + state[namespace].foo
67+
),
68+
}),
69+
}
70+
}
71+
const config = namespaces({
72+
foo: fooNamespace,
73+
})
74+
const app = new App(config)
75+
76+
expect(app.state.foo.foo).toEqual('bar')
77+
expect(app.actions.foo.foo('mip')).toEqual('mipbar')
78+
})
4879
})
4980

5081
describe('OPERATORS', () => {

packages/node_modules/overmind/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { EventEmitter } from 'betsy'
33
import ProxyStateTree from 'proxy-state-tree'
44
import Devtools, { Message, safeValue } from './Devtools'
55
import Action, { IValueAction, INoValueAction } from './Action'
6-
export { default as compose } from './compose'
6+
export { default as namespaces, Namespace } from './namespaces'
77
export { default as derived } from './derived'
88
export { default as computed } from './computed'
99

@@ -54,14 +54,14 @@ export default class App<
5454
Providers extends object,
5555
Actions extends
5656
| {
57-
[namespace: string]: ActionsCallback<Providers, State>
57+
[namespace: string]: ActionsCallback<{}, {}>
5858
}
5959
| ActionsCallback<Providers, State>
6060
> {
6161
private proxyStateTree: ProxyStateTree
6262
devtools: Devtools
6363
actions: Actions extends {
64-
[namespace: string]: ActionsCallback<Providers, State>
64+
[namespace: string]: ActionsCallback<{}, {}>
6565
}
6666
? { [Namespace in keyof Actions]: ReturnType<Actions[Namespace]> }
6767
: Actions extends ActionsCallback<Providers, State>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
export type Namespace = 'namespace'
2+
3+
type Module = {
4+
state?: any
5+
providers?: any
6+
actions?: any
7+
}
8+
9+
type ModuleFunction = (namespace: string) => Module
10+
11+
type TNamespaces = {
12+
[namespace: string]: Module | ModuleFunction
13+
}
14+
15+
export default function namespaces<Namespaces extends TNamespaces>(
16+
namespaces: Namespaces
17+
): {
18+
state: {
19+
[Namespace in keyof Namespaces]: Namespaces[Namespace] extends ModuleFunction
20+
? ReturnType<Namespaces[Namespace]>['state']
21+
: Namespaces[Namespace] extends Module
22+
? Namespaces[Namespace]['state']
23+
: any
24+
}
25+
providers: {
26+
[Namespace in keyof Namespaces]: Namespaces[Namespace] extends ModuleFunction
27+
? ReturnType<Namespaces[Namespace]>['providers']
28+
: Namespaces[Namespace] extends Module
29+
? Namespaces[Namespace]['providers']
30+
: any
31+
}
32+
actions: {
33+
[Namespace in keyof Namespaces]: Namespaces[Namespace] extends ModuleFunction
34+
? ReturnType<Namespaces[Namespace]>['actions']
35+
: Namespaces[Namespace] extends Module
36+
? Namespaces[Namespace]['actions']
37+
: any
38+
}
39+
} {
40+
return Object.keys(namespaces).reduce(
41+
(aggr, key) => {
42+
const namespace =
43+
typeof namespaces[key] === 'function'
44+
? (namespaces[key] as ModuleFunction)(key)
45+
: (namespaces[key] as Module)
46+
47+
return Object.assign({
48+
state: {
49+
...aggr.state,
50+
[key]: namespace.state || {},
51+
},
52+
providers: {
53+
...aggr.providers,
54+
[key]: namespace.providers || {},
55+
},
56+
actions: {
57+
...aggr.actions,
58+
[key]: namespace.actions || {},
59+
},
60+
})
61+
},
62+
{
63+
state: {},
64+
providers: {},
65+
actions: {},
66+
}
67+
)
68+
}

0 commit comments

Comments
 (0)