package gen import ( "fmt" "os" "path/filepath" "regexp" "strconv" "strings" . "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/common" "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/flag" GO "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/translate/got" TS "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/translate/tst" ) var ( expandTranscludeExpression = regexp.MustCompile(`"\$\._transclude_":(true|"\w+")`) expandVarExpression = regexp.MustCompile(`"\$(\.\w+)"`) removeAllSpacesExpression = regexp.MustCompile(`(\s|\t|\r|\n)+`) ) func CreateProject() (*Project, error) { var ( err error path string id string files []os.FileInfo entity *Entity resource *Resource directory string mode = *flag.Mode paramAcceptFiled = map[string]bool{} p = &Project{ Mode: mode, SchemasRef: map[string]*Entity{}, Icons: map[string]string{}, ReplaceWhenEmpty: map[string]bool{}, OmitEmpty: map[string]bool{}, FormatMap: map[string]string{}, Queries: &QueryDef{}, Translators: map[string]TranslationFn{ "go": GO.Translate, "angular6": TS.Translate, }, TranslatorBuildOptionsMap: map[string]func(*Project, *BuildOptions) (*BuildSet, error){ "go": GO.Build, "angular6": TS.Build, }, } ) if directory, err = os.Getwd(); err != nil { return nil, err } root, _ := filepath.Abs("../") p.Paths = PathMap{ "current": root, "dist": fmt.Sprintf("%s/dist", root), "build": fmt.Sprintf("%s/build", root), "include": fmt.Sprintf("%s/project/include", root), "project": fmt.Sprintf("%s/project", root), } if err = JsonParseMode(p.Paths.Project("/project"), mode, p); err != nil { return nil, err } if err = ParseJson(p.Paths.Project("/queries.json"), &p.Queries); err != nil { p.Queries.Blacklistwords = map[string][]string{} p.Queries.Queries = map[string]string{} } if err = loadQueries(p, directory); err != nil { return nil, err } if err = expandQueries(p); err != nil { return nil, err } if err = ParseJson(p.Paths.Project("/common.json"), &p.Resource); err != nil { p.Resource = &Resource{} } for id, v := range p.Resource.CommonParams { if v.ID == "" { v.ID = id } } if err = JsonParseMode(p.Paths.Project("/env/environment"), mode, &p.Environment); err != nil { return nil, err } for id, variable := range p.Environment { variable.ID = id } p.Metrics = map[string]*Metric{} // Carrega os arquivos de entidades localizados na pasta entities // path = fmt.Sprintf("%s/metrics", directory) path = p.Paths.Project("/metrics") if files, err = GetFiles(path); err == nil { fmt.Println("Read metrics...") for _, file := range files { if file.Name()[0] == '*' { continue } if !file.IsDir() { if err = ParseJson(filepath.Join(path, file.Name()), &p.Metrics); err != nil { return nil, err } } } } p.HasMetrics = len(p.Metrics)>0 // Carrega os arquivos de entidades localizados na pasta entities path = p.Paths.Project("/entities") if files, err = GetFiles(path); err == nil { fmt.Println("Read entities...") for _, file := range files { if file.Name()[0] == '*' { continue } if !file.IsDir() { entity = &Entity{} if err = ParseJson(filepath.Join(path, file.Name()), entity); err != nil { return nil, err } p.Schemas = append(p.Schemas, entity) } } } // Carrega os arquivos de recursos localizados na pasta resources path = p.Paths.Project("/resources") if files, err = GetFiles(path); err == nil { fmt.Println("Read resources...") for _, file := range files { if file.Name()[0] == '*' { continue } resource = &Resource{} if err = ParseJson(filepath.Join(path, file.Name()), resource); err != nil { return nil, err } if file.Name() == "global.json" { p.Resource = resource } else { p.Resources = append(p.Resources, resource) } } } // Inicializa variaveis do projeto if p.OmitEmpty == nil { p.OmitEmpty = map[string]bool{} } p.ReplaceWhenEmpty = map[string]bool{ "json": true, "bson": true, } // p.OmitEmpty["json"] = true // p.OmitEmpty["bson"] = true // Atualiza o mapeamento de entidades e resources p.SchemasRef = map[string]*Entity{} for _, s := range p.Schemas { id = GenericPart.ReplaceAllString(s.ID, "") for _, p := range s.Properties { if err = p.ParseAutogenerate(); err != nil { return nil, err } } p.SchemasRef[id] = s p.SchemasRef[id+"Reference"] = SchemaReference(s) p.SchemasRef[id+"Input"] = SchemaInput(s) } for _, r := range p.Resources { format := map[string]*Value{} for _, f := range r.Formats { switch f.Fields { case "@all": f.Fields = "" case "@reference": if ref, found := p.SchemasRef[r.Entity+"Reference"]; found { fields := []string{} for _, propertie := range ref.Properties { fields = append(fields, propertie.ID) } f.Fields = strings.Join(fields, ",") } } format[f.Value] = f } for _, m := range r.Methods { m.Resource = r m.Entity = r.Entity m.Parameters = map[string]*Parameter{} if p.Resource.CommonParams == nil { continue } for _, p1 := range m.ParametersString { if p2, ok := p.Resource.CommonParams[p1]; ok { m.Parameters[p1] = p2 } else { panic(fmt.Errorf("Param '%s' not defined!", p1)) } } for _, param := range m.Parameters { if _, ok := paramAcceptFiled[param.ID]; ok { continue } paramAcceptFiled[param.ID] = true if param.ConvertTo == "" { param.ConvertTo = param.Type } // if param.Validation != nil { // if param.Validation.AcceptRef != nil { // for _, accept := range param.Validation.AcceptRef { // param.Validation.Accept = append(param.Validation.Accept, format[accept]) // } // } // if param.Validation.RejectRef != nil { // for _, reject := range param.Validation.RejectRef { // param.Validation.Reject = append(param.Validation.Reject, format[reject]) // } // } // } } } } if err = interpolateProject(p); err != nil { return nil, err } // o, _ := json.Marshal(p) readBuildVersion(p, directory) return p, nil } func readBuildVersion(project *Project, directory string) { var ( filename = project.Paths.Project("/.buildversion") build = "" buildInt = 0 err error ) defer func() { FilePutContents(filename, strconv.Itoa(buildInt), 0777) }() if build, err = FileGetContents(filename); err != nil { build = "0" } buildInt, _ = strconv.Atoi(build) buildInt++ project.BuildVersion = fmt.Sprintf("%s.%d", project.Version, buildInt) } func SchemaReference(s *Entity) *Entity { x := *s x.Properties = []*Propertie{} for _, p := range s.Properties { if p.Reference { x.Properties = append(x.Properties, p) } } return &x } func SchemaInput(s *Entity) *Entity { x := *s x.Properties = []*Propertie{} for _, p := range s.Properties { if !p.Readonly { x.Properties = append(x.Properties, p) } } return &x } func interpolateProject(project *Project) (err error) { data := map[string]interface{}{ "baseUrl": project.BaseURL, } for _, resource := range project.Resources { data["entity"] = resource.Entity for _, method := range resource.Methods { method.Request = ResolveParams(method.Request, data) method.Response = ResolveParams(method.Response, data) // replace baseurl in scopes scopes := []string{} for _, scope := range method.Scopes { scopes = append( scopes, ResolveParams(scope, data), ) } method.Scopes = scopes } } for _, variable := range project.Environment { variable.Default = ResolveParams(variable.Default, data) } return } func loadQueries(project *Project, directory string) (err error) { var ( files []os.FileInfo data string queryKey string ) path := project.Paths.Project("/queries") if files, err = GetFiles(path); err == nil { fmt.Println("Read queries...") for _, file := range files { if file.Name()[0] == '*' { continue } // resource = &Resource{} if data, err = FileGetContents(filepath.Join(path, file.Name())); err != nil { return } queryKey = strings.ReplaceAll(strings.ReplaceAll(file.Name(), "_", ":"), ".json", "") data = removeAllSpacesExpression.ReplaceAllString(data, "") data = expandTranscludeExpression.ReplaceAllStringFunc(data, func(input string) string { parts := strings.Split(input, ":") selector := strings.Trim(parts[len(parts)-1], `"`) return fmt.Sprintf("{._transclude_%s}", selector) }) data = expandVarExpression.ReplaceAllStringFunc(data, func(input string) string { input = strings.TrimLeft(strings.TrimRight(input, `"`), `"$`) return fmt.Sprintf("{{%s}}", input) }) project.Queries.Queries[queryKey] = data } } return } func expandQueries(project *Project) (err error) { var ( newquery string found bool ) for key, query := range project.Queries.Queries { if len(query) > 0 && query[0] == '$' { if newquery, found = project.Queries.Queries[query[1:]]; !found { panic(fmt.Errorf("Query `%s` not defined", query[1:])) } project.Queries.Queries[key] = newquery } } return }