diff --git a/packages/@aws-cdk/core/lib/aspect.ts b/packages/@aws-cdk/core/lib/aspect.ts index e892336d22f26..0ccc0aa90f964 100644 --- a/packages/@aws-cdk/core/lib/aspect.ts +++ b/packages/@aws-cdk/core/lib/aspect.ts @@ -1,5 +1,7 @@ import { IConstruct } from 'constructs'; +const ASPECTS_SYMBOL = Symbol('cdk-aspects'); + /** * Represents an Aspect */ @@ -10,8 +12,6 @@ export interface IAspect { visit(node: IConstruct): void; } -const ASPECTS_SYMBOL = Symbol('cdk-aspects'); - /** * Aspects can be applied to CDK tree scopes and can operate on the tree before * synthesis. @@ -25,8 +25,10 @@ export class Aspects { public static of(scope: IConstruct): Aspects { let aspects = (scope as any)[ASPECTS_SYMBOL]; if (!aspects) { - aspects = Object.defineProperty(scope, ASPECTS_SYMBOL, { - value: new Aspects(scope), + aspects = new Aspects(scope); + + Object.defineProperty(scope, ASPECTS_SYMBOL, { + value: aspects, configurable: false, enumerable: false, }); @@ -36,13 +38,13 @@ export class Aspects { private readonly _aspects = new Array(); - private constructor(_construct: IConstruct) { } + private constructor(private readonly scope: IConstruct) { } /** - * Apply an aspect on this scope. - * @param aspect The aspect to apply. + * Adds an aspect to apply this scope before synthesis. + * @param aspect The aspect to add. */ - public apply(aspect: IAspect) { + public add(aspect: IAspect) { this._aspects.push(aspect); } @@ -52,4 +54,4 @@ export class Aspects { public get aspects(): IAspect[] { return [ ...this._aspects ]; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/core/lib/construct-compat.ts b/packages/@aws-cdk/core/lib/construct-compat.ts deleted file mode 100644 index 1f6d7ee117feb..0000000000000 --- a/packages/@aws-cdk/core/lib/construct-compat.ts +++ /dev/null @@ -1,372 +0,0 @@ -/** - * Constructs compatibility layer. - * - * This file includes types that shadow types in the "constructs" module in - * order to allow backwards-compatiblity in the AWS CDK v1.0 release line. - * - * There are pretty ugly hacks here, which mostly involve downcasting types to - * adhere to legacy AWS CDK APIs. - * - * This file, in its entirety, is expected to be removed in v2.0. - */ - -// import * as cxschema from '@aws-cdk/cloud-assembly-schema'; -// import * as cxapi from '@aws-cdk/cx-api'; -// import * as constructs from 'constructs'; -// import { IAspect } from './aspect'; -// import { IDependable } from './dependency'; -// import { Token } from './token'; - -// const ORIGINAL_CONSTRUCT_NODE_SYMBOL = Symbol.for('@aws-cdk/core.ConstructNode'); -// const CONSTRUCT_SYMBOL = Symbol.for('@aws-cdk/core.Construct'); - -// /** -// * Represents a construct. -// */ -// export interface IConstruct extends constructs.IConstruct, IDependable { -// /** -// * The construct tree node for this construct. -// */ -// readonly node: ConstructNode; -// } - -// /** -// * Represents the building block of the construct graph. -// * -// * All constructs besides the root construct must be created within the scope of -// * another construct. -// */ -// export class Construct extends constructs.Construct implements IConstruct { -// /** -// * Return whether the given object is a Construct -// */ -// public static isConstruct(x: any): x is Construct { -// return typeof x === 'object' && x !== null && CONSTRUCT_SYMBOL in x; -// } - -// /** -// * The construct tree node associated with this construct. -// */ -// public readonly node: ConstructNode; - -// constructor(scope: Construct, id: string) { -// super(scope, id, { -// nodeFactory: { -// createNode: (h: constructs.Construct, s: constructs.IConstruct, i: string) => -// new ConstructNode(h as Construct, s as IConstruct, i)._actualNode, -// }, -// }); - -// if (Token.isUnresolved(id)) { -// throw new Error(`Cannot use tokens in construct ID: ${id}`); -// } - -// Object.defineProperty(this, CONSTRUCT_SYMBOL, { value: true }); -// this.node = ConstructNode._unwrap(constructs.Node.of(this)); - -// const disableTrace = -// this.node.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) || -// this.node.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); -// process.env.CDK_DISABLE_STACK_TRACE = '1'; -// } -// } - -// /** -// * Validate the current construct. -// * -// * This method can be implemented by derived constructs in order to perform -// * validation logic. It is called on all constructs before synthesis. -// * -// * @returns An array of validation error messages, or an empty array if the construct is valid. -// */ -// protected onValidate(): string[] { -// return this.validate(); -// } - -// /** -// * Perform final modifications before synthesis -// * -// * This method can be implemented by derived constructs in order to perform -// * final changes before synthesis. prepare() will be called after child -// * constructs have been prepared. -// * -// * This is an advanced framework feature. Only use this if you -// * understand the implications. -// */ -// protected onPrepare(): void { -// this.prepare(); -// } - -// /** -// * Allows this construct to emit artifacts into the cloud assembly during synthesis. -// * -// * This method is usually implemented by framework-level constructs such as `Stack` and `Asset` -// * as they participate in synthesizing the cloud assembly. -// * -// * @param session The synthesis session. -// */ -// protected onSynthesize(session: constructs.ISynthesisSession): void { -// this.synthesize({ -// outdir: session.outdir, -// assembly: session.assembly!, -// }); -// } - -// /** -// * Validate the current construct. -// * -// * This method can be implemented by derived constructs in order to perform -// * validation logic. It is called on all constructs before synthesis. -// * -// * @returns An array of validation error messages, or an empty array if the construct is valid. -// */ -// protected validate(): string[] { -// return []; -// } - -// /** -// * Perform final modifications before synthesis -// * -// * This method can be implemented by derived constructs in order to perform -// * final changes before synthesis. prepare() will be called after child -// * constructs have been prepared. -// * -// * This is an advanced framework feature. Only use this if you -// * understand the implications. -// */ -// protected prepare(): void { -// return; -// } - -// /** -// * Allows this construct to emit artifacts into the cloud assembly during synthesis. -// * -// * This method is usually implemented by framework-level constructs such as `Stack` and `Asset` -// * as they participate in synthesizing the cloud assembly. -// * -// * @param session The synthesis session. -// */ -// protected synthesize(session: ISynthesisSession): void { -// ignore(session); -// } -// } - -// /** -// * Represents the construct node in the scope tree. -// */ -// export class ConstructNode { -// /** -// * Separator used to delimit construct path components. -// */ -// public static readonly PATH_SEP = '/'; - -// /** -// * Returns the wrapping `@aws-cdk/core.ConstructNode` instance from a `constructs.ConstructNode`. -// * -// * @internal -// */ -// public static _unwrap(c: constructs.Node): ConstructNode { -// const x = (c as any)[ORIGINAL_CONSTRUCT_NODE_SYMBOL]; -// if (!x) { -// throw new Error('invalid ConstructNode type'); -// } - -// return x; -// } - -// /** -// * Synthesizes a CloudAssembly from a construct tree. -// * @param node The root of the construct tree. -// * @param options Synthesis options. -// * @deprecated Use `app.synth()` or `stage.synth()` instead -// */ -// public static synth(node: ConstructNode, options: SynthesisOptions = { }): cxapi.CloudAssembly { -// // eslint-disable-next-line @typescript-eslint/no-require-imports -// const a: typeof import('././private/synthesis') = require('./private/synthesis'); -// return a.synthesize(node.root, options); -// } - -// /** -// * Invokes "prepare" on all constructs (depth-first, post-order) in the tree under `node`. -// * @param node The root node -// * @deprecated Use `app.synth()` instead -// */ -// public static prepare(node: ConstructNode) { -// // eslint-disable-next-line @typescript-eslint/no-require-imports -// const p: typeof import('./private/prepare-app') = require('./private/prepare-app'); -// p.prepareApp(node.root); // resolve cross refs and nested stack assets. -// return node._actualNode.prepare(); -// } - -// /** -// * Invokes "validate" on all constructs in the tree (depth-first, pre-order) and returns -// * the list of all errors. An empty list indicates that there are no errors. -// * -// * @param node The root node -// */ -// public static validate(node: ConstructNode): ValidationError[] { -// return node._actualNode.validate().map(e => ({ source: e.source as Construct, message: e.message })); -// } - -// /** -// * @internal -// */ -// public readonly _actualNode: constructs.Node; - -// constructor(host: Construct, scope: IConstruct, id: string) { -// this._actualNode = new constructs.Node(host, scope, id); - -// // store a back reference on _actualNode so we can our ConstructNode from it -// Object.defineProperty(this._actualNode, ORIGINAL_CONSTRUCT_NODE_SYMBOL, { -// value: this, -// configurable: false, -// enumerable: false, -// }); -// } - -// /** -// * Returns the scope in which this construct is defined. -// * -// * The value is `undefined` at the root of the construct scope tree. -// */ -// public get scope(): IConstruct | undefined { -// return this._actualNode.scope as IConstruct; -// } - -// /** -// * The id of this construct within the current scope. -// * -// * This is a a scope-unique id. To obtain an app-unique id for this construct, use `uniqueId`. -// */ -// public get id() { return this._actualNode.id; } - -// /** -// * The full, absolute path of this construct in the tree. -// * -// * Components are separated by '/'. -// */ -// public get path(): string { return this._actualNode.path; } - -// /** -// * A tree-global unique alphanumeric identifier for this construct. -// * Includes all components of the tree. -// */ -// public get uniqueId(): string { return this._actualNode.uniqueId; } - -// /** -// * Return a direct child by id, or undefined -// * -// * @param id Identifier of direct child -// * @returns the child if found, or undefined -// */ -// public tryFindChild(id: string): IConstruct | undefined { return this._actualNode.tryFindChild(id) as IConstruct; } - -// /** -// * Return a direct child by id -// * -// * Throws an error if the child is not found. -// * -// * @param id Identifier of direct child -// * @returns Child with the given id. -// */ -// public findChild(id: string): IConstruct { return this._actualNode.findChild(id) as IConstruct; } - -// /** -// * Returns the child construct that has the id `Default` or `Resource"`. -// * This is usually the construct that provides the bulk of the underlying functionality. -// * Useful for modifications of the underlying construct that are not available at the higher levels. -// * -// * @throws if there is more than one child -// * @returns a construct or undefined if there is no default child -// */ -// public get defaultChild(): IConstruct | undefined { return this._actualNode.defaultChild as IConstruct; } - -// /** -// * Override the defaultChild property. -// * -// * This should only be used in the cases where the correct -// * default child is not named 'Resource' or 'Default' as it -// * should be. -// * -// * If you set this to undefined, the default behavior of finding -// * the child named 'Resource' or 'Default' will be used. -// */ -// public set defaultChild(value: IConstruct | undefined) { this._actualNode.defaultChild = value; } - -// /** -// * All direct children of this construct. -// */ -// public get children(): IConstruct[] { return this._actualNode.children as IConstruct[]; } - -// /** -// * Return this construct and all of its children in the given order -// */ -// public findAll(order: ConstructOrder = ConstructOrder.PREORDER): IConstruct[] { return this._actualNode.findAll(order) as IConstruct[]; } - -// /** -// * This can be used to set contextual values. -// * Context must be set before any children are added, since children may consult context info during construction. -// * If the key already exists, it will be overridden. -// * @param key The context key -// * @param value The context value -// */ -// public setContext(key: string, value: any) { -// if (Token.isUnresolved(key)) { -// throw new Error('Invalid context key: context keys can\'t include tokens'); -// } -// this._actualNode.setContext(key, value); -// } - -// /** -// * Retrieves a value from tree context. -// * -// * Context is usually initialized at the root, but can be overridden at any point in the tree. -// * -// * @param key The context key -// * @returns The context value or `undefined` if there is no context value for thie key. -// */ -// public tryGetContext(key: string): any { -// if (Token.isUnresolved(key)) { -// throw new Error('Invalid context key: context keys can\'t include tokens'); -// } -// return this._actualNode.tryGetContext(key); -// } - -// /** -// * An immutable array of metadata objects associated with this construct. -// * This can be used, for example, to implement support for deprecation notices, source mapping, etc. -// */ -// public get metadata() { return this._actualNode.metadata as cxapi.MetadataEntry[]; } - -// /** -// * Adds a { "info": } metadata entry to this construct. -// * The toolkit will display the info message when apps are synthesized. -// * @param message The info message. -// */ -// public addInfo(message: string): void { -// this._actualNode.addMetadata(cxschema.ArtifactMetadataEntryType.INFO, message); -// } - -// /** -// * Adds a { "warning": } metadata entry to this construct. -// * The toolkit will display the warning when an app is synthesized, or fail -// * if run in --strict mode. -// * @param message The warning message. -// */ -// public addWarning(message: string): void { -// this._actualNode.addMetadata(cxschema.ArtifactMetadataEntryType.WARN, message); -// } - -// /** -// * Adds an { "error": } metadata entry to this construct. -// * The toolkit will fail synthesis when errors are reported. -// * @param message The error message. -// */ -// public addError(message: string) { -// this._actualNode.addMetadata(cxschema.ArtifactMetadataEntryType.ERROR, message); -// } diff --git a/packages/@aws-cdk/core/lib/private/synthesis.ts b/packages/@aws-cdk/core/lib/private/synthesis.ts index 3ab3686d1acd6..bbeca35379c87 100644 --- a/packages/@aws-cdk/core/lib/private/synthesis.ts +++ b/packages/@aws-cdk/core/lib/private/synthesis.ts @@ -63,22 +63,30 @@ function invokeAspects(root: IConstruct) { recurse(root, []); - function recurse(construct: IConstruct, inheritedAspects: IAspect[]) { + function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) { const node = construct.node; - - const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects]; - const nodeAspectsCount = node._aspects.length; + const aspects = Aspects.of(construct); + const allAspectsHere = [...inheritedAspects ?? [], ...aspects.aspects]; + const nodeAspectsCount = aspects.aspects.length; for (const aspect of allAspectsHere) { - if (node.invokedAspects.includes(aspect)) { continue; } + let invoked = invokedByPath[node.path]; + if (!invoked) { + invoked = invokedByPath[node.path] = []; + } + + if (invoked.includes(aspect)) { continue; } aspect.visit(construct); + // if an aspect was added to the node while invoking another aspect it will not be invoked, emit a warning // the `nestedAspectWarning` flag is used to prevent the warning from being emitted for every child - if (!nestedAspectWarning && nodeAspectsCount !== node._aspects.length) { + if (!nestedAspectWarning && nodeAspectsCount !== aspects.aspects.length) { construct.node.addWarning('We detected an Aspect was added via another Aspect, and will not be applied'); nestedAspectWarning = true; } - node.invokedAspects.push(aspect); + + // mark as invoked for this node + invoked.push(aspect); } for (const child of construct.node.children) { @@ -145,3 +153,4 @@ function visit(root: IConstruct, order: 'pre' | 'post', cb: (x: IConstruct) => v cb(root); } } + diff --git a/packages/@aws-cdk/core/lib/tag-aspect.ts b/packages/@aws-cdk/core/lib/tag-aspect.ts index a98eb4aacd336..6791583f84817 100644 --- a/packages/@aws-cdk/core/lib/tag-aspect.ts +++ b/packages/@aws-cdk/core/lib/tag-aspect.ts @@ -86,17 +86,21 @@ abstract class TagBase implements IAspect { export class Tag extends TagBase { /** - * add tags to the node of a construct and all its the taggable children + * DEPRECATED: add tags to the node of a construct and all its the taggable children + * + * @deprecated use `Tags.of(scope).add()` */ public static add(scope: Construct, key: string, value: string, props: TagProps = {}) { - Aspects.of(scope).apply(new Tag(key, value, props)); + Tags.of(scope).add(key, value, props); } /** - * remove tags to the node of a construct and all its the taggable children + * DEPRECATED: remove tags to the node of a construct and all its the taggable children + * + * @deprecated use `Tags.of(scope).remove()` */ public static remove(scope: Construct, key: string, props: TagProps = {}) { - Aspects.of(scope).apply(new RemoveTag(key, props)); + Tags.of(scope).remove(key, props); } /** @@ -126,6 +130,35 @@ export class Tag extends TagBase { } } +/** + * Manages AWS tags for all resources within a construct scope. + */ +export class Tags { + /** + * Returns the tags API for this scope. + * @param scope The scope + */ + public static of(scope: IConstruct): Tags { + return new Tags(scope); + } + + private constructor(private readonly scope: IConstruct) { } + + /** + * add tags to the node of a construct and all its the taggable children + */ + public add(key: string, value: string, props: TagProps = {}) { + Aspects.of(this.scope).add(new Tag(key, value, props)); + } + + /** + * remove tags to the node of a construct and all its the taggable children + */ + public remove(key: string, props: TagProps = {}) { + Aspects.of(this.scope).add(new RemoveTag(key, props)); + } +} + /** * The RemoveTag Aspect will handle removing tags from this node and children */ diff --git a/packages/@aws-cdk/core/test/test.aspect.ts b/packages/@aws-cdk/core/test/test.aspect.ts index 3cbd08e5b141c..afb723d2ab2ff 100644 --- a/packages/@aws-cdk/core/test/test.aspect.ts +++ b/packages/@aws-cdk/core/test/test.aspect.ts @@ -29,12 +29,7 @@ export = { 'Aspects are invoked only once'(test: Test) { const app = new App(); const root = new MyConstruct(app, 'MyConstruct'); -<<<<<<< HEAD - Aspects.of(root).apply(new VisitOnce()); - -======= - root.node.applyAspect(new VisitOnce()); ->>>>>>> origin/master + Aspects.of(root).add(new VisitOnce()); app.synth(); test.deepEqual(root.visitCounter, 1); app.synth(); @@ -46,9 +41,9 @@ export = { const app = new App(); const root = new MyConstruct(app, 'MyConstruct'); const child = new MyConstruct(root, 'ChildConstruct'); - root.node.applyAspect({ + Aspects.of(root).add({ visit(construct: IConstruct) { - construct.node.applyAspect({ + Aspects.of(construct).add({ visit(inner: IConstruct) { inner.node.addMetadata('test', 'would-be-ignored'); }, @@ -67,7 +62,7 @@ export = { const app = new App(); const root = new MyConstruct(app, 'Construct'); const child = new MyConstruct(root, 'ChildConstruct'); - root.node.applyAspect(new MyAspect()); + Aspects.of(root).add(new MyAspect()); app.synth(); test.deepEqual(root.node.metadata[0].type, 'foo'); test.deepEqual(root.node.metadata[0].data, 'bar'); diff --git a/packages/@aws-cdk/core/test/test.stack.ts b/packages/@aws-cdk/core/test/test.stack.ts index 68db13d9c5b12..9b969602e06d0 100644 --- a/packages/@aws-cdk/core/test/test.stack.ts +++ b/packages/@aws-cdk/core/test/test.stack.ts @@ -841,7 +841,7 @@ export = { const stack2 = new Stack(stack1, 'stack2'); // WHEN - Tag.add(app, 'foo', 'bar'); + Tags.of(app).add('foo', 'bar'); // THEN const asm = app.synth(); diff --git a/packages/@aws-cdk/core/test/test.stage.ts b/packages/@aws-cdk/core/test/test.stage.ts index 8f6b1e0cefc68..89e0dfaacb394 100644 --- a/packages/@aws-cdk/core/test/test.stage.ts +++ b/packages/@aws-cdk/core/test/test.stage.ts @@ -149,7 +149,7 @@ export = { // WHEN const aspect = new TouchingAspect(); - Aspects.of(stack).apply(aspect); + Aspects.of(stack).add(aspect); // THEN app.synth(); @@ -169,7 +169,7 @@ export = { // WHEN const aspect = new TouchingAspect(); - Aspects.of(app).apply(aspect); + Aspects.of(app).add(aspect); // THEN app.synth(); @@ -302,4 +302,4 @@ class BogusStack extends Stack { function acctRegion(s: Stack) { return [s.account, s.region]; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/core/test/test.tag-aspect.ts b/packages/@aws-cdk/core/test/test.tag-aspect.ts index 35cb15ae6f5d5..0014339611aa8 100644 --- a/packages/@aws-cdk/core/test/test.tag-aspect.ts +++ b/packages/@aws-cdk/core/test/test.tag-aspect.ts @@ -56,7 +56,7 @@ export = { const map = new MapTaggableResource(res, 'MapFakeResource', { type: 'AWS::Fake::Thing', }); - Aspects.of(res).apply(new Tag('foo', 'bar')); + Aspects.of(res).add(new Tag('foo', 'bar')); synthesize(root); @@ -74,17 +74,10 @@ export = { const res2 = new TaggableResource(res, 'FakeResource', { type: 'AWS::Fake::Thing', }); -<<<<<<< HEAD - Aspects.of(res).apply(new Tag('foo', 'bar')); - Aspects.of(res).apply(new Tag('foo', 'foobar')); - Aspects.of(res).apply(new Tag('foo', 'baz')); - Aspects.of(res2).apply(new Tag('foo', 'good')); -======= - res.node.applyAspect(new Tag('foo', 'bar')); - res.node.applyAspect(new Tag('foo', 'foobar')); - res.node.applyAspect(new Tag('foo', 'baz')); - res2.node.applyAspect(new Tag('foo', 'good')); ->>>>>>> origin/master + Aspects.of(res).add(new Tag('foo', 'bar')); + Aspects.of(res).add(new Tag('foo', 'foobar')); + Aspects.of(res).add(new Tag('foo', 'baz')); + Aspects.of(res2).add(new Tag('foo', 'good')); synthesize(root); test.deepEqual(res.tags.renderTags(), [{key: 'foo', value: 'baz'}]); test.deepEqual(res2.tags.renderTags(), [{key: 'foo', value: 'good'}]); @@ -105,18 +98,10 @@ export = { const map = new MapTaggableResource(res, 'MapFakeResource', { type: 'AWS::Fake::Thing', }); -<<<<<<< HEAD - Aspects.of(root).apply(new Tag('root', 'was here')); - Aspects.of(res).apply(new Tag('first', 'there is only 1')); - Aspects.of(res).apply(new RemoveTag('root')); - Aspects.of(res).apply(new RemoveTag('doesnotexist')); - -======= - root.node.applyAspect(new Tag('root', 'was here')); - res.node.applyAspect(new Tag('first', 'there is only 1')); - res.node.applyAspect(new RemoveTag('root')); - res.node.applyAspect(new RemoveTag('doesnotexist')); ->>>>>>> origin/master + Aspects.of(root).add(new Tag('root', 'was here')); + Aspects.of(res).add(new Tag('first', 'there is only 1')); + Aspects.of(res).add(new RemoveTag('root')); + Aspects.of(res).add(new RemoveTag('doesnotexist')); synthesize(root); test.deepEqual(res.tags.renderTags(), [{key: 'first', value: 'there is only 1'}]); @@ -140,10 +125,10 @@ export = { const map = new MapTaggableResource(res, 'MapFakeResource', { type: 'AWS::Fake::Thing', }); - Tag.add(root, 'root', 'was here'); - Tag.add(res, 'first', 'there is only 1'); - Tag.remove(res, 'root'); - Tag.remove(res, 'doesnotexist'); + Tags.of(root).add('root', 'was here'); + Tags.of(res).add('first', 'there is only 1'); + Tags.of(res).remove('root'); + Tags.of(res).remove('doesnotexist'); synthesize(root); @@ -159,11 +144,7 @@ export = { type: 'AWS::Fake::Thing', }); -<<<<<<< HEAD - Aspects.of(res).apply(new Tag('foo', 'bar')); -======= - res.node.applyAspect(new Tag('foo', 'bar')); ->>>>>>> origin/master + Aspects.of(res).add(new Tag('foo', 'bar')); synthesize(root); test.deepEqual(res.tags.renderTags(), [{key: 'foo', value: 'bar'}]); synthesize(root); @@ -180,13 +161,8 @@ export = { const res2 = new TaggableResource(res, 'FakeResource', { type: 'AWS::Fake::Thing', }); -<<<<<<< HEAD - Aspects.of(res).apply(new RemoveTag('key')); - Aspects.of(res2).apply(new Tag('key', 'value')); -======= - res.node.applyAspect(new RemoveTag('key')); - res2.node.applyAspect(new Tag('key', 'value')); ->>>>>>> origin/master + Aspects.of(res).add(new RemoveTag('key')); + Aspects.of(res2).add(new Tag('key', 'value')); synthesize(root); test.deepEqual(res.tags.renderTags(), undefined); test.deepEqual(res2.tags.renderTags(), undefined); @@ -200,13 +176,8 @@ export = { const res2 = new TaggableResource(res, 'FakeResource', { type: 'AWS::Fake::Thing', }); -<<<<<<< HEAD - Aspects.of(res).apply(new RemoveTag('key', {priority: 0})); - Aspects.of(res2).apply(new Tag('key', 'value')); -======= - res.node.applyAspect(new RemoveTag('key', {priority: 0})); - res2.node.applyAspect(new Tag('key', 'value')); ->>>>>>> origin/master + Aspects.of(res).add(new RemoveTag('key', {priority: 0})); + Aspects.of(res2).add(new Tag('key', 'value')); synthesize(root); test.deepEqual(res.tags.renderTags(), undefined); test.deepEqual(res2.tags.renderTags(), [{key: 'key', value: 'value'}]); @@ -249,11 +220,7 @@ export = { ], }, }); -<<<<<<< HEAD - Aspects.of(aspectBranch).apply(new Tag('aspects', 'rule')); -======= - aspectBranch.node.applyAspect(new Tag('aspects', 'rule')); ->>>>>>> origin/master + Aspects.of(aspectBranch).add(new Tag('aspects', 'rule')); synthesize(root); test.deepEqual(aspectBranch.testProperties().tags, [{key: 'aspects', value: 'rule'}, {key: 'cfn', value: 'is cool'}]); test.deepEqual(asgResource.testProperties().tags, [