hashicorp / hcl-lang

Schema and decoder to be used as building blocks for an HCL2-based language server.
https://pkg.go.dev/github.com/hashicorp/hcl-lang
Mozilla Public License 2.0
83 stars 24 forks source link

`SetSchema` and `LoadFile` do not exist #417

Open rcjsuen opened 1 week ago

rcjsuen commented 1 week ago

Both of these functions are mentioned in the README.md but running a full text search in the project does not turn up any meaningful results in code. Am I misunderstanding something?

d, err := NewDecoder()
if err != nil {
    // ...
}
d.SetSchema(schema)

// for each (known) file (e.g. any *.tf file in Terraform)
f, pDiags := hclsyntax.ParseConfig(configBytes, "example.tf", hcl.InitialPos)
if len(pDiags) > 0 {
    // ...
}
err = d.LoadFile("example.tf", f)
if err != nil {
    // ...
}
dbanck commented 1 week ago

Hi @rcjsuen,

Sorry, you're not missing anything. The README is outdated after a refactoring (https://github.com/hashicorp/hcl-lang/pull/92) that happened a while ago.

The decoder now works based on paths instead of single files. An updated example might look like this:

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/hashicorp/hcl-lang/decoder"
    "github.com/hashicorp/hcl-lang/lang"
    "github.com/hashicorp/hcl-lang/reference"
    "github.com/hashicorp/hcl-lang/schema"
    "github.com/hashicorp/hcl/v2"
    "github.com/hashicorp/hcl/v2/hclsyntax"
    "github.com/zclconf/go-cty/cty"
)

type PathReader struct {
    Files map[string]*hcl.File
}

var _ decoder.PathReader = &PathReader{}

func (pr *PathReader) PathContext(path lang.Path) (*decoder.PathContext, error) {
    // TODO? Handle multiple language IDs if needed
    schema := &schema.BodySchema{
        Attributes: map[string]*schema.AttributeSchema{
            "test": {
                Constraint: schema.LiteralType{Type: cty.String},
            },
        },
    }

    pathContext := &decoder.PathContext{
        Schema:           schema,
        ReferenceOrigins: make(reference.Origins, 0),
        ReferenceTargets: make(reference.Targets, 0),
        Files:            pr.Files,
    }

    return pathContext, nil
}

func (pr *PathReader) Paths(ctx context.Context) []lang.Path {
    return []lang.Path{}
}

func main() {
    // 1. Parse your workspace
    src, err := os.ReadFile("example.tf")
    if err != nil {
        // ...
    }

    f, pDiags := hclsyntax.ParseConfig(src, "example.tf", hcl.InitialPos)
    if len(pDiags) > 0 {
        // ...
    }

    // 2. Create a PathReader that has a way to access the files in your workspace
    decoder := decoder.NewDecoder(&PathReader{
        Files: map[string]*hcl.File{
            "example.tf": f,
        },
    })

    // 3. Create a PathDecoder for a all files in a specific path
    pathDecoder, err := decoder.Path(lang.Path{
        Path:       ".",
        LanguageID: "terraform",
    })
    if err != nil {
        // ..
    }

    // 4. Use LSP methods
    completions, _ := pathDecoder.CompletionAtPos(context.Background(), "example.tf", hcl.InitialPos)
    fmt.Printf("# Completions: %#v\n", completions)
}