diff --git a/gnovm/pkg/gnomod/parse.go b/gnovm/pkg/gnomod/parse.go index a62eb1cbdc1..dfb5ac62057 100644 --- a/gnovm/pkg/gnomod/parse.go +++ b/gnovm/pkg/gnomod/parse.go @@ -99,8 +99,10 @@ func (f *File) add(errs *modfile.ErrorList, block *modfile.LineBlock, line *modf errorf("repeated module statement") return } + deprecated := parseDeprecation(block, line) f.Module = &modfile.Module{ - Syntax: line, + Syntax: line, + Deprecated: deprecated, } if len(args) != 1 { errorf("usage: module module/path") diff --git a/gnovm/pkg/gnomod/parse_test.go b/gnovm/pkg/gnomod/parse_test.go new file mode 100644 index 00000000000..ce3a745147e --- /dev/null +++ b/gnovm/pkg/gnomod/parse_test.go @@ -0,0 +1,118 @@ +package gnomod + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestModuleDeprecated(t *testing.T) { + for _, tc := range []struct { + desc, in, expected string + }{ + { + desc: "no_comment", + in: `module m`, + }, + { + desc: "other_comment", + in: `// yo + module m`, + }, + { + desc: "deprecated_no_colon", + in: `//Deprecated + module m`, + }, + { + desc: "deprecated_no_space", + in: `//Deprecated:blah + module m`, + expected: "blah", + }, + { + desc: "deprecated_simple", + in: `// Deprecated: blah + module m`, + expected: "blah", + }, + { + desc: "deprecated_lowercase", + in: `// deprecated: blah + module m`, + }, + { + desc: "deprecated_multiline", + in: `// Deprecated: one + // two + module m`, + expected: "one\ntwo", + }, + { + desc: "deprecated_mixed", + in: `// some other comment + // Deprecated: blah + module m`, + }, + { + desc: "deprecated_middle", + in: `// module m is Deprecated: blah + module m`, + }, + { + desc: "deprecated_multiple", + in: `// Deprecated: a + // Deprecated: b + module m`, + expected: "a\nDeprecated: b", + }, + { + desc: "deprecated_paragraph", + in: `// Deprecated: a + // b + // + // c + module m`, + expected: "a\nb", + }, + { + desc: "deprecated_paragraph_space", + in: `// Deprecated: the next line has a space + // + // c + module m`, + expected: "the next line has a space", + }, + { + desc: "deprecated_suffix", + in: `module m // Deprecated: blah`, + expected: "blah", + }, + { + desc: `deprecated_mixed_suffix`, + in: `// some other comment + module m // Deprecated: blah`, + }, + { + desc: "deprecated_mixed_suffix_paragraph", + in: `// some other comment + // + module m // Deprecated: blah`, + expected: "blah", + }, + { + desc: "deprecated_block", + in: `// Deprecated: blah + module ( + m + )`, + expected: "blah", + }, + } { + t.Run(tc.desc, func(t *testing.T) { + f, err := Parse("in", []byte(tc.in)) + assert.Nil(t, err) + assert.Equal(t, tc.expected, f.Module.Deprecated) + }) + } +} diff --git a/gnovm/pkg/gnomod/read.go b/gnovm/pkg/gnomod/read.go index 75b632cb2e2..a05efa19c9f 100644 --- a/gnovm/pkg/gnomod/read.go +++ b/gnovm/pkg/gnomod/read.go @@ -15,6 +15,7 @@ import ( "fmt" "os" "path/filepath" + "regexp" "strconv" "strings" "unicode" @@ -793,3 +794,42 @@ func parseReplace(filename string, line *modfile.Line, verb string, args []strin Syntax: line, }, nil } + +// parseDeprecation extracts the text of comments on a "module" directive and +// extracts a deprecation message from that. +// +// A deprecation message is contained in a paragraph within a block of comments +// that starts with "Deprecated:" (case sensitive). The message runs until the +// end of the paragraph and does not include the "Deprecated:" prefix. If the +// comment block has multiple paragraphs that start with "Deprecated:", +// parseDeprecation returns the message from the first. +func parseDeprecation(block *modfile.LineBlock, line *modfile.Line) string { + text := parseDirectiveComment(block, line) + rx := regexp.MustCompile(`(?s)(?:^|\n\n)Deprecated: *(.*?)(?:$|\n\n)`) + m := rx.FindStringSubmatch(text) + if m == nil { + return "" + } + return m[1] +} + +// parseDirectiveComment extracts the text of comments on a directive. +// If the directive's lien does not have comments and is part of a block that +// does have comments, the block's comments are used. +func parseDirectiveComment(block *modfile.LineBlock, line *modfile.Line) string { + comments := line.Comment() + if block != nil && len(comments.Before) == 0 && len(comments.Suffix) == 0 { + comments = block.Comment() + } + groups := [][]modfile.Comment{comments.Before, comments.Suffix} + var lines []string + for _, g := range groups { + for _, c := range g { + if !strings.HasPrefix(c.Token, "//") { + continue // blank line + } + lines = append(lines, strings.TrimSpace(strings.TrimPrefix(c.Token, "//"))) + } + } + return strings.Join(lines, "\n") +}