Skip to content

Commit 02f3727

Browse files
committed
v1.0.0
Fixes #5
1 parent 9f00749 commit 02f3727

File tree

11 files changed

+791
-310
lines changed

11 files changed

+791
-310
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*.txt
2+
*.pprof
3+
cmap2/
4+
cache/
5+
debug

README.md

Lines changed: 85 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -25,120 +25,119 @@ Inspired by [tkrajina/typescriptify-golang-structs](https://github.com/tkrajina/
2525

2626
#### Example struct
2727

28+
* Input:
29+
30+
```go
31+
type OtherStruct struct {
32+
T time.Time `json:"t,omitempty"`
33+
}
34+
35+
type ComplexStruct struct {
36+
S string `json:"s,omitempty"`
37+
I int `json:"i,omitempty"`
38+
F float64 `json:"f,omitempty"`
39+
TS *int64 `json:"ts,omitempty" ts:"date,null"`
40+
T time.Time `json:"t,omitempty"` // automatically handled
41+
NullOther *OtherStruct `json:"o,omitempty"`
42+
NoNullOther *OtherStruct `json:"nno,omitempty" ts:",no-null"`
43+
}
2844
```
29-
type S struct{
30-
Date int64 `json:"date" ts:"date"`
31-
GoOnly string `json:"server-side-only" ts:"-"`
32-
NoNull *OtherStruct `ts:"no-null"` // the generated TS code will always use new OtherStruct instead of null for the default value.
33-
Null int64 `ts:"null"` // the default value in the generated TS code will be null instead of 0.
45+
46+
* Output:
47+
48+
```ts
49+
// ... helpers...
50+
// struct2ts:github.com/OneOfOne/struct2ts_test.ComplexStructOtherStruct
51+
class ComplexStructOtherStruct {
52+
t: Date;
53+
54+
constructor(data?: any) {
55+
const d: any = (data && typeof data === 'object') ? ToObject(data) : {};
56+
this.t = ('t' in d) ? ParseDate(d.t) : new Date();
57+
}
58+
59+
toObject(): any {
60+
const cfg: any = {};
61+
cfg.t = 'string';
62+
return ToObject(this, cfg);
63+
}
3464
}
65+
66+
// struct2ts:github.com/OneOfOne/struct2ts_test.ComplexStruct
67+
class ComplexStruct {
68+
s: string;
69+
i: number;
70+
f: number;
71+
ts: Date | null;
72+
t: Date;
73+
o: ComplexStructOtherStruct | null;
74+
nno: ComplexStructOtherStruct;
75+
76+
constructor(data?: any) {
77+
const d: any = (data && typeof data === 'object') ? ToObject(data) : {};
78+
this.s = ('s' in d) ? d.s as string : '';
79+
this.i = ('i' in d) ? d.i as number : 0;
80+
this.f = ('f' in d) ? d.f as number : 0;
81+
this.ts = ('ts' in d) ? ParseDate(d.ts) : null;
82+
this.t = ('t' in d) ? ParseDate(d.t) : new Date();
83+
this.o = ('o' in d) ? new ComplexStructOtherStruct(d.o) : null;
84+
this.nno = new ComplexStructOtherStruct(d.nno);
85+
}
86+
87+
toObject(): any {
88+
const cfg: any = {};
89+
cfg.i = 'number';
90+
cfg.f = 'number';
91+
cfg.t = 'string';
92+
return ToObject(this, cfg);
93+
}
94+
}
95+
// ...exports...
96+
3597
```
3698

37-
## Example
99+
## Command Line Usage
38100

39101
```
40102
┏━ oneofone@Ava ❨✪/O/struct2ts❩ ❨master ⚡❩
41103
┗━━➤ struct2ts -h
42-
usage: struct2ts [<flags>] <pkg.struct>...
104+
usage: struct2ts [<flags>] [<pkg.struct>...]
43105
44106
Flags:
45-
-h, --help Show context-sensitive help (also try --help-long and --help-man).
107+
-h, --help Show context-sensitive help (also try --help-long
108+
and --help-man).
46109
--indent="\t" Output indentation.
47110
-m, --mark-optional-fields Add `?` to fields with omitempty.
111+
-6, --es6 generate es6 code
48112
-C, --no-ctor Don't generate a ctor.
49113
-T, --no-toObject Don't generate a Class.toObject() method.
50-
-D, --no-date Don't automatically handle time.Unix () <-> JS Date().
114+
-E, --no-exports Don't automatically export the generated types.
115+
-D, --no-date Don't automatically handle time.Unix () <-> JS
116+
Date().
117+
-H, --no-helpers Don't output the helpers.
51118
-N, --no-default-values Don't assign default/zero values in the ctor.
52-
-i, --interface Only generate an interface (disables all the other options).
53-
-s, --src-only Only output the Go code (helpful if you want to edit it yourself).
119+
-i, --interface Only generate an interface (disables all the other
120+
options).
121+
-s, --src-only Only output the Go code (helpful if you want to
122+
edit it yourself).
54123
-p, --package-name="main" the package name to use if --src-only is set.
55-
-k, --keep-temp Keep the generated Go file, ignored if --src-only is set.
124+
-k, --keep-temp Keep the generated Go file, ignored if --src-only
125+
is set.
56126
-o, --out="-" Write the output to a file instead of stdout.
57127
-V, --version Show application version.
58128
59129
Args:
60-
<pkg.struct> List of structs to convert (github.com/you/auth/users.User or just users.User).
130+
[<pkg.struct>] List of structs to convert (github.com/you/auth/users.User,
131+
users.User or users.User:AliasUser).
61132
62-
┏━ oneofone@Ava ❨✪/O/struct2ts❩ ❨master ⚡❩
63-
┗━━➤ struct2ts struct2ts.Options
64-
65-
main.go:75: executing: go run /tmp/s2ts_gen_725543931.go
66-
// struct2ts:github.com/OneOfOne/struct2ts.Options
67-
export class Options {
68-
Indent: string = '';
69-
NoAssignDefaults: boolean = false;
70-
InterfaceOnly: boolean = false;
71-
MarkOptional: boolean = false;
72-
NoConstructor: boolean = false;
73-
NoToObject: boolean = false;
74-
NoDate: boolean = false;
75-
76-
constructor(data?: any) {
77-
if (typeof data !== 'object') return;
78-
79-
if ('Indent' in data) this.Indent = data.Indent as string;
80-
if ('NoAssignDefaults' in data) this.NoAssignDefaults = data.NoAssignDefaults as boolean;
81-
if ('InterfaceOnly' in data) this.InterfaceOnly = data.InterfaceOnly as boolean;
82-
if ('MarkOptional' in data) this.MarkOptional = data.MarkOptional as boolean;
83-
if ('NoConstructor' in data) this.NoConstructor = data.NoConstructor as boolean;
84-
if ('NoToObject' in data) this.NoToObject = data.NoToObject as boolean;
85-
if ('NoDate' in data) this.NoDate = data.NoDate as boolean;
86-
}
87-
88-
toObject(): { [key:string]: any } {
89-
const data: { [key:string]: any } = {};
90-
91-
if (this.Indent) data.Indent = this.Indent;
92-
if (this.NoAssignDefaults) data.NoAssignDefaults = this.NoAssignDefaults;
93-
if (this.InterfaceOnly) data.InterfaceOnly = this.InterfaceOnly;
94-
if (this.MarkOptional) data.MarkOptional = this.MarkOptional;
95-
if (this.NoConstructor) data.NoConstructor = this.NoConstructor;
96-
if (this.NoToObject) data.NoToObject = this.NoToObject;
97-
if (this.NoDate) data.NoDate = this.NoDate;
98-
return data;
99-
}
100-
}
101-
102-
┏━ oneofone@Ava ❨✪/O/struct2ts❩ ❨master ⚡❩
103-
┗━━➤ struct2ts --src-only struct2ts.Options
104-
// this file was automatically generated using struct2ts --src-only struct2ts.Options
105-
package main
106133
107-
import (
108-
"os"
109134
110-
"github.com/OneOfOne/struct2ts"
111-
)
112-
113-
func main() {
114-
if err := runStruct2TS(); err != nil {
115-
panic(err)
116-
}
117-
}
118-
119-
func runStruct2TS() error {
120-
s := struct2ts.New(&struct2ts.Options{
121-
Indent: " ",
122-
123-
NoAssignDefaults: false,
124-
InterfaceOnly: false,
125-
126-
NoConstructor: false,
127-
MarkOptional: false,
128-
NoToObject: false,
129-
NoDate: false,
130-
})
131-
132-
s.Add(struct2ts.Options{})
133-
134-
return s.RenderTo(os.Stdout)
135-
}
136135
```
137136

138137
## TODO
139138

140139
* Use [xast](https://github.com/OneOfOne/struct2ts) to skip reflection.
141-
* Support ES6.
140+
* ~~Support ES6.~~
142141
* Support annoymous structs.
143142

144143
## License

cmd/genHelpers.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/sh
2+
3+
IN=$1
4+
INJS=${IN/\.ts/\.js}
5+
OUT=$2
6+
tsc -t es6 -m es6 $IN || exit 1
7+
8+
echo package struct2ts > $OUT
9+
echo >> $OUT
10+
echo "const ts_helpers = \`" >> $OUT
11+
cat $IN >> $OUT
12+
echo "\`" >> $OUT
13+
14+
echo >> $OUT
15+
echo "const es6_helpers = \`" >> $OUT
16+
perl -pe 's/\s{4}/\t/g' < $INJS >> $OUT
17+
rm $INJS
18+
echo "\`" >> $OUT

cmd/struct2ts/main.go

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
KP "gopkg.in/alecthomas/kingpin.v2"
1919
)
2020

21-
const version = "v0.0.3"
21+
const version = "v1.0.0"
2222

2323
var (
2424
opts struct2ts.Options
@@ -37,9 +37,12 @@ var (
3737
func init() {
3838
KP.Flag("indent", "Output indentation.").Default("\t").StringVar(&opts.Indent)
3939
KP.Flag("mark-optional-fields", "Add `?` to fields with omitempty.").Short('m').BoolVar(&opts.MarkOptional)
40+
KP.Flag("es6", "generate es6 code").Short('6').BoolVar(&opts.ES6)
4041
KP.Flag("no-ctor", "Don't generate a ctor.").Short('C').BoolVar(&opts.NoConstructor)
4142
KP.Flag("no-toObject", "Don't generate a Class.toObject() method.").Short('T').BoolVar(&opts.NoToObject)
43+
KP.Flag("no-exports", "Don't automatically export the generated types.").Short('E').BoolVar(&opts.NoExports)
4244
KP.Flag("no-date", "Don't automatically handle time.Unix () <-> JS Date().").Short('D').BoolVar(&opts.NoDate)
45+
KP.Flag("no-helpers", "Don't output the helpers.").Short('H').BoolVar(&opts.NoHelpers)
4346
KP.Flag("no-default-values", "Don't assign default/zero values in the ctor.").Short('N').BoolVar(&opts.NoAssignDefaults)
4447
KP.Flag("interface", "Only generate an interface (disables all the other options).").Short('i').BoolVar(&opts.InterfaceOnly)
4548

@@ -51,8 +54,9 @@ func init() {
5154

5255
KP.Flag("out", "Write the output to a file instead of stdout.").Short('o').Default("-").StringVar(&outFile)
5356

54-
KP.Arg("pkg.struct", "List of structs to convert (github.com/you/auth/users.User or just users.User).").
55-
Required().StringsVar(&types)
57+
KP.Arg("pkg.struct", "List of structs to convert (github.com/you/auth/users.User, users.User or users.User:AliasUser).").
58+
StringsVar(&types)
59+
5660
}
5761

5862
type M map[string]interface{}
@@ -64,6 +68,7 @@ func main() {
6468
KP.Parse()
6569

6670
out := os.Stdout
71+
6772
if outFile != "-" && outFile != "/dev/stdout" {
6873
of, err := os.Create(outFile)
6974
if err != nil {
@@ -117,9 +122,10 @@ func main() {
117122

118123
func render() ([]byte, error) {
119124
var (
120-
buf bytes.Buffer
121-
imports []string
122-
ttypes = types[:0]
125+
buf bytes.Buffer
126+
imports []string
127+
ttypes = types[:0]
128+
typesWithNames [][2]string
123129
)
124130

125131
for _, t := range types {
@@ -132,15 +138,20 @@ func render() ([]byte, error) {
132138
imports = append(imports, t[:dotIdx])
133139
t = t[idx+1:]
134140
}
135-
ttypes = append(ttypes, t)
141+
if idx := strings.LastIndexByte(t, ':'); idx != -1 {
142+
typesWithNames = append(typesWithNames, [2]string{t[:idx], t[idx+1:]})
143+
} else {
144+
ttypes = append(ttypes, t)
145+
}
136146
}
137147

138148
err := tmpl.Execute(&buf, M{
139-
"pkgName": pkgName,
140-
"cmd": strings.Join(os.Args[1:], " "),
141-
"opts": opts,
142-
"imports": imports,
143-
"types": ttypes,
149+
"pkgName": pkgName,
150+
"cmd": strings.Join(os.Args[1:], " "),
151+
"opts": opts,
152+
"imports": imports,
153+
"types": ttypes,
154+
"typesWithNames": typesWithNames,
144155
})
145156

146157
return buf.Bytes(), err
@@ -156,11 +167,18 @@ const fileTmpl = `// this file was automatically generated using struct2ts {{.cm
156167
package {{.pkgName}}
157168
158169
import (
170+
"flag"
171+
"log"
172+
"io"
159173
"os"
174+
160175
"github.com/OneOfOne/struct2ts"
161176
{{ range $_, $imp := .imports }}"{{$imp}}"{{ end }}
162177
)
163-
{{ if eq .pkgName "main" }}func main() {
178+
{{- if eq .pkgName "main" }}
179+
func main() {
180+
log.SetFlags(log.Lshortfile)
181+
164182
var (
165183
out = flag.String("o", "-", "output")
166184
f = os.Stdout
@@ -177,7 +195,8 @@ import (
177195
if err = runStruct2TS(f); err != nil {
178196
panic(err)
179197
}
180-
}{{ end }}
198+
}
199+
{{- end }}
181200
182201
func runStruct2TS(w io.Writer) error {
183202
s := struct2ts.New(&struct2ts.Options{
@@ -189,13 +208,21 @@ func runStruct2TS(w io.Writer) error {
189208
NoConstructor: {{ .opts.NoConstructor }},
190209
MarkOptional: {{ .opts.MarkOptional }},
191210
NoToObject: {{ .opts.NoToObject }},
211+
NoExports: {{ .opts.NoExports }},
212+
NoHelpers: {{ .opts.NoHelpers }},
192213
NoDate: {{ .opts.NoDate }},
214+
215+
ES6: {{ .opts.ES6 }},
193216
})
194217
195218
{{ range $_, $t := .types }}
196-
s.Add({{$t}}{}){{ end }}
219+
s.Add({{$t}}{})
220+
{{- end }}
221+
{{ range $_, $t := .typesWithNames }}
222+
s.AddWithName({{index $t 0}}{}, "{{index $t 1}}")
223+
{{- end }}
197224
198-
io.WriteString(w, "// this file was automatically generated, DO NOT EDIT\n\n")
225+
io.WriteString(w, "// this file was automatically generated, DO NOT EDIT\n")
199226
return s.RenderTo(w)
200227
}
201228
`

0 commit comments

Comments
 (0)