From e8797a9cbacd06dbf573ac5a343c4c1322c244f3 Mon Sep 17 00:00:00 2001 From: Kevin Delisle Date: Mon, 2 Oct 2017 15:58:12 -0400 Subject: [PATCH] feat(core): App-level configuration method app.config will bind all first and second level properties for retrieval via injection or .get methods --- packages/core/src/application.ts | 32 +++++++++++++++++++++ packages/core/test/unit/application.test.ts | 27 +++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/packages/core/src/application.ts b/packages/core/src/application.ts index 153205341a25..6df5048657b6 100644 --- a/packages/core/src/application.ts +++ b/packages/core/src/application.ts @@ -19,6 +19,8 @@ export class Application extends Context { // Make options available to other modules as well. this.bind(CoreBindings.APPLICATION_CONFIG).to(options); + this.config(options); + if (options.components) { for (const component of options.components) { this.component(component); @@ -161,6 +163,36 @@ export class Application extends Context { ); } + // tslint:disable-next-line:no-any + private config(cfg: {[key: string]: any}) { + for (const key in cfg) { + const item = cfg[key]; + // Iterate through the keys one level down (not recursively!) + if (item instanceof Object) { + for (const subkey in item) { + this.bindItemOrClass(`${key}.${subkey}`, item[subkey]); + } + } + this.bindItemOrClass(key, item); + } + } + /** + * Helper function for either binding an item or a class, depending. + * @private + * @param key The key of the configuration element. + * @param itemOrClass The item or class to bind. + */ + // tslint:disable-next-line:no-any + private bindItemOrClass(key: string, itemOrClass: any) { + if (itemOrClass instanceof Function) { + this.bind(key) + .toClass(itemOrClass) + .inScope(BindingScope.SINGLETON); + } else { + this.bind(key).to(itemOrClass); + } + } + /** * Add a component to this application. * diff --git a/packages/core/test/unit/application.test.ts b/packages/core/test/unit/application.test.ts index c4d0f542483e..facad401580f 100644 --- a/packages/core/test/unit/application.test.ts +++ b/packages/core/test/unit/application.test.ts @@ -26,6 +26,33 @@ describe('Application', () => { }); describe('configuration', () => { + it('allows bindings to be set via config method', async () => { + // tslint:disable-next-line:no-any + const samoflange: any = { + vertices: 'many', + usefulness: 0, + }; + const app = new Application({ + magicCode: 'foobar', + servers: { + abc123: FakeServer, + }, + CustomComponentCo: { + samoflange: samoflange, + }, + }); + const code = await app.get('magicCode'); + const server = (await app.getServer('abc123')) as FakeServer; + expect(code).to.equal('foobar'); + expect(server.constructor.name).to.equal(FakeServer.name); + const samo = await app.get('CustomComponentCo.samoflange'); + for (const key in samo) { + expect(samo[key]).to.equal(samoflange[key]); + } + const vertices = await app.get('CustomComponentCo.samoflange#vertices'); + expect(vertices).to.equal('many'); + }); + it('allows servers to be provided via config', async () => { const name = 'abc123'; const app = new Application({