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