import * as fs from "fs" ; import * as path from "path" ; import * as glob from "glob" ; import { utils } from "./utils" ; import { ensureNoTsHeaderFiles } from "./utils/ensureNoTsHeaderFiles" ; import { env , recalculateEnv } from "./../classes/process/env" ; import { id , recalcuateId } from "./../classes/process/id" ; import { actionheroVersion , recalculateActionheroVersion , } from "./../classes/process/actionheroVersion" ; import { recalculateIsTypescript , typescript , } from "./../classes/process/typescript" ; import { projectRoot , recalculateProjectRoot , } from "./../classes/process/projectRoot" ; import { RouteMethod , RoutesConfig , RouteType } from ".." ; import { ActionheroConfigInterface } from "../classes/config" ; export function buildConfig ( ) { const configPaths = [ ] ; let config = { process : { env , id , typescript , projectRoot , actionheroVersion , } , } ; function addConfigPath ( pathToCheck , alreadySplit ) { if ( typeof pathToCheck === "string" ) { if ( ! alreadySplit ) { addConfigPath ( pathToCheck . split ( "," ) , true ) ; } else { if ( pathToCheck . charAt ( 0 ) !== "/" ) { pathToCheck = path . resolve ( projectRoot , pathToCheck ) ; } if ( fs . existsSync ( pathToCheck ) ) { configPaths . push ( pathToCheck ) ; } } } else if ( Array . isArray ( pathToCheck ) ) { pathToCheck . map ( ( entry ) => { addConfigPath ( entry , alreadySplit ) ; } ) ; } } [ utils . argv . config ?. toString ( ) , process . env . ACTIONHERO_CONFIG ] . map ( ( entry ) => { addConfigPath ( entry , false ) ; } ) ; if ( configPaths . length < 1 && typescript ) { addConfigPath ( "src/config" , false ) ; } if ( configPaths . length < 1 ) { addConfigPath ( "dist/config" , false ) ; } if ( configPaths . length < 1 ) { throw new Error ( configPaths + "No config directory found in this project.  Did you compile your typescript project?" ) ; } const loadConfigFile = ( f ) => { const localConfig = require ( f ) ; if ( f . includes ( "routes.js" ) || f . includes ( "routes.ts" ) ) { if ( f . includes ( `${ path . sep }node_modules${ path . sep }actionhero${ path . sep }` ) ) { return ; } let localRoutes = { routes : { } } ; if ( localConfig . DEFAULT ) { localRoutes = utils . hashMerge ( localRoutes , localConfig . DEFAULT , config ) ; } if ( localConfig [ env ] ) { localRoutes = utils . hashMerge ( localRoutes , localConfig [ env ] , config ) ; } ( Object . keys ( localRoutes . routes ) as RouteMethod [ ] ) . forEach ( ( v ) => { if ( config . routes && config . routes [ v ] ) { config . routes [ v ] . push ( ... localRoutes . routes [ v ] ) ; } else { if ( ! config . routes ) config . routes = { } ; config . routes [ v ] = localRoutes . routes [ v ] ; } } ) ; } else { if ( localConfig . DEFAULT ) { config = utils . hashMerge ( config , localConfig . DEFAULT , config ) ; } if ( localConfig [ env ] ) { config = utils . hashMerge ( config , localConfig [ env ] , config ) ; } } } ; const loadConfigDirectory = ( configPath , watch ) => { const configFiles = ensureNoTsHeaderFiles ( glob . sync ( path . join ( configPath , "**" , "**/*(*.js|*.ts)" ) ) ) ; let loadRetries = 0 ; let loadErrors = { } ; for ( let i = 0 , limit = configFiles . length ; i < limit ; i ++ ) { const f = configFiles [ i ] ; try { loadConfigFile ( f ) ; loadRetries = 0 ; loadErrors = { } ; } catch ( error ) { loadErrors [ f ] = { error : error , msg : error . toString ( ) } ; if ( ++ loadRetries === limit - i ) { Object . keys ( loadErrors ) . forEach ( ( e ) => { console . log ( loadErrors [ e ] . error . stack ) ; console . log ( "" ) ; delete loadErrors [ e ] . error ; } ) ; throw new Error ( "Unable to load configurations, errors: " + JSON . stringify ( loadErrors ) ) ; } configFiles . push ( configFiles . splice ( i -- , 1 ) [ 0 ] ) ; continue ; } } configFiles . forEach ( loadConfigFile ) ; if ( config . routes ) { ( Object . keys ( config . routes ) as RouteMethod [ ] ) . forEach ( ( v ) => { config . routes [ v ] = config . routes [ v ] . filter ( ( route , index , self ) => index === self . findIndex ( ( r ) => r . path === route . path && r . action === route . action && r . apiVersion === route . apiVersion && r . matchTrailingPathParts === route . matchTrailingPathParts && r . dir === route . dir ) ) ; } ) ; } } ; loadConfigDirectory ( path . join ( __dirname , "/../config" ) , false ) ; configPaths . map ( ( p ) => loadConfigDirectory ( p , false ) ) ; if ( process . env . ACTIONHERO_CONFIG_OVERRIDES ) { try { config = utils . hashMerge ( config , JSON . parse ( process . env . ACTIONHERO_CONFIG_OVERRIDES ) ) ; } catch ( error ) { throw new Error ( `could not parse ACTIONHERO_CONFIG_OVERRIDES: ${ error }` ) ; } } if ( utils . argv . ACTIONHERO_CONFIG_OVERRIDES ) { try { config = utils . hashMerge ( config , JSON . parse ( utils . argv . ACTIONHERO_CONFIG_OVERRIDES . toString ( ) ) ) ; } catch ( error ) { throw new Error ( `could not parse ACTIONHERO_CONFIG_OVERRIDES: ${ error }` ) ; } } return config ; } export let config = buildConfig ( ) ; /**
 * Rebuild Actionhero's `config` object.  Useful when Environment variables effecting the config may have changed.
 */ export const rebuildConfig = ( ) => { recalculateEnv ( ) ; recalculateActionheroVersion ( ) ; recalcuateId ( ) ; recalculateProjectRoot ( ) ; recalculateIsTypescript ( ) ; config = buildConfig ( ) ; } ;