gen.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. package gen
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. . "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/common"
  10. "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/flag"
  11. GO "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/translate/got"
  12. TS "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/translate/tst"
  13. )
  14. var (
  15. expandTranscludeExpression = regexp.MustCompile(`"\$\._transclude_":(true|"\w+")`)
  16. expandVarExpression = regexp.MustCompile(`"\$(\.\w+)"`)
  17. removeAllSpacesExpression = regexp.MustCompile(`(\s|\t|\r|\n)+`)
  18. )
  19. func CreateProject() (*Project, error) {
  20. var (
  21. err error
  22. path string
  23. id string
  24. files []os.FileInfo
  25. entity *Entity
  26. resource *Resource
  27. directory string
  28. mode = *flag.Mode
  29. paramAcceptFiled = map[string]bool{}
  30. p = &Project{
  31. Mode: mode,
  32. SchemasRef: map[string]*Entity{},
  33. Icons: map[string]string{},
  34. ReplaceWhenEmpty: map[string]bool{},
  35. OmitEmpty: map[string]bool{},
  36. FormatMap: map[string]string{},
  37. Queries: &QueryDef{},
  38. Translators: map[string]TranslationFn{
  39. "go": GO.Translate,
  40. "angular6": TS.Translate,
  41. },
  42. TranslatorBuildOptionsMap: map[string]func(*Project, *BuildOptions) (*BuildSet, error){
  43. "go": GO.Build,
  44. "angular6": TS.Build,
  45. },
  46. }
  47. )
  48. if directory, err = os.Getwd(); err != nil {
  49. return nil, err
  50. }
  51. root, _ := filepath.Abs("../")
  52. p.Paths = PathMap{
  53. "current": root,
  54. "dist": fmt.Sprintf("%s/dist", root),
  55. "build": fmt.Sprintf("%s/build", root),
  56. "include": fmt.Sprintf("%s/project/include", root),
  57. "project": fmt.Sprintf("%s/project", root),
  58. }
  59. if err = JsonParseMode(p.Paths.Project("/project"), mode, p); err != nil {
  60. return nil, err
  61. }
  62. if err = ParseJson(p.Paths.Project("/queries.json"), &p.Queries); err != nil {
  63. p.Queries.Blacklistwords = map[string][]string{}
  64. p.Queries.Queries = map[string]string{}
  65. }
  66. if err = loadQueries(p, directory); err != nil {
  67. return nil, err
  68. }
  69. if err = expandQueries(p); err != nil {
  70. return nil, err
  71. }
  72. if err = ParseJson(p.Paths.Project("/common.json"), &p.Resource); err != nil {
  73. p.Resource = &Resource{}
  74. }
  75. for id, v := range p.Resource.CommonParams {
  76. if v.ID == "" {
  77. v.ID = id
  78. }
  79. }
  80. if err = JsonParseMode(p.Paths.Project("/env/environment"), mode, &p.Environment); err != nil {
  81. return nil, err
  82. }
  83. for id, variable := range p.Environment {
  84. variable.ID = id
  85. }
  86. p.Metrics = map[string]*Metric{}
  87. // Carrega os arquivos de entidades localizados na pasta entities
  88. // path = fmt.Sprintf("%s/metrics", directory)
  89. path = p.Paths.Project("/metrics")
  90. if files, err = GetFiles(path); err == nil {
  91. fmt.Println("Read metrics...")
  92. for _, file := range files {
  93. if file.Name()[0] == '*' {
  94. continue
  95. }
  96. if !file.IsDir() {
  97. if err = ParseJson(filepath.Join(path, file.Name()), &p.Metrics); err != nil {
  98. return nil, err
  99. }
  100. }
  101. }
  102. }
  103. p.HasMetrics = len(p.Metrics)>0
  104. // Carrega os arquivos de entidades localizados na pasta entities
  105. path = p.Paths.Project("/entities")
  106. if files, err = GetFiles(path); err == nil {
  107. fmt.Println("Read entities...")
  108. for _, file := range files {
  109. if file.Name()[0] == '*' {
  110. continue
  111. }
  112. if !file.IsDir() {
  113. entity = &Entity{}
  114. if err = ParseJson(filepath.Join(path, file.Name()), entity); err != nil {
  115. return nil, err
  116. }
  117. p.Schemas = append(p.Schemas, entity)
  118. }
  119. }
  120. }
  121. // Carrega os arquivos de recursos localizados na pasta resources
  122. path = p.Paths.Project("/resources")
  123. if files, err = GetFiles(path); err == nil {
  124. fmt.Println("Read resources...")
  125. for _, file := range files {
  126. if file.Name()[0] == '*' {
  127. continue
  128. }
  129. resource = &Resource{}
  130. if err = ParseJson(filepath.Join(path, file.Name()), resource); err != nil {
  131. return nil, err
  132. }
  133. if file.Name() == "global.json" {
  134. p.Resource = resource
  135. } else {
  136. p.Resources = append(p.Resources, resource)
  137. }
  138. }
  139. }
  140. // Inicializa variaveis do projeto
  141. if p.OmitEmpty == nil {
  142. p.OmitEmpty = map[string]bool{}
  143. }
  144. p.ReplaceWhenEmpty = map[string]bool{
  145. "json": true,
  146. "bson": true,
  147. }
  148. // p.OmitEmpty["json"] = true
  149. // p.OmitEmpty["bson"] = true
  150. // Atualiza o mapeamento de entidades e resources
  151. p.SchemasRef = map[string]*Entity{}
  152. for _, s := range p.Schemas {
  153. id = GenericPart.ReplaceAllString(s.ID, "")
  154. for _, p := range s.Properties {
  155. if err = p.ParseAutogenerate(); err != nil {
  156. return nil, err
  157. }
  158. }
  159. p.SchemasRef[id] = s
  160. p.SchemasRef[id+"Reference"] = SchemaReference(s)
  161. p.SchemasRef[id+"Input"] = SchemaInput(s)
  162. }
  163. for _, r := range p.Resources {
  164. format := map[string]*Value{}
  165. for _, f := range r.Formats {
  166. switch f.Fields {
  167. case "@all":
  168. f.Fields = ""
  169. case "@reference":
  170. if ref, found := p.SchemasRef[r.Entity+"Reference"]; found {
  171. fields := []string{}
  172. for _, propertie := range ref.Properties {
  173. fields = append(fields, propertie.ID)
  174. }
  175. f.Fields = strings.Join(fields, ",")
  176. }
  177. }
  178. format[f.Value] = f
  179. }
  180. for _, m := range r.Methods {
  181. m.Resource = r
  182. m.Entity = r.Entity
  183. m.Parameters = map[string]*Parameter{}
  184. if p.Resource.CommonParams == nil {
  185. continue
  186. }
  187. for _, p1 := range m.ParametersString {
  188. if p2, ok := p.Resource.CommonParams[p1]; ok {
  189. m.Parameters[p1] = p2
  190. } else {
  191. panic(fmt.Errorf("Param '%s' not defined!", p1))
  192. }
  193. }
  194. for _, param := range m.Parameters {
  195. if _, ok := paramAcceptFiled[param.ID]; ok {
  196. continue
  197. }
  198. paramAcceptFiled[param.ID] = true
  199. if param.ConvertTo == "" {
  200. param.ConvertTo = param.Type
  201. }
  202. // if param.Validation != nil {
  203. // if param.Validation.AcceptRef != nil {
  204. // for _, accept := range param.Validation.AcceptRef {
  205. // param.Validation.Accept = append(param.Validation.Accept, format[accept])
  206. // }
  207. // }
  208. // if param.Validation.RejectRef != nil {
  209. // for _, reject := range param.Validation.RejectRef {
  210. // param.Validation.Reject = append(param.Validation.Reject, format[reject])
  211. // }
  212. // }
  213. // }
  214. }
  215. }
  216. }
  217. if err = interpolateProject(p); err != nil {
  218. return nil, err
  219. }
  220. // o, _ := json.Marshal(p)
  221. readBuildVersion(p, directory)
  222. return p, nil
  223. }
  224. func readBuildVersion(project *Project, directory string) {
  225. var (
  226. filename = project.Paths.Project("/.buildversion")
  227. build = ""
  228. buildInt = 0
  229. err error
  230. )
  231. defer func() {
  232. FilePutContents(filename, strconv.Itoa(buildInt), 0777)
  233. }()
  234. if build, err = FileGetContents(filename); err != nil {
  235. build = "0"
  236. }
  237. buildInt, _ = strconv.Atoi(build)
  238. buildInt++
  239. project.BuildVersion = fmt.Sprintf("%s.%d", project.Version, buildInt)
  240. }
  241. func SchemaReference(s *Entity) *Entity {
  242. x := *s
  243. x.Properties = []*Propertie{}
  244. for _, p := range s.Properties {
  245. if p.Reference {
  246. x.Properties = append(x.Properties, p)
  247. }
  248. }
  249. return &x
  250. }
  251. func SchemaInput(s *Entity) *Entity {
  252. x := *s
  253. x.Properties = []*Propertie{}
  254. for _, p := range s.Properties {
  255. if !p.Readonly {
  256. x.Properties = append(x.Properties, p)
  257. }
  258. }
  259. return &x
  260. }
  261. func interpolateProject(project *Project) (err error) {
  262. data := map[string]interface{}{
  263. "baseUrl": project.BaseURL,
  264. }
  265. for _, resource := range project.Resources {
  266. data["entity"] = resource.Entity
  267. for _, method := range resource.Methods {
  268. method.Request = ResolveParams(method.Request, data)
  269. method.Response = ResolveParams(method.Response, data)
  270. // replace baseurl in scopes
  271. scopes := []string{}
  272. for _, scope := range method.Scopes {
  273. scopes = append(
  274. scopes,
  275. ResolveParams(scope, data),
  276. )
  277. }
  278. method.Scopes = scopes
  279. }
  280. }
  281. for _, variable := range project.Environment {
  282. variable.Default = ResolveParams(variable.Default, data)
  283. }
  284. return
  285. }
  286. func loadQueries(project *Project, directory string) (err error) {
  287. var (
  288. files []os.FileInfo
  289. data string
  290. queryKey string
  291. )
  292. path := project.Paths.Project("/queries")
  293. if files, err = GetFiles(path); err == nil {
  294. fmt.Println("Read queries...")
  295. for _, file := range files {
  296. if file.Name()[0] == '*' {
  297. continue
  298. }
  299. // resource = &Resource{}
  300. if data, err = FileGetContents(filepath.Join(path, file.Name())); err != nil {
  301. return
  302. }
  303. queryKey = strings.ReplaceAll(strings.ReplaceAll(file.Name(), "_", ":"), ".json", "")
  304. data = removeAllSpacesExpression.ReplaceAllString(data, "")
  305. data = expandTranscludeExpression.ReplaceAllStringFunc(data, func(input string) string {
  306. parts := strings.Split(input, ":")
  307. selector := strings.Trim(parts[len(parts)-1], `"`)
  308. return fmt.Sprintf("{._transclude_%s}", selector)
  309. })
  310. data = expandVarExpression.ReplaceAllStringFunc(data, func(input string) string {
  311. input = strings.TrimLeft(strings.TrimRight(input, `"`), `"$`)
  312. return fmt.Sprintf("{{%s}}", input)
  313. })
  314. project.Queries.Queries[queryKey] = data
  315. }
  316. }
  317. return
  318. }
  319. func expandQueries(project *Project) (err error) {
  320. var (
  321. newquery string
  322. found bool
  323. )
  324. for key, query := range project.Queries.Queries {
  325. if len(query) > 0 && query[0] == '$' {
  326. if newquery, found = project.Queries.Queries[query[1:]]; !found {
  327. panic(fmt.Errorf("Query `%s` not defined", query[1:]))
  328. }
  329. project.Queries.Queries[key] = newquery
  330. }
  331. }
  332. return
  333. }