Skip to content

Commit e8c9d9e

Browse files
committed
feat(action-chain): extract ActionChain methods as static utilities
1 parent d3f167c commit e8c9d9e

File tree

6 files changed

+126
-126
lines changed

6 files changed

+126
-126
lines changed

packages/node_modules/action-chain/src/ActionBase.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { ActionChain, ExecutionContext } from './ActionChain'
1+
import { ActionChain } from './ActionChain'
2+
import { ExecutionContext } from './types'
23

34
export class StopExecution {
45
constructor(public value: any) {}
@@ -103,8 +104,9 @@ export class ActionBase<Effects> {
103104

104105
const path = executionContextWithPath.__path
105106

106-
const effects = this.actionChain.getEffects(
107-
thisExecution,
107+
const effects = Object.assign(
108+
{},
109+
this.actionChain.getEffects(thisExecution),
108110
executionContextWithPath
109111
)
110112

Lines changed: 8 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,9 @@
11
import { EventEmitter } from 'betsy'
2+
import { proxifyEffects } from './utils'
3+
import { ActionChainEvents, Execution } from './types'
24

35
const IS_DEVELOPMENT = process.env.NODE_ENV !== 'production'
46

5-
export type Execution = {
6-
operatorId: number
7-
actionId: number
8-
executionId: number
9-
}
10-
11-
export type ExecutionContext = {
12-
__execution: Execution
13-
__path: string[]
14-
}
15-
16-
export type ActionExecution = {
17-
actionId: number
18-
executionId: number
19-
actionName: string
20-
value?: any
21-
}
22-
23-
type OperatorExecution = {
24-
actionId: number
25-
executionId: number
26-
operatorId: number
27-
type: string
28-
name: string
29-
path: string
30-
}
31-
32-
interface ActionChainEvents {
33-
effect: Execution & {
34-
name: string
35-
method: string | number | symbol
36-
result: any
37-
args: any[]
38-
}
39-
'action:start': ActionExecution
40-
'action:end': ActionExecution
41-
'operator:start': OperatorExecution
42-
'operator:async': OperatorExecution & {
43-
isAsync: boolean
44-
}
45-
'operator:end': OperatorExecution & {
46-
isAsync: boolean
47-
result: any
48-
}
49-
}
50-
51-
function isObject(value) {
52-
return typeof value === 'object' && !Array.isArray(value) && value !== null
53-
}
54-
557
export class ActionChain<Effects, ExtraEvents = {}> extends EventEmitter<
568
ActionChainEvents & ExtraEvents
579
> {
@@ -60,68 +12,17 @@ export class ActionChain<Effects, ExtraEvents = {}> extends EventEmitter<
6012
private options: { providerExceptions?: string[] } = {}
6113
) {
6214
super()
63-
this.options.providerExceptions = options.providerExceptions || []
64-
}
65-
private createGetHandler(execution: Execution, path: string) {
66-
return (target, prop) => {
67-
if (typeof target[prop] === 'function') {
68-
return (...args) => {
69-
const result = target[prop](...args)
70-
if (result instanceof Promise) {
71-
result.then((promisedResult) => {
72-
this.emitAsync('effect', {
73-
...execution,
74-
name: path,
75-
method: prop,
76-
args,
77-
result: promisedResult,
78-
})
79-
})
80-
} else {
81-
this.emitAsync('effect', {
82-
...execution,
83-
name: path,
84-
method: prop,
85-
args,
86-
result,
87-
})
88-
}
89-
90-
return result
91-
}
92-
} else if (isObject(target[prop])) {
93-
return new Proxy(target[prop], {
94-
get: this.createGetHandler(execution, path + '.' + prop),
95-
})
96-
}
97-
98-
return target[prop]
99-
}
10015
}
10116

102-
getEffects(thisExecution: Execution, executionContext: ExecutionContext) {
103-
let effects = this.effects
104-
17+
getEffects(thisExecution: Execution) {
10518
if (IS_DEVELOPMENT) {
106-
effects = Object.keys(this.effects).reduce(
107-
(currentEffects, key) => {
108-
if (
109-
this.options.providerExceptions.indexOf(key) === -1 &&
110-
isObject(this.effects[key])
111-
) {
112-
currentEffects[key] = new Proxy(this.effects[key], {
113-
get: this.createGetHandler(thisExecution, key),
114-
})
115-
} else {
116-
currentEffects[key] = this.effects[key]
117-
}
118-
119-
return currentEffects
120-
},
121-
{} as Effects
19+
return proxifyEffects(
20+
this.effects,
21+
this.options.providerExceptions,
22+
(effect) => this.emitAsync('effect', { ...thisExecution, ...effect })
12223
)
12324
}
12425

125-
return Object.assign({}, effects, executionContext)
26+
return this.effects
12627
}
12728
}
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
export { ActionBase, StopExecution } from './ActionBase'
2-
export {
3-
ActionChain,
4-
ActionExecution,
5-
Execution,
6-
ExecutionContext,
7-
} from './ActionChain'
2+
export { ActionChain } from './ActionChain'
3+
export { ActionExecution, Execution, ExecutionContext } from './types'
4+
export { doNotProxy } from './utils'
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
export type Execution = {
2+
operatorId: number
3+
actionId: number
4+
executionId: number
5+
}
6+
7+
export type ExecutionContext = {
8+
__execution: Execution
9+
__path: string[]
10+
}
11+
12+
export type ActionExecution = {
13+
actionId: number
14+
executionId: number
15+
actionName: string
16+
value?: any
17+
}
18+
19+
export type OperatorExecution = {
20+
actionId: number
21+
executionId: number
22+
operatorId: number
23+
type: string
24+
name: string
25+
path: string
26+
}
27+
28+
export type EffectResult = {
29+
name: string
30+
method: string | number | symbol
31+
result: any
32+
args: any[]
33+
}
34+
35+
export interface ActionChainEvents {
36+
effect: Execution & EffectResult
37+
'action:start': ActionExecution
38+
'action:end': ActionExecution
39+
'operator:start': OperatorExecution
40+
'operator:async': OperatorExecution & { isAsync: true }
41+
'operator:end': OperatorExecution & { isAsync: boolean; result: any }
42+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { EffectResult } from './types'
2+
3+
export const doNotProxy = Symbol('doNotProxy')
4+
5+
function isObject(value) {
6+
return typeof value === 'object' && !Array.isArray(value) && value !== null
7+
}
8+
9+
function createProxyGetHandler(
10+
path: string,
11+
cb: (effect: EffectResult) => void
12+
): ProxyHandler<any>['get'] {
13+
return (target, prop) => {
14+
if (typeof target[prop] === 'function') {
15+
return (...args) => {
16+
const result = target[prop](...args)
17+
if (result instanceof Promise) {
18+
result.then((promisedResult) => {
19+
// eslint-disable-next-line standard/no-callback-literal
20+
cb({
21+
name: path,
22+
method: prop,
23+
args,
24+
result: promisedResult,
25+
})
26+
})
27+
} else {
28+
// eslint-disable-next-line standard/no-callback-literal
29+
cb({
30+
name: path,
31+
method: prop,
32+
args,
33+
result,
34+
})
35+
}
36+
return result
37+
}
38+
} else if (isObject(target[prop])) {
39+
return new Proxy(target[prop], {
40+
get: createProxyGetHandler(path + '.' + prop.toString(), cb),
41+
})
42+
}
43+
}
44+
}
45+
46+
export function proxifyEffects<Effects>(
47+
effects: Effects,
48+
skipKeys: string[] = [],
49+
cb: (effect: EffectResult) => void
50+
): Effects {
51+
return Object.keys(effects).reduce(
52+
(currentEffects, key) => {
53+
const effect = effects[key]
54+
if (skipKeys.indexOf(key) === -1 && isObject(effect)) {
55+
currentEffects[key] = new Proxy(effect, {
56+
get: createProxyGetHandler(key, cb),
57+
})
58+
} else {
59+
currentEffects[key] = effect
60+
}
61+
return currentEffects
62+
},
63+
{} as Effects
64+
)
65+
}

packages/node_modules/overmind/src/index.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ActionChain } from 'action-chain'
1+
import { ActionChain, doNotProxy } from 'action-chain'
22
import { EventEmitter } from 'betsy'
33
import ProxyStateTree from 'proxy-state-tree'
44
import Devtools, { Message, safeValue } from './Devtools'
@@ -280,15 +280,8 @@ export default class App<
280280
The action chain with the context configuration
281281
*/
282282
const actionChain = new ActionChain(
283-
Object.assign(
284-
{
285-
state: proxyStateTree.get(),
286-
},
287-
configuration.effects || {}
288-
),
289-
{
290-
providerExceptions: ['state'],
291-
}
283+
Object.assign({ state: proxyStateTree.get() }, configuration.effects),
284+
{ providerExceptions: ['state'] }
292285
)
293286

294287
/*

0 commit comments

Comments
 (0)