You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(core): warn if an aspect was added via another aspect (aws#8639)
### Updated PR
Since we introduced [`stages`](aws#8423) which had the unintended side effect of the CDK not supporting adding an Aspect via another Aspect, we have not seen any issues reported beside aws#8536, that was resolved without requiring this capability.
Given that, and the fact this features has many sharp edges we decided to leave it unsupported, and add a warning in the meantime.
-----------
Following up on aws#8536
If an aspect is added via another aspect, the inner aspect will not be invoked. Take for example this code:
```typescript
const app = new cdk.App();
app.node.applyAspect({
visit(construct: cdk.IConstruct) {
construct.node.applyAspect({
visit(construct: cdk.IConstruct) {
console.info("Invoking aspect on construct: " + construct.node.id); // This will not be called
}
})
}
});
```
Since aspects are added only on the top level node, if an aspect is added while `InvokeAspects` is called on that node, it will be ignored since it will not be added to list of aspects to invoke (`allAspectsHere` in the bellow code):
```typescript
function invokeAspects(root: IConstruct) {
recurse(root, []);
function recurse(construct: IConstruct, inheritedAspects: constructs.IAspect[]) {
// hackery to be able to access some private members with strong types (yack!)
const node: NodeWithAspectPrivatesHangingOut = construct.node._actualNode as any;
const allAspectsHere = [...inheritedAspects ?? [], ...node._aspects];
for (const aspect of allAspectsHere) {
if (node.invokedAspects.includes(aspect)) { continue; }
aspect.visit(construct); <-- an aspect that was added here will not be added to `allAspectsHere` and will be ignored
node.invokedAspects.push(aspect);
}
for (const child of construct.node.children) {
if (!Stage.isStage(child)) {
recurse(child, allAspectsHere);
}
}
}
}
```
Assuming this is not something we want to support**, we can detect it by comparing the size of `node._aspects` before and after the call to `aspect.visit`, and emit a warning if there has been a change. Note that while the aspect will not be invoked it will be added to every child construct during the recursive visit. Emitting a warning for each child construct will result in a noisy console, to prevent this I have added a flag that will only allow adding **one warning per application**, given this limitation I'm not sure there is a lot of value in adding the warning, thoughts?
If we decide to add it I will add tests.
(** theoretically we could support it by adding the aspects to `allAspectsHere` during the loop, but this will require a non trivial implementation in order to avoid infinite recursion)
----
*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
0 commit comments