@@ -56,6 +56,26 @@ const fallbackRunWithContext = (fn: () => unknown) => fn()
56
56
57
57
type _ArrayType < AT > = AT extends Array < infer T > ? T : never
58
58
59
+ /**
60
+ * Marks a function as an action for `$onAction`
61
+ * @internal
62
+ */
63
+ const ACTION_MARKER = Symbol ( )
64
+ /**
65
+ * Action name symbol. Allows to add a name to an action after defining it
66
+ * @internal
67
+ */
68
+ const ACTION_NAME = Symbol ( )
69
+ /**
70
+ * Function type extended with action markers
71
+ * @internal
72
+ */
73
+ interface MarkedAction < Fn extends _Method = _Method > {
74
+ ( ...args : Parameters < Fn > ) : ReturnType < Fn >
75
+ [ ACTION_MARKER ] : boolean
76
+ [ ACTION_NAME ] : string
77
+ }
78
+
59
79
function mergeReactiveObjects <
60
80
T extends Record < any , unknown > | Map < unknown , unknown > | Set < unknown > ,
61
81
> ( target : T , patchToApply : _DeepPartial < T > ) : T {
@@ -211,7 +231,7 @@ function createSetupStore<
211
231
A extends _ActionsTree ,
212
232
> (
213
233
$id : Id ,
214
- setup : ( ) => SS ,
234
+ setup : ( helpers : SetupStoreHelpers ) => SS ,
215
235
options :
216
236
| DefineSetupStoreOptions < Id , S , G , A >
217
237
| DefineStoreOptions < Id , S , G , A > = { } ,
@@ -350,14 +370,18 @@ function createSetupStore<
350
370
}
351
371
352
372
/**
353
- * Wraps an action to handle subscriptions.
354
- *
373
+ * Helper that wraps function so it can be tracked with $onAction
374
+ * @param fn - action to wrap
355
375
* @param name - name of the action
356
- * @param action - action to wrap
357
- * @returns a wrapped action to handle subscriptions
358
376
*/
359
- function wrapAction ( name : string , action : _Method ) {
360
- return function ( this : any ) {
377
+ const action = < Fn extends _Method > ( fn : Fn , name : string = '' ) : Fn => {
378
+ if ( ACTION_MARKER in fn ) {
379
+ // we ensure the name is set from the returned function
380
+ ; ( fn as unknown as MarkedAction < Fn > ) [ ACTION_NAME ] = name
381
+ return fn
382
+ }
383
+
384
+ const wrappedAction = function ( this : any ) {
361
385
setActivePinia ( pinia )
362
386
const args = Array . from ( arguments )
363
387
@@ -373,15 +397,15 @@ function createSetupStore<
373
397
// @ts -expect-error
374
398
triggerSubscriptions ( actionSubscriptions , {
375
399
args,
376
- name,
400
+ name : wrappedAction [ ACTION_NAME ] ,
377
401
store,
378
402
after,
379
403
onError,
380
404
} )
381
405
382
406
let ret : unknown
383
407
try {
384
- ret = action . apply ( this && this . $id === $id ? this : store , args )
408
+ ret = fn . apply ( this && this . $id === $id ? this : store , args )
385
409
// handle sync errors
386
410
} catch ( error ) {
387
411
triggerSubscriptions ( onErrorCallbackList , error )
@@ -403,7 +427,14 @@ function createSetupStore<
403
427
// trigger after callbacks
404
428
triggerSubscriptions ( afterCallbackList , ret )
405
429
return ret
406
- }
430
+ } as MarkedAction < Fn >
431
+
432
+ wrappedAction [ ACTION_MARKER ] = true
433
+ wrappedAction [ ACTION_NAME ] = name // will be set later
434
+
435
+ // @ts -expect-error: we are intentionally limiting the returned type to just Fn
436
+ // because all the added properties are internals that are exposed through `$onAction()` only
437
+ return wrappedAction
407
438
}
408
439
409
440
const _hmrPayload = /*#__PURE__*/ markRaw ( {
@@ -480,7 +511,7 @@ function createSetupStore<
480
511
481
512
// TODO: idea create skipSerialize that marks properties as non serializable and they are skipped
482
513
const setupStore = runWithContext ( ( ) =>
483
- pinia . _e . run ( ( ) => ( scope = effectScope ( ) ) . run ( setup ) ! )
514
+ pinia . _e . run ( ( ) => ( scope = effectScope ( ) ) . run ( ( ) => setup ( { action } ) ) ! )
484
515
) !
485
516
486
517
// overwrite existing actions to support $onAction
@@ -519,8 +550,7 @@ function createSetupStore<
519
550
}
520
551
// action
521
552
} else if ( typeof prop === 'function' ) {
522
- // @ts -expect-error: we are overriding the function we avoid wrapping if
523
- const actionValue = __DEV__ && hot ? prop : wrapAction ( key , prop )
553
+ const actionValue = __DEV__ && hot ? prop : action ( prop as _Method , key )
524
554
// this a hot module replacement store because the hotUpdate method needs
525
555
// to do it with the right context
526
556
/* istanbul ignore if */
@@ -629,9 +659,9 @@ function createSetupStore<
629
659
} )
630
660
631
661
for ( const actionName in newStore . _hmrPayload . actions ) {
632
- const action : _Method = newStore [ actionName ]
662
+ const actionFn : _Method = newStore [ actionName ]
633
663
634
- set ( store , actionName , wrapAction ( actionName , action ) )
664
+ set ( store , actionName , action ( actionFn , actionName ) )
635
665
}
636
666
637
667
// TODO: does this work in both setup and option store?
@@ -784,13 +814,9 @@ export type StoreState<SS> =
784
814
? UnwrapRef < S >
785
815
: _ExtractStateFromSetupStore < SS >
786
816
787
- // type a1 = _ExtractStateFromSetupStore<{ a: Ref<number>; action: () => void }>
788
- // type a2 = _ExtractActionsFromSetupStore<{ a: Ref<number>; action: () => void }>
789
- // type a3 = _ExtractGettersFromSetupStore<{
790
- // a: Ref<number>
791
- // b: ComputedRef<string>
792
- // action: () => void
793
- // }>
817
+ export interface SetupStoreHelpers {
818
+ action : < Fn extends _Method > ( fn : Fn ) => Fn
819
+ }
794
820
795
821
/**
796
822
* Creates a `useStore` function that retrieves the store instance
@@ -831,7 +857,7 @@ export function defineStore<
831
857
*/
832
858
export function defineStore < Id extends string , SS > (
833
859
id : Id ,
834
- storeSetup : ( ) => SS ,
860
+ storeSetup : ( helpers : SetupStoreHelpers ) => SS ,
835
861
options ?: DefineSetupStoreOptions <
836
862
Id ,
837
863
_ExtractStateFromSetupStore < SS > ,
0 commit comments