fixed makefile

This commit is contained in:
anthdm 2024-06-08 21:59:00 +02:00
parent 49f59f090f
commit e11eda9b3b
7 changed files with 210 additions and 30 deletions

View file

@ -8,7 +8,7 @@ endif
# re-create _templ.txt files on change, then send reload event to browser.
# Default url: http://localhost:7331
templ:
@templ generate --watch --proxy="http://localhost$(HTTP_LISTEN_ADDR)" --open-browser=false -v
@go run github.com/a-h/templ/cmd/templ@latest generate --watch --proxy="http://localhost$(HTTP_LISTEN_ADDR)" --open-browser=false -v
# run air to detect any go file changes to re-build and re-run the server.
server:
@ -30,7 +30,7 @@ esbuild:
# watch for any js or css change in the assets/ folder, then reload the browser via templ proxy.
sync_assets:
go run github.com/cosmtrek/air@v1.51.0 \
--build.cmd "templ generate --notify-proxy" \
--build.cmd "go run github.com/a-h/templ/cmd/templ@latest generate --notify-proxy" \
--build.bin "true" \
--build.delay "100" \
--build.exclude_dir "" \

View file

@ -8,7 +8,7 @@ require (
)
require (
github.com/anthdm/gothkit v0.0.0-20240608092625-85a106b8717c
github.com/anthdm/gothkit v0.0.0-20240608094934-49f59f090fb7
github.com/fatih/color v1.16.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect

View file

@ -4,6 +4,8 @@ github.com/anthdm/gothkit v0.0.0-20240608091251-8198dfa775c8 h1:2C+WGVrNvIiSLFLJ
github.com/anthdm/gothkit v0.0.0-20240608091251-8198dfa775c8/go.mod h1:/zW/YMI9hOvRTQwmpfRU+CoJ+m4LZYuzC496KFOJAM8=
github.com/anthdm/gothkit v0.0.0-20240608092625-85a106b8717c h1:JYV/co6zKfSR4eR/MVORi6wQvva1tikbBS8Xgd2GVFc=
github.com/anthdm/gothkit v0.0.0-20240608092625-85a106b8717c/go.mod h1:/zW/YMI9hOvRTQwmpfRU+CoJ+m4LZYuzC496KFOJAM8=
github.com/anthdm/gothkit v0.0.0-20240608094934-49f59f090fb7 h1:W2/7bSR+GBehAC1+Tg/wigCA6o4y3VAFnkLG4NypB6A=
github.com/anthdm/gothkit v0.0.0-20240608094934-49f59f090fb7/go.mod h1:/zW/YMI9hOvRTQwmpfRU+CoJ+m4LZYuzC496KFOJAM8=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=

View file

@ -46,7 +46,7 @@ html,
-o-tab-size: 4;
tab-size: 4;
/* 3 */
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
/* 4 */
font-feature-settings: normal;
/* 5 */

View file

@ -4,6 +4,8 @@ import (
"fmt"
"reflect"
"regexp"
"time"
"unicode"
)
var (
@ -11,6 +13,7 @@ var (
urlRegex = regexp.MustCompile(`^(http(s)?://)?([\da-z\.-]+)\.([a-z\.]{2,6})([/\w \.-]*)*/?$`)
)
// RuleSet holds the state of a single rule.
type RuleSet struct {
Name string
RuleValue any
@ -21,6 +24,7 @@ type RuleSet struct {
ValidateFunc func(RuleSet) bool
}
// Message overrides the default message of a RuleSet
func (set RuleSet) Message(msg string) RuleSet {
set.ErrorMessage = msg
return set
@ -49,8 +53,64 @@ func In[T any](values []T) RuleSet {
}
}
func Required() RuleSet {
return RuleSet{
var ContainsUpper = RuleSet{
Name: "containsUpper",
ValidateFunc: func(rule RuleSet) bool {
str, ok := rule.FieldValue.(string)
if !ok {
return false
}
for _, ch := range str {
if unicode.IsUpper(rune(ch)) {
return true
}
}
return false
},
MessageFunc: func(set RuleSet) string {
return "must contain at least 1 uppercase character"
},
}
var ContainsNumeric = RuleSet{
Name: "containsNumeric",
ValidateFunc: func(rule RuleSet) bool {
str, ok := rule.FieldValue.(string)
if !ok {
return false
}
for _, ch := range str {
if isSpecial(ch) {
return true
}
}
return false
},
MessageFunc: func(set RuleSet) string {
return "must contain at least 1 numeric character"
},
}
var ContainsSpecial = RuleSet{
Name: "containsSpecial",
ValidateFunc: func(rule RuleSet) bool {
str, ok := rule.FieldValue.(string)
if !ok {
return false
}
for _, ch := range str {
if isSpecial(ch) {
return true
}
}
return false
},
MessageFunc: func(set RuleSet) string {
return "must contain at least 1 special character"
},
}
var Required = RuleSet{
Name: "required",
MessageFunc: func(set RuleSet) string {
return "is a required field"
@ -63,10 +123,8 @@ func Required() RuleSet {
return len(str) > 0
},
}
}
func Url() RuleSet {
return RuleSet{
var URL = RuleSet{
Name: "url",
MessageFunc: func(set RuleSet) string {
return "is not a valid url"
@ -79,10 +137,8 @@ func Url() RuleSet {
return urlRegex.MatchString(u)
},
}
}
func Email() RuleSet {
return RuleSet{
var Email = RuleSet{
Name: "email",
MessageFunc: func(set RuleSet) string {
return "is not a valid email address"
@ -95,6 +151,64 @@ func Email() RuleSet {
return emailRegex.MatchString(email)
},
}
var Time = RuleSet{
Name: "time",
ValidateFunc: func(set RuleSet) bool {
t, ok := set.FieldValue.(time.Time)
if !ok {
return false
}
return t.After(time.Time{})
},
MessageFunc: func(set RuleSet) string {
return "is not a valid time"
},
}
func TimeAfter(t time.Time) RuleSet {
return RuleSet{
Name: "timeAfter",
ValidateFunc: func(set RuleSet) bool {
t, ok := set.FieldValue.(time.Time)
if !ok {
return false
}
return t.After(t)
},
MessageFunc: func(set RuleSet) string {
return fmt.Sprintf("is not after %v", set.FieldValue)
},
}
}
func TimeBefore(t time.Time) RuleSet {
return RuleSet{
Name: "timeBefore",
ValidateFunc: func(set RuleSet) bool {
t, ok := set.FieldValue.(time.Time)
if !ok {
return false
}
return t.Before(t)
},
MessageFunc: func(set RuleSet) string {
return fmt.Sprintf("is not before %v", set.FieldValue)
},
}
}
func EQ[T comparable](v T) RuleSet {
return RuleSet{
Name: "eq",
RuleValue: v,
ValidateFunc: func(set RuleSet) bool {
return set.FieldValue.(T) == v
},
MessageFunc: func(set RuleSet) string {
return fmt.Sprintf("should be equal to %v", v)
},
}
}
func LTE[T Numeric](n T) RuleSet {
@ -182,3 +296,7 @@ func Min(n int) RuleSet {
},
}
}
func isSpecial(ch rune) bool {
return true
}

View file

@ -47,6 +47,7 @@ func Merge(schema, other Schema) Schema {
return newSchema
}
// Rules is a function that takes any amount of RuleSets
func Rules(rules ...RuleSet) []RuleSet {
ruleSets := make([]RuleSet, len(rules))
for i := 0; i < len(ruleSets); i++ {

View file

@ -1,11 +1,70 @@
package validate
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
var createdAt = time.Now()
var testSchema = Schema{
"createdAt": Rules(Time),
"startedAt": Rules(TimeBefore(time.Now())),
"deletedAt": Rules(TimeAfter(createdAt)),
"email": Rules(Email),
"url": Rules(URL),
"password": Rules(
ContainsSpecial,
ContainsUpper,
ContainsNumeric,
Min(7),
Max(50),
),
"age": Rules(GTE(18)),
"bet": Rules(GT(0), LTE(10)),
"username": Rules(Required),
}
func TestTime(t *testing.T) {
type Foo struct {
CreatedAt time.Time
}
foo := Foo{
CreatedAt: time.Now(),
}
schema := Schema{
"createdAt": Rules(Time),
}
_, ok := Validate(foo, schema)
assert.True(t, ok)
foo.CreatedAt = time.Time{}
_, ok = Validate(foo, schema)
assert.False(t, ok)
}
func TestURL(t *testing.T) {
type Foo struct {
URL string
}
foo := Foo{
URL: "not an url",
}
schema := Schema{
"url": Rules(URL),
}
errors, ok := Validate(foo, schema)
assert.False(t, ok)
foo.URL = "www.user.com"
errors, ok = Validate(foo, schema)
assert.True(t, ok)
fmt.Println(errors)
}
func TestRuleIn(t *testing.T) {
type Foo struct {
Currency string
@ -29,7 +88,7 @@ func TestValidate(t *testing.T) {
Username string
}
schema := Schema{
"email": Rules(Email()),
"email": Rules(Email),
// Test both lower and uppercase
"Username": Rules(Min(3), Max(10)),
}