Skip to content

Commit f301284

Browse files
committed
revamped actions
1 parent 50f726f commit f301284

File tree

1 file changed

+60
-75
lines changed

1 file changed

+60
-75
lines changed

packages/plexus-core/src/action.ts

Lines changed: 60 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
import { isAsyncFunction } from '@plexusjs/utils'
22
import { PlexusInstance, instance } from './instance/instance'
3-
import { PlexusError } from './error'
3+
import { PlexusError, handlePlexusError } from './error'
44
type ErrorHandler = (error: any) => unknown
55

66
export interface PlexusActionHooks {
7+
/**
8+
* Add a new error handler for this action. This will catch any errors that occur during the execution of this action and prevent a crash.
9+
* @param handler? A function that will be called when an error occurs; omit to fail silently.
10+
* @param {boolean}useGlobal Should the global error handler be used? (default: true)
11+
*
12+
*/
713
onCatch(handler?: ErrorHandler, useGlobal?: boolean): void
814
/**
915
* Ignore the default hault preActions
1016
*/
1117
ignoreInit(): void
18+
/**
19+
* Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished.
20+
* @param fn The function to run in a batch
21+
*/
1222
batch<ReturnType = any>(fn: () => ReturnType): ReturnType
1323
}
1424
export type ActionFunction<
@@ -89,21 +99,12 @@ class PlexusActionHelpers {
8999
*/
90100
get hooks(): PlexusActionHooks {
91101
return {
92-
/**
93-
* Add a new error handler for this action. This will catch any errors that occur during the execution of this action and prevent a crash.
94-
* @param handler? A function that will be called when an error occurs; omit to fail silently.
95-
*
96-
*/
97102
onCatch: (handler?: ErrorHandler, useGlobal = true): void => {
98103
return this.onCatch(handler, useGlobal)
99104
},
100105
ignoreInit: (): void => {
101106
return this.ignoreInit()
102107
},
103-
/**
104-
* Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished.
105-
* @param fn The function to run in a batch
106-
*/
107108
batch: <BatchResponse>(batchFn: () => BatchResponse): BatchResponse => {
108109
return this.instance().runtime.batch<any>(batchFn)
109110
},
@@ -118,8 +119,6 @@ export function _action<Returns, Fn extends ActionFunction>(
118119
): InnerFunction<Fn> {
119120
const helpers = new PlexusActionHelpers(instance)
120121

121-
console.log('function constructor', fn.constructor.name, isAsyncFunction(fn))
122-
123122
if (typeof fn !== 'function') {
124123
console.warn(
125124
'%cPlexus WARN:%c An action must be of type Function.',
@@ -128,80 +127,66 @@ export function _action<Returns, Fn extends ActionFunction>(
128127
)
129128
throw new Error('An action must be of type Function.')
130129
}
131-
130+
/**
131+
* if the instance is not ready, wait for it to be
132+
* */
133+
const runInit = () => {
134+
if (!instance().ready && !helpers._skipInit) {
135+
if (isAsyncFunction(fn)) {
136+
// async call; just return the promise
137+
return instance().runtime.runInit()
138+
}
139+
// sync call
140+
let hold = true
141+
while (hold) {
142+
instance().runtime.runInit(() => {
143+
hold = false
144+
})
145+
}
146+
}
147+
}
148+
// we NEED this conditional. I tried to make this fit into one function definition instead of two, but it didn't work; async error catching flops for some reason.
149+
if (isAsyncFunction(fn)) {
150+
return async function newAction(...args) {
151+
try {
152+
await runInit()
153+
// if the action is batched, run it in a batch
154+
return batched
155+
? await instance().runtime.batch(
156+
async () => await fn(helpers.hooks, ...args)
157+
)
158+
: await fn(helpers.hooks, ...args)
159+
} catch (e) {
160+
// only return the error if there is no handler
161+
if (!helpers.catchError && !instance()._globalCatch) {
162+
throw handlePlexusError(e)
163+
}
164+
helpers.runErrorHandlers(e)
165+
// otherwise run the handler
166+
return handlePlexusError(e)
167+
}
168+
} as InnerFunction<Fn>
169+
}
132170
function newAction(...args) {
133171
try {
134172
// if the instance is not ready, wait for it to be
135-
// !NOTE: this is probably not a good way to do this, but it works for now
136-
if (!instance().ready && !helpers._skipInit) {
137-
let hold = true
138-
while (hold) {
139-
instance().runtime.runInit(() => {
140-
hold = false
141-
})
142-
}
143-
}
144-
// if the action is batched, run it in a batch
145-
if (batched) {
146-
return instance().runtime.batch(() => fn(helpers.hooks, ...args))
147-
}
148-
// run the function
149-
return fn(helpers.hooks, ...args)
173+
runInit()
174+
// if the action is batched, run it in a batch; otherwise run it normally
175+
return batched
176+
? instance().runtime.batch(() => fn(helpers.hooks, ...args))
177+
: fn(helpers.hooks, ...args)
150178
} catch (e) {
151179
// only return the error if there is no handler
152-
153180
if (!helpers.catchError && !instance()._globalCatch) {
154-
console.log('error caught but returning', e)
155-
if (e instanceof PlexusError) throw e
156-
if (e instanceof Error) {
157-
throw new PlexusError(
158-
`An error occurred during the execution of an action (${e.message})`,
159-
{ origin: 'action', stack: e.stack }
160-
)
161-
}
181+
throw handlePlexusError(e)
162182
}
163-
console.log('error caught', e)
164183
helpers.runErrorHandlers(e)
165-
166-
// otherwise run the handler and return null
167-
// TODO: return a PlexusError; needs to be a package wide change
168-
return new PlexusError(
169-
'An error occurred during the execution of an action',
170-
{ origin: 'action' }
171-
)
184+
// otherwise run the handler
185+
return handlePlexusError(e)
172186
}
173187
}
174188
// return the proxy function
175189
return newAction as InnerFunction<Fn>
176-
177-
// const newAction = async (...args) => {
178-
// try {
179-
// // if the instance is not ready, wait for it to be
180-
// if (!instance().ready && !helpers._skipInit) {
181-
// await instance().runtime.runInit()
182-
// }
183-
// // if the action is batched, run it in a batch
184-
// console.log('(async)hewhewhewhewhewh', batched, 'hewhewhewhewhewh')
185-
// if (batched) {
186-
// console.log('using a batch in an async action...')
187-
// return instance().runtime.batch(async () => {
188-
// console.log('running the async action in a batch')
189-
// return await fn(helpers.hooks, ...args)
190-
// })
191-
// }
192-
// // run the function
193-
// return await fn(helpers.hooks, ...args)
194-
// } catch (e) {
195-
// // only return the error if there is no handler
196-
// if (!helpers.catchError && !instance()._globalCatch) throw e
197-
// helpers.runErrorHandlers(e)
198-
// // otherwise run the handler and return null
199-
// return null
200-
// }
201-
// }
202-
// // return the proxy function
203-
// return newAction as InnerFunction<Fn>
204-
// // return proxyFn as InnerFunction<Fn>
205190
}
206191

207192
/**
@@ -210,7 +195,7 @@ export function _action<Returns, Fn extends ActionFunction>(
210195
* @returns The intended return value of fn, or null if an error is caught
211196
*/
212197
export function action<Fn extends ActionFunction>(fn: Fn): InnerFunction<Fn> {
213-
return _action(() => instance(), fn) as InnerFunction<Fn>
198+
return _action(() => instance(), fn)
214199
}
215200

216201
/**

0 commit comments

Comments
 (0)