diff --git a/CHANGELOG.md b/CHANGELOG.md index af22c13..9ce23d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Removed support for Node.js below 12 - Added support for asynchronous creators (#54) - Added optional `direction` parameter to middlewares (#53) +- Added a deep merge of injector settings (#52) - Updated dependencies ## 0.14.3 diff --git a/src/server/core/config.ts b/src/server/core/config.ts index f0511cd..708137f 100644 --- a/src/server/core/config.ts +++ b/src/server/core/config.ts @@ -89,6 +89,25 @@ export function readConfiguration(path: string): ConfigurationFile { return {}; } +function deepMerge(obj: any, value: any) { + Object.keys(value).forEach((key) => { + const oldItem = obj[key]; + const newItem = value[key]; + + if (newItem === undefined) { + delete obj[key]; + } else if (Array.isArray(oldItem) && Array.isArray(newItem)) { + obj[key] = [...oldItem, ...newItem] as any; + } else if (typeof oldItem === 'object') { + obj[key] = deepMerge({ ...oldItem }, newItem); + } else { + obj[key] = newItem; + } + }); + + return obj; +} + function mergeObjects( sources: Array>, select: (config: Partial) => Dict, @@ -99,21 +118,7 @@ function mergeObjects( const value = select(source); if (value && typeof value === 'object') { - Object.keys(value).forEach((key) => { - const oldItem = obj[key]; - const newItem = value[key]; - - if (newItem === undefined) { - delete obj[key]; - } else if (typeof oldItem === 'object') { - obj[key] = { - ...oldItem, - ...newItem, - }; - } else { - obj[key] = newItem; - } - }); + deepMerge(obj, value); } } diff --git a/src/server/core/webserver.ts b/src/server/core/webserver.ts index 547758d..f23ab8f 100644 --- a/src/server/core/webserver.ts +++ b/src/server/core/webserver.ts @@ -222,7 +222,11 @@ export class WebServer extends EventEmitter implements BaseKrasServer { return api; } - start() { + async setup() {} + + async start() { + await this.setup(); + this.app.all('*', (req: Request, res: Response) => { if (req.method !== 'OPTIONS') { const hook = findHook(this.hooks, req); @@ -239,7 +243,7 @@ export class WebServer extends EventEmitter implements BaseKrasServer { return corsHandler(req, res); }); - return new Promise((resolve) => { + return await new Promise((resolve) => { this.server.listen(this.port, () => { this.emit('open', { port: this.port, diff --git a/src/server/server.ts b/src/server/server.ts index e532ede..3cf8b3a 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -55,7 +55,7 @@ export class MockServer extends MockServerCore implements KrasServer { readonly logs: Array = []; readonly logLevel: LogLevel; - constructor(config: KrasConfiguration) { + constructor(private config: KrasConfiguration) { super(config); this.logLevel = config.logLevel || 'error'; @@ -66,15 +66,18 @@ export class MockServer extends MockServerCore implements KrasServer { } } - async setup(config: KrasConfiguration) { + async setup() { + const config = this.config; + await super.setup(); await withManagement(this, config); await withInjectors(this, config); await withMiddlewares(this, config); await withFiles(this, config); } - stop() { - return super.stop().then(() => this.injectors.forEach(disposeInjector)); + async stop() { + await super.stop(); + this.injectors.forEach(disposeInjector); } private log(type: LogEntryType, data: any) { @@ -98,30 +101,28 @@ export function readKrasConfig(options?: ConfigurationOptions, ...files: Array) { +export function buildKras(config?: Partial) { const options = buildConfiguration(config); - const server = new MockServer(options); - await server.setup(options); - return server; + return new MockServer(options); } -export async function buildKrasWithCli(config: KrasConfiguration) { - const server = await buildKras(config); +export function buildKrasWithCli(config: KrasConfiguration) { + const server = buildKras(config); connectToCli(server, config.api !== false); return server; } export async function runKras(config?: Partial) { - const server = await buildKras(config); - server.start(); + const server = buildKras(config); + await server.start(); return server; } export type KrasRuntimeConfiguration = Partial & KrasHandlerConfiguration; export function withKras(config?: KrasRuntimeConfiguration) { - return async (callback: KrasRunner) => { - const server = await buildKras(config); + return (callback: KrasRunner) => { + const server = buildKras(config); configureHandler(server, config); return runWith(server, callback); }; @@ -205,8 +206,8 @@ export function connectToCli(server: MockServer, canManage = true) { export async function runFromCli(options: ConfigurationOptions, rcfile: string) { const config = readKrasConfig(options, resolve(homedir(), krasrc), resolve(currentDir, krasrc), rcfile); - const server = await buildKrasWithCli(config); + const server = buildKrasWithCli(config); console.log(`Starting kras v${version} ...`); - server.start(); + await server.start(); return server; }