import * as fs from "fs" ; import * as path from "path" ; import * as tsc from "typescript" ; import { Pair } from "tstl/utility/Pair" ; import { Singleton } from "tstl/thread/Singleton" ; import { ControllerAnalyzer } from "./analyses/ControllerAnalyzer" ; import { ReflectAnalyzer } from "./analyses/ReflectAnalyzer" ; import { SourceFinder } from "./analyses/SourceFinder" ; import { SdkGenerator } from "./generates/SdkGenerator" ; import { IController } from "./structures/IController" ; import { IRoute } from "./structures/IRoute" ; import { ArrayUtil } from "./utils/ArrayUtil" ; export class NestiaApplication { private readonly config_ : NestiaApplication . IConfiguration ; private readonly bundle_checker_ : Singleton < Promise < ( str : string ) => boolean > > ; public constructor ( config ) { this . config_ = config ; this . bundle_checker_ = new Singleton ( async ( ) => { const bundles = await fs . promises . readdir ( `${ __dirname }${ path . sep }bundle` ) ; const tuples = await ArrayUtil . asyncMap ( bundles , async ( file ) => { const relative = `${ this . config_ . output }${ path . sep }${ file }` ; const stats = await fs . promises . stat ( `${ __dirname }${ path . sep }bundle${ path . sep }${ file }` ) ; return new Pair ( relative , stats . isDirectory ( ) ) ; } ) ; return ( file ) : boolean => { for ( const it of tuples ) if ( it . second === false && file === it . first ) return true ; else if ( it . second === true && file . indexOf ( it . first ) === 0 ) return true ; return false ; } ; } ) ; } public async generate ( ) { const fileList = [ ] ; const inputList = this . config_ . input instanceof Array ? this . config_ . input : [ this . config_ . input ] ; for ( const file of inputList . map ( str => path . resolve ( str ) ) ) { const found = await SourceFinder . find ( file ) ; const filtered = await ArrayUtil . asyncFilter ( found , file => this . is_not_excluded ( file ) ) ; fileList . push ( ... filtered ) ; } const unique = new WeakSet ( ) ; const controllerList = [ ] ; for ( const file of fileList ) controllerList . push ( ... await ReflectAnalyzer . analyze ( unique , file ) ) ; const program = tsc . createProgram ( controllerList . map ( c => c . file ) , this . config_ . compilerOptions || { } ) ; const checker = program . getTypeChecker ( ) ; const routeList = [ ] ; for ( const controller of controllerList ) { const sourceFile = program . getSourceFile ( controller . file ) ; if ( sourceFile === undefined ) continue ; routeList . push ( ... ControllerAnalyzer . analyze ( checker , sourceFile , controller ) ) ; } await SdkGenerator . generate ( this . config_ . output , routeList ) ; } private async is_not_excluded ( file ) { return file . indexOf ( `${ this . config_ . output }${ path . sep }functional` ) === - 1 && ( await this . bundle_checker_ . get ( ) ) ( file ) === false ; } } export namespace NestiaApplication { export interface IConfiguration { input : string | string [ ] ; output : string ; compilerOptions ? : tsc . CompilerOptions ; } }