1package templates
2
3import (
4 "fmt"
5 "go/types"
6 "strconv"
7 "strings"
8
9 "github.com/99designs/gqlgen/internal/code"
10)
11
12type Import struct {
13 Name string
14 Path string
15 Alias string
16}
17
18type Imports struct {
19 imports []*Import
20 destDir string
21}
22
23func (i *Import) String() string {
24 if strings.HasSuffix(i.Path, i.Alias) {
25 return strconv.Quote(i.Path)
26 }
27
28 return i.Alias + " " + strconv.Quote(i.Path)
29}
30
31func (s *Imports) String() string {
32 res := ""
33 for i, imp := range s.imports {
34 if i != 0 {
35 res += "\n"
36 }
37 res += imp.String()
38 }
39 return res
40}
41
42func (s *Imports) Reserve(path string, aliases ...string) (string, error) {
43 if path == "" {
44 panic("empty ambient import")
45 }
46
47 // if we are referencing our own package we dont need an import
48 if code.ImportPathForDir(s.destDir) == path {
49 return "", nil
50 }
51
52 name := code.NameForPackage(path)
53 var alias string
54 if len(aliases) != 1 {
55 alias = name
56 } else {
57 alias = aliases[0]
58 }
59
60 if existing := s.findByPath(path); existing != nil {
61 if existing.Alias == alias {
62 return "", nil
63 }
64 return "", fmt.Errorf("ambient import already exists")
65 }
66
67 if alias := s.findByAlias(alias); alias != nil {
68 return "", fmt.Errorf("ambient import collides on an alias")
69 }
70
71 s.imports = append(s.imports, &Import{
72 Name: name,
73 Path: path,
74 Alias: alias,
75 })
76
77 return "", nil
78}
79
80func (s *Imports) Lookup(path string) string {
81 if path == "" {
82 return ""
83 }
84
85 path = code.NormalizeVendor(path)
86
87 // if we are referencing our own package we dont need an import
88 if code.ImportPathForDir(s.destDir) == path {
89 return ""
90 }
91
92 if existing := s.findByPath(path); existing != nil {
93 return existing.Alias
94 }
95
96 imp := &Import{
97 Name: code.NameForPackage(path),
98 Path: path,
99 }
100 s.imports = append(s.imports, imp)
101
102 alias := imp.Name
103 i := 1
104 for s.findByAlias(alias) != nil {
105 alias = imp.Name + strconv.Itoa(i)
106 i++
107 if i > 10 {
108 panic(fmt.Errorf("too many collisions, last attempt was %s", alias))
109 }
110 }
111 imp.Alias = alias
112
113 return imp.Alias
114}
115
116func (s *Imports) LookupType(t types.Type) string {
117 return types.TypeString(t, func(i *types.Package) string {
118 return s.Lookup(i.Path())
119 })
120}
121
122func (s Imports) findByPath(importPath string) *Import {
123 for _, imp := range s.imports {
124 if imp.Path == importPath {
125 return imp
126 }
127 }
128 return nil
129}
130
131func (s Imports) findByAlias(alias string) *Import {
132 for _, imp := range s.imports {
133 if imp.Alias == alias {
134 return imp
135 }
136 }
137 return nil
138}