diff --git a/file/file.go b/file/file.go index 1527f6b..580d5a6 100644 --- a/file/file.go +++ b/file/file.go @@ -19,6 +19,10 @@ type File struct { // Definitions of the file defs *parser.Definitions + + // Package aliases of the file + // Maps alias to import path + importAliases map[string]string } // New create a File and analise CUE ast in it. @@ -29,15 +33,25 @@ func New(path string) (*File, error) { } defs := parser.Definitions{} - parser.ParseDefs(&defs, content) + importAliases := make(map[string]string) + parser.ParseDefs(&defs, importAliases, content) return &File{ - path: path, - content: content, - defs: &defs, + path: path, + content: content, + defs: &defs, + importAliases: importAliases, }, nil } +// AliasImportPath returns the import path of some package alias. +func (f *File) AliasImportPath(alias string) (string, bool) { + if importPath, ok := f.importAliases[alias]; ok { + return importPath, true + } + return "", false +} + func (f *File) String() string { return fmt.Sprintf("%s,%s", f.path, f.defs) } diff --git a/parser/definition.go b/parser/definition.go index c6d5492..e1faf57 100644 --- a/parser/definition.go +++ b/parser/definition.go @@ -3,6 +3,7 @@ package parser import ( "fmt" "sort" + "strconv" "cuelang.org/go/cue/ast" "cuelang.org/go/cue/token" @@ -54,7 +55,7 @@ func (def Definitions) Find(line int, column int) (string, error) { // - Ident: those are definitions from the package itself // - SelectorExpr: those are definitions from external package // they will be stored as . (E.g., foo.#Bar) -func ParseDefs(defs *Definitions, f *ast.File) { +func ParseDefs(defs *Definitions, importAliases map[string]string, f *ast.File) { ast.Walk(f, func(node ast.Node) bool { switch v := node.(type) { // case: #Def @@ -75,7 +76,14 @@ func ParseDefs(defs *Definitions, f *ast.File) { defs.AppendRange(definitionName, pkg.Pos(), v.Sel.End()) return false } + + case *ast.ImportSpec: + if v.Name != nil { + importPath, _ := strconv.Unquote(v.Path.Value) + importAliases[v.Name.String()] = importPath + } } + return true }, nil) } diff --git a/parser/definition_test.go b/parser/definition_test.go index cdf262d..593ab63 100644 --- a/parser/definition_test.go +++ b/parser/definition_test.go @@ -116,7 +116,8 @@ func TestDefinitionParsing(t *testing.T) { } defs := Definitions{} - ParseDefs(&defs, f) + importAliases := make(map[string]string) + ParseDefs(&defs, importAliases, f) output := defs.String() for _, o := range tc.output { require.Contains(t, output, o) @@ -177,7 +178,8 @@ func TestFindDefinition(t *testing.T) { } defs := Definitions{} - ParseDefs(&defs, f) + importAliases := make(map[string]string) + ParseDefs(&defs, importAliases, f) name, err := defs.Find(tc.input.line, tc.input.col) if err != nil { diff --git a/plan/plan.go b/plan/plan.go index 5e35196..6abc71a 100644 --- a/plan/plan.go +++ b/plan/plan.go @@ -1,6 +1,7 @@ package plan import ( + "errors" "fmt" "path/filepath" "sync" @@ -143,7 +144,9 @@ func (p *Plan) GetDefinition(path string, line, char int) (*loader.Value, error) } else { i, found := p.imports[def.Pkg()] if !found { - return nil, fmt.Errorf("imported package %s not registered in plan", def.Def()) + if i, err = p.findInstanceAlias(path, def.Pkg()); err != nil { + return nil, fmt.Errorf("imported package %s not registered in plan", def.Def()) + } } return i.GetDefinition(def.Def()) @@ -186,13 +189,38 @@ func (p *Plan) GetInstance(path string, line, char int) (*loader.Instance, error } else { i, found := p.imports[def.Pkg()] if !found { - return nil, fmt.Errorf("imported package %s not registered in plan", def.Def()) + if i, err = p.findInstanceAlias(path, def.Pkg()); err != nil { + return nil, fmt.Errorf("imported package %s not registered in plan", def.Def()) + } } return i, nil } } +// findInstanceAlias returns the instance of a package alias +func (p *Plan) findInstanceAlias(path string, pkgAlias string) (*loader.Instance, error) { + p.log.Debugf("Looking for pkg alias: %s", pkgAlias) + + p.muFiles.RLock() + defer p.muFiles.RUnlock() + + f, ok := p.files[path] + if !ok { + return nil, fmt.Errorf("file not registered") + } + + if importPath, ok := f.AliasImportPath(pkgAlias); ok { + for _, i := range p.imports { + if i.ImportPath == importPath { + return i, nil + } + } + return nil, fmt.Errorf("no instance found for %s", importPath) + } + return nil, errors.New("not an alias") +} + func (p *Plan) findDefInFile(path string, line, char int) (*internal.Definition, error) { p.log.Debugf("Looking for file: %s", path) @@ -243,7 +271,9 @@ func (p *Plan) GetDoc(path string, line, char int) (*loader.Value, error) { } else { i, found := p.imports[_def.Pkg()] if !found { - return nil, fmt.Errorf("imported package %s not registered in plan", _def.Def()) + if i, err = p.findInstanceAlias(path, _def.Pkg()); err != nil { + return nil, fmt.Errorf("imported package %s not registered in plan", _def.Def()) + } } return i.GetValue() diff --git a/plan/plan_test.go b/plan/plan_test.go index 12e00b1..47935b5 100644 --- a/plan/plan_test.go +++ b/plan/plan_test.go @@ -52,7 +52,8 @@ func TestNew(t *testing.T) { RootFilePath: "main.cue", Kind: File, imports: map[string]*loader.Instance{ - "test": nil, + "test": nil, + "test2": nil, }, }, }, @@ -176,22 +177,22 @@ func TestPlan_GetDefinition(t *testing.T) { defs: []Def{ { path: "_#TestName", - line: 7, + line: 8, char: 1, }, { path: "#Test", - line: 9, + line: 10, char: 9, }, { path: "_#TestName", - line: 15, + line: 16, char: 12, }, { path: "#Test", - line: 14, + line: 15, char: 15, }, }, @@ -365,19 +366,19 @@ func TestPlan_GetInstance(t *testing.T) { file: "main.cue", defs: []Def{ { - line: 7, + line: 8, char: 1, }, { - line: 9, + line: 10, char: 9, }, { - line: 15, + line: 16, char: 12, }, { - line: 14, + line: 15, char: 15, }, }, @@ -500,7 +501,8 @@ func TestPlan_Reload(t *testing.T) { RootFilePath: "main.cue", Kind: File, imports: map[string]*loader.Instance{ - "test": nil, + "test": nil, + "test2": nil, }, }, }, diff --git a/plan/testdata/with-cue-mod/cue.mod/pkg/test.com/test2/test2.cue b/plan/testdata/with-cue-mod/cue.mod/pkg/test.com/test2/test2.cue new file mode 100644 index 0000000..d79e393 --- /dev/null +++ b/plan/testdata/with-cue-mod/cue.mod/pkg/test.com/test2/test2.cue @@ -0,0 +1,7 @@ +package test2 + +#Test: { + name: string + + assert: string +} diff --git a/plan/testdata/with-cue-mod/main.cue b/plan/testdata/with-cue-mod/main.cue index a73d415..66314b5 100644 --- a/plan/testdata/with-cue-mod/main.cue +++ b/plan/testdata/with-cue-mod/main.cue @@ -2,6 +2,7 @@ package main import ( "test.com/test" + t "test.com/test2" ) _#TestName: =~"test" @@ -11,7 +12,7 @@ test1: test.#Test & { assert: "it's the first test" } -test2: test.#Test & { +test2: t.#Test & { name: _#TestName & "test 2" assert: "it's the second test" }