summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2024-11-17 14:55:05 +0100
committerMathias Magnusson <mathias@magnusson.space>2024-11-17 14:55:05 +0100
commit72440d0e3b2a8224b65491202798f5c0b18a2dde (patch)
treee75675956ab77bf635ade8f2599dfa060a66f83c /cmd
parent14db9705ae1c2a10bb5e62a66a72f5cbc7aa7b13 (diff)
downloadhh-72440d0e3b2a8224b65491202798f5c0b18a2dde.tar.gz
mkChangeItUp
Diffstat (limited to 'cmd')
-rw-r--r--cmd/generate/main.go128
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
}