Skip to content

Commit

Permalink
Fimp: test confirms that it works
Browse files Browse the repository at this point in the history
  • Loading branch information
David Arnold committed Nov 12, 2020
1 parent c76e106 commit 45fde44
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 31 deletions.
79 changes: 79 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
root = true

[*]
charset = utf-8

end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

indent_style = space
indent_size = 4

[*.mod]
indent_style = tab

[{Makefile,**.mk}]
indent_style = tab

[*.go]
indent_style = tab

[*.css]
indent_size = 2

[*.proto]
indent_size = 2

[*.ftl]
indent_size = 2

[*.toml]
indent_size = 2

[*.swift]
indent_size = 4

[*.tmpl]
indent_size = 2

[*.js]
indent_size = 2
block_comment_start = /*
block_comment_end = */

[*.{html,htm}]
indent_size = 2

[*.bat]
end_of_line = crlf

[*.{yml,yaml}]
indent_size = 2

[*.json]
indent_size = 2

[.{babelrc,eslintrc,prettierrc}]
indent_size = 2

[{Fastfile,.buckconfig,BUCK}]
indent_size = 2

[*.diff]
indent_size = 1

[*.m]
indent_size = 1
indent_style = space
block_comment_start = /**
block_comment = *
block_comment_end = */

[*.java]
indent_size = 4
indent_style = space
block_comment_start = /**
block_comment = *
block_comment_end = */

12 changes: 12 additions & 0 deletions ddd-domain-gen/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
Expand All @@ -34,6 +35,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
github.com/dave/jennifer v1.4.1 h1:XyqG6cn5RQsTj3qlWQTKlRGAyrTcsk1kUmWdZBzRjDw=
github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
Expand Down Expand Up @@ -66,6 +68,7 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
Expand All @@ -92,18 +95,22 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
Expand All @@ -130,6 +137,7 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
Expand All @@ -148,7 +156,9 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
Expand All @@ -169,6 +179,7 @@ github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
Expand Down Expand Up @@ -287,6 +298,7 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
Expand Down
89 changes: 58 additions & 31 deletions ddd-domain-gen/pkg/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"go/types"
"os"
"path/filepath"
"reflect"
"regexp"
"strings"

Expand All @@ -19,9 +20,26 @@ func Main(sourceTypeName string) error {

// Get the package of the file with go:generate comment
goPackage := os.Getenv("GOPACKAGE")
path, err := os.Getwd()
if err != nil {
return err
}

// Build the target file name
goFile := os.Getenv("GOFILE")
ext := filepath.Ext(goFile)
baseFilename := goFile[0 : len(goFile)-len(ext)]
targetFilename := baseFilename + "_gen.go"

// Remove existing target file (before loading the package)
if _, err := os.Stat(targetFilename); err == nil {
if err := os.Remove(targetFilename); err != nil {
return err
}
}

// Inspect package and use type checker to infer imported types
pkg, err := loadPackage(goPackage)
pkg, err := loadPackage(path)
if err != nil {
return err
}
Expand All @@ -44,30 +62,37 @@ func Main(sourceTypeName string) error {
}

// Generate code using jennifer
err = generate(goPackage, sourceTypeName, structType)
err = generate(goPackage, targetFilename, sourceTypeName, structType)
if err != nil {
return err
}
return nil
}

// Use a simple regexp pattern to match tag values
// StructTag Key
var (
structRequiredTagPattern = regexp.MustCompile(`required:"([^"]+)"`)
structTagGenKey = "gen"
structTagDDDKey = "ddd"
)

// A simple regexp pattern to match tag values
var (
structRequiredTagPattern = regexp.MustCompile(`required'([^']+)'`)
structPrivateTagPattern = regexp.MustCompile(`private`)
structGenGetterTagPattern = regexp.MustCompile(`gen-getter`)
structGenGetterTagPattern = regexp.MustCompile(`getter`)
)

func generate(goPackage, sourceTypeName string, structType *types.Struct) error {
func generate(goPackage, targetFilename, sourceTypeName string, structType *types.Struct) error {

// Start a new file in this package
// return fmt.Errorf(goPackage)
f := NewFile(goPackage)

// Add a package comment, so IDEs detect files as generated
f.PackageComment("Code generated by ddd-domain-gen, DO NOT EDIT.")

f.Line()
f.Comment("Generators ...")
f.Line()

// 1. define code region variables
var (
Expand All @@ -83,19 +108,25 @@ func generate(goPackage, sourceTypeName string, structType *types.Struct) error
// 2. iterate over struct fields and populate those variables
for i := 0; i < structType.NumFields(); i++ {
field := structType.Field(i)
tagValue := structType.Tag(i)
tag := reflect.StructTag(structType.Tag(i))

// 2.1 match default getter creation to fields
genGetterMatchs := structGenGetterTagPattern.FindStringSubmatch(tagValue)
if genGetterMatchs != nil {
genGetterFields = append(genGetterFields, field)
if structTagGenKeyValue, ok := tag.Lookup(structTagGenKey); ok {
if matches := structGenGetterTagPattern.FindStringSubmatch(structTagGenKeyValue); matches != nil {
genGetterFields = append(genGetterFields, field)
}
}

// 2.2 separate private and public fields
var private bool
privateMatchs := structPrivateTagPattern.FindStringSubmatch(tagValue)
if privateMatchs != nil {
private = true
var requiredMatches []string
if structTagDDDKeyValue, ok := tag.Lookup(structTagDDDKey); ok {
if matches := structPrivateTagPattern.FindStringSubmatch(structTagDDDKeyValue); matches != nil {
private = true
}
requiredMatches = structRequiredTagPattern.FindStringSubmatch(structTagDDDKeyValue)
}
if private {
privateParams = append(privateParams, Id(field.Name()).Id(field.Type().String()))
privateFields = append(privateFields, field)
} else {
Expand All @@ -104,7 +135,6 @@ func generate(goPackage, sourceTypeName string, structType *types.Struct) error
}

// 2.2 generate required validation code (error if also private)
requiredMatches := structRequiredTagPattern.FindStringSubmatch(tagValue)
if requiredMatches != nil {
if private {
return fmt.Errorf("private field %s cannot be required", field.Name())
Expand All @@ -129,7 +159,10 @@ func generate(goPackage, sourceTypeName string, structType *types.Struct) error
f.Commentf("New returns a guaranteed-to-be-valid %s or an error", sourceTypeName)
f.Func().Id("New").Params(
publicParams...,
).Op("*").Id(sourceTypeName).Err().BlockFunc(func(g *Group) {
).Call(
Op("*").Id(sourceTypeName),
Error(),
).BlockFunc(func(g *Group) {
for _, code := range publicValidations {
g.Add(code)
}
Expand All @@ -139,17 +172,17 @@ func generate(goPackage, sourceTypeName string, structType *types.Struct) error
d[Id(fld.Name())] = Id(fld.Name())
}
}),
))
), Nil())
})

// -- Add MustNew() constructor
f.Commentf("MustNew returns a guaranteed-to-be-valid %s or panics", sourceTypeName)
f.Func().Id("MustNew").Params(
publicParams...,
).Parens(
).Call(
Op("*").Id(sourceTypeName),
).Block(
Id(sF).Err().Op(":=").Id("New").CallFunc(func(g *Group) {
Id(sF).Op(",").Err().Op(":=").Id("New").CallFunc(func(g *Group) {
for _, fld := range publicFields {
g.Id(fld.Name())
}
Expand All @@ -160,8 +193,8 @@ func generate(goPackage, sourceTypeName string, structType *types.Struct) error
Return(Id(sF)),
)

f.Line()
f.Comment("Marshalers ...")
f.Line()

// -- Add UnmarshalFromRepository() unmarshaler
f.Commentf("UnmarshalFromRepository unmarshals %s from the repository so that non-constructable", sourceTypeName)
Expand All @@ -171,7 +204,7 @@ func generate(goPackage, sourceTypeName string, structType *types.Struct) error
f.Comment("Reason: This method initializes private state, so you could corrupt the domain.")
f.Func().Id("UnmarshalFromRepository").Params(
allParams...,
).Op("*").Id(sourceTypeName).Err().BlockFunc(func(g *Group) {
).Op("*").Id(sourceTypeName).BlockFunc(func(g *Group) {
g.Id(sF).Op(":=").Id("MustNew").CallFunc(func(g *Group) {
for _, fld := range publicFields {
g.Id(fld.Name())
Expand All @@ -183,24 +216,18 @@ func generate(goPackage, sourceTypeName string, structType *types.Struct) error
g.Return(Id(sF))
})

f.Line()
f.Comment("Getters ...")
f.Line()
for _, fld := range genGetterFields {
fN := strings.Title(fld.Name())
f.Commentf("%s returns %s value", fN, fld.Name())
f.Func().Params(
Id(sF), Id(sourceTypeName),
).Id(fN).Op("*").Id(fld.Type().String()).Block(
Return(Id(sF).Dot(fld.Name()).Id(fld.Name())),
Id(sF).Op("*").Id(sourceTypeName),
).Id(fN).Params().Id(fld.Type().String()).Block(
Return(Id(sF).Dot(fld.Name())),
)
}

// Build the target file name
goFile := os.Getenv("GOFILE")
ext := filepath.Ext(goFile)
baseFilename := goFile[0 : len(goFile)-len(ext)]
targetFilename := baseFilename + "_gen.go"

// Write generated file
return f.Save(targetFilename)
}
Expand Down
10 changes: 10 additions & 0 deletions ddd-domain-gen/tests/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tests

//go:generate go run ../main.go -t Account
type Account struct {
uuid *string `gen:"getter" ddd:"required'field uuid is missing'"`
holder *string `gen:"getter" ddd:"required'field holder is missing'"`
address *string `gen:"getter"`
balance *int64 `ddd:"private"` // read via domain logic: don't generate default getter
values *[]int64 `ddd:"private" gen:"getter"`
}
Loading

0 comments on commit 45fde44

Please sign in to comment.