feat: explorer codelens nav + template resource locations#1617
Open
megha-narayanan wants to merge 14 commits into
Open
feat: explorer codelens nav + template resource locations#1617megha-narayanan wants to merge 14 commits into
megha-narayanan wants to merge 14 commits into
Conversation
Decorate every CFN-resource ConstructNode with templateFile: the absolute path of the template that declares its logicalId, descending into CDK-managed nested stacks via the aws:asset:path resource metadata (the same link CDK's deploy/diff uses). This is the data the clickable CodeLens needs to open a resource in its synthesized template. Self-contained in cdk-explorer: a recursive walk over stacksRecursively builds a flat logicalId -> templateFile map; no cloud-assembly-api or toolkit-lib changes.
Add findLogicalIdPosition(templateText, logicalId): the 0-based position of a resource's definition key within its synthesized template. Anchors on the "<id>": key, so Ref/GetAtt/DependsOn value occurrences of the same id are not matched. Pairs with the templateFile resolved per node to give the clickable CodeLens its navigation target.
Add resourceTarget(node) -> { uri, range }: reads the node's resolved
template, locates its logicalId via findLogicalIdPosition, and returns a
file:// uri + zero-width range to reveal. Returns undefined when the node
has no template/logicalId or the id is not found -- the single not-navigable
signal callers filter on. Joins the templateFile (Bit 1) and locator (Bit 2)
into the target the clickable CodeLens will carry.
…ource lenses
A lens for a single resource now carries command cdkExplorer.openResource
with its { uri, range } navigation target as the argument, so a client can
open the template at the resource. Multiple resources on one line stay
title-only (picker comes later), as does a single resource whose target
cannot be resolved. Server-side only -- nothing executes the command until
the client registers a handler.
…cker
A lens now carries an array of resource choices ({ label, target }) under
cdkExplorer.openResource. A single resource is a one-element array the client
opens directly; multiple resources on one line (an L2 fanning out) let the
client show a picker. Unresolvable resources are dropped, and a line where
none resolve stays title-only.
…xes)
A1: key templateFiles by stack hierarchicalId, not a flat logicalId map --
logical IDs are stack-relative so same-shape stacks (prod/dev/regional) would
otherwise collide last-write-wins and navigate to the wrong template.
B1: type the template walk via local CfnTemplate/CfnResource (no any).
B2: narrow resourceTarget to { templateFile?, logicalId: string }, dropping
the impossible-state guard since commandFor only passes resolved resources.
Lens titles are type-forward and drop the noisy hashed logical ID: single -> 'Creates AWS::S3::Bucket' multi -> 'Creates N resources: <type>, <type>, ...' (now shows types) The picker carries each choice as a QuickPick item (label = CFN type, description = friendly construct path, e.g. 'MyStack/MyBucket') instead of an opaque logical-ID hash. Also drops the unused ResourceChoice export and the ResourceLensInfo relabel allocation (review nits C1/C2).
…its C3/C4) C3: replace the dynamic RegExp (+escapeRegExp guarding an impossible state, since logical IDs are [A-Za-z0-9]) with a plain trimStart/startsWith key match plus a next-char colon check. Same anti-false-match and prefix-collision guarantees, no regex. C4: trim JSDoc that restated the code.
… fallback Fixes the parent-vs-nested logical-ID collision: a NestedStack resets the logical-ID namespace, so a parent resource and a resource in its own nested stack can share an id and the per-stack logical-ID map resolved the parent to the nested template. Key primarily by construct path (globally unique, from aws:cdk:path metadata) which disambiguates the twins; fall back to the per-stack logical-ID map when path metadata is off (--no-path-metadata), so resolution never regresses. Fixtures now emit aws:cdk:path (matching real synth); adds collision + fallback regression tests.
missing/unparseable nested template skips only its subtree instead of aborting the entire readAssembly (matches the file's graceful-degradation contract). (depth-2) resolution test and an unreadable-nested-template guard test.
…onstructTree Move templateFile resolution from cdk-explorer into the core tree builder. buildConstructTree now threads the active CloudFormation template down the construct tree, switching to the nested template at each NestedStack boundary (the *.NestedStack construct + its sibling NestedStackResource's aws:asset:path). Because resolution is positional (by tree position, not by logical ID), it is correct for parent/nested resources that share a stack-relative logical ID -- with no per-stack id map and no dependence on aws:cdk:path/path metadata. This eliminates the --no-path-metadata collision the explorer's id-keyed index had. cdk-explorer drops buildTemplateFileIndex + its maps and just consumes the templateFile field. Test fixtures now emit the faithful NestedStack topology (sibling NestedStackResource node) that real synth produces.
…arden types - Top-level/Stage stacks read through the artifact's cached, fail-loud template getter instead of a shadow-parsing loadTemplate (which swallowed errors and kept a second cache). - Detect NestedStack boundaries via the sibling AWS::CloudFormation::Stack node rather than the construct fqn, so jsii-published NestedStack subclasses (fqn not ending in .NestedStack) are handled and don't mis-inherit the parent. - Resolve the nested asset path against the owner stack's assembly directory (the Stage sub-assembly for staged stacks), not the root assembly. - Thread a single both-or-neither TemplateScope through the walk (rename from NestedTemplateScope) with a shared NO_TEMPLATE seed; drop now-dead WalkContext.assembly and RawTreeNode.constructInfo. - Add direct caa nested-stack tests (resolved, missing/unreadable, no asset metadata, parent/nested logical-id twin, jsii-subclass detection).
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
rix0rrr
approved these changes
Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on #1592, which surfaced display-only CodeLens entries for the CFN
resources each construct produces. This PR makes them clickable. Selecting a
lens jumps to the resource's definition in the synthesized CloudFormation template.
Features:
openResourcecommand that opensthe resource's template file at its logical-ID line.
single-resource constructs open directly.
templateFileresolution (cloud-assembly-api) —buildConstructTreethreads the owning template through the tree, switching at NestedStack boundaries.
Creates AWS::S3::Bucket, orCreates 3 resources: AWS::S3::Bucket, AWS::S3::BucketPolicy, AWS::KMS::Key.Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license