From 8cd3c23be33cb9e5e27f559512fceada4d50367c Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Thu, 30 May 2019 20:18:18 +0300 Subject: [PATCH] feat(core): node.defaultChild as a shortcut to escape hatch (#2684) Convenience property which returns the child with id "Resource" or "Default" (fails if there are both). This is useful in order to enable escape hatching. Closes #2290 --- packages/@aws-cdk/cdk/lib/construct.ts | 15 +++++++ packages/@aws-cdk/cdk/test/test.construct.ts | 41 ++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/packages/@aws-cdk/cdk/lib/construct.ts b/packages/@aws-cdk/cdk/lib/construct.ts index 8bbfc2f4ec0de..83088a1ac2748 100644 --- a/packages/@aws-cdk/cdk/lib/construct.ts +++ b/packages/@aws-cdk/cdk/lib/construct.ts @@ -183,6 +183,21 @@ export class ConstructNode { return ret; } + /** + * Returns the child construct that has the id "Default" or "Resource". + * @throws if there is more than one child + * @returns a construct or undefined if there is no default child + */ + public get defaultChild(): IConstruct | undefined { + const resourceChild = this.tryFindChild('Resource'); + const defaultChild = this.tryFindChild('Default'); + if (resourceChild && defaultChild) { + throw new Error(`Cannot determine default child for ${this.path}. There is both a child with id "Resource" and id "Default"`); + } + + return defaultChild || resourceChild; + } + /** * All direct children of this construct. */ diff --git a/packages/@aws-cdk/cdk/test/test.construct.ts b/packages/@aws-cdk/cdk/test/test.construct.ts index b314b3b42f64e..8ae01847064e3 100644 --- a/packages/@aws-cdk/cdk/test/test.construct.ts +++ b/packages/@aws-cdk/cdk/test/test.construct.ts @@ -479,6 +479,47 @@ export = { test.ok(child2.node.root === root); test.ok(child1_1_1.node.root === root); test.done(); + }, + + 'defaultChild': { + 'returns the child with id "Resource"'(test: Test) { + const root = new Root(); + new Construct(root, 'child1'); + const defaultChild = new Construct(root, 'Resource'); + new Construct(root, 'child2'); + + test.same(root.node.defaultChild, defaultChild); + test.done(); + }, + 'returns the child with id "Default"'(test: Test) { + const root = new Root(); + new Construct(root, 'child1'); + const defaultChild = new Construct(root, 'Default'); + new Construct(root, 'child2'); + + test.same(root.node.defaultChild, defaultChild); + test.done(); + }, + 'returns "undefined" if there is no default'(test: Test) { + const root = new Root(); + new Construct(root, 'child1'); + new Construct(root, 'child2'); + + test.equal(root.node.defaultChild, undefined); + test.done(); + }, + 'fails if there are both "Resource" and "Default"'(test: Test) { + const root = new Root(); + new Construct(root, 'child1'); + new Construct(root, 'Default'); + new Construct(root, 'child2'); + new Construct(root, 'Resource'); + + test.throws(() => root.node.defaultChild, + /Cannot determine default child for . There is both a child with id "Resource" and id "Default"/); + test.done(); + + } } };