@@ -96,7 +96,7 @@ type FunctionPaths<T, Prefix extends string = ""> = {
9696 : never ;
9797} [ keyof T & string ] ;
9898
99- type ActionCreatorsMask < T extends Record < string , any > = Record < string , any > > = {
99+ type ActionCreatorsMask < T extends Record < string , any > > = {
100100 [ K in FunctionPaths < T > | '*' | '**' | ( string & { } ) ] ?: boolean | (
101101 // Allow overriding leafs
102102 K extends '*' | '**' | `${string } .*` | `${string } .**`
@@ -294,41 +294,21 @@ const devtoolsImpl: DevtoolsImpl =
294294 }
295295 return new Function ( 'return ' + action ) ( ) ;
296296 }
297- if ( options . actionCreators ) {
297+
298+ // Not using the redux plugin
299+ if ( ! ( api as any ) . dispatch && options . actionCreators ) {
298300 try {
299301 evalAction = require ( '@redux-devtools/utils' ) . evalAction ;
302+ actionCreators = getActionsArray (
303+ initialState as Record < string , unknown > ,
304+ options . actionCreators as ActionCreatorsMask < { } >
305+ ) ;
306+ // override to pass it to the extension connector, any is ok, we dont care about the type anymore
307+ options . actionCreators = actionCreators as any ;
300308 } catch {
301309 console . warn ( '[zustand devtools middleware] Please install @redux-devtools/utils to use actionCreators in devtools middleware' ) ;
302310 }
303- actionCreators = getActionsArray (
304- initialState as Record < string , unknown > ,
305- options . actionCreators as ActionCreatorsMask < { } >
306- ) ;
307- // override to pass it to the extension connector, any is ok, we dont care about the type anymore
308- options . actionCreators = actionCreators as any ;
309- }
310311
311- // We connect after extracting action creators from the initial state
312- const { connection, ...connectionInformation } = extractConnectionInformation ( store , extensionConnector , options ) ;
313-
314- if ( connectionInformation . type === 'untracked' ) {
315- connection ?. init ( initialState )
316- } else {
317- connectionInformation . stores [ connectionInformation . store ] = api
318- connection ?. init (
319- Object . fromEntries (
320- Object . entries ( connectionInformation . stores ) . map ( ( [ key , store ] ) => [
321- key ,
322- key === connectionInformation . store
323- ? initialState
324- : store . getState ( ) ,
325- ] ) ,
326- ) ,
327- )
328- }
329-
330- // Not using the redux plugin
331- if ( ! ( api as any ) . dispatchFromDevtools && options . actionCreators ) {
332312 ( api as any ) . dispatchFromDevtools = true ;
333313 ( api as any ) . dispatch = ( payload : {
334314 type : string ,
@@ -353,6 +333,25 @@ const devtoolsImpl: DevtoolsImpl =
353333 }
354334 }
355335
336+ // We connect after extracting action creators from the initial state
337+ const { connection, ...connectionInformation } = extractConnectionInformation ( store , extensionConnector , options ) ;
338+
339+ if ( connectionInformation . type === 'untracked' ) {
340+ connection ?. init ( initialState )
341+ } else {
342+ connectionInformation . stores [ connectionInformation . store ] = api
343+ connection ?. init (
344+ Object . fromEntries (
345+ Object . entries ( connectionInformation . stores ) . map ( ( [ key , store ] ) => [
346+ key ,
347+ key === connectionInformation . store
348+ ? initialState
349+ : store . getState ( ) ,
350+ ] ) ,
351+ ) ,
352+ )
353+ }
354+
356355 if (
357356 ( api as any ) . dispatchFromDevtools &&
358357 typeof ( api as any ) . dispatch === 'function'
@@ -528,40 +527,44 @@ function maskToRegex(mask: string): RegExp {
528527}
529528
530529function getActionsArray < T extends Record < string , any > > ( actionCreators : T , mask : ActionCreatorsMask < T > ) : ActionCreatorObject [ ] {
531- if ( Array . isArray ( actionCreators ) ) return actionCreators ;
532- if ( typeof actionCreators !== 'object' ) return [ ] ;
533-
534- const getActionsArray = require ( '@redux-devtools/utils' ) . getActionsArray ;
535- const flat = getActionsArray ( actionCreators ) ;
530+ const getActions = require ( '@redux-devtools/utils' ) . getActionsArray ;
531+ const flat = getActions ( actionCreators ) ;
536532 const actions = new Map < string , ActionCreatorObject > ( ) ;
537533 const customActions = new Map < string , ActionCreatorObject > (
538- getActionsArray ( mask ) . map ( ( action : ActionCreatorObject ) => [ action . name , action ] )
534+ getActions ( mask ) . map ( ( action : ActionCreatorObject ) => [ action . name , action ] )
539535 ) ;
536+
537+ // Sort matchers by specificity
540538 const matchers = Object . entries ( mask ?? { } )
541539 . map ( ( [ key , picked ] ) => ( {
542540 matcher : maskToRegex ( key ) ,
543541 picked,
544- wildcard : key . includes ( '*' ) ,
545- } ) ) ;
542+ key,
543+ } ) ) . toSorted ( ( a , b ) => {
544+ const aIsDoubleWildcard = a . key . includes ( '**' ) ;
545+ const bIsDoubleWildcard = b . key . includes ( '**' ) ;
546+ if ( aIsDoubleWildcard !== bIsDoubleWildcard ) {
547+ return aIsDoubleWildcard ? - 1 : 1 ;
548+ }
549+
550+ const aIsSingleWildcard = a . key . includes ( '*' ) && ! aIsDoubleWildcard ;
551+ const bIsSingleWildcard = b . key . includes ( '*' ) && ! bIsDoubleWildcard ;
552+ if ( aIsSingleWildcard !== bIsSingleWildcard ) {
553+ return aIsSingleWildcard ? - 1 : 1 ;
554+ }
555+
556+ return a . key . length - b . key . length ;
557+ } ) ;
546558
547- next_action: for ( const action of flat ) {
548- for ( const { matcher, picked, wildcard } of matchers ) {
559+ for ( const action of flat ) {
560+ for ( const { matcher, picked } of matchers ) {
549561 if ( matcher . test ( action . name ) ) {
550- if ( ! wildcard ) {
551- if ( picked ) {
552- actions . set ( action . name ,
553- customActions . get ( action . name ) ?? {
554- name : action . name ,
555- func : action . func ,
556- args : action . args ,
557- } ) ;
558- } else {
559- actions . delete ( action . name ) ;
560- }
561- continue next_action;
562+ if ( picked === false ) {
563+ actions . delete ( action . name ) ;
564+ continue ;
562565 }
563566
564- actions . set ( action . name , {
567+ actions . set ( action . name , customActions . get ( action . name ) ?? {
565568 name : action . name ,
566569 func : typeof picked === 'function' ? picked : action . func ,
567570 args : action . args ,
@@ -570,5 +573,9 @@ function getActionsArray<T extends Record<string, any>>(actionCreators: T, mask:
570573 }
571574 }
572575
576+ for ( const [ name , action ] of customActions . entries ( ) ) {
577+ actions . set ( name , action ) ;
578+ }
579+
573580 return Array . from ( actions . values ( ) ) ;
574581}
0 commit comments