Skip to content

Commit 5955696

Browse files
feat(overmind): add derived parent to derived function
1 parent f99d1d5 commit 5955696

File tree

6 files changed

+146
-97
lines changed

6 files changed

+146
-97
lines changed

packages/node_modules/overmind-devtools/src/app/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { TConnect, createConnect } from 'overmind-react'
33

44
import * as actions from './actions'
55
import * as effects from './effects'
6-
import * as state from './state'
6+
import state from './state'
77

88
const config = {
99
onInitialize: actions.onInitialize,

packages/node_modules/overmind-devtools/src/app/state.ts

Lines changed: 93 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -9,94 +9,101 @@ import {
99
Tab,
1010
} from './types'
1111

12-
export let isConnecting: boolean = true
13-
14-
export let error: string = null
15-
16-
export let currentAppName: string = null
17-
18-
export let port: string = '3031'
19-
20-
export let apps: Apps = {}
21-
22-
export let newPortValue: string = ''
23-
24-
export let currentTab: Tab = Tab.State
25-
26-
export let expandedStatePaths: string[] = ['']
27-
28-
export const currentApp: Derive<App> = (state) =>
29-
state.apps[state.currentAppName]
30-
31-
export const componentsMounted: Derive<Component[]> = (state) =>
32-
Object.keys(state.currentApp.components).reduce(
33-
(aggr, key) => {
34-
if (state.currentApp.components[key].isMounted) {
35-
return aggr.concat(state.currentApp.components[key])
36-
}
37-
38-
return aggr
39-
},
40-
[] as Component[]
41-
)
42-
43-
export const componentsUpdateCount: Derive<number> = (state) =>
44-
state.componentsMounted.reduce(
45-
(aggr, component) => aggr + component.updateCount,
46-
0
47-
)
48-
49-
export const componentsStatePathCount: Derive<number> = (state) =>
50-
state.componentsMounted.reduce(
51-
(aggr, component) => aggr + component.paths.length,
52-
0
53-
)
54-
55-
export const flushes: Derive<Flush[]> = (state) =>
56-
Object.keys(state.currentApp.flushes)
57-
.sort(
58-
(idA, idB) =>
59-
state.currentApp.flushes[idB].flushId -
60-
state.currentApp.flushes[idA].flushId
61-
)
62-
.map((id) => state.currentApp.flushes[id])
63-
64-
export const flushesMutationsCount: Derive<number> = (state) =>
65-
state.flushes.reduce((aggr, flush) => aggr + flush.mutations.length, 0)
66-
67-
export const flushesStatePathCount: Derive<number> = (state) =>
68-
state.flushes.reduce((aggr, flush) => {
69-
return flush.mutations.reduce(
70-
(aggr, mutation) =>
71-
aggr.includes(mutation.path) ? aggr : aggr.concat(mutation.path),
72-
aggr
73-
)
74-
}, []).length
75-
76-
export const currentAction: Derive<Action> = (state) =>
77-
state.currentApp.actions[state.currentApp.currentActionId]
78-
79-
export let expandAllActionDetails: boolean = false
80-
81-
export const expandedComponents: string[] = []
12+
type State = {
13+
isConnecting: boolean
14+
error: string
15+
port: string
16+
apps: Apps
17+
currentAppName: string
18+
newPortValue: string
19+
currentTab: Tab
20+
expandedStatePaths: string[]
21+
expandAllActionDetails: boolean
22+
expandedComponents: string[]
23+
currentAction: Derive<Action>
24+
currentApp: Derive<App>
25+
componentsMounted: Derive<Component[]>
26+
componentsUpdateCount: Derive<number>
27+
componentsStatePathCount: Derive<number>
28+
flushes: Derive<Flush[]>
29+
flushesMutationsCount: Derive<number>
30+
flushesStatePathCount: Derive<number>
31+
groupedComponents: Derive<GroupedComponents>
32+
}
8233

83-
export const groupedComponents: Derive<GroupedComponents> = (state) => {
84-
const components = state.componentsMounted
34+
const state: State = {
35+
isConnecting: true,
36+
error: null,
37+
currentAppName: null,
38+
port: '3031',
39+
apps: {},
40+
newPortValue: '',
41+
currentTab: Tab.State,
42+
expandedStatePaths: [''],
43+
expandAllActionDetails: false,
44+
expandedComponents: [],
45+
currentApp: (state) => state.apps[state.currentAppName],
46+
componentsMounted: (state) =>
47+
Object.keys(state.currentApp.components).reduce(
48+
(aggr, key) => {
49+
if (state.currentApp.components[key].isMounted) {
50+
return aggr.concat(state.currentApp.components[key])
51+
}
8552

86-
return components.reduce(
87-
(aggr, component) => {
88-
if (aggr[component.name]) {
89-
aggr[component.name].components.push(component)
90-
} else {
91-
aggr[component.name] = {
92-
name: component.name,
93-
components: [component],
94-
isCollapsed: !state.expandedComponents.includes(component.name),
53+
return aggr
54+
},
55+
[] as Component[]
56+
),
57+
componentsUpdateCount: (state) =>
58+
state.componentsMounted.reduce(
59+
(aggr, component) => aggr + component.updateCount,
60+
0
61+
),
62+
componentsStatePathCount: (state) =>
63+
state.componentsMounted.reduce(
64+
(aggr, component) => aggr + component.paths.length,
65+
0
66+
),
67+
flushes: (state) =>
68+
Object.keys(state.currentApp.flushes)
69+
.sort(
70+
(idA, idB) =>
71+
state.currentApp.flushes[idB].flushId -
72+
state.currentApp.flushes[idA].flushId
73+
)
74+
.map((id) => state.currentApp.flushes[id]),
75+
flushesMutationsCount: (state) =>
76+
state.flushes.reduce((aggr, flush) => aggr + flush.mutations.length, 0),
77+
flushesStatePathCount: (state) =>
78+
state.flushes.reduce((aggr, flush) => {
79+
return flush.mutations.reduce(
80+
(aggr, mutation) =>
81+
aggr.includes(mutation.path) ? aggr : aggr.concat(mutation.path),
82+
aggr
83+
)
84+
}, []).length,
85+
currentAction: (state) =>
86+
state.currentApp.actions[state.currentApp.currentActionId],
87+
groupedComponents(state) {
88+
const components = state.componentsMounted
89+
90+
return components.reduce(
91+
(aggr, component) => {
92+
if (aggr[component.name]) {
93+
aggr[component.name].components.push(component)
94+
} else {
95+
aggr[component.name] = {
96+
name: component.name,
97+
components: [component],
98+
isCollapsed: !state.expandedComponents.includes(component.name),
99+
}
95100
}
96-
}
97101

98-
return aggr
99-
},
100-
{} as GroupedComponents
101-
)
102+
return aggr
103+
},
104+
{} as GroupedComponents
105+
)
106+
},
102107
}
108+
109+
export default state

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

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('Derived', () => {
3131
let renderCount = 0
3232
const changeFoo: Action = ({ state }) => (state.foo = 'bar2')
3333

34-
const derived: Derive<string> = (state: State) => state.foo.toUpperCase()
34+
const derived: Derive<string> = (state) => state.foo.toUpperCase()
3535

3636
const config = {
3737
state: {
@@ -49,7 +49,7 @@ describe('Derived', () => {
4949
}
5050
actions: typeof config.actions
5151
}>
52-
type Action<Input = void, Output = any> = TAction<IApp, Input, Output>
52+
type Action<Input = void> = TAction<IApp, Input>
5353
type Derive<Value> = TDerive<IApp, Value>
5454

5555
const app = new Overmind(config)
@@ -72,7 +72,7 @@ describe('Derived', () => {
7272
expect(state.upperFoo).toBe('BAR2')
7373
}
7474

75-
const derived: Derive<string> = (state: State) => state.foo.toUpperCase()
75+
const derived: Derive<string> = (state) => state.foo.toUpperCase()
7676

7777
const config = {
7878
state: {
@@ -90,10 +90,44 @@ describe('Derived', () => {
9090
}
9191
actions: typeof config.actions
9292
}>
93-
type Action<Input = void, Output = any> = TAction<IApp, Input, Output>
93+
type Action<Input = void> = TAction<IApp, Input>
9494
type Derive<Value> = TDerive<IApp, Value>
9595

9696
const app = new Overmind(config)
97+
98+
app.actions.changeFoo()
99+
})
100+
test('should pass parent as second argument', () => {
101+
expect.assertions(1)
102+
const changeFoo: Action = ({ state }) => {
103+
state.foo = 'bar2'
104+
expect(state.upperFoo).toBe('BAR2')
105+
}
106+
107+
const derived: Derive<string, State> = (_, parent) =>
108+
parent.foo.toUpperCase()
109+
110+
const config = {
111+
state: {
112+
foo: 'bar',
113+
upperFoo: derived,
114+
},
115+
actions: {
116+
changeFoo,
117+
},
118+
}
119+
type IApp = TApp<{
120+
state: {
121+
foo: string
122+
upperFoo: string
123+
}
124+
actions: typeof config.actions
125+
}>
126+
type Action<Input = void> = TAction<IApp, Input>
127+
type Derive<Value, Parent = any> = TDerive<IApp, Value, Parent>
128+
129+
const app = new Overmind(config)
130+
97131
app.actions.changeFoo()
98132
})
99133
})

packages/node_modules/overmind/src/derived.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export class Derived {
99
private value: any = null
1010
private paths: Set<string>
1111
private updateCount: number = 0
12-
constructor(private cb: (state: object) => void) {
12+
constructor(private cb: (state: object, parent: object) => void) {
1313
return this.evaluate.bind(this)
1414
}
1515
evaluate(
@@ -23,9 +23,12 @@ export class Derived {
2323
this.value[IS_PROXY] &&
2424
this.value[VALUE][(proxyStateTree as any).PROXY] !== this.value)
2525
) {
26+
const state = proxyStateTree.get()
27+
const pathAsArray = path.split('.')
28+
pathAsArray.pop()
29+
const parent = pathAsArray.reduce((curr, key) => curr[key], state)
2630
const trackId = proxyStateTree.startPathsTracking()
27-
28-
this.value = this.cb(proxyStateTree.get())
31+
this.value = this.cb(state, parent)
2932
this.isDirty = false
3033
this.paths = proxyStateTree.clearPathsTracking(trackId)
3134
if (!this.proxyStateTreeListener) {

packages/node_modules/overmind/src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export type Action<Value = void> = TAction<App, Value>
3636

3737
export type Context<Value> = TContext<App, Value>
3838

39-
export type Derive<Value> = TDerive<App, Value>
39+
export type Derive<Value, Parent = any> = TDerive<App, Value, Parent>
4040

4141
export type Reaction = TReaction<App>
4242

@@ -62,7 +62,9 @@ export class Overmind<Config extends Configuration> implements BaseApp {
6262
initialized: Promise<any>
6363
eventHub: EventEmitter<Events>
6464
devtools: Devtools
65-
actions: ResolveActions<Config['actions'] | {}>
65+
actions: Config['actions'] extends undefined
66+
? {}
67+
: ResolveActions<Config['actions']>
6668
state: ResolveState<Config['state']>
6769
effects: Config['effects']
6870
constructor(configuration: Config, options: Options = {}) {

packages/node_modules/overmind/src/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export type TOperator<C, RC> = (
4242
final?: (err, Error, val?: RC) => void
4343
) => void
4444

45-
export type TDerive<App extends BaseApp, Value> = (state: App['state']) => Value
45+
export type TDerive<App extends BaseApp, Value, Parent = any> = (
46+
state: App['state'],
47+
parent: Parent
48+
) => Value
4649

4750
export type TReaction<App extends BaseApp> = (
4851
reaction: (

0 commit comments

Comments
 (0)