Skip to content

Commit

Permalink
Merge pull request #25 from arran4/Custom
Browse files Browse the repository at this point in the history
Custom output per type
  • Loading branch information
OneOfOne authored Dec 16, 2020
2 parents 4d67dcd + fa88827 commit ad72616
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 5 deletions.
11 changes: 6 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*.txt
*.pprof
cmap2/
cache/
debug
/*.txt
/*.pprof
/cmap2/
/cache/
/debug
/testdata/testmodel1/s2ts_gen_*.go
/helpers.js
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ Args:
```

## Advanced

### Custom output per model

```golang
type CustomTypescript interface {
RenderCustomTypescript(w io.Writer) (err error)
}
```
If your model implements a ```RenderCustomTypescript(w io.Writer) (err error)``` function it will inject what ever you
write to the writer at the end of the model. struct2ts will handle the first level of indenting for you.

## TODO

* Use [xast](https://github.com/OneOfOne/xast) to skip reflection.
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5Vpd
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/tools v0.0.0-20190213135902-6bedcd10978a h1:ncPOGSo3avrTTUKHvDmwoS5E5of95qqNwftSXoxX+Wk=
golang.org/x/tools v0.0.0-20190213135902-6bedcd10978a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
43 changes: 43 additions & 0 deletions struct.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package struct2ts

import (
"errors"
"fmt"
"io"
"reflect"
Expand Down Expand Up @@ -57,10 +58,52 @@ func (s *Struct) RenderTo(opts *Options, w io.Writer) (err error) {
return
}

if err = s.RenderCustom(opts, w); err != nil {
return
}

_, err = fmt.Fprint(w, "}")
return
}

type CustomTypescript interface {
RenderCustomTypescript(w io.Writer) (err error)
}

func (s *Struct) RenderCustom(opts *Options, w io.Writer) (err error) {
ww := newTabScanner(w, opts.indents[1])
ctit := reflect.TypeOf((*CustomTypescript)(nil)).Elem()
var implementingType reflect.Type = nil
if s.t.Implements(ctit) {
implementingType = ctit
}
if reflect.PtrTo(s.t).Implements(ctit) {
implementingType = reflect.PtrTo(s.t)
}
if implementingType != nil {
m, ok := implementingType.MethodByName("RenderCustomTypescript")
if !ok {
return errors.New("couldn't get method RenderCustomTypescript")
}
_, err = fmt.Fprintf(ww, "\n")
o := reflect.New(s.t)
if implementingType.Kind() != reflect.Ptr {
o = o.Elem()
}
wv := reflect.ValueOf(ww)
r := m.Func.Call([]reflect.Value{o, wv})
if len(r) > 0 && !r[0].IsNil() {
switch r0t := r[0].Interface().(type) {
case error:
return r0t
}
}
_, err = fmt.Fprintf(w, "\n")
}

return
}

func (s *Struct) RenderFields(opts *Options, w io.Writer) (err error) {
for _, f := range s.Fields {
if err = f.RenderTopLevel(w, opts); err != nil {
Expand Down
37 changes: 37 additions & 0 deletions tabscanner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package struct2ts

import "io"

type tabScanner struct {
output io.Writer
tabs []byte
}

func (ts *tabScanner) Write(bs []byte) (n int, err error) {
p := 0
var rn int
for pos, b := range bs {
switch b {
case '\n':
rn, err = ts.output.Write(bs[p : pos+1])
n += rn
if err != nil {
return
}
_, err = ts.output.Write(ts.tabs)
if err != nil {
return
}
p = pos + 1
}
}
rn, err = ts.output.Write(bs[p:])
return n + rn, err
}

func newTabScanner(w io.Writer, tabs string) io.Writer {
return &tabScanner{
output: w,
tabs: []byte(tabs),
}
}
95 changes: 95 additions & 0 deletions tabscanner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package struct2ts

import (
"bytes"
"testing"
)

func TestTabScanner_Write(t *testing.T) {
tests := []struct {
Name string
Input struct {
Tabs string
Buffers []string
}
Expected struct {
Output string
n *int
}
}{
{
"One new line mid string - one input, 3 spaces",
struct {
Tabs string
Buffers []string
}{Tabs: " ", Buffers: []string{"Hello how are you?\nI'm fine thanks!"}},
struct {
Output string
n *int
}{Output: "Hello how are you?\n I'm fine thanks!"},
},
{
"One new line end string - one input, 3 spaces",
struct {
Tabs string
Buffers []string
}{Tabs: " ", Buffers: []string{"Hello how are you?\n"}},
struct {
Output string
n *int
}{Output: "Hello how are you?\n "},
},
{
"One new line start string - one input, 3 spaces",
struct {
Tabs string
Buffers []string
}{Tabs: " ", Buffers: []string{"\nHello how are you?"}},
struct {
Output string
n *int
}{Output: "\n Hello how are you?"},
},
{
"empty string",
struct {
Tabs string
Buffers []string
}{Tabs: " ", Buffers: []string{""}},
struct {
Output string
n *int
}{Output: ""},
},
{
"Just a new line",
struct {
Tabs string
Buffers []string
}{Tabs: " ", Buffers: []string{"\n"}},
struct {
Output string
n *int
}{Output: "\n "},
},
}
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
outputBuffer := bytes.NewBuffer(nil)
ts := newTabScanner(outputBuffer, test.Input.Tabs)
for _, s := range test.Input.Buffers {
_, err := ts.Write([]byte(s))
if err != nil {
t.Error("Buffer write error", err)
}
}
if outputBuffer.String() != test.Expected.Output {
t.Log("Output buffer doesn't match. Got ")
t.Log(outputBuffer.String())
t.Log("expected")
t.Log(test.Expected.Output)
t.Fail()
}
})
}
}
28 changes: 28 additions & 0 deletions testdata/testmodel1/testmodel1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package testmodel1

import (
"fmt"
"io"
)

type Struct1 struct {
HasNoCustomInterface int
}

type Struct2 struct {
TotallyDoesHaveOneAsAPointer int
}

func (s *Struct2) RenderCustomTypescript(w io.Writer) (err error) {
fmt.Fprint(w, "// Custom Output!!!")
return nil
}

type Struct3 struct {
TotallyDoesHaveOne int
}

func (s Struct3) RenderCustomTypescript(w io.Writer) (err error) {
fmt.Fprint(w, "// Custom Output!!!")
return nil
}
5 changes: 5 additions & 0 deletions testdata/testmodel1/testmodel1.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash -Xe

go run github.com/OneOfOne/struct2ts/cmd/struct2ts github.com/OneOfOne/struct2ts/testdata/testmodel1.Struct1
go run github.com/OneOfOne/struct2ts/cmd/struct2ts github.com/OneOfOne/struct2ts/testdata/testmodel1.Struct2
go run github.com/OneOfOne/struct2ts/cmd/struct2ts github.com/OneOfOne/struct2ts/testdata/testmodel1.Struct3

0 comments on commit ad72616

Please sign in to comment.