diff options
author | Mathias Magnusson <mathias@magnusson.space> | 2024-11-17 14:55:05 +0100 |
---|---|---|
committer | Mathias Magnusson <mathias@magnusson.space> | 2024-11-17 14:55:05 +0100 |
commit | 72440d0e3b2a8224b65491202798f5c0b18a2dde (patch) | |
tree | e75675956ab77bf635ade8f2599dfa060a66f83c /cmd/generate/main.go | |
parent | 14db9705ae1c2a10bb5e62a66a72f5cbc7aa7b13 (diff) | |
download | hh-72440d0e3b2a8224b65491202798f5c0b18a2dde.tar.gz |
mkChangeItUp
Diffstat (limited to 'cmd/generate/main.go')
-rw-r--r-- | cmd/generate/main.go | 128 |
1 files changed, 97 insertions, 31 deletions
diff --git a/cmd/generate/main.go b/cmd/generate/main.go index 9f1f839..67e745c 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -8,7 +8,11 @@ import ( "go/parser" "go/scanner" "go/token" + "io" "net/http" + "os" + "reflect" + "slices" "strconv" "strings" ) @@ -19,59 +23,121 @@ func main() { } } +func slice(fileContents string, filePosInfo *token.File, start token.Pos, end token.Pos) string { + return fileContents[filePosInfo.Position(start).Offset:filePosInfo.Position(end).Offset] +} + func run() error { + filename := "examples/basic.go" + fileBytes, err := os.ReadFile(filename) + if err != nil { + return err + } + // fileContents := string(fileBytes) var fset token.FileSet - f, err := parser.ParseFile(&fset, "examples/basic.go", nil, parser.ParseComments|parser.SkipObjectResolution) + fp := fset.AddFile(filename, -1, len(fileBytes)) + _ = fp + f, err := parser.ParseFile(&fset, "examples/basic.go", fileBytes, parser.ParseComments|parser.SkipObjectResolution) if err != nil { return err } + var output bytes.Buffer + output.WriteString("package ") + output.WriteString(f.Name.Name) + output.WriteByte('\n') for _, decl := range f.Decls { f, ok := decl.(*ast.FuncDecl) if !ok { continue } + if f.Doc == nil { + continue + } hhRoute := f.Doc.List[len(f.Doc.List)-1].Text var routeSpec string if routeSpec, ok = strings.CutPrefix(hhRoute, "//hh:route "); !ok { continue } - rs, err := parseRouteSpec(routeSpec) - if err != nil { - return err + split := strings.Split(routeSpec, " ") + var method, path string + if len(split) == 1 { + path = split[0] + } else if len(split) == 2 { + method = split[0] + path = split[1] + } else { + return errors.New("Invalid route spec. Expected `//hh:route [method] [path]` or `//hh:route [path]`") } - var wrapper bytes.Buffer - wrapper.WriteString("func httpWrapper_") - wrapper.WriteString(f.Name.String()) - wrapper.WriteString("[S any](s S, r *http.Request, w http.ResponseWriter) {") - i := 0 - for _, p := range f.Type.Params.List { - for _, n := range p.Names { - wrapper.WriteString("\n\tvar") - wrapper.WriteString(strconv.Itoa(i)) - wrapper.WriteString(" := ") - wrapper.WriteString(n.Name) - i++ + if !slices.ContainsFunc([]string{ + "", + http.MethodGet, + http.MethodHead, + http.MethodPost, + http.MethodPut, + http.MethodPatch, + http.MethodDelete, + http.MethodConnect, + http.MethodOptions, + http.MethodTrace, + }, func(m string) bool { return m == method }) { + return errors.New("Invalid http method " + method) + } + output.WriteString("\nfunc hh_") + output.WriteString(f.Name.String()) + output.WriteString("[S any](s S, w http.ResponseWriter, r *http.Request) {") + parsedRequestType, ok := f.Type.Params.List[1].Type.(*ast.StructType) + if !ok { + return errors.New("Parsed request type must be a struct") + } + for _, field := range parsedRequestType.Fields.List { + for _, nameIdent := range field.Names { + typ := field.Type + name := nameIdent.Name + var tag string + if field.Tag != nil { + tag = reflect.StructTag(field.Tag.Value[1 : len(field.Tag.Value)-1]).Get("hh") + } + fmt.Println(typ, name, tag) + tags := strings.Split(tag, ",") + // TODO: handle raw request. Or maybe that should be a separate parameter + if len(tags) == 0 { + return errors.New("Don't know what to do with '" + name + "'. You must add a tag to specify") + } + switch tags[0] { + case "form": + output.WriteString("\n\t") + output.WriteString(name) + output.WriteString(" := r.FormValue(\"") + output.WriteString(name) + output.WriteString("\")") + case "cookie": + // panic("todo") + } } } - wrapper.WriteString("\t") - wrapper.WriteString(f.Name.Name) - wrapper.WriteString("(") - i = 0 - for _, p := range f.Type.Params.List { - for range p.Names { - if i > 0 { - wrapper.WriteString(", ") - } - wrapper.WriteString("var") - wrapper.WriteString(strconv.Itoa(i)) - i++ + i := 0 + output.WriteString("\n\t") + output.WriteString(f.Name.Name) + output.WriteString("(w, ") + i = 0 + for _, field := range parsedRequestType.Fields.List { + for _, nameIdent := range field.Names { + typ := field.Type + name := nameIdent.Name + if i > 0 { + output.WriteString(", ") + } + output.WriteString("var") + output.WriteString(strconv.Itoa(i)) + i++ } } - wrapper.WriteString(")\n") - wrapper.WriteString("}\n") + output.WriteString(")\n") + output.WriteString("}\n") - fmt.Printf("`%v`\n`%v`\n`%v`\n", routeSpec, f.Name.Name, rs) + fmt.Printf("`%v`\n`%v`\n", path, f.Name.Name) } + io.Copy(os.Stdout, &output) return nil } |