1package pgs 2 3import ( 4 "github.com/golang/protobuf/proto" 5 "github.com/golang/protobuf/protoc-gen-go/descriptor" 6) 7 8// File describes the contents of a single proto file. 9type File interface { 10 ParentEntity 11 12 // InputPath returns the input FilePath. This is equivalent to the value 13 // returned by Name. 14 InputPath() FilePath 15 16 // Descriptor returns the underlying descriptor for the proto file 17 Descriptor() *descriptor.FileDescriptorProto 18 19 // Services returns the services from this proto file. 20 Services() []Service 21 22 // SyntaxSourceCodeInfo returns the comment info attached to the `syntax` 23 // stanza of the file. This method is an alias of the SourceCodeInfo method. 24 SyntaxSourceCodeInfo() SourceCodeInfo 25 26 // PackageSourceCodeInfo returns the comment info attached to the `package` 27 // stanza of the file. 28 PackageSourceCodeInfo() SourceCodeInfo 29 30 setPackage(p Package) 31 32 addService(s Service) 33 34 addPackageSourceCodeInfo(info SourceCodeInfo) 35} 36 37type file struct { 38 desc *descriptor.FileDescriptorProto 39 fqn string 40 pkg Package 41 enums []Enum 42 defExts []Extension 43 msgs []Message 44 srvs []Service 45 buildTarget bool 46 syntaxInfo, packageInfo SourceCodeInfo 47} 48 49func (f *file) Name() Name { return Name(f.desc.GetName()) } 50func (f *file) FullyQualifiedName() string { return f.fqn } 51func (f *file) Syntax() Syntax { return Syntax(f.desc.GetSyntax()) } 52func (f *file) Package() Package { return f.pkg } 53func (f *file) File() File { return f } 54func (f *file) BuildTarget() bool { return f.buildTarget } 55func (f *file) Descriptor() *descriptor.FileDescriptorProto { return f.desc } 56func (f *file) InputPath() FilePath { return FilePath(f.Name().String()) } 57func (f *file) MapEntries() (me []Message) { return nil } 58func (f *file) SourceCodeInfo() SourceCodeInfo { return f.SyntaxSourceCodeInfo() } 59func (f *file) SyntaxSourceCodeInfo() SourceCodeInfo { return f.syntaxInfo } 60func (f *file) PackageSourceCodeInfo() SourceCodeInfo { return f.packageInfo } 61 62func (f *file) Enums() []Enum { 63 return f.enums 64} 65 66func (f *file) AllEnums() []Enum { 67 es := f.Enums() 68 for _, m := range f.msgs { 69 es = append(es, m.AllEnums()...) 70 } 71 return es 72} 73 74func (f *file) Messages() []Message { 75 return f.msgs 76} 77 78func (f *file) AllMessages() []Message { 79 msgs := f.Messages() 80 for _, m := range f.msgs { 81 msgs = append(msgs, m.AllMessages()...) 82 } 83 return msgs 84} 85 86func (f *file) Services() []Service { 87 return f.srvs 88} 89 90func (f *file) Imports() (i []File) { 91 // Mapping for avoiding duplicate entries 92 importMap := make(map[string]File, len(f.AllMessages())+len(f.srvs)) 93 for _, m := range f.AllMessages() { 94 for _, imp := range m.Imports() { 95 importMap[imp.File().Name().String()] = imp 96 } 97 } 98 for _, s := range f.srvs { 99 for _, imp := range s.Imports() { 100 importMap[imp.File().Name().String()] = imp 101 } 102 } 103 for _, imp := range importMap { 104 i = append(i, imp) 105 } 106 return 107} 108 109func (f *file) Extension(desc *proto.ExtensionDesc, ext interface{}) (bool, error) { 110 return extension(f.desc.GetOptions(), desc, &ext) 111} 112 113func (f *file) DefinedExtensions() []Extension { 114 return f.defExts 115} 116 117func (f *file) accept(v Visitor) (err error) { 118 if v == nil { 119 return nil 120 } 121 122 if v, err = v.VisitFile(f); err != nil || v == nil { 123 return 124 } 125 126 for _, e := range f.enums { 127 if err = e.accept(v); err != nil { 128 return 129 } 130 } 131 132 for _, m := range f.msgs { 133 if err = m.accept(v); err != nil { 134 return 135 } 136 } 137 138 for _, s := range f.srvs { 139 if err = s.accept(v); err != nil { 140 return 141 } 142 } 143 144 for _, ext := range f.defExts { 145 if err = ext.accept(v); err != nil { 146 return 147 } 148 } 149 150 return 151} 152 153func (f *file) addDefExtension(ext Extension) { 154 f.defExts = append(f.defExts, ext) 155} 156 157func (f *file) setPackage(pkg Package) { f.pkg = pkg } 158 159func (f *file) addEnum(e Enum) { 160 e.setParent(f) 161 f.enums = append(f.enums, e) 162} 163 164func (f *file) addMessage(m Message) { 165 m.setParent(f) 166 f.msgs = append(f.msgs, m) 167} 168 169func (f *file) addService(s Service) { 170 s.setFile(f) 171 f.srvs = append(f.srvs, s) 172} 173 174func (f *file) addMapEntry(m Message) { panic("cannot add map entry directly to file") } 175 176func (f *file) childAtPath(path []int32) Entity { 177 switch { 178 case len(path) == 0: 179 return f 180 case len(path)%2 == 1: // all declaration paths are multiples of two 181 return nil 182 } 183 184 var child Entity 185 switch path[0] { 186 case messageTypePath: 187 child = f.msgs[path[1]] 188 case enumTypePath: 189 child = f.enums[path[1]] 190 case servicePath: 191 child = f.srvs[path[1]] 192 default: 193 return nil 194 } 195 196 return child.childAtPath(path[2:]) 197} 198 199func (f *file) addSourceCodeInfo(info SourceCodeInfo) { 200 f.syntaxInfo = info 201} 202 203func (f *file) addPackageSourceCodeInfo(info SourceCodeInfo) { 204 f.packageInfo = info 205} 206 207var _ File = (*file)(nil) 208