import { asResolutionOptions , assertTargetType , Binding , BindingFilter , BindingFromClassOptions , BindingSpec , BindingTemplate , Constructor , Context , ContextTags , ContextView , createBindingFromClass , createViewGetter , filterByTag , includesTagValue , inject , injectable , Injection , InjectionMetadata , ResolutionSession , } from '@loopback/context' ; import { CoreTags } from './keys' ; example extensionPoint param name export function extensionPoint ( name , ... specs ) { return injectable ( { tags : { [ CoreTags . EXTENSION_POINT ] : name } } , ... specs ) ; } example extensionPoint extensions param extensionPointName param metadata export function extensions ( extensionPointName ? , metadata ? ) { return inject ( '' , { ... metadata , decorator : '@extensions' } , ( ctx , injection , session ) => { assertTargetType ( injection , Function , 'Getter function' ) ; const bindingFilter = filterByExtensionPoint ( injection , session , extensionPointName ) ; return createViewGetter ( ctx , bindingFilter , injection . metadata . bindingComparator , { ... metadata , ... asResolutionOptions ( session ) } ) ; } ) ; } export namespace extensions { example extensionPoint extensions param extensionPointName param metadata export function view ( extensionPointName ? , metadata ? ) { return inject ( '' , { ... metadata , decorator : '@extensions.view' } , ( ctx , injection , session ) => { assertTargetType ( injection , ContextView ) ; const bindingFilter = filterByExtensionPoint ( injection , session , extensionPointName ) ; return ctx . createView ( bindingFilter , injection . metadata . bindingComparator , metadata ) ; } ) ; } example extensionPoint extensions param extensionPointName param metadata export function list ( extensionPointName ? , metadata ? ) { return inject ( '' , { ... metadata , decorator : '@extensions.instances' } , ( ctx , injection , session ) => { assertTargetType ( injection , Array ) ; const bindingFilter = filterByExtensionPoint ( injection , session , extensionPointName ) ; const viewForExtensions = new ContextView ( ctx , bindingFilter , injection . metadata . bindingComparator ) ; return viewForExtensions . resolve ( { ... metadata , ... asResolutionOptions ( session ) , } ) ; } ) ; } } param injection param session param extensionPointName function filterByExtensionPoint ( injection , session , extensionPointName ? ) { extensionPointName = extensionPointName ?? inferExtensionPointName ( injection . target , session . currentBinding ) ; return extensionFilter ( extensionPointName ) ; } param injectionTarget param currentBinding function inferExtensionPointName ( injectionTarget , currentBinding ? ) { if ( currentBinding ) { const name = currentBinding . tagMap [ CoreTags . EXTENSION_POINT ] || currentBinding . tagMap [ ContextTags . NAME ] ; if ( name ) return name ; } let target ; if ( typeof injectionTarget === 'function' ) { target = injectionTarget ; } else { target = injectionTarget . constructor ; } return target . name ; } param extensionPointNames export function extensionFilter ( ... extensionPointNames ) { return filterByTag ( { [ CoreTags . EXTENSION_FOR ] : includesTagValue ( ... extensionPointNames ) , } ) ; } param extensionPointNames export function extensionFor ( ... extensionPointNames ) { return binding => { if ( extensionPointNames . length === 0 ) return ; let extensionPoints = binding . tagMap [ CoreTags . EXTENSION_FOR ] ; if ( extensionPoints == null ) { extensionPoints = [ ] ; } else if ( typeof extensionPoints === 'string' ) { extensionPoints = [ extensionPoints ] ; } for ( const extensionPointName of extensionPointNames ) { if ( ! extensionPoints . includes ( extensionPointName ) ) { extensionPoints . push ( extensionPointName ) ; } } if ( extensionPoints . length === 1 ) { extensionPoints = extensionPoints [ 0 ] ; } binding . tag ( { [ CoreTags . EXTENSION_FOR ] : extensionPoints } ) ; } ; } param context param extensionPointName param extensionClass param options export function addExtension ( context , extensionPointName , extensionClass , options ? ) { const binding = createBindingFromClass ( extensionClass , options ) . apply ( extensionFor ( extensionPointName ) ) ; context . add ( binding ) ; return binding ; }