aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/vektah/gqlgen/codegen/import_build.go
blob: f0877ed3d42d189e1ea3073f87bf2d47e64add4c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package codegen

import (
	"fmt"
	"go/build"
	"sort"
	"strconv"
	"strings"
)

// These imports are referenced by the generated code, and are assumed to have the
// default alias. So lets make sure they get added first, and any later collisions get
// renamed.
var ambientImports = []string{
	"context",
	"fmt",
	"io",
	"strconv",
	"time",
	"sync",
	"github.com/vektah/gqlgen/neelance/introspection",
	"github.com/vektah/gqlgen/neelance/errors",
	"github.com/vektah/gqlgen/neelance/query",
	"github.com/vektah/gqlgen/neelance/schema",
	"github.com/vektah/gqlgen/neelance/validation",
	"github.com/vektah/gqlgen/graphql",
}

func buildImports(types NamedTypes, destDir string) *Imports {
	imports := Imports{
		destDir: destDir,
	}

	for _, ambient := range ambientImports {
		imports.add(ambient)
	}

	// Imports from top level user types
	for _, t := range types {
		t.Import = imports.add(t.Package)
	}

	return &imports
}

func (s *Imports) add(path string) *Import {
	if path == "" {
		return nil
	}

	if stringHasSuffixFold(s.destDir, path) {
		return nil
	}

	if existing := s.findByPath(path); existing != nil {
		return existing
	}

	pkg, err := build.Default.Import(path, s.destDir, 0)
	if err != nil {
		panic(err)
	}

	imp := &Import{
		Name: pkg.Name,
		Path: path,
	}
	s.imports = append(s.imports, imp)

	return imp
}

func stringHasSuffixFold(s, suffix string) bool {
	return len(s) >= len(suffix) && strings.EqualFold(s[len(s)-len(suffix):], suffix)
}

func (s Imports) finalize() []*Import {
	// ensure stable ordering by sorting
	sort.Slice(s.imports, func(i, j int) bool {
		return s.imports[i].Path > s.imports[j].Path
	})

	for _, imp := range s.imports {
		alias := imp.Name

		i := 1
		for s.findByAlias(alias) != nil {
			alias = imp.Name + strconv.Itoa(i)
			i++
			if i > 10 {
				panic(fmt.Errorf("too many collisions, last attempt was %s", alias))
			}
		}
		imp.alias = alias
	}

	return s.imports
}

func (s Imports) findByPath(importPath string) *Import {
	for _, imp := range s.imports {
		if imp.Path == importPath {
			return imp
		}
	}
	return nil
}

func (s Imports) findByAlias(alias string) *Import {
	for _, imp := range s.imports {
		if imp.alias == alias {
			return imp
		}
	}
	return nil
}