gen.go 8.8 KB

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