@@ -66,95 +66,141 @@ export function collectLegacyHooks (target: any, method: string) {
6666
6767// Converts different hook registration formats into the
6868// same internal format
69- export function convertHookData ( obj : any ) {
70- let hook : any = { } ;
69+ export function convertHookData ( input : any ) {
70+ const result : { [ method : string ] : LegacyHookFunction [ ] } = { } ;
7171
72- if ( Array . isArray ( obj ) ) {
73- hook = { all : obj } ;
74- } else if ( typeof obj !== 'object' ) {
75- hook = { all : [ obj ] } ;
72+ if ( Array . isArray ( input ) ) {
73+ result . all = input ;
74+ } else if ( typeof input !== 'object' ) {
75+ result . all = [ input ] ;
7676 } else {
77- for ( const [ key , value ] of Object . entries ( obj ) ) {
78- hook [ key ] = ! Array . isArray ( value ) ? [ value ] : value ;
77+ for ( const key of Object . keys ( input ) ) {
78+ const value = input [ key ] ;
79+ result [ key ] = Array . isArray ( value ) ? value : [ value ] ;
7980 }
8081 }
8182
82- return hook ;
83+ return result ;
8384}
8485
85- const types = [ 'before' , 'after' , 'error' ] ;
86+ type LegacyType = 'before' | 'after' | 'error' ;
8687
87- const wrappers : any = {
88+ type LegacyMap = { [ type in LegacyType ] : ReturnType < typeof convertHookData > } ;
89+
90+ type LegacyAdapter = HookFunction & { hooks : LegacyHookFunction [ ] } ;
91+
92+ type LegacyStore = {
93+ before : { [ method : string ] : LegacyAdapter } ,
94+ after : { [ method : string ] : LegacyAdapter } ,
95+ error : { [ method : string ] : LegacyAdapter } ,
96+ hooks : { [ method : string ] : HookFunction [ ] }
97+ } ;
98+
99+ const types : LegacyType [ ] = [ 'before' , 'after' , 'error' ] ;
100+
101+ const isType = ( value : any ) : value is LegacyType => types . includes ( value ) ;
102+
103+ const wrappers = {
88104 before : fromBeforeHooks ,
89105 after : fromAfterHooks ,
90106 error : fromErrorHooks ,
91107} ;
92108
93- // Add `.hooks` functionality to an object
94- export function enableLegacyHooks (
95- obj : any ,
96- methods : string [ ] = defaultServiceMethods
97- ) {
98- const hookData : any = { hooks : { } } ;
99-
100- for ( const type of types ) {
101- hookData [ type ] = { } ;
102- }
109+ const createStore = ( methods : string [ ] ) => {
110+ const store : LegacyStore = {
111+ before : { } ,
112+ after : { } ,
113+ error : { } ,
114+ hooks : { }
115+ } ;
103116
104117 for ( const method of methods ) {
105- hookData . hooks [ method ] = [ ] ;
118+ store . hooks [ method ] = [ ] ;
106119 }
107120
108- // Add non-enumerable `__hooks` property to the object
109- Object . defineProperty ( obj , '__hooks' , {
121+ return store ;
122+ } ;
123+
124+ const setStore = ( object : any , store : LegacyStore ) => {
125+ Object . defineProperty ( object , '__hooks' , {
110126 configurable : true ,
111- value : hookData ,
127+ value : store ,
112128 writable : true
113129 } ) ;
130+ } ;
114131
115- return function legacyHooks ( this : any , allHooks : LegacyHookMap < any , any > ) {
116- const touched = new Set < string > ( ) ;
132+ const getStore = ( object : any ) : LegacyStore => object . __hooks ;
117133
118- for ( const [ type , current ] of Object . entries ( allHooks ) ) {
119- if ( ! types . includes ( type ) ) {
120- throw new Error ( `'${ type } ' is not a valid hook type` ) ;
121- }
134+ const createMap = ( input : LegacyHookMap < any , any > , methods : string [ ] ) => {
135+ const map = { } as LegacyMap ;
122136
123- const hooks = convertHookData ( current ) ;
137+ for ( const type of Object . keys ( input ) ) {
138+ if ( ! isType ( type ) ) {
139+ throw new Error ( `'${ type } ' is not a valid hook type` ) ;
140+ }
124141
125- for ( const method of Object . keys ( hooks ) ) {
126- if ( method !== 'all' && ! methods . includes ( method ) ) {
127- throw new Error ( `'${ method } ' is not a valid hook method` ) ;
128- }
142+ const data = convertHookData ( input [ type ] ) ;
143+
144+ for ( const method of Object . keys ( data ) ) {
145+ if ( method !== 'all' && ! methods . includes ( method ) ) {
146+ throw new Error ( `'${ method } ' is not a valid hook method` ) ;
129147 }
148+ }
149+
150+ map [ type ] = data ;
151+ }
152+
153+ return map ;
154+ } ;
130155
131- for ( const method of methods ) {
132- if ( ! hooks . all ?. length && ! hooks [ method ] ?. length ) continue ;
156+ const createAdapter = ( type : LegacyType ) => {
157+ const hooks : LegacyHookFunction [ ] = [ ] ;
158+ const hook = wrappers [ type ] ( hooks ) ;
159+ const adapter = Object . assign ( hook , { hooks } ) ;
133160
134- const hook = this . __hooks [ type ] [ method ] ||= ( ( ) => {
135- const hooks : LegacyHookFunction [ ] = [ ] ;
136- const hook = wrappers [ type ] ( hooks ) ;
137- hook . hooks = hooks ;
138- touched . add ( method ) ;
139- return hook ;
140- } ) ( ) ;
161+ return adapter ;
162+ } ;
163+
164+ const updateStore = ( store : LegacyStore , map : LegacyMap ) => {
165+ for ( const method of Object . keys ( store . hooks ) ) {
166+ let adapted = false ;
167+
168+ for ( const key of Object . keys ( map ) ) {
169+ const type = key as LegacyType ;
170+ const allHooks = map [ type ] . all || [ ] ;
171+ const methodHooks = map [ type ] [ method ] || [ ] ;
141172
142- hook . hooks . push ( ...( hooks . all || [ ] ) , ...( hooks [ method ] || [ ] ) ) ;
173+ if ( allHooks . length || methodHooks . length ) {
174+ const adapter = store [ type ] [ method ] ||= ( adapted = true , createAdapter ( type ) ) ;
175+
176+ adapter . hooks . push ( ...allHooks , ...methodHooks ) ;
143177 }
144178 }
145179
146- for ( const method of touched ) {
147- const before = this . __hooks . before [ method ] ;
148- const after = this . __hooks . after [ method ] ;
149- const error = this . __hooks . error [ method ] ;
180+ if ( adapted ) {
181+ store . hooks [ method ] = [
182+ store . error [ method ] ,
183+ store . before [ method ] ,
184+ store . after [ method ]
185+ ] . filter ( hook => hook ) ;
186+ }
187+ }
188+ } ;
150189
151- const hooks : HookFunction [ ] = [ ] ;
152- if ( error ) hooks . push ( error ) ;
153- if ( before ) hooks . push ( before ) ;
154- if ( after ) hooks . push ( after ) ;
190+ // Add `.hooks` functionality to an object
191+ export function enableLegacyHooks (
192+ object : any ,
193+ methods : string [ ] = defaultServiceMethods
194+ ) {
195+ const store = createStore ( methods ) ;
155196
156- this . __hooks . hooks [ method ] = hooks ;
157- }
197+ setStore ( object , store ) ;
198+
199+ return function legacyHooks ( this : any , input : LegacyHookMap < any , any > ) {
200+ const store = getStore ( this ) ;
201+ const map = createMap ( input , methods ) ;
202+
203+ updateStore ( store , map ) ;
158204
159205 return this ;
160206 }
0 commit comments