Skip to content

Commit 7153f92

Browse files
refactor(overmind): move deepCopy to avoid circular dependency warning
1 parent 587f288 commit 7153f92

File tree

2 files changed

+119
-60
lines changed

2 files changed

+119
-60
lines changed

packages/node_modules/overmind/src/statemachine.ts

Lines changed: 115 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
import isPlainObject from 'is-plain-obj'
12
import { PATH, PROXY_TREE, VALUE } from 'proxy-state-tree'
2-
3-
import { deepCopy } from './utils'
43
import { IState } from '.'
54

65
type TState = {
@@ -16,23 +15,48 @@ type TEvents = {
1615
data?: any
1716
}
1817

19-
20-
export type StatemachineTransitions<States extends TState, Events extends TEvents, BaseState extends TBaseState> = {
21-
[Type in Events["type"]]: [BaseState] extends [never] ?
22-
((state: States, payload: Events extends { type: Type } ? Events["data"] : never) => States | void) :
23-
((state: States & BaseState, payload: Events extends { type: Type } ? Events["data"] : never) => States | void)
18+
export type StatemachineTransitions<
19+
States extends TState,
20+
Events extends TEvents,
21+
BaseState extends TBaseState
22+
> = {
23+
[Type in Events['type']]: [BaseState] extends [never]
24+
? ((
25+
state: States,
26+
payload: Events extends { type: Type } ? Events['data'] : never
27+
) => States | void)
28+
: ((
29+
state: States & BaseState,
30+
payload: Events extends { type: Type } ? Events['data'] : never
31+
) => States | void)
2432
}
2533

26-
export interface MachineMethods<States extends TState, Events extends TEvents, BaseState extends TBaseState> {
27-
matches<T extends States["current"]>(
28-
current: T,
29-
): Statemachine<States extends { current: T} ? States : never, Events, BaseState> | undefined
30-
send<T extends Events["type"]>(
31-
...args: Events extends { type: T, data: any } ? [T, Events["data"]] : [T]
34+
export interface MachineMethods<
35+
States extends TState,
36+
Events extends TEvents,
37+
BaseState extends TBaseState
38+
> {
39+
matches<T extends States['current']>(
40+
current: T
41+
):
42+
| Statemachine<
43+
States extends { current: T } ? States : never,
44+
Events,
45+
BaseState
46+
>
47+
| undefined
48+
send<T extends Events['type']>(
49+
...args: Events extends { type: T; data: any } ? [T, Events['data']] : [T]
3250
): Statemachine<States, Events, BaseState>
3351
}
3452

35-
export type Statemachine<States extends TState, Events extends TEvents, BaseState extends TBaseState = never> = [BaseState] extends [never] ? States & MachineMethods<States, Events, BaseState> : States & BaseState & MachineMethods<States, Events, BaseState>
53+
export type Statemachine<
54+
States extends TState,
55+
Events extends TEvents,
56+
BaseState extends TBaseState = never
57+
> = [BaseState] extends [never]
58+
? States & MachineMethods<States, Events, BaseState>
59+
: States & BaseState & MachineMethods<States, Events, BaseState>
3660

3761
const INITIAL_STATE = Symbol('INITIAL_STATE')
3862
const TRANSITIONS = Symbol('TRANSITIONS')
@@ -41,15 +65,52 @@ const IS_DISPOSED = Symbol('IS_DISPOSED')
4165
const CURRENT_KEYS = Symbol('CURRENT_KEYS')
4266
const BASE_STATE = Symbol('BASE_STATE')
4367

44-
export class StateMachine<State extends TState, Events extends TEvents, BaseState extends TBaseState> {
45-
current: State["current"]
46-
private [INITIAL_STATE]: State["current"]
68+
// We have to export here to avoid a circular dependency issue with "utils"
69+
export function deepCopy(obj) {
70+
if (obj instanceof StateMachine) {
71+
return (obj as any).clone()
72+
} else if (isPlainObject(obj)) {
73+
return Object.keys(obj).reduce((aggr: any, key) => {
74+
if (key === '__esModule') {
75+
return aggr
76+
}
77+
78+
const originalDescriptor = Object.getOwnPropertyDescriptor(obj, key)
79+
const isAGetter = originalDescriptor && 'get' in originalDescriptor
80+
const value = obj[key]
81+
82+
if (isAGetter) {
83+
Object.defineProperty(aggr, key, originalDescriptor as any)
84+
} else {
85+
aggr[key] = deepCopy(value)
86+
}
87+
88+
return aggr
89+
}, {})
90+
} else if (Array.isArray(obj)) {
91+
return obj.map((item) => deepCopy(item))
92+
}
93+
94+
return obj
95+
}
96+
97+
export class StateMachine<
98+
State extends TState,
99+
Events extends TEvents,
100+
BaseState extends TBaseState
101+
> {
102+
current: State['current']
103+
private [INITIAL_STATE]: State['current']
47104
private [TRANSITIONS]: StatemachineTransitions<State, Events, BaseState>
48105
private [STATE]: any
49106
private [BASE_STATE]: BaseState
50107
private [IS_DISPOSED] = false
51108
private clone() {
52-
return new StateMachine(this[TRANSITIONS], deepCopy(this[STATE]), deepCopy(this[BASE_STATE]))
109+
return new StateMachine(
110+
this[TRANSITIONS],
111+
deepCopy(this[STATE]),
112+
deepCopy(this[BASE_STATE])
113+
)
53114
}
54115
private dispose() {
55116
Object.keys(this[VALUE]).forEach((key) => {
@@ -59,7 +120,11 @@ export class StateMachine<State extends TState, Events extends TEvents, BaseStat
59120
})
60121
this[VALUE][IS_DISPOSED] = true
61122
}
62-
constructor(transitions: StatemachineTransitions<State, Events, BaseState>, state: State, baseState: BaseState) {
123+
constructor(
124+
transitions: StatemachineTransitions<State, Events, BaseState>,
125+
state: State,
126+
baseState: BaseState
127+
) {
63128
this[STATE] = state
64129
this[BASE_STATE] = baseState
65130
this[INITIAL_STATE] = state.current
@@ -71,12 +136,16 @@ export class StateMachine<State extends TState, Events extends TEvents, BaseStat
71136
send(type, data) {
72137
if (this[VALUE][IS_DISPOSED]) {
73138
if (process.env.NODE_ENV === 'development') {
74-
console.warn(`Overmind - The statemachine at "${this[PATH]}" has been disposed, but you tried to transition on it`)
139+
console.warn(
140+
`Overmind - The statemachine at "${
141+
this[PATH]
142+
}" has been disposed, but you tried to transition on it`
143+
)
75144
}
76145
return this
77146
}
78147

79-
const tree = (this[PROXY_TREE].master.mutationTree || this[PROXY_TREE])
148+
const tree = this[PROXY_TREE].master.mutationTree || this[PROXY_TREE]
80149
const transition = this[VALUE][TRANSITIONS][type]
81150

82151
tree.enableMutations()
@@ -103,16 +172,31 @@ export class StateMachine<State extends TState, Events extends TEvents, BaseStat
103172
}
104173
}
105174

106-
export type StatemachineFactory<States extends TState, Events extends TEvents, BaseState extends TBaseState> = [BaseState] extends [never] ? {
107-
create(state: States): Statemachine<States, Events, {}>
108-
} : {
109-
create(state: States, baseState: BaseState): Statemachine<States, Events, BaseState>
110-
}
175+
export type StatemachineFactory<
176+
States extends TState,
177+
Events extends TEvents,
178+
BaseState extends TBaseState
179+
> = [BaseState] extends [never]
180+
? {
181+
create(state: States): Statemachine<States, Events, {}>
182+
}
183+
: {
184+
create(
185+
state: States,
186+
baseState: BaseState
187+
): Statemachine<States, Events, BaseState>
188+
}
111189

112-
export function statemachine<States extends TState, Events extends TEvents, BaseState extends TBaseState = never>(transitions: StatemachineTransitions<States, Events, BaseState>): StatemachineFactory<States, Events, BaseState> {
113-
return {
114-
create(state, baseState) {
190+
export function statemachine<
191+
States extends TState,
192+
Events extends TEvents,
193+
BaseState extends TBaseState = never
194+
>(
195+
transitions: StatemachineTransitions<States, Events, BaseState>
196+
): StatemachineFactory<States, Events, BaseState> {
197+
return {
198+
create(state, baseState) {
115199
return new StateMachine(transitions, state as any, baseState as any)
116-
}
117-
} as any
200+
},
201+
} as any
118202
}

packages/node_modules/overmind/src/utils.ts

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import isPlainObject from 'is-plain-obj'
22
import { IMutation, IS_PROXY, VALUE } from 'proxy-state-tree'
3-
import { StateMachine } from './statemachine'
3+
import { deepCopy } from './statemachine'
4+
5+
// Due to avoid circular dependency warnings we export this utility from here
6+
export { deepCopy } from './statemachine'
47

58
export const ENVIRONMENT = (() => {
69
let env: string
@@ -78,34 +81,6 @@ export function getFunctionName(func: Function) {
7881
return func.name || (func as any).displayName || ''
7982
}
8083

81-
export function deepCopy(obj) {
82-
if (obj instanceof StateMachine) {
83-
return (obj as any).clone()
84-
} else if (isPlainObject(obj)) {
85-
return Object.keys(obj).reduce((aggr: any, key) => {
86-
if (key === '__esModule') {
87-
return aggr
88-
}
89-
90-
const originalDescriptor = Object.getOwnPropertyDescriptor(obj, key)
91-
const isAGetter = originalDescriptor && 'get' in originalDescriptor
92-
const value = obj[key]
93-
94-
if (isAGetter) {
95-
Object.defineProperty(aggr, key, originalDescriptor as any)
96-
} else {
97-
aggr[key] = deepCopy(value)
98-
}
99-
100-
return aggr
101-
}, {})
102-
} else if (Array.isArray(obj)) {
103-
return obj.map((item) => deepCopy(item))
104-
}
105-
106-
return obj
107-
}
108-
10984
const getChangeMutationsDelimiter = '.'
11085
export function getChangeMutations(
11186
stateA: object,

0 commit comments

Comments
 (0)