github.com/yaegashi/msgraph.go@v0.1.4/gen/generator_generate.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "encoding/xml" 6 "fmt" 7 "io" 8 "os" 9 "path/filepath" 10 "sort" 11 "strings" 12 "text/template" 13 ) 14 15 type Const struct { 16 Name, Value, Type string 17 } 18 19 type EnumType struct { 20 Name string 21 Sym string 22 Members []*EnumTypeMember 23 Description string 24 } 25 26 type EnumTypeMember struct { 27 Name string 28 Sym string 29 Value string 30 Description string 31 } 32 33 type EntityType struct { 34 Name string 35 Sym string 36 Type string 37 Base string 38 Members []*EntityTypeMember 39 Navigations []*EntityTypeNavigation 40 Description string 41 } 42 43 type EntityTypeMember struct { 44 Name string 45 Sym string 46 Type string 47 Description string 48 } 49 50 type EntityTypeNavigation struct { 51 Name string 52 Sym string 53 Type string 54 Description string 55 } 56 57 type ActionType struct { 58 Name string 59 Sym string 60 BindingParameterType string 61 Parameters []*ActionTypeParameter 62 ReturnType string 63 Description string 64 } 65 66 type ActionTypeParameter struct { 67 Name string 68 Sym string 69 Type string 70 Description string 71 } 72 73 type EntitySet struct { 74 Name string 75 Sym string 76 Type string 77 } 78 79 type Singleton struct { 80 Name string 81 Sym string 82 Type string 83 } 84 85 func (g *Generator) Generate() error { 86 tmpl, err := template.ParseGlob("templates/*.tmpl") 87 if err != nil { 88 return err 89 } 90 91 inFile, err := os.Open(g.In) 92 if err != nil { 93 return err 94 } 95 defer inFile.Close() 96 97 var o Elem 98 dec := xml.NewDecoder(inFile) 99 err = dec.Decode(&o) 100 if err != nil { 101 return err 102 } 103 104 schema := o.Elems[0].Elems[0] 105 enumTypeMap := map[string]*EnumType{} 106 entityTypeMap := map[string]*EntityType{} 107 actionTypeMap := map[string][]*ActionType{} 108 entitySetMap := map[string]*EntitySet{} 109 singletonMap := map[string]*Singleton{} 110 requestModelMap := map[string]bool{} 111 actionRequestBuilderMap := map[string][]string{} 112 113 for _, x := range schema.Elems { 114 switch x.XMLName.Local { 115 case "EnumType": 116 m := x.AttrMap() 117 n := m["Name"] 118 t := &EnumType{Name: n, Sym: exported(n), Description: "undocumented"} 119 for _, y := range x.Elems { 120 n := y.Attrs[0].Value 121 // ex. Collection(String) -> StringCollection 122 if strings.HasPrefix(n, colPrefix) { 123 n = n[len(colPrefix):len(n)-1] + "Collection" 124 } 125 v := y.Attrs[1].Value 126 m := &EnumTypeMember{Name: n, Sym: exported(n), Value: v, Description: "undocumented"} 127 t.Members = append(t.Members, m) 128 } 129 enumTypeMap[n] = t 130 case "EntityType", "ComplexType": 131 m := x.AttrMap() 132 n := m["Name"] 133 if _, ok := reservedTypeTable[n]; ok { 134 continue 135 } 136 t := nsPrefix + n 137 b, _ := m["BaseType"] 138 et := &EntityType{Name: n, Sym: exported(n), Type: t, Base: b, Description: "undocumented"} 139 if strings.HasSuffix(et.Sym, "Request") { 140 et.Sym += "Object" 141 g.SymTypeMap[t] = et.Sym 142 } 143 for _, y := range x.Elems { 144 ma := y.AttrMap() 145 switch y.XMLName.Local { 146 case "Property": 147 n := ma["Name"] 148 t := ma["Type"] 149 m := &EntityTypeMember{Name: n, Sym: exported(n), Type: t, Description: "undocumented"} 150 et.Members = append(et.Members, m) 151 case "NavigationProperty": 152 n := ma["Name"] 153 t := ma["Type"] 154 m := &EntityTypeNavigation{Name: n, Sym: exported(n), Type: t, Description: "undocumented"} 155 if strings.HasSuffix(m.Sym, "Request") { 156 m.Sym += "Navigation" 157 } 158 et.Navigations = append(et.Navigations, m) 159 } 160 } 161 entityTypeMap[et.Name] = et 162 case "Action": 163 m := x.AttrMap() 164 n := m["Name"] 165 at := &ActionType{Name: n, Sym: exported(n), Description: "undocumented"} 166 if strings.HasSuffix(at.Sym, "Request") { 167 at.Sym += "Action" 168 } 169 for _, y := range x.Elems { 170 ma := y.AttrMap() 171 switch y.XMLName.Local { 172 case "Parameter": 173 n := ma["Name"] 174 t := ma["Type"] 175 m := &ActionTypeParameter{Name: n, Sym: exported(n), Type: t, Description: "undocumented"} 176 at.Parameters = append(at.Parameters, m) 177 case "ReturnType": 178 at.ReturnType = ma["Type"] 179 } 180 } 181 at.BindingParameterType = at.Parameters[0].Type 182 at.Parameters = at.Parameters[1:] 183 actionTypeMap[at.BindingParameterType] = append(actionTypeMap[at.BindingParameterType], at) 184 case "EntityContainer": 185 for _, y := range x.Elems { 186 ma := y.AttrMap() 187 switch y.XMLName.Local { 188 case "EntitySet": 189 s := &EntitySet{ 190 Name: ma["Name"], 191 Sym: exported(ma["Name"]), 192 Type: ma["EntityType"], 193 } 194 entitySetMap[s.Name] = s 195 case "Singleton": 196 s := &Singleton{ 197 Name: ma["Name"], 198 Sym: exported(ma["Name"]), 199 Type: ma["Type"], 200 } 201 singletonMap[s.Name] = s 202 } 203 } 204 case "Annotations": 205 mas := x.AttrMap() 206 target, _ := stripNSPrefix(mas["Target"]) 207 targetList := strings.Split(target, "/") 208 targetMember := "" 209 if len(targetList) > 1 { 210 target = targetList[0] 211 targetMember = targetList[1] 212 } 213 for _, y := range x.Elems { 214 switch y.XMLName.Local { 215 case "Annotation": 216 ma := y.AttrMap() 217 term, _ := ma["Term"] 218 str, _ := ma["String"] 219 if term == "Org.OData.Core.V1.Description" { 220 if e, ok := entityTypeMap[target]; ok { 221 if targetMember == "" { 222 e.Description = str 223 } else { 224 for _, mem := range e.Members { 225 if mem.Name == targetMember { 226 mem.Description = str 227 } 228 } 229 } 230 } 231 } 232 } 233 } 234 } 235 } 236 237 // Copy all *.go files without template processing 238 // Copy everything below the first "// BEGIN" line to the output 239 paths, err := filepath.Glob("templates/*.go") 240 if err != nil { 241 return err 242 } 243 for _, path := range paths { 244 err := func() error { 245 inFile, err := os.Open(path) 246 if err != nil { 247 return err 248 } 249 defer inFile.Close() 250 outFile, err := g.Create(filepath.Base(path), "") 251 if err != nil { 252 return err 253 } 254 defer outFile.Close() 255 scanner := bufio.NewScanner(inFile) 256 enabled := false 257 for scanner.Scan() { 258 line := scanner.Text() 259 if strings.HasPrefix(line, "// BEGIN") { 260 enabled = true 261 continue 262 } 263 if enabled { 264 fmt.Fprintln(outFile, line) 265 } 266 } 267 return scanner.Err() 268 }() 269 if err != nil { 270 return err 271 } 272 } 273 274 // Copy some *.go.tmpl files with template processing 275 for _, path := range []string{"const.go.tmpl"} { 276 out, err := g.Create(path[:len(path)-5], "") 277 if err != nil { 278 return err 279 } 280 err = tmpl.ExecuteTemplate(out, path, g) 281 if err != nil { 282 return err 283 } 284 out.Close() 285 } 286 287 var out io.WriteCloser 288 289 keys := []string{} 290 for x := range enumTypeMap { 291 keys = append(keys, x) 292 } 293 sort.Strings(keys) 294 for _, key := range keys { 295 x := enumTypeMap[key] 296 out, err = g.Create("Enum", x.Sym) 297 g.X = x 298 if err != nil { 299 return err 300 } 301 err := tmpl.ExecuteTemplate(out, "enum.go.tmpl", g) 302 if err != nil { 303 return err 304 } 305 out.Close() 306 } 307 308 keys = nil 309 for x := range entityTypeMap { 310 keys = append(keys, x) 311 } 312 sort.Strings(keys) 313 for _, key := range keys { 314 x := entityTypeMap[key] 315 out, err = g.Create("Model", x.Sym) 316 if err != nil { 317 return err 318 } 319 g.X = x 320 err := tmpl.ExecuteTemplate(out, "model.go.tmpl", g) 321 if err != nil { 322 return err 323 } 324 out.Close() 325 } 326 327 keys = nil 328 for x := range actionTypeMap { 329 keys = append(keys, x) 330 } 331 sort.Strings(keys) 332 for _, a := range keys { 333 if _, ok := reservedTypeTable[a]; ok { 334 continue 335 } 336 x := actionTypeMap[a] 337 out, err = g.Create("Action", g.SymBaseType(a)) 338 if err != nil { 339 return err 340 } 341 requestModelMap[g.SymBaseType(a)] = true 342 for _, y := range x { 343 g.X = y 344 err := tmpl.ExecuteTemplate(out, "action.go.tmpl", g) 345 if err != nil { 346 return err 347 } 348 } 349 out.Close() 350 } 351 352 for _, x := range entityTypeMap { 353 if len(x.Navigations) == 0 { 354 continue 355 } 356 requestModelMap[x.Sym] = true 357 for _, y := range x.Navigations { 358 requestModelMap[g.SymBaseType(y.Type)] = true 359 } 360 } 361 for _, x := range entitySetMap { 362 requestModelMap[g.SymBaseType(x.Type)] = true 363 } 364 for _, x := range singletonMap { 365 requestModelMap[g.SymBaseType(x.Type)] = true 366 } 367 368 keys = nil 369 for x := range requestModelMap { 370 keys = append(keys, x) 371 } 372 sort.Strings(keys) 373 for _, x := range keys { 374 out, err = g.Create("Request", x) 375 if err != nil { 376 return err 377 } 378 g.X = x 379 err := tmpl.ExecuteTemplate(out, "request_model.go.tmpl", g) 380 if err != nil { 381 return err 382 } 383 out.Close() 384 } 385 386 out, err = g.Create("GraphService", "") 387 if err != nil { 388 return err 389 } 390 keys = nil 391 for x := range entitySetMap { 392 keys = append(keys, x) 393 } 394 sort.Strings(keys) 395 for _, key := range keys { 396 g.X = &EntityType{Name: "GraphService", Sym: "GraphService"} 397 g.Y = entitySetMap[key] 398 err := tmpl.ExecuteTemplate(out, "request_collection_navigation.go.tmpl", g) 399 if err != nil { 400 return err 401 } 402 } 403 keys = nil 404 for x := range singletonMap { 405 keys = append(keys, x) 406 } 407 sort.Strings(keys) 408 for _, key := range keys { 409 g.X = &EntityType{Name: "GraphService", Sym: "GraphService"} 410 g.Y = singletonMap[key] 411 err := tmpl.ExecuteTemplate(out, "request_navigation.go.tmpl", g) 412 if err != nil { 413 return err 414 } 415 } 416 out.Close() 417 418 keys = nil 419 for x := range entityTypeMap { 420 keys = append(keys, x) 421 } 422 sort.Strings(keys) 423 for _, key := range keys { 424 x := entityTypeMap[key] 425 actionRequestBuilderMap[x.Type] = append(actionRequestBuilderMap[x.Type], x.Sym) 426 if len(x.Navigations) == 0 { 427 continue 428 } 429 out, err = g.Create("Action", x.Sym) 430 if err != nil { 431 return err 432 } 433 g.X = x 434 sort.Slice(x.Navigations, func(i, j int) bool { return x.Navigations[i].Name < x.Navigations[j].Name }) 435 for _, y := range x.Navigations { 436 g.Y = y 437 if isCollectionType(y.Type) { 438 actionRequestBuilderMap[y.Type] = append(actionRequestBuilderMap[y.Type], x.Sym+y.Sym+"Collection") 439 err := tmpl.ExecuteTemplate(out, "request_collection_navigation.go.tmpl", g) 440 if err != nil { 441 return err 442 } 443 } else { 444 err := tmpl.ExecuteTemplate(out, "request_navigation.go.tmpl", g) 445 if err != nil { 446 return err 447 } 448 } 449 } 450 out.Close() 451 } 452 453 keys = nil 454 for x := range actionTypeMap { 455 keys = append(keys, x) 456 } 457 sort.Strings(keys) 458 for _, a := range keys { 459 x := actionTypeMap[a] 460 if _, ok := reservedTypeTable[a]; ok { 461 continue 462 } 463 for _, y := range x { 464 out, err = g.Create("Request", g.SymBaseType(a)+y.Sym) 465 if err != nil { 466 return err 467 } 468 g.Y = y 469 if b, ok := actionRequestBuilderMap[a]; ok { 470 g.X = b 471 if y.ReturnType == "" { 472 err = tmpl.ExecuteTemplate(out, "request_action_void.go.tmpl", g) 473 } else if isCollectionType(y.ReturnType) { 474 err = tmpl.ExecuteTemplate(out, "request_action_collection.go.tmpl", g) 475 } else { 476 err = tmpl.ExecuteTemplate(out, "request_action_single.go.tmpl", g) 477 } 478 if err != nil { 479 return err 480 } 481 } 482 out.Close() 483 } 484 } 485 486 return nil 487 }