diff --git a/packages/@aws-cdk/alexa-ask/package-lock.json b/packages/@aws-cdk/alexa-ask/package-lock.json new file mode 100644 index 0000000000000..43dc492db8f02 --- /dev/null +++ b/packages/@aws-cdk/alexa-ask/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/alexa-ask", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/assets-docker/lib/image-asset.ts b/packages/@aws-cdk/assets-docker/lib/image-asset.ts index 3eccf231d8199..770ee2238657d 100644 --- a/packages/@aws-cdk/assets-docker/lib/image-asset.ts +++ b/packages/@aws-cdk/assets-docker/lib/image-asset.ts @@ -95,7 +95,7 @@ export class DockerImageAsset extends cdk.Construct implements assets.IAsset { // Parse repository name and tag from the parameter (@sha256:) // 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(); diff --git a/packages/@aws-cdk/assets/lib/asset.ts b/packages/@aws-cdk/assets/lib/asset.ts index 24d2d012012c1..8824fb0dfdf96 100644 --- a/packages/@aws-cdk/assets/lib/asset.ts +++ b/packages/@aws-cdk/assets/lib/asset.ts @@ -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); diff --git a/packages/@aws-cdk/assets/package-lock.json b/packages/@aws-cdk/assets/package-lock.json index 7857428255a28..52815efde4278 100644 --- a/packages/@aws-cdk/assets/package-lock.json +++ b/packages/@aws-cdk/assets/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/assets", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/aws-amazonmq/package-lock.json b/packages/@aws-cdk/aws-amazonmq/package-lock.json new file mode 100644 index 0000000000000..4941a70ef3e19 --- /dev/null +++ b/packages/@aws-cdk/aws-amazonmq/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-amazonmq", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-apigateway/lib/api-key.ts b/packages/@aws-cdk/aws-apigateway/lib/api-key.ts index 1baf475f57f1b..ad3523064e5de 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/api-key.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/api-key.ts @@ -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 { diff --git a/packages/@aws-cdk/aws-apigateway/lib/deployment.ts b/packages/@aws-cdk/aws-apigateway/lib/deployment.ts index 3c2a0861fea16..1102b6e4bb774 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/deployment.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/deployment.ts @@ -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'; @@ -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 }); } /** diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/aws.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/aws.ts index 2d42cf08f6b50..5ee538ee60dd0 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/aws.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/aws.ts @@ -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', @@ -88,7 +88,7 @@ export class AwsIntegration extends Integration { sep: '/', resourceName: apiValue, }); - }), + }}), options: props.options, }); } diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index 8da76ef3bf597..d357423f00ccc 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -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); diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index 665d169f1e8ff..502cbeef35c3b 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -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); diff --git a/packages/@aws-cdk/aws-apigateway/lib/stage.ts b/packages/@aws-cdk/aws-apigateway/lib/stage.ts index f4c9ba393d683..d89961bbdf2d7 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/stage.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/stage.ts @@ -197,7 +197,7 @@ export class Stage extends Resource { methodSettings, }); - this.stageName = resource.ref; + this.stageName = resource.refAsString; this.restApi = props.deployment.api; } diff --git a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts index 0f22312c28860..29051a3a8711b 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts @@ -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'; @@ -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), @@ -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) { diff --git a/packages/@aws-cdk/aws-apigateway/package-lock.json b/packages/@aws-cdk/aws-apigateway/package-lock.json new file mode 100644 index 0000000000000..065923a2596cb --- /dev/null +++ b/packages/@aws-cdk/aws-apigateway/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-apigateway", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts b/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts index 886da94fd1ff6..d3647822b2bf5 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.deployment.ts @@ -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); diff --git a/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts b/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts index 48e42b6681d2c..b9c042022c9be 100644 --- a/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts +++ b/packages/@aws-cdk/aws-applicationautoscaling/lib/step-scaling-action.ts @@ -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 }); diff --git a/packages/@aws-cdk/aws-appmesh/package-lock.json b/packages/@aws-cdk/aws-appmesh/package-lock.json new file mode 100644 index 0000000000000..2ba8b7729284b --- /dev/null +++ b/packages/@aws-cdk/aws-appmesh/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-appmesh", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-appstream/package-lock.json b/packages/@aws-cdk/aws-appstream/package-lock.json new file mode 100644 index 0000000000000..e2858bb829b14 --- /dev/null +++ b/packages/@aws-cdk/aws-appstream/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-appstream", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-appsync/package-lock.json b/packages/@aws-cdk/aws-appsync/package-lock.json new file mode 100644 index 0000000000000..1a58d9434c324 --- /dev/null +++ b/packages/@aws-cdk/aws-appsync/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-appsync", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-athena/package-lock.json b/packages/@aws-cdk/aws-athena/package-lock.json new file mode 100644 index 0000000000000..33fc6d7013d7e --- /dev/null +++ b/packages/@aws-cdk/aws-athena/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-athena", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts index 671ed8d8a6208..ba8f4363fb12a 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -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'; @@ -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, @@ -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, diff --git a/packages/@aws-cdk/aws-autoscaling/lib/step-scaling-action.ts b/packages/@aws-cdk/aws-autoscaling/lib/step-scaling-action.ts index 084dbef4b81d2..a0eeed3f0fca4 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/step-scaling-action.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/step-scaling-action.ts @@ -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; diff --git a/packages/@aws-cdk/aws-autoscaling/package-lock.json b/packages/@aws-cdk/aws-autoscaling/package-lock.json new file mode 100644 index 0000000000000..1e7496f714c38 --- /dev/null +++ b/packages/@aws-cdk/aws-autoscaling/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-autoscaling", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-autoscalingplans/package-lock.json b/packages/@aws-cdk/aws-autoscalingplans/package-lock.json new file mode 100644 index 0000000000000..661c14b3791e3 --- /dev/null +++ b/packages/@aws-cdk/aws-autoscalingplans/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-autoscalingplans", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-batch/package-lock.json b/packages/@aws-cdk/aws-batch/package-lock.json new file mode 100644 index 0000000000000..f4404dec75430 --- /dev/null +++ b/packages/@aws-cdk/aws-batch/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-batch", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-budgets/package-lock.json b/packages/@aws-cdk/aws-budgets/package-lock.json new file mode 100644 index 0000000000000..b74bf313aa017 --- /dev/null +++ b/packages/@aws-cdk/aws-budgets/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-budgets", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package-lock.json b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package-lock.json index 85280e50e25d8..a8a81e6e93e6b 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package-lock.json +++ b/packages/@aws-cdk/aws-certificatemanager/lambda-packages/dns_validated_certificate_handler/package-lock.json @@ -1,6 +1,6 @@ { "name": "dns_validated_certificate_handler", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/aws-certificatemanager/package-lock.json b/packages/@aws-cdk/aws-certificatemanager/package-lock.json new file mode 100644 index 0000000000000..9941f958ff887 --- /dev/null +++ b/packages/@aws-cdk/aws-certificatemanager/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-certificatemanager", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-cloud9/package-lock.json b/packages/@aws-cdk/aws-cloud9/package-lock.json new file mode 100644 index 0000000000000..e369c3ac1c3f6 --- /dev/null +++ b/packages/@aws-cdk/aws-cloud9/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-cloud9", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-cloudformation/package-lock.json b/packages/@aws-cdk/aws-cloudformation/package-lock.json index a3ed3ecb2fc67..acfc8d4c428a9 100644 --- a/packages/@aws-cdk/aws-cloudformation/package-lock.json +++ b/packages/@aws-cdk/aws-cloudformation/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/aws-cloudformation", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts b/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts index 7d762ca10c3dc..52097fc45b6e6 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/alarm.ts @@ -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'; @@ -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) diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/dashboard.ts b/packages/@aws-cdk/aws-cloudwatch/lib/dashboard.ts index 3091806aea51c..4d7aae6e3f4b7 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/dashboard.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/dashboard.ts @@ -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"; @@ -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({ @@ -67,7 +67,7 @@ export class Dashboard extends Resource { periodOverride: props ? props.periodOverride : undefined, widgets: column.toJson(), }); - }).toString() + }}) }); } diff --git a/packages/@aws-cdk/aws-cloudwatch/package-lock.json b/packages/@aws-cdk/aws-cloudwatch/package-lock.json new file mode 100644 index 0000000000000..e9d9d048c6dc5 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-cloudwatch", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index ff011bdc8d973..381b2c7c2ffff 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -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'; @@ -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), }); diff --git a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts index 8683696cf804b..9badd9435488e 100644 --- a/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts +++ b/packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts @@ -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: { diff --git a/packages/@aws-cdk/aws-codedeploy/lib/lambda/application.ts b/packages/@aws-cdk/aws-codedeploy/lib/lambda/application.ts index 515c7fbaf7a4f..a0a795858f209 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/lambda/application.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/lambda/application.ts @@ -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); } } diff --git a/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts index 047b29aab2e5b..ea0d6cc945294 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts @@ -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; @@ -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 }), } }; } diff --git a/packages/@aws-cdk/aws-codedeploy/lib/server/application.ts b/packages/@aws-cdk/aws-codedeploy/lib/server/application.ts index 2231c4049a970..14c4beb231898 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/server/application.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/server/application.ts @@ -68,7 +68,7 @@ export class ServerApplication extends Resource implements IServerApplication { computePlatform: 'Server', }); - this.applicationName = resource.ref; + this.applicationName = resource.refAsString; this.applicationArn = arnForApplication(this.applicationName); } } diff --git a/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-config.ts b/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-config.ts index 3c67e65114e84..96fd860d7a644 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-config.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-config.ts @@ -113,7 +113,7 @@ export class ServerDeploymentConfig extends cdk.Resource implements IServerDeplo minimumHealthyHosts: props.minimumHealthyHosts._json, }); - this.deploymentConfigName = resource.ref.toString(); + this.deploymentConfigName = resource.refAsString; this.deploymentConfigArn = arnForDeploymentConfig(this.deploymentConfigName); } } @@ -125,4 +125,4 @@ function deploymentConfig(name: string): IServerDeploymentConfig { }; } -function ignore(_x: any) { return; } \ No newline at end of file +function ignore(_x: any) { return; } diff --git a/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts index 93c61be2cf0ab..b5f5f5c7eb02c 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/server/deployment-group.ts @@ -290,10 +290,7 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase { serviceRoleArn: this.role.roleArn, deploymentConfigName: props.deploymentConfig && props.deploymentConfig.deploymentConfigName, - autoScalingGroups: new cdk.Token(() => - this._autoScalingGroups.length === 0 - ? undefined - : this._autoScalingGroups.map(asg => asg.autoScalingGroupName)).toList(), + autoScalingGroups: cdk.Lazy.listValue({ produce: () => this._autoScalingGroups.map(asg => asg.autoScalingGroupName) }, { omitEmpty: true }), loadBalancerInfo: this.loadBalancerInfo(props.loadBalancer), deploymentStyle: props.loadBalancer === undefined ? undefined @@ -302,8 +299,8 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase { }, ec2TagSet: this.ec2TagSet(props.ec2InstanceTags), onPremisesTagSet: this.onPremiseTagSet(props.onPremiseInstanceTags), - 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; diff --git a/packages/@aws-cdk/aws-codedeploy/package-lock.json b/packages/@aws-cdk/aws-codedeploy/package-lock.json new file mode 100644 index 0000000000000..638a56ec96458 --- /dev/null +++ b/packages/@aws-cdk/aws-codedeploy/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-codedeploy", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts index 58a3f0f4c4443..96db314388eae 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/cloudformation/pipeline-actions.ts @@ -227,8 +227,8 @@ export abstract class CloudFormationDeployAction extends CloudFormationAction { ...configuration, // None evaluates to empty string which is falsey and results in undefined Capabilities: (capabilities && capabilities.toString()) || undefined, - RoleArn: new cdk.Token(() => this.deploymentRole.roleArn), - ParameterOverrides: new cdk.Token(() => Stack.of(this.scope).toJsonString(props.parameterOverrides)), + RoleArn: cdk.Lazy.stringValue({ produce: () => this.deploymentRole.roleArn }), + ParameterOverrides: cdk.Lazy.stringValue({ produce: () => Stack.of(this.scope).toJsonString(props.parameterOverrides) }), TemplateConfiguration: props.templateConfiguration ? props.templateConfiguration.location : undefined, StackName: props.stackName, }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts index f3702d270b4f0..1c0c31b84379d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts @@ -84,7 +84,7 @@ export class CodeBuildAction extends codepipeline.Action { this.props = props; if (this.inputs.length > 1) { - this.configuration.PrimarySource = new cdk.Token(() => this.inputs[0].artifactName); + this.configuration.PrimarySource = cdk.Lazy.stringValue({ produce: () => this.inputs[0].artifactName }); } } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/manual-approval-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/manual-approval-action.ts index 6acb9487f6610..46767f3f75a8b 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/manual-approval-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/manual-approval-action.ts @@ -42,7 +42,7 @@ export class ManualApprovalAction extends codepipeline.Action { category: codepipeline.ActionCategory.Approval, provider: 'Manual', artifactBounds: { minInputs: 0, maxInputs: 0, minOutputs: 0, maxOutputs: 0 }, - configuration: new cdk.Token(() => this.actionConfiguration()), + configuration: cdk.Lazy.anyValue({ produce: () => this.actionConfiguration() }), }); this.props = props; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package-lock.json b/packages/@aws-cdk/aws-codepipeline-actions/package-lock.json index f51b8e2394277..07af5026023d6 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package-lock.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/aws-codepipeline-actions", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json index 387568106ab8d..ffc75c74f5afe 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json @@ -476,10 +476,10 @@ "Id": "MyTopic", "InputTransformer": { "InputPathsMap": { - "f1": "$.detail.pipeline", - "f2": "$.detail.state" + "detail-pipeline": "$.detail.pipeline", + "detail-state": "$.detail.state" }, - "InputTemplate": "\"Pipeline changed state to \"" + "InputTemplate": "\"Pipeline changed state to \"" } } ] diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/test.lambda-invoke-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/test.lambda-invoke-action.ts index 3e8e40894cde4..bf070ad979170 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/test.lambda-invoke-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/lambda/test.lambda-invoke-action.ts @@ -1,7 +1,7 @@ import { expect, haveResourceLike } from "@aws-cdk/assert"; import codepipeline = require('@aws-cdk/aws-codepipeline'); import lambda = require('@aws-cdk/aws-lambda'); -import { Aws, SecretValue, Stack, Token } from "@aws-cdk/cdk"; +import { Aws, Lazy, SecretValue, Stack, Token } from "@aws-cdk/cdk"; import { Test } from 'nodeunit'; import cpactions = require('../../lib'); @@ -34,7 +34,7 @@ export = { 'properly resolves any Tokens passed in userParameters'(test: Test) { const stack = stackIncludingLambdaInvokeCodePipeline({ - key: new Token(() => Aws.region), + key: Lazy.stringValue({ produce: () => Aws.region }), }); expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { @@ -68,7 +68,7 @@ export = { 'properly resolves any stringified Tokens passed in userParameters'(test: Test) { const stack = stackIncludingLambdaInvokeCodePipeline({ - key: new Token(() => null).toString(), + key: Token.asString(null), }); expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts index 5c37285b3a008..e75cb83e80a50 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts @@ -83,7 +83,7 @@ export = { runOrder: 8, output: new codepipeline.Artifact('A'), branch: 'branch', - oauthToken: SecretValue.plainText(secret.stringValue), + oauthToken: SecretValue.plainText(secret.valueAsString), owner: 'foo', repo: 'bar', trigger: cpactions.GitHubTrigger.Poll @@ -142,7 +142,7 @@ export = { runOrder: 8, output: new codepipeline.Artifact('A'), branch: 'branch', - oauthToken: SecretValue.plainText(secret.stringValue), + oauthToken: SecretValue.plainText(secret.valueAsString), owner: 'foo', repo: 'bar', trigger: cpactions.GitHubTrigger.None @@ -201,7 +201,7 @@ export = { runOrder: 8, output: new codepipeline.Artifact('A'), branch: 'branch', - oauthToken: SecretValue.plainText(secret.stringValue), + oauthToken: SecretValue.plainText(secret.valueAsString), owner: 'foo', repo: 'bar' }), diff --git a/packages/@aws-cdk/aws-codepipeline/lib/artifact.ts b/packages/@aws-cdk/aws-codepipeline/lib/artifact.ts index e9c8ca0b5dd8d..c0cd163e9f4b6 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/artifact.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/artifact.ts @@ -1,5 +1,5 @@ import s3 = require("@aws-cdk/aws-s3"); -import { Token } from "@aws-cdk/cdk"; +import { Lazy, Token } from "@aws-cdk/cdk"; import validation = require('./validation'); /** @@ -112,15 +112,17 @@ export class ArtifactPath { public get location() { const artifactName = this.artifact.artifactName ? this.artifact.artifactName - : new Token(() => this.artifact.artifactName).toString(); + : Lazy.stringValue({ produce: () => this.artifact.artifactName }); return `${artifactName}::${this.fileName}`; } } function artifactAttribute(artifact: Artifact, attributeName: string) { - return new Token(() => ({ 'Fn::GetArtifactAtt': [artifact.artifactName, attributeName] })).toString(); + const lazyArtifactName = Lazy.stringValue({ produce: () => artifact.artifactName }); + return Token.asString({ 'Fn::GetArtifactAtt': [lazyArtifactName, attributeName] }); } function artifactGetParam(artifact: Artifact, jsonFile: string, keyName: string) { - return new Token(() => ({ 'Fn::GetParam': [artifact.artifactName, jsonFile, keyName] })).toString(); + const lazyArtifactName = Lazy.stringValue({ produce: () => artifact.artifactName }); + return Token.asString({ 'Fn::GetParam': [lazyArtifactName, jsonFile, keyName] }); } diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 32a39218757e3..966d70cae181f 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -2,7 +2,7 @@ import events = require('@aws-cdk/aws-events'); import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); import s3 = require('@aws-cdk/aws-s3'); -import { Construct, PhysicalName, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/cdk'; +import { Construct, Lazy, PhysicalName, RemovalPolicy, Resource, Stack } from '@aws-cdk/cdk'; import { Action, IPipeline, IStage } from "./action"; import { CfnPipeline } from './codepipeline.generated'; import { Stage } from './stage'; @@ -242,9 +242,9 @@ export class Pipeline extends PipelineBase { }); const codePipeline = new CfnPipeline(this, 'Resource', { - artifactStore: new Token(() => this.renderArtifactStore()), - artifactStores: new Token(() => this.renderArtifactStores()), - stages: new Token(() => this.renderStages()), + artifactStore: Lazy.anyValue({ produce: () => this.renderArtifactStore() }), + artifactStores: Lazy.anyValue({ produce: () => this.renderArtifactStores() }), + stages: Lazy.anyValue({ produce: () => this.renderStages() }), roleArn: this.role.roleArn, restartExecutionOnUpdate: props && props.restartExecutionOnUpdate, name: props && props.pipelineName, @@ -255,7 +255,7 @@ export class Pipeline extends PipelineBase { this.artifactBucket.grantReadWrite(this.role); - this.pipelineName = codePipeline.ref; + this.pipelineName = codePipeline.refAsString; this.pipelineVersion = codePipeline.pipelineVersion; this.crossRegionReplicationBuckets = props.crossRegionReplicationBuckets || {}; this.artifactStores = {}; diff --git a/packages/@aws-cdk/aws-codepipeline/lib/validation.ts b/packages/@aws-cdk/aws-codepipeline/lib/validation.ts index f3b90d3c72ede..2853165951ab6 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/validation.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/validation.ts @@ -55,7 +55,7 @@ export function validateArtifactName(artifactName: string | undefined): void { function validateAgainstRegex(regex: RegExp, thing: string, name: string | undefined) { // name could be a Token - in that case, skip validation altogether - if (cdk.Token.isToken(name)) { + if (cdk.Token.isUnresolved(name)) { return; } diff --git a/packages/@aws-cdk/aws-codepipeline/package-lock.json b/packages/@aws-cdk/aws-codepipeline/package-lock.json new file mode 100644 index 0000000000000..20b7430831fc6 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-codepipeline", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index e536c131f1782..dd59ca6d6fea7 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -1,6 +1,6 @@ import iam = require('@aws-cdk/aws-iam'); import lambda = require('@aws-cdk/aws-lambda'); -import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { CfnUserPool } from './cognito.generated'; /** @@ -393,7 +393,7 @@ export class UserPool extends Resource implements IUserPool { usernameAttributes, aliasAttributes, autoVerifiedAttributes: props.autoVerifiedAttributes, - lambdaConfig: new Token(() => this.triggers) + lambdaConfig: Lazy.anyValue({ produce: () => this.triggers }) }); this.userPoolId = userPool.userPoolId; this.userPoolArn = userPool.userPoolArn; diff --git a/packages/@aws-cdk/aws-cognito/package-lock.json b/packages/@aws-cdk/aws-cognito/package-lock.json new file mode 100644 index 0000000000000..ad5d92cf61446 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-cognito", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-config/lib/managed-rules.ts b/packages/@aws-cdk/aws-config/lib/managed-rules.ts index 5c42afced58f1..d6f6947128e03 100644 --- a/packages/@aws-cdk/aws-config/lib/managed-rules.ts +++ b/packages/@aws-cdk/aws-config/lib/managed-rules.ts @@ -1,6 +1,6 @@ import iam = require('@aws-cdk/aws-iam'); import sns = require('@aws-cdk/aws-sns'); -import { Construct, Stack, Token } from '@aws-cdk/cdk'; +import { Construct, Lazy, Stack } from '@aws-cdk/cdk'; import { ManagedRule, RuleProps } from './rule'; /** @@ -77,7 +77,7 @@ export class CloudFormationStackDriftDetectionCheck extends ManagedRule { ...props, identifier: 'CLOUDFORMATION_STACK_DRIFT_DETECTION_CHECK', inputParameters: { - cloudformationRoleArn: new Token(() => this.role.roleArn) + cloudformationRoleArn: Lazy.stringValue({ produce: () => this.role.roleArn }) } }); diff --git a/packages/@aws-cdk/aws-config/lib/rule.ts b/packages/@aws-cdk/aws-config/lib/rule.ts index 1ee8783db6f19..c1d2f39d4083c 100644 --- a/packages/@aws-cdk/aws-config/lib/rule.ts +++ b/packages/@aws-cdk/aws-config/lib/rule.ts @@ -1,7 +1,7 @@ import events = require('@aws-cdk/aws-events'); import iam = require('@aws-cdk/aws-iam'); import lambda = require('@aws-cdk/aws-lambda'); -import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { CfnConfigRule } from './config.generated'; /** @@ -255,7 +255,7 @@ export class ManagedRule extends RuleNew { description: props.description, inputParameters: props.inputParameters, maximumExecutionFrequency: props.maximumExecutionFrequency, - scope: new Token(() => this.scope), + scope: Lazy.anyValue({ produce: () => this.scope }), source: { owner: 'AWS', sourceIdentifier: props.identifier @@ -358,7 +358,7 @@ export class CustomRule extends RuleNew { description: props.description, inputParameters: props.inputParameters, maximumExecutionFrequency: props.maximumExecutionFrequency, - scope: new Token(() => this.scope), + scope: Lazy.anyValue({ produce: () => this.scope }), source: { owner: 'CUSTOM_LAMBDA', sourceDetails, diff --git a/packages/@aws-cdk/aws-config/package-lock.json b/packages/@aws-cdk/aws-config/package-lock.json new file mode 100644 index 0000000000000..e1efa396fa118 --- /dev/null +++ b/packages/@aws-cdk/aws-config/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-config", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-datapipeline/package-lock.json b/packages/@aws-cdk/aws-datapipeline/package-lock.json new file mode 100644 index 0000000000000..449678588395b --- /dev/null +++ b/packages/@aws-cdk/aws-datapipeline/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-datapipeline", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-dax/package-lock.json b/packages/@aws-cdk/aws-dax/package-lock.json new file mode 100644 index 0000000000000..9aa49cef9a39a --- /dev/null +++ b/packages/@aws-cdk/aws-dax/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-dax", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-directoryservice/package-lock.json b/packages/@aws-cdk/aws-directoryservice/package-lock.json new file mode 100644 index 0000000000000..b7606f2738d67 --- /dev/null +++ b/packages/@aws-cdk/aws-directoryservice/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-directoryservice", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-dlm/package-lock.json b/packages/@aws-cdk/aws-dlm/package-lock.json new file mode 100644 index 0000000000000..49128589c917a --- /dev/null +++ b/packages/@aws-cdk/aws-dlm/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-dlm", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-dms/package-lock.json b/packages/@aws-cdk/aws-dms/package-lock.json new file mode 100644 index 0000000000000..5d946ca1c12b7 --- /dev/null +++ b/packages/@aws-cdk/aws-dms/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-dms", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-docdb/package-lock.json b/packages/@aws-cdk/aws-docdb/package-lock.json new file mode 100644 index 0000000000000..cdfe1327e310b --- /dev/null +++ b/packages/@aws-cdk/aws-docdb/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-docdb", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package-lock.json b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package-lock.json index a826ef0b4c49c..e9fc166459b53 100644 --- a/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package-lock.json +++ b/packages/@aws-cdk/aws-dynamodb-global/lambda-packages/aws-global-table-coordinator/package-lock.json @@ -1,6 +1,6 @@ { "name": "aws-global-lambda-coordinator", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/aws-dynamodb-global/package-lock.json b/packages/@aws-cdk/aws-dynamodb-global/package-lock.json new file mode 100644 index 0000000000000..1e80e406ec79a --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb-global/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-dynamodb-global", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-dynamodb/lib/table.ts b/packages/@aws-cdk/aws-dynamodb/lib/table.ts index e9cb106f2c61d..7a82d95e8c646 100644 --- a/packages/@aws-cdk/aws-dynamodb/lib/table.ts +++ b/packages/@aws-cdk/aws-dynamodb/lib/table.ts @@ -1,6 +1,6 @@ import appscaling = require('@aws-cdk/aws-applicationautoscaling'); import iam = require('@aws-cdk/aws-iam'); -import { Aws, Construct, Resource, Stack, Token } from '@aws-cdk/cdk'; +import { Aws, Construct, Lazy, Resource, Stack } from '@aws-cdk/cdk'; import { CfnTable } from './dynamodb.generated'; import { EnableScalingProps, IScalableTableAttribute } from './scalable-attribute-api'; import { ScalableTableAttribute } from './scalable-table-attribute'; @@ -233,8 +233,8 @@ export class Table extends Resource { tableName: props.tableName, keySchema: this.keySchema, attributeDefinitions: this.attributeDefinitions, - globalSecondaryIndexes: new Token(() => this.globalSecondaryIndexes.length > 0 ? this.globalSecondaryIndexes : undefined), - localSecondaryIndexes: new Token(() => this.localSecondaryIndexes.length > 0 ? this.localSecondaryIndexes : undefined), + globalSecondaryIndexes: Lazy.anyValue({ produce: () => this.globalSecondaryIndexes }, { omitEmptyArray: true }), + localSecondaryIndexes: Lazy.anyValue({ produce: () => this.localSecondaryIndexes }, { omitEmptyArray: true }), pointInTimeRecoverySpecification: props.pitrEnabled ? { pointInTimeRecoveryEnabled: props.pitrEnabled } : undefined, billingMode: this.billingMode === BillingMode.PayPerRequest ? this.billingMode : undefined, provisionedThroughput: props.billingMode === BillingMode.PayPerRequest ? undefined : { @@ -423,7 +423,7 @@ export class Table extends Resource { actions, resourceArns: [ this.tableArn, - new Token(() => this.hasIndex ? `${this.tableArn}/index/*` : Aws.noValue).toString() + Lazy.stringValue({ produce: () => this.hasIndex ? `${this.tableArn}/index/*` : Aws.noValue }) ], scope: this, }); diff --git a/packages/@aws-cdk/aws-dynamodb/package-lock.json b/packages/@aws-cdk/aws-dynamodb/package-lock.json new file mode 100644 index 0000000000000..8ef7f5259f77d --- /dev/null +++ b/packages/@aws-cdk/aws-dynamodb/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-dynamodb", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group-rule.ts b/packages/@aws-cdk/aws-ec2/lib/security-group-rule.ts index 4b5d0379b9066..e968eeb9555ff 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group-rule.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group-rule.ts @@ -153,7 +153,7 @@ export enum Protocol { * A single TCP port */ export class TcpPort implements IPortRange { - public readonly canInlineRule = !Token.isToken(this.port); + public readonly canInlineRule = !Token.isUnresolved(this.port); constructor(private readonly port: number) { } @@ -167,7 +167,7 @@ export class TcpPort implements IPortRange { } public toString() { - return Token.isToken(this.port) ? `{IndirectPort}` : this.port.toString(); + return Token.isUnresolved(this.port) ? `{IndirectPort}` : this.port.toString(); } } @@ -175,7 +175,7 @@ export class TcpPort implements IPortRange { * A TCP port range */ export class TcpPortRange implements IPortRange { - public readonly canInlineRule = !Token.isToken(this.startPort) && !Token.isToken(this.endPort); + public readonly canInlineRule = !Token.isUnresolved(this.startPort) && !Token.isUnresolved(this.endPort); constructor(private readonly startPort: number, private readonly endPort: number) { } @@ -216,7 +216,7 @@ export class TcpAllPorts implements IPortRange { * A single UDP port */ export class UdpPort implements IPortRange { - public readonly canInlineRule = !Token.isToken(this.port); + public readonly canInlineRule = !Token.isUnresolved(this.port); constructor(private readonly port: number) { } @@ -230,7 +230,7 @@ export class UdpPort implements IPortRange { } public toString() { - const port = Token.isToken(this.port) ? '{IndirectPort}' : this.port; + const port = Token.isUnresolved(this.port) ? '{IndirectPort}' : this.port; return `UDP ${port}`; } } @@ -239,7 +239,7 @@ export class UdpPort implements IPortRange { * A UDP port range */ export class UdpPortRange implements IPortRange { - public readonly canInlineRule = !Token.isToken(this.startPort) && !Token.isToken(this.endPort); + public readonly canInlineRule = !Token.isUnresolved(this.startPort) && !Token.isUnresolved(this.endPort); constructor(private readonly startPort: number, private readonly endPort: number) { } @@ -280,7 +280,7 @@ export class UdpAllPorts implements IPortRange { * A set of matching ICMP Type & Code */ export class IcmpTypeAndCode implements IPortRange { - public readonly canInlineRule = !Token.isToken(this.type) && !Token.isToken(this.code); + public readonly canInlineRule = !Token.isUnresolved(this.type) && !Token.isUnresolved(this.code); constructor(private readonly type: number, private readonly code: number) { } @@ -321,7 +321,7 @@ export class IcmpPing implements IPortRange { * All ICMP Codes for a given ICMP Type */ export class IcmpAllTypeCodes implements IPortRange { - public readonly canInlineRule = !Token.isToken(this.type); + public readonly canInlineRule = !Token.isUnresolved(this.type); constructor(private readonly type: number) { } @@ -373,4 +373,4 @@ export class AllTraffic implements IPortRange { public toString() { return 'ALL TRAFFIC'; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index 994f3130cfe10..31f6946d92ea2 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -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 { Connections, IConnectable } from './connections'; import { CfnSecurityGroup, CfnSecurityGroupEgress, CfnSecurityGroupIngress } from './ec2.generated'; import { IPortRange, ISecurityGroupRule } from './security-group-rule'; @@ -275,8 +275,8 @@ export class SecurityGroup extends SecurityGroupBase { this.securityGroup = new CfnSecurityGroup(this, 'Resource', { groupName: props.groupName, groupDescription, - securityGroupIngress: new Token(() => this.directIngressRules), - securityGroupEgress: new Token(() => this.directEgressRules), + securityGroupIngress: Lazy.anyValue({ produce: () => this.directIngressRules }), + securityGroupEgress: Lazy.anyValue({ produce: () => this.directEgressRules }), vpcId: props.vpc.vpcId, }); diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts index bbe83e76efa24..96bb3aab7fb3f 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-endpoint.ts @@ -1,5 +1,5 @@ import iam = require('@aws-cdk/aws-iam'); -import { Aws, Construct, IResource, Resource, Token } from '@aws-cdk/cdk'; +import { Aws, Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { Connections, IConnectable } from './connections'; import { CfnVPCEndpoint } from './ec2.generated'; import { SecurityGroup } from './security-group'; @@ -172,7 +172,7 @@ export class GatewayVpcEndpoint extends VpcEndpoint implements IGatewayVpcEndpoi } const endpoint = new CfnVPCEndpoint(this, 'Resource', { - policyDocument: new Token(() => this.policyDocument), + policyDocument: Lazy.anyValue({ produce: () => this.policyDocument }), routeTableIds, serviceName: props.service.name, vpcEndpointType: VpcEndpointType.Gateway, @@ -373,7 +373,7 @@ export class InterfaceVpcEndpoint extends VpcEndpoint implements IInterfaceVpcEn const endpoint = new CfnVPCEndpoint(this, 'Resource', { privateDnsEnabled: props.privateDnsEnabled !== undefined ? props.privateDnsEnabled : true, - policyDocument: new Token(() => this.policyDocument), + policyDocument: Lazy.anyValue({ produce: () => this.policyDocument }), securityGroupIds: [this.securityGroupId], serviceName: props.service.name, vpcEndpointType: VpcEndpointType.Interface, diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index c94618974d2d6..a4a25c41713cd 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -810,12 +810,12 @@ export class Vpc extends VpcBase { }); this.internetDependencies.push(igw); const att = new CfnVPCGatewayAttachment(this, 'VPCGW', { - internetGatewayId: igw.ref, - vpcId: this.resource.ref + internetGatewayId: igw.refAsString, + vpcId: this.resource.refAsString }); (this.publicSubnets as PublicSubnet[]).forEach(publicSubnet => { - publicSubnet.addDefaultInternetRoute(igw.ref, att); + publicSubnet.addDefaultInternetRoute(igw.refAsString, att); }); // if gateways are needed create them @@ -1129,12 +1129,12 @@ export class Subnet extends cdk.Resource implements ISubnet { const table = new CfnRouteTable(this, 'RouteTable', { vpcId: props.vpcId, }); - this.routeTableId = table.ref; + this.routeTableId = table.refAsString; // Associate the public route table for this subnet, to this subnet new CfnSubnetRouteTableAssociation(this, 'RouteTableAssociation', { subnetId: this.subnetId, - routeTableId: table.ref + routeTableId: table.refAsString }); } diff --git a/packages/@aws-cdk/aws-ec2/package-lock.json b/packages/@aws-cdk/aws-ec2/package-lock.json new file mode 100644 index 0000000000000..2d986a32e3367 --- /dev/null +++ b/packages/@aws-cdk/aws-ec2/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-ec2", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-ec2/test/test.security-group.ts b/packages/@aws-cdk/aws-ec2/test/test.security-group.ts index f54af3a228ce2..091c6e46a3d0b 100644 --- a/packages/@aws-cdk/aws-ec2/test/test.security-group.ts +++ b/packages/@aws-cdk/aws-ec2/test/test.security-group.ts @@ -1,5 +1,5 @@ import { expect, haveResource } from '@aws-cdk/assert'; -import { Stack, Token } from '@aws-cdk/cdk'; +import { Lazy, Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; import { @@ -145,11 +145,11 @@ export = { const ports = [ new TcpPort(1234), - new TcpPort(new Token(5000).toNumber()), + new TcpPort(Lazy.numberValue({ produce: () => 5000 })), new TcpAllPorts(), new TcpPortRange(80, 90), new UdpPort(2345), - new UdpPort(new Token(777).toNumber()), + new UdpPort(Lazy.numberValue({ produce: () => 7777 })), new UdpAllPorts(), new UdpPortRange(85, 95), new IcmpTypeAndCode(5, 1), @@ -174,8 +174,8 @@ export = { 'if tokens are used in ports, `canInlineRule` should be false to avoid cycles'(test: Test) { // GIVEN - const p1 = new Token(() => 80).toNumber(); - const p2 = new Token(() => 5000).toNumber(); + const p1 = Lazy.numberValue({ produce: () => 80 }); + const p2 = Lazy.numberValue({ produce: () => 5000 }); // WHEN const ports = [ @@ -201,4 +201,4 @@ export = { test.done(); } -}; \ No newline at end of file +}; diff --git a/packages/@aws-cdk/aws-ecr/lib/repository.ts b/packages/@aws-cdk/aws-ecr/lib/repository.ts index 7a8ae20363706..9fa3186fedf3a 100644 --- a/packages/@aws-cdk/aws-ecr/lib/repository.ts +++ b/packages/@aws-cdk/aws-ecr/lib/repository.ts @@ -1,6 +1,6 @@ import events = require('@aws-cdk/aws-events'); import iam = require('@aws-cdk/aws-iam'); -import { Construct, DeletionPolicy, IConstruct, IResource, Resource, Stack, Token } from '@aws-cdk/cdk'; +import { Construct, DeletionPolicy, IConstruct, IResource, Lazy, Resource, Stack, Token } from '@aws-cdk/cdk'; import { CfnRepository } from './ecr.generated'; import { CountType, LifecycleRule, TagStatus } from './lifecycle'; @@ -288,7 +288,7 @@ export class Repository extends RepositoryBase { // if repositoryArn is a token, the repository name is also required. this is because // repository names can include "/" (e.g. foo/bar/myrepo) and it is impossible to // parse the name from an ARN using CloudFormation's split/select. - if (Token.isToken(repositoryArn)) { + if (Token.isUnresolved(repositoryArn)) { throw new Error('"repositoryArn" is a late-bound value, and therefore "repositoryName" is required. Use `fromRepositoryAttributes` instead'); } @@ -343,8 +343,8 @@ export class Repository extends RepositoryBase { const resource = new CfnRepository(this, 'Resource', { repositoryName: props.repositoryName, // It says "Text", but they actually mean "Object". - repositoryPolicyText: new Token(() => this.policyDocument), - lifecyclePolicy: new Token(() => this.renderLifecyclePolicy()), + repositoryPolicyText: Lazy.anyValue({ produce: () => this.policyDocument }), + lifecyclePolicy: Lazy.anyValue({ produce: () => this.renderLifecyclePolicy() }), }); if (props.retain) { diff --git a/packages/@aws-cdk/aws-ecr/package-lock.json b/packages/@aws-cdk/aws-ecr/package-lock.json new file mode 100644 index 0000000000000..307883d4718a2 --- /dev/null +++ b/packages/@aws-cdk/aws-ecr/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-ecr", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index 847c8310fbe5f..33f30feebec03 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -4,7 +4,7 @@ import ec2 = require('@aws-cdk/aws-ec2'); import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); import iam = require('@aws-cdk/aws-iam'); import cloudmap = require('@aws-cdk/aws-servicediscovery'); -import { IResource, Resource, Stack } from '@aws-cdk/cdk'; +import { IResource, Lazy, Resource, Stack } from '@aws-cdk/cdk'; import cdk = require('@aws-cdk/cdk'); import { NetworkMode, TaskDefinition } from '../base/task-definition'; import { ICluster } from '../cluster'; @@ -146,15 +146,15 @@ export abstract class BaseService extends Resource this.resource = new CfnService(this, "Service", { desiredCount: props.desiredCount, serviceName: props.serviceName, - loadBalancers: new cdk.Token(() => this.loadBalancers), + loadBalancers: Lazy.anyValue({ produce: () => this.loadBalancers }), deploymentConfiguration: { maximumPercent: props.maximumPercent || 200, minimumHealthyPercent: props.minimumHealthyPercent === undefined ? 50 : props.minimumHealthyPercent }, healthCheckGracePeriodSeconds: props.healthCheckGracePeriodSeconds, /* role: never specified, supplanted by Service Linked Role */ - networkConfiguration: new cdk.Token(() => this.networkConfiguration), - serviceRegistries: new cdk.Token(() => this.serviceRegistries), + networkConfiguration: Lazy.anyValue({ produce: () => this.networkConfiguration }), + serviceRegistries: Lazy.anyValue({ produce: () => this.serviceRegistries }), ...additionalProps }); @@ -249,7 +249,7 @@ export abstract class BaseService extends Resource awsvpcConfiguration: { assignPublicIp: assignPublicIp ? 'ENABLED' : 'DISABLED', subnets: vpc.selectSubnets(vpcSubnets).subnetIds, - securityGroups: new cdk.Token(() => [securityGroup!.securityGroupId]).toList(), + securityGroups: Lazy.listValue({ produce: () => [securityGroup!.securityGroupId] }), } }; } diff --git a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts index bb21d9061abd0..fa1e6419f699d 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts @@ -1,5 +1,5 @@ import iam = require('@aws-cdk/aws-iam'); -import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { ContainerDefinition, ContainerDefinitionOptions } from '../container-definition'; import { CfnTaskDefinition } from '../ecs.generated'; import { PlacementConstraint } from '../placement'; @@ -262,9 +262,9 @@ export class TaskDefinition extends TaskDefinitionBase { }); const taskDef = new CfnTaskDefinition(this, 'Resource', { - containerDefinitions: new Token(() => this.containers.map(x => x.renderContainerDefinition())), - volumes: new Token(() => this.volumes), - executionRoleArn: new Token(() => this.executionRole && this.executionRole.roleArn).toString(), + containerDefinitions: Lazy.anyValue({ produce: () => this.containers.map(x => x.renderContainerDefinition()) }), + volumes: Lazy.anyValue({ produce: () => this.volumes }), + executionRoleArn: Lazy.stringValue({ produce: () => this.executionRole && this.executionRole.roleArn }), family: this.family, taskRoleArn: this.taskRole.roleArn, requiresCompatibilities: [ @@ -272,8 +272,9 @@ export class TaskDefinition extends TaskDefinitionBase { ...(isFargateCompatible(props.compatibility) ? ["FARGATE"] : []), ], networkMode: this.networkMode, - placementConstraints: new Token( - () => !isFargateCompatible(this.compatibility) && this.placementConstraints.length > 0 ? this.placementConstraints : undefined), + placementConstraints: Lazy.anyValue({ produce: () => + !isFargateCompatible(this.compatibility) && this.placementConstraints.length > 0 ? this.placementConstraints : undefined + }), cpu: props.cpu, memory: props.memoryMiB, }); diff --git a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts index 59f4552f174a9..f9ae74eb5f4e8 100644 --- a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts @@ -1,7 +1,7 @@ import cloudwatch = require ('@aws-cdk/aws-cloudwatch'); import ec2 = require('@aws-cdk/aws-ec2'); import elb = require('@aws-cdk/aws-elasticloadbalancing'); -import { Construct, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, Lazy, Resource } from '@aws-cdk/cdk'; import { BaseService, BaseServiceProps, IService } from '../base/base-service'; import { NetworkMode, TaskDefinition } from '../base/task-definition'; import { CfnService } from '../ecs.generated'; @@ -123,8 +123,8 @@ export class Ec2Service extends BaseService implements IEc2Service, elb.ILoadBal cluster: props.cluster.clusterName, taskDefinition: props.taskDefinition.taskDefinitionArn, launchType: 'EC2', - placementConstraints: new Token(() => this.constraints.length > 0 ? this.constraints : undefined), - placementStrategies: new Token(() => this.strategies.length > 0 ? this.strategies : undefined), + placementConstraints: Lazy.anyValue({ produce: () => this.constraints }, { omitEmptyArray: true }), + placementStrategies: Lazy.anyValue({ produce: () => this.strategies }, { omitEmptyArray: true }), schedulingStrategy: props.daemon ? 'DAEMON' : 'REPLICA', }, props.cluster.clusterName, props.taskDefinition); diff --git a/packages/@aws-cdk/aws-efs/package-lock.json b/packages/@aws-cdk/aws-efs/package-lock.json new file mode 100644 index 0000000000000..88b15b84fc517 --- /dev/null +++ b/packages/@aws-cdk/aws-efs/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-efs", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-eks/package-lock.json b/packages/@aws-cdk/aws-eks/package-lock.json new file mode 100644 index 0000000000000..66e25b41385b3 --- /dev/null +++ b/packages/@aws-cdk/aws-eks/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-eks", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-elasticache/package-lock.json b/packages/@aws-cdk/aws-elasticache/package-lock.json new file mode 100644 index 0000000000000..05f1385637b70 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticache/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-elasticache", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-elasticbeanstalk/package-lock.json b/packages/@aws-cdk/aws-elasticbeanstalk/package-lock.json new file mode 100644 index 0000000000000..814e4e6130675 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticbeanstalk/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-elasticbeanstalk", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts index 719d558942405..fad3d826d81fc 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts @@ -1,7 +1,7 @@ import { AnyIPv4, Connections, IConnectable, IPortRange, ISecurityGroup, ISubnet, IVpc, SecurityGroup, TcpPort } from '@aws-cdk/aws-ec2'; -import { Construct, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, Lazy, Resource } from '@aws-cdk/cdk'; import { CfnLoadBalancer } from './elasticloadbalancing.generated'; /** @@ -223,7 +223,7 @@ export class LoadBalancer extends Resource implements IConnectable { this.elb = new CfnLoadBalancer(this, 'Resource', { securityGroups: [ this.securityGroup.securityGroupId ], subnets: subnets.map(s => s.subnetId), - listeners: new Token(() => this.listeners), + listeners: Lazy.anyValue({ produce: () => this.listeners }), scheme: props.internetFacing ? 'internet-facing' : 'internal', healthCheck: props.healthCheck && healthCheckToJSON(props.healthCheck), }); @@ -281,7 +281,7 @@ export class LoadBalancer extends Resource implements IConnectable { * @attribute */ public get loadBalancerName() { - return this.elb.ref; + return this.elb.refAsString; } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/package-lock.json b/packages/@aws-cdk/aws-elasticloadbalancing/package-lock.json new file mode 100644 index 0000000000000..f9436ea4ced33 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancing/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-elasticloadbalancing", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts index d72ebfb356b48..200f0e9852aef 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts @@ -130,8 +130,8 @@ export class ApplicationListenerRule extends cdk.Construct { const resource = new CfnListenerRule(this, 'Resource', { listenerArn: props.listener.listenerArn, priority: props.priority, - conditions: new cdk.Token(() => this.renderConditions()), - actions: new cdk.Token(() => this.actions), + conditions: cdk.Lazy.anyValue({ produce: () => this.renderConditions() }), + actions: cdk.Lazy.anyValue({ produce: () => this.actions }), }); if (props.hostHeader) { @@ -147,7 +147,7 @@ export class ApplicationListenerRule extends cdk.Construct { this.addFixedResponse(props.fixedResponse); } - this.listenerRuleArn = resource.ref; + this.listenerRuleArn = resource.refAsString; } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 3fec6822fbe80..adb38a833cffc 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -1,5 +1,5 @@ import ec2 = require('@aws-cdk/aws-ec2'); -import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { BaseListener } from '../shared/base-listener'; import { HealthCheck } from '../shared/base-target-group'; import { ApplicationProtocol, SslPolicy } from '../shared/enums'; @@ -112,7 +112,7 @@ export class ApplicationListener extends BaseListener implements IApplicationLis super(scope, id, { loadBalancerArn: props.loadBalancer.loadBalancerArn, - certificates: new Token(() => this.certificateArns.map(certificateArn => ({ certificateArn }))), + certificates: Lazy.anyValue({ produce: () => this.certificateArns.map(certificateArn => ({ certificateArn })) }), protocol, port, sslPolicy: props.sslPolicy, diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts index 377e495a7e02e..023dd5686c155 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts @@ -2,7 +2,7 @@ import cloudwatch = require('@aws-cdk/aws-cloudwatch'); import ec2 = require('@aws-cdk/aws-ec2'); import iam = require('@aws-cdk/aws-iam'); import s3 = require('@aws-cdk/aws-s3'); -import { Construct, Resource, Stack, Token } from '@aws-cdk/cdk'; +import { Construct, Lazy, Resource, Stack } from '@aws-cdk/cdk'; import { BaseLoadBalancer, BaseLoadBalancerProps, ILoadBalancerV2 } from '../shared/base-load-balancer'; import { IpAddressType } from '../shared/enums'; import { ApplicationListener, BaseApplicationListenerProps } from './application-listener'; @@ -63,7 +63,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic constructor(scope: Construct, id: string, props: ApplicationLoadBalancerProps) { super(scope, id, props, { type: "application", - securityGroups: new Token(() => [this.securityGroup.securityGroupId]), + securityGroups: Lazy.listValue({ produce: () => [this.securityGroup.securityGroupId] }), ipAddressType: props.ipAddressType, }); diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts index 9b233274671cc..406db3cd7ea33 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-listener.ts @@ -1,4 +1,4 @@ -import { Construct, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, Lazy, Resource } from '@aws-cdk/cdk'; import { CfnListener } from '../elasticloadbalancingv2.generated'; import { ITargetGroup } from './base-target-group'; @@ -18,10 +18,10 @@ export abstract class BaseListener extends Resource { const resource = new CfnListener(this, 'Resource', { ...additionalProps, - defaultActions: new Token(() => this.defaultActions), + defaultActions: Lazy.anyValue({ produce: () => this.defaultActions }), }); - this.listenerArn = resource.ref; + this.listenerArn = resource.refAsString; } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts index 815c1a06dc798..d4af6cf547020 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts @@ -1,5 +1,5 @@ import ec2 = require('@aws-cdk/aws-ec2'); -import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { CfnLoadBalancer } from '../elasticloadbalancingv2.generated'; import { Attributes, ifUndefined, renderAttributes } from './util'; @@ -136,7 +136,7 @@ export abstract class BaseLoadBalancer extends Resource { name: baseProps.loadBalancerName, subnets: subnetIds, scheme: internetFacing ? 'internet-facing' : 'internal', - loadBalancerAttributes: new Token(() => renderAttributes(this.attributes)), + loadBalancerAttributes: Lazy.anyValue({ produce: () => renderAttributes(this.attributes) }), ...additionalProps }); if (internetFacing) { @@ -149,7 +149,7 @@ export abstract class BaseLoadBalancer extends Resource { this.loadBalancerDnsName = resource.loadBalancerDnsName; this.loadBalancerFullName = resource.loadBalancerFullName; this.loadBalancerName = resource.loadBalancerName; - this.loadBalancerArn = resource.ref; + this.loadBalancerArn = resource.refAsString; this.loadBalancerSecurityGroups = resource.loadBalancerSecurityGroups; } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index 63857f0a3c62c..930487f9bae5c 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -213,28 +213,28 @@ export abstract class TargetGroupBase extends cdk.Construct implements ITargetGr this.resource = new CfnTargetGroup(this, 'Resource', { name: baseProps.targetGroupName, - targetGroupAttributes: new cdk.Token(() => renderAttributes(this.attributes)), - targetType: new cdk.Token(() => this.targetType), - targets: new cdk.Token(() => this.targetsJson), + targetGroupAttributes: cdk.Lazy.anyValue({ produce: () => renderAttributes(this.attributes) }), + targetType: cdk.Lazy.stringValue({ produce: () => this.targetType }), + targets: cdk.Lazy.anyValue({ produce: () => this.targetsJson }), vpcId: baseProps.vpc.vpcId, // HEALTH CHECK - healthCheckIntervalSeconds: new cdk.Token(() => this.healthCheck && this.healthCheck.intervalSecs), - healthCheckPath: new cdk.Token(() => this.healthCheck && this.healthCheck.path), - healthCheckPort: new cdk.Token(() => this.healthCheck && this.healthCheck.port), - healthCheckProtocol: new cdk.Token(() => this.healthCheck && this.healthCheck.protocol), - healthCheckTimeoutSeconds: new cdk.Token(() => this.healthCheck && this.healthCheck.timeoutSeconds), - healthyThresholdCount: new cdk.Token(() => this.healthCheck && this.healthCheck.healthyThresholdCount), - unhealthyThresholdCount: new cdk.Token(() => this.healthCheck && this.healthCheck.unhealthyThresholdCount), - matcher: new cdk.Token(() => this.healthCheck && this.healthCheck.healthyHttpCodes !== undefined ? { + healthCheckIntervalSeconds: cdk.Lazy.numberValue({ produce: () => this.healthCheck && this.healthCheck.intervalSecs }), + healthCheckPath: cdk.Lazy.stringValue({ produce: () => this.healthCheck && this.healthCheck.path }), + healthCheckPort: cdk.Lazy.stringValue({ produce: () => this.healthCheck && this.healthCheck.port }), + healthCheckProtocol: cdk.Lazy.stringValue({ produce: () => this.healthCheck && this.healthCheck.protocol }), + healthCheckTimeoutSeconds: cdk.Lazy.numberValue({ produce: () => this.healthCheck && this.healthCheck.timeoutSeconds }), + healthyThresholdCount: cdk.Lazy.numberValue({ produce: () => this.healthCheck && this.healthCheck.healthyThresholdCount }), + unhealthyThresholdCount: cdk.Lazy.numberValue({ produce: () => this.healthCheck && this.healthCheck.unhealthyThresholdCount }), + matcher: cdk.Lazy.anyValue({ produce: () => this.healthCheck && this.healthCheck.healthyHttpCodes !== undefined ? { httpCode: this.healthCheck.healthyHttpCodes - } : undefined), + } : undefined }), ...additionalProps }); this.targetGroupLoadBalancerArns = this.resource.targetGroupLoadBalancerArns; - this.targetGroupArn = this.resource.ref; + this.targetGroupArn = this.resource.refAsString; this.targetGroupFullName = this.resource.targetGroupFullName; this.loadBalancerArns = this.resource.targetGroupLoadBalancerArns.toString(); this.targetGroupName = this.resource.targetGroupName; diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/package-lock.json b/packages/@aws-cdk/aws-elasticloadbalancingv2/package-lock.json new file mode 100644 index 0000000000000..7f3b3dae77e27 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-elasticloadbalancingv2", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-elasticsearch/package-lock.json b/packages/@aws-cdk/aws-elasticsearch/package-lock.json new file mode 100644 index 0000000000000..40b7e1043dd36 --- /dev/null +++ b/packages/@aws-cdk/aws-elasticsearch/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-elasticsearch", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-emr/package-lock.json b/packages/@aws-cdk/aws-emr/package-lock.json new file mode 100644 index 0000000000000..4cc949cbc2abc --- /dev/null +++ b/packages/@aws-cdk/aws-emr/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-emr", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json index 04a6e3740851e..a87767b5ef881 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/integ.project-events.expected.json @@ -59,10 +59,10 @@ "Id": "MyTopic", "InputTransformer": { "InputPathsMap": { - "f1": "$.detail.repositoryName", - "f2": "$.detail.referenceName" + "detail-repositoryName": "$.detail.repositoryName", + "detail-referenceName": "$.detail.referenceName" }, - "InputTemplate": "\"A commit was pushed to the repository on branch \"" + "InputTemplate": "\"A commit was pushed to the repository on branch \"" } } ] @@ -316,9 +316,9 @@ "Id": "MyTopic", "InputTransformer": { "InputPathsMap": { - "f1": "$.detail.completed-phase" + "detail-completed-phase": "$.detail.completed-phase" }, - "InputTemplate": "\"Build phase changed to \"" + "InputTemplate": "\"Build phase changed to \"" } } ] diff --git a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts index 01a2fb6c707a2..108df76336b71 100644 --- a/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/ecs/event-rule-target.test.ts @@ -46,9 +46,9 @@ test("Can use EC2 taskdef as EventRule target", () => { }, InputTransformer: { InputPathsMap: { - f1: "$.detail.event" + "detail-event": "$.detail.event" }, - InputTemplate: "{\"containerOverrides\":[{\"name\":\"TheContainer\",\"command\":[\"echo\",]}]}" + InputTemplate: "{\"containerOverrides\":[{\"name\":\"TheContainer\",\"command\":[\"echo\",]}]}" }, RoleArn: { "Fn::GetAtt": ["TaskDefEventsRoleFB3B67B8", "Arn"] } } diff --git a/packages/@aws-cdk/aws-events/lib/input.ts b/packages/@aws-cdk/aws-events/lib/input.ts index 1fd9b67c5ce43..7c089f20b0e20 100644 --- a/packages/@aws-cdk/aws-events/lib/input.ts +++ b/packages/@aws-cdk/aws-events/lib/input.ts @@ -1,4 +1,5 @@ -import { DefaultTokenResolver, IResolveContext, resolve, Stack, StringConcat, Token } from '@aws-cdk/cdk'; +import { DefaultTokenResolver, IResolvable, IResolveContext, + Lazy, Stack, StringConcat, Token, Tokenization } from '@aws-cdk/cdk'; import { IRule } from './rule-ref'; /** @@ -134,7 +135,7 @@ class FieldAwareEventInput extends RuleTargetInput { if (existing !== undefined) { return existing; } fieldCounter += 1; - const key = f.nameHint || `f${fieldCounter}`; + const key = f.displayHint || `f${fieldCounter}`; pathToKey.set(f.path, key); return key; } @@ -164,13 +165,13 @@ class FieldAwareEventInput extends RuleTargetInput { let resolved: string; if (this.inputType === InputType.Multiline) { // JSONify individual lines - resolved = resolve(this.input, { + resolved = Tokenization.resolve(this.input, { scope: rule, resolver: new EventFieldReplacer() }); resolved = resolved.split('\n').map(stack.toJsonString).join('\n'); } else { - resolved = stack.toJsonString(resolve(this.input, { + resolved = stack.toJsonString(Tokenization.resolve(this.input, { scope: rule, resolver: new EventFieldReplacer() })); @@ -207,9 +208,9 @@ class FieldAwareEventInput extends RuleTargetInput { private unquoteKeyPlaceholders(sub: string) { if (this.inputType !== InputType.Object) { return sub; } - return new Token((ctx: IResolveContext) => + return Lazy.stringValue({ produce: (ctx: IResolveContext) => ctx.resolve(sub).replace(OPENING_STRING_REGEX, '<').replace(CLOSING_STRING_REGEX, '>') - ).toString(); + }); } } @@ -222,61 +223,74 @@ const CLOSING_STRING_REGEX = new RegExp(regexQuote(UNLIKELY_CLOSING_STRING + '"' /** * Represents a field in the event pattern */ -export class EventField extends Token { +export class EventField implements IResolvable { /** * Extract the event ID from the event */ public static get eventId(): string { - return this.fromPath('$.id', 'eventId'); + return this.fromPath('$.id'); } /** * Extract the detail type from the event */ public static get detailType(): string { - return this.fromPath('$.detail-type', 'detailType'); + return this.fromPath('$.detail-type'); } /** * Extract the source from the event */ public static get source(): string { - return this.fromPath('$.source', 'source'); + return this.fromPath('$.source'); } /** * Extract the account from the event */ public static get account(): string { - return this.fromPath('$.account', 'account'); + return this.fromPath('$.account'); } /** * Extract the time from the event */ public static get time(): string { - return this.fromPath('$.time', 'time'); + return this.fromPath('$.time'); } /** * Extract the region from the event */ public static get region(): string { - return this.fromPath('$.region', 'region'); + return this.fromPath('$.region'); } /** * Extract a custom JSON path from the event */ - public static fromPath(path: string, nameHint?: string): string { - return new EventField(path, nameHint).toString(); + public static fromPath(path: string): string { + return new EventField(path).toString(); } - private constructor(public readonly path: string, public readonly nameHint?: string) { - super(() => path); + public readonly displayHint: string; + private constructor(public readonly path: string) { + this.displayHint = this.path.replace(/^[^a-zA-Z0-9_-]+/, '').replace(/[^a-zA-Z0-9_-]/g, '-'); Object.defineProperty(this, EVENT_FIELD_SYMBOL, { value: true }); } + + public resolve(_ctx: IResolveContext): any { + return this.path; + } + + public toString() { + return Token.asString(this, { displayHint: this.displayHint }); + } + + public toJSON() { + return ``; + } } enum InputType { diff --git a/packages/@aws-cdk/aws-events/lib/rule.ts b/packages/@aws-cdk/aws-events/lib/rule.ts index 152657993cee0..3a3993ac3ae4c 100644 --- a/packages/@aws-cdk/aws-events/lib/rule.ts +++ b/packages/@aws-cdk/aws-events/lib/rule.ts @@ -1,4 +1,4 @@ -import { Construct, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, Lazy, Resource } from '@aws-cdk/cdk'; import { EventPattern } from './event-pattern'; import { CfnRule } from './events.generated'; import { IRule } from './rule-ref'; @@ -96,9 +96,9 @@ export class Rule extends Resource implements IRule { name: props.ruleName, description: props.description, state: props.enabled == null ? 'ENABLED' : (props.enabled ? 'ENABLED' : 'DISABLED'), - scheduleExpression: new Token(() => this.scheduleExpression).toString(), - eventPattern: new Token(() => this.renderEventPattern()), - targets: new Token(() => this.renderTargets()), + scheduleExpression: Lazy.stringValue({ produce: () => this.scheduleExpression }), + eventPattern: Lazy.anyValue({ produce: () => this.renderEventPattern() }), + targets: Lazy.anyValue({ produce: () => this.renderTargets() }), }); this.ruleArn = resource.ruleArn; diff --git a/packages/@aws-cdk/aws-events/package-lock.json b/packages/@aws-cdk/aws-events/package-lock.json new file mode 100644 index 0000000000000..44399519e9887 --- /dev/null +++ b/packages/@aws-cdk/aws-events/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-events", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-events/test/test.input.ts b/packages/@aws-cdk/aws-events/test/test.input.ts index 8ca4b6659d787..4fe918f32e245 100644 --- a/packages/@aws-cdk/aws-events/test/test.input.ts +++ b/packages/@aws-cdk/aws-events/test/test.input.ts @@ -81,7 +81,7 @@ export = { scheduleExpression: 'rate(1 minute)' }); - const world = new cdk.Token(() => 'world'); + const world = cdk.Lazy.stringValue({ produce: () => 'world' }); // WHEN rule.addTarget(new SomeTarget(RuleTargetInput.fromText(`hello ${world}`))); diff --git a/packages/@aws-cdk/aws-events/test/test.rule.ts b/packages/@aws-cdk/aws-events/test/test.rule.ts index d9c0ed4230521..5ed5cba222f5b 100644 --- a/packages/@aws-cdk/aws-events/test/test.rule.ts +++ b/packages/@aws-cdk/aws-events/test/test.rule.ts @@ -168,7 +168,7 @@ export = { bind: () => ({ id: 'T2', arn: 'ARN2', - input: RuleTargetInput.fromText(`This is ${EventField.fromPath('$.detail.bla', 'bla')}`), + input: RuleTargetInput.fromText(`This is ${EventField.fromPath('$.detail.bla')}`), }) }; @@ -199,9 +199,9 @@ export = { "Id": "T2", "InputTransformer": { "InputPathsMap": { - "bla": "$.detail.bla" + "detail-bla": "$.detail.bla" }, - "InputTemplate": "\"This is \"" + "InputTemplate": "\"This is \"" }, } ] @@ -275,9 +275,9 @@ export = { "Id": "T3", "InputTransformer": { "InputPathsMap": { - "f1": "$.detail.bar" + "detail-bar": "$.detail.bar" }, - "InputTemplate": "{\"foo\":}" + "InputTemplate": "{\"foo\":}" } }, { @@ -405,4 +405,4 @@ class SomeTarget implements IRuleTarget { id: 'T1', arn: 'ARN1', kinesisParameters: { partitionKeyPath: 'partitionKeyPath' } }; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-fsx/package-lock.json b/packages/@aws-cdk/aws-fsx/package-lock.json new file mode 100644 index 0000000000000..fd8b6eea227e7 --- /dev/null +++ b/packages/@aws-cdk/aws-fsx/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-fsx", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-gamelift/package-lock.json b/packages/@aws-cdk/aws-gamelift/package-lock.json new file mode 100644 index 0000000000000..7034374118c86 --- /dev/null +++ b/packages/@aws-cdk/aws-gamelift/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-gamelift", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-glue/package-lock.json b/packages/@aws-cdk/aws-glue/package-lock.json new file mode 100644 index 0000000000000..85ea5216ba853 --- /dev/null +++ b/packages/@aws-cdk/aws-glue/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-glue", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-greengrass/package-lock.json b/packages/@aws-cdk/aws-greengrass/package-lock.json new file mode 100644 index 0000000000000..05da67f490fd1 --- /dev/null +++ b/packages/@aws-cdk/aws-greengrass/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-greengrass", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-guardduty/package-lock.json b/packages/@aws-cdk/aws-guardduty/package-lock.json new file mode 100644 index 0000000000000..ca9b82d83dbd7 --- /dev/null +++ b/packages/@aws-cdk/aws-guardduty/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-guardduty", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-iam/lib/policy-document.ts b/packages/@aws-cdk/aws-iam/lib/policy-document.ts index d0e2813d5da67..aaabe7f18f987 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy-document.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy-document.ts @@ -3,7 +3,7 @@ import { AccountPrincipal, AccountRootPrincipal, Anyone, ArnPrincipal, Canonical FederatedPrincipal, IPrincipal, ServicePrincipal, ServicePrincipalOpts } from './principals'; import { mergePrincipal } from './util'; -export class PolicyDocument extends cdk.Token implements cdk.IResolvedValuePostProcessor { +export class PolicyDocument implements cdk.IResolvableWithPostProcess { private statements = new Array(); private _autoAssignSids = false; @@ -13,7 +13,6 @@ export class PolicyDocument extends cdk.Token implements cdk.IResolvedValuePostP * policy. All statements of this document will be copied in. */ constructor(private readonly baseDocument: any = {}) { - super(); } /** @@ -24,17 +23,7 @@ export class PolicyDocument extends cdk.Token implements cdk.IResolvedValuePostP } public resolve(_context: cdk.IResolveContext): any { - if (this.isEmpty) { - return undefined; - } - - const doc = { - ...this.baseDocument, - Statement: (this.baseDocument.Statement || []).concat(this.statements), - Version: this.baseDocument.Version || '2012-10-17' - }; - - return doc; + return this.render(); } /** @@ -92,12 +81,36 @@ export class PolicyDocument extends cdk.Token implements cdk.IResolvedValuePostP this.statements.push(statement); return this; } + + public toString() { + return cdk.Token.asString(this, { + displayHint: 'PolicyDocument' + }); + } + + public toJSON() { + return this.render(); + } + + private render() { + if (this.isEmpty) { + return undefined; + } + + const doc = { + ...this.baseDocument, + Statement: (this.baseDocument.Statement || []).concat(this.statements), + Version: this.baseDocument.Version || '2012-10-17' + }; + + return doc; + } } /** * Represents a statement in an IAM policy document. */ -export class PolicyStatement extends cdk.Token { +export class PolicyStatement implements cdk.IResolvable { public sid?: string; private action = new Array(); @@ -107,7 +120,6 @@ export class PolicyStatement extends cdk.Token { private effect?: PolicyStatementEffect; constructor(effect: PolicyStatementEffect = PolicyStatementEffect.Allow) { - super(); this.effect = effect; } @@ -269,9 +281,7 @@ export class PolicyStatement extends cdk.Token { } public limitToAccount(accountId: string): PolicyStatement { - return this.addCondition('StringEquals', new cdk.Token(() => { - return { 'sts:ExternalId': accountId }; - })); + return this.addCondition('StringEquals', { 'sts:ExternalId': accountId }); } // @@ -297,7 +307,7 @@ export class PolicyStatement extends cdk.Token { return undefined; } - if (cdk.Token.isToken(values)) { + if (cdk.Token.isUnresolved(values)) { return values; } @@ -338,6 +348,16 @@ export class PolicyStatement extends cdk.Token { return result; } } + + public toString() { + return cdk.Token.asString(this, { + displayHint: 'PolicyStatement' + }); + } + + public toJSON() { + return this.toJson(); + } } export enum PolicyStatementEffect { diff --git a/packages/@aws-cdk/aws-iam/lib/policy.ts b/packages/@aws-cdk/aws-iam/lib/policy.ts index eb4f199024d86..8d3b7f66d7343 100644 --- a/packages/@aws-cdk/aws-iam/lib/policy.ts +++ b/packages/@aws-cdk/aws-iam/lib/policy.ts @@ -1,4 +1,4 @@ -import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { IGroup } from './group'; import { CfnPolicy } from './iam.generated'; import { PolicyDocument, PolicyStatement } from './policy-document'; @@ -94,7 +94,7 @@ export class Policy extends Resource implements IPolicy { const resource = new CfnPolicy(this, 'Resource', { policyDocument: this.document, - policyName: new Token(() => this.policyName).toString(), + policyName: Lazy.stringValue({ produce: () => this.policyName }).toString(), roles: undefinedIfEmpty(() => this.roles.map(r => r.roleName)), users: undefinedIfEmpty(() => this.users.map(u => u.userName)), groups: undefinedIfEmpty(() => this.groups.map(g => g.groupName)), diff --git a/packages/@aws-cdk/aws-iam/lib/principals.ts b/packages/@aws-cdk/aws-iam/lib/principals.ts index 81df7ba7d6628..8a79d26190e02 100644 --- a/packages/@aws-cdk/aws-iam/lib/principals.ts +++ b/packages/@aws-cdk/aws-iam/lib/principals.ts @@ -311,20 +311,26 @@ export class CompositePrincipal extends PrincipalBase { /** * A lazy token that requires an instance of Stack to evaluate */ -class StackDependentToken extends cdk.Token { +class StackDependentToken implements cdk.IResolvable { constructor(private readonly fn: (stack: cdk.Stack) => any) { - super(); } public resolve(context: cdk.IResolveContext) { return this.fn(Stack.of(context.scope)); } + + public toString() { + return cdk.Token.asString(this); + } + + public toJSON() { + return ``; + } } -class ServicePrincipalToken extends cdk.Token { +class ServicePrincipalToken implements cdk.IResolvable { constructor(private readonly service: string, private readonly opts: ServicePrincipalOpts) { - super(); } public resolve(ctx: cdk.IResolveContext) { @@ -332,4 +338,14 @@ class ServicePrincipalToken extends cdk.Token { const fact = RegionInfo.get(region).servicePrincipal(this.service); return fact || Default.servicePrincipal(this.service, region, Stack.of(ctx.scope).urlSuffix); } + + public toString() { + return cdk.Token.asString(this, { + displayHint: this.service + }); + } + + public toJSON() { + return `<${this.service}>`; + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-iam/lib/util.ts b/packages/@aws-cdk/aws-iam/lib/util.ts index 930ecd15b915f..504b6922ba954 100644 --- a/packages/@aws-cdk/aws-iam/lib/util.ts +++ b/packages/@aws-cdk/aws-iam/lib/util.ts @@ -1,13 +1,13 @@ -import { Token } from '@aws-cdk/cdk'; +import { Lazy } from '@aws-cdk/cdk'; import { IPolicy } from './policy'; const MAX_POLICY_NAME_LEN = 128; export function undefinedIfEmpty(f: () => string[]): string[] { - return new Token(() => { + return Lazy.listValue({ produce: () => { const array = f(); return (array && array.length > 0) ? array : undefined; - }).toList(); + }}); } /** diff --git a/packages/@aws-cdk/aws-iam/package-lock.json b/packages/@aws-cdk/aws-iam/package-lock.json new file mode 100644 index 0000000000000..6f7b10ca185d6 --- /dev/null +++ b/packages/@aws-cdk/aws-iam/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-iam", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-iam/test/test.policy-document.ts b/packages/@aws-cdk/aws-iam/test/test.policy-document.ts index d7818c1e878a1..2ba27fcd6f0ac 100644 --- a/packages/@aws-cdk/aws-iam/test/test.policy-document.ts +++ b/packages/@aws-cdk/aws-iam/test/test.policy-document.ts @@ -1,4 +1,4 @@ -import { Stack, Token } from '@aws-cdk/cdk'; +import { Lazy, Stack, Token } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; import { Anyone, AnyPrincipal, CanonicalUserPrincipal, IPrincipal, PolicyDocument, PolicyStatement } from '../lib'; import { ArnPrincipal, CompositePrincipal, FederatedPrincipal, PrincipalPolicyFragment, ServicePrincipal } from '../lib'; @@ -14,7 +14,7 @@ export = { p.addResource('yourQueue'); p.addAllResources(); - p.addAwsAccountPrincipal(`my${new Token({ account: 'account' })}name`); + p.addAwsAccountPrincipal(`my${Token.asString({ account: 'account' })}name`); p.limitToAccount('12221121221'); test.deepEqual(stack.resolve(p), { Action: @@ -290,8 +290,8 @@ export = { const stack = new Stack(); const statement = new PolicyStatement() - .addActions(...new Token(() => ['a', 'b', 'c']).toList()) - .addResources(...new Token(() => ['x', 'y', 'z']).toList()); + .addActions(...Lazy.listValue({ produce: () => ['a', 'b', 'c'] })) + .addResources(...Lazy.listValue({ produce: () => ['x', 'y', 'z'] })); test.deepEqual(stack.resolve(statement), { Effect: 'Allow', @@ -506,11 +506,11 @@ export = { const p = new PolicyDocument(); const statement1 = new PolicyStatement() - .addResource(new Token(() => 'resource').toString()) - .addAction(new Token(() => 'action').toString()); + .addResource(Lazy.stringValue({ produce: () => 'resource' })) + .addAction(Lazy.stringValue({ produce: () => 'action' })); const statement2 = new PolicyStatement() - .addResource(new Token(() => 'resource').toString()) - .addAction(new Token(() => 'action').toString()); + .addResource(Lazy.stringValue({ produce: () => 'resource' })) + .addAction(Lazy.stringValue({ produce: () => 'action' })); // WHEN p.addStatement(statement1); diff --git a/packages/@aws-cdk/aws-inspector/package-lock.json b/packages/@aws-cdk/aws-inspector/package-lock.json new file mode 100644 index 0000000000000..2507287da0488 --- /dev/null +++ b/packages/@aws-cdk/aws-inspector/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-inspector", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-iot/package-lock.json b/packages/@aws-cdk/aws-iot/package-lock.json new file mode 100644 index 0000000000000..170eb491260a8 --- /dev/null +++ b/packages/@aws-cdk/aws-iot/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-iot", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-iot1click/package-lock.json b/packages/@aws-cdk/aws-iot1click/package-lock.json new file mode 100644 index 0000000000000..cf344eac6fadc --- /dev/null +++ b/packages/@aws-cdk/aws-iot1click/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-iot1click", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-iotanalytics/package-lock.json b/packages/@aws-cdk/aws-iotanalytics/package-lock.json new file mode 100644 index 0000000000000..e929ce14a814e --- /dev/null +++ b/packages/@aws-cdk/aws-iotanalytics/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-iotanalytics", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-kinesis/package-lock.json b/packages/@aws-cdk/aws-kinesis/package-lock.json new file mode 100644 index 0000000000000..cf09f28192981 --- /dev/null +++ b/packages/@aws-cdk/aws-kinesis/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-kinesis", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-kinesisanalytics/package-lock.json b/packages/@aws-cdk/aws-kinesisanalytics/package-lock.json new file mode 100644 index 0000000000000..eed4071df37a5 --- /dev/null +++ b/packages/@aws-cdk/aws-kinesisanalytics/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-kinesisanalytics", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-kinesisfirehose/package-lock.json b/packages/@aws-cdk/aws-kinesisfirehose/package-lock.json new file mode 100644 index 0000000000000..46e43556dd97b --- /dev/null +++ b/packages/@aws-cdk/aws-kinesisfirehose/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-kinesisfirehose", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-kms/lib/alias.ts b/packages/@aws-cdk/aws-kms/lib/alias.ts index f99646ec68178..26a068caa4363 100644 --- a/packages/@aws-cdk/aws-kms/lib/alias.ts +++ b/packages/@aws-cdk/aws-kms/lib/alias.ts @@ -81,7 +81,7 @@ export class Alias extends AliasBase { constructor(scope: Construct, id: string, props: AliasProps) { super(scope, id); - if (!Token.unresolved(props.name)) { + if (!Token.isUnresolved(props.name)) { if (!props.name.startsWith(REQUIRED_ALIAS_PREFIX)) { throw new Error(`Alias must start with the prefix "${REQUIRED_ALIAS_PREFIX}": ${props.name}`); } diff --git a/packages/@aws-cdk/aws-kms/package-lock.json b/packages/@aws-cdk/aws-kms/package-lock.json new file mode 100644 index 0000000000000..8789f6bec1325 --- /dev/null +++ b/packages/@aws-cdk/aws-kms/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-kms", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package-lock.json b/packages/@aws-cdk/aws-lambda-event-sources/package-lock.json new file mode 100644 index 0000000000000..1e8866f1f17f4 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-event-sources/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-lambda-event-sources", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-lambda/lib/code.ts b/packages/@aws-cdk/aws-lambda/lib/code.ts index 0c0ddc19e3bf1..eafd8a2c5f97c 100644 --- a/packages/@aws-cdk/aws-lambda/lib/code.ts +++ b/packages/@aws-cdk/aws-lambda/lib/code.ts @@ -280,8 +280,8 @@ export class CfnParametersCode extends Code { /** @internal */ public _toJSON(_?: cdk.CfnResource): CfnFunction.CodeProperty { return { - s3Bucket: this._bucketNameParam!.stringValue, - s3Key: this._objectKeyParam!.stringValue, + s3Bucket: this._bucketNameParam!.valueAsString, + s3Key: this._objectKeyParam!.valueAsString, }; } diff --git a/packages/@aws-cdk/aws-lambda/lib/function.ts b/packages/@aws-cdk/aws-lambda/lib/function.ts index e7aa0cee86089..5151cf57eb958 100644 --- a/packages/@aws-cdk/aws-lambda/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda/lib/function.ts @@ -3,7 +3,7 @@ import ec2 = require('@aws-cdk/aws-ec2'); import iam = require('@aws-cdk/aws-iam'); import logs = require('@aws-cdk/aws-logs'); import sqs = require('@aws-cdk/aws-sqs'); -import { Construct, Fn, Stack, Token } from '@aws-cdk/cdk'; +import { Construct, Fn, Lazy, Stack } from '@aws-cdk/cdk'; import { Code } from './code'; import { IEventSource } from './event-source'; import { FunctionAttributes, FunctionBase, IFunction } from './function-base'; @@ -421,16 +421,16 @@ export class Function extends FunctionBase { throw new Error(`Environment variables are not supported in this region (${region}); consider using tags or SSM parameters instead`); } - const resource = new CfnFunction(this, 'Resource', { + const resource: CfnFunction = new CfnFunction(this, 'Resource', { functionName: props.functionName, description: props.description, - code: new Token(() => props.code._toJSON(resource)), - layers: new Token(() => this.layers.length > 0 ? this.layers.map(layer => layer.layerVersionArn) : undefined).toList(), + code: Lazy.anyValue({ produce: () => props.code._toJSON(resource) }), + layers: Lazy.listValue({ produce: () => this.layers.map(layer => layer.layerVersionArn) }, { omitEmpty: true }), handler: props.handler, timeout: props.timeout, runtime: props.runtime.name, role: this.role.roleArn, - environment: new Token(() => this.renderEnvironment()), + environment: Lazy.anyValue({ produce: () => this.renderEnvironment() }), memorySize: props.memorySize, vpcConfig: this.configureVpc(props), deadLetterConfig: this.buildDeadLetterConfig(props), @@ -440,7 +440,7 @@ export class Function extends FunctionBase { resource.node.addDependency(this.role); - this.functionName = resource.ref; + this.functionName = resource.refAsString; this.functionArn = resource.functionArn; this.handler = props.handler; this.runtime = props.runtime; diff --git a/packages/@aws-cdk/aws-lambda/lib/layers.ts b/packages/@aws-cdk/aws-lambda/lib/layers.ts index 1f474a3d4c1fe..185f4e753c270 100644 --- a/packages/@aws-cdk/aws-lambda/lib/layers.ts +++ b/packages/@aws-cdk/aws-lambda/lib/layers.ts @@ -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 { Code } from './code'; import { CfnLayerVersion, CfnLayerVersionPermission } from './lambda.generated'; import { Runtime } from './runtime'; @@ -169,9 +169,9 @@ export class LayerVersion extends LayerVersionBase { // Allow usage of the code in this context... props.code.bind(this); - const resource = new CfnLayerVersion(this, 'Resource', { + const resource: CfnLayerVersion = new CfnLayerVersion(this, 'Resource', { compatibleRuntimes: props.compatibleRuntimes && props.compatibleRuntimes.map(r => r.name), - content: new Token(() => props.code._toJSON(resource)), + content: Lazy.anyValue({ produce: () => props.code._toJSON(resource) }), description: props.description, layerName: props.name, licenseInfo: props.license, diff --git a/packages/@aws-cdk/aws-lambda/package-lock.json b/packages/@aws-cdk/aws-lambda/package-lock.json index a59fe6581d7ea..da7805774808b 100644 --- a/packages/@aws-cdk/aws-lambda/package-lock.json +++ b/packages/@aws-cdk/aws-lambda/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/aws-lambda", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts b/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts index 7bda668a1739b..f71765f5aeeb3 100644 --- a/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts +++ b/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts @@ -1,6 +1,6 @@ import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { Construct, Stack } from '@aws-cdk/cdk'; +import { Construct, Lazy, Stack } from '@aws-cdk/cdk'; import { ILogGroup } from './log-group'; import { CfnDestination } from './logs.generated'; import { ILogSubscriptionDestination, LogSubscriptionDestinationConfig } from './subscription-filter'; @@ -65,7 +65,7 @@ export class CrossAccountDestination extends cdk.Construct implements ILogSubscr super(scope, id); // In the underlying model, the name is not optional, but we make it so anyway. - const destinationName = props.destinationName || new cdk.Token(() => this.generateUniqueName()).toString(); + const destinationName = props.destinationName || Lazy.stringValue({ produce: () => this.generateUniqueName() }); this.resource = new CfnDestination(this, 'Resource', { destinationName, @@ -99,6 +99,8 @@ export class CrossAccountDestination extends cdk.Construct implements ILogSubscr * Return a stringified JSON version of the PolicyDocument */ private lazyStringifiedPolicyDocument(): string { - return new cdk.Token(() => this.policyDocument.isEmpty ? '' : Stack.of(this).toJsonString(this.policyDocument)).toString(); + return Lazy.stringValue({ produce: () => + this.policyDocument.isEmpty ? '' : Stack.of(this).toJsonString(this.policyDocument) + }); } } diff --git a/packages/@aws-cdk/aws-logs/package-lock.json b/packages/@aws-cdk/aws-logs/package-lock.json new file mode 100644 index 0000000000000..d465e7774a3a5 --- /dev/null +++ b/packages/@aws-cdk/aws-logs/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-logs", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-mediastore/package-lock.json b/packages/@aws-cdk/aws-mediastore/package-lock.json new file mode 100644 index 0000000000000..abb94051c1a06 --- /dev/null +++ b/packages/@aws-cdk/aws-mediastore/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-mediastore", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-neptune/package-lock.json b/packages/@aws-cdk/aws-neptune/package-lock.json new file mode 100644 index 0000000000000..257d26343b623 --- /dev/null +++ b/packages/@aws-cdk/aws-neptune/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-neptune", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-opsworks/package-lock.json b/packages/@aws-cdk/aws-opsworks/package-lock.json new file mode 100644 index 0000000000000..d9645089e9557 --- /dev/null +++ b/packages/@aws-cdk/aws-opsworks/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-opsworks", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-opsworkscm/package-lock.json b/packages/@aws-cdk/aws-opsworkscm/package-lock.json new file mode 100644 index 0000000000000..b77049a33d9fd --- /dev/null +++ b/packages/@aws-cdk/aws-opsworkscm/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-opsworkscm", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-pinpointemail/package-lock.json b/packages/@aws-cdk/aws-pinpointemail/package-lock.json new file mode 100644 index 0000000000000..8e3bf30c29b51 --- /dev/null +++ b/packages/@aws-cdk/aws-pinpointemail/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-pinpointemail", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-quickstarts/package-lock.json b/packages/@aws-cdk/aws-quickstarts/package-lock.json new file mode 100644 index 0000000000000..995856da05bfd --- /dev/null +++ b/packages/@aws-cdk/aws-quickstarts/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-quickstarts", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-ram/package-lock.json b/packages/@aws-cdk/aws-ram/package-lock.json new file mode 100644 index 0000000000000..cc73fd23f6de6 --- /dev/null +++ b/packages/@aws-cdk/aws-ram/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-ram", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index bc3cb557dd5b6..082a14efa92fc 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -301,7 +301,7 @@ export class DatabaseCluster extends DatabaseClusterBase { engine: props.engine.name, engineVersion: props.engineVersion, dbClusterIdentifier: props.clusterIdentifier, - dbSubnetGroupName: subnetGroup.ref, + dbSubnetGroupName: subnetGroup.refAsString, vpcSecurityGroupIds: [this.securityGroupId], port: props.port, dbClusterParameterGroupName: props.parameterGroup && props.parameterGroup.parameterGroupName, @@ -325,10 +325,10 @@ export class DatabaseCluster extends DatabaseClusterBase { cluster.options.deletionPolicy = deleteReplacePolicy; cluster.options.updateReplacePolicy = deleteReplacePolicy; - this.clusterIdentifier = cluster.ref; + this.clusterIdentifier = cluster.refAsString; // create a number token that represents the port of the cluster - const portAttribute = new Token(() => cluster.dbClusterEndpointPort).toNumber(); + const portAttribute = Token.asNumber(cluster.dbClusterEndpointPort); this.clusterEndpoint = new Endpoint(cluster.dbClusterEndpointAddress, portAttribute); this.clusterReadEndpoint = new Endpoint(cluster.dbClusterReadEndpointAddress, portAttribute); @@ -358,13 +358,13 @@ export class DatabaseCluster extends DatabaseClusterBase { // Link to cluster engine: props.engine.name, engineVersion: props.engineVersion, - dbClusterIdentifier: cluster.ref, + dbClusterIdentifier: cluster.refAsString, dbInstanceIdentifier: instanceIdentifier, // Instance properties dbInstanceClass: databaseInstanceType(props.instanceProps.instanceType), publiclyAccessible, // This is already set on the Cluster. Unclear to me whether it should be repeated or not. Better yes. - dbSubnetGroupName: subnetGroup.ref, + dbSubnetGroupName: subnetGroup.refAsString, dbParameterGroupName: props.instanceProps.parameterGroup && props.instanceProps.parameterGroup.parameterGroupName, }); @@ -375,7 +375,7 @@ export class DatabaseCluster extends DatabaseClusterBase { // things in the right order. instance.node.addDependency(internetConnected); - this.instanceIdentifiers.push(instance.ref); + this.instanceIdentifiers.push(instance.refAsString); this.instanceEndpoints.push(new Endpoint(instance.dbInstanceEndpointAddress, portAttribute)); } diff --git a/packages/@aws-cdk/aws-rds/lib/endpoint.ts b/packages/@aws-cdk/aws-rds/lib/endpoint.ts index e0855a30efa02..89f658b603236 100644 --- a/packages/@aws-cdk/aws-rds/lib/endpoint.ts +++ b/packages/@aws-cdk/aws-rds/lib/endpoint.ts @@ -25,7 +25,7 @@ export class Endpoint { this.hostname = address; this.port = port; - const portDesc = Token.isToken(port) ? '{IndirectPort}' : port; + const portDesc = Token.isUnresolved(port) ? '{IndirectPort}' : port; this.socketAddress = `${address}:${portDesc}`; } } diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index c367d9a7bd449..3ae8dd578f85e 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -744,7 +744,7 @@ export class DatabaseInstance extends DatabaseInstanceSource implements IDatabas this.dbInstanceEndpointPort = instance.dbInstanceEndpointPort; // create a number token that represents the port of the instance - const portAttribute = new Token(() => instance.dbInstanceEndpointPort).toNumber(); + const portAttribute = Token.asNumber(instance.dbInstanceEndpointPort); this.instanceEndpoint = new Endpoint(instance.dbInstanceEndpointAddress, portAttribute); const deleteReplacePolicy = props.deleteReplacePolicy || DeletionPolicy.Retain; @@ -838,7 +838,7 @@ export class DatabaseInstanceFromSnapshot extends DatabaseInstanceSource impleme this.dbInstanceEndpointPort = instance.dbInstanceEndpointPort; // create a number token that represents the port of the instance - const portAttribute = new Token(() => instance.dbInstanceEndpointPort).toNumber(); + const portAttribute = Token.asNumber(instance.dbInstanceEndpointPort); this.instanceEndpoint = new Endpoint(instance.dbInstanceEndpointAddress, portAttribute); const deleteReplacePolicy = props.deleteReplacePolicy || DeletionPolicy.Retain; @@ -915,7 +915,7 @@ export class DatabaseInstanceReadReplica extends DatabaseInstanceNew implements this.dbInstanceEndpointPort = instance.dbInstanceEndpointPort; // create a number token that represents the port of the instance - const portAttribute = new Token(() => instance.dbInstanceEndpointPort).toNumber(); + const portAttribute = Token.asNumber(instance.dbInstanceEndpointPort); this.instanceEndpoint = new Endpoint(instance.dbInstanceEndpointAddress, portAttribute); const deleteReplacePolicy = props.deleteReplacePolicy || DeletionPolicy.Retain; diff --git a/packages/@aws-cdk/aws-rds/package-lock.json b/packages/@aws-cdk/aws-rds/package-lock.json new file mode 100644 index 0000000000000..6002bc3b61beb --- /dev/null +++ b/packages/@aws-cdk/aws-rds/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-rds", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-redshift/package-lock.json b/packages/@aws-cdk/aws-redshift/package-lock.json new file mode 100644 index 0000000000000..d9e8bb63d769f --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-redshift", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-robomaker/package-lock.json b/packages/@aws-cdk/aws-robomaker/package-lock.json new file mode 100644 index 0000000000000..f111e99101866 --- /dev/null +++ b/packages/@aws-cdk/aws-robomaker/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-robomaker", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts b/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts index 22f91d6e48488..fe3bf4b13a34e 100644 --- a/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts +++ b/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts @@ -1,5 +1,5 @@ import ec2 = require('@aws-cdk/aws-ec2'); -import { Construct, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, Lazy, Resource } from '@aws-cdk/cdk'; import { HostedZoneAttributes, IHostedZone } from './hosted-zone-ref'; import { CaaAmazonRecord, ZoneDelegationRecord } from './record-set'; import { CfnHostedZone } from './route53.generated'; @@ -85,10 +85,10 @@ export class HostedZone extends Resource implements IHostedZone { name: props.zoneName + '.', hostedZoneConfig: props.comment ? { comment: props.comment } : undefined, queryLoggingConfig: props.queryLogsLogGroupArn ? { cloudWatchLogsLogGroupArn: props.queryLogsLogGroupArn } : undefined, - vpcs: new Token(() => this.vpcs.length === 0 ? undefined : this.vpcs) + vpcs: Lazy.anyValue({ produce: () => this.vpcs.length === 0 ? undefined : this.vpcs }) }); - this.hostedZoneId = resource.ref; + this.hostedZoneId = resource.refAsString; this.hostedZoneNameServers = resource.hostedZoneNameServers; this.zoneName = props.zoneName; diff --git a/packages/@aws-cdk/aws-route53/lib/record-set.ts b/packages/@aws-cdk/aws-route53/lib/record-set.ts index 4e13c8c0ba62c..1d178c6abc69d 100644 --- a/packages/@aws-cdk/aws-route53/lib/record-set.ts +++ b/packages/@aws-cdk/aws-route53/lib/record-set.ts @@ -122,7 +122,7 @@ export class RecordSet extends Resource implements IRecordSet { comment: props.comment }); - this.domainName = recordSet.ref; + this.domainName = recordSet.refAsString; } } @@ -442,9 +442,9 @@ export class ZoneDelegationRecord extends RecordSet { super(scope, id, { ...props, recordType: RecordType.NS, - target: RecordTarget.fromValues(...Token.isToken(props.nameServers) + target: RecordTarget.fromValues(...Token.isUnresolved(props.nameServers) ? props.nameServers // Can't map a string-array token! - : props.nameServers.map(ns => (Token.isToken(ns) || ns.endsWith('.')) ? ns : `${ns}.`) + : props.nameServers.map(ns => (Token.isUnresolved(ns) || ns.endsWith('.')) ? ns : `${ns}.`) ), ttl: props.ttl || 172_800 }); diff --git a/packages/@aws-cdk/aws-route53resolver/package-lock.json b/packages/@aws-cdk/aws-route53resolver/package-lock.json new file mode 100644 index 0000000000000..c0d5b7901ffd2 --- /dev/null +++ b/packages/@aws-cdk/aws-route53resolver/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-route53resolver", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-s3-deployment/package-lock.json b/packages/@aws-cdk/aws-s3-deployment/package-lock.json new file mode 100644 index 0000000000000..c60eb044e16be --- /dev/null +++ b/packages/@aws-cdk/aws-s3-deployment/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-s3-deployment", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index a29dfaefb599d..b73d8725f32e9 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -1,7 +1,8 @@ import events = require('@aws-cdk/aws-events'); import iam = require('@aws-cdk/aws-iam'); import kms = require('@aws-cdk/aws-kms'); -import { applyRemovalPolicy, Construct, IResource, PhysicalName, RemovalPolicy, Resource, ResourceIdentifiers, Stack, Token } from '@aws-cdk/cdk'; +import { applyRemovalPolicy, Construct, IResource, Lazy, PhysicalName, + RemovalPolicy, Resource, ResourceIdentifiers, Stack, Token } from '@aws-cdk/cdk'; import { EOL } from 'os'; import { BucketPolicy } from './bucket-policy'; import { IBucketNotificationDestination } from './destination'; @@ -815,16 +816,18 @@ export class Bucket extends BucketBase { }); const { bucketEncryption, encryptionKey } = this.parseEncryption(props); - this.validateBucketName(this.physicalName); + if (props.bucketName && !Token.isUnresolved(props.bucketName)) { + this.validateBucketName(props.bucketName); + } const resource = new CfnBucket(this, 'Resource', { bucketName: this.physicalName.value, bucketEncryption, versioningConfiguration: props.versioned ? { status: 'Enabled' } : undefined, - lifecycleConfiguration: new Token(() => this.parseLifecycleConfiguration()), + lifecycleConfiguration: Lazy.anyValue({ produce: () => this.parseLifecycleConfiguration() }), websiteConfiguration: this.renderWebsiteConfiguration(props), publicAccessBlockConfiguration: props.blockPublicAccess, - metricsConfigurations: new Token(() => this.parseMetricConfiguration()) + metricsConfigurations: Lazy.anyValue({ produce: () => this.parseMetricConfiguration() }) }); applyRemovalPolicy(resource, props.removalPolicy !== undefined ? props.removalPolicy : RemovalPolicy.Orphan); @@ -939,7 +942,7 @@ export class Bucket extends BucketBase { private validateBucketName(physicalName: PhysicalName): void { const bucketName = physicalName.value; - if (!bucketName || Token.isToken(bucketName)) { + if (!bucketName || Token.isUnresolved(bucketName)) { // the name is a late-bound value, not a defined string, // so skip validation return; diff --git a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts index 634e1aef0065b..733df4e6f0956 100644 --- a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts +++ b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts @@ -107,7 +107,7 @@ export class BucketNotifications extends cdk.Construct { properties: { ServiceToken: handlerArn, BucketName: this.bucket.bucketName, - NotificationConfiguration: new cdk.Token(() => this.renderNotificationConfiguration()) + NotificationConfiguration: cdk.Lazy.anyValue({ produce: () => this.renderNotificationConfiguration() }) } }); } diff --git a/packages/@aws-cdk/aws-s3/package-lock.json b/packages/@aws-cdk/aws-s3/package-lock.json new file mode 100644 index 0000000000000..b693a6f0ddaba --- /dev/null +++ b/packages/@aws-cdk/aws-s3/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-s3", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-s3/test/test.bucket.ts b/packages/@aws-cdk/aws-s3/test/test.bucket.ts index aebaa00ed53e7..1972c9e617174 100644 --- a/packages/@aws-cdk/aws-s3/test/test.bucket.ts +++ b/packages/@aws-cdk/aws-s3/test/test.bucket.ts @@ -32,7 +32,7 @@ export = { 'CFN properties are type-validated during resolution'(test: Test) { const stack = new cdk.Stack(); new s3.Bucket(stack, 'MyBucket', { - bucketName: cdk.PhysicalName.of(new cdk.Token(() => 5).toString()) // Oh no + bucketName: cdk.PhysicalName.of(cdk.Token.asString(5)) // Oh no }); test.throws(() => { @@ -106,7 +106,7 @@ export = { const stack = new cdk.Stack(); test.doesNotThrow(() => new s3.Bucket(stack, 'MyBucket', { - bucketName: cdk.PhysicalName.of(new cdk.Token(() => '_BUCKET').toString()), + bucketName: cdk.PhysicalName.of(cdk.Lazy.stringValue({ produce: () => '_BUCKET' })), })); test.done(); diff --git a/packages/@aws-cdk/aws-s3/test/test.util.ts b/packages/@aws-cdk/aws-s3/test/test.util.ts index 6ece7e06b0058..416c0c9ac8ae2 100644 --- a/packages/@aws-cdk/aws-s3/test/test.util.ts +++ b/packages/@aws-cdk/aws-s3/test/test.util.ts @@ -49,7 +49,7 @@ export = { 'can parse bucket name even if it contains a token'(test: Test) { const stack = new cdk.Stack(); - const bucketArn = `arn:aws:s3:::${new cdk.Token({ Ref: 'my-bucket' })}`; + const bucketArn = `arn:aws:s3:::${cdk.Token.asString({ Ref: 'my-bucket' })}`; test.deepEqual(stack.resolve(parseBucketName(stack, { bucketArn })), { "Fn::Select": [ diff --git a/packages/@aws-cdk/aws-sagemaker/package-lock.json b/packages/@aws-cdk/aws-sagemaker/package-lock.json new file mode 100644 index 0000000000000..5c96562ef2fc5 --- /dev/null +++ b/packages/@aws-cdk/aws-sagemaker/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-sagemaker", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-sam/package-lock.json b/packages/@aws-cdk/aws-sam/package-lock.json new file mode 100644 index 0000000000000..5b4ff54ca1ea7 --- /dev/null +++ b/packages/@aws-cdk/aws-sam/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-sam", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-sdb/package-lock.json b/packages/@aws-cdk/aws-sdb/package-lock.json new file mode 100644 index 0000000000000..d845f50e09e24 --- /dev/null +++ b/packages/@aws-cdk/aws-sdb/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-sdb", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-secretsmanager/package-lock.json b/packages/@aws-cdk/aws-secretsmanager/package-lock.json new file mode 100644 index 0000000000000..dad8b31715f6f --- /dev/null +++ b/packages/@aws-cdk/aws-secretsmanager/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-secretsmanager", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-servicecatalog/package-lock.json b/packages/@aws-cdk/aws-servicecatalog/package-lock.json new file mode 100644 index 0000000000000..31fb378bc4b3a --- /dev/null +++ b/packages/@aws-cdk/aws-servicecatalog/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-servicecatalog", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-servicediscovery/package-lock.json b/packages/@aws-cdk/aws-servicediscovery/package-lock.json new file mode 100644 index 0000000000000..7e53f0fed2ac6 --- /dev/null +++ b/packages/@aws-cdk/aws-servicediscovery/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-servicediscovery", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-ses/lib/receipt-rule.ts b/packages/@aws-cdk/aws-ses/lib/receipt-rule.ts index 13ce9d4d48099..7cff06f11a752 100644 --- a/packages/@aws-cdk/aws-ses/lib/receipt-rule.ts +++ b/packages/@aws-cdk/aws-ses/lib/receipt-rule.ts @@ -1,5 +1,5 @@ import lambda = require('@aws-cdk/aws-lambda'); -import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk'; +import { Construct, IResource, Lazy, Resource } from '@aws-cdk/cdk'; import { IReceiptRuleAction, LambdaInvocationType, ReceiptRuleActionProps, ReceiptRuleLambdaAction } from './receipt-rule-action'; import { IReceiptRuleSet } from './receipt-rule-set'; import { CfnReceiptRule } from './ses.generated'; @@ -118,7 +118,7 @@ export class ReceiptRule extends Resource implements IReceiptRule { const resource = new CfnReceiptRule(this, 'Resource', { after: props.after ? props.after.receiptRuleName : undefined, rule: { - actions: new Token(() => this.getRenderedActions()), + actions: Lazy.anyValue({ produce: () => this.getRenderedActions() }), enabled: props.enabled === undefined ? true : props.enabled, name: props.name, recipients: props.recipients, diff --git a/packages/@aws-cdk/aws-ses/package-lock.json b/packages/@aws-cdk/aws-ses/package-lock.json new file mode 100644 index 0000000000000..18b762fbb6a32 --- /dev/null +++ b/packages/@aws-cdk/aws-ses/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-ses", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-sns/lib/topic.ts b/packages/@aws-cdk/aws-sns/lib/topic.ts index 3184167cc0cc3..2821191fa5c7f 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic.ts @@ -53,7 +53,7 @@ export class Topic extends TopicBase { topicName: props.topicName }); - this.topicArn = resource.ref; + this.topicArn = resource.refAsString; this.topicName = resource.topicName; } } diff --git a/packages/@aws-cdk/aws-sqs/lib/queue.ts b/packages/@aws-cdk/aws-sqs/lib/queue.ts index f34d62d002a16..ad1a9bec47a12 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue.ts @@ -257,7 +257,7 @@ export class Queue extends QueueBase { this.encryptionMasterKey = encryptionMasterKey; this.queueArn = queue.queueArn; this.queueName = queue.queueName; - this.queueUrl = queue.ref; + this.queueUrl = queue.refAsString; function _determineEncryptionProps(this: Queue): { encryptionProps: EncryptionProps, encryptionMasterKey?: kms.IKey } { let encryption = props.encryption || QueueEncryption.Unencrypted; diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter-store-string.ts b/packages/@aws-cdk/aws-ssm/lib/parameter-store-string.ts index b47940dfc6d86..0a17bba387c4f 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter-store-string.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter-store-string.ts @@ -45,7 +45,7 @@ export class ParameterStoreString extends cdk.Construct { type: 'AWS::SSM::Parameter::Value', default: props.parameterName }); - this.stringValue = param.stringValue; + this.stringValue = param.valueAsString; } else { // Use a dynamic reference const dynRef = new cdk.CfnDynamicReference(cdk.CfnDynamicReferenceService.Ssm, `${props.parameterName}:${props.version}`); diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index 27b4d44aaffa6..69d5a263e6b83 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -217,11 +217,11 @@ export class StringListParameter extends ParameterBase implements IStringListPar constructor(scope: Construct, id: string, props: StringListParameterProps) { super(scope, id); - if (props.stringListValue.find(str => !Token.isToken(str) && str.indexOf(',') !== -1)) { + if (props.stringListValue.find(str => !Token.isUnresolved(str) && str.indexOf(',') !== -1)) { throw new Error('Values of a StringList SSM Parameter cannot contain the \',\' character. Use a string parameter instead.'); } - if (props.allowedPattern && !Token.isToken(props.stringListValue)) { + if (props.allowedPattern && !Token.isUnresolved(props.stringListValue)) { props.stringListValue.forEach(str => _assertValidValue(str, props.allowedPattern!)); } @@ -249,7 +249,7 @@ export class StringListParameter extends ParameterBase implements IStringListPar * ``cdk.unresolved``). */ function _assertValidValue(value: string, allowedPattern: string): void { - if (Token.isToken(value) || Token.isToken(allowedPattern)) { + if (Token.isUnresolved(value) || Token.isUnresolved(allowedPattern)) { // Unable to perform validations against unresolved tokens return; } diff --git a/packages/@aws-cdk/aws-ssm/package-lock.json b/packages/@aws-cdk/aws-ssm/package-lock.json new file mode 100644 index 0000000000000..02904c3ccff9f --- /dev/null +++ b/packages/@aws-cdk/aws-ssm/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-ssm", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts index 31c48ca238877..71d9af9245c0a 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts @@ -44,7 +44,10 @@ export = { // THEN test.doesNotThrow(() => { - new ssm.StringParameter(stack, 'Parameter', { allowedPattern: '^Bar$', stringValue: new cdk.Token(() => 'Foo!').toString() }); + new ssm.StringParameter(stack, 'Parameter', { + allowedPattern: '^Bar$', + stringValue: cdk.Lazy.stringValue({ produce: () => 'Foo!' }), + }); }); test.done(); }, @@ -99,7 +102,7 @@ export = { // THEN test.doesNotThrow(() => new ssm.StringListParameter(stack, 'Parameter', { allowedPattern: '^(Foo|Bar)$', - stringListValue: ['Foo', new cdk.Token(() => 'Baz!').toString()] + stringListValue: ['Foo', cdk.Lazy.stringValue({ produce: () => 'Baz!' })], })); test.done(); }, diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/run-ecs-task-base.ts b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/run-ecs-task-base.ts index 9702081f36e0b..c05cabd30f5bf 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/lib/run-ecs-task-base.ts +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/lib/run-ecs-task-base.ts @@ -64,7 +64,7 @@ export class EcsRunTaskBase implements ec2.IConnectable, sfn.IStepFunctionsTask for (const override of this.props.containerOverrides || []) { const name = override.containerName; - if (!cdk.Token.isToken(name)) { + if (!cdk.Token.isUnresolved(name)) { const cont = this.props.taskDefinition.node.tryFindChild(name); if (!cont) { throw new Error(`Overrides mention container with name '${name}', but no such container in task definition`); @@ -112,7 +112,7 @@ export class EcsRunTaskBase implements ec2.IConnectable, sfn.IStepFunctionsTask AwsvpcConfiguration: { AssignPublicIp: assignPublicIp !== undefined ? (assignPublicIp ? 'ENABLED' : 'DISABLED') : undefined, Subnets: vpc.selectSubnets(subnetSelection).subnetIds, - SecurityGroups: new cdk.Token(() => [this.securityGroup!.securityGroupId]), + SecurityGroups: cdk.Lazy.listValue({ produce: () => [this.securityGroup!.securityGroupId] }), } }; } @@ -130,7 +130,7 @@ export class EcsRunTaskBase implements ec2.IConnectable, sfn.IStepFunctionsTask .addAllResources(), new iam.PolicyStatement() .addAction('iam:PassRole') - .addResources(...new cdk.Token(() => this.taskExecutionRoles().map(r => r.roleArn)).toList()) + .addResources(...cdk.Lazy.listValue({ produce: () => this.taskExecutionRoles().map(r => r.roleArn) })) ]; if (this.sync) { diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts b/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts index 4fd4e2a693e05..c6d1890e2512f 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/fields.ts @@ -1,3 +1,4 @@ +import { Token } from "@aws-cdk/cdk"; import { findReferencedPaths, JsonPathToken, renderObject } from "./json-path"; /** @@ -17,7 +18,7 @@ export class Data { */ public static listAt(path: string): string[] { validateDataPath(path); - return new JsonPathToken(path).toList(); + return Token.asList(new JsonPathToken(path)); } /** @@ -25,7 +26,7 @@ export class Data { */ public static numberAt(path: string): number { validateDataPath(path); - return new JsonPathToken(path).toNumber(); + return Token.asNumber(new JsonPathToken(path)); } /** @@ -61,7 +62,7 @@ export class Context { */ public static numberAt(path: string): number { validateContextPath(path); - return new JsonPathToken(path).toNumber(); + return Token.asNumber(new JsonPathToken(path)); } /** diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts b/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts index eb80f01684e3c..51bf01e370c5f 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/json-path.ts @@ -1,16 +1,30 @@ -import { Token, TokenMap } from '@aws-cdk/cdk'; +import { IResolvable, IResolveContext, Token, Tokenization } from '@aws-cdk/cdk'; const JSON_PATH_TOKEN_SYMBOL = Symbol.for('@aws-cdk/aws-stepfunctions.JsonPathToken'); -export class JsonPathToken extends Token { +export class JsonPathToken implements IResolvable { public static isJsonPathToken(x: any): x is JsonPathToken { return (x as any)[JSON_PATH_TOKEN_SYMBOL] === true; } + public displayHint: string; + constructor(public readonly path: string) { - super(() => path, `field${path}`); // Make function to prevent eager evaluation in superclass + this.displayHint = path.replace(/^[^a-zA-Z]+/, ''); Object.defineProperty(this, JSON_PATH_TOKEN_SYMBOL, { value: true }); } + + public resolve(_ctx: IResolveContext): any { + return this.path; + } + + public toString() { + return Token.asString(this, { displayHint: this.displayHint }); + } + + public toJSON() { + return ``; + } } /** @@ -161,7 +175,7 @@ function renderNumber(key: string, value: number): {[key: string]: number | stri * Otherwise return undefined. */ function jsonPathString(x: string): string | undefined { - const fragments = TokenMap.instance().splitString(x); + const fragments = Tokenization.reverseString(x); const jsonPathTokens = fragments.tokens.filter(JsonPathToken.isJsonPathToken); if (jsonPathTokens.length > 0 && fragments.length > 1) { @@ -179,7 +193,7 @@ function jsonPathString(x: string): string | undefined { * Otherwise return undefined. */ function jsonPathStringList(x: string[]): string | undefined { - return pathFromToken(TokenMap.instance().lookupList(x)); + return pathFromToken(Tokenization.reverseList(x)); } /** @@ -188,9 +202,9 @@ function jsonPathStringList(x: string[]): string | undefined { * Otherwise return undefined. */ function jsonPathNumber(x: number): string | undefined { - return pathFromToken(TokenMap.instance().lookupNumberToken(x)); + return pathFromToken(Tokenization.reverseNumber(x)); } -function pathFromToken(token: Token | undefined) { +function pathFromToken(token: IResolvable | undefined) { return token && (JsonPathToken.isJsonPathToken(token) ? token.path : undefined); } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-stepfunctions/package-lock.json b/packages/@aws-cdk/aws-stepfunctions/package-lock.json new file mode 100644 index 0000000000000..5c4116790c45a --- /dev/null +++ b/packages/@aws-cdk/aws-stepfunctions/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-stepfunctions", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-transfer/package-lock.json b/packages/@aws-cdk/aws-transfer/package-lock.json new file mode 100644 index 0000000000000..4b129490f012d --- /dev/null +++ b/packages/@aws-cdk/aws-transfer/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-transfer", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-waf/package-lock.json b/packages/@aws-cdk/aws-waf/package-lock.json new file mode 100644 index 0000000000000..40ed347c892e1 --- /dev/null +++ b/packages/@aws-cdk/aws-waf/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-waf", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-wafregional/package-lock.json b/packages/@aws-cdk/aws-wafregional/package-lock.json new file mode 100644 index 0000000000000..b8e72ca77c2b1 --- /dev/null +++ b/packages/@aws-cdk/aws-wafregional/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-wafregional", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/aws-workspaces/package-lock.json b/packages/@aws-cdk/aws-workspaces/package-lock.json new file mode 100644 index 0000000000000..445a87595d26c --- /dev/null +++ b/packages/@aws-cdk/aws-workspaces/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/aws-workspaces", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/@aws-cdk/cdk/lib/arn.ts b/packages/@aws-cdk/cdk/lib/arn.ts index 338c35fd894b8..51761d8f007d3 100644 --- a/packages/@aws-cdk/cdk/lib/arn.ts +++ b/packages/@aws-cdk/cdk/lib/arn.ts @@ -78,7 +78,7 @@ export function arnFromComponents(components: ArnComponents, stack: Stack): stri * components of the ARN. */ export function parseArn(arn: string, sepIfToken: string = '/', hasName: boolean = true): ArnComponents { - if (Token.isToken(arn)) { + if (Token.isUnresolved(arn)) { return parseToken(arn, sepIfToken, hasName); } diff --git a/packages/@aws-cdk/cdk/lib/cfn-condition.ts b/packages/@aws-cdk/cdk/lib/cfn-condition.ts index 4b97b48467f61..72029793ae5af 100644 --- a/packages/@aws-cdk/cdk/lib/cfn-condition.ts +++ b/packages/@aws-cdk/cdk/lib/cfn-condition.ts @@ -1,6 +1,6 @@ import { CfnRefElement } from './cfn-element'; import { Construct } from './construct'; -import { IResolveContext } from './token'; +import { IResolvable, IResolveContext } from './resolvable'; export interface CfnConditionProps { /** @@ -15,7 +15,9 @@ export interface CfnConditionProps { * Represents a CloudFormation condition, for resources which must be conditionally created and * the determination must be made at deploy time. */ -export class CfnCondition extends CfnRefElement implements ICfnConditionExpression { +export class CfnCondition extends CfnRefElement implements ICfnConditionExpression, IResolvable { + public readonly displayHint: string | undefined; + /** * The condition statement. */ @@ -27,6 +29,7 @@ export class CfnCondition extends CfnRefElement implements ICfnConditionExpressi */ constructor(scope: Construct, id: string, props?: CfnConditionProps) { super(scope, id); + this.displayHint = `Cond${id}`; this.expression = props && props.expression; } diff --git a/packages/@aws-cdk/cdk/lib/cfn-dynamic-reference.ts b/packages/@aws-cdk/cdk/lib/cfn-dynamic-reference.ts index 4f3c18495916d..f545f77aa62eb 100644 --- a/packages/@aws-cdk/cdk/lib/cfn-dynamic-reference.ts +++ b/packages/@aws-cdk/cdk/lib/cfn-dynamic-reference.ts @@ -1,4 +1,4 @@ -import { Token } from "./token"; +import { Intrinsic } from "./private/intrinsic"; /** * Properties for a Dynamic Reference @@ -23,9 +23,9 @@ export interface DynamicReferenceProps { * * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html */ -export class CfnDynamicReference extends Token { +export class CfnDynamicReference extends Intrinsic { constructor(service: CfnDynamicReferenceService, key: string) { - super(() => '{{resolve:' + service + ':' + key + '}}'); + super('{{resolve:' + service + ':' + key + '}}'); } } diff --git a/packages/@aws-cdk/cdk/lib/cfn-element.ts b/packages/@aws-cdk/cdk/lib/cfn-element.ts index e4943070963a2..e94f92a78a00f 100644 --- a/packages/@aws-cdk/cdk/lib/cfn-element.ts +++ b/packages/@aws-cdk/cdk/lib/cfn-element.ts @@ -1,5 +1,7 @@ import cxapi = require('@aws-cdk/cx-api'); import { Construct } from "./construct"; +import { Lazy } from "./lazy"; +import { Token } from './token'; const CFN_ELEMENT_SYMBOL = Symbol.for('@aws-cdk/cdk.CfnElement'); @@ -50,11 +52,13 @@ export abstract class CfnElement extends Construct { Object.defineProperty(this, CFN_ELEMENT_SYMBOL, { value: true }); - this.node.addMetadata(cxapi.LOGICAL_ID_METADATA_KEY, new (require("./token").Token)(() => this.logicalId), this.constructor); - this.stack = Stack.of(this); this._logicalId = this.stack.logicalIds.getLogicalId(this); - this.logicalId = new Token(() => this._logicalId, `${notTooLong(this.node.path)}.LogicalID`).toString(); + this.logicalId = Lazy.stringValue({ produce: () => this._logicalId }, { + displayHint: `${notTooLong(this.node.path)}.LogicalID` + }); + + this.node.addMetadata(cxapi.LOGICAL_ID_METADATA_KEY, this.logicalId, this.constructor); } /** @@ -130,6 +134,13 @@ export abstract class CfnElement extends Construct { if (e.type !== 'CfnSynthesisError') { throw e; } } } + + /** + * Return a token that will CloudFormation { Ref } this stack element + */ + protected get ref(): IResolvable { + return CfnReference.for(this, 'Ref'); + } } /** @@ -144,17 +155,17 @@ export abstract class CfnElement extends Construct { */ export abstract class CfnRefElement extends CfnElement { /** - * Returns a token to a CloudFormation { Ref } that references this entity based on it's logical ID. + * Return a token that will CloudFormation { Ref } this stack element */ - public get ref(): string { - return this.referenceToken.toString(); + public get ref(): IResolvable { + return super.ref; } /** - * Return a token that will CloudFormation { Ref } this stack element + * Return a string that will CloudFormation { Ref } this stack element */ - public get referenceToken(): Token { - return CfnReference.for(this, 'Ref'); + public get refAsString(): string { + return Token.asString(this.ref); } } @@ -163,7 +174,7 @@ function notTooLong(x: string) { return x.substr(0, 47) + '...' + x.substr(x.length - 47); } -import { CfnReference } from "./cfn-reference"; -import { findTokens } from "./resolve"; +import { CfnReference } from "./private/cfn-reference"; +import { findTokens } from "./private/resolve"; +import { IResolvable } from "./resolvable"; import { Stack } from './stack'; -import { Token } from './token'; diff --git a/packages/@aws-cdk/cdk/lib/cfn-mapping.ts b/packages/@aws-cdk/cdk/lib/cfn-mapping.ts index a7e63805ac463..d02a435bc3024 100644 --- a/packages/@aws-cdk/cdk/lib/cfn-mapping.ts +++ b/packages/@aws-cdk/cdk/lib/cfn-mapping.ts @@ -44,12 +44,12 @@ export class CfnMapping extends CfnRefElement { */ public findInMap(key1: string, key2: string): string { // opportunistically check that the key exists (if the key does not contain tokens) - if (!Token.isToken(key1) && !(key1 in this.mapping)) { + if (!Token.isUnresolved(key1) && !(key1 in this.mapping)) { throw new Error(`Mapping doesn't contain top-level key '${key1}'`); } // opportunistically check that the second key exists (if the key does not contain tokens) - if (!Token.isToken(key1) && !Token.isToken(key2) && !(key2 in this.mapping[key1])) { + if (!Token.isUnresolved(key1) && !Token.isUnresolved(key2) && !(key2 in this.mapping[key1])) { throw new Error(`Mapping doesn't contain second-level key '${key2}'`); } diff --git a/packages/@aws-cdk/cdk/lib/cfn-output.ts b/packages/@aws-cdk/cdk/lib/cfn-output.ts index 66f538e73a8ef..8223bcb986ee7 100644 --- a/packages/@aws-cdk/cdk/lib/cfn-output.ts +++ b/packages/@aws-cdk/cdk/lib/cfn-output.ts @@ -135,10 +135,6 @@ export class CfnOutput extends CfnElement { }; } - public get ref(): string { - throw new Error('Outputs cannot be referenced'); - } - /** * Allocate an export name for this `CfnOutput` if not already done. */ diff --git a/packages/@aws-cdk/cdk/lib/cfn-parameter.ts b/packages/@aws-cdk/cdk/lib/cfn-parameter.ts index cab3ccbc7eb87..d2762c9f17a89 100644 --- a/packages/@aws-cdk/cdk/lib/cfn-parameter.ts +++ b/packages/@aws-cdk/cdk/lib/cfn-parameter.ts @@ -1,12 +1,15 @@ -import { CfnRefElement } from './cfn-element'; +import { CfnElement } from './cfn-element'; import { Construct } from './construct'; +import { IResolvable, IResolveContext } from './resolvable'; import { Token } from './token'; export interface CfnParameterProps { /** * The data type for the parameter (DataType). + * + * @default String */ - readonly type: string; + readonly type?: string; /** * A value of the appropriate type for the template to use if no value is specified @@ -90,27 +93,16 @@ export interface CfnParameterProps { * Parameters enable you to input custom values to your template each time you create or * update a stack. */ -export class CfnParameter extends CfnRefElement { - /** - * A token that represents the actual value of this parameter. - */ - public value: Token; - - /** - * The parameter value token represented as a string. - */ - public stringValue: string; - - /** - * The parameter value token represented as a string array. - */ - public stringListValue: string[]; +export class CfnParameter extends CfnElement implements IResolvable { + public readonly displayHint: string | undefined; /** * Indicates if this parameter has "NoEcho" set. */ public readonly noEcho: boolean; + private readonly type: string; + private properties: CfnParameterProps; /** @@ -121,15 +113,51 @@ export class CfnParameter extends CfnRefElement { * @param scope The parent construct. * @param props The parameter properties. */ - constructor(scope: Construct, id: string, props: CfnParameterProps) { + constructor(scope: Construct, id: string, props: CfnParameterProps = {}) { super(scope, id); + this.type = props.type || 'String'; + this.displayHint = `Param${id}`; this.properties = props; - this.value = this.referenceToken; - this.stringValue = this.value.toString(); - this.stringListValue = this.value.toList(); this.noEcho = props.noEcho || false; } + /** + * The parameter value as a Token + */ + public get value(): IResolvable { + return super.ref; + } + + /** + * The parameter value, if it represents a string. + */ + public get valueAsString(): string { + if (!isStringType(this.type)) { + throw new Error(`Parameter type (${this.type}) is not a string type`); + } + return Token.asString(this.ref); + } + + /** + * The parameter value, if it represents a string list. + */ + public get valueAsList(): string[] { + if (!isListType(this.type)) { + throw new Error(`Parameter type (${this.type}) is not a string list type`); + } + return Token.asList(this.ref); + } + + /** + * The parameter value, if it represents a string list. + */ + public get valueAsNumber(): number { + if (!isNumberType(this.type)) { + throw new Error(`Parameter type (${this.type}) is not a number type`); + } + return Token.asNumber(this.ref); + } + /** * @internal */ @@ -137,7 +165,7 @@ export class CfnParameter extends CfnRefElement { return { Parameters: { [this.logicalId]: { - Type: this.properties.type, + Type: this.type, Default: this.properties.default, AllowedPattern: this.properties.allowedPattern, AllowedValues: this.properties.allowedValues, @@ -153,11 +181,28 @@ export class CfnParameter extends CfnRefElement { }; } - /** - * Allows using parameters as tokens without the need to dereference them. - * This implicitly implements Token, until we make it an interface. - */ - public resolve(): any { - return this.value; + public resolve(_context: IResolveContext): any { + return this.ref; } } + +/** + * Whether the given parameter type looks like a list type + */ +function isListType(type: string) { + return type.indexOf('List<') >= 0 || type.indexOf('CommaDelimitedList') >= 0; +} + +/** + * Whether the given parameter type looks like a number type + */ +function isNumberType(type: string) { + return type === 'Number'; +} + +/** + * Whether the given parameter type looks like a string type + */ +function isStringType(type: string) { + return !isListType(type) && !isNumberType(type); +} diff --git a/packages/@aws-cdk/cdk/lib/cfn-resource.ts b/packages/@aws-cdk/cdk/lib/cfn-resource.ts index c8a8fb292dafd..38317256cf8f3 100644 --- a/packages/@aws-cdk/cdk/lib/cfn-resource.ts +++ b/packages/@aws-cdk/cdk/lib/cfn-resource.ts @@ -1,13 +1,14 @@ import cxapi = require('@aws-cdk/cx-api'); import { CfnCondition } from './cfn-condition'; -import { Construct, IConstruct } from './construct'; -import { CreationPolicy, DeletionPolicy, UpdatePolicy } from './resource-policy'; -import { capitalizePropertyNames, ignoreEmpty, PostResolveToken } from './util'; // import required to be here, otherwise causes a cycle when running the generated JavaScript // tslint:disable-next-line:ordered-imports import { CfnRefElement } from './cfn-element'; -import { CfnReference } from './cfn-reference'; +import { Construct, IConstruct } from './construct'; +import { CfnReference } from './private/cfn-reference'; +import { IResolvable } from './resolvable'; +import { CreationPolicy, DeletionPolicy, UpdatePolicy } from './resource-policy'; import { TagManager } from './tag-manager'; +import { capitalizePropertyNames, ignoreEmpty, PostResolveToken } from './util'; export interface CfnResourceProps { /** @@ -121,7 +122,7 @@ export class CfnResource extends CfnRefElement { * in case there is no generated attribute. * @param attributeName The name of the attribute. */ - public getAtt(attributeName: string) { + public getAtt(attributeName: string): IResolvable { return CfnReference.for(this, attributeName); } diff --git a/packages/@aws-cdk/cdk/lib/cloudformation-lang.ts b/packages/@aws-cdk/cdk/lib/cloudformation-lang.ts index c505b454a39d2..cb07b064c594a 100644 --- a/packages/@aws-cdk/cdk/lib/cloudformation-lang.ts +++ b/packages/@aws-cdk/cdk/lib/cloudformation-lang.ts @@ -1,7 +1,9 @@ -import { isIntrinsic, minimalCloudFormationJoin } from "./instrinsics"; -import { DefaultTokenResolver, IFragmentConcatenator, resolve } from "./resolve"; +import { Lazy } from "./lazy"; +import { Intrinsic } from "./private/intrinsic"; +import { resolve } from "./private/resolve"; +import { DefaultTokenResolver, IFragmentConcatenator, IResolvable, IResolveContext } from "./resolvable"; import { TokenizedStringFragments } from "./string-fragments"; -import { IResolveContext, Token } from "./token"; +import { Token } from "./token"; /** * Routines that know how to do operations at the CloudFormation document language level @@ -43,7 +45,7 @@ export class CloudFormationLang { super(CLOUDFORMATION_CONCAT); } - public resolveToken(t: Token, context: IResolveContext) { + public resolveToken(t: IResolvable, context: IResolveContext) { return wrap(super.resolveToken(t, context)); } public resolveString(fragments: TokenizedStringFragments, context: IResolveContext) { @@ -55,15 +57,15 @@ export class CloudFormationLang { } // We need a ResolveContext to get started so return a Token - return new Token((ctx: IResolveContext) => { - return JSON.stringify(resolve(obj, { + return Lazy.stringValue({ produce: (ctx: IResolveContext) => + JSON.stringify(resolve(obj, { scope: ctx.scope, resolver: new IntrinsincWrapper() - })); - }).toString(); + })) + }); function wrap(value: any): any { - return isIntrinsic(value) ? new IntrinsicToken(() => deepQuoteStringsForJSON(value)) : value; + return isIntrinsic(value) ? new JsonToken(deepQuoteStringsForJSON(value)) : value; } } @@ -92,7 +94,7 @@ export class CloudFormationLang { /** * Token that also stringifies in the toJSON() operation. */ -class IntrinsicToken extends Token { +class JsonToken extends Intrinsic { /** * Special handler that gets called when JSON.stringify() is used. */ @@ -134,4 +136,54 @@ const CLOUDFORMATION_CONCAT: IFragmentConcatenator = { /** * Default Token resolver for CloudFormation templates */ -export const CLOUDFORMATION_TOKEN_RESOLVER = new DefaultTokenResolver(CLOUDFORMATION_CONCAT); \ No newline at end of file +export const CLOUDFORMATION_TOKEN_RESOLVER = new DefaultTokenResolver(CLOUDFORMATION_CONCAT); + +/** + * Do an intelligent CloudFormation join on the given values, producing a minimal expression + */ +export function minimalCloudFormationJoin(delimiter: string, values: any[]): any[] { + let i = 0; + while (i < values.length) { + const el = values[i]; + if (isSplicableFnJoinIntrinsic(el)) { + values.splice(i, 1, ...el['Fn::Join'][1]); + } else if (i > 0 && isPlainString(values[i - 1]) && isPlainString(values[i])) { + values[i - 1] += delimiter + values[i]; + values.splice(i, 1); + } else { + i += 1; + } + } + + return values; + + function isPlainString(obj: any): boolean { + return typeof obj === 'string' && !Token.isUnresolved(obj); + } + + function isSplicableFnJoinIntrinsic(obj: any): boolean { + return isIntrinsic(obj) + && Object.keys(obj)[0] === 'Fn::Join' + && obj['Fn::Join'][0] === delimiter; + } +} + +/** + * Return whether the given value represents a CloudFormation intrinsic + */ +function isIntrinsic(x: any) { + if (Array.isArray(x) || x === null || typeof x !== 'object') { return false; } + + const keys = Object.keys(x); + if (keys.length !== 1) { return false; } + + return keys[0] === 'Ref' || isNameOfCloudFormationIntrinsic(keys[0]); +} + +export function isNameOfCloudFormationIntrinsic(name: string): boolean { + if (!name.startsWith('Fn::')) { + return false; + } + // these are 'fake' intrinsics, only usable inside the parameter overrides of a CFN CodePipeline Action + return name !== 'Fn::GetArtifactAtt' && name !== 'Fn::GetParam'; +} diff --git a/packages/@aws-cdk/cdk/lib/construct.ts b/packages/@aws-cdk/cdk/lib/construct.ts index c0bbda8f82340..af2e2dec8997a 100644 --- a/packages/@aws-cdk/cdk/lib/construct.ts +++ b/packages/@aws-cdk/cdk/lib/construct.ts @@ -1,7 +1,8 @@ import cxapi = require('@aws-cdk/cx-api'); import { IAspect } from './aspect'; import { DependableTrait, IDependable } from './dependency'; -import { createStackTrace } from './stack-trace'; +import { createStackTrace } from './private/stack-trace'; +import { IResolvable } from './resolvable'; import { Token } from './token'; import { makeUniqueId } from './uniqueid'; @@ -141,7 +142,7 @@ export class ConstructNode { // escape any path separators so they don't wreck havoc this.id = this._escapePathSeparator(this.id); - if (Token.isToken(id)) { + if (Token.isUnresolved(id)) { throw new Error(`Cannot use tokens in construct ID: ${id}`); } } @@ -404,7 +405,7 @@ export class ConstructNode { /** * Record a reference originating from this construct node */ - public addReference(...refs: Token[]) { + public addReference(...refs: IResolvable[]) { for (const ref of refs) { if (Reference.isReference(ref)) { this._references.add(ref); diff --git a/packages/@aws-cdk/cdk/lib/fn.ts b/packages/@aws-cdk/cdk/lib/fn.ts index 1c4ab8f823350..db9e524340617 100644 --- a/packages/@aws-cdk/cdk/lib/fn.ts +++ b/packages/@aws-cdk/cdk/lib/fn.ts @@ -1,6 +1,8 @@ import { ICfnConditionExpression } from './cfn-condition'; -import { minimalCloudFormationJoin } from './instrinsics'; -import { IResolveContext, Token } from './token'; +import { minimalCloudFormationJoin } from './cloudformation-lang'; +import { Intrinsic } from './private/intrinsic'; +import { IResolvable, IResolveContext } from './resolvable'; +import { Token } from './token'; // tslint:disable:max-line-length @@ -53,11 +55,11 @@ export class Fn { public static split(delimiter: string, source: string): string[] { // short-circut if source is not a token - if (!Token.isToken(source)) { + if (!Token.isUnresolved(source)) { return source.split(delimiter); } - return new FnSplit(delimiter, source).toList(); + return Token.asList(new FnSplit(delimiter, source)); } /** @@ -67,7 +69,7 @@ export class Fn { * @returns a token represented as a string */ public static select(index: number, array: string[]): string { - if (!Token.isToken(array)) { + if (!Token.isUnresolved(array)) { return array[index]; } @@ -113,7 +115,7 @@ export class Fn { * @returns a token represented as a string */ public static cidr(ipBlock: string, count: number, sizeMask?: string): string[] { - return new FnCidr(ipBlock, count, sizeMask).toList(); + return Token.asList(new FnCidr(ipBlock, count, sizeMask)); } /** @@ -130,7 +132,7 @@ export class Fn { * @returns a token represented as a string array */ public static getAZs(region?: string): string[] { - return new FnGetAZs(region).toList(); + return Token.asList(new FnGetAZs(region)); } /** @@ -264,7 +266,7 @@ export class Fn { * @returns a token represented as a string array */ public refAll(parameterType: string): string[] { - return new FnRefAll(parameterType).toList(); + return Token.asList(new FnRefAll(parameterType)); } /** @@ -292,14 +294,14 @@ export class Fn { * @returns a token represented as a string array */ public valueOfAll(parameterType: string, attribute: string): string[] { - return new FnValueOfAll(parameterType, attribute).toList(); + return Token.asList(new FnValueOfAll(parameterType, attribute)); } } /** * Base class for tokens that represent CloudFormation intrinsic functions. */ -class FnBase extends Token { +class FnBase extends Intrinsic { constructor(name: string, value: any) { super({ [name]: value }); } @@ -456,7 +458,7 @@ class FnCidr extends FnBase { } } -class FnConditionBase extends Token implements ICfnConditionExpression { +class FnConditionBase extends Intrinsic implements ICfnConditionExpression { constructor(type: string, value: any) { super({ [type]: value }); } @@ -627,7 +629,7 @@ class FnValueOfAll extends FnBase { * the specified delimiter. If a delimiter is the empty string, the set of values are concatenated * with no delimiter. */ -class FnJoin extends Token { +class FnJoin implements IResolvable { private readonly delimiter: string; private readonly listOfValues: any[]; // Cache for the result of resolveValues() - since it otherwise would be computed several times @@ -643,14 +645,13 @@ class FnJoin extends Token { if (listOfValues.length === 0) { throw new Error(`FnJoin requires at least one value to be provided`); } - super(); this.delimiter = delimiter; this.listOfValues = listOfValues; } public resolve(context: IResolveContext): any { - if (Token.isToken(this.listOfValues)) { + if (Token.isUnresolved(this.listOfValues)) { // This is a list token, don't try to do smart things with it. return { 'Fn::Join': [ this.delimiter, this.listOfValues ] }; } @@ -661,6 +662,14 @@ class FnJoin extends Token { return { 'Fn::Join': [ this.delimiter, resolved ] }; } + public toString() { + return Token.asString(this, { displayHint: 'Fn::Join' }); + } + + public toJSON() { + return ``; + } + /** * Optimization: if an Fn::Join is nested in another one and they share the same delimiter, then flatten it up. Also, * if two concatenated elements are literal strings (not tokens), then pre-concatenate them with the delimiter, to @@ -672,4 +681,4 @@ class FnJoin extends Token { const resolvedValues = this.listOfValues.map(context.resolve); return this._resolvedValues = minimalCloudFormationJoin(this.delimiter, resolvedValues); } -} +} \ No newline at end of file diff --git a/packages/@aws-cdk/cdk/lib/index.ts b/packages/@aws-cdk/cdk/lib/index.ts index d52d784f1e495..bc99eb685e1cf 100644 --- a/packages/@aws-cdk/cdk/lib/index.ts +++ b/packages/@aws-cdk/cdk/lib/index.ts @@ -3,10 +3,10 @@ export * from './tag-aspect'; export * from './construct'; export * from './token'; -export * from './token-map'; +export * from './resolvable'; +export * from './lazy'; export * from './tag-manager'; export * from './dependency'; -export * from './resolve'; export * from './string-fragments'; export * from './reference'; @@ -17,7 +17,6 @@ export * from './logical-id'; export * from './cfn-mapping'; export * from './cfn-output'; export * from './cfn-parameter'; -export * from './cfn-reference'; export * from './pseudo'; export * from './cfn-resource'; export * from './resource-policy'; @@ -39,3 +38,7 @@ export * from './secret-value'; export * from './resource'; export * from './physical-name'; export * from './resource-identifiers'; + +// WARNING: Should not be exported, but currently is because of a bug. See the +// class description for more information. +export * from './private/intrinsic'; diff --git a/packages/@aws-cdk/cdk/lib/instrinsics.ts b/packages/@aws-cdk/cdk/lib/instrinsics.ts deleted file mode 100644 index d81926ea49393..0000000000000 --- a/packages/@aws-cdk/cdk/lib/instrinsics.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Do an intelligent CloudFormation join on the given values, producing a minimal expression - */ -export function minimalCloudFormationJoin(delimiter: string, values: any[]): any[] { - let i = 0; - while (i < values.length) { - const el = values[i]; - if (isSplicableFnJoinInstrinsic(el)) { - values.splice(i, 1, ...el['Fn::Join'][1]); - } else if (i > 0 && isPlainString(values[i - 1]) && isPlainString(values[i])) { - values[i - 1] += delimiter + values[i]; - values.splice(i, 1); - } else { - i += 1; - } - } - - return values; - - function isPlainString(obj: any): boolean { - return typeof obj === 'string' && !require('./token').Token.isToken(obj); - } - - function isSplicableFnJoinInstrinsic(obj: any): boolean { - return isIntrinsic(obj) - && Object.keys(obj)[0] === 'Fn::Join' - && obj['Fn::Join'][0] === delimiter; - } -} - -/** - * Return whether the given value represents a CloudFormation intrinsic - */ -export function isIntrinsic(x: any) { - if (Array.isArray(x) || x === null || typeof x !== 'object') { return false; } - - const keys = Object.keys(x); - if (keys.length !== 1) { return false; } - - return keys[0] === 'Ref' || isNameOfCloudFormationIntrinsic(keys[0]); -} - -export function isNameOfCloudFormationIntrinsic(name: string): boolean { - if (!name.startsWith('Fn::')) { - return false; - } - // these are 'fake' intrinsics, only usable inside the parameter overrides of a CFN CodePipeline Action - return name !== 'Fn::GetArtifactAtt' && name !== 'Fn::GetParam'; -} - -/** - * Return whether this is an intrinsic that could potentially (or definitely) evaluate to a list - */ -export function canEvaluateToList(x: any) { - return isIntrinsic(x) && ['Ref', 'Fn::GetAtt', 'Fn::GetAZs', 'Fn::Split', 'Fn::FindInMap', 'Fn::ImportValue'].includes(Object.keys(x)[0]); -} diff --git a/packages/@aws-cdk/cdk/lib/lazy.ts b/packages/@aws-cdk/cdk/lib/lazy.ts new file mode 100644 index 0000000000000..bcf1d59a10b12 --- /dev/null +++ b/packages/@aws-cdk/cdk/lib/lazy.ts @@ -0,0 +1,185 @@ +import { IResolvable, IResolveContext } from "./resolvable"; +import { Token } from "./token"; + +/** + * Interface for lazy string producers + */ +export interface IStringValue { + /** + * Produce the string value + */ + produce(context: IResolveContext): string | undefined; +} + +/** + * Interface for lazy list producers + */ +export interface IListProducer { + /** + * Produce the list value + */ + produce(context: IResolveContext): string[] | undefined; +} + +/** + * Interface for lazy number producers + */ +export interface INumberProducer { + /** + * Produce the number value + */ + produce(context: IResolveContext): number | undefined; +} + +/** + * Interface for lazy untyped value producers + */ +export interface IAnyProducer { + /** + * Produce the value + */ + produce(context: IResolveContext): any; +} + +/** + * Options for creating a lazy string token + */ +export interface LazyStringValueOptions { + /** + * Use the given name as a display hint + * + * @default - No hint + */ + readonly displayHint?: string; +} + +/** + * Options for creating a lazy list token + */ +export interface LazyListValueOptions { + /** + * Use the given name as a display hint + * + * @default - No hint + */ + readonly displayHint?: string; + + /** + * If the produced list is empty, return 'undefined' instead + * + * @default false + */ + readonly omitEmpty?: boolean; +} + +/** + * Options for creating lazy untyped tokens + */ +export interface LazyAnyValueOptions { + /** + * Use the given name as a display hint + * + * @default - No hint + */ + readonly displayHint?: string; + + /** + * If the produced value is an array and it is empty, return 'undefined' instead + * + * @default false + */ + readonly omitEmptyArray?: boolean; +} + +/** + * Lazily produce a value + * + * Can be used to return a string, list or numeric value whose actual value + * will only be calculated later, during synthesis. + */ +export class Lazy { + public static stringValue(producer: IStringValue, options: LazyStringValueOptions = {}) { + return Token.asString(new LazyString(producer), options); + } + + public static numberValue(producer: INumberProducer) { + return Token.asNumber(new LazyNumber(producer)); + } + + public static listValue(producer: IListProducer, options: LazyListValueOptions = {}) { + return Token.asList(new LazyList(producer, options), options); + } + + public static anyValue(producer: IAnyProducer, options: LazyAnyValueOptions = {}): IResolvable { + return new LazyAny(producer, options); + } + + private constructor() { + } +} + +abstract class LazyBase implements IResolvable { + public abstract resolve(context: IResolveContext): any; + + public toString() { + return Token.asString(this); + } + + /** + * Turn this Token into JSON + * + * Called automatically when JSON.stringify() is called on a Token. + */ + public toJSON(): any { + return ''; + } + +} + +class LazyString extends LazyBase { + constructor(private readonly producer: IStringValue) { + super(); + } + + public resolve(context: IResolveContext) { + return this.producer.produce(context); + } +} + +class LazyNumber extends LazyBase { + constructor(private readonly producer: INumberProducer) { + super(); + } + + public resolve(context: IResolveContext) { + return this.producer.produce(context); + } +} + +class LazyList extends LazyBase { + constructor(private readonly producer: IListProducer, private readonly options: LazyListValueOptions = {}) { + super(); + } + + public resolve(context: IResolveContext) { + const ret = this.producer.produce(context); + if (ret !== undefined && ret.length === 0 && this.options.omitEmpty) { + return undefined; + } + return ret; + } +} + +class LazyAny extends LazyBase { + constructor(private readonly producer: IAnyProducer, private readonly options: LazyAnyValueOptions = {}) { + super(); + } + + public resolve(context: IResolveContext) { + const ret = this.producer.produce(context); + if (Array.isArray(ret) && ret.length === 0 && this.options.omitEmptyArray) { + return undefined; + } + return ret; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/cdk/lib/physical-name.ts b/packages/@aws-cdk/cdk/lib/physical-name.ts index 5a77556848eb0..b1a8b0d88fe98 100644 --- a/packages/@aws-cdk/cdk/lib/physical-name.ts +++ b/packages/@aws-cdk/cdk/lib/physical-name.ts @@ -1,6 +1,6 @@ +import { Lazy } from "./lazy"; import { generatePhysicalName } from "./physical-name-generator"; import { IResource } from './resource'; -import { Token } from "./token"; /** * Options allowing customizing the automatically generated physical name of the resource. @@ -103,7 +103,7 @@ class LateBoundPhysicalName extends PhysicalName { super(); this.value = options.crossEnvironment - ? new Token(() => this.name).toString() + ? Lazy.stringValue({ produce: () => this.name }) : undefined; } diff --git a/packages/@aws-cdk/cdk/lib/cfn-reference.ts b/packages/@aws-cdk/cdk/lib/private/cfn-reference.ts similarity index 79% rename from packages/@aws-cdk/cdk/lib/cfn-reference.ts rename to packages/@aws-cdk/cdk/lib/private/cfn-reference.ts index 2f440bcda7062..839f073b13774 100644 --- a/packages/@aws-cdk/cdk/lib/cfn-reference.ts +++ b/packages/@aws-cdk/cdk/lib/private/cfn-reference.ts @@ -1,4 +1,4 @@ -import { Reference } from "./reference"; +import { Reference } from "../reference"; const CFN_REFERENCE_SYMBOL = Symbol.for('@aws-cdk/cdk.CfnReference'); @@ -20,7 +20,7 @@ export class CfnReference extends Reference { /** * Check whether this is actually a Reference */ - public static isCfnReference(x: Token): x is CfnReference { + public static isCfnReference(x: IResolvable): x is CfnReference { return CFN_REFERENCE_SYMBOL in x; } @@ -32,12 +32,12 @@ export class CfnReference extends Reference { * the prepare() phase (for the purpose of cross-stack references), it's * important that the state isn't lost if it's lazily created, like so: * - * new Token(() => new CfnReference(...)) + * Lazy.stringValue({ produce: () => new CfnReference(...) }) */ - public static for(target: CfnRefElement, attribute: string) { + public static for(target: CfnElement, attribute: string) { return CfnReference.singletonReference(target, attribute, () => { - const cfnInstrinsic = attribute === 'Ref' ? { Ref: target.logicalId } : { 'Fn::GetAtt': [ target.logicalId, attribute ]}; - return new CfnReference(cfnInstrinsic, attribute, target); + const cfnIntrinsic = attribute === 'Ref' ? { Ref: target.logicalId } : { 'Fn::GetAtt': [ target.logicalId, attribute ]}; + return new CfnReference(cfnIntrinsic, attribute, target); }); } @@ -46,8 +46,8 @@ export class CfnReference extends Reference { */ public static forPseudo(pseudoName: string, scope: Construct) { return CfnReference.singletonReference(scope, `Pseudo:${pseudoName}`, () => { - const cfnInstrinsic = { Ref: pseudoName }; - return new CfnReference(cfnInstrinsic, pseudoName, scope); + const cfnIntrinsic = { Ref: pseudoName }; + return new CfnReference(cfnIntrinsic, pseudoName, scope); }); } @@ -81,20 +81,16 @@ export class CfnReference extends Reference { /** * The Tokens that should be returned for each consuming stack (as decided by the producing Stack) */ - private readonly replacementTokens: Map; + private readonly replacementTokens: Map; private readonly originalDisplayName: string; private readonly humanReadableDesc: string; - private constructor(value: any, displayName: string, target: Construct) { - if (typeof(value) === 'function') { - throw new Error('Reference can only hold CloudFormation intrinsics (not a function)'); - } - + protected constructor(value: any, private readonly displayName: string, target: IConstruct) { // prepend scope path to display name - super(value, `${target.node.id}.${displayName}`, target); + super(value, target); this.originalDisplayName = displayName; - this.replacementTokens = new Map(); + this.replacementTokens = new Map(); this.humanReadableDesc = `target = ${target.node.path}`; this.producingStack = Stack.of(target); @@ -130,12 +126,21 @@ export class CfnReference extends Reference { } } + /** + * Implementation of toString() that will use the display name + */ + public toString(): string { + return Token.asString(this, { + displayHint: `${this.target.node.id}.${this.displayName}` + }); + } + /** * Export a Token value for use in another stack * * Works by mutating the producing stack in-place. */ - private exportValue(tokenValue: Token, consumingStack: Stack): Token { + private exportValue(tokenValue: Token, consumingStack: Stack): IResolvable { const producingStack = this.producingStack!; if (producingStack.env.account !== consumingStack.env.account || producingStack.env.region !== consumingStack.env.region) { @@ -163,12 +168,14 @@ export class CfnReference extends Reference { // We want to return an actual FnImportValue Token here, but Fn.importValue() returns a 'string', // so construct one in-place. - return new Token({ 'Fn::ImportValue': output.obtainExportName() }); + return new Intrinsic({ 'Fn::ImportValue': output.obtainExportName() }); } } -import { CfnRefElement } from "./cfn-element"; -import { CfnOutput } from "./cfn-output"; -import { Construct, IConstruct } from "./construct"; -import { Stack } from "./stack"; -import { IResolveContext, Token } from "./token"; +import { CfnElement } from "../cfn-element"; +import { CfnOutput } from "../cfn-output"; +import { Construct, IConstruct } from "../construct"; +import { IResolvable, IResolveContext } from "../resolvable"; +import { Stack } from "../stack"; +import { Token } from "../token"; +import { Intrinsic } from "./intrinsic"; diff --git a/packages/@aws-cdk/cdk/lib/cross-environment-token.ts b/packages/@aws-cdk/cdk/lib/private/cross-environment-token.ts similarity index 72% rename from packages/@aws-cdk/cdk/lib/cross-environment-token.ts rename to packages/@aws-cdk/cdk/lib/private/cross-environment-token.ts index f32a2ca35df8c..e9689f79b971d 100644 --- a/packages/@aws-cdk/cdk/lib/cross-environment-token.ts +++ b/packages/@aws-cdk/cdk/lib/private/cross-environment-token.ts @@ -1,7 +1,7 @@ -import { ArnComponents } from './arn'; -import { IResource } from './resource'; -import { Stack } from './stack'; -import { IResolveContext, Token } from './token'; +import { ArnComponents } from '../arn'; +import { IResolvable, IResolveContext } from '../resolvable'; +import { IResource } from '../resource'; +import { Stack } from '../stack'; /** * A Token that represents a reference that spans accounts and/or regions, @@ -10,9 +10,7 @@ import { IResolveContext, Token } from './token'; * instead use the {@link ResourceIdentifiers} class. * This class is private to the @aws-cdk/cdk package. */ -export abstract class CrossEnvironmentToken extends Token { - private readonly resource: IResource; - +export abstract class CrossEnvironmentToken implements IResolvable { /** * @param regularValue the value used when this is referenced NOT from a cross account and/or region Stack * @param crossEnvironmentValue the value used when this is referenced from a cross account and/or region Stack @@ -20,9 +18,7 @@ export abstract class CrossEnvironmentToken extends Token { * @param displayName a short name to be used in Token display */ protected constructor(private readonly regularValue: string, private readonly crossEnvironmentValue: any, - resource: IResource, displayName: string) { - super(undefined, displayName); - + private readonly resource: IResource) { this.resource = resource; } @@ -41,13 +37,13 @@ export abstract class CrossEnvironmentToken extends Token { } export class CrossEnvironmentPhysicalArnToken extends CrossEnvironmentToken { - constructor(regularValue: string, arnComponents: ArnComponents, resource: IResource, displayName: string = 'Arn') { - super(regularValue, Stack.of(resource).formatArn(arnComponents), resource, displayName); + constructor(regularValue: string, arnComponents: ArnComponents, resource: IResource) { + super(regularValue, Stack.of(resource).formatArn(arnComponents), resource); } } export class CrossEnvironmentPhysicalNameToken extends CrossEnvironmentToken { - constructor(regularValue: string, resource: IResource, displayName: string = 'Ref') { - super(regularValue, resource.physicalName.value, resource, displayName); + constructor(regularValue: string, resource: IResource) { + super(regularValue, resource.physicalName.value, resource); } } diff --git a/packages/@aws-cdk/cdk/lib/encoding.ts b/packages/@aws-cdk/cdk/lib/private/encoding.ts similarity index 94% rename from packages/@aws-cdk/cdk/lib/encoding.ts rename to packages/@aws-cdk/cdk/lib/private/encoding.ts index 90af8112ff41b..ef57fe0d06634 100644 --- a/packages/@aws-cdk/cdk/lib/encoding.ts +++ b/packages/@aws-cdk/cdk/lib/private/encoding.ts @@ -1,6 +1,7 @@ -import { IFragmentConcatenator } from "./resolve"; -import { TokenizedStringFragments } from "./string-fragments"; -import { RESOLVE_METHOD, Token } from "./token"; +import { IResolvable } from "../resolvable"; +import { IFragmentConcatenator } from "../resolvable"; +import { TokenizedStringFragments } from "../string-fragments"; +import { isResolvableObject } from "../token"; // Details for encoding and decoding Tokens into native types; should not be exported @@ -41,7 +42,7 @@ export class TokenString { /** * Split string on markers, substituting markers with Tokens */ - public split(lookup: (id: string) => Token): TokenizedStringFragments { + public split(lookup: (id: string) => IResolvable): TokenizedStringFragments { const ret = new TokenizedStringFragments(); let rest = 0; @@ -102,7 +103,6 @@ export function containsListTokenElement(xs: any[]) { * that includes token markers), or it's a listifictaion of a Token string. * * @param obj The object to test. - * @deprecated use `Token.unresolved` */ export function unresolved(obj: any): boolean { if (typeof(obj) === 'string') { @@ -112,7 +112,7 @@ export function unresolved(obj: any): boolean { } else if (Array.isArray(obj) && obj.length === 1) { return typeof(obj[0]) === 'string' && TokenString.forListToken(obj[0]).test(); } else { - return obj && typeof(obj[RESOLVE_METHOD]) === 'function'; + return isResolvableObject(obj); } } diff --git a/packages/@aws-cdk/cdk/lib/private/intrinsic.ts b/packages/@aws-cdk/cdk/lib/private/intrinsic.ts new file mode 100644 index 0000000000000..f7469cf4f542c --- /dev/null +++ b/packages/@aws-cdk/cdk/lib/private/intrinsic.ts @@ -0,0 +1,77 @@ +import { IResolvable, IResolveContext } from "../resolvable"; +import { Token } from "../token"; +import { createStackTrace } from "./stack-trace"; + +/** + * Token subclass that represents values intrinsic to the target document language + * + * WARNING: this class should not be externally exposed, but is currently visible + * because of a limitation of jsii (https://github.com/awslabs/jsii/issues/524). + * + * This class will disappear in a future release and should not be used. + * + * @experimental + */ +export class Intrinsic implements IResolvable { + /** + * The captured stack trace which represents the location in which this token was created. + */ + protected readonly trace: string[]; + + private readonly value: any; + + constructor(value: any) { + if (isFunction(value)) { + throw new Error(`Argument to Intrinsic must be a plain value object, got ${value}`); + } + + this.trace = createStackTrace(); + this.value = value; + } + + public resolve(_context: IResolveContext) { + return this.value; + } + + /** + * Convert an instance of this Token to a string + * + * This method will be called implicitly by language runtimes if the object + * is embedded into a string. We treat it the same as an explicit + * stringification. + */ + public toString(): string { + return Token.asString(this); + } + + /** + * Turn this Token into JSON + * + * Called automatically when JSON.stringify() is called on a Token. + */ + public toJSON(): any { + // We can't do the right work here because in case we contain a function, we + // won't know the type of value that function represents (in the simplest + // case, string or number), and we can't know that without an + // IResolveContext to actually do the resolution, which we don't have. + + // We used to throw an error, but since JSON.stringify() is often used in + // error messages to produce a readable representation of an object, if we + // throw here we'll obfuscate that descriptive error with something worse. + // So return a string representation that indicates this thing is a token + // and needs resolving. + return ``; + } + + /** + * Creates a throwable Error object that contains the token creation stack trace. + * @param message Error message + */ + protected newError(message: string): any { + return new Error(`${message}\nToken created:\n at ${this.trace.join('\n at ')}\nError thrown:`); + } +} + +function isFunction(x: any) { + return typeof x === 'function'; +} \ No newline at end of file diff --git a/packages/@aws-cdk/cdk/lib/resolve.ts b/packages/@aws-cdk/cdk/lib/private/resolve.ts similarity index 63% rename from packages/@aws-cdk/cdk/lib/resolve.ts rename to packages/@aws-cdk/cdk/lib/private/resolve.ts index 01b970935409e..70495d8706557 100644 --- a/packages/@aws-cdk/cdk/lib/resolve.ts +++ b/packages/@aws-cdk/cdk/lib/private/resolve.ts @@ -1,7 +1,7 @@ -import { IConstruct } from './construct'; +import { IConstruct } from '../construct'; +import { DefaultTokenResolver, IResolvable, IResolveContext, ITokenResolver, StringConcat } from '../resolvable'; +import { TokenizedStringFragments } from '../string-fragments'; import { containsListTokenElement, TokenString, unresolved } from "./encoding"; -import { TokenizedStringFragments } from './string-fragments'; -import { IResolveContext, isResolvedValuePostProcessor, RESOLVE_METHOD, Token } from "./token"; import { TokenMap } from './token-map'; // This file should not be exported to consumers, resolving should happen through Construct.resolve() @@ -155,107 +155,10 @@ export function resolve(obj: any, options: IResolveOptions): any { return result; } -/** - * How to resolve tokens - */ -export interface ITokenResolver { - /** - * Resolve a single token - */ - resolveToken(t: Token, context: IResolveContext): any; - - /** - * Resolve a string with at least one stringified token in it - * - * (May use concatenation) - */ - resolveString(s: TokenizedStringFragments, context: IResolveContext): any; - - /** - * Resolve a tokenized list - */ - resolveList(l: string[], context: IResolveContext): any; -} - -/** - * Function used to concatenate symbols in the target document language - * - * Interface so it could potentially be exposed over jsii. - */ -export interface IFragmentConcatenator { - /** - * Join the fragment on the left and on the right - */ - join(left: any | undefined, right: any | undefined): any; -} - -/** - * Converts all fragments to strings and concats those - * - * Drops 'undefined's. - */ -export class StringConcat implements IFragmentConcatenator { - public join(left: any | undefined, right: any | undefined): any { - if (left === undefined) { return right !== undefined ? `${right}` : undefined; } - if (right === undefined) { return `${left}`; } - return `${left}${right}`; - } -} - -/** - * Default resolver implementation - */ -export class DefaultTokenResolver implements ITokenResolver { - constructor(private readonly concat: IFragmentConcatenator) { - } - - /** - * Default Token resolution - * - * Resolve the Token, recurse into whatever it returns, - * then finally post-process it. - */ - public resolveToken(t: Token, context: IResolveContext) { - let resolved = t[RESOLVE_METHOD](context); - - // The token might have returned more values that need resolving, recurse - resolved = context.resolve(resolved); - - if (isResolvedValuePostProcessor(t)) { - resolved = t.postProcess(resolved, context); - } - - return resolved; - } - - /** - * Resolve string fragments to Tokens - */ - public resolveString(fragments: TokenizedStringFragments, context: IResolveContext) { - return fragments.mapTokens({ mapToken: context.resolve }).join(this.concat); - } - - public resolveList(xs: string[], context: IResolveContext) { - // Must be a singleton list token, because concatenation is not allowed. - if (xs.length !== 1) { - throw new Error(`Cannot add elements to list token, got: ${xs}`); - } - - const str = TokenString.forListToken(xs[0]); - const fragments = str.split(tokenMap.lookupToken.bind(tokenMap)); - if (fragments.length !== 1) { - throw new Error(`Cannot concatenate strings in a tokenized string array, got: ${xs[0]}`); - } - - return fragments.mapTokens({ mapToken: context.resolve }).firstValue; - } - -} - /** * Find all Tokens that are used in the given structure */ -export function findTokens(scope: IConstruct, fn: () => any): Token[] { +export function findTokens(scope: IConstruct, fn: () => any): IResolvable[] { const resolver = new RememberingTokenResolver(new StringConcat()); resolve(fn(), { scope, prefix: [], resolver }); @@ -267,9 +170,9 @@ export function findTokens(scope: IConstruct, fn: () => any): Token[] { * Remember all Tokens encountered while resolving */ export class RememberingTokenResolver extends DefaultTokenResolver { - private readonly tokensSeen = new Set(); + private readonly tokensSeen = new Set(); - public resolveToken(t: Token, context: IResolveContext) { + public resolveToken(t: IResolvable, context: IResolveContext) { this.tokensSeen.add(t); return super.resolveToken(t, context); } @@ -279,7 +182,7 @@ export class RememberingTokenResolver extends DefaultTokenResolver { return ret; } - public get tokens(): Token[] { + public get tokens(): IResolvable[] { return Array.from(this.tokensSeen); } } diff --git a/packages/@aws-cdk/cdk/lib/stack-trace.ts b/packages/@aws-cdk/cdk/lib/private/stack-trace.ts similarity index 100% rename from packages/@aws-cdk/cdk/lib/stack-trace.ts rename to packages/@aws-cdk/cdk/lib/private/stack-trace.ts diff --git a/packages/@aws-cdk/cdk/lib/token-map.ts b/packages/@aws-cdk/cdk/lib/private/token-map.ts similarity index 59% rename from packages/@aws-cdk/cdk/lib/token-map.ts rename to packages/@aws-cdk/cdk/lib/private/token-map.ts index 0adb4ef31fb8a..5e006b55b9dae 100644 --- a/packages/@aws-cdk/cdk/lib/token-map.ts +++ b/packages/@aws-cdk/cdk/lib/private/token-map.ts @@ -1,10 +1,15 @@ +import { IResolvable } from "../resolvable"; +import { TokenizedStringFragments } from "../string-fragments"; +import { Token } from "../token"; import { BEGIN_LIST_TOKEN_MARKER, BEGIN_STRING_TOKEN_MARKER, createTokenDouble, END_TOKEN_MARKER, extractTokenDouble, TokenString, VALID_KEY_CHARS } from "./encoding"; -import { TokenizedStringFragments } from "./string-fragments"; -import { Token } from "./token"; const glob = global as any; +const STRING_SYMBOL = Symbol.for('@aws-cdk/cdk.TokenMap.STRING'); +const LIST_SYMBOL = Symbol.for('@aws-cdk/cdk.TokenMap.LIST'); +const NUMBER_SYMBOL = Symbol.for('@aws-cdk/cdk.TokenMap.NUMBER'); + /** * Central place where we keep a mapping from Tokens to their String representation * @@ -25,8 +30,8 @@ export class TokenMap { return glob.__cdkTokenMap; } - private readonly stringTokenMap = new Map(); - private readonly numberTokenMap = new Map(); + private readonly stringTokenMap = new Map(); + private readonly numberTokenMap = new Map(); private tokenCounter = 0; /** @@ -40,52 +45,46 @@ export class TokenMap { * hint. This may be used to produce aesthetically pleasing and * recognizable token representations for humans. */ - public registerString(token: Token, representationHint?: string): string { - const key = this.register(token, representationHint); - return `${BEGIN_STRING_TOKEN_MARKER}${key}${END_TOKEN_MARKER}`; + public registerString(token: IResolvable, displayHint?: string): string { + return cachedValue(token, STRING_SYMBOL, () => { + const key = this.registerStringKey(token, displayHint); + return `${BEGIN_STRING_TOKEN_MARKER}${key}${END_TOKEN_MARKER}`; + }); } /** * Generate a unique string for this Token, returning a key */ - public registerList(token: Token, representationHint?: string): string[] { - const key = this.register(token, representationHint); - return [`${BEGIN_LIST_TOKEN_MARKER}${key}${END_TOKEN_MARKER}`]; - } - - /** - * Lookup a token from an encoded value - */ - public tokenFromEncoding(x: any): Token | undefined { - if (typeof 'x' === 'string') { return this.lookupString(x); } - if (Array.isArray(x)) { return this.lookupList(x); } - if (typeof x === 'object' && x !== null && Token.isToken(x)) { - return x as Token; - } - return undefined; + public registerList(token: IResolvable, displayHint?: string): string[] { + return cachedValue(token, LIST_SYMBOL, () => { + const key = this.registerStringKey(token, displayHint); + return [`${BEGIN_LIST_TOKEN_MARKER}${key}${END_TOKEN_MARKER}`]; + }); } /** * Create a unique number representation for this Token and return it */ - public registerNumber(token: Token): number { - const tokenIndex = this.tokenCounter++; - this.numberTokenMap.set(tokenIndex, token); - return createTokenDouble(tokenIndex); + public registerNumber(token: IResolvable): number { + return cachedValue(token, NUMBER_SYMBOL, () => { + return this.registerNumberKey(token); + }); } /** - * Split a string into literals and Tokens + * Lookup a token from an encoded value */ - public splitString(s: string): TokenizedStringFragments { - const str = TokenString.forString(s); - return str.split(this.lookupToken.bind(this)); + public tokenFromEncoding(x: any): IResolvable | undefined { + if (typeof 'x' === 'string') { return this.lookupString(x); } + if (Array.isArray(x)) { return this.lookupList(x); } + if (Token.isUnresolved(x)) { return x; } + return undefined; } /** * Reverse a string representation into a Token object */ - public lookupString(s: string): Token | undefined { + public lookupString(s: string): IResolvable | undefined { const fragments = this.splitString(s); if (fragments.tokens.length > 0 && fragments.length === 1) { return fragments.firstToken; @@ -96,7 +95,7 @@ export class TokenMap { /** * Reverse a string representation into a Token object */ - public lookupList(xs: string[]): Token | undefined { + public lookupList(xs: string[]): IResolvable | undefined { if (xs.length !== 1) { return undefined; } const str = TokenString.forListToken(xs[0]); const fragments = str.split(this.lookupToken.bind(this)); @@ -106,10 +105,18 @@ export class TokenMap { return undefined; } + /** + * Split a string into literals and Tokens + */ + public splitString(s: string): TokenizedStringFragments { + const str = TokenString.forString(s); + return str.split(this.lookupToken.bind(this)); + } + /** * Reverse a number encoding into a Token, or undefined if the number wasn't a Token */ - public lookupNumberToken(x: number): Token | undefined { + public lookupNumberToken(x: number): IResolvable | undefined { const tokenIndex = extractTokenDouble(x); if (tokenIndex === undefined) { return undefined; } const t = this.numberTokenMap.get(tokenIndex); @@ -122,7 +129,7 @@ export class TokenMap { * * This excludes the token markers. */ - public lookupToken(key: string): Token { + public lookupToken(key: string): IResolvable { const token = this.stringTokenMap.get(key); if (!token) { throw new Error(`Unrecognized token key: ${key}`); @@ -130,11 +137,29 @@ export class TokenMap { return token; } - private register(token: Token, representationHint?: string): string { + private registerStringKey(token: IResolvable, displayHint?: string): string { const counter = this.tokenCounter++; - const representation = (representationHint || `TOKEN`).replace(new RegExp(`[^${VALID_KEY_CHARS}]`, 'g'), '.'); + const representation = (displayHint || `TOKEN`).replace(new RegExp(`[^${VALID_KEY_CHARS}]`, 'g'), '.'); const key = `${representation}.${counter}`; this.stringTokenMap.set(key, token); return key; } -} \ No newline at end of file + + private registerNumberKey(token: IResolvable): number { + const counter = this.tokenCounter++; + this.numberTokenMap.set(counter, token); + return createTokenDouble(counter); + } +} + +/** + * Get a cached value for an object, storing it on the object in a symbol + */ +function cachedValue(x: A, sym: symbol, prod: () => B) { + let cached = (x as any)[sym as any]; + if (cached === undefined) { + cached = prod(); + Object.defineProperty(x, sym, { value: cached }); + } + return cached; +} diff --git a/packages/@aws-cdk/cdk/lib/pseudo.ts b/packages/@aws-cdk/cdk/lib/pseudo.ts index 2a7d168f9e7d8..f248ed8b5de14 100644 --- a/packages/@aws-cdk/cdk/lib/pseudo.ts +++ b/packages/@aws-cdk/cdk/lib/pseudo.ts @@ -1,5 +1,5 @@ -import { CfnReference } from './cfn-reference'; import { Construct } from './construct'; +import { CfnReference } from './private/cfn-reference'; import { Token } from './token'; const AWS_ACCOUNTID = 'AWS::AccountId'; @@ -23,35 +23,37 @@ export class Aws { } public static get accountId(): string { - return new UnscopedPseudo(AWS_ACCOUNTID).toString(); + return pseudoString(AWS_ACCOUNTID); } public static get urlSuffix(): string { - return new UnscopedPseudo(AWS_URLSUFFIX).toString(); + return pseudoString(AWS_URLSUFFIX); } public static get notificationArns(): string[] { - return new UnscopedPseudo(AWS_NOTIFICATIONARNS).toList(); + return Token.asList({ Ref: AWS_NOTIFICATIONARNS }, { + displayHint: AWS_NOTIFICATIONARNS + }); } public static get partition(): string { - return new UnscopedPseudo(AWS_PARTITION).toString(); + return pseudoString(AWS_PARTITION); } public static get region(): string { - return new UnscopedPseudo(AWS_REGION).toString(); + return pseudoString(AWS_REGION); } public static get stackId(): string { - return new UnscopedPseudo(AWS_STACKID).toString(); + return pseudoString(AWS_STACKID); } public static get stackName(): string { - return new UnscopedPseudo(AWS_STACKNAME).toString(); + return pseudoString(AWS_STACKNAME); } public static get noValue(): string { - return new UnscopedPseudo(AWS_NOVALUE).toString(); + return pseudoString(AWS_NOVALUE); } } @@ -66,36 +68,40 @@ export class ScopedAws { } public get accountId(): string { - return CfnReference.forPseudo(AWS_ACCOUNTID, this.scope).toString(); + return this.asString(AWS_ACCOUNTID); } public get urlSuffix(): string { - return CfnReference.forPseudo(AWS_URLSUFFIX, this.scope).toString(); + return this.asString(AWS_URLSUFFIX); } public get notificationArns(): string[] { - return CfnReference.forPseudo(AWS_NOTIFICATIONARNS, this.scope).toList(); + return Token.asList(CfnReference.forPseudo(AWS_NOTIFICATIONARNS, this.scope), { + displayHint: AWS_NOTIFICATIONARNS + }); } public get partition(): string { - return CfnReference.forPseudo(AWS_PARTITION, this.scope).toString(); + return this.asString(AWS_PARTITION); } public get region(): string { - return CfnReference.forPseudo(AWS_REGION, this.scope).toString(); + return this.asString(AWS_REGION); } public get stackId(): string { - return CfnReference.forPseudo(AWS_STACKID, this.scope).toString(); + return this.asString(AWS_STACKID); } public get stackName(): string { - return CfnReference.forPseudo(AWS_STACKNAME, this.scope).toString(); + return this.asString(AWS_STACKNAME); } -} -class UnscopedPseudo extends Token { - constructor(name: string) { - super({ Ref: name }, name); + private asString(name: string) { + return Token.asString(CfnReference.forPseudo(name, this.scope), { displayHint: name }); } -} \ No newline at end of file +} + +function pseudoString(name: string): string { + return Token.asString({ Ref: name }, { displayHint: name }); +} diff --git a/packages/@aws-cdk/cdk/lib/reference.ts b/packages/@aws-cdk/cdk/lib/reference.ts index 49de124557f61..52c9cf989c946 100644 --- a/packages/@aws-cdk/cdk/lib/reference.ts +++ b/packages/@aws-cdk/cdk/lib/reference.ts @@ -1,27 +1,27 @@ -import { Token } from "./token"; +import { Intrinsic } from "./private/intrinsic"; const REFERENCE_SYMBOL = Symbol.for('@aws-cdk/cdk.Reference'); /** - * A Token that represents a reference between two constructs + * An intrinsic Token that represents a reference to a construct. * * References are recorded. */ -export class Reference extends Token { +export abstract class Reference extends Intrinsic { /** * Check whether this is actually a Reference */ public static isReference(x: any): x is Reference { - return REFERENCE_SYMBOL in x; + return typeof x === 'object' && x !== null && REFERENCE_SYMBOL in x; } - public readonly target: Construct; + public readonly target: IConstruct; - constructor(value: any, displayName: string, target: Construct) { - super(value, displayName); + constructor(value: any, target: IConstruct) { + super(value); this.target = target; Object.defineProperty(this, REFERENCE_SYMBOL, { value: true }); } } -import { Construct } from "./construct"; +import { IConstruct } from "./construct"; diff --git a/packages/@aws-cdk/cdk/lib/resolvable.ts b/packages/@aws-cdk/cdk/lib/resolvable.ts new file mode 100644 index 0000000000000..646a69f3c4b86 --- /dev/null +++ b/packages/@aws-cdk/cdk/lib/resolvable.ts @@ -0,0 +1,152 @@ +import { IConstruct } from "./construct"; +import { TokenString } from "./private/encoding"; +import { TokenMap } from "./private/token-map"; +import { TokenizedStringFragments } from "./string-fragments"; + +/** + * Current resolution context for tokens + */ +export interface IResolveContext { + /** + * The scope from which resolution has been initiated + */ + readonly scope: IConstruct; + + /** + * Resolve an inner object + */ + resolve(x: any): any; +} + +/** + * Interface for values that can be resolvable later + * + * Tokens are special objects that participate in synthesis. + */ +export interface IResolvable { + /** + * Produce the Token's value at resolution time + */ + resolve(context: IResolveContext): any; + + /** + * Return a string representation of this resolvable object. + * + * Returns a reversible string representation. + */ + toString(): string; +} + +/** + * A Token that can post-process the complete resolved value, after resolve() has recursed over it + */ +export interface IResolvableWithPostProcess extends IResolvable { + /** + * Process the completely resolved value, after full recursion/resolution has happened + */ + postProcess(input: any, context: IResolveContext): any; +} + +/** + * How to resolve tokens + */ +export interface ITokenResolver { + /** + * Resolve a single token + */ + resolveToken(t: IResolvable, context: IResolveContext): any; + + /** + * Resolve a string with at least one stringified token in it + * + * (May use concatenation) + */ + resolveString(s: TokenizedStringFragments, context: IResolveContext): any; + + /** + * Resolve a tokenized list + */ + resolveList(l: string[], context: IResolveContext): any; +} + +/** + * Function used to concatenate symbols in the target document language + * + * Interface so it could potentially be exposed over jsii. + */ +export interface IFragmentConcatenator { + /** + * Join the fragment on the left and on the right + */ + join(left: any | undefined, right: any | undefined): any; +} + +/** + * Converts all fragments to strings and concats those + * + * Drops 'undefined's. + */ +export class StringConcat implements IFragmentConcatenator { + public join(left: any | undefined, right: any | undefined): any { + if (left === undefined) { return right !== undefined ? `${right}` : undefined; } + if (right === undefined) { return `${left}`; } + return `${left}${right}`; + } +} + +/** + * Default resolver implementation + */ +export class DefaultTokenResolver implements ITokenResolver { + constructor(private readonly concat: IFragmentConcatenator) { + } + + /** + * Default Token resolution + * + * Resolve the Token, recurse into whatever it returns, + * then finally post-process it. + */ + public resolveToken(t: IResolvable, context: IResolveContext) { + let resolved = t.resolve(context); + + // The token might have returned more values that need resolving, recurse + resolved = context.resolve(resolved); + + if (isResolvedValuePostProcessor(t)) { + resolved = t.postProcess(resolved, context); + } + + return resolved; + } + + /** + * Resolve string fragments to Tokens + */ + public resolveString(fragments: TokenizedStringFragments, context: IResolveContext) { + return fragments.mapTokens({ mapToken: context.resolve }).join(this.concat); + } + + public resolveList(xs: string[], context: IResolveContext) { + // Must be a singleton list token, because concatenation is not allowed. + if (xs.length !== 1) { + throw new Error(`Cannot add elements to list token, got: ${xs}`); + } + + const str = TokenString.forListToken(xs[0]); + const tokenMap = TokenMap.instance(); + const fragments = str.split(tokenMap.lookupToken.bind(tokenMap)); + if (fragments.length !== 1) { + throw new Error(`Cannot concatenate strings in a tokenized string array, got: ${xs[0]}`); + } + + return fragments.mapTokens({ mapToken: context.resolve }).firstValue; + } +} + +/** + * Whether the given object is an `IResolvedValuePostProcessor` + */ +function isResolvedValuePostProcessor(x: any): x is IResolvableWithPostProcess { + return x.postProcess !== undefined; +} diff --git a/packages/@aws-cdk/cdk/lib/resource-identifiers.ts b/packages/@aws-cdk/cdk/lib/resource-identifiers.ts index 1f97c30e7d9c3..022131e762da6 100644 --- a/packages/@aws-cdk/cdk/lib/resource-identifiers.ts +++ b/packages/@aws-cdk/cdk/lib/resource-identifiers.ts @@ -1,6 +1,7 @@ import { ArnComponents } from './arn'; -import { CrossEnvironmentPhysicalArnToken, CrossEnvironmentPhysicalNameToken } from './cross-environment-token'; +import { CrossEnvironmentPhysicalArnToken, CrossEnvironmentPhysicalNameToken } from './private/cross-environment-token'; import { IResource } from './resource'; +import { Token } from './token'; /** * Construction properties for {@link ResourceIdentifiers}. @@ -31,15 +32,15 @@ export class ResourceIdentifiers { public readonly name: string; constructor(resource: IResource, props: ResourceIdentifiersProps) { - this.arn = new CrossEnvironmentPhysicalArnToken( + this.arn = Token.asString(new CrossEnvironmentPhysicalArnToken( props.arn, props.arnComponents, resource, - ).toString(); + ), { displayHint: 'Arn' }); - this.name = new CrossEnvironmentPhysicalNameToken( + this.name = Token.asString(new CrossEnvironmentPhysicalNameToken( props.name, resource, - ).toString(); + ), { displayHint: 'Name' }); } } diff --git a/packages/@aws-cdk/cdk/lib/runtime.ts b/packages/@aws-cdk/cdk/lib/runtime.ts index 56e2aec98595b..78694558a6755 100644 --- a/packages/@aws-cdk/cdk/lib/runtime.ts +++ b/packages/@aws-cdk/cdk/lib/runtime.ts @@ -374,7 +374,7 @@ export function unionValidator(...validators: Validator[]): Validator { /** * Return whether the indicated value represents a CloudFormation intrinsic. * - * CloudFormation instrinsics are modeled as objects with a single key, which + * CloudFormation intrinsics are modeled as objects with a single key, which * look like: { "Fn::GetAtt": [...] } or similar. */ function isCloudFormationIntrinsic(x: any) { diff --git a/packages/@aws-cdk/cdk/lib/secret-value.ts b/packages/@aws-cdk/cdk/lib/secret-value.ts index e5b12581eda2e..3a4b8db632b53 100644 --- a/packages/@aws-cdk/cdk/lib/secret-value.ts +++ b/packages/@aws-cdk/cdk/lib/secret-value.ts @@ -1,6 +1,6 @@ import { CfnDynamicReference, CfnDynamicReferenceService } from './cfn-dynamic-reference'; import { CfnParameter } from './cfn-parameter'; -import { Token } from './token'; +import { Intrinsic } from './private/intrinsic'; /** * Work with secret values in the CDK @@ -17,7 +17,7 @@ import { Token } from './token'; * You can escape the check by calling `Secret.plainTex()`, but doing * so is highly discouraged. */ -export class SecretValue extends Token { +export class SecretValue extends Intrinsic { /** * Construct a literal secret value for use with secret-aware constructs * @@ -74,7 +74,7 @@ export class SecretValue extends Token { * @param ref The dynamic reference to use. */ public static cfnDynamicReference(ref: CfnDynamicReference) { - return new SecretValue(() => ref.toString()); + return new SecretValue(ref); } /** diff --git a/packages/@aws-cdk/cdk/lib/stack.ts b/packages/@aws-cdk/cdk/lib/stack.ts index d5d85facba520..fcf3401b2ec4b 100644 --- a/packages/@aws-cdk/cdk/lib/stack.ts +++ b/packages/@aws-cdk/cdk/lib/stack.ts @@ -7,7 +7,7 @@ import { CLOUDFORMATION_TOKEN_RESOLVER, CloudFormationLang } from './cloudformat import { Construct, ConstructNode, IConstruct, ISynthesisSession } from './construct'; import { Environment } from './environment'; import { HashedAddressingScheme, IAddressingScheme, LogicalIDs } from './logical-id'; -import { resolve } from './resolve'; +import { resolve } from './private/resolve'; import { makeUniqueId } from './uniqueid'; const STACK_SYMBOL = Symbol.for('@aws-cdk/cdk.Stack'); @@ -690,8 +690,8 @@ function cfnElements(node: IConstruct, into: CfnElement[] = []): CfnElement[] { // These imports have to be at the end to prevent circular imports import { ArnComponents, arnFromComponents, parseArn } from './arn'; import { CfnElement } from './cfn-element'; -import { CfnReference } from './cfn-reference'; import { CfnResource, TagType } from './cfn-resource'; +import { CfnReference } from './private/cfn-reference'; import { Aws, ScopedAws } from './pseudo'; import { ITaggable, TagManager } from './tag-manager'; diff --git a/packages/@aws-cdk/cdk/lib/string-fragments.ts b/packages/@aws-cdk/cdk/lib/string-fragments.ts index f33caf2cd94ec..0dc43a4e7ce65 100644 --- a/packages/@aws-cdk/cdk/lib/string-fragments.ts +++ b/packages/@aws-cdk/cdk/lib/string-fragments.ts @@ -1,5 +1,5 @@ -import { IFragmentConcatenator } from "./resolve"; -import { Token } from "./token"; +import { IFragmentConcatenator, IResolvable } from "./resolvable"; +import { isResolvableObject } from "./token"; /** * Result of the split of a string with Tokens @@ -7,7 +7,7 @@ import { Token } from "./token"; * Either a literal part of the string, or an unresolved Token. */ type LiteralFragment = { type: 'literal'; lit: any; }; -type TokenFragment = { type: 'token'; token: Token; }; +type TokenFragment = { type: 'token'; token: IResolvable; }; type IntrinsicFragment = { type: 'intrinsic'; value: any; }; type Fragment = LiteralFragment | TokenFragment | IntrinsicFragment; @@ -17,7 +17,7 @@ type Fragment = LiteralFragment | TokenFragment | IntrinsicFragment; export class TokenizedStringFragments { private readonly fragments = new Array(); - public get firstToken(): Token | undefined { + public get firstToken(): IResolvable | undefined { const first = this.fragments[0]; if (first.type === 'token') { return first.token; } return undefined; @@ -35,7 +35,7 @@ export class TokenizedStringFragments { this.fragments.push({ type: 'literal', lit }); } - public addToken(token: Token) { + public addToken(token: IResolvable) { this.fragments.push({ type: 'token', token }); } @@ -46,8 +46,8 @@ export class TokenizedStringFragments { /** * Return all Tokens from this string */ - public get tokens(): Token[] { - const ret = new Array(); + public get tokens(): IResolvable[] { + const ret = new Array(); for (const f of this.fragments) { if (f.type === 'token') { ret.push(f.token); @@ -69,7 +69,7 @@ export class TokenizedStringFragments { break; case 'token': const mapped = mapper.mapToken(f.token); - if (isTokenObject(mapped)) { + if (isResolvableObject(mapped)) { ret.addToken(mapped); } else { ret.addIntrinsic(mapped); @@ -113,7 +113,7 @@ export interface ITokenMapper { /** * Replace a single token */ - mapToken(t: Token): any; + mapToken(t: IResolvable): any; } /** @@ -128,13 +128,3 @@ function fragmentValue(fragment: Fragment): any { case 'intrinsic': return fragment.value; } } - -/** - * Whether x is literally a Token object - * - * Can't use Token.isToken() because that has been co-opted - * to mean something else. - */ -function isTokenObject(x: any): x is Token { - return typeof(x) === 'object' && x !== null && Token.isToken(x); -} \ No newline at end of file diff --git a/packages/@aws-cdk/cdk/lib/token.ts b/packages/@aws-cdk/cdk/lib/token.ts index bc4f3dca4e971..e5c5127873943 100644 --- a/packages/@aws-cdk/cdk/lib/token.ts +++ b/packages/@aws-cdk/cdk/lib/token.ts @@ -1,13 +1,10 @@ import { IConstruct } from "./construct"; -import { unresolved } from "./encoding"; -import { createStackTrace } from './stack-trace'; -import { TokenMap } from "./token-map"; - -/** - * If objects has a function property by this name, they will be considered tokens, and this - * function will be called to resolve the value for this object. - */ -export const RESOLVE_METHOD = 'resolve'; +import { unresolved } from "./private/encoding"; +import { Intrinsic } from "./private/intrinsic"; +import { resolve } from "./private/resolve"; +import { TokenMap } from "./private/token-map"; +import { IResolvable, ITokenResolver } from "./resolvable"; +import { TokenizedStringFragments } from "./string-fragments"; /** * Represents a special or lazily-evaluated value. @@ -21,64 +18,21 @@ export const RESOLVE_METHOD = 'resolve'; */ export class Token { /** - * @deprecated use `Token.isToken` - */ - public static unresolved(obj: any): boolean { - return unresolved(obj); - } - - /** - * Returns true if obj is a token (i.e. has the resolve() method or is a - * string or array which includes token markers). + * Returns true if obj represents an unresolved value * - * @param obj The object to test. - */ - public static isToken(obj: any): boolean { - return unresolved(obj); - } - - /** - * The captured stack trace which represents the location in which this token was created. - */ - protected readonly trace: string[]; - - private tokenStringification?: string; - private tokenListification?: string[]; - private tokenNumberification?: number; - - /** - * Creates a token that resolves to `value`. - * - * If value is a function, the function is evaluated upon resolution and - * the value it returns will be used as the token's value. - * - * displayName is used to represent the Token when it's embedded into a string; it - * will look something like this: - * - * "embedded in a larger string is ${Token[DISPLAY_NAME.123]}" + * One of these must be true: * - * This value is used as a hint to humans what the meaning of the Token is, - * and does not have any effect on the evaluation. + * - `obj` is an IResolvable + * - `obj` is a string containing at least one encoded `IResolvable` + * - `obj` is either an encoded number or list * - * Must contain only alphanumeric and simple separator characters (_.:-). + * This does NOT recurse into lists or objects to see if they + * containing resolvables. * - * @param valueOrFunction What this token will evaluate to, literal or function. - * @param displayName A human-readable display hint for this Token - */ - constructor(private readonly valueOrFunction?: any, private readonly displayName?: string) { - this.trace = createStackTrace(); - } - - /** - * @returns The resolved value for this token. + * @param obj The object to test. */ - public resolve(context: IResolveContext): any { - let value = this.valueOrFunction; - if (typeof(value) === 'function') { - value = value(context); - } - - return value; + public static isUnresolved(obj: any): boolean { + return unresolved(obj); } /** @@ -92,123 +46,108 @@ export class Token { * complex values with the Tokens restored by calling `resolve()` * on the string. */ - public toString(): string { - // Optimization: if we can immediately resolve this, don't bother - // registering a Token (unless it's already a token). - if (typeof(this.valueOrFunction) === 'string') { - return this.valueOrFunction; - } - - if (this.tokenStringification === undefined) { - this.tokenStringification = TokenMap.instance().registerString(this, this.displayName); - } - - return this.tokenStringification; + public static asString(value: any, options: EncodingOptions = {}): string { + if (typeof value === 'string') { return value; } + return TokenMap.instance().registerString(Token.asAny(value), options.displayHint); } /** - * Turn this Token into JSON - * - * This gets called by JSON.stringify(). We want to prohibit this, because - * it's not possible to do this properly, so we just throw an error here. + * Return a reversible number representation of this token */ - public toJSON(): any { - // We can't do the right work here because in case we contain a function, we - // won't know the type of value that function represents (in the simplest - // case, string or number), and we can't know that without an - // IResolveContext to actually do the resolution, which we don't have. + public static asNumber(value: any): number { + if (typeof value === 'number') { return value; } + return TokenMap.instance().registerNumber(Token.asAny(value)); + } - // We used to throw an error, but since JSON.stringify() is often used in - // error messages to produce a readable representation of an object, if we - // throw here we'll obfuscate that descriptive error with something worse. - // So return a string representation that indicates this thing is a token - // and needs resolving. - return JSON.stringify(``); + /** + * Return a reversible list representation of this token + */ + public static asList(value: any, options: EncodingOptions = {}): string[] { + if (Array.isArray(value) && value.every(x => typeof x === 'string')) { return value; } + return TokenMap.instance().registerList(Token.asAny(value), options.displayHint); } /** - * Return a string list representation of this token - * - * Call this if the Token intrinsically evaluates to a list of strings. - * If so, you can represent the Token in a similar way in the type - * system. - * - * Note that even though the Token is represented as a list of strings, you - * still cannot do any operations on it such as concatenation, indexing, - * or taking its length. The only useful operations you can do to these lists - * is constructing a `FnJoin` or a `FnSelect` on it. + * Return a resolvable representation of the given value */ - public toList(): string[] { - if (Array.isArray(this.valueOrFunction)) { - return this.valueOrFunction; - } + public static asAny(value: any): IResolvable { + return isResolvableObject(value) ? value : new Intrinsic(value); + } - if (this.tokenListification === undefined) { - this.tokenListification = TokenMap.instance().registerList(this, this.displayName); - } - return this.tokenListification; + private constructor() { } +} +/** + * Less oft-needed functions to manipulate Tokens + */ +export class Tokenization { /** - * Return a floating point representation of this Token - * - * Call this if the Token intrinsically resolves to something that represents - * a number, and you need to pass it into an API that expects a number. - * - * You may not do any operations on the returned value; any arithmetic or - * other operations can and probably will destroy the token-ness of the value. + * Un-encode a string potentially containing encoded tokens */ - public toNumber(): number { - // Optimization: if we can immediately resolve this, don't bother - // registering a Token. - if (typeof(this.valueOrFunction) === 'number') { - return this.valueOrFunction; - } + public static reverseString(s: string): TokenizedStringFragments { + return TokenMap.instance().splitString(s); + } - if (this.tokenNumberification === undefined) { - this.tokenNumberification = TokenMap.instance().registerNumber(this); - } + /** + * Un-encode a Tokenized value from a number + */ + public static reverseNumber(n: number): IResolvable | undefined { + return TokenMap.instance().lookupNumberToken(n); + } - return this.tokenNumberification; + /** + * Un-encode a Tokenized value from a list + */ + public static reverseList(l: string[]): IResolvable | undefined { + return TokenMap.instance().lookupList(l); } /** - * Creates a throwable Error object that contains the token creation stack trace. - * @param message Error message + * Resolves an object by evaluating all tokens and removing any undefined or empty objects or arrays. + * Values can only be primitives, arrays or tokens. Other objects (i.e. with methods) will be rejected. + * + * @param obj The object to resolve. + * @param options Prefix key path components for diagnostics. */ - protected newError(message: string): any { - return new Error(`${message}\nToken created:\n at ${this.trace.join('\n at ')}\nError thrown:`); + public static resolve(obj: any, options: ResolveOptions): any { + return resolve(obj, options); + } + + private constructor() { } } /** - * Current resolution context for tokens + * Options to the resolve() operation + * + * NOT the same as the ResolveContext; ResolveContext is exposed to Token + * implementors and resolution hooks, whereas this struct is just to bundle + * a number of things that would otherwise be arguments to resolve() in a + * readable way. */ -export interface IResolveContext { +export interface ResolveOptions { /** - * The scope from which resolution has been initiated + * The scope from which resolution is performed */ readonly scope: IConstruct; /** - * Resolve an inner object + * The resolver to apply to any resolvable tokens found */ - resolve(x: any): any; + readonly resolver: ITokenResolver; } /** - * A Token that can post-process the complete resolved value, after resolve() has recursed over it + * Properties to string encodings */ -export interface IResolvedValuePostProcessor { +export interface EncodingOptions { /** - * Process the completely resolved value, after full recursion/resolution has happened + * A hint for the Token's purpose when stringifying it */ - postProcess(input: any, context: IResolveContext): any; + readonly displayHint?: string; } -/** - * Whether the given object is an `IResolvedValuePostProcessor` - */ -export function isResolvedValuePostProcessor(x: any): x is IResolvedValuePostProcessor { - return x.postProcess !== undefined; +export function isResolvableObject(x: any): x is IResolvable { + return typeof(x) === 'object' && x !== null && typeof x.resolve === 'function'; } \ No newline at end of file diff --git a/packages/@aws-cdk/cdk/lib/uniqueid.ts b/packages/@aws-cdk/cdk/lib/uniqueid.ts index 00a46f9e50379..d7d3f7a48b027 100644 --- a/packages/@aws-cdk/cdk/lib/uniqueid.ts +++ b/packages/@aws-cdk/cdk/lib/uniqueid.ts @@ -36,7 +36,7 @@ export function makeUniqueId(components: string[]) { } // Lazy require in order to break a module dependency cycle - const unresolvedTokens = components.filter(c => require('./encoding').unresolved(c)); + const unresolvedTokens = components.filter(c => require('./private/encoding').unresolved(c)); if (unresolvedTokens.length > 0) { throw new Error(`ID components may not include unresolved tokens: ${unresolvedTokens.join(',')}`); } diff --git a/packages/@aws-cdk/cdk/lib/util.ts b/packages/@aws-cdk/cdk/lib/util.ts index f1edac35f5fc6..6eb6c94f08719 100644 --- a/packages/@aws-cdk/cdk/lib/util.ts +++ b/packages/@aws-cdk/cdk/lib/util.ts @@ -1,6 +1,7 @@ import { IConstruct } from "./construct"; -import { Stack } from './stack'; -import { IResolveContext, IResolvedValuePostProcessor, Token } from "./token"; +import { Intrinsic } from "./private/intrinsic"; +import { IResolvableWithPostProcess, IResolveContext } from "./resolvable"; +import { Stack } from "./stack"; /** * Given an object, converts all keys to PascalCase given they are currently in camel case. @@ -77,7 +78,7 @@ export function filterUndefined(obj: any): any { /** * A Token that applies a function AFTER resolve resolution */ -export class PostResolveToken extends Token implements IResolvedValuePostProcessor { +export class PostResolveToken extends Intrinsic implements IResolvableWithPostProcess { constructor(value: any, private readonly processor: (x: any) => any) { super(value); } diff --git a/packages/@aws-cdk/cdk/package-lock.json b/packages/@aws-cdk/cdk/package-lock.json index 7ecde957fce59..9dd626a4e4359 100644 --- a/packages/@aws-cdk/cdk/package-lock.json +++ b/packages/@aws-cdk/cdk/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/cdk", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/cdk/test/evaluate-cfn.ts b/packages/@aws-cdk/cdk/test/evaluate-cfn.ts index 90120ae04ad26..0ae333cef60bb 100644 --- a/packages/@aws-cdk/cdk/test/evaluate-cfn.ts +++ b/packages/@aws-cdk/cdk/test/evaluate-cfn.ts @@ -3,7 +3,7 @@ * * Note that this function is not production quality, it exists to support tests. */ -import { isNameOfCloudFormationIntrinsic } from '../lib/instrinsics'; +import { isNameOfCloudFormationIntrinsic } from '../lib/cloudformation-lang'; export function evaluateCFN(object: any, context: {[key: string]: string} = {}): any { const intrinsics: any = { diff --git a/packages/@aws-cdk/cdk/test/test.arn.ts b/packages/@aws-cdk/cdk/test/test.arn.ts index f7fd18a749ec5..d8eb7d48ee6e9 100644 --- a/packages/@aws-cdk/cdk/test/test.arn.ts +++ b/packages/@aws-cdk/cdk/test/test.arn.ts @@ -1,5 +1,6 @@ import { Test } from 'nodeunit'; -import { ArnComponents, CfnOutput, ScopedAws, Stack, Token } from '../lib'; +import { ArnComponents, CfnOutput, ScopedAws, Stack } from '../lib'; +import { Intrinsic } from '../lib/private/intrinsic'; import { toCloudFormation } from './util'; export = { @@ -176,7 +177,7 @@ export = { 'a Token with : separator'(test: Test) { const stack = new Stack(); const theToken = { Ref: 'SomeParameter' }; - const parsed = stack.parseArn(new Token(() => theToken).toString(), ':'); + const parsed = stack.parseArn(new Intrinsic(theToken).toString(), ':'); test.deepEqual(stack.resolve(parsed.partition), { 'Fn::Select': [ 1, { 'Fn::Split': [ ':', theToken ]} ]}); test.deepEqual(stack.resolve(parsed.service), { 'Fn::Select': [ 2, { 'Fn::Split': [ ':', theToken ]} ]}); @@ -192,7 +193,7 @@ export = { 'a Token with / separator'(test: Test) { const stack = new Stack(); const theToken = { Ref: 'SomeParameter' }; - const parsed = stack.parseArn(new Token(() => theToken).toString()); + const parsed = stack.parseArn(new Intrinsic(theToken).toString()); test.equal(parsed.sep, '/'); diff --git a/packages/@aws-cdk/cdk/test/test.cloudformation-json.ts b/packages/@aws-cdk/cdk/test/test.cloudformation-json.ts index 60c10c69a2b27..9da9e24f388d0 100644 --- a/packages/@aws-cdk/cdk/test/test.cloudformation-json.ts +++ b/packages/@aws-cdk/cdk/test/test.cloudformation-json.ts @@ -1,5 +1,6 @@ import { Test } from 'nodeunit'; -import { Fn, Stack, Token } from '../lib'; +import { Fn, Lazy, Stack, Token } from '../lib'; +import { Intrinsic } from '../lib/private/intrinsic'; import { evaluateCFN } from './evaluate-cfn'; export = { @@ -54,7 +55,7 @@ export = { 'integer Tokens behave correctly in stringification and JSONification'(test: Test) { // GIVEN const stack = new Stack(); - const num = new Token(() => 1); + const num = new Intrinsic(1); const embedded = `the number is ${num}`; // WHEN @@ -82,7 +83,7 @@ export = { 'intrinsic Tokens embed correctly in JSONification'(test: Test) { // GIVEN const stack = new Stack(); - const bucketName = new Token({ Ref: 'MyBucket' }); + const bucketName = new Intrinsic({ Ref: 'MyBucket' }); // WHEN const resolved = stack.resolve(stack.toJsonString({ theBucket: bucketName })); @@ -96,7 +97,7 @@ export = { 'fake intrinsics are serialized to objects'(test: Test) { const stack = new Stack(); - const fakeIntrinsics = new Token(() => ({ + const fakeIntrinsics = new Intrinsic({ a: { 'Fn::GetArtifactAtt': { key: 'val', @@ -108,7 +109,7 @@ export = { 'val2', ], }, - })); + }); const stringified = stack.toJsonString(fakeIntrinsics); test.equal(evaluateCFN(stack.resolve(stringified)), @@ -138,7 +139,7 @@ export = { 'Tokens in Tokens are handled correctly'(test: Test) { // GIVEN const stack = new Stack(); - const bucketName = new Token({ Ref: 'MyBucket' }); + const bucketName = new Intrinsic({ Ref: 'MyBucket' }); const combinedName = Fn.join('', [ 'The bucket name is ', bucketName.toString() ]); // WHEN @@ -154,7 +155,7 @@ export = { 'Doubly nested strings evaluate correctly in JSON context'(test: Test) { // WHEN const stack = new Stack(); - const fidoSays = new Token(() => 'woof'); + const fidoSays = Lazy.stringValue({ produce: () => 'woof' }); // WHEN const resolved = stack.resolve(stack.toJsonString({ @@ -170,7 +171,7 @@ export = { 'Doubly nested intrinsics evaluate correctly in JSON context'(test: Test) { // GIVEN const stack = new Stack(); - const fidoSays = new Token(() => ({ Ref: 'Something' })); + const fidoSays = Lazy.anyValue({ produce: () => ({ Ref: 'Something' }) }); // WHEN const resolved = stack.resolve(stack.toJsonString({ @@ -187,7 +188,7 @@ export = { 'Quoted strings in embedded JSON context are escaped'(test: Test) { // GIVEN const stack = new Stack(); - const fidoSays = new Token(() => '"woof"'); + const fidoSays = Lazy.stringValue({ produce: () => '"woof"' }); // WHEN const resolved = stack.resolve(stack.toJsonString({ @@ -206,7 +207,7 @@ export = { */ function tokensThatResolveTo(value: any): Token[] { return [ - new Token(value), - new Token(() => value) + new Intrinsic(value), + Lazy.anyValue({ produce: () => value }) ]; } diff --git a/packages/@aws-cdk/cdk/test/test.condition.ts b/packages/@aws-cdk/cdk/test/test.condition.ts index e5fa20dcdc882..e83741ef77902 100644 --- a/packages/@aws-cdk/cdk/test/test.condition.ts +++ b/packages/@aws-cdk/cdk/test/test.condition.ts @@ -45,7 +45,7 @@ export = { }); // THEN - test.ok(cdk.Token.isToken(propValue)); + test.ok(cdk.Token.isUnresolved(propValue)); test.deepEqual(toCloudFormation(stack), { Resources: { MyResource: { diff --git a/packages/@aws-cdk/cdk/test/test.construct.ts b/packages/@aws-cdk/cdk/test/test.construct.ts index 455dc251585ff..a467bef17a774 100644 --- a/packages/@aws-cdk/cdk/test/test.construct.ts +++ b/packages/@aws-cdk/cdk/test/test.construct.ts @@ -1,6 +1,6 @@ import cxapi = require('@aws-cdk/cx-api'); import { Test } from 'nodeunit'; -import { App as Root, Construct, ConstructNode, ConstructOrder, IConstruct, Token, ValidationError } from '../lib'; +import { App as Root, Construct, ConstructNode, ConstructOrder, IConstruct, Lazy, ValidationError } from '../lib'; // tslint:disable:variable-name // tslint:disable:max-line-length @@ -66,7 +66,7 @@ export = { "dont allow unresolved tokens to be used in construct IDs"(test: Test) { // GIVEN const root = new Root(); - const token = new Token(() => 'lazy'); + const token = Lazy.stringValue({ produce: () => 'lazy' }); // WHEN + THEN test.throws(() => new Construct(root, `MyID: ${token}`), /Cannot use tokens in construct ID: MyID: \${Token/); diff --git a/packages/@aws-cdk/cdk/test/test.fn.ts b/packages/@aws-cdk/cdk/test/test.fn.ts index f88db2116f7a6..bbec8b7acf8ef 100644 --- a/packages/@aws-cdk/cdk/test/test.fn.ts +++ b/packages/@aws-cdk/cdk/test/test.fn.ts @@ -2,6 +2,7 @@ import fc = require('fast-check'); import _ = require('lodash'); import nodeunit = require('nodeunit'); import { Fn, Stack, Token } from '../lib'; +import { Intrinsic } from '../lib/private/intrinsic'; function asyncTest(cb: (test: nodeunit.Test) => Promise): (test: nodeunit.Test) => void { return async (test: nodeunit.Test) => { @@ -129,8 +130,8 @@ export = nodeunit.testCase({ }); function stringListToken(o: any): string[] { - return new Token(o).toList(); + return Token.asList(new Intrinsic(o)); } function stringToken(o: any): string { - return new Token(o).toString(); + return Token.asString(new Intrinsic(o)); } diff --git a/packages/@aws-cdk/cdk/test/test.output.ts b/packages/@aws-cdk/cdk/test/test.output.ts index 857ac9d55df01..3d75fd53840cf 100644 --- a/packages/@aws-cdk/cdk/test/test.output.ts +++ b/packages/@aws-cdk/cdk/test/test.output.ts @@ -22,13 +22,6 @@ export = { test.done(); }, - 'outputs cannot be referenced'(test: Test) { - const stack = new Stack(); - const output = new CfnOutput(stack, 'MyOutput', { description: 'My CfnOutput', value: 'boom' }); - test.throws(() => output.ref); - test.done(); - }, - 'disableExport can be used to disable the auto-export behavior'(test: Test) { const stack = new Stack(); const output = new CfnOutput(stack, 'MyOutput', { disableExport: true, value: 'boom' }); diff --git a/packages/@aws-cdk/cdk/test/test.parameter.ts b/packages/@aws-cdk/cdk/test/test.parameter.ts index 5fd688ee6f5c5..b22e3f099a1c0 100644 --- a/packages/@aws-cdk/cdk/test/test.parameter.ts +++ b/packages/@aws-cdk/cdk/test/test.parameter.ts @@ -13,7 +13,7 @@ export = { description: 'My first parameter' }); - new CfnResource(stack, 'Resource', { type: 'Type', properties: { ReferenceToParam: param.ref } }); + new CfnResource(stack, 'Resource', { type: 'Type', properties: { ReferenceToParam: param.value } }); test.deepEqual(toCloudFormation(stack), { Parameters: { diff --git a/packages/@aws-cdk/cdk/test/test.stack.ts b/packages/@aws-cdk/cdk/test/test.stack.ts index af97bb504f06e..28ed10d1f5eb0 100644 --- a/packages/@aws-cdk/cdk/test/test.stack.ts +++ b/packages/@aws-cdk/cdk/test/test.stack.ts @@ -1,6 +1,7 @@ import cxapi = require('@aws-cdk/cx-api'); import { Test } from 'nodeunit'; -import { App, CfnCondition, CfnOutput, CfnParameter, CfnResource, Construct, ConstructNode, Include, ScopedAws, Stack, Token } from '../lib'; +import { App, CfnCondition, CfnOutput, CfnParameter, CfnResource, Construct, ConstructNode, Include, Lazy, ScopedAws, Stack } from '../lib'; +import { Intrinsic } from '../lib/private/intrinsic'; import { toCloudFormation } from './util'; export = { @@ -198,7 +199,7 @@ export = { // WHEN - used in another resource new CfnResource(stack2, 'SomeResource', { type: 'AWS::Some::Resource', properties: { - someProperty: new Token(() => resource1.ref), + someProperty: new Intrinsic(resource1.ref), }}); // THEN @@ -226,7 +227,7 @@ export = { const stack2 = new Stack(app, 'Stack2'); // WHEN - used in another stack - new CfnParameter(stack2, 'SomeParameter', { type: 'String', default: new Token(() => account1) }); + new CfnParameter(stack2, 'SomeParameter', { type: 'String', default: Lazy.stringValue({ produce: () => account1 }) }); const assembly = app.synth(); const template1 = assembly.getStack(stack1.name).template; @@ -390,7 +391,7 @@ export = { // { Ref } and { GetAtt } new CfnResource(stack, 'RefToBonjour', { type: 'Other::Resource', properties: { - RefToBonjour: bonjour.ref.toString(), + RefToBonjour: bonjour.refAsString, GetAttBonjour: bonjour.getAtt('TheAtt').toString() }}); diff --git a/packages/@aws-cdk/cdk/test/test.tokens.ts b/packages/@aws-cdk/cdk/test/test.tokens.ts index ed150eb0c63db..10afd2932e5d1 100644 --- a/packages/@aws-cdk/cdk/test/test.tokens.ts +++ b/packages/@aws-cdk/cdk/test/test.tokens.ts @@ -1,7 +1,9 @@ import { Test } from 'nodeunit'; -import { findTokens, Fn, Stack, Token } from '../lib'; -import { createTokenDouble, extractTokenDouble } from '../lib/encoding'; -import { TokenMap } from '../lib/token-map'; +import { Fn, isResolvableObject, Lazy, Stack, Token, Tokenization } from '../lib'; +import { createTokenDouble, extractTokenDouble } from '../lib/private/encoding'; +import { Intrinsic } from '../lib/private/intrinsic'; +import { findTokens } from '../lib/private/resolve'; +import { IResolvable } from '../lib/resolvable'; import { evaluateCFN } from './evaluate-cfn'; export = { @@ -14,7 +16,7 @@ export = { 'if a value is an object with a token value, it will be evaluated'(test: Test) { const obj = { RegularValue: 'hello', - LazyValue: new Token('World') + LazyValue: new Intrinsic('World') }; test.deepEqual(resolve(obj), { @@ -53,7 +55,7 @@ export = { 'tokens are evaluated recursively'(test: Test) { const obj = new Promise1(); - const actual = resolve(new Token(() => ({ Obj: obj }))); + const actual = resolve(new Intrinsic({ Obj: obj })); test.deepEqual(actual, { Obj: [ @@ -125,16 +127,16 @@ export = { }, 'isToken(obj) can be used to determine if an object is a token'(test: Test) { - test.ok(Token.isToken({ resolve: () => 123 })); - test.ok(Token.isToken({ a: 1, b: 2, resolve: () => 'hello' })); - test.ok(!Token.isToken({ a: 1, b: 2, resolve: 3 })); + test.ok(isResolvableObject({ resolve: () => 123 })); + test.ok(isResolvableObject({ a: 1, b: 2, resolve: () => 'hello' })); + test.ok(!isResolvableObject({ a: 1, b: 2, resolve: 3 })); test.done(); }, 'Token can be used to create tokens that contain a constant value'(test: Test) { - test.equal(resolve(new Token(12)), 12); - test.equal(resolve(new Token('hello')), 'hello'); - test.deepEqual(resolve(new Token([ 'hi', 'there' ])), [ 'hi', 'there' ]); + test.equal(resolve(new Intrinsic(12)), 12); + test.equal(resolve(new Intrinsic('hello')), 'hello'); + test.deepEqual(resolve(new Intrinsic([ 'hi', 'there' ])), [ 'hi', 'there' ]); test.done(); }, @@ -148,7 +150,7 @@ export = { 'tokens can be stringified and evaluated to conceptual value'(test: Test) { // GIVEN - const token = new Token(() => 'woof woof'); + const token = new Intrinsic('woof woof'); // WHEN const stringified = `The dog says: ${token}`; @@ -161,28 +163,16 @@ export = { 'tokens stringification can be reversed'(test: Test) { // GIVEN - const token = new Token(() => 'woof woof'); + const token = new Intrinsic('woof woof'); // THEN - test.equal(token, TokenMap.instance().lookupString(`${token}`)); - test.done(); - }, - - 'concatenated tokens are undefined'(test: Test) { - // GIVEN - const token = new Token(() => 'woof woof'); - - // WHEN - test.equal(undefined, TokenMap.instance().lookupString(`${token}bla`)); - test.equal(undefined, TokenMap.instance().lookupString(`bla${token}`)); - test.equal(undefined, TokenMap.instance().lookupString(`bla`)); - + test.equal(token, Tokenization.reverseString(`${token}`).firstToken); test.done(); }, 'Tokens stringification and reversing of CloudFormation Tokens is implemented using Fn::Join'(test: Test) { // GIVEN - const token = new Token(() => ({ woof: 'woof' })); + const token = new Intrinsic( ({ woof: 'woof' })); // WHEN const stringified = `The dog says: ${token}`; @@ -197,8 +187,8 @@ export = { 'Doubly nested strings evaluate correctly in scalar context'(test: Test) { // GIVEN - const token1 = new Token(() => "world"); - const token2 = new Token(() => `hello ${token1}`); + const token1 = new Intrinsic( "world"); + const token2 = new Intrinsic( `hello ${token1}`); // WHEN const resolved1 = resolve(token2.toString()); @@ -213,7 +203,7 @@ export = { 'integer Tokens can be stringified and evaluate to conceptual value'(test: Test) { // GIVEN - for (const token of literalTokensThatResolveTo(1)) { + for (const token of tokensThatResolveTo(1)) { // WHEN const stringified = `the number is ${token}`; const resolved = resolve(stringified); @@ -226,7 +216,7 @@ export = { 'intrinsic Tokens can be stringified and evaluate to conceptual value'(test: Test) { // GIVEN - for (const bucketName of cloudFormationTokensThatResolveTo({ Ref: 'MyBucket' })) { + for (const bucketName of tokensThatResolveTo({ Ref: 'MyBucket' })) { // WHEN const resolved = resolve(`my bucket is named ${bucketName}`); @@ -268,7 +258,7 @@ export = { 'tokens can be used in hash keys but must resolve to a string'(test: Test) { // GIVEN - const token = new Token(() => 'I am a string'); + const token = new Intrinsic( 'I am a string'); // WHEN const s = { @@ -282,7 +272,7 @@ export = { 'tokens can be nested in hash keys'(test: Test) { // GIVEN - const token = new Token(() => new Token(() => new Token(() => 'I am a string'))); + const token = new Intrinsic(Lazy.stringValue({ produce: () => Lazy.stringValue({ produce: (() => 'I am a string') }) })); // WHEN const s = { @@ -296,8 +286,8 @@ export = { 'tokens can be nested and concatenated in hash keys'(test: Test) { // GIVEN - const innerToken = new Token(() => 'toot'); - const token = new Token(() => `${innerToken} the woot`); + const innerToken = new Intrinsic( 'toot'); + const token = new Intrinsic( `${innerToken} the woot`); // WHEN const s = { @@ -311,8 +301,8 @@ export = { 'can find nested tokens in hash keys'(test: Test) { // GIVEN - const innerToken = new Token(() => 'toot'); - const token = new Token(() => `${innerToken} the woot`); + const innerToken = new Intrinsic( 'toot'); + const token = new Intrinsic( `${innerToken} the woot`); // WHEN const s = { @@ -328,7 +318,7 @@ export = { 'fails if token in a hash key resolves to a non-string'(test: Test) { // GIVEN - const token = new Token({ Ref: 'Other' }); + const token = new Intrinsic({ Ref: 'Other' }); // WHEN const s = { @@ -343,11 +333,11 @@ export = { 'list encoding': { 'can encode Token to string and resolve the encoding'(test: Test) { // GIVEN - const token = new Token({ Ref: 'Other' }); + const token = new Intrinsic({ Ref: 'Other' }); // WHEN const struct = { - XYZ: token.toList() + XYZ: Token.asList(token) }; // THEN @@ -360,10 +350,10 @@ export = { 'cannot add to encoded list'(test: Test) { // GIVEN - const token = new Token({ Ref: 'Other' }); + const token = new Intrinsic({ Ref: 'Other' }); // WHEN - const encoded: string[] = token.toList(); + const encoded: string[] = Token.asList(token); encoded.push('hello'); // THEN @@ -376,10 +366,10 @@ export = { 'cannot add to strings in encoded list'(test: Test) { // GIVEN - const token = new Token({ Ref: 'Other' }); + const token = new Intrinsic({ Ref: 'Other' }); // WHEN - const encoded: string[] = token.toList(); + const encoded: string[] = Token.asList(token); encoded[0] += 'hello'; // THEN @@ -392,7 +382,7 @@ export = { 'can pass encoded lists to FnSelect'(test: Test) { // GIVEN - const encoded: string[] = new Token({ Ref: 'Other' }).toList(); + const encoded: string[] = Token.asList(new Intrinsic({ Ref: 'Other' })); // WHEN const struct = Fn.select(1, encoded); @@ -407,7 +397,7 @@ export = { 'can pass encoded lists to FnJoin'(test: Test) { // GIVEN - const encoded: string[] = new Token({ Ref: 'Other' }).toList(); + const encoded: string[] = Token.asList(new Intrinsic({ Ref: 'Other' })); // WHEN const struct = Fn.join('/', encoded); @@ -422,7 +412,7 @@ export = { 'can pass encoded lists to FnJoin, even if join is stringified'(test: Test) { // GIVEN - const encoded: string[] = new Token({ Ref: 'Other' }).toList(); + const encoded: string[] = Token.asList(new Intrinsic({ Ref: 'Other' })); // WHEN const struct = Fn.join('/', encoded).toString(); @@ -467,11 +457,12 @@ export = { 'can number-encode and resolve Token objects'(test: Test) { // GIVEN - const x = new Token(() => 123); + const x = new Intrinsic( 123); // THEN - const encoded = x.toNumber(); - test.equal(true, Token.isToken(encoded), 'encoded number does not test as token'); + const encoded = Token.asNumber(x); + test.equal(false, isResolvableObject(encoded), 'encoded number does not test as token'); + test.equal(true, Token.isUnresolved(encoded), 'encoded number does not test as token'); // THEN const resolved = resolve({ value: encoded }); @@ -484,13 +475,13 @@ export = { 'stack trace is captured at token creation'(test: Test) { function fn1() { function fn2() { - class ExposeTrace extends Token { + class ExposeTrace extends Intrinsic { public get creationTrace() { return this.trace; } } - return new ExposeTrace(() => 'hello'); + return new ExposeTrace('hello'); } return fn2(); @@ -506,7 +497,7 @@ export = { function fn1() { function fn2() { function fn3() { - class ThrowingToken extends Token { + class ThrowingToken extends Intrinsic { public throwError(message: string) { throw this.newError(message); } @@ -527,7 +518,6 @@ export = { const tests: any = { }; const inputs = [ - () => 'lazy', 'a string', 1234, { an_object: 1234 }, @@ -537,91 +527,76 @@ export = { for (const input of inputs) { // GIVEN - const stringToken = new Token(input).toString(); - const numberToken = new Token(input).toNumber(); - const listToken = new Token(input).toList(); + const stringToken = Token.asString(new Intrinsic(input)); + const numberToken = Token.asNumber(new Intrinsic(input)); + const listToken = Token.asList(new Intrinsic(input)); // THEN - const expected = typeof(input) === 'function' ? input() : input; + const expected = input; tests[`${input}.toNumber()`] = (test: Test) => { - test.deepEqual(resolve(new Token(stringToken).toNumber()), expected); + test.deepEqual(resolve(Token.asNumber(new Intrinsic(stringToken))), expected); test.done(); }; tests[`${input}.toNumber()`] = (test: Test) => { - test.deepEqual(resolve(new Token(listToken).toNumber()), expected); + test.deepEqual(resolve(Token.asNumber(new Intrinsic(listToken))), expected); test.done(); }; tests[`${input}.toNumber()`] = (test: Test) => { - test.deepEqual(resolve(new Token(numberToken).toNumber()), expected); + test.deepEqual(resolve(Token.asNumber(new Intrinsic(numberToken))), expected); test.done(); }; tests[`${input}.toString()`] = (test: Test) => { - test.deepEqual(resolve(new Token(stringToken).toString()), expected); + test.deepEqual(resolve(new Intrinsic(stringToken).toString()), expected); test.done(); }; tests[`${input}.toString()`] = (test: Test) => { - test.deepEqual(resolve(new Token(listToken).toString()), expected); + test.deepEqual(resolve(new Intrinsic(listToken).toString()), expected); test.done(); }; tests[`${input}.toString()`] = (test: Test) => { - test.deepEqual(resolve(new Token(numberToken).toString()), expected); + test.deepEqual(resolve(new Intrinsic(numberToken).toString()), expected); test.done(); }; tests[`${input}.toList()`] = (test: Test) => { - test.deepEqual(resolve(new Token(stringToken).toList()), expected); + test.deepEqual(resolve(Token.asList(new Intrinsic(stringToken))), expected); test.done(); }; tests[`${input}.toList()`] = (test: Test) => { - test.deepEqual(resolve(new Token(listToken).toList()), expected); + test.deepEqual(resolve(Token.asList(new Intrinsic(listToken))), expected); test.done(); }; tests[`${input}.toList()`] = (test: Test) => { - test.deepEqual(resolve(new Token(numberToken).toList()), expected); + test.deepEqual(resolve(Token.asList(new Intrinsic(numberToken))), expected); test.done(); }; } return tests; })(), - - 'toXxx short circuts if the input is of the same type': { - 'toNumber(number)'(test: Test) { - test.deepEqual(new Token(123).toNumber(), 123); - test.done(); - }, - 'toList(list)'(test: Test) { - test.deepEqual(new Token([1, 2, 3]).toList(), [1, 2, 3]); - test.done(); - }, - 'toString(string)'(test: Test) { - test.deepEqual(new Token('string').toString(), 'string'), - test.done(); - } - } }; -class Promise2 extends Token { +class Promise2 implements IResolvable { public resolve() { return { Data: { stringProp: 'hello', numberProp: 1234, }, - Recurse: new Token(() => 42) + Recurse: new Intrinsic( 42) }; } } -class Promise1 extends Token { +class Promise1 implements IResolvable { public p2 = [ new Promise2(), new Promise2() ]; public resolve() { @@ -643,32 +618,15 @@ class DataType extends BaseDataType { } /** - * Return various flavors of Tokens that resolve to the given value - */ -function literalTokensThatResolveTo(value: any): Token[] { - return [ - new Token(value), - new Token(() => value) - ]; -} - -/** - * Return various flavors of Tokens that resolve to the given value + * Return Tokens in both flavors that resolve to the given string */ -function cloudFormationTokensThatResolveTo(value: any): Token[] { +function tokensThatResolveTo(value: any): Token[] { return [ - new Token(value), - new Token(() => value) + new Intrinsic(value), + Lazy.anyValue({ produce: () => value }) ]; } -/** - * Return Tokens in both flavors that resolve to the given string - */ -function tokensThatResolveTo(value: string): Token[] { - return literalTokensThatResolveTo(value).concat(cloudFormationTokensThatResolveTo(value)); -} - /** * Wrapper for resolve that creates an throwaway Construct to call it on * diff --git a/packages/@aws-cdk/cfnspec/package-lock.json b/packages/@aws-cdk/cfnspec/package-lock.json index 9c3e7978b03f0..2774413ae8581 100644 --- a/packages/@aws-cdk/cfnspec/package-lock.json +++ b/packages/@aws-cdk/cfnspec/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/cfnspec", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/cx-api/package-lock.json b/packages/@aws-cdk/cx-api/package-lock.json index 91cf6faf15e55..95698e52cb358 100644 --- a/packages/@aws-cdk/cx-api/package-lock.json +++ b/packages/@aws-cdk/cx-api/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/cx-api", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/region-info/package-lock.json b/packages/@aws-cdk/region-info/package-lock.json index 48e630d8cb61b..b482ee9e16235 100644 --- a/packages/@aws-cdk/region-info/package-lock.json +++ b/packages/@aws-cdk/region-info/package-lock.json @@ -1,6 +1,6 @@ { "name": "@aws-cdk/region-info", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/@aws-cdk/runtime-values/package-lock.json b/packages/@aws-cdk/runtime-values/package-lock.json new file mode 100644 index 0000000000000..776ce899976b5 --- /dev/null +++ b/packages/@aws-cdk/runtime-values/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@aws-cdk/runtime-values", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/aws-cdk/package-lock.json b/packages/aws-cdk/package-lock.json index 2127c560273fd..d1c412cf0f97c 100644 --- a/packages/aws-cdk/package-lock.json +++ b/packages/aws-cdk/package-lock.json @@ -1,6 +1,6 @@ { "name": "aws-cdk", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/cdk-dasm/package-lock.json b/packages/cdk-dasm/package-lock.json index 2fa1fedafe731..8697e9b81b6db 100644 --- a/packages/cdk-dasm/package-lock.json +++ b/packages/cdk-dasm/package-lock.json @@ -1,6 +1,6 @@ { "name": "cdk-dasm", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/cdk/package-lock.json b/packages/cdk/package-lock.json new file mode 100644 index 0000000000000..d766869a92e4f --- /dev/null +++ b/packages/cdk/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "cdk", + "version": "0.33.0", + "lockfileVersion": 1 +} diff --git a/packages/decdk/lib/declarative-stack.ts b/packages/decdk/lib/declarative-stack.ts index 385edd2640f9f..4f6e1ad06931a 100644 --- a/packages/decdk/lib/declarative-stack.ts +++ b/packages/decdk/lib/declarative-stack.ts @@ -382,7 +382,7 @@ function invokeMethod(stack: cdk.Stack, method: reflect.Callable, parameters: an * an `Fn::GetAtt`. */ function deconstructGetAtt(stack: cdk.Stack, id: string, attribute: string) { - new cdk.Token(() => { + return cdk.Lazy.stringValue({ produce: () => { const res = stack.node.tryFindChild(id); if (!res) { const include = stack.node.tryFindChild('Include') as cdk.Include; @@ -399,7 +399,7 @@ function deconstructGetAtt(stack: cdk.Stack, id: string, attribute: string) { return { "Fn::GetAtt": [ id, attribute ] }; } return (res as any)[attribute]; - }).toString(); + }}); } function findConstruct(stack: cdk.Stack, id: string) { diff --git a/packages/decdk/package-lock.json b/packages/decdk/package-lock.json index 113386ff25ff3..2e2cacf5d9099 100644 --- a/packages/decdk/package-lock.json +++ b/packages/decdk/package-lock.json @@ -1,6 +1,6 @@ { "name": "decdk", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/decdk/package.json b/packages/decdk/package.json index ff691d33ed52d..8cf08e3203b17 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -155,4 +155,4 @@ "engines": { "node": ">= 8.10.0" } -} +} \ No newline at end of file diff --git a/tools/awslint/lib/rules/construct.ts b/tools/awslint/lib/rules/construct.ts index 341b005bdfa4b..7b9cbb53b6255 100644 --- a/tools/awslint/lib/rules/construct.ts +++ b/tools/awslint/lib/rules/construct.ts @@ -234,7 +234,7 @@ constructLinter.add({ const found = (fqn && e.ctx.sys.tryFindFqn(fqn)); if (found) { - e.assert(!(fqn === e.ctx.core.tokenClass.fqn), `${e.ctx.propsFqn}.${property.name}`); + e.assert(!(fqn === e.ctx.core.tokenInterface.fqn), `${e.ctx.propsFqn}.${property.name}`); } } } diff --git a/tools/awslint/lib/rules/core-types.ts b/tools/awslint/lib/rules/core-types.ts index 8708b36ed6c42..2f7f9205d3f5e 100644 --- a/tools/awslint/lib/rules/core-types.ts +++ b/tools/awslint/lib/rules/core-types.ts @@ -9,7 +9,7 @@ enum CoreTypesFqn { ConstructInterface = "@aws-cdk/cdk.IConstruct", Resource = "@aws-cdk/cdk.Resource", ResourceInterface = "@aws-cdk/cdk.IResource", - Token = "@aws-cdk/cdk.Token" + ResolvableInterface = "@aws-cdk/cdk.IResolvable" } export class CoreTypes { @@ -108,8 +108,8 @@ export class CoreTypes { /** * @returns `classType` for the core type Token */ - public get tokenClass() { - return this.sys.findClass(CoreTypesFqn.Token); + public get tokenInterface() { + return this.sys.findInterface(CoreTypesFqn.ResolvableInterface); } private readonly sys: TypeSystem; diff --git a/tools/awslint/package-lock.json b/tools/awslint/package-lock.json index c0208eb4b4c67..c25c7b75fed91 100644 --- a/tools/awslint/package-lock.json +++ b/tools/awslint/package-lock.json @@ -1,6 +1,6 @@ { "name": "awslint", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tools/cdk-build-tools/package-lock.json b/tools/cdk-build-tools/package-lock.json index 8732bd473ce42..f5d2b017ca987 100644 --- a/tools/cdk-build-tools/package-lock.json +++ b/tools/cdk-build-tools/package-lock.json @@ -1,6 +1,6 @@ { "name": "cdk-build-tools", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tools/cfn2ts/lib/codegen.ts b/tools/cfn2ts/lib/codegen.ts index 23d66fab92150..1be8f5529ec9f 100644 --- a/tools/cfn2ts/lib/codegen.ts +++ b/tools/cfn2ts/lib/codegen.ts @@ -297,9 +297,11 @@ export default class CodeGenerator { // initialize all attribute properties for (const at of attributes) { if (at.attributeType === 'string') { - this.code.line(`this.${at.propertyName} = ${at.constructorArguments}.toString();`); + this.code.line(`this.${at.propertyName} = ${CORE}.Token.asString(${at.constructorArguments});`); } else if (at.attributeType === 'string[]') { - this.code.line(`this.${at.propertyName} = ${at.constructorArguments}.toList();`); + this.code.line(`this.${at.propertyName} = ${CORE}.Token.asList(${at.constructorArguments});`); + } else if (at.attributeType === 'number') { + this.code.line(`this.${at.propertyName} = ${CORE}.Token.asNumber(${at.constructorArguments});`); } else if (at.attributeType === genspec.TOKEN_NAME.fqn) { this.code.line(`this.${at.propertyName} = ${at.constructorArguments};`); } diff --git a/tools/cfn2ts/lib/genspec.ts b/tools/cfn2ts/lib/genspec.ts index 4603e4b9b092f..4aab6695c57e5 100644 --- a/tools/cfn2ts/lib/genspec.ts +++ b/tools/cfn2ts/lib/genspec.ts @@ -88,7 +88,7 @@ export class CodeName { } export const TAG_NAME = new CodeName('', CORE_NAMESPACE, 'CfnTag'); -export const TOKEN_NAME = new CodeName('', CORE_NAMESPACE, 'Token'); +export const TOKEN_NAME = new CodeName('', CORE_NAMESPACE, 'IResolvable'); /** * Resource attribute @@ -174,6 +174,8 @@ export function attributeDefinition(resourceName: CodeName, attributeName: strin let attrType: string; if ('PrimitiveType' in spec && spec.PrimitiveType === 'String') { attrType = 'string'; + } else if ('PrimitiveType' in spec && spec.PrimitiveType === 'Integer') { + attrType = 'number'; } else if ('Type' in spec && 'PrimitiveItemType' in spec && spec.Type === 'List' && spec.PrimitiveItemType === 'String') { attrType = 'string[]'; } else { diff --git a/tools/cfn2ts/package-lock.json b/tools/cfn2ts/package-lock.json index e1708d85449e6..c42ff3294a215 100644 --- a/tools/cfn2ts/package-lock.json +++ b/tools/cfn2ts/package-lock.json @@ -1,6 +1,6 @@ { "name": "cfn2ts", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tools/pkglint/package-lock.json b/tools/pkglint/package-lock.json index 9b7315b0b241d..6243481d77d33 100644 --- a/tools/pkglint/package-lock.json +++ b/tools/pkglint/package-lock.json @@ -1,6 +1,6 @@ { "name": "pkglint", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tools/pkgtools/package-lock.json b/tools/pkgtools/package-lock.json index f1ee9dde8daae..4049b419136ad 100644 --- a/tools/pkgtools/package-lock.json +++ b/tools/pkgtools/package-lock.json @@ -1,6 +1,6 @@ { "name": "pkgtools", - "version": "0.33.0", + "version": "0.34.0", "lockfileVersion": 1, "requires": true, "dependencies": {