import { Definition , DefinitionKind } from './Definition' ; import { Reference } from './Reference' ; export type Metadata = Reference < any > | Definition < any > ; /**
 * Keep all [[Definition]] and references.
 * Provide methods to query metadata with its associated class or graphql type name.
 */ export class MetadataStorage { protected readonly deferredRegister : Array < ( ) => void > = [ ] ; protected deferredResolved = false ; public readonly definitions : Definition [ ] = [ ] ; public readonly references : Reference [ ] = [ ] ; public deferRegister ( metadataFn ) { this . deferredRegister . unshift ( metadataFn ) ; } protected resolveDeferred ( ) { while ( this . deferredRegister . length > 0 ) { this . deferredRegister . pop ( ) ! ( ) ; } } public registerMetadata ( metadata ) { metadata . map ( entry => { if ( entry instanceof Definition ) { this . definitions . push ( entry ) ; } else if ( entry instanceof Reference ) { this . references . push ( entry ) ; } } ) ; } param metadataClass param definitionKey param asKind public getDefinition < T extends Definition > ( metadataClass , definitionKey , asKind ) { this . resolveDeferred ( ) ; const entry = this . definitions . find ( metadata => { let classOrNameMatched ; if ( typeof definitionKey === 'string' ) { classOrNameMatched = metadata . definitionName === definitionKey ; } else { classOrNameMatched = metadata . definitionClass === definitionKey ; } const typeMatched = asKind === 'any' || metadata . kind === 'any' || metadata . kind === asKind ; return classOrNameMatched && ( metadata instanceof metadataClass ) && typeMatched ; } ) ; return entry as T ; } public findReference < T extends Reference > ( metadataClass , definitionKey ) { this . resolveDeferred ( ) ; const entries = this . references . filter ( metadata => { let classOrNameMatched ; if ( definitionKey instanceof Function ) { classOrNameMatched = metadata . source instanceof Function && equalsOrInherits ( definitionKey , metadata . source ) ; } else { classOrNameMatched = metadata . source === definitionKey ; } return classOrNameMatched && ( metadata instanceof metadataClass ) ; } ) ; return entries as T [ ] ; } } export function equalsOrInherits ( cls , superClass ) { return cls === superClass || cls . prototype instanceof superClass ; }