Skip to content

Commit 39a3193

Browse files
authored
Merge pull request #88 from gzuidhof/fix-comment-on-unexported-decl-and-commas
Fix comma-separated fields, fix emitted comment on unexported declarations
2 parents 5974386 + c1a3ec3 commit 39a3193

File tree

9 files changed

+180
-87
lines changed

9 files changed

+180
-87
lines changed

examples/globalconfig/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Code generated by tygo. DO NOT EDIT.
2+
3+
//////////
4+
// source: globalconfig.go
5+
6+
export interface Config {
7+
Duration: number /* int, ns */;
8+
}

tygo.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ packages:
1818
export type Something = string | number;
1919
- path: "github.com/gzuidhof/tygo/examples/simple"
2020
fallback_type: unknown
21+
type_mappings:
22+
time.Time: "string /* RFC3339 */"
2123
- path: "github.com/gzuidhof/tygo/examples/inheritance"
2224
fallback_type: unknown
2325
frontmatter:

tygo/fixtures_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ func parseMarkdownFixtures(fileContents []byte) ([]MarkdownFixture, error) {
7878
}
7979

8080
return fixtures, nil
81-
8281
}
8382

8483
// Tests all markdown files in `testdata/fixtures/` directory.

tygo/generator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (g *Tygo) Generate() error {
7272
return nil
7373
}
7474

75-
err = os.WriteFile(outPath, []byte(code), 0664)
75+
err = os.WriteFile(outPath, []byte(code), 0o664)
7676
if err != nil {
7777
return nil
7878
}

tygo/package_generator.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ func (g *PackageGenerator) generateFile(s *strings.Builder, file *ast.File, file
1212

1313
ast.Inspect(file, func(n ast.Node) bool {
1414
switch x := n.(type) {
15-
1615
// GenDecl can be an import, type, var, or const expression
1716
case *ast.GenDecl:
1817
if x.Tok == token.IMPORT {

tygo/testdata/fixtures/simple.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,71 @@ Empty file
6969
Unexported
7070

7171
```go
72+
// A comment on an unexported constant
7273
const myValue = 3
74+
75+
// A comment on an unexported type
76+
type myType struct {
77+
// A comment on an unexported field
78+
field string
79+
}
80+
81+
// Mixed unexported and exported
82+
const (
83+
unexportedValue = 7 // A comment on an unexported constant
84+
ExportedValue = 42 // A comment on an exported constant
85+
)
86+
87+
// Unexported group
88+
const (
89+
unexportedValue1 = 1 // A comment on an unexported constant
90+
unexportedValue2 = 2 // Another comment on an unexported constant
91+
)
7392
```
7493

7594
```ts
95+
/**
96+
* Mixed unexported and exported
97+
*/
98+
export const ExportedValue = 42; // A comment on an exported constant
99+
```
100+
101+
102+
Comma
103+
104+
```go
105+
type A struct {
106+
Foo, Bar, baz string // A comment on fields separated by a comma
107+
}
108+
109+
type B struct {
110+
// A comment above the fields separated by a comma
111+
Foo, Bar, baz string
112+
}
113+
114+
115+
```
116+
```ts
117+
export interface A {
118+
Foo: string; // A comment on fields separated by a comma
119+
Bar: string; // A comment on fields separated by a comma
120+
}
121+
export interface B {
122+
/**
123+
* A comment above the fields separated by a comma
124+
*/
125+
Foo: string;
126+
/**
127+
* A comment above the fields separated by a comma
128+
*/
129+
Bar: string;
130+
}
131+
```
132+
133+
```go
134+
const Pi, E = 3.14, 2.71 // A comment on constants separated by a comma
135+
```
136+
```ts
137+
export const Pi = 3.14; // A comment on constants separated by a comma
138+
export const E = 2.71; // A comment on constants separated by a comma
76139
```

tygo/write.go

Lines changed: 91 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ import (
1212
"github.com/fatih/structtag"
1313
)
1414

15-
var validJSNameRegexp = regexp.MustCompile(`(?m)^[\pL_][\pL\pN_]*$`)
16-
var backquoteEscapeRegexp = regexp.MustCompile(`([$\\])`)
17-
var octalPrefixRegexp = regexp.MustCompile(`^0[0-7]`)
18-
var unicode8Regexp = regexp.MustCompile(`\\\\|\\U[\da-fA-F]{8}`)
15+
var (
16+
validJSNameRegexp = regexp.MustCompile(`(?m)^[\pL_][\pL\pN_]*$`)
17+
backquoteEscapeRegexp = regexp.MustCompile(`([$\\])`)
18+
octalPrefixRegexp = regexp.MustCompile(`^0[0-7]`)
19+
unicode8Regexp = regexp.MustCompile(`\\\\|\\U[\da-fA-F]{8}`)
20+
)
1921

2022
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence#table
2123
var jsNumberOperatorPrecedence = map[token.Token]int{
@@ -292,110 +294,115 @@ func (g *PackageGenerator) writeStructFields(s *strings.Builder, fields []*ast.F
292294
required := false
293295
readonly := false
294296

295-
var fieldName string
297+
fieldNames := make([]string, 0, len(f.Names))
296298
if len(f.Names) == 0 { // anonymous field
297299
if name, valid := getAnonymousFieldName(f.Type); valid {
298-
fieldName = name
300+
fieldNames = append(fieldNames, name)
301+
}
302+
} else {
303+
for _, name := range f.Names {
304+
if len(name.Name) == 0 || 'A' > name.Name[0] || name.Name[0] > 'Z' {
305+
continue
306+
}
307+
fieldNames = append(fieldNames, name.Name)
299308
}
300-
}
301-
if len(f.Names) != 0 && f.Names[0] != nil && len(f.Names[0].Name) != 0 {
302-
fieldName = f.Names[0].Name
303-
}
304-
if len(fieldName) == 0 || 'A' > fieldName[0] || fieldName[0] > 'Z' {
305-
continue
306309
}
307310

308-
var name string
309-
var tstype string
310-
if f.Tag != nil {
311-
tags, err := structtag.Parse(f.Tag.Value[1 : len(f.Tag.Value)-1])
312-
if err != nil {
313-
panic(err)
314-
}
311+
for _, fieldName := range fieldNames {
315312

316-
jsonTag, err := tags.Get("json")
317-
if err == nil {
318-
name = jsonTag.Name
319-
if name == "-" {
320-
continue
313+
var name string
314+
var tstype string
315+
if f.Tag != nil {
316+
tags, err := structtag.Parse(f.Tag.Value[1 : len(f.Tag.Value)-1])
317+
if err != nil {
318+
panic(err)
321319
}
322320

323-
optional = jsonTag.HasOption("omitempty") || jsonTag.HasOption("omitzero")
324-
}
325-
yamlTag, err := tags.Get("yaml")
326-
if err == nil {
327-
name = yamlTag.Name
328-
if name == "-" {
329-
continue
321+
jsonTag, err := tags.Get("json")
322+
if err == nil {
323+
name = jsonTag.Name
324+
if name == "-" {
325+
continue
326+
}
327+
328+
optional = jsonTag.HasOption("omitempty") || jsonTag.HasOption("omitzero")
329+
}
330+
yamlTag, err := tags.Get("yaml")
331+
if err == nil {
332+
name = yamlTag.Name
333+
if name == "-" {
334+
continue
335+
}
336+
337+
optional = yamlTag.HasOption("omitempty")
330338
}
331339

332-
optional = yamlTag.HasOption("omitempty")
340+
tstypeTag, err := tags.Get("tstype")
341+
if err == nil {
342+
tstype = tstypeTag.Name
343+
if tstype == "-" || tstypeTag.HasOption("extends") {
344+
continue
345+
}
346+
required = tstypeTag.HasOption("required")
347+
readonly = tstypeTag.HasOption("readonly")
348+
}
333349
}
334350

335-
tstypeTag, err := tags.Get("tstype")
336-
if err == nil {
337-
tstype = tstypeTag.Name
338-
if tstype == "-" || tstypeTag.HasOption("extends") {
339-
continue
351+
if len(name) == 0 {
352+
if g.conf.Flavor == "yaml" {
353+
name = strings.ToLower(fieldName)
354+
} else {
355+
name = fieldName
340356
}
341-
required = tstypeTag.HasOption("required")
342-
readonly = tstypeTag.HasOption("readonly")
343357
}
344-
}
345358

346-
if len(name) == 0 {
347-
if g.conf.Flavor == "yaml" {
348-
name = strings.ToLower(fieldName)
349-
} else {
350-
name = fieldName
359+
if g.PreserveTypeComments() {
360+
g.writeCommentGroupIfNotNil(s, f.Doc, depth+1)
351361
}
352-
}
353362

354-
if g.PreserveTypeComments() {
355-
g.writeCommentGroupIfNotNil(s, f.Doc, depth+1)
356-
}
363+
g.writeIndent(s, depth+1)
364+
quoted := !validJSName(name)
365+
if quoted {
366+
s.WriteByte('\'')
367+
}
368+
if readonly {
369+
s.WriteString("readonly ")
370+
}
371+
s.WriteString(name)
372+
if quoted {
373+
s.WriteByte('\'')
374+
}
357375

358-
g.writeIndent(s, depth+1)
359-
quoted := !validJSName(name)
360-
if quoted {
361-
s.WriteByte('\'')
362-
}
363-
if readonly {
364-
s.WriteString("readonly ")
365-
}
366-
s.WriteString(name)
367-
if quoted {
368-
s.WriteByte('\'')
369-
}
376+
switch t := f.Type.(type) {
377+
case *ast.StarExpr:
378+
optional = !required
379+
f.Type = t.X
380+
}
370381

371-
switch t := f.Type.(type) {
372-
case *ast.StarExpr:
373-
optional = !required
374-
f.Type = t.X
375-
}
382+
if optional && g.conf.OptionalType == "undefined" {
383+
s.WriteByte('?')
384+
}
376385

377-
if optional && g.conf.OptionalType == "undefined" {
378-
s.WriteByte('?')
379-
}
386+
s.WriteString(": ")
380387

381-
s.WriteString(": ")
388+
if tstype == "" {
389+
g.writeType(s, f.Type, nil, depth, false)
390+
if optional && g.conf.OptionalType == "null" {
391+
s.WriteString(" | null")
392+
}
393+
} else {
394+
s.WriteString(tstype)
395+
}
396+
s.WriteByte(';')
382397

383-
if tstype == "" {
384-
g.writeType(s, f.Type, nil, depth, false)
385-
if optional && g.conf.OptionalType == "null" {
386-
s.WriteString(" | null")
398+
if f.Comment != nil && g.PreserveTypeComments() {
399+
// Line comment is present, that means a comment after the field.
400+
s.WriteString(" // ")
401+
s.WriteString(f.Comment.Text())
402+
} else {
403+
s.WriteByte('\n')
387404
}
388-
} else {
389-
s.WriteString(tstype)
390-
}
391-
s.WriteByte(';')
392405

393-
if f.Comment != nil && g.PreserveTypeComments() {
394-
// Line comment is present, that means a comment after the field.
395-
s.WriteString(" // ")
396-
s.WriteString(f.Comment.Text())
397-
} else {
398-
s.WriteByte('\n')
399406
}
400407

401408
}

tygo/write_comment.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ import (
55
"strings"
66
)
77

8+
// PreserveDocComments returns true if doc comments should be preserved.
9+
// These are comments that are not associated with a type or function, but rather
10+
// with the package or file itself.
811
func (g *PackageGenerator) PreserveDocComments() bool {
912
return g.conf.PreserveComments == "default"
1013
}
1114

15+
// PreserveTypeComments returns true if type comments should be preserved.
1216
func (g *PackageGenerator) PreserveTypeComments() bool {
1317
return g.conf.PreserveComments == "types" || g.conf.PreserveComments == "default"
1418
}

tygo/write_toplevel.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func (g *PackageGenerator) emitVar(s *strings.Builder, dec *ast.GenDecl) {
4545
}
4646
s.WriteString(v[1:len(v)-1] + "\n")
4747
}
48+
4849
func (g *PackageGenerator) writeGroupDecl(s *strings.Builder, decl *ast.GenDecl) {
4950
// This checks whether the declaration is a group declaration like:
5051
// const (
@@ -53,6 +54,16 @@ func (g *PackageGenerator) writeGroupDecl(s *strings.Builder, decl *ast.GenDecl)
5354
// )
5455
isGroupedDeclaration := len(decl.Specs) > 1
5556

57+
// Check if decl is exported, if not, we exit early so we don't write its comment.
58+
if !isGroupedDeclaration {
59+
if ts, ok := decl.Specs[0].(*ast.TypeSpec); ok && !ts.Name.IsExported() {
60+
return
61+
}
62+
if vs, ok := decl.Specs[0].(*ast.ValueSpec); ok && !vs.Names[0].IsExported() {
63+
return
64+
}
65+
}
66+
5667
if !isGroupedDeclaration && g.PreserveTypeComments() {
5768
g.writeCommentGroupIfNotNil(s, decl.Doc, 0)
5869
}

0 commit comments

Comments
 (0)