package gen import ( "fmt" "os" "path/filepath" "regexp" "strconv" "strings" . "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/common" GO "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/translate/got" TS "git.eugeniocarvalho.dev/eugeniucarvalho/apicodegen/translate/tst" ) func CreateProject(mode string) (*Project, error) { var ( err error path string id string files []os.FileInfo entity *Entity resource *Resource directory string 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, }, } ) if directory, err = os.Getwd(); err != nil { return nil, err } // Carrega a configuracao default do projeto // root := []string{fmt.Sprintf("%s/project.json", directory)} // if mode != "" { // root = append(root, fmt.Sprintf("%s/project.%s.json", directory, mode)) // } // for _, file := range root { // if file == "" { // continue // } // if err = ParseJson(file, p); err != nil { // return nil, err // } // } if err = JsonParseMode(fmt.Sprintf("%s/project", directory), mode, p); err != nil { return nil, err } if err = ParseJson("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("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("env/environment", mode, &p.Environment); err != nil { return nil, err } for id, variable := range p.Environment { variable.ID = id } // Carrega os arquivos de entidades localizados na pasta entities path = fmt.Sprintf("%s/entities", directory) 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 = fmt.Sprintf("%s/resources", directory) 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 = fmt.Sprintf("%s/buildversion", directory) 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 } } // enviroment variables // for _, variable := range project.Environment { variable.Default = ResolveParams(variable.Default, data) } return } var ( expandTranscludeExpression = regexp.MustCompile(`"\$\._transclude_":true`) expandVarExpression = regexp.MustCompile(`"\$(\.\w+)"`) removeAllSpacesExpression = regexp.MustCompile(`(\s|\t|\r|\n)+`) ) func loadQueries(project *Project, directory string) (err error) { var ( files []os.FileInfo data string queryKey string ) path := fmt.Sprintf("%s/queries", directory) 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 { return "{._transclude_}" }) 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 }