Skip to content

Commit

Permalink
refactor(core): refactor API of Tokens (#2757)
Browse files Browse the repository at this point in the history
Tokens are now represented by the interface `IResolvable`. The class `Token`
still exists, but it is used to hold static routines for token encoding
(`Token.asString()`).

Actual token use is split into 2 categories:

- *Intrinsics*, represented by static methods on `Token`: these are to represent values
  that will be understood by the deployment language formalism (e.g.
  CloudFormation), and can be used to escape language type checking.
- *Lazy values*, represented by a `Lazy` class with static factories:
  these will be used to represent type-checked but lazily-produced
  values (evaluated at synthesis time).

In order to be JSII-compatible (which does not currently support
lambdas), `Lazy.stringValue()` et. al. take an interface with a single
method instead of a function.

Also changed in this commit: shoring up property names for encoded
tokens in classes like `CfnParameter` and `CfnElement`.

* `.stringValue` => `.valueAsString`, etc so `.value`, `.valueAsString`,
  `.valueAsList` etc. group together in autocomplete.
* `.ref` now returns a Token, `.refAsString` returns the stringified
  version that token.

To match the other standard the latter should actually be `.refAsString`
but `.ref` is used in so many places that this might be uncomfortable?

Fixes #1933.

BREAKING CHANGES:

* `Token` can no longer be instantiated. You probably want to use 
  `Lazy.stringValue` and others, or `Token.asString()` and others.
* `Token.isToken()`/`Token.unresolved()` => `Token.isUnresolved()`.
* `CfnOutput`: remove `.ref`, since they can't be referenced anyway.
* `CfnParameter`: rename `.stringValue` => `.valueAsString` (and
  similar for lists and numbers).
* `.ref` now returns an `IToken`, use `.refAsString` to get a
  string-encoded Token.
* `TokenMap` is now no longer exported, some parts of its functionality
  are available through the static `Tokenization` class.
* `IResolvedValuePostProcessor` => `IResolvableWithPostProcess`.
  • Loading branch information
rix0rrr authored Jun 11, 2019
1 parent 1378e2d commit a12fcfa
Show file tree
Hide file tree
Showing 233 changed files with 1,779 additions and 995 deletions.
5 changes: 5 additions & 0 deletions packages/@aws-cdk/alexa-ask/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@aws-cdk/assets-docker/lib/image-asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export class DockerImageAsset extends cdk.Construct implements assets.IAsset {

// Parse repository name and tag from the parameter (<REPO_NAME>@sha256:<TAG>)
// Example: cdk/cdkexampleimageb2d7f504@sha256:72c4f956379a43b5623d529ddd969f6826dde944d6221f445ff3e7add9875500
const components = cdk.Fn.split('@sha256:', imageNameParameter.stringValue);
const components = cdk.Fn.split('@sha256:', imageNameParameter.valueAsString);
const repositoryName = cdk.Fn.select(0, components).toString();
const imageSha = cdk.Fn.select(1, components).toString();

Expand Down
8 changes: 4 additions & 4 deletions packages/@aws-cdk/assets/lib/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ export class Asset extends cdk.Construct implements IAsset {
type: 'String',
});

this.s3BucketName = bucketParam.stringValue;
this.s3Prefix = cdk.Fn.select(0, cdk.Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, keyParam.stringValue)).toString();
const s3Filename = cdk.Fn.select(1, cdk.Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, keyParam.stringValue)).toString();
this.s3BucketName = bucketParam.valueAsString;
this.s3Prefix = cdk.Fn.select(0, cdk.Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, keyParam.valueAsString)).toString();
const s3Filename = cdk.Fn.select(1, cdk.Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, keyParam.valueAsString)).toString();
this.s3ObjectKey = `${this.s3Prefix}${s3Filename}`;
this.artifactHash = hashParam.stringValue;
this.artifactHash = hashParam.valueAsString;

this.bucket = s3.Bucket.fromBucketName(this, 'AssetBucket', this.s3BucketName);

Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/assets/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-amazonmq/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/api-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export class ApiKey extends Resource implements IApiKey {
stageKeys: this.renderStageKeys(props.resources)
});

this.keyId = resource.ref;
this.keyId = resource.refAsString;
}

private renderStageKeys(resources: RestApi[] | undefined): CfnApiKey.StageKeyProperty[] | undefined {
Expand Down
4 changes: 2 additions & 2 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, Stack, Token } from '@aws-cdk/cdk';
import { Construct, DeletionPolicy, Lazy, Resource, Stack } from '@aws-cdk/cdk';
import crypto = require('crypto');
import { CfnDeployment, CfnDeploymentProps } from './apigateway.generated';
import { IRestApi } from './restapi';
Expand Down Expand Up @@ -76,7 +76,7 @@ export class Deployment extends Resource {
}

this.api = props.api;
this.deploymentId = new Token(() => this.resource.deploymentId).toString();
this.deploymentId = Lazy.stringValue({ produce: () => this.resource.deploymentId });
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-apigateway/lib/integrations/aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class AwsIntegration extends Integration {
super({
type,
integrationHttpMethod: props.integrationHttpMethod || 'POST',
uri: new cdk.Token(() => {
uri: cdk.Lazy.stringValue({ produce: () => {
if (!this.scope) { throw new Error('AwsIntegration must be used in API'); }
return Stack.of(this.scope).formatArn({
service: 'apigateway',
Expand All @@ -88,7 +88,7 @@ export class AwsIntegration extends Integration {
sep: '/',
resourceName: apiValue,
});
}),
}}),
options: props.options,
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class Method extends Resource {

const resource = new CfnMethod(this, 'Resource', methodProps);

this.methodId = resource.ref;
this.methodId = resource.refAsString;

props.resource.restApi._attachMethod(this);

Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/restapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export class RestApi extends Resource implements IRestApi {
parameters: props.parameters,
});

this.restApiId = resource.ref;
this.restApiId = resource.refAsString;

this.configureDeployment(props);

Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export class Stage extends Resource {
methodSettings,
});

this.stageName = resource.ref;
this.stageName = resource.refAsString;
this.restApi = props.deployment.api;
}

Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Token } from '@aws-cdk/cdk';
import { Lazy, Token } from '@aws-cdk/cdk';
import { Construct, Resource } from '@aws-cdk/cdk';
import { IApiKey } from './api-key';
import { CfnUsagePlan, CfnUsagePlanKey } from './apigateway.generated';
Expand Down Expand Up @@ -156,7 +156,7 @@ export class UsagePlan extends Resource {
let resource: CfnUsagePlan;

resource = new CfnUsagePlan(this, 'Resource', {
apiStages: new Token(() => this.renderApiStages(this.apiStages)),
apiStages: Lazy.anyValue({ produce: () => this.renderApiStages(this.apiStages) }),
description: props.description,
quota: this.renderQuota(props),
throttle: this.renderThrottle(props.throttle),
Expand All @@ -165,7 +165,7 @@ export class UsagePlan extends Resource {

this.apiStages.push(...(props.apiStages || []));

this.usagePlanId = resource.ref;
this.usagePlanId = resource.refAsString;

// Add ApiKey when
if (props.apiKey) {
Expand Down
5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-apigateway/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/test/test.deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export = {

// tokens supported, and are resolved upon synthesis
const value = 'hello hello';
deployment.addToLogicalId({ foo: new cdk.Token(() => value) });
deployment.addToLogicalId({ foo: cdk.Lazy.stringValue({ produce: () => value }) });

const template2 = synthesize();
test.ok(template2.Resources.deployment33381975a12dfe81474913364dc31c06e37f9449);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class StepScalingAction extends cdk.Construct {
cooldown: props.cooldownSec,
minAdjustmentMagnitude: props.minAdjustmentMagnitude,
metricAggregationType: props.metricAggregationType,
stepAdjustments: new cdk.Token(() => this.adjustments),
stepAdjustments: cdk.Lazy.anyValue({ produce: () => this.adjustments }),
} as CfnScalingPolicy.StepScalingPolicyConfigurationProperty
});

Expand Down
5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-appmesh/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-appstream/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-appsync/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-athena/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2');
import iam = require('@aws-cdk/aws-iam');
import sns = require('@aws-cdk/aws-sns');

import { AutoScalingRollingUpdate, Construct, Fn, IResource, Resource, Tag, Token } from '@aws-cdk/cdk';
import { AutoScalingRollingUpdate, Construct, Fn, IResource, Lazy, Resource, Tag } from '@aws-cdk/cdk';
import { CfnAutoScalingGroup, CfnAutoScalingGroupProps, CfnLaunchConfiguration } from './autoscaling.generated';
import { BasicLifecycleHookProps, LifecycleHook } from './lifecycle-hook';
import { BasicScheduledActionProps, ScheduledAction } from './scheduled-action';
Expand Down Expand Up @@ -375,15 +375,15 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements

// use delayed evaluation
const machineImage = props.machineImage.getImage(this);
const userDataToken = new Token(() => Fn.base64((machineImage.os.createUserData(this.userDataLines)))).toString();
const securityGroupsToken = new Token(() => this.securityGroups.map(sg => sg.securityGroupId));
const userDataToken = Lazy.stringValue({ produce: () => Fn.base64((machineImage.os.createUserData(this.userDataLines))) });
const securityGroupsToken = Lazy.listValue({ produce: () => this.securityGroups.map(sg => sg.securityGroupId) });

const launchConfig = new CfnLaunchConfiguration(this, 'LaunchConfig', {
imageId: machineImage.imageId,
keyName: props.keyName,
instanceType: props.instanceType.toString(),
securityGroups: securityGroupsToken.toList(),
iamInstanceProfile: iamProfile.ref,
securityGroups: securityGroupsToken,
iamInstanceProfile: iamProfile.refAsString,
userData: userDataToken,
associatePublicIpAddress: props.associatePublicIpAddress,
spotPrice: props.spotPrice,
Expand All @@ -408,9 +408,9 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements
minSize: minCapacity.toString(),
maxSize: maxCapacity.toString(),
desiredCapacity: desiredCapacity.toString(),
launchConfigurationName: launchConfig.ref,
loadBalancerNames: new Token(() => this.loadBalancerNames.length > 0 ? this.loadBalancerNames : undefined).toList(),
targetGroupArns: new Token(() => this.targetGroupArns.length > 0 ? this.targetGroupArns : undefined).toList(),
launchConfigurationName: launchConfig.refAsString,
loadBalancerNames: Lazy.listValue({ produce: () => this.loadBalancerNames }, { omitEmpty: true }),
targetGroupArns: Lazy.listValue({ produce: () => this.targetGroupArns }, { omitEmpty: true }),
notificationConfigurations: !props.notificationsTopic ? undefined : [
{
topicArn: props.notificationsTopic.topicArn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class StepScalingAction extends cdk.Construct {
adjustmentType: props.adjustmentType,
minAdjustmentMagnitude: props.minAdjustmentMagnitude,
metricAggregationType: props.metricAggregationType,
stepAdjustments: new cdk.Token(() => this.adjustments),
stepAdjustments: cdk.Lazy.anyValue({ produce: () => this.adjustments }),
});

this.scalingPolicyArn = resource.scalingPolicyArn;
Expand Down
5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-autoscaling/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-autoscalingplans/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-batch/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-budgets/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-certificatemanager/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-cloud9/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-cloudformation/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 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, Stack, Token } from '@aws-cdk/cdk';
import { Construct, IResource, Lazy, Resource, Stack } from '@aws-cdk/cdk';
import { IAlarmAction } from './alarm-action';
import { CfnAlarm } from './cloudwatch.generated';
import { HorizontalAnnotation } from './graph';
Expand Down Expand Up @@ -133,9 +133,9 @@ export class Alarm extends Resource implements IAlarm {

// Actions
actionsEnabled: props.actionsEnabled,
alarmActions: new Token(() => this.alarmActionArns).toList(),
insufficientDataActions: new Token(() => this.insufficientDataActionArns).toList(),
okActions: new Token(() => this.okActionArns).toList(),
alarmActions: Lazy.listValue({ produce: () => this.alarmActionArns }),
insufficientDataActions: Lazy.listValue({ produce: (() => this.insufficientDataActionArns) }),
okActions: Lazy.listValue({ produce: () => this.okActionArns }),

// Metric
...metricJson(props.metric)
Expand Down
6 changes: 3 additions & 3 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, Stack, Token } from "@aws-cdk/cdk";
import { Construct, Lazy, Resource, Stack } from "@aws-cdk/cdk";
import { CfnDashboard } from './cloudwatch.generated';
import { Column, Row } from "./layout";
import { IWidget } from "./widget";
Expand Down Expand Up @@ -58,7 +58,7 @@ export class Dashboard extends Resource {

new CfnDashboard(this, 'Resource', {
dashboardName: (props && props.dashboardName) || undefined,
dashboardBody: new Token(() => {
dashboardBody: Lazy.stringValue({ produce: () => {
const column = new Column(...this.rows);
column.position(0, 0);
return Stack.of(this).toJsonString({
Expand All @@ -67,7 +67,7 @@ export class Dashboard extends Resource {
periodOverride: props ? props.periodOverride : undefined,
widgets: column.toJson(),
});
}).toString()
}})
});
}

Expand Down
5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-cloudwatch/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions packages/@aws-cdk/aws-codebuild/lib/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import ecr = require('@aws-cdk/aws-ecr');
import events = require('@aws-cdk/aws-events');
import iam = require('@aws-cdk/aws-iam');
import kms = require('@aws-cdk/aws-kms');
import { Aws, Construct, IResource, PhysicalName, Resource, ResourceIdentifiers, Stack, Token } from '@aws-cdk/cdk';
import { Aws, Construct, IResource, Lazy, PhysicalName, Resource, ResourceIdentifiers, Stack } from '@aws-cdk/cdk';
import { BuildArtifacts, CodePipelineBuildArtifacts, NoBuildArtifacts } from './artifacts';
import { Cache } from './cache';
import { CfnProject } from './codebuild.generated';
Expand Down Expand Up @@ -705,8 +705,8 @@ export class Project extends ProjectBase {
cache: cache._toCloudFormation(),
name: this.physicalName.value,
timeoutInMinutes: props.timeout,
secondarySources: new Token(() => this.renderSecondarySources()),
secondaryArtifacts: new Token(() => this.renderSecondaryArtifacts()),
secondarySources: Lazy.anyValue({ produce: () => this.renderSecondarySources() }),
secondaryArtifacts: Lazy.anyValue({ produce: () => this.renderSecondaryArtifacts() }),
triggers: this.source._buildTriggers(),
vpcConfig: this.configureVpc(props),
});
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1135,7 +1135,7 @@ export = {
environment: {
environmentVariables: {
FOO: { value: '1234' },
BAR: { value: `111${new cdk.Token({ twotwotwo: '222' })}`, type: codebuild.BuildEnvironmentVariableType.ParameterStore }
BAR: { value: `111${cdk.Token.asString({ twotwotwo: '222' })}`, type: codebuild.BuildEnvironmentVariableType.ParameterStore }
}
},
environmentVariables: {
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-codedeploy/lib/lambda/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class LambdaApplication extends Resource implements ILambdaApplication {
computePlatform: 'Lambda'
});

this.applicationName = resource.ref;
this.applicationName = resource.refAsString;
this.applicationArn = arnForApplication(this.applicationName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy
deploymentType: 'BLUE_GREEN',
deploymentOption: 'WITH_TRAFFIC_CONTROL'
},
alarmConfiguration: new cdk.Token(() => renderAlarmConfiguration(this.alarms, props.ignorePollAlarmsFailure)),
autoRollbackConfiguration: new cdk.Token(() => renderAutoRollbackConfiguration(this.alarms, props.autoRollback)),
alarmConfiguration: cdk.Lazy.anyValue({ produce: () => renderAlarmConfiguration(this.alarms, props.ignorePollAlarmsFailure) }),
autoRollbackConfiguration: cdk.Lazy.anyValue({ produce: () => renderAutoRollbackConfiguration(this.alarms, props.autoRollback) }),
});

this.deploymentGroupName = resource.deploymentGroupName;
Expand All @@ -180,8 +180,8 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy
codeDeployLambdaAliasUpdate: {
applicationName: this.application.applicationName,
deploymentGroupName: resource.deploymentGroupName,
beforeAllowTrafficHook: new cdk.Token(() => this.preHook === undefined ? undefined : this.preHook.functionName).toString(),
afterAllowTrafficHook: new cdk.Token(() => this.postHook === undefined ? undefined : this.postHook.functionName).toString()
beforeAllowTrafficHook: cdk.Lazy.stringValue({ produce: () => this.preHook && this.preHook.functionName }),
afterAllowTrafficHook: cdk.Lazy.stringValue({ produce: () => this.postHook && this.postHook.functionName }),
}
};
}
Expand Down
Loading

0 comments on commit a12fcfa

Please sign in to comment.