import type * as ts from 'typescript' ; import { Scope } from '../../scope/scope' ; import { core } from '../../core/core' ; import { TypescriptHelper } from '../helper/helper' ; import { GetMockPropertiesFromDeclarations } from '../mock/mockProperties' ; import { GetTypeQueryDescriptorFromDeclaration } from '../typeQuery/typeQuery' ; import { createIdentifier , createPropertySignature , createTypeLiteralNode , createTypeQueryNode , } from '../../../typescriptFactory/typescriptFactory' ; import GetDeclarationFromSymbol = TypescriptHelper . GetDeclarationFromSymbol ; type ExternalSource = ts . SourceFile | ts . ModuleDeclaration ; export function GetModuleDescriptor ( node , scope ) { if ( ! node . name ) { throw new Error ( `Cannot look up symbol for a node without a name: ${ node . getText ( ) }.` ) ; } const typeChecker = core . typeChecker ; const symbolAlias = typeChecker . getSymbolAtLocation ( node . name ) ; if ( ! symbolAlias ) { throw new Error ( `The type checker failed to look up symbol for \`${ node . name . getText ( ) }'.` ) ; } const symbol = typeChecker . getAliasedSymbol ( symbolAlias ) ; const externalModuleDeclaration = GetDeclarationFromSymbol ( symbol ) ; if ( isExternalSource ( externalModuleDeclaration ) ) { return GetPropertiesFromSourceFileOrModuleDeclarationDescriptor ( externalModuleDeclaration , symbol , scope ) ; } return GetTypeQueryDescriptorFromDeclaration ( externalModuleDeclaration , scope ) ; } function isExternalSource ( declaration ) { return ( core . ts . isSourceFile ( declaration ) || core . ts . isModuleDeclaration ( declaration ) ) ; } function GetPropertiesFromSourceFileOrModuleDeclarationDescriptor ( sourceFile , symbol , scope ) { return GetMockPropertiesFromDeclarations ( GetPropertiesFromSourceFileOrModuleDeclaration ( symbol , scope ) , [ ] , scope ) ; } interface ModuleExportsDeclarations { declaration : ts . Declaration ; originalDeclaration : ts . NamedDeclaration ; } export function GetPropertiesFromSourceFileOrModuleDeclaration ( symbol , scope ) { const typeChecker = core . typeChecker ; const moduleExports = typeChecker . getExportsOfModule ( symbol ) ; return moduleExports . map ( ( prop ) : Partial < ModuleExportsDeclarations > => { const originalSymbol = TypescriptHelper . GetAliasedSymbolSafe ( prop ) ; const originalDeclaration = originalSymbol ?. declarations ?. [ 0 ] ; const declaration = prop ?. declarations ?. [ 0 ] ; return { declaration , originalDeclaration , } ; } ) . filter ( ( d ) => ! ! d . originalDeclaration && d . declaration ) . map ( ( d ) : ts . PropertySignature => { if ( core . ts . isExportAssignment ( d . declaration ) ) { return createPropertySignature ( 'default' , createTypeQueryNode ( d . originalDeclaration . name as ts . Identifier ) ) ; } if ( core . ts . isExportSpecifier ( d . declaration ) && core . ts . isSourceFile ( d . originalDeclaration ) ) { const exportSpecifierSymbol = typeChecker . getSymbolAtLocation ( d . declaration . name ) ; if ( ! exportSpecifierSymbol ) { throw new Error ( `The type checker failed to look up symbol for \`${ d . declaration . name . getText ( ) }'.` ) ; } const exportSpecifierAliasSymbol = typeChecker . getAliasedSymbol ( exportSpecifierSymbol ) ; const exportSpecifierProperties = GetPropertiesFromSourceFileOrModuleDeclaration ( exportSpecifierAliasSymbol , scope ) ; const propertyType = createTypeLiteralNode ( exportSpecifierProperties ) ; return createPropertySignature ( d . declaration . name , propertyType ) ; } return createPropertySignature ( ( d . originalDeclaration . name as ts . Identifier ) || createIdentifier ( 'default' ) , createTypeQueryNode ( d . originalDeclaration . name as ts . Identifier ) ) ; } ) ; }