cuelang.org/go@v0.13.0/cue/ast/astutil/util.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package astutil 16 17 import ( 18 "path" 19 "strconv" 20 "strings" 21 22 "cuelang.org/go/cue/ast" 23 "cuelang.org/go/cue/token" 24 ) 25 26 // ImportPathName derives the package name from the given import path. 27 // 28 // Examples: 29 // 30 // string string 31 // foo.com/bar bar 32 // foo.com/bar:baz baz 33 // 34 // Deprecated: use [ast.ParseImportPath] instead to obtain the 35 // qualifier. 36 func ImportPathName(id string) string { 37 // TODO use ast.ParseImportPath(id).Qualifier and change 38 // callers to understand that they might receive an empty string. 39 name := path.Base(id) 40 if p := strings.LastIndexByte(name, ':'); p > 0 { 41 name = name[p+1:] 42 } 43 return name 44 } 45 46 // ImportInfo describes the information contained in an ImportSpec. 47 type ImportInfo struct { 48 Ident string // identifier used to refer to the import 49 PkgName string // name of the package 50 ID string // full import path, including the name 51 Dir string // import path, excluding the name 52 } 53 54 // ParseImportSpec returns the name and full path of an ImportSpec. 55 func ParseImportSpec(spec *ast.ImportSpec) (ImportInfo, error) { 56 str, err := strconv.Unquote(spec.Path.Value) 57 if err != nil { 58 return ImportInfo{}, err 59 } 60 ip := ast.ParseImportPath(str) 61 info := ImportInfo{ 62 ID: str, 63 Ident: ip.Qualifier, 64 PkgName: ip.Qualifier, 65 Dir: ip.Unqualified().String(), 66 } 67 if spec.Name != nil { 68 info.Ident = spec.Name.Name 69 } 70 return info, nil 71 } 72 73 // CopyComments associates comments of one node with another. 74 // It may change the relative position of comments. 75 func CopyComments(to, from ast.Node) { 76 if from == nil { 77 return 78 } 79 ast.SetComments(to, ast.Comments(from)) 80 } 81 82 // CopyPosition sets the position of one node to another. 83 func CopyPosition(to, from ast.Node) { 84 if from == nil { 85 return 86 } 87 ast.SetPos(to, from.Pos()) 88 } 89 90 // CopyMeta copies comments and position information from one node to another. 91 // It returns the destination node. 92 func CopyMeta(to, from ast.Node) ast.Node { 93 if from == nil { 94 return to 95 } 96 ast.SetComments(to, ast.Comments(from)) 97 ast.SetPos(to, from.Pos()) 98 return to 99 } 100 101 // insertImport looks up an existing import with the given name and path or will 102 // add spec if it doesn't exist. It returns a spec in decls matching spec. 103 func insertImport(decls *[]ast.Decl, spec *ast.ImportSpec) *ast.ImportSpec { 104 x, _ := ParseImportSpec(spec) 105 106 a := *decls 107 108 var imports *ast.ImportDecl 109 var orig *ast.ImportSpec 110 111 p := 0 112 outer: 113 for i := 0; i < len(a); i++ { 114 d := a[i] 115 switch t := d.(type) { 116 default: 117 break outer 118 119 case *ast.Package: 120 p = i + 1 121 case *ast.CommentGroup: 122 p = i + 1 123 case *ast.Attribute: 124 continue 125 case *ast.ImportDecl: 126 p = i + 1 127 imports = t 128 for _, s := range t.Specs { 129 y, _ := ParseImportSpec(s) 130 if y.ID != x.ID { 131 continue 132 } 133 orig = s 134 if x.Ident == "" || y.Ident == x.Ident { 135 return s 136 } 137 } 138 } 139 } 140 141 // Import not found, add one. 142 if imports == nil { 143 imports = &ast.ImportDecl{} 144 preamble := append(a[:p:p], imports) 145 a = append(preamble, a[p:]...) 146 *decls = a 147 } 148 149 if orig != nil { 150 CopyComments(spec, orig) 151 } 152 imports.Specs = append(imports.Specs, spec) 153 ast.SetRelPos(imports.Specs[0], token.NoRelPos) 154 155 return spec 156 }