/
plugin.go
168 lines (136 loc) · 4.21 KB
/
plugin.go
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package serverutils
import (
"log"
"os"
"path/filepath"
"strings"
"github.com/99designs/gqlgen/plugin"
"github.com/99designs/gqlgen/codegen/config"
"github.com/vektah/gqlparser/v2/ast"
)
// NewImportPlugin initializes a new import plugin
//
// early sources are the source files to add before loading the service schema
// late sources are the source files to add after loading the service schema
// generate is a flag to determine whether to generate schema files or not
// path represents the path to store the imported schema files the folder name is `exported`
func NewImportPlugin(earlySources, lateSources []*ast.Source, generate bool, path string) plugin.Plugin {
p := &ImportPlugin{
earlySources: earlySources,
lateSources: lateSources,
generate: generate,
}
if generate {
p.directory = p.CreateSourceDirectory(path)
}
return p
}
// ImportPlugin is a gqlgen plugin that hooks into the gqlgen code generation lifecycle
// and adds schema definitions from an imported library
type ImportPlugin struct {
// the additional sources i.e "graphql files"
earlySources, lateSources []*ast.Source
directory string
generate bool
}
// Name is the name of the plugin
func (m *ImportPlugin) Name() string {
return "import plugin"
}
// MutateConfig implements the ConfigMutator interface
func (m *ImportPlugin) MutateConfig(cfg *config.Config) error {
return nil
}
// InjectSourceEarly is used to inject the library schema before loading the service schema.
func (m *ImportPlugin) InjectSourceEarly() *ast.Source {
// check if there are sources
if m.earlySources == nil {
return nil
}
// initialize a graphql file that holds the imported schema as it's own source file
o := ast.Source{
Name: "imported.graphql",
Input: "",
BuiltIn: false,
}
for _, source := range m.earlySources {
// federation directives and entities are already provided using the federation plugin
// They should be skipped to avoid conflict with/from the federation plugin
if strings.Contains(source.Name, "federation/directives.graphql") || strings.Contains(source.Name, "federation/entity.graphql") {
continue
}
// Contents of the source file
o.Input += source.Input
if m.generate {
m.GenerateSchemaFile(m.directory, source)
}
}
return &o
}
// InjectSourceLate is used to inject more sources after loading the service souces
func (m *ImportPlugin) InjectSourceLate(schema *ast.Schema) *ast.Source {
// check if there are late sources
if m.lateSources == nil {
return nil
}
// initialize a graphql file that holds the imported schema as it's own source file
o := ast.Source{
Name: "imported.graphql",
Input: "",
BuiltIn: false,
}
for _, source := range m.earlySources {
// federation directives and entities are already provided using the federation plugin
// They should be skipped to avoid conflict with the federation one
if strings.Contains(source.Name, "federation/directives.graphql") || strings.Contains(source.Name, "federation/entity.graphql") {
continue
}
// Contents of the source file
o.Input += source.Input
if m.generate {
m.GenerateSchemaFile(m.directory, source)
}
}
return &o
}
// CreateSourceDirectory creates the directory for the additional sources
// The files are necessary when publishing a service's schema to the registry
func (m *ImportPlugin) CreateSourceDirectory(path string) string {
dir, err := os.Getwd()
if err != nil {
log.Println(err)
}
dir = filepath.Join(dir, path, "imported")
// remove the old generated files if they exist
if _, err := os.Stat(dir); !os.IsNotExist(err) {
err = os.RemoveAll(dir)
if err != nil {
log.Println(err)
}
}
// create a new generated folder
err = os.Mkdir(dir, 0750)
if err != nil {
log.Println(err)
}
return dir
}
// GenerateSchemaFile generates the associated schema file from ast source
func (m *ImportPlugin) GenerateSchemaFile(dir string, source *ast.Source) {
fileName := filepath.Base(source.Name)
file := filepath.Join(dir, fileName)
f, err := os.Create(file)
if err != nil {
log.Println(err)
}
defer func() {
err := f.Close()
if err != nil {
log.Println(err)
}
}()
_, err = f.WriteString(source.Input)
if err != nil {
log.Println(err)
}
}