From a58f49380186bd705ed7e54e20978d68341cda39 Mon Sep 17 00:00:00 2001 From: spinillos Date: Tue, 4 Apr 2023 14:16:38 +0200 Subject: [PATCH 1/3] Fix inner comments --- generate_test.go | 1 - generator.go | 18 +++++++++++------- testdata/imports/inline_comments.txtar | 4 ++-- ts/ast/lit.go | 19 +++++++++++++++++-- ts/ts.go | 20 ++++++++------------ 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/generate_test.go b/generate_test.go index 16a3737..7442f11 100644 --- a/generate_test.go +++ b/generate_test.go @@ -47,7 +47,6 @@ func TestGenerateWithImports(t *testing.T) { "imports/oneref_verbose": "Figure out how to disambiguate struct literals from the struct-with-braces-and-one-element case", "imports/struct_shorthand": "Shorthand struct notation is currently unsupported, needs fixing", "imports/single_embed": "Single-item struct embeds should be treated as just another interface to compose, but get confused with references - #60", - "imports/inline_comments": "Inline comments do not appear be retrievable from cue.Value.Doc()", "imports/nulltype": "null types are not handled correctly", }, } diff --git a/generator.go b/generator.go index 504bb6e..fb95fa9 100644 --- a/generator.go +++ b/generator.go @@ -277,7 +277,6 @@ type KV struct { // if memberNames is absent, then keys implicitly generated as CamelCase // - string struct: struct keys get enum keys, struct values enum values func (g *generator) genEnum(name string, v cue.Value) []ts.Decl { - vdoc := v.Doc() // FIXME compensate for attribute-applying call to Unify() on incoming Value op, dvals := v.Expr() if op == cue.AndOp { @@ -302,7 +301,7 @@ func (g *generator) genEnum(name string, v cue.Value) []ts.Decl { ret[0] = tsast.TypeDecl{ Name: ts.Ident(name), Type: tsast.EnumType{Elems: exprs}, - CommentList: commentsForGroup(vdoc, true), + CommentList: commentsFor(v, true), Export: g.c.Export, } @@ -469,7 +468,6 @@ func (g *generator) genInterface(name string, v cue.Value) []ts.Decl { } var elems []tsast.KeyValueExpr var defs []tsast.KeyValueExpr - iter, _ := v.Fields(cue.Optional(true)) for iter != nil && iter.Next() { if iter.Selector().PkgPath() != "" { @@ -1444,14 +1442,20 @@ func commentsForGroup(cgs []*ast.CommentGroup, jsdoc bool) []tsast.Comment { } ret := make([]tsast.Comment, 0, len(cgs)) for _, cg := range cgs { - if cg.Line { - panic("hit it") - } ret = append(ret, ts.CommentFromCUEGroup(cg, jsdoc)) } return ret } func commentsFor(v cue.Value, jsdoc bool) []tsast.Comment { - return commentsForGroup(v.Doc(), jsdoc) + docs := v.Doc() + if s, ok := v.Source().(*ast.Field); ok { + for _, c := range s.Comments() { + if !c.Doc && c.Line { + docs = append(docs, c) + } + } + } + + return commentsForGroup(docs, jsdoc) } diff --git a/testdata/imports/inline_comments.txtar b/testdata/imports/inline_comments.txtar index 962980c..dc1d5a8 100644 --- a/testdata/imports/inline_comments.txtar +++ b/testdata/imports/inline_comments.txtar @@ -35,9 +35,9 @@ export type Nested = { * tripleInner has a before comment and * it's multiline */ - tripleInner: string, + tripleInner: string; // tripleInner has an inline comment }, }, }; // Nested has an inline comment -export type SimpleOnlyInline = string; // comment on SimpleOnlyInline +export type SimpleOnlyInline = string; // comment on SimpleOnlyInline diff --git a/ts/ast/lit.go b/ts/ast/lit.go index f6c6f9a..3027559 100644 --- a/ts/ast/lit.go +++ b/ts/ast/lit.go @@ -54,9 +54,20 @@ func (o ObjectLit) innerString(aeol EOL, lvl int) string { write("{\n") for _, e := range o.Elems { + hasInlineComments := false + for _, c := range e.Comments() { + if c.Pos == CommentInline { + hasInlineComments = true + } + } indent(lvl) write(formatInner(aeol, lvl, e)) - write(eol) + if hasInlineComments { + write("\n") + } else { + write(eol) + } + } indent(lvl - 1) @@ -97,7 +108,11 @@ func formatInner(eol EOL, lvl int, n Node) string { b.WriteString(prinner(eol, lvl, n)) for ; i < len(comms) && comms[i].Pos == CommentInline; i++ { - b.WriteString(" " + comms[i].innerString(eol, lvl) + " ") + if _, ok := n.(KeyValueExpr); ok { + b.WriteString("; " + comms[i].innerString(eol, lvl)) + } else { + b.WriteString(" " + comms[i].innerString(eol, lvl)) + } } for ; i < len(comms); i++ { diff --git a/ts/ts.go b/ts/ts.go index 010e1f7..095e41a 100644 --- a/ts/ts.go +++ b/ts/ts.go @@ -147,14 +147,12 @@ func CommentFromCUEGroup(cg *cast.CommentGroup, jsdoc bool) ast.Comment { } prefix := func() { b.WriteString("// ") } - if jsdoc { - b.WriteString("/**") - if cg.Line { - prefix = func() { b.WriteString(" ") } - } else { - b.WriteString("\n") - prefix = func() { b.WriteString(" * ") } - } + if jsdoc && cg.Doc && !cg.Line { + b.WriteString("/**\n") + prefix = func() { b.WriteString(" * ") } + } else if jsdoc && !cg.Doc && cg.Line { + b.WriteString("//") + prefix = func() { b.WriteString(" ") } } scanner := bufio.NewScanner(strings.NewReader(cg.Text())) @@ -167,10 +165,8 @@ func CommentFromCUEGroup(cg *cast.CommentGroup, jsdoc bool) ast.Comment { b.WriteString(scanner.Text()) i++ } - if jsdoc { - if !cg.Line { - b.WriteString("\n") - } + if jsdoc && cg.Doc { + b.WriteString("\n") b.WriteString(" */") } From 838330ac02b11e35db11f783d09167ae3c869a32 Mon Sep 17 00:00:00 2001 From: spinillos Date: Tue, 4 Apr 2023 14:31:03 +0200 Subject: [PATCH 2/3] Small refactor --- generator.go | 21 +++++------- ts/comments.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ ts/ts.go | 82 -------------------------------------------- 3 files changed, 101 insertions(+), 94 deletions(-) create mode 100644 ts/comments.go diff --git a/generator.go b/generator.go index 275f256..852266c 100644 --- a/generator.go +++ b/generator.go @@ -1431,17 +1431,6 @@ func referenceValueAs(v cue.Value, kinds ...TSType) (ts.Expr, error) { return nil, nil } -func commentsForGroup(cgs []*ast.CommentGroup, jsdoc bool) []tsast.Comment { - if cgs == nil { - return nil - } - ret := make([]tsast.Comment, 0, len(cgs)) - for _, cg := range cgs { - ret = append(ret, ts.CommentFromCUEGroup(cg, jsdoc)) - } - return ret -} - func commentsFor(v cue.Value, jsdoc bool) []tsast.Comment { docs := v.Doc() if s, ok := v.Source().(*ast.Field); ok { @@ -1452,5 +1441,13 @@ func commentsFor(v cue.Value, jsdoc bool) []tsast.Comment { } } - return commentsForGroup(docs, jsdoc) + ret := make([]tsast.Comment, 0, len(docs)) + for _, cg := range docs { + ret = append(ret, ts.CommentFromCUEGroup(ts.Comment{ + Text: cg.Text(), + Multiline: cg.Doc && !cg.Line, + JSDoc: jsdoc, + })) + } + return ret } diff --git a/ts/comments.go b/ts/comments.go new file mode 100644 index 0000000..19752a3 --- /dev/null +++ b/ts/comments.go @@ -0,0 +1,92 @@ +package ts + +import ( + "bufio" + "strings" + + "github.com/grafana/cuetsy/ts/ast" + "github.com/kr/text" +) + +// CommentFromString takes a string input and formats it as an ast.CommentList. +// +// Line breaks are automatically inserted to minimize raggedness, with a loose +// width limit the provided lim. +// +// If the jsdoc param is true, the resulting comment will be formatted with +// JSDoc ( /** ... */ )-style. Otherwise, ordinary comment leader ( // ... ) will +// be used. +// +// The returned ast.CommentList will have the default CommentAbove position. +func CommentFromString(s string, lim int, jsdoc bool) ast.Comment { + var b strings.Builder + prefix := func() { b.WriteString("// ") } + if jsdoc { + b.WriteString("/**\n") + prefix = func() { b.WriteString(" * ") } + } + + scanner := bufio.NewScanner(strings.NewReader(text.Wrap(s, lim))) + var i int + for scanner.Scan() { + if i != 0 { + b.WriteString("\n") + } + prefix() + b.WriteString(scanner.Text()) + i++ + } + if jsdoc { + b.WriteString("\n */\n") + } + + return ast.Comment{ + Text: b.String(), + } +} + +type Comment struct { + Text string + Multiline bool + JSDoc bool +} + +// CommentFromCUEGroup creates an ast.CommentList from a Comment. +// +// Original line breaks are preserved, in keeping with principles of semantic line breaks. +func CommentFromCUEGroup(cg Comment) ast.Comment { + var b strings.Builder + pos := ast.CommentAbove + if !cg.Multiline { + pos = ast.CommentInline + } + + prefix := func() { b.WriteString("// ") } + if cg.JSDoc && cg.Multiline { + b.WriteString("/**\n") + prefix = func() { b.WriteString(" * ") } + } else { + b.WriteString("//") + prefix = func() { b.WriteString(" ") } + } + + scanner := bufio.NewScanner(strings.NewReader(cg.Text)) + var i int + for scanner.Scan() { + if i != 0 { + b.WriteString("\n") + } + prefix() + b.WriteString(scanner.Text()) + i++ + } + if cg.JSDoc && cg.Multiline { + b.WriteString("\n") + b.WriteString(" */") + } + + return ast.Comment{ + Text: b.String(), + Pos: pos, + } +} diff --git a/ts/ts.go b/ts/ts.go index 095e41a..2125cea 100644 --- a/ts/ts.go +++ b/ts/ts.go @@ -1,12 +1,7 @@ package ts import ( - "bufio" - "strings" - - cast "cuelang.org/go/cue/ast" "github.com/grafana/cuetsy/ts/ast" - "github.com/kr/text" ) type ( @@ -98,80 +93,3 @@ func Bool(b bool) Expr { } return Ident("false") } - -// CommentFromString takes a string input and formats it as an ast.CommentList. -// -// Line breaks are automatically inserted to minimize raggedness, with a loose -// width limit the provided lim. -// -// If the jsdoc param is true, the resulting comment will be formatted with -// JSDoc ( /** ... */ )-style. Otherwise, ordinary comment leader ( // ... ) will -// be used. -// -// The returned ast.CommentList will have the default CommentAbove position. -func CommentFromString(s string, lim int, jsdoc bool) ast.Comment { - var b strings.Builder - prefix := func() { b.WriteString("// ") } - if jsdoc { - b.WriteString("/**\n") - prefix = func() { b.WriteString(" * ") } - } - - scanner := bufio.NewScanner(strings.NewReader(text.Wrap(s, lim))) - var i int - for scanner.Scan() { - if i != 0 { - b.WriteString("\n") - } - prefix() - b.WriteString(scanner.Text()) - i++ - } - if jsdoc { - b.WriteString("\n */\n") - } - - return ast.Comment{ - Text: b.String(), - } -} - -// CommentFromCUEGroup creates an ast.CommentList from a CUE AST CommentGroup. -// -// Original line breaks are preserved, in keeping with principles of semantic line breaks. -func CommentFromCUEGroup(cg *cast.CommentGroup, jsdoc bool) ast.Comment { - var b strings.Builder - pos := ast.CommentAbove - if cg.Line { - pos = ast.CommentInline - } - - prefix := func() { b.WriteString("// ") } - if jsdoc && cg.Doc && !cg.Line { - b.WriteString("/**\n") - prefix = func() { b.WriteString(" * ") } - } else if jsdoc && !cg.Doc && cg.Line { - b.WriteString("//") - prefix = func() { b.WriteString(" ") } - } - - scanner := bufio.NewScanner(strings.NewReader(cg.Text())) - var i int - for scanner.Scan() { - if i != 0 { - b.WriteString("\n") - } - prefix() - b.WriteString(scanner.Text()) - i++ - } - if jsdoc && cg.Doc { - b.WriteString("\n") - b.WriteString(" */") - } - - return ast.Comment{ - Text: b.String(), - Pos: pos, - } -} From a04fa291d7a29b51d2500b1b84747dae55144a91 Mon Sep 17 00:00:00 2001 From: spinillos Date: Tue, 4 Apr 2023 14:33:07 +0200 Subject: [PATCH 3/3] Undo deleted line --- generator.go | 1 + 1 file changed, 1 insertion(+) diff --git a/generator.go b/generator.go index 852266c..8f2f14d 100644 --- a/generator.go +++ b/generator.go @@ -468,6 +468,7 @@ func (g *generator) genInterface(name string, v cue.Value) []ts.Decl { } var elems []tsast.KeyValueExpr var defs []tsast.KeyValueExpr + iter, _ := v.Fields(cue.Optional(true)) for iter != nil && iter.Next() { if iter.Selector().PkgPath() != "" {