~repos /gromer

#golang#htmx#ssr

git clone https://pyrossh.dev/repos/gromer.git

gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.


76c43570 Peter John

4 years ago
rename package and fix bugs
Files changed (11) hide show
  1. api_explorer.go +3 -3
  2. cmd/{wapp → gromer}/main.go +31 -23
  3. css.go +3 -2
  4. go.mod +4 -1
  5. go.sum +12 -0
  6. hooks.go +1 -1
  7. hooks_test.go +1 -1
  8. html.go +1 -118
  9. html_test.go +1 -1
  10. http.go +133 -0
  11. readme.md +10 -15
api_explorer.go CHANGED
@@ -1,4 +1,4 @@
1
- package wapp
1
+ package gromer
2
2
 
3
3
  import (
4
4
  "context"
@@ -51,8 +51,8 @@ func ApiExplorer(apiDefs []ApiDefinition) func(c context.Context) (HtmlPage, int
51
51
  Head(
52
52
  Title("Example"),
53
53
  Meta("description", "Example"),
54
- Meta("author", "pyros2097"),
54
+ Meta("author", "pyros.sh"),
55
- Meta("keywords", "wapp,pyros2097"),
55
+ Meta("keywords", "pyros.sh, gromer"),
56
56
  Meta("viewport", "width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, viewport-fit=cover"),
57
57
  Link("icon", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEU0OkArMjhobHEoPUPFEBIuO0L+AAC2FBZ2JyuNICOfGx7xAwTjCAlCNTvVDA1aLzQ3COjMAAAAVUlEQVQI12NgwAaCDSA0888GCItjn0szWGBJTVoGSCjWs8TleQCQYV95evdxkFT8Kpe0PLDi5WfKd4LUsN5zS1sKFolt8bwAZrCaGqNYJAgFDEpQAAAzmxafI4vZWwAAAABJRU5ErkJggg=="),
58
58
  Link("stylesheet", "https://cdn.jsdelivr.net/npm/codemirror@5.63.1/lib/codemirror.css"),
cmd/{wapp → gromer}/main.go RENAMED
@@ -2,6 +2,7 @@ package main
2
2
 
3
3
  import (
4
4
  "bytes"
5
+ "flag"
5
6
  "fmt"
6
7
  "io/ioutil"
7
8
  "log"
@@ -10,7 +11,7 @@ import (
10
11
  "strings"
11
12
 
12
13
  "github.com/gobuffalo/velvet"
13
- "github.com/pyros2097/wapp"
14
+ "github.com/pyros2097/gromer"
14
15
  "golang.org/x/mod/modfile"
15
16
  )
16
17
 
@@ -78,7 +79,7 @@ func rewritePkg(pkg string) string {
78
79
  return lastItem
79
80
  }
80
81
 
81
- func getApiFunc(method, route string, params []string) wapp.ApiDefinition {
82
+ func getApiFunc(method, route string, params []string) gromer.ApiDefinition {
82
83
  muxRoute := bytes.NewBuffer(nil)
83
84
  foundStart := false
84
85
  for _, v := range route {
@@ -92,7 +93,7 @@ func getApiFunc(method, route string, params []string) wapp.ApiDefinition {
92
93
  muxRoute.WriteString(string(v))
93
94
  }
94
95
  }
95
- return wapp.ApiDefinition{
96
+ return gromer.ApiDefinition{
96
97
  Method: method,
97
98
  PathParams: params,
98
99
  Path: muxRoute.String(),
@@ -154,19 +155,26 @@ func getApiFunc(method, route string, params []string) wapp.ApiDefinition {
154
155
  // }
155
156
 
156
157
  func main() {
158
+ moduleName := ""
159
+ pkgFlag := flag.String("pkg", "", "specify a package name")
160
+ flag.Parse()
161
+ if pkgFlag == nil || *pkgFlag == "" {
157
- data, err := ioutil.ReadFile("go.mod")
162
+ data, err := ioutil.ReadFile("go.mod")
158
- if err != nil {
163
+ if err != nil {
159
- log.Fatalf("go.mod file not found %s", err.Error())
164
+ log.Fatalf("go.mod file not found %s", err.Error())
160
- }
165
+ }
161
- modTree, err := modfile.Parse("go.mod", data, nil)
166
+ modTree, err := modfile.Parse("go.mod", data, nil)
162
- if err != nil {
167
+ if err != nil {
163
- log.Fatalf("could not parse go.mod %s", err.Error())
168
+ log.Fatalf("could not parse go.mod %s", err.Error())
169
+ }
170
+ moduleName = modTree.Module.Mod.Path
171
+ } else {
172
+ moduleName = *pkgFlag
164
173
  }
165
- moduleName := modTree.Module.Mod.Path
166
174
  routes := []*Route{}
167
- apiDefs := []wapp.ApiDefinition{}
175
+ apiDefs := []gromer.ApiDefinition{}
168
176
  allPkgs := map[string]string{}
169
- err = filepath.Walk("pages",
177
+ err := filepath.Walk("pages",
170
178
  func(filesrc string, info os.FileInfo, err error) error {
171
179
  if err != nil {
172
180
  return err
@@ -182,7 +190,7 @@ func main() {
182
190
  pkg = "pages"
183
191
  }
184
192
  routePath := rewritePath(path)
185
- params := wapp.GetRouteParams(routePath)
193
+ params := gromer.GetRouteParams(routePath)
186
194
  routes = append(routes, &Route{
187
195
  Method: method,
188
196
  Path: routePath,
@@ -206,7 +214,7 @@ func main() {
206
214
  ctx.Set("routes", routes)
207
215
  ctx.Set("apiDefs", apiDefs)
208
216
  ctx.Set("tick", "`")
209
- s, err := velvet.Render(`// Code generated by wapp. DO NOT EDIT.
217
+ s, err := velvet.Render(`// Code generated by gromer. DO NOT EDIT.
210
218
  package main
211
219
 
212
220
  import (
@@ -217,7 +225,7 @@ import (
217
225
 
218
226
  "github.com/apex/gateway/v2"
219
227
  "github.com/gorilla/mux"
220
- "github.com/pyros2097/wapp"
228
+ "github.com/pyros2097/gromer"
221
229
  "github.com/rs/zerolog/log"
222
230
  "gocloud.dev/server"
223
231
 
@@ -234,7 +242,7 @@ func main() {
234
242
  r := mux.NewRouter()
235
243
  r.NotFoundHandler = http.HandlerFunc(notFound)
236
244
  r.PathPrefix("/assets/").Handler(wrapCache(http.FileServer(http.FS(assetsFS))))
237
- handle(r, "GET", "/api", wapp.ApiExplorer(apiDefinitions()))
245
+ handle(r, "GET", "/api", gromer.ApiExplorer(apiDefinitions()))
238
246
  {{#each routes as |route| }}handle(r, "{{ route.Method }}", "{{ route.Path }}", {{ route.Pkg }}.{{ route.Method }})
239
247
  {{/each}}
240
248
  if !isLambda {
@@ -259,14 +267,14 @@ func wrapCache(h http.Handler) http.Handler {
259
267
  }
260
268
 
261
269
  func notFound(w http.ResponseWriter, r *http.Request) {
262
- wapp.LogReq(404, r)
270
+ gromer.LogReq(404, r)
263
271
  }
264
272
 
265
273
  func handle(router *mux.Router, method, route string, h interface{}) {
266
274
  router.HandleFunc(route, func(w http.ResponseWriter, r *http.Request) {
267
275
  var status int
268
276
  defer func() {
269
- wapp.LogReq(status, r)
277
+ gromer.LogReq(status, r)
270
278
  }()
271
279
  ctx, err := context.WithContext(c.WithValue(
272
280
  c.WithValue(
@@ -274,18 +282,18 @@ func handle(router *mux.Router, method, route string, h interface{}) {
274
282
  "url", r.URL),
275
283
  "header", r.Header))
276
284
  if err != nil {
277
- wapp.RespondError(w, 500, err)
285
+ gromer.RespondError(w, 500, err)
278
286
  return
279
287
  }
280
- status, err = wapp.PerformRequest(route, h, ctx, w, r)
288
+ status, err = gromer.PerformRequest(route, h, ctx, w, r)
281
289
  if err != nil {
282
290
  log.Error().Stack().Err(err).Msg("")
283
291
  }
284
292
  }).Methods(method)
285
293
  }
286
294
 
287
- func apiDefinitions() []wapp.ApiDefinition {
295
+ func apiDefinitions() []gromer.ApiDefinition {
288
- return []wapp.ApiDefinition{
296
+ return []gromer.ApiDefinition{
289
297
  {{#each apiDefs as |api| }}
290
298
  {
291
299
  Method: "{{api.Method}}",
css.go CHANGED
@@ -1,4 +1,4 @@
1
- package wapp
1
+ package gromer
2
2
 
3
3
  type M map[string]interface{}
4
4
  type MS map[string]string
@@ -467,8 +467,9 @@ func mapApply(obj KeyValues) {
467
467
  twClassLookup[className] = vstring + ": " + vv + ";"
468
468
  }
469
469
  if varr, ok := v.(Arr); ok {
470
+ twClassLookup[className] = ""
470
471
  for _, kk := range varr {
471
- twClassLookup[className] = kk.(string) + ": " + vv + ";"
472
+ twClassLookup[className] += kk.(string) + ": " + vv + ";"
472
473
  }
473
474
  }
474
475
  }
go.mod CHANGED
@@ -1,9 +1,10 @@
1
- module github.com/pyros2097/wapp
1
+ module github.com/pyros2097/gromer
2
2
 
3
3
  go 1.16
4
4
 
5
5
  require (
6
6
  git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999 // indirect
7
+ github.com/apex/gateway/v2 v2.0.0 // indirect
7
8
  github.com/aymerick/raymond v2.0.2+incompatible // indirect
8
9
  github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect
9
10
  github.com/bradleyjkemp/cupaloy v2.3.0+incompatible
@@ -19,6 +20,7 @@ require (
19
20
  github.com/gobuffalo/velvet v0.0.0-20170320144106-d97471bf5d8f
20
21
  github.com/gogo/protobuf v1.1.1 // indirect
21
22
  github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 // indirect
23
+ github.com/google/uuid v1.3.0 // indirect
22
24
  github.com/googleapis/gax-go v2.0.0+incompatible // indirect
23
25
  github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
24
26
  github.com/gorilla/context v1.1.1 // indirect
@@ -28,6 +30,7 @@ require (
28
30
  github.com/jonboulle/clockwork v0.1.0 // indirect
29
31
  github.com/jtolds/gls v4.2.1+incompatible // indirect
30
32
  github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
33
+ github.com/lib/pq v1.10.4 // indirect
31
34
  github.com/markbates/inflect v1.0.4 // indirect
32
35
  github.com/mattn/go-isatty v0.0.14 // indirect
33
36
  github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
go.sum CHANGED
@@ -97,7 +97,11 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
97
97
  github.com/GoogleCloudPlatform/cloudsql-proxy v1.24.0/go.mod h1:3tx938GhY4FC+E1KT/jNjDw7Z5qxAEtIiERJ2sXjnII=
98
98
  github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
99
99
  github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
100
+ github.com/apex/gateway/v2 v2.0.0 h1:tJwKiB7ObbXuF3yoqTf/CfmaZRhHB+GfilTNSCf1Wnc=
101
+ github.com/apex/gateway/v2 v2.0.0/go.mod h1:y+uuK0JxdvTHZeVns501/7qklBhnDHtGU0hfUQ6QIfI=
100
102
  github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
103
+ github.com/aws/aws-lambda-go v1.17.0 h1:Ogihmi8BnpmCNktKAGpNwSiILNNING1MiosnKUfU8m0=
104
+ github.com/aws/aws-lambda-go v1.17.0/go.mod h1:FEwgPLE6+8wcGBTe5cJN3JWurd1Ztm9zN4jsXsjzKKw=
101
105
  github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
102
106
  github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
103
107
  github.com/aws/aws-sdk-go v1.40.34/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
@@ -138,6 +142,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
138
142
  github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
139
143
  github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
140
144
  github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
145
+ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
141
146
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
142
147
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
143
148
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -263,6 +268,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
263
268
  github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
264
269
  github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
265
270
  github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
271
+ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
266
272
  github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
267
273
  github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
268
274
  github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
@@ -307,6 +313,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
307
313
  github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
308
314
  github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
309
315
  github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
316
+ github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
317
+ github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
310
318
  github.com/markbates/inflect v1.0.4 h1:5fh1gzTFhfae06u3hzHYO9xe3l3v3nW5Pwt3naLTP5g=
311
319
  github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
312
320
  github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
@@ -340,6 +348,7 @@ github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
340
348
  github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
341
349
  github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
342
350
  github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
351
+ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
343
352
  github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
344
353
  github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
345
354
  github.com/shurcooL/github_flavored_markdown v0.0.0-20210228213109-c3a9aa474629 h1:86e54L0i3pH3dAIA8OxBbfLrVyhoGpnNk1iJCigAWYs=
@@ -375,9 +384,11 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
375
384
  github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
376
385
  github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
377
386
  github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
387
+ github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
378
388
  github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
379
389
  github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
380
390
  github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
391
+ github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
381
392
  github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
382
393
  github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
383
394
  github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -804,6 +815,7 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
804
815
  gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
805
816
  gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
806
817
  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
818
+ gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
807
819
  gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
808
820
  gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
809
821
  gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
hooks.go CHANGED
@@ -1,4 +1,4 @@
1
- package wapp
1
+ package gromer
2
2
 
3
3
  type Context struct {
4
4
  index int
hooks_test.go CHANGED
@@ -1,4 +1,4 @@
1
- package wapp
1
+ package gromer
2
2
 
3
3
  import (
4
4
  "testing"
html.go CHANGED
@@ -1,28 +1,13 @@
1
- package wapp
1
+ package gromer
2
2
 
3
3
  import (
4
4
  "bytes"
5
- "encoding/json"
6
5
  "fmt"
7
6
  "io"
8
- "net/http"
9
- "os"
10
- "reflect"
11
- "regexp"
12
7
  "strconv"
13
8
  "strings"
14
-
15
- "github.com/fatih/color"
16
- "github.com/gorilla/mux"
17
- "github.com/rs/zerolog"
18
- "github.com/rs/zerolog/log"
19
9
  )
20
10
 
21
- func init() {
22
- zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
23
- log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
24
- }
25
-
26
11
  func writeIndent(w io.Writer, indent int) {
27
12
  for i := 0; i < indent*2; i++ {
28
13
  w.Write([]byte(" "))
@@ -413,105 +398,3 @@ func XData(v string) Attribute {
413
398
  func XText(v string) Attribute {
414
399
  return Attribute{"x-text", v}
415
400
  }
416
-
417
- func RespondError(w http.ResponseWriter, status int, err error) {
418
- w.WriteHeader(status)
419
- w.Header().Set("Content-Type", "application/json")
420
- data, _ := json.Marshal(map[string]string{
421
- "error": err.Error(),
422
- })
423
- w.Write(data)
424
- }
425
-
426
- var pathParamsRegex = regexp.MustCompile(`{(.*?)}`)
427
-
428
- func GetRouteParams(route string) []string {
429
- params := []string{}
430
- found := pathParamsRegex.FindAllString(route, -1)
431
- for _, v := range found {
432
- params = append(params, strings.Replace(strings.Replace(v, "}", "", 1), "{", "", 1))
433
- }
434
- return params
435
- }
436
-
437
- func PerformRequest(route string, h interface{}, ctx interface{}, w http.ResponseWriter, r *http.Request) (int, error) {
438
- params := GetRouteParams(route)
439
- args := []reflect.Value{reflect.ValueOf(ctx)}
440
- funcType := reflect.TypeOf(h)
441
- icount := funcType.NumIn()
442
- vars := mux.Vars(r)
443
- for _, k := range params {
444
- args = append(args, reflect.ValueOf(vars[k]))
445
- }
446
- if len(args) != icount {
447
- structType := funcType.In(icount - 1)
448
- instance := reflect.New(structType)
449
- if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" {
450
- err := json.NewDecoder(r.Body).Decode(instance.Interface())
451
- if err != nil {
452
- RespondError(w, 500, err)
453
- return 500, err
454
- }
455
- } else if r.Method == "GET" {
456
- rv := instance.Elem()
457
- for i := 0; i < structType.NumField(); i++ {
458
- if f := rv.Field(i); f.CanSet() {
459
- jsonName := structType.Field(i).Tag.Get("json")
460
- jsonValue := r.URL.Query().Get(jsonName)
461
- if f.Kind() == reflect.String {
462
- f.SetString(jsonValue)
463
- } else if f.Kind() == reflect.Int64 {
464
- v, err := strconv.ParseInt(jsonValue, 10, 64)
465
- if err != nil {
466
- RespondError(w, 500, err)
467
- return 500, err
468
- }
469
- f.SetInt(v)
470
- } else {
471
- panic("Uknown query param: " + jsonValue)
472
- }
473
- }
474
- }
475
- }
476
- args = append(args, instance.Elem())
477
- }
478
- values := reflect.ValueOf(h).Call(args)
479
- response := values[0].Interface()
480
- responseStatus := values[1].Interface().(int)
481
- responseError := values[2].Interface()
482
- if responseError != nil {
483
- RespondError(w, responseStatus, responseError.(error))
484
- return responseStatus, responseError.(error)
485
- }
486
- if v, ok := response.(HtmlPage); ok {
487
- w.Header().Set("Content-Type", "text/html")
488
- // This has to be at end always
489
- w.WriteHeader(responseStatus)
490
- v.WriteHtml(w)
491
- return 200, nil
492
- }
493
- w.Header().Set("Content-Type", "application/json")
494
- // This has to be at end always
495
- w.WriteHeader(responseStatus)
496
- data, _ := json.Marshal(response)
497
- w.Write(data)
498
- return 200, nil
499
- }
500
-
501
- func LogReq(status int, r *http.Request) {
502
- a := color.FgGreen
503
- if status >= 500 {
504
- a = color.FgRed
505
- } else if status >= 400 {
506
- a = color.FgYellow
507
- }
508
- m := color.FgCyan
509
- if r.Method == "POST" {
510
- m = color.FgYellow
511
- } else if r.Method == "PUT" {
512
- m = color.FgMagenta
513
- } else if r.Method == "DELETE" {
514
- m = color.FgRed
515
- }
516
- log.Info().Msgf("%3s %s %s", color.New(a).Sprint(status), color.New(m).Sprintf("%-4s", r.Method), color.WhiteString(r.URL.Path))
517
- }
html_test.go CHANGED
@@ -1,4 +1,4 @@
1
- package wapp
1
+ package gromer
2
2
 
3
3
  import (
4
4
  "bytes"
http.go ADDED
@@ -0,0 +1,133 @@
1
+ package gromer
2
+
3
+ import (
4
+ "encoding/json"
5
+ "net/http"
6
+ "os"
7
+ "reflect"
8
+ "regexp"
9
+ "strconv"
10
+ "strings"
11
+
12
+ "github.com/fatih/color"
13
+ "github.com/gorilla/mux"
14
+ "github.com/rs/zerolog"
15
+ "github.com/rs/zerolog/log"
16
+ )
17
+
18
+ func init() {
19
+ zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
20
+ log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
21
+ }
22
+
23
+ func RespondError(w http.ResponseWriter, status int, err error) {
24
+ w.WriteHeader(status)
25
+ w.Header().Set("Content-Type", "application/json")
26
+ data, _ := json.Marshal(map[string]string{
27
+ "error": err.Error(),
28
+ })
29
+ w.Write(data)
30
+ }
31
+
32
+ var pathParamsRegex = regexp.MustCompile(`{(.*?)}`)
33
+
34
+ func GetRouteParams(route string) []string {
35
+ params := []string{}
36
+ found := pathParamsRegex.FindAllString(route, -1)
37
+ for _, v := range found {
38
+ params = append(params, strings.Replace(strings.Replace(v, "}", "", 1), "{", "", 1))
39
+ }
40
+ return params
41
+ }
42
+
43
+ func PerformRequest(route string, h interface{}, ctx interface{}, w http.ResponseWriter, r *http.Request) (int, error) {
44
+ params := GetRouteParams(route)
45
+ args := []reflect.Value{reflect.ValueOf(ctx)}
46
+ funcType := reflect.TypeOf(h)
47
+ icount := funcType.NumIn()
48
+ vars := mux.Vars(r)
49
+ for _, k := range params {
50
+ args = append(args, reflect.ValueOf(vars[k]))
51
+ }
52
+ if len(args) != icount {
53
+ structType := funcType.In(icount - 1)
54
+ instance := reflect.New(structType)
55
+ if structType.Kind() != reflect.Struct {
56
+ panic(route + " func final param should be a struct")
57
+ }
58
+ if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" {
59
+ err := json.NewDecoder(r.Body).Decode(instance.Interface())
60
+ if err != nil {
61
+ RespondError(w, 500, err)
62
+ return 500, err
63
+ }
64
+ } else if r.Method == "GET" {
65
+ rv := instance.Elem()
66
+ for i := 0; i < structType.NumField(); i++ {
67
+ if f := rv.Field(i); f.CanSet() {
68
+ jsonName := structType.Field(i).Tag.Get("json")
69
+ jsonValue := r.URL.Query().Get(jsonName)
70
+ if f.Kind() == reflect.String {
71
+ f.SetString(jsonValue)
72
+ } else if f.Kind() == reflect.Int64 {
73
+ v, err := strconv.ParseInt(jsonValue, 10, 64)
74
+ if err != nil {
75
+ RespondError(w, 500, err)
76
+ return 500, err
77
+ }
78
+ f.SetInt(v)
79
+ } else if f.Kind() == reflect.Int32 {
80
+ v, err := strconv.ParseInt(jsonValue, 10, 32)
81
+ if err != nil {
82
+ RespondError(w, 500, err)
83
+ return 500, err
84
+ }
85
+ f.SetInt(v)
86
+ } else {
87
+ panic("Uknown query param: " + jsonValue)
88
+ }
89
+ }
90
+ }
91
+ }
92
+ args = append(args, instance.Elem())
93
+ }
94
+ values := reflect.ValueOf(h).Call(args)
95
+ response := values[0].Interface()
96
+ responseStatus := values[1].Interface().(int)
97
+ responseError := values[2].Interface()
98
+ if responseError != nil {
99
+ RespondError(w, responseStatus, responseError.(error))
100
+ return responseStatus, responseError.(error)
101
+ }
102
+ if v, ok := response.(HtmlPage); ok {
103
+ w.Header().Set("Content-Type", "text/html")
104
+ // This has to be at end always
105
+ w.WriteHeader(responseStatus)
106
+ v.WriteHtml(w)
107
+ return 200, nil
108
+ }
109
+ w.Header().Set("Content-Type", "application/json")
110
+ // This has to be at end always
111
+ w.WriteHeader(responseStatus)
112
+ data, _ := json.Marshal(response)
113
+ w.Write(data)
114
+ return 200, nil
115
+ }
116
+
117
+ func LogReq(status int, r *http.Request) {
118
+ a := color.FgGreen
119
+ if status >= 500 {
120
+ a = color.FgRed
121
+ } else if status >= 400 {
122
+ a = color.FgYellow
123
+ }
124
+ m := color.FgCyan
125
+ if r.Method == "POST" {
126
+ m = color.FgYellow
127
+ } else if r.Method == "PUT" {
128
+ m = color.FgMagenta
129
+ } else if r.Method == "DELETE" {
130
+ m = color.FgRed
131
+ }
132
+ log.Info().Msgf("%3s %s %s", color.New(a).Sprint(status), color.New(m).Sprintf("%-4s", r.Method), color.WhiteString(r.URL.Path))
133
+ }
readme.md CHANGED
@@ -1,28 +1,23 @@
1
1
  <p align="center">
2
- <a href="https://goreportcard.com/report/github.com/pyros2097/wapp"><img src="https://goreportcard.com/badge/github.com/pyros2097/wapp" alt="Go Report Card"></a>
2
+ <a href="https://goreportcard.com/report/github.com/pyros2097/gromer"><img src="https://goreportcard.com/badge/github.com/pyros2097/gromer" alt="Go Report Card"></a>
3
- <a href="https://GitHub.com/pyros2097/wapp/releases/"><img src="https://img.shields.io/github/release/pyros2097/wapp.svg" alt="GitHub release"></a>
3
+ <a href="https://GitHub.com/pyros2097/gromer/releases/"><img src="https://img.shields.io/github/release/pyros2097/gromer.svg" alt="GitHub release"></a>
4
- <a href="https://pkg.go.dev/github.com/pyros2097/wapp"><img src="https://img.shields.io/badge/dev-reference-007d9c?logo=go&logoColor=white&style=flat" alt="pkg.go.dev docs"></a>
4
+ <a href="https://pkg.go.dev/github.com/pyros2097/gromer"><img src="https://img.shields.io/badge/dev-reference-007d9c?logo=go&logoColor=white&style=flat" alt="pkg.go.dev docs"></a>
5
5
  </p>
6
6
 
7
- # wapp
7
+ # gromer
8
8
 
9
- **wapp** is a framework to build web apps in golang.
9
+ **gromer** is a framework to build web apps in golang.
10
10
  It uses a declarative syntax using funcs that allows creating and dealing with HTML elements only by using Go, and without writing any HTML markup. It is highly opioninated and integrates uses tailwind css and alpinejs.
11
11
 
12
- # Install
13
-
14
- ```sh
15
- go mod init
16
- go get -u -v github.com/pyros2097/wapp
17
- ```
18
-
19
12
  # Install Cli
20
13
 
21
14
  ```sh
22
15
  go mod init
23
- go get -u -v github.com/pyros2097/wapp/cmd/wapp
16
+ go get -u -v github.com/pyros2097/wapp/cmd/gromer
24
17
  ```
25
18
 
26
- # Example
19
+ # Using
20
+ You need to follow this directory structure similar to nextjs for the api route handlers to be generated
21
+ Please look at the example for now,
27
22
 
28
- https://github.com/pyros2097/wapp-example
23
+ [Example](https://github.com/pyros2097/gromer/tree/master/example)