Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): warn if an aspect was added via another aspect (#8639)
### Updated PR Since we introduced [`stages`](#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 #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 #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*
- Loading branch information