import { CreateDtsFlags , CreateOptions , PlainObj , ExportFlags } from './' ; import ts from 'typescript' ; import * as dom from './dom' ; import path from 'path' ; import fs from 'fs' ; export interface Declaration { import : dom . Import [ ] ; export : dom . TopLevelDeclaration [ ] ; fragment : dom . NamespaceMember [ ] ; } export interface ImportCacheElement { default ? : string ; list : Array < { name : string ; as ? : string ; } > ; from : string ; realPath : string ; } export interface Env { file : string ; dist : string ; uniqId : number ; flags : CreateDtsFlags ; program : ts . Program ; checker : ts . TypeChecker ; sourceFile : ts . SourceFile ; declaration : Declaration ; importCache : { [ key ] : ImportCacheElement ; } ; declareCache : Array < { node : ts . Declaration ; name : string ; } > ; publicNames : PlainObj < number > ; exportDefaultName ? : string ; exportNamespace ? : dom . NamespaceDeclaration ; interfaceList : dom . InterfaceDeclaration [ ] ; deps : { [ key ] : { env : Env ; namespace : dom . NamespaceDeclaration ; } ; } ; ambientModNames : string [ ] ; exportFlags : ExportFlags ; toString : ( ) => string ; write : ( prefix ? : string ) => string ; } export let env ; let envCache = { } ; const envStack = [ ] ; export function getTopEnv ( ) { return envStack . length ? envStack [ 0 ] : env ; } function getTopEnvOpt < T extends keyof Env = keyof Env > ( key , def ) { return envStack . length ? envStack [ 0 ] [ key ] : def ; } export function getEnv ( file ) { return envCache [ file ] ; } export function createEnv ( file , options = { } ) { const program = ts . createProgram ( [ file ] , { target : ts . ScriptTarget . ES2017 , module : ts . ModuleKind . CommonJS , allowJs : true , noErrorTruncation : true , } ) ; if ( env ) { envStack . push ( env ) ; } const checker = program . getTypeChecker ( ) ; const sourceFile = program . getSourceFile ( file ) ! ; const ambientMods = checker . getAmbientModules ( ) ; const ambientModNames = ambientMods . map ( mod => mod . escapedName . toString ( ) . replace ( /^"|"$/g , '' ) ) ; env = { file , dist : options . dist || `${ path . dirname ( file ) }/${ path . basename ( file , path . extname ( file ) ) }.d.ts` , deps : { } , program , checker , sourceFile , declaration : { import : [ ] , fragment : [ ] , export : [ ] , } , ambientModNames , declareCache : [ ] , interfaceList : [ ] , exportFlags : ExportFlags . None , uniqId : getTopEnvOpt ( 'uniqId' , 100 ) , flags : getTopEnvOpt ( 'flags' , ( options . flags || CreateDtsFlags . None ) ) , publicNames : getTopEnvOpt ( 'publicNames' , { } ) , importCache : getTopEnvOpt ( 'importCache' , { } ) , toString ( ) { return [ dom . emit ( this . declaration . import ) , dom . emit ( this . declaration . fragment ) , dom . emit ( this . declaration . export ) , ] . join ( '' ) ; } , write ( prefix ? ) { const content = this . toString ( ) ; fs . writeFileSync ( this . dist , `${ prefix ? `${ prefix }\n\n` : '' }${ content }` ) ; return content ; } , } ; envCache [ file ] = env ; } export function popEnv ( ) { const response = env ; env = envStack . pop ( ) ! ; if ( ! envStack . length ) { envCache = { } ; } return response ; }