Skip to content

Commit

Permalink
Merge pull request #92 from jmattheis/config
Browse files Browse the repository at this point in the history
Config
  • Loading branch information
jmattheis authored Oct 23, 2023
2 parents a1ae13d + da6cafe commit c39db06
Show file tree
Hide file tree
Showing 233 changed files with 5,945 additions and 4,626 deletions.
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ do is create an interface and execute goverter. The project is meant as
alternative to [jinzhu/copier](https://github.com/jinzhu/copier) that doesn't
use reflection.

[Installation](https://goverter.jmattheis.de/#/install)[Conversion Docs](https://goverter.jmattheis.de/#/conversion/)
[Installation](https://goverter.jmattheis.de/#/install)
[CLI](https://goverter.jmattheis.de/#/cli)
[Config](https://goverter.jmattheis.de/#/config/)

## Features

Expand All @@ -37,12 +39,12 @@ use reflection.
- [Deep copies](https://en.wikipedia.org/wiki/Object_copying#Deep_copy) per
default and supports [shallow
copying](https://en.wikipedia.org/wiki/Object_copying#Shallow_copy)
- **Customizable**: [You can implement custom converter methods](https://goverter.jmattheis.de/#/conversion/custom)
- [Clear errors when generating the conversion methods](https://goverter.jmattheis.de/#/conversion/?id=error-early) if
- **Customizable**: [You can implement custom converter methods](https://goverter.jmattheis.de/#/config/extend)
- [Clear errors when generating the conversion methods](https://goverter.jmattheis.de/#/generation?id=error-early) if
- the target struct has unmapped fields
- types cannot be converted without losing information

## Usage
## Getting Started

1. Ensure your `go version` is 1.16 or above

Expand All @@ -52,7 +54,8 @@ use reflection.
$ go mod init module-name
```

1. Create your converter interface and mark it with a comment containing `goverter:converter`
1. Create your converter interface and mark it with a comment containing
[`goverter:converter`](https://goverter.jmattheis.de/#/config/converter)

`input.go`

Expand Down Expand Up @@ -82,15 +85,16 @@ use reflection.
}
```

See [Conversion](https://goverter.jmattheis.de/#/conversion/) for more information.
See [Configuration](https://goverter.jmattheis.de/#/config) for more information.

1. Run `goverter`:

```bash
$ go run github.com/jmattheis/goverter/cmd/[email protected] ./
```

See [Installation](https://goverter.jmattheis.de/#/install) for more information.
See [Installation](https://goverter.jmattheis.de/#/install) and
[CLI](https://goverter.jmattheis.de/#/cli) for more information.

1. goverter created a file at `./generated/generated.go`, it may look like this:

Expand Down Expand Up @@ -119,6 +123,8 @@ use reflection.
}
```
See [Generation](https://goverter.jmattheis.de/#/generation) for more information.
## Versioning
goverter uses [SemVer](http://semver.org/) for versioning the cli.
Expand Down
32 changes: 8 additions & 24 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package builder

import (
"github.com/dave/jennifer/jen"
"github.com/jmattheis/goverter/config"
"github.com/jmattheis/goverter/method"
"github.com/jmattheis/goverter/namer"
"github.com/jmattheis/goverter/xtype"
)
Expand All @@ -23,9 +25,9 @@ type Generator interface {
source, target *xtype.Type,
errWrapper ErrorWrapper) ([]jen.Code, *xtype.JenID, *Error)

CallExtendMethod(
CallMethod(
ctx *MethodContext,
method *ExtendMethod,
method *method.Definition,
sourceID *xtype.JenID,
source, target *xtype.Type,
errWrapper ErrorWrapper) ([]jen.Code, *xtype.JenID, *Error)
Expand All @@ -34,12 +36,10 @@ type Generator interface {
// MethodContext exposes information for the current method.
type MethodContext struct {
*namer.Namer
Fields map[string]*FieldMapping
Conf *config.Method
FieldsTarget string
Signature xtype.Signature
TargetType *xtype.Type
AutoMap []string
Flags ConversionFlags
SeenNamed map[string]struct{}

TargetVar *jen.Statement
Expand Down Expand Up @@ -68,32 +68,16 @@ func (ctx *MethodContext) SetErrorTargetVar(m *jen.Statement) {
}
}

func (ctx *MethodContext) Field(target *xtype.Type, name string) *FieldMapping {
func (ctx *MethodContext) Field(target *xtype.Type, name string) *config.FieldMapping {
if ctx.FieldsTarget != target.T.String() {
return emptyMapping
}

prop, ok := ctx.Fields[name]
prop, ok := ctx.Conf.Fields[name]
if !ok {
return emptyMapping
}
return prop
}

var emptyMapping *FieldMapping = &FieldMapping{}

type FieldMapping struct {
Source string
Ignore bool
Function *ExtendMethod
}
type ExtendMethod struct {
ID string
Name string
SelfAsFirstParam bool
ReturnError bool
Call *jen.Statement
// optional source
Source *xtype.Type
Target *xtype.Type
}
var emptyMapping *config.FieldMapping = &config.FieldMapping{}
37 changes: 0 additions & 37 deletions builder/flags.go

This file was deleted.

2 changes: 1 addition & 1 deletion builder/pointer.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type SourcePointer struct{}

// Matches returns true, if the builder can create handle the given types.
func (*SourcePointer) Matches(ctx *MethodContext, source, target *xtype.Type) bool {
return ctx.Flags.Has(FlagZeroValueOnPtrInconsistency) && source.Pointer && !target.Pointer
return ctx.Conf.UseZeroValueOnPointerInconsistency && source.Pointer && !target.Pointer
}

// Build creates conversion source code for the given source and target type.
Expand Down
2 changes: 1 addition & 1 deletion builder/skipcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type SkipCopy struct{}

// Matches returns true, if the builder can create handle the given types.
func (*SkipCopy) Matches(ctx *MethodContext, source, target *xtype.Type) bool {
return ctx.Flags.Has(FlagSkipCopySameType) && source.T.String() == target.T.String()
return ctx.Conf.SkipCopySameType && source.T.String() == target.T.String()
}

// Build creates conversion source code for the given source and target type.
Expand Down
19 changes: 10 additions & 9 deletions builder/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (*Struct) Build(gen Generator, ctx *MethodContext, sourceID *xtype.JenID, s
if fieldMapping.Ignore {
continue
}
if !targetField.Exported() && ctx.Flags.Has(FlagIgnoreUnexported) {
if !targetField.Exported() && ctx.Conf.IgnoreUnexported {
continue
}

Expand Down Expand Up @@ -107,7 +107,7 @@ func (*Struct) Build(gen Generator, ctx *MethodContext, sourceID *xtype.JenID, s
functionCallSourceID = sourceID.ParentPointer
functionCallSourceType = source.AsPointer()
default:
cause := fmt.Sprintf("cannot not use\n\t%s\nbecause source type mismatch\n\nExtend method param type: %s\nConverter source type: %s", def.ID, def.Source.T.String(), nextSource.T.String())
cause := fmt.Sprintf("cannot use\n\t%s\nbecause source type mismatch\n\nExtend method param type: %s\nConverter source type: %s", def.ID, def.Source.T.String(), nextSource.T.String())
return nil, nil, NewError(cause).Lift(&Path{
Prefix: "(",
SourceID: "source)",
Expand All @@ -125,7 +125,7 @@ func (*Struct) Build(gen Generator, ctx *MethodContext, sourceID *xtype.JenID, s
return nil, nil, NewError(cause).Lift(&Path{
Prefix: ".",
SourceID: "()",
SourceType: def.Target.T.String(),
SourceType: def.Parameters.Target.T.String(),
TargetID: targetField.Name(),
TargetType: targetField.Type().String(),
}).Lift(&Path{
Expand All @@ -134,7 +134,7 @@ func (*Struct) Build(gen Generator, ctx *MethodContext, sourceID *xtype.JenID, s
SourceType: def.ID,
}).Lift(sourceLift...)
}
callStmt, callReturnID, err := gen.CallExtendMethod(ctx, fieldMapping.Function, functionCallSourceID, functionCallSourceType, targetFieldType, errWrapper)
callStmt, callReturnID, err := gen.CallMethod(ctx, fieldMapping.Function, functionCallSourceID, functionCallSourceType, targetFieldType, errWrapper)
if err != nil {
return nil, nil, err.Lift(sourceLift...)
}
Expand Down Expand Up @@ -177,11 +177,11 @@ func mapField(

var path []string
if pathString == "" {
sourceMatch, err := xtype.FindField(targetField.Name(), ctx.Flags.Has(FlagMatchIgnoreCase), ignored, source, additionalFieldSources)
sourceMatch, err := xtype.FindField(targetField.Name(), ctx.Conf.MatchIgnoreCase, ignored, source, additionalFieldSources)
if err != nil {
cause := fmt.Sprintf("Cannot match the target field with the source entry: %s.", err.Error())
skip := false
if ctx.Flags.Has(FlagIgnoreMissing) {
if ctx.Conf.IgnoreMissing {
_, skip = err.(*xtype.NoMatchError)
}
return nil, nil, nil, nil, skip, NewError(cause).Lift(&Path{
Expand Down Expand Up @@ -274,7 +274,7 @@ func mapField(

func parseAutoMap(ctx *MethodContext, source *xtype.Type) ([]xtype.FieldSources, *Error) {
fieldSources := []xtype.FieldSources{}
for _, field := range ctx.AutoMap {
for _, field := range ctx.Conf.AutoMap {
innerSource := source
lift := []*Path{}
path := strings.Split(field, ".")
Expand Down Expand Up @@ -315,8 +315,9 @@ func unexportedStructError(targetField, sourceType, targetType string) string {
Possible solutions:
* Ignore the given field:
https://goverter.jmattheis.de/#/conversion/mapping?id=ignore
https://goverter.jmattheis.de/#/config/ignore
* Create a custom converter function:
https://goverter.jmattheis.de/#/conversion/custom`, targetField)
https://goverter.jmattheis.de/#/config/extend
https://goverter.jmattheis.de/#/config/map`, targetField)
}
92 changes: 92 additions & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package cli

import (
"flag"
"fmt"

"github.com/jmattheis/goverter"
"github.com/jmattheis/goverter/config"
)

type Strings []string

func (s Strings) String() string {
return fmt.Sprint([]string(s))
}

func (s *Strings) Set(value string) error {
*s = append(*s, value)
return nil
}

func Parse(args []string) (*goverter.GenerateConfig, error) {
switch len(args) {
case 0:
return nil, usage("unknown")
case 1:
return nil, usageErr("missing command: ", args[0])
default:
if args[1] != "gen" {
return nil, usageErr("unknown command: "+args[1], args[0])
}
}

fs := flag.NewFlagSet(args[0], flag.ContinueOnError)
fs.Usage = func() {
// fmt.Println(usage(args[0]))
}

var global Strings
fs.Var(&global, "global", "add ")
fs.Var(&global, "g", "add ")

if err := fs.Parse(args[2:]); err != nil {
return nil, usageErr(err.Error(), args[0])
}
patterns := fs.Args()

if len(patterns) == 0 {
return nil, usageErr("missing PATTERN", args[0])
}

c := goverter.GenerateConfig{
PackagePatterns: patterns,
Global: config.RawLines{
Lines: global,
Location: "command line (-g, -global)",
},
}

return &c, nil
}

func usageErr(err, cmd string) error {
return fmt.Errorf("Error: %s\n%s", err, usage(cmd))
}

func usage(cmd string) error {
return fmt.Errorf(`Usage:
%s gen [OPTIONS] PACKAGE...
PACKAGE(s):
Define the import paths goverter will use to search for converter interfaces.
You can define multiple packages and use the special ... golang pattern to
select multiple packages. See $ go help packages
OPTIONS:
-g [value], -global [value]:
apply settings to all defined converters. For a list of available
settings see: https://goverter.jmattheis.de/#/config/
-h, --help:
display this help page
Examples:
%s gen ./example/simple ./example/complex
%s gen ./example/...
%s gen github.com/jmattheis/goverter/example/simple
%s gen -g 'ignoreMissing no' -g 'skipCopySameType' ./simple
Documentation:
Full documentation is available here: https://goverter.jmattheis.de`, cmd, cmd, cmd, cmd, cmd)
}
Loading

0 comments on commit c39db06

Please sign in to comment.