import * as _ from "underscore" ; import { StepBinding } from "./step-binding" ; import { ContextType , StepPattern , TagName } from "./types" ; /**
 * Describes the binding metadata that is associated with a binding class.
 */ interface TargetBinding { /**
     * A reference to the step bindings that are associated with the binding class.
     */ stepBindings : StepBinding [ ] ; /**
     * The context types that are to be injected into the binding class during execution.
     */ contextTypes : ContextType [ ] ; } /**
 * Represents the default step pattern.
 */ export const DEFAULT_STEP_PATTERN = "/.*/" ; /**
 * Represents the default tag.
 */ export const DEFAULT_TAG = "*" ; /**
 * A metadata registry that captures information about bindings and their bound step bindings.
 */ export class BindingRegistry { private _bindings = new Map < StepPattern , Map < TagName , StepBinding [ ] > > ( ) ; private _targetBindings = new Map < any , TargetBinding > ( ) ; returns public static get instance ( ) : BindingRegistry { const BINDING_REGISTRY_SLOTNAME = "__CUCUMBER_TSFLOW_BINDINGREGISTRY" ; const registry = ( global as any ) [ BINDING_REGISTRY_SLOTNAME ] ; if ( ! registry ) { ( global as any ) [ BINDING_REGISTRY_SLOTNAME ] = new BindingRegistry ( ) ; } return registry || ( global as any ) [ BINDING_REGISTRY_SLOTNAME ] ; } param targetPrototype param contextTypes public registerContextTypesForTarget ( targetPrototype , contextTypes ? ) { if ( ! contextTypes ) { return ; } let targetDecorations = this . _targetBindings . get ( targetPrototype ) ; if ( ! targetDecorations ) { targetDecorations = { stepBindings : [ ] , contextTypes : [ ] } ; this . _targetBindings . set ( targetPrototype , targetDecorations ) ; } targetDecorations . contextTypes = contextTypes ; } param targetPrototype returns public getContextTypesForTarget ( targetPrototype ) { const targetBinding = this . _targetBindings . get ( targetPrototype ) ; if ( ! targetBinding ) { return [ ] ; } return targetBinding . contextTypes ; } param stepBinding public registerStepBinding ( stepBinding ) { if ( ! stepBinding . tag ) { stepBinding . tag = DEFAULT_TAG ; } const stepPattern = stepBinding . stepPattern ? stepBinding . stepPattern . toString ( ) : DEFAULT_STEP_PATTERN ; let tagMap = this . _bindings . get ( stepPattern ) ; if ( ! tagMap ) { tagMap = new Map < TagName , StepBinding [ ] > ( ) ; this . _bindings . set ( stepPattern , tagMap ) ; } let stepBindings = tagMap . get ( stepBinding . tag ) ; if ( ! stepBindings ) { stepBindings = [ ] ; tagMap . set ( stepBinding . tag , stepBindings ) ; } if ( ! stepBindings . some ( b => isSameStepBinding ( stepBinding , b ) ) ) { stepBindings . push ( stepBinding ) ; } let targetBinding = this . _targetBindings . get ( stepBinding . targetPrototype ) ; if ( ! targetBinding ) { targetBinding = { stepBindings : [ ] , contextTypes : [ ] } ; this . _targetBindings . set ( stepBinding . targetPrototype , targetBinding ) ; } if ( ! targetBinding . stepBindings . some ( b => isSameStepBinding ( stepBinding , b ) ) ) { targetBinding . stepBindings . push ( stepBinding ) ; } function isSameStepBinding ( a , b ) { return ( a . callsite . filename === b . callsite . filename && a . callsite . lineNumber === b . callsite . lineNumber && String ( a . stepPattern ) === String ( b . stepPattern ) ) ; } } param targetPrototype returns public getStepBindingsForTarget ( targetPrototype ) { const targetBinding = this . _targetBindings . get ( targetPrototype ) ; if ( ! targetBinding ) { return [ ] ; } return targetBinding . stepBindings ; } param stepPattern param tags returns public getStepBindings ( stepPattern , tags ) { const tagMap = this . _bindings . get ( stepPattern ) ; if ( ! tagMap ) { return [ ] ; } const matchingStepBindings = this . mapTagNamesToStepBindings ( tags , tagMap ) ; if ( matchingStepBindings . length > 0 ) { return matchingStepBindings ; } return this . mapTagNamesToStepBindings ( [ "*" ] , tagMap ) ; } param tags param tagMap returns private mapTagNamesToStepBindings ( tags , tagMap ) { const matchingStepBindings = _ . flatten ( _ . map ( tags , tag => tagMap . get ( tag ) ) ) ; return _ . reject ( matchingStepBindings , stepBinding => stepBinding === undefined ) ; } }