gen.go 8.5 KB

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