import * as path from "path" ; import * as fs from "fs" ; import * as glob from "glob" ; import { program } from "commander" ; import { typescript } from "../classes/process/typescript" ; import { projectRoot } from "../classes/process/projectRoot" ; import { ensureNoTsHeaderFiles } from "../modules/utils/ensureNoTsHeaderFiles" ; import { CLI } from "../classes/cli" ; import { PackageJson } from "type-fest" ; import "../config/api" ; import "../config/plugins" ; import "../config/logger" ; import "../config/routes" ; export namespace ActionheroCLIRunner { export async function run ( ) { program . storeOptionsAsProperties ( false ) ; program . version ( getVersion ( ) ) ; let pathsLoaded = [ ] ; try { const { config } = await import ( "../index" ) ; for ( const p of config . general . paths . cli ) { await loadDirectory ( path . join ( p ) , pathsLoaded ) ; } for ( const plugin of Object . values ( config . plugins ) ) { if ( plugin . cli !== false ) { await loadDirectory ( path . join ( plugin . path , "bin" ) , pathsLoaded ) ; await loadDirectory ( path . join ( plugin . path , "dist" , "bin" ) , pathsLoaded ) ; } } if ( config . general . cliIncludeInternal !== false ) { await loadDirectory ( __dirname , pathsLoaded ) ; } } catch ( e ) { await loadDirectory ( path . join ( __dirname ) , pathsLoaded , "generate" ) ; } program . parse ( process . argv ) ; } export async function loadDirectory ( dir , pathsLoaded , match = "*" ) { if ( ! fs . existsSync ( dir ) ) return ; const realpath = fs . realpathSync ( dir ) ; if ( pathsLoaded . includes ( realpath ) ) return ; pathsLoaded . push ( realpath ) ; const matcher = `${ realpath }/**/+(${ typescript ? `${ match }.js|*.ts` : `${ match }.js` })` ; const files = ensureNoTsHeaderFiles ( glob . sync ( matcher ) ) ; for ( const i in files ) { const collection = await import ( files [ i ] ) ; for ( const j in collection ) { const command = collection [ j ] ; convertCLIToCommanderAction ( command ) ; } } } export async function convertCLIToCommanderAction ( cliConstructor ) { if ( Object . getPrototypeOf ( cliConstructor ?. prototype ?. constructor || { } ) . name !== "CLI" ) { return ; } const instance = new cliConstructor ( ) ; const command = program . command ( instance . name ) . description ( instance . description ) . action ( async ( _arg1 , _arg2 , _arg3 , _arg4 , _arg5 ) => { await runCommand ( instance , _arg1 , _arg2 , _arg3 , _arg4 , _arg5 ) ; } ) . on ( "--help" , ( ) => { if ( instance . example ) { console . log ( "" ) ; console . log ( "Example: \r\n" + "  " + instance . example ) ; } if ( typeof instance . help === "function" ) instance . help ( ) ; } ) ; for ( const key in instance . inputs ) { const input = instance . inputs [ key ] ; if ( input . flag && ! input . letter ) { throw new Error ( `flag inputs require a short letter (${ JSON . stringify ( input ) })` ) ; } const separators = input . required ? [ "<" , ">" ] : [ "[" , "]" ] ; const methodName = input . required ? "requiredOption" : "option" ; const argString = `${ input . letter ? `-${ input . letter }, ` : "" }--${ key } ${ input . flag ? "" : `${ separators [ 0 ] }${ input . placeholder || key }${ input . variadic ? "..." : "" }${ separators [ 1 ] }` }` ; command [ methodName ] ( argString , input . description , input . default ) ; } } export async function runCommand ( instance , _arg1 , _arg2 , _arg3 , _arg4 , _arg5 ) { let toStop = false ; let _arguments = [ ] ; let params = { } ; [ _arg1 , _arg2 , _arg3 , _arg4 , _arg5 ] . forEach ( ( arg ) => { if ( typeof arg ?. opts === "function" ) { params = arg . opts ( ) ; } else if ( arg !== null && arg !== undefined && typeof arg !== "object" ) { _arguments . push ( arg ) ; } } ) ; params [ "_arguments" ] = _arguments ; for ( const [ key , inputOpts ] of Object . entries ( instance . inputs ) ) { if ( typeof inputOpts . formatter === "function" ) { params [ key ] = await inputOpts . formatter ( params [ key ] ) ; } if ( typeof inputOpts . validator === "function" ) { await inputOpts . validator ( params [ key ] ) ; } } if ( instance . initialize === false && instance . start === false ) { toStop = await instance . run ( { params } ) ; } else { try { const { Process } = await import ( "../index" ) ; const actionHeroProcess = new Process ( ) ; if ( instance . initialize ) await actionHeroProcess . initialize ( ) ; if ( instance . start ) await actionHeroProcess . start ( ) ; toStop = await instance . run ( { params } ) ; } catch ( error ) { console . error ( error . toString ( ) ) ; process . exit ( 1 ) ; } } if ( toStop || toStop === null || toStop === undefined ) { setTimeout ( process . exit , 500 , 0 ) ; } } export function readPackageJSON ( file ) { return JSON . parse ( fs . readFileSync ( file ) . toString ( ) ) ; } export function getVersion ( ) { const parentPackageJSON = path . join ( projectRoot , "package.json" ) ; if ( fs . existsSync ( parentPackageJSON ) ) { const pkg = readPackageJSON ( parentPackageJSON ) ; return pkg . version ; } else { const pkg = readPackageJSON ( path . join ( __dirname , ".." , ".." , "package.json" ) ) ; return pkg . version ; } } } ActionheroCLIRunner . run ( ) ;