diff --git a/packages/@aws-cdk/aws-cloudformation-codepipeline/lib/pipeline-actions.ts b/packages/@aws-cdk/aws-cloudformation-codepipeline/lib/pipeline-actions.ts index 7b5dee76168eb..69209fe58bae2 100644 --- a/packages/@aws-cdk/aws-cloudformation-codepipeline/lib/pipeline-actions.ts +++ b/packages/@aws-cdk/aws-cloudformation-codepipeline/lib/pipeline-actions.ts @@ -53,7 +53,7 @@ export abstract class CloudFormationAction extends codepipeline.DeployAction { }); if (props.outputFileName) { - this.artifact = this.addOutputArtifact(props.outputArtifactName || (parent.name + this.name + 'Artifact')); + this.artifact = this.addOutputArtifact(props.outputArtifactName || (parent.id + this.id + 'Artifact')); } } } diff --git a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts index 5fbbe2605f1d7..0fc363819d073 100644 --- a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts @@ -174,7 +174,7 @@ export class CloudTrail extends cdk.Construct { includeGlobalServiceEvents: props.includeGlobalServiceEvents == null ? true : props.includeGlobalServiceEvents, trailName: props.trailName, kmsKeyId: props.kmsKey && props.kmsKey.keyArn, - s3BucketName: s3bucket.name, + s3BucketName: s3bucket.bucketName, s3KeyPrefix: props.s3KeyPrefix, cloudWatchLogsLogGroupArn: this.cloudWatchLogsGroupArn, cloudWatchLogsRoleArn: this.cloudWatchLogsRoleArn, diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index 1fc3925b3c26b..48120f478fa55 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -266,7 +266,7 @@ export abstract class ProjectRef extends cdk.Construct implements events.IEventR } return { - id: this.name, + id: this.id, arn: this.projectArn, roleArn: this.eventsRole.roleArn, }; diff --git a/packages/@aws-cdk/aws-codepipeline/lib/actions.ts b/packages/@aws-cdk/aws-codepipeline/lib/actions.ts index 5b89af927f753..805835c43fb8a 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/actions.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/actions.ts @@ -152,7 +152,7 @@ export abstract class Action extends cdk.Construct { */ public render(): cloudformation.PipelineResource.ActionDeclarationProperty { return { - name: this.name, + name: this.id, inputArtifacts: this.inputArtifacts.map(a => ({ name: a.name })), actionTypeId: { category: this.category.toString(), @@ -174,8 +174,8 @@ export abstract class Action extends cdk.Construct { source: [ 'aws.codepipeline' ], resources: [ this.stage.pipeline.pipelineArn ], detail: { - stage: [ this.stage.name ], - action: [ this.name ], + stage: [ this.stage.id ], + action: [ this.id ], }, }); return rule; diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 7b72cbfe7ec01..5520436fac94d 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -164,7 +164,7 @@ export class Pipeline extends cdk.Construct implements events.IEventRuleTarget { } return { - id: this.name, + id: this.id, arn: this.pipelineArn, roleArn: this.eventsRole.roleArn, }; @@ -224,8 +224,8 @@ export class Pipeline extends cdk.Construct implements events.IEventRuleTarget { } private appendStage(stage: Stage) { - if (this.stages.find(x => x.name === stage.name)) { - throw new Error(`A stage with name '${stage.name}' already exists`); + if (this.stages.find(x => x.id === stage.id)) { + throw new Error(`A stage with name '${stage.id}' already exists`); } this.stages.push(stage); @@ -235,7 +235,7 @@ export class Pipeline extends cdk.Construct implements events.IEventRuleTarget { return util.flatMap(this.stages, (stage, i) => { const onlySourceActionsPermitted = i === 0; return util.flatMap(stage.actions, (action, _) => - validation.validateSourceAction(onlySourceActionsPermitted, action.category, action.name, stage.name) + validation.validateSourceAction(onlySourceActionsPermitted, action.category, action.id, stage.id) ); }); } diff --git a/packages/@aws-cdk/aws-codepipeline/lib/stage.ts b/packages/@aws-cdk/aws-codepipeline/lib/stage.ts index 3f74cf9db9985..65cbc7ddfc541 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/stage.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/stage.ts @@ -46,7 +46,7 @@ export class Stage extends cdk.Construct { public render(): cloudformation.PipelineResource.StageDeclarationProperty { return { - name: this.name, + name: this.id, actions: this._actions.map(action => action.render()) }; } @@ -59,7 +59,7 @@ export class Stage extends cdk.Construct { source: [ 'aws.codepipeline' ], resources: [ this.pipeline.pipelineArn ], detail: { - stage: [ this.name ], + stage: [ this.id ], }, }); return rule; @@ -84,7 +84,7 @@ export class Stage extends cdk.Construct { private validateHasActions(): string[] { if (this._actions.length === 0) { - return [`Stage '${this.name}' must have at least one action`]; + return [`Stage '${this.id}' must have at least one action`]; } return []; } diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts index 862cacd238e6a..9bf961f808fbf 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts @@ -185,7 +185,7 @@ export abstract class FunctionRef extends cdk.Construct } return { - id: this.name, + id: this.id, arn: this.functionArn, }; } diff --git a/packages/@aws-cdk/aws-sns/lib/topic-ref.ts b/packages/@aws-cdk/aws-sns/lib/topic-ref.ts index c5476d05c4cb9..563915b5cc65c 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic-ref.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic-ref.ts @@ -80,9 +80,9 @@ export abstract class TopicRef extends cdk.Construct implements events.IEventRul * @param queue The target queue */ public subscribeQueue(queue: sqs.QueueRef) { - const subscriptionName = queue.name + 'Subscription'; + const subscriptionName = queue.id + 'Subscription'; if (this.tryFindChild(subscriptionName)) { - throw new Error(`A subscription between the topic ${this.name} and the queue ${queue.name} already exists`); + throw new Error(`A subscription between the topic ${this.id} and the queue ${queue.id} already exists`); } // we use the queue name as the subscription's. there's no meaning to subscribing @@ -114,10 +114,10 @@ export abstract class TopicRef extends cdk.Construct implements events.IEventRul * @param lambdaFunction The Lambda function to invoke */ public subscribeLambda(lambdaFunction: lambda.FunctionRef) { - const subscriptionName = lambdaFunction.name + 'Subscription'; + const subscriptionName = lambdaFunction.id + 'Subscription'; if (this.tryFindChild(subscriptionName)) { - throw new Error(`A subscription between the topic ${this.name} and the lambda ${lambdaFunction.name} already exists`); + throw new Error(`A subscription between the topic ${this.id} and the lambda ${lambdaFunction.id} already exists`); } const sub = new Subscription(this, subscriptionName, { @@ -126,7 +126,7 @@ export abstract class TopicRef extends cdk.Construct implements events.IEventRul protocol: SubscriptionProtocol.Lambda }); - lambdaFunction.addPermission(this.name, { + lambdaFunction.addPermission(this.id, { sourceArn: this.topicArn, principal: new cdk.ServicePrincipal('sns.amazonaws.com'), }); @@ -223,7 +223,7 @@ export abstract class TopicRef extends cdk.Construct implements events.IEventRul } return { - id: this.name, + id: this.id, arn: this.topicArn, }; } diff --git a/packages/@aws-cdk/cdk/lib/cloudformation/logical-id.ts b/packages/@aws-cdk/cdk/lib/cloudformation/logical-id.ts index 5f89093795981..b1a30a40b84d7 100644 --- a/packages/@aws-cdk/cdk/lib/cloudformation/logical-id.ts +++ b/packages/@aws-cdk/cdk/lib/cloudformation/logical-id.ts @@ -1,5 +1,5 @@ import { makeUniqueId } from '../util/uniqueid'; -import { StackElement } from "./stack"; +import { StackElement } from './stack'; const PATH_SEP = '/'; diff --git a/packages/@aws-cdk/cdk/lib/cloudformation/stack.ts b/packages/@aws-cdk/cdk/lib/cloudformation/stack.ts index 9afe7265bdec4..9f1b4a799a8fb 100644 --- a/packages/@aws-cdk/cdk/lib/cloudformation/stack.ts +++ b/packages/@aws-cdk/cdk/lib/cloudformation/stack.ts @@ -86,10 +86,16 @@ export class Stack extends Construct { */ public readonly templateOptions: TemplateOptions = {}; + /** + * The CloudFormation stack name. + */ + public readonly name: string; + /** * Creates a new stack. * * @param parent Parent of this stack, usually a Program instance. + * @param name The name of the CloudFormation stack. Defaults to "Stack". * @param props Stack properties. */ public constructor(parent?: App, name?: string, props?: StackProps) { @@ -98,6 +104,7 @@ export class Stack extends Construct { this.env = this.parseEnvironment(props); this.logicalIds = new LogicalIDs(props && props.namingScheme ? props.namingScheme : new HashedAddressingScheme()); + this.name = name || 'Stack'; } /** @@ -195,7 +202,7 @@ export class Stack extends Construct { * CloudFormation stack names can include dashes in addition to the regular identifier * character classes, and we don't allow one of the magic markers. */ - protected _validateName(name: string) { + protected _validateId(name: string) { if (!Stack.VALID_STACK_NAME_REGEX.test(name)) { throw new Error(`Stack name must match the regular expression: ${Stack.VALID_STACK_NAME_REGEX.toString()}, got '${name}'`); } diff --git a/packages/@aws-cdk/cdk/lib/core/construct.ts b/packages/@aws-cdk/cdk/lib/core/construct.ts index 3b52c7092b7d1..16fd813a89130 100644 --- a/packages/@aws-cdk/cdk/lib/core/construct.ts +++ b/packages/@aws-cdk/cdk/lib/core/construct.ts @@ -13,13 +13,9 @@ export class Construct { public readonly parent?: Construct; /** - * @deprecated use `id` - */ - public readonly name: string; - - /** - * The subtree-local id of the construct. - * This id is unique within the subtree. To obtain a tree-unique id, use `uniqueId`. + * The local id of the construct. + * This id is unique amongst its siblings. + * To obtain a tree-global unique id for this construct, use `uniqueId`. */ public readonly id: string; @@ -30,7 +26,7 @@ export class Construct { public readonly path: string; /** - * A tree-unique alpha-numeric identifier for this construct. + * A tree-global unique alphanumeric identifier for this construct. * Includes all components of the tree. */ public readonly uniqueId: string; @@ -56,7 +52,6 @@ export class Construct { */ constructor(parent: Construct, id: string) { this.id = id; - this.name = id; // legacy this.parent = parent; // We say that parent is required, but some root constructs bypass the type checks and @@ -75,7 +70,7 @@ export class Construct { // Validate the name we ended up with if (this.id !== '') { - this._validateName(this.id); + this._validateId(this.id); } const components = this.rootPath().map(c => c.id); @@ -294,12 +289,12 @@ export class Construct { } /** - * Validate that the name of the construct is a legal identifier. - * Construct names can be any characters besides the path separator. + * Validate that the id of the construct legal. + * Construct IDs can be any characters besides the path separator. */ - protected _validateName(name: string) { - if (name.indexOf(PATH_SEP) !== -1) { - throw new Error(`Construct names cannot include '${PATH_SEP}': ${name}`); + protected _validateId(id: string) { + if (id.indexOf(PATH_SEP) !== -1) { + throw new Error(`Construct names cannot include '${PATH_SEP}': ${id}`); } } diff --git a/packages/@aws-cdk/cdk/lib/util/.gitignore b/packages/@aws-cdk/cdk/lib/util/.gitignore deleted file mode 100644 index f3e1fe1de16f9..0000000000000 --- a/packages/@aws-cdk/cdk/lib/util/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -!md5.js - diff --git a/packages/@aws-cdk/cdk/lib/util/md5.js b/packages/@aws-cdk/cdk/lib/util/md5.js deleted file mode 100644 index 762de3c52012a..0000000000000 --- a/packages/@aws-cdk/cdk/lib/util/md5.js +++ /dev/null @@ -1,280 +0,0 @@ -/* - * JavaScript MD5 - * https://github.com/blueimp/JavaScript-MD5 - * - * Copyright 2011, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * https://opensource.org/licenses/MIT - * - * Based on - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * Distributed under the BSD License - * See http://pajhome.org.uk/crypt/md5 for more info. - */ - -/* global define */ - -;(function ($) { - 'use strict' - - /* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ - function safeAdd (x, y) { - var lsw = (x & 0xffff) + (y & 0xffff) - var msw = (x >> 16) + (y >> 16) + (lsw >> 16) - return (msw << 16) | (lsw & 0xffff) - } - - /* - * Bitwise rotate a 32-bit number to the left. - */ - function bitRotateLeft (num, cnt) { - return (num << cnt) | (num >>> (32 - cnt)) - } - - /* - * These functions implement the four basic operations the algorithm uses. - */ - function md5cmn (q, a, b, x, s, t) { - return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b) - } - function md5ff (a, b, c, d, x, s, t) { - return md5cmn((b & c) | (~b & d), a, b, x, s, t) - } - function md5gg (a, b, c, d, x, s, t) { - return md5cmn((b & d) | (c & ~d), a, b, x, s, t) - } - function md5hh (a, b, c, d, x, s, t) { - return md5cmn(b ^ c ^ d, a, b, x, s, t) - } - function md5ii (a, b, c, d, x, s, t) { - return md5cmn(c ^ (b | ~d), a, b, x, s, t) - } - - /* - * Calculate the MD5 of an array of little-endian words, and a bit length. - */ - function binlMD5 (x, len) { - /* append padding */ - x[len >> 5] |= 0x80 << (len % 32) - x[((len + 64) >>> 9 << 4) + 14] = len - - var i - var olda - var oldb - var oldc - var oldd - var a = 1732584193 - var b = -271733879 - var c = -1732584194 - var d = 271733878 - - for (i = 0; i < x.length; i += 16) { - olda = a - oldb = b - oldc = c - oldd = d - - a = md5ff(a, b, c, d, x[i], 7, -680876936) - d = md5ff(d, a, b, c, x[i + 1], 12, -389564586) - c = md5ff(c, d, a, b, x[i + 2], 17, 606105819) - b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330) - a = md5ff(a, b, c, d, x[i + 4], 7, -176418897) - d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426) - c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341) - b = md5ff(b, c, d, a, x[i + 7], 22, -45705983) - a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416) - d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417) - c = md5ff(c, d, a, b, x[i + 10], 17, -42063) - b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162) - a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682) - d = md5ff(d, a, b, c, x[i + 13], 12, -40341101) - c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290) - b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329) - - a = md5gg(a, b, c, d, x[i + 1], 5, -165796510) - d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632) - c = md5gg(c, d, a, b, x[i + 11], 14, 643717713) - b = md5gg(b, c, d, a, x[i], 20, -373897302) - a = md5gg(a, b, c, d, x[i + 5], 5, -701558691) - d = md5gg(d, a, b, c, x[i + 10], 9, 38016083) - c = md5gg(c, d, a, b, x[i + 15], 14, -660478335) - b = md5gg(b, c, d, a, x[i + 4], 20, -405537848) - a = md5gg(a, b, c, d, x[i + 9], 5, 568446438) - d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690) - c = md5gg(c, d, a, b, x[i + 3], 14, -187363961) - b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501) - a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467) - d = md5gg(d, a, b, c, x[i + 2], 9, -51403784) - c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473) - b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734) - - a = md5hh(a, b, c, d, x[i + 5], 4, -378558) - d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463) - c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562) - b = md5hh(b, c, d, a, x[i + 14], 23, -35309556) - a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060) - d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353) - c = md5hh(c, d, a, b, x[i + 7], 16, -155497632) - b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640) - a = md5hh(a, b, c, d, x[i + 13], 4, 681279174) - d = md5hh(d, a, b, c, x[i], 11, -358537222) - c = md5hh(c, d, a, b, x[i + 3], 16, -722521979) - b = md5hh(b, c, d, a, x[i + 6], 23, 76029189) - a = md5hh(a, b, c, d, x[i + 9], 4, -640364487) - d = md5hh(d, a, b, c, x[i + 12], 11, -421815835) - c = md5hh(c, d, a, b, x[i + 15], 16, 530742520) - b = md5hh(b, c, d, a, x[i + 2], 23, -995338651) - - a = md5ii(a, b, c, d, x[i], 6, -198630844) - d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415) - c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905) - b = md5ii(b, c, d, a, x[i + 5], 21, -57434055) - a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571) - d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606) - c = md5ii(c, d, a, b, x[i + 10], 15, -1051523) - b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799) - a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359) - d = md5ii(d, a, b, c, x[i + 15], 10, -30611744) - c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380) - b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649) - a = md5ii(a, b, c, d, x[i + 4], 6, -145523070) - d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379) - c = md5ii(c, d, a, b, x[i + 2], 15, 718787259) - b = md5ii(b, c, d, a, x[i + 9], 21, -343485551) - - a = safeAdd(a, olda) - b = safeAdd(b, oldb) - c = safeAdd(c, oldc) - d = safeAdd(d, oldd) - } - return [a, b, c, d] - } - - /* - * Convert an array of little-endian words to a string - */ - function binl2rstr (input) { - var i - var output = '' - var length32 = input.length * 32 - for (i = 0; i < length32; i += 8) { - output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff) - } - return output - } - - /* - * Convert a raw string to an array of little-endian words - * Characters >255 have their high-byte silently ignored. - */ - function rstr2binl (input) { - var i - var output = [] - output[(input.length >> 2) - 1] = undefined - for (i = 0; i < output.length; i += 1) { - output[i] = 0 - } - var length8 = input.length * 8 - for (i = 0; i < length8; i += 8) { - output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32) - } - return output - } - - /* - * Calculate the MD5 of a raw string - */ - function rstrMD5 (s) { - return binl2rstr(binlMD5(rstr2binl(s), s.length * 8)) - } - - /* - * Calculate the HMAC-MD5, of a key and some data (raw strings) - */ - function rstrHMACMD5 (key, data) { - var i - var bkey = rstr2binl(key) - var ipad = [] - var opad = [] - var hash - ipad[15] = opad[15] = undefined - if (bkey.length > 16) { - bkey = binlMD5(bkey, key.length * 8) - } - for (i = 0; i < 16; i += 1) { - ipad[i] = bkey[i] ^ 0x36363636 - opad[i] = bkey[i] ^ 0x5c5c5c5c - } - hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8) - return binl2rstr(binlMD5(opad.concat(hash), 512 + 128)) - } - - /* - * Convert a raw string to a hex string - */ - function rstr2hex (input) { - var hexTab = '0123456789abcdef' - var output = '' - var x - var i - for (i = 0; i < input.length; i += 1) { - x = input.charCodeAt(i) - output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f) - } - return output - } - - /* - * Encode a string as utf-8 - */ - function str2rstrUTF8 (input) { - return unescape(encodeURIComponent(input)) - } - - /* - * Take string arguments and return either raw or hex encoded strings - */ - function rawMD5 (s) { - return rstrMD5(str2rstrUTF8(s)) - } - function hexMD5 (s) { - return rstr2hex(rawMD5(s)) - } - function rawHMACMD5 (k, d) { - return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d)) - } - function hexHMACMD5 (k, d) { - return rstr2hex(rawHMACMD5(k, d)) - } - - function md5 (string, key, raw) { - if (!key) { - if (!raw) { - return hexMD5(string) - } - return rawMD5(string) - } - if (!raw) { - return hexHMACMD5(key, string) - } - return rawHMACMD5(key, string) - } - - if (typeof define === 'function' && define.amd) { - define(function () { - return md5 - }) - } else if (typeof module === 'object' && module.exports) { - module.exports = md5 - } else { - $.md5 = md5 - } -})(this) diff --git a/packages/@aws-cdk/cdk/lib/util/uniqueid.ts b/packages/@aws-cdk/cdk/lib/util/uniqueid.ts index 6c7e27a87ebf9..43edf7286c47f 100644 --- a/packages/@aws-cdk/cdk/lib/util/uniqueid.ts +++ b/packages/@aws-cdk/cdk/lib/util/uniqueid.ts @@ -1,5 +1,5 @@ // tslint:disable-next-line:no-var-requires -const md5 = require('./md5'); +import crypto = require('crypto'); /** * Resources with this ID are hidden from humans @@ -20,17 +20,19 @@ const HASH_LEN = 8; const MAX_HUMAN_LEN = 240; // max ID len is 255 /** - * Given a set of named path components, returns a unique alpha-numeric identifier - * with a maximum length of 255. This is done by calculating a hash on the full path - * and using it as a suffix of a length-limited "human" rendition of the path components. + * Calculates a unique ID for a set of textual components. + * + * This is done by calculating a hash on the full path and using it as a suffix + * of a length-limited "human" rendition of the path components. * * @param components The path components + * @returns a unique alpha-numeric identifier with a maximum length of 255 */ export function makeUniqueId(components: string[]) { components = components.filter(x => x !== HIDDEN_ID); if (components.length === 0) { - throw new Error('Unable to calculate a unique ID for an empty path'); + throw new Error('Unable to calculate a unique id for an empty set of components'); } // top-level resources will simply use the `name` as-is in order to support @@ -42,8 +44,8 @@ export function makeUniqueId(components: string[]) { const hash = pathHash(components); const human = removeDupes(components) - .map(removeNonAlpha) .filter(x => x !== HIDDEN_FROM_HUMAN_ID) + .map(removeNonAlphanumeric) .join('') .slice(0, MAX_HUMAN_LEN); @@ -56,21 +58,22 @@ export function makeUniqueId(components: string[]) { * The hash is limited in size. */ function pathHash(path: string[]): string { - return md5(path.join(PATH_SEP)).slice(0, HASH_LEN).toUpperCase(); + const md5 = crypto.createHash('md5').update(path.join(PATH_SEP)).digest("hex"); + return md5.slice(0, HASH_LEN).toUpperCase(); } /** * Removes all non-alphanumeric characters in a string. */ -function removeNonAlpha(s: string) { +function removeNonAlphanumeric(s: string) { return s.replace(/[^A-Za-z0-9]/g, ''); } /** * Remove duplicate "terms" from the path list * - * If a component name is completely the same as the suffix of - * the previous component name, we get rid of it. + * If the previous path component name ends with this component name, skip the + * current component. */ function removeDupes(path: string[]): string[] { const ret = new Array(); diff --git a/packages/@aws-cdk/cdk/test/core/test.construct.ts b/packages/@aws-cdk/cdk/test/core/test.construct.ts index 70d4c80577d59..c7a563beb2d4b 100644 --- a/packages/@aws-cdk/cdk/test/core/test.construct.ts +++ b/packages/@aws-cdk/cdk/test/core/test.construct.ts @@ -67,6 +67,12 @@ export = { test.done(); }, + 'cannot calculate uniqueId if the construct path is ["Default"]'(test: Test) { + const root = new Root(); + test.throws(() => new Construct(root, 'Default'), /Unable to calculate a unique id for an empty set of components/); + test.done(); + }, + 'construct.getChildren() returns an array of all children'(test: Test) { const root = new Root(); const child = new Construct(root, 'Child1'); @@ -424,7 +430,7 @@ class ConstructWithRequired extends Construct { * Construct that *must* be named "Spartacus" */ class IAmSpartacusConstruct extends Construct { - protected _validateName(name: string) { + protected _validateId(name: string) { if (name !== "Spartacus") { throw new Error("Construct name must be 'Spartacus'"); }