Skip to content

Commit

Permalink
refactor(core): improvements to Construct API (#2767)
Browse files Browse the repository at this point in the history
Closes #1934

BREAKING CHANGE:
* **core:** `node.stack` is now `Stack.of(construct)` (fixes #2766)
* **core:** `node.resolve` has been moved to `stack.resolve`.
* **core:** `node.stringifyJson` has been moved to `stack.stringifyJson`.
* **core:** `node.validateTree` is now `ConstructNode.validate(node)`
* **core:** `node.prepareTree` is now `ConstructNode.prepare(node)`
* **core:** `node.getContext` is now `node.tryGetContext`
* **core:** `node.recordReference` is now `node.addReference`
* **core:** `node.apply` is now `node.applyAspect`
* **core:** `node.ancestors()` is now `node.scopes`
* **core:** `node.required` has been removed.
* **core:** `node.typename` has been removed.
* **core:** `node.addChild` is now private
* **core:** `node.findReferences()` is now `node.references`
* **core:** `node.findDependencies()` is now `node.dependencies`
* **core:** `stack.dependencies()` is now `stack.dependencies`
* **core:** `CfnElement.stackPath` has been removed.
* **core:** `CloudFormationLang` is now internal (use `stack.toJsonString()`)
  • Loading branch information
Elad Ben-Israel committed Jun 6, 2019
1 parent 9a34d47 commit 3f7a0ad
Show file tree
Hide file tree
Showing 148 changed files with 939 additions and 988 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class PipelineDeployStackAction extends cdk.Construct {
constructor(scope: cdk.Construct, id: string, props: PipelineDeployStackActionProps) {
super(scope, id);

if (!cdk.environmentEquals(props.stack.env, this.node.stack.env)) {
if (!cdk.environmentEquals(props.stack.env, cdk.Stack.of(this).env)) {
// FIXME: Add the necessary to extend to stacks in a different account
throw new Error(`Cross-environment deployment is not supported`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import cpactions = require('@aws-cdk/aws-codepipeline-actions');
import iam = require('@aws-cdk/aws-iam');
import s3 = require('@aws-cdk/aws-s3');
import cdk = require('@aws-cdk/cdk');
import { ConstructNode } from '@aws-cdk/cdk';
import cxapi = require('@aws-cdk/cx-api');
import fc = require('fast-check');
import nodeunit = require('nodeunit');
Expand Down Expand Up @@ -289,7 +290,7 @@ export = nodeunit.testCase({
for (let i = 0 ; i < assetCount ; i++) {
deployedStack.node.addMetadata(cxapi.ASSET_METADATA, {});
}
test.deepEqual(action.node.validateTree().map(x => x.message),
test.deepEqual(ConstructNode.validate(action.node).map(x => x.message),
[`Cannot deploy the stack DeployedStack because it references ${assetCount} asset(s)`]);
}
)
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/assets/lib/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export class Asset extends cdk.Construct implements IAsset {
* (e.g. "Code" for AWS::Lambda::Function)
*/
public addResourceMetadata(resource: cdk.CfnResource, resourceProperty: string) {
if (!this.node.getContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT)) {
if (!this.node.tryGetContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT)) {
return; // not enabled
}

Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/assets/lib/staging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class Staging extends Construct {
this.copyOptions = props;
this.sourceHash = fingerprint(this.sourcePath, props);

const stagingDisabled = this.node.getContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
if (stagingDisabled) {
this.stagedPath = this.sourcePath;
} else {
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/assets/test/test.asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export = {
// verify that now the template contains parameters for this asset
const session = app.synth();

test.deepEqual(stack.node.resolve(entry!.data), {
test.deepEqual(stack.resolve(entry!.data), {
path: SAMPLE_ASSET_DIR,
id: 'MyStackMyAssetBDDF29E3',
packaging: 'zip',
Expand Down Expand Up @@ -84,7 +84,7 @@ export = {
// synthesize first so "prepare" is called
const template = SynthUtils.synthesize(stack).template;

test.deepEqual(stack.node.resolve(entry!.data), {
test.deepEqual(stack.resolve(entry!.data), {
path: 'asset.78add9eaf468dfa2191da44a7da92a21baba4c686cf6053d772556768ef21197.txt',
packaging: 'file',
id: 'MyAsset',
Expand Down
8 changes: 5 additions & 3 deletions packages/@aws-cdk/aws-apigateway/lib/deployment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Construct, DeletionPolicy, Resource, Token } from '@aws-cdk/cdk';
import { Construct, DeletionPolicy, Resource, Stack, Token } from '@aws-cdk/cdk';
import crypto = require('crypto');
import { CfnDeployment, CfnDeploymentProps } from './apigateway.generated';
import { IRestApi } from './restapi';
Expand Down Expand Up @@ -99,7 +99,7 @@ class LatestDeploymentResource extends CfnDeployment {
constructor(scope: Construct, id: string, props: CfnDeploymentProps) {
super(scope, id, props);

this.originalLogicalId = this.node.stack.logicalIds.getLogicalId(this);
this.originalLogicalId = Stack.of(this).logicalIds.getLogicalId(this);
}

/**
Expand All @@ -121,12 +121,14 @@ class LatestDeploymentResource extends CfnDeployment {
* add via `addToLogicalId`.
*/
protected prepare() {
const stack = Stack.of(this);

// if hash components were added to the deployment, we use them to calculate
// a logical ID for the deployment resource.
if (this.hashComponents.length > 0) {
const md5 = crypto.createHash('md5');
this.hashComponents
.map(c => this.node.resolve(c))
.map(c => stack.resolve(c))
.forEach(c => md5.update(JSON.stringify(c)));

this.overrideLogicalId(this.originalLogicalId + md5.digest("hex"));
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-apigateway/lib/integrations/aws.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import cdk = require('@aws-cdk/cdk');
import { Stack } from '@aws-cdk/cdk';
import { Integration, IntegrationOptions, IntegrationType } from '../integration';
import { Method } from '../method';
import { parseAwsApiCall } from '../util';
Expand Down Expand Up @@ -80,7 +81,7 @@ export class AwsIntegration extends Integration {
integrationHttpMethod: props.integrationHttpMethod || 'POST',
uri: new cdk.Token(() => {
if (!this.scope) { throw new Error('AwsIntegration must be used in API'); }
return this.scope.node.stack.formatArn({
return Stack.of(this.scope).formatArn({
service: 'apigateway',
account: backend,
resource: apiType,
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-apigateway/lib/method.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Construct, Resource } from '@aws-cdk/cdk';
import { Construct, Resource, Stack } from '@aws-cdk/cdk';
import { CfnMethod, CfnMethodProps } from './apigateway.generated';
import { ConnectionType, Integration } from './integration';
import { MockIntegration } from './integrations/mock';
Expand Down Expand Up @@ -197,7 +197,7 @@ export class Method extends Resource {
} else if (options.credentialsPassthrough) {
// arn:aws:iam::*:user/*
// tslint:disable-next-line:max-line-length
credentials = this.node.stack.formatArn({ service: 'iam', region: '', account: '*', resource: 'user', sep: '/', resourceName: '*' });
credentials = Stack.of(this).formatArn({ service: 'iam', region: '', account: '*', resource: 'user', sep: '/', resourceName: '*' });
}

return {
Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/aws-apigateway/lib/restapi.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import iam = require('@aws-cdk/aws-iam');
import { CfnOutput, Construct, IResource as IResourceBase, Resource } from '@aws-cdk/cdk';
import { CfnOutput, Construct, IResource as IResourceBase, Resource, Stack } from '@aws-cdk/cdk';
import { ApiKey, IApiKey } from './api-key';
import { CfnAccount, CfnRestApi } from './apigateway.generated';
import { Deployment } from './deployment';
Expand Down Expand Up @@ -284,7 +284,7 @@ export class RestApi extends Resource implements IRestApi {
method = '*';
}

return this.node.stack.formatArn({
return Stack.of(this).formatArn({
service: 'execute-api',
resource: this.restApiId,
sep: '/',
Expand Down Expand Up @@ -343,7 +343,7 @@ export class RestApi extends Resource implements IRestApi {
private configureCloudWatchRole(apiResource: CfnRestApi) {
const role = new iam.Role(this, 'CloudWatchRole', {
assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'),
managedPolicyArns: [ this.node.stack.formatArn({
managedPolicyArns: [ Stack.of(this).formatArn({
service: 'iam',
region: '',
account: 'aws',
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-apigateway/lib/stage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Construct, Resource } from '@aws-cdk/cdk';
import { Construct, Resource, Stack } from '@aws-cdk/cdk';
import { CfnStage } from './apigateway.generated';
import { Deployment } from './deployment';
import { IRestApi } from './restapi';
Expand Down Expand Up @@ -209,7 +209,7 @@ export class Stage extends Resource {
if (!path.startsWith('/')) {
throw new Error(`Path must begin with "/": ${path}`);
}
return `https://${this.restApi.restApiId}.execute-api.${this.node.stack.region}.${this.node.stack.urlSuffix}/${this.stageName}${path}`;
return `https://${this.restApi.restApiId}.execute-api.${Stack.of(this).region}.${Stack.of(this).urlSuffix}/${this.stageName}${path}`;
}

private renderMethodSettings(props: StageProps): CfnStage.MethodSettingProperty[] | undefined {
Expand Down
1 change: 0 additions & 1 deletion packages/@aws-cdk/aws-apigateway/test/test.deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ export = {
test.done();

function synthesize() {
stack.node.prepareTree();
return SynthUtils.synthesize(stack).template;
}
},
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-apigateway/test/test.method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export = {
});

// THEN
test.deepEqual(method.node.resolve(method.methodArn), {
test.deepEqual(stack.resolve(method.methodArn), {
"Fn::Join": [
"",
[
Expand Down Expand Up @@ -182,7 +182,7 @@ export = {
});

// THEN
test.deepEqual(method.node.resolve(method.testMethodArn), {
test.deepEqual(stack.resolve(method.testMethodArn), {
"Fn::Join": [
"",
[
Expand Down
10 changes: 5 additions & 5 deletions packages/@aws-cdk/aws-apigateway/test/test.restapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ export = {
const imported = apigateway.RestApi.fromRestApiId(stack, 'imported-api', 'api-rxt4498f');

// THEN
test.deepEqual(imported.node.resolve(imported.restApiId), 'api-rxt4498f');
test.deepEqual(stack.resolve(imported.restApiId), 'api-rxt4498f');
test.done();
},

Expand All @@ -347,7 +347,7 @@ export = {
api.root.addMethod('GET');

// THEN
test.deepEqual(api.node.resolve(api.url), { 'Fn::Join':
test.deepEqual(stack.resolve(api.url), { 'Fn::Join':
[ '',
[ 'https://',
{ Ref: 'apiC8550315' },
Expand All @@ -358,7 +358,7 @@ export = {
"/",
{ Ref: 'apiDeploymentStageprod896C8101' },
'/' ] ] });
test.deepEqual(api.node.resolve(api.urlForPath('/foo/bar')), { 'Fn::Join':
test.deepEqual(stack.resolve(api.urlForPath('/foo/bar')), { 'Fn::Join':
[ '',
[ 'https://',
{ Ref: 'apiC8550315' },
Expand Down Expand Up @@ -405,7 +405,7 @@ export = {
const arn = api.executeApiArn('method', '/path', 'stage');

// THEN
test.deepEqual(api.node.resolve(arn), { 'Fn::Join':
test.deepEqual(stack.resolve(arn), { 'Fn::Join':
[ '',
[ 'arn:',
{ Ref: 'AWS::Partition' },
Expand Down Expand Up @@ -438,7 +438,7 @@ export = {
const method = api.root.addMethod('ANY');

// THEN
test.deepEqual(api.node.resolve(method.methodArn), { 'Fn::Join':
test.deepEqual(stack.resolve(method.methodArn), { 'Fn::Join':
[ '',
[ 'arn:',
{ Ref: 'AWS::Partition' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements
});
this.connections = new ec2.Connections({ securityGroups: [this.securityGroup] });
this.securityGroups.push(this.securityGroup);
this.node.apply(new Tag(NAME_TAG, this.node.path));
this.node.applyAspect(new Tag(NAME_TAG, this.node.path));

this.role = props.role || new iam.Role(this, 'InstanceRole', {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,8 @@ export = {
pauseTimeSec: 345
},
});
asg.node.apply(new cdk.Tag('superfood', 'acai'));
asg.node.apply(new cdk.Tag('notsuper', 'caramel', { applyToLaunchedInstances: false }));
asg.node.applyAspect(new cdk.Tag('superfood', 'acai'));
asg.node.applyAspect(new cdk.Tag('notsuper', 'caramel', { applyToLaunchedInstances: false }));

// THEN
expect(stack).to(haveResource("AWS::AutoScaling::AutoScalingGroup", {
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-cloudtrail/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import iam = require('@aws-cdk/aws-iam');
import kms = require('@aws-cdk/aws-kms');
import logs = require('@aws-cdk/aws-logs');
import s3 = require('@aws-cdk/aws-s3');
import { Construct, Resource } from '@aws-cdk/cdk';
import { Construct, Resource, Stack } from '@aws-cdk/cdk';
import { CfnTrail } from './cloudtrail.generated';

// AWS::CloudTrail CloudFormation Resources:
Expand Down Expand Up @@ -136,7 +136,7 @@ export class Trail extends Resource {
.addServicePrincipal(cloudTrailPrincipal));

s3bucket.addToResourcePolicy(new iam.PolicyStatement()
.addResource(s3bucket.arnForObjects(`AWSLogs/${this.node.stack.accountId}/*`))
.addResource(s3bucket.arnForObjects(`AWSLogs/${Stack.of(this).accountId}/*`))
.addActions("s3:PutObject")
.addServicePrincipal(cloudTrailPrincipal)
.setCondition("StringEquals", {'s3:x-amz-acl': "bucket-owner-full-control"}));
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk';
import { Construct, IResource, Resource, Stack, Token } from '@aws-cdk/cdk';
import { IAlarmAction } from './alarm-action';
import { CfnAlarm } from './cloudwatch.generated';
import { HorizontalAnnotation } from './graph';
Expand Down Expand Up @@ -80,7 +80,7 @@ export class Alarm extends Resource implements IAlarm {
public static fromAlarmArn(scope: Construct, id: string, alarmArn: string): IAlarm {
class Import extends Resource implements IAlarm {
public readonly alarmArn = alarmArn;
public readonly alarmName = scope.node.stack.parseArn(alarmArn, ':').resourceName!;
public readonly alarmName = Stack.of(scope).parseArn(alarmArn, ':').resourceName!;
}
return new Import(scope, id);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-cloudwatch/lib/dashboard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Construct, Resource, Token } from "@aws-cdk/cdk";
import { Construct, Resource, Stack, Token } from "@aws-cdk/cdk";
import { CfnDashboard } from './cloudwatch.generated';
import { Column, Row } from "./layout";
import { IWidget } from "./widget";
Expand Down Expand Up @@ -61,7 +61,7 @@ export class Dashboard extends Resource {
dashboardBody: new Token(() => {
const column = new Column(...this.rows);
column.position(0, 0);
return this.node.stringifyJson({
return Stack.of(this).toJsonString({
start: props ? props.start : undefined,
end: props ? props.end : undefined,
periodOverride: props ? props.periodOverride : undefined,
Expand Down
14 changes: 7 additions & 7 deletions packages/@aws-cdk/aws-cloudwatch/test/test.graphs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export = {
});

// THEN
test.deepEqual(stack.node.resolve(widget.toJson()), [{
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'metric',
width: 6,
height: 6,
Expand Down Expand Up @@ -45,7 +45,7 @@ export = {
});

// THEN
test.deepEqual(stack.node.resolve(widget.toJson()), [{
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'metric',
width: 6,
height: 6,
Expand Down Expand Up @@ -74,7 +74,7 @@ export = {
});

// THEN
test.deepEqual(stack.node.resolve(widget.toJson()), [{
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'metric',
width: 6,
height: 3,
Expand Down Expand Up @@ -105,7 +105,7 @@ export = {
});

// THEN
test.deepEqual(stack.node.resolve(widget.toJson()), [{
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'metric',
width: 6,
height: 6,
Expand Down Expand Up @@ -139,7 +139,7 @@ export = {
});

// THEN
test.deepEqual(stack.node.resolve(widget.toJson()), [{
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'metric',
width: 6,
height: 6,
Expand Down Expand Up @@ -182,7 +182,7 @@ export = {
});

// THEN
test.deepEqual(stack.node.resolve(widget.toJson()), [{
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'metric',
width: 6,
height: 6,
Expand Down Expand Up @@ -229,7 +229,7 @@ export = {
});

// THEN
test.deepEqual(stack.node.resolve(widget.toJson()), [{
test.deepEqual(stack.resolve(widget.toJson()), [{
type: 'metric',
width: 6,
height: 6,
Expand Down
Loading

0 comments on commit 3f7a0ad

Please sign in to comment.