Skip to content

Commit

Permalink
feat(core): deprecate "Construct.node" in favor of "Construct.construct"
Browse files Browse the repository at this point in the history
To reduce the chance for conflicts with generated domain-specific properties in subclasses of `Construct` (see [terraform-cdk issue]), we decided that we will rename `node` to `construct`, which is less prevalent.

We plan to remove the `node` API in the next major version of the AWS CDK, and therefore recommend users to migrate their code to use `construct` instead.

Part of aws/aws-cdk-rfcs#192
[terraform-cdk issue]: hashicorp/terraform-cdk#230
  • Loading branch information
Elad Ben-Israel committed Aug 10, 2020
1 parent 938f326 commit 68fbdb2
Show file tree
Hide file tree
Showing 40 changed files with 296 additions and 286 deletions.
8 changes: 4 additions & 4 deletions packages/@aws-cdk/core/lib/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ export class App extends Stage {
this.loadContext(props.context);

if (props.stackTraces === false) {
this.node.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true);
this.construct.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true);
}

if (props.runtimeInfo === false) {
this.node.setContext(cxapi.DISABLE_VERSION_REPORTING, true);
this.construct.setContext(cxapi.DISABLE_VERSION_REPORTING, true);
}

const autoSynth = props.autoSynth !== undefined ? props.autoSynth : cxapi.OUTDIR_ENV in process.env;
Expand All @@ -120,7 +120,7 @@ export class App extends Stage {
private loadContext(defaults: { [key: string]: string } = { }) {
// prime with defaults passed through constructor
for (const [ k, v ] of Object.entries(defaults)) {
this.node.setContext(k, v);
this.construct.setContext(k, v);
}

// read from environment
Expand All @@ -130,7 +130,7 @@ export class App extends Stage {
: { };

for (const [ k, v ] of Object.entries(contextFromEnvironment)) {
this.node.setContext(k, v);
this.construct.setContext(k, v);
}
}
}
8 changes: 4 additions & 4 deletions packages/@aws-cdk/core/lib/asset-staging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import * as cxapi from '@aws-cdk/cx-api';
import * as fs from 'fs-extra';
import { AssetHashType, AssetOptions } from './assets';
import { BundlingOptions } from './bundling';
import { Construct } from './construct-compat';
import { FileSystem, FingerprintOptions } from './fs';
import { Stage } from './stage';
import { Construct } from './construct-compat';

const STAGING_TMP = '.cdk.staging';

Expand Down Expand Up @@ -95,7 +95,7 @@ export class AssetStaging extends Construct {

this.assetHash = this.calculateHash(props);

const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
const stagingDisabled = this.construct.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
if (stagingDisabled) {
this.stagedPath = this.bundleDir ?? this.sourcePath;
} else {
Expand Down Expand Up @@ -179,7 +179,7 @@ export class AssetStaging extends Construct {
];

try {
process.stderr.write(`Bundling asset ${this.node.path}...\n`);
process.stderr.write(`Bundling asset ${this.construct.path}...\n`);
options.image._run({
command: options.command,
user,
Expand All @@ -188,7 +188,7 @@ export class AssetStaging extends Construct {
workingDirectory: options.workingDirectory ?? AssetStaging.BUNDLING_INPUT_DIR,
});
} catch (err) {
throw new Error(`Failed to run bundling Docker image for asset ${this.node.path}: ${err}`);
throw new Error(`Failed to run bundling Docker image for asset ${this.construct.path}: ${err}`);
}

if (FileSystem.isEmpty(bundleDir)) {
Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/core/lib/cfn-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ export abstract class CfnElement extends Construct {
this.stack = Stack.of(this);

this.logicalId = Lazy.stringValue({ produce: () => this.synthesizeLogicalId() }, {
displayHint: `${notTooLong(this.node.path)}.LogicalID`,
displayHint: `${notTooLong(this.construct.path)}.LogicalID`,
});

this.node.addMetadata(cxschema.ArtifactMetadataEntryType.LOGICAL_ID, this.logicalId, this.constructor);
this.construct.addMetadata(cxschema.ArtifactMetadataEntryType.LOGICAL_ID, this.logicalId, this.constructor);
}

/**
Expand All @@ -78,7 +78,7 @@ export abstract class CfnElement extends Construct {
* node +internal+ entries filtered.
*/
public get creationStack(): string[] {
const trace = this.node.metadata.find(md => md.type === cxschema.ArtifactMetadataEntryType.LOGICAL_ID)!.trace;
const trace = this.construct.metadata.find(md => md.type === cxschema.ArtifactMetadataEntryType.LOGICAL_ID)!.trace;
if (!trace) {
return [];
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/core/lib/cfn-output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class CfnOutput extends CfnElement {
super(scope, id);

if (props.value === undefined) {
throw new Error(`Missing value for CloudFormation output at path "${this.node.path}"`);
throw new Error(`Missing value for CloudFormation output at path "${this.construct.path}"`);
}

this._description = props.description;
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/core/lib/cfn-parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ export class CfnParser {
if (!depResource) {
throw new Error(`Resource '${logicalId}' depends on '${dep}' that doesn't exist`);
}
resource.node.addDependency(depResource);
resource.construct.addDependency(depResource);
}
}

Expand Down
10 changes: 5 additions & 5 deletions packages/@aws-cdk/core/lib/cfn-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ export class CfnResource extends CfnRefElement {
// if aws:cdk:enable-path-metadata is set, embed the current construct's
// path in the CloudFormation template, so it will be possible to trace
// back to the actual construct path.
if (this.node.tryGetContext(cxapi.PATH_METADATA_ENABLE_CONTEXT)) {
this.addMetadata(cxapi.PATH_METADATA_KEY, this.node.path);
if (this.construct.tryGetContext(cxapi.PATH_METADATA_ENABLE_CONTEXT)) {
this.addMetadata(cxapi.PATH_METADATA_KEY, this.construct.path);
}
}

Expand Down Expand Up @@ -238,7 +238,7 @@ export class CfnResource extends CfnRefElement {
return;
}

addDependency(this, target, `"${this.node.path}" depends on "${target.node.path}"`);
addDependency(this, target, `"${this.construct.path}" depends on "${target.construct.path}"`);
}

/**
Expand Down Expand Up @@ -312,7 +312,7 @@ export class CfnResource extends CfnRefElement {
return ret;
} catch (e) {
// Change message
e.message = `While synthesizing ${this.node.path}: ${e.message}`;
e.message = `While synthesizing ${this.construct.path}: ${e.message}`;
// Adjust stack trace (make it look like node built it, too...)
const trace = this.creationStack;
if (trace) {
Expand All @@ -330,7 +330,7 @@ export class CfnResource extends CfnRefElement {
function renderDependsOn(dependsOn: Set<CfnResource>) {
return Array
.from(dependsOn)
.sort((x, y) => x.node.path.localeCompare(y.node.path))
.sort((x, y) => x.construct.path.localeCompare(y.construct.path))
.map(r => r.logicalId);
}

Expand Down
23 changes: 19 additions & 4 deletions packages/@aws-cdk/core/lib/construct-compat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export interface IConstruct extends constructs.IConstruct, IDependable {
* The construct tree node for this construct.
*/
readonly node: ConstructNode;

/**
* The construct tree node for this construct.
*/
readonly construct: ConstructNode;
}

/**
Expand Down Expand Up @@ -61,9 +66,18 @@ export class Construct extends constructs.Construct implements IConstruct {

/**
* The construct tree node associated with this construct.
*
* @deprecate `Construct.node` is being deprecated in favor of
* `Construct.construct`. This API will be removed in the next major version
* of the AWS CDK, please migrate your code to use `construct` instead.
*/
public readonly node: ConstructNode;

/**
* Construct API.
*/
public readonly construct: ConstructNode;

constructor(scope: Construct, id: string) {
super(scope, id, {
nodeFactory: {
Expand All @@ -78,15 +92,16 @@ export class Construct extends constructs.Construct implements IConstruct {

Object.defineProperty(this, CONSTRUCT_SYMBOL, { value: true });
this.node = ConstructNode._unwrap(constructs.Node.of(this));
this.construct = this.node;

const disableTrace =
this.node.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) ||
this.node.tryGetContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA) ||
this.construct.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) ||
this.construct.tryGetContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA) ||
process.env.CDK_DISABLE_STACK_TRACE;

if (disableTrace) {
this.node.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true);
this.node.setContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA, true);
this.construct.setContext(cxapi.DISABLE_METADATA_STACK_TRACE, true);
this.construct.setContext(constructs.ConstructMetadata.DISABLE_STACK_TRACE_IN_METADATA, true);
process.env.CDK_DISABLE_STACK_TRACE = '1';
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/core/lib/context-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export class ContextProvider {
}

const { key, props } = this.getKey(scope, options);
const value = scope.node.tryGetContext(key);
const value = scope.construct.tryGetContext(key);
const providerError = extractProviderError(value);

// if context is missing or an error occurred during context retrieval,
Expand All @@ -107,7 +107,7 @@ export class ContextProvider {
});

if (providerError !== undefined) {
scope.node.addError(providerError);
scope.construct.addError(providerError);
}
return { value: options.dummyValue };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export class CustomResourceProvider extends Construct {
public static getOrCreate(scope: Construct, uniqueid: string, props: CustomResourceProviderProps) {
const id = `${uniqueid}CustomResourceProvider`;
const stack = Stack.of(scope);
const provider = stack.node.tryFindChild(id) as CustomResourceProvider
const provider = stack.construct.tryFindChild(id) as CustomResourceProvider
?? new CustomResourceProvider(stack, id, props);

return provider.serviceToken;
Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/core/lib/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function addDependency<T extends Element>(source: T, target: T, reason?:
const targetStage = Stage.of(targetStack);
if (sourceStage !== targetStage) {
// eslint-disable-next-line max-len
throw new Error(`You cannot add a dependency from '${source.node.path}' (in ${describeStage(sourceStage)}) to '${target.node.path}' (in ${describeStage(targetStage)}): dependency cannot cross stage boundaries`);
throw new Error(`You cannot add a dependency from '${source.construct.path}' (in ${describeStage(sourceStage)}) to '${target.construct.path}' (in ${describeStage(targetStage)}): dependency cannot cross stage boundaries`);
}

// find the deepest common stack between the two elements
Expand Down Expand Up @@ -70,7 +70,7 @@ export function addDependency<T extends Element>(source: T, target: T, reason?:
// `source` is a direct or indirect nested stack of `target`, and this is not
// possible (nested stacks cannot depend on their parents).
if (commonStack === target) {
throw new Error(`Nested stack '${sourceStack.node.path}' cannot depend on a parent stack '${targetStack.node.path}': ${reason}`);
throw new Error(`Nested stack '${sourceStack.construct.path}' cannot depend on a parent stack '${targetStack.construct.path}': ${reason}`);
}

// we have a common stack from which we can reach both `source` and `target`
Expand Down Expand Up @@ -103,5 +103,5 @@ export function addDependency<T extends Element>(source: T, target: T, reason?:
function describeStage(assembly: Stage | undefined): string {
if (!assembly) { return 'an unrooted construct tree'; }
if (!assembly.parentStage) { return 'the App'; }
return `Stage '${assembly.node.path}'`;
return `Stage '${assembly.construct.path}'`;
}
4 changes: 2 additions & 2 deletions packages/@aws-cdk/core/lib/nested-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class NestedStack extends Stack {
Object.defineProperty(this, NESTED_STACK_SYMBOL, { value: true });

// this is the file name of the synthesized template file within the cloud assembly
this.templateFile = `${this.node.uniqueId}.nested.template.json`;
this.templateFile = `${this.construct.uniqueId}.nested.template.json`;

this.parameters = props.parameters || {};

Expand Down Expand Up @@ -223,7 +223,7 @@ function findParentStack(scope: Construct): Stack {
throw new Error('Nested stacks cannot be defined as a root construct');
}

const parentStack = scope.node.scopes.reverse().find(p => Stack.isStack(p));
const parentStack = scope.construct.scopes.reverse().find(p => Stack.isStack(p));
if (!parentStack) {
throw new Error('Nested stacks must be defined within scope of another non-nested stack');
}
Expand Down
7 changes: 1 addition & 6 deletions packages/@aws-cdk/core/lib/private/cfn-reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,6 @@ export class CfnReference extends Reference {
const consumingStack = Stack.of(context.scope);
const token = this.replacementTokens.get(consumingStack);

// if (!token && this.isCrossStackReference(consumingStack) && !context.preparing) {
// eslint-disable-next-line max-len
// throw new Error(`Cross-stack reference (${context.scope.node.path} -> ${this.target.node.path}) has not been assigned a value--call prepare() first`);
// }

if (token) {
return token.resolve(context);
} else {
Expand Down Expand Up @@ -138,7 +133,7 @@ export class CfnReference extends Reference {
*/
public toString(): string {
return Token.asString(this, {
displayHint: `${this.target.node.id}.${this.displayName}`,
displayHint: `${this.target.construct.id}.${this.displayName}`,
});
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/core/lib/private/physical-name-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import { TokenMap } from './token-map';
export function generatePhysicalName(resource: IResource): string {
const stack = Stack.of(resource);
const stackPart = new PrefixNamePart(stack.stackName, 25);
const idPart = new SuffixNamePart(resource.node.uniqueId, 24);
const idPart = new SuffixNamePart(resource.construct.uniqueId, 24);

const region: string = stack.region;
if (Token.isUnresolved(region) || !region) {
throw new Error(`Cannot generate a physical name for ${resource.node.path}, because the region is un-resolved or missing`);
throw new Error(`Cannot generate a physical name for ${resource.construct.path}, because the region is un-resolved or missing`);
}

const account: string = stack.account;
if (Token.isUnresolved(account) || !account) {
throw new Error(`Cannot generate a physical name for ${resource.node.path}, because the account is un-resolved or missing`);
throw new Error(`Cannot generate a physical name for ${resource.construct.path}, because the account is un-resolved or missing`);
}

const parts = [stackPart, idPart]
Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/core/lib/private/prepare-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { resolveReferences } from './refs';
*/
export function prepareApp(root: IConstruct) {
// apply dependencies between resources in depending subtrees
for (const dependency of root.node.dependencies) {
for (const dependency of root.construct.dependencies) {
const targetCfnResources = findCfnResources(dependency.target);
const sourceCfnResources = findCfnResources(dependency.source);

Expand Down Expand Up @@ -71,7 +71,7 @@ function findAllNestedStacks(root: IConstruct) {

// create a list of all nested stacks in depth-first post order this means
// that we first prepare the leaves and then work our way up.
for (const stack of root.node.findAll(ConstructOrder.POSTORDER /* <== important */)) {
for (const stack of root.construct.findAll(ConstructOrder.POSTORDER /* <== important */)) {
if (includeStack(stack)) {
result.push(stack);
}
Expand All @@ -84,7 +84,7 @@ function findAllNestedStacks(root: IConstruct) {
* Find all resources in a set of constructs
*/
function findCfnResources(root: IConstruct): CfnResource[] {
return root.node.findAll().filter(CfnResource.isCfnResource);
return root.construct.findAll().filter(CfnResource.isCfnResource);
}

interface INestedStackPrivateApi {
Expand Down
Loading

0 comments on commit 68fbdb2

Please sign in to comment.