diff --git a/decoder/expr_object.go b/decoder/expr_object.go index 8bf357f1..cbcacb25 100644 --- a/decoder/expr_object.go +++ b/decoder/expr_object.go @@ -3,7 +3,6 @@ package decoder import ( "context" - "github.com/hashicorp/hcl-lang/lang" "github.com/hashicorp/hcl-lang/reference" "github.com/hashicorp/hcl-lang/schema" "github.com/hashicorp/hcl/v2" @@ -17,11 +16,6 @@ type Object struct { pathCtx *PathContext } -func (obj Object) SemanticTokens(ctx context.Context) []lang.SemanticToken { - // TODO - return nil -} - func (obj Object) ReferenceOrigins(ctx context.Context, allowSelfRefs bool) reference.Origins { // TODO return nil diff --git a/decoder/expr_object_semtok.go b/decoder/expr_object_semtok.go new file mode 100644 index 00000000..c77462b5 --- /dev/null +++ b/decoder/expr_object_semtok.go @@ -0,0 +1,46 @@ +package decoder + +import ( + "context" + + "github.com/hashicorp/hcl-lang/lang" + "github.com/hashicorp/hcl/v2/hclsyntax" +) + +func (obj Object) SemanticTokens(ctx context.Context) []lang.SemanticToken { + eType, ok := obj.expr.(*hclsyntax.ObjectConsExpr) + if !ok { + return []lang.SemanticToken{} + } + + if len(eType.Items) == 0 || len(obj.cons.Attributes) == 0 { + return []lang.SemanticToken{} + } + + tokens := make([]lang.SemanticToken, 0) + + for _, item := range eType.Items { + attrName, attrRange, ok := getRawObjectAttributeName(item.KeyExpr) + if !ok { + // invalid expression + continue + } + + aSchema, ok := obj.cons.Attributes[attrName] + if !ok { + // unknown attribute + return nil + } + + tokens = append(tokens, lang.SemanticToken{ + Type: lang.TokenObjectKey, + Modifiers: lang.SemanticTokenModifiers{}, + Range: *attrRange, + }) + + expr := newExpression(obj.pathCtx, item.ValueExpr, aSchema.Constraint) + tokens = append(tokens, expr.SemanticTokens(ctx)...) + } + + return tokens +} diff --git a/decoder/expr_object_semtok_test.go b/decoder/expr_object_semtok_test.go new file mode 100644 index 00000000..e43d2dc3 --- /dev/null +++ b/decoder/expr_object_semtok_test.go @@ -0,0 +1,49 @@ +package decoder + +import ( + "context" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/hcl-lang/lang" + "github.com/hashicorp/hcl-lang/schema" + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/hclsyntax" +) + +func TestSemanticTokens_exprObject(t *testing.T) { + testCases := []struct { + testName string + attrSchema map[string]*schema.AttributeSchema + cfg string + expectedSemanticTokens []lang.SemanticToken + }{ + // TODO + } + for i, tc := range testCases { + t.Run(fmt.Sprintf("%d-%s", i, tc.testName), func(t *testing.T) { + bodySchema := &schema.BodySchema{ + Attributes: tc.attrSchema, + } + + f, _ := hclsyntax.ParseConfig([]byte(tc.cfg), "test.tf", hcl.InitialPos) + d := testPathDecoder(t, &PathContext{ + Schema: bodySchema, + Files: map[string]*hcl.File{ + "test.tf": f, + }, + }) + + ctx := context.Background() + tokens, err := d.SemanticTokensInFile(ctx, "test.tf") + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(tc.expectedSemanticTokens, tokens); diff != "" { + t.Fatalf("unexpected tokens: %s", diff) + } + }) + } +}