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.
Closes #2
(Schema) Reference types
In general the schema recognizes two types of references - (1) type-aware, and (2) type-less
In Terraform type-aware references are commonly used to set values of fields via reference. For example:
Here
key_name
is of typestring
and relatedlyaws_key_pair.iac_in_action.key_name
points to a field of typestring
.Type-less references are used to draw an explicit dependency between resources, e.g.
Here in this particular context of
depends_on
,aws_s3_bucket.example
only represents a "pointer" to the lower block, but isn't concerned about what data (whether any) it points to.Type Declaration
It is only possible to declare type explicitly via the schema. e.g. schema sets
name
tostring
and that's what it will always be.More dynamic declaration and inference would be also useful in Terraform, specifically for variables, where variable type is declared within the config, or is inferred in case of
local
s. This seemed like a scope-creep in this MVP, so I left it out, but it's certainly something to revisit.TODO: Create issue for this.
There can be cases where the same address (such as
aws_s3_bucket.example
) can be type-less and type-aware, it only depends on the context. This is why we allow references with the same address to exist and then filter based on context.Functionality
This PR adds support for traversal expressions in the following areas:
Completion
This is the trickiest and most complex part with most edge cases - many of which are yet to be covered in follow-up PRs.
Currently we decode all steps of a traversal and also return such "fully expanded" traversals instead of letting the user complete step-by-step.
e.g. given a config & schema
we would complete just
aws_lb.example.listener[0].protocol
for traversal of typestring
andaws_lb.example.listener[0].port
for traversal of typenumber
. This may be good/better UX in this particular context and small snippet, but might not scale with larger configurations.The internal structure will allow us to explore some alternative approaches though and possibly even combine them, so that e.g. we can complete just all resource types (e.g.
aws_lb
), then after.
we complete all reference names for that resource type (e.g.example
), then after.
all the attributes of that particular resource instance and so on.The completion does not take any external sources (such as Terraform state) into effect, but relies purely on configuration and schema. This means that e.g. if a map/list/set has some elements computed outside of the configuration these would NOT be surfaced as elements of a given field via
[0]
,[1]
,["key"]
etc. This will likely be a useful feature for Terraform, but it is intentionally left out from this MVP for complexity.Another edge case which is not entirely related to this PR, but perhaps becomes more visible is that we don't provide completion inside nested expressions in most cases yet. I implemented some of the simple ones, such as
where
depends_on
isSetExpr
, but only where the wrapping expression (SetExpr, ListExpr) is empty - i.e. for the first element only. Again - this is certainly something that should be implemented, but was left out for complexity.Hover
Due to the way things are structured, we would only provide hover data for a matching reference, for example
I believe this is ok trade-off for now, but we can revisit later, if necessary.
Semantic Tokens
The same limitation as in hover applies here - if the traversal expression doesn't exist/match, then it won't be reported as token at all.
There is a new token type
lang.TokenTraversalStep
which represents the parts between dots in addresses. This is cleaner than reporting the whole traversal as token, because clients could otherwise paint it all the same colour (including index numbers/keys, brackets and dots).We could go further here and report individual tokens with some more context/meaning, but this would also require collecting such meaning via schema somehow. See hashicorp/vscode-terraform#574 for related discussion.