Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: parse only specific extension tag #1219

Merged
merged 5 commits into from Dec 11, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions cmd/swag/main.go
Expand Up @@ -34,6 +34,7 @@ const (
parseGoListFlag = "parseGoList"
quietFlag = "quiet"
tagsFlag = "tags"
parseExtensionFlag = "parseExtension"
)

var initFlags = []cli.Flag{
Expand Down Expand Up @@ -129,6 +130,11 @@ var initFlags = []cli.Flag{
Value: true,
Usage: "Parse dependency via 'go list'",
},
&cli.StringFlag{
Name: parseExtensionFlag,
Value: "",
Usage: "Parse only those operations that match given extension",
},
&cli.StringFlag{
Name: tagsFlag,
Aliases: []string{"t"},
Expand Down Expand Up @@ -158,6 +164,7 @@ func initAction(ctx *cli.Context) error {
return gen.New().Build(&gen.Config{
SearchDir: ctx.String(searchDirFlag),
Excludes: ctx.String(excludeFlag),
ParseExtension: ctx.String(parseExtensionFlag),
MainAPIFile: ctx.String(generalInfoFlag),
PropNamingStrategy: strategy,
OutputDir: ctx.String(outputFlag),
Expand Down
4 changes: 4 additions & 0 deletions gen/gen.go
Expand Up @@ -72,6 +72,9 @@ type Config struct {
// excludes dirs and files in SearchDir,comma separated
Excludes string

// outputs only specific extension
ParseExtension string

// OutputDir represents the output directory for all the generated files
OutputDir string

Expand Down Expand Up @@ -167,6 +170,7 @@ func (g *Gen) Build(config *Config) error {
swag.SetMarkdownFileDirectory(config.MarkdownFilesDir),
swag.SetDebugger(config.Debugger),
swag.SetExcludedDirsAndFiles(config.Excludes),
swag.SetParseExtension(config.ParseExtension),
swag.SetCodeExamplesDirectory(config.CodeExampleFilesDir),
swag.SetStrict(config.Strict),
swag.SetOverrides(overrides),
Expand Down
29 changes: 28 additions & 1 deletion parser.go
Expand Up @@ -137,6 +137,9 @@ type Parser struct {
// excludes excludes dirs and files in SearchDir
excludes map[string]struct{}

// tells parser to include only specific extension
parseExtension string

// debugging output goes here
debug Debugger

Expand Down Expand Up @@ -265,6 +268,13 @@ func SetTags(include string) func(*Parser) {
}
}

// SetParseExtension parses only those operations which match given extension
func SetParseExtension(parseExtension string) func(*Parser) {
return func(p *Parser) {
p.parseExtension = parseExtension
}
}

// SetStrict sets whether swag should error or warn when it detects cases which are most likely user errors.
func SetStrict(strict bool) func(*Parser) {
return func(p *Parser) {
Expand Down Expand Up @@ -828,12 +838,29 @@ func (parser *Parser) matchTags(comments []*ast.Comment) (match bool) {
return true
}

func (parser *Parser) matchExtension(comments []*ast.Comment) (match bool) {
if len(parser.parseExtension) != 0 {
for _, comment := range comments {
commentLine := strings.TrimSpace(strings.TrimLeft(comment.Text, "/"))
fields := FieldsByAnySpace(commentLine, 2)
lowerAttribute := strings.ToLower(fields[0])

if lowerAttribute == fmt.Sprintf("@x-%s", strings.ToLower(parser.parseExtension)) {
return true
}
}
return false
}
return true
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only thing you are using from the parser is parser.ParseExtension, This function is a mimic of in_array func in_array(val string, array []string) bool with default to true if the search value is empty.

Such a simple function should not be attached to the parser.

func matchExtension(textToFind string, comments []*ast.Comment) bool

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.
I was basically c/p above matchTags without too much thinking. you have a good point.

I can detach it from the parser, before that just to double check do you recommend to create a "helper" in_array-type method or still keep it specific to extension parsing? (Not sure if we have such a helper file/methods today somewhere - can't find them in the repo)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just detach the function from the parser.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

// ParseRouterAPIInfo parses router api info for given astFile.
func (parser *Parser) ParseRouterAPIInfo(fileName string, astFile *ast.File) error {
for _, astDescription := range astFile.Decls {
astDeclaration, ok := astDescription.(*ast.FuncDecl)
if ok && astDeclaration.Doc != nil && astDeclaration.Doc.List != nil {
if parser.matchTags(astDeclaration.Doc.List) {
if parser.matchTags(astDeclaration.Doc.List) &&
parser.matchExtension(astDeclaration.Doc.List) {
// for per 'function' comment, create a new 'Operation' object
operation := NewOperation(parser, SetCodeExampleFilesDirectory(parser.codeExampleFilesDir))
for _, comment := range astDeclaration.Doc.List {
Expand Down
48 changes: 48 additions & 0 deletions parser_test.go
Expand Up @@ -3878,3 +3878,51 @@ func TestParser_matchTags(t *testing.T) {
})
}
}

func TestParser_parseExtension(t *testing.T) {

src, err := os.ReadFile("testdata/parseExtension/parseExtension.go")
assert.NoError(t, err)

f, err := goparser.ParseFile(token.NewFileSet(), "", src, goparser.ParseComments)
assert.NoError(t, err)

tests := []struct {
name string
parser *Parser
expectedPaths map[string]bool
}{
{
name: "when no flag is set, everything is exported",
parser: New(),
expectedPaths: map[string]bool{"/without-extension": true, "/with-another-extension": true, "/with-correct-extension": true},
},
{
name: "when nonexistent flag is set, nothing is exported",
parser: New(SetParseExtension("nonexistent-extension-filter")),
expectedPaths: map[string]bool{"/without-extension": false, "/with-another-extension": false, "/with-correct-extension": false},
},
{
name: "when correct flag is set, only that Path is exported",
parser: New(SetParseExtension("google-backend")),
expectedPaths: map[string]bool{"/without-extension": false, "/with-another-extension": false, "/with-correct-extension": true},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err = tt.parser.ParseRouterAPIInfo("", f)
assert.NoError(t, err)
for p, isExpected := range tt.expectedPaths {
_, ok := tt.parser.swagger.Paths.Paths[p]
assert.Equal(t, isExpected, ok)
}

for p := range tt.parser.swagger.Paths.Paths {
_, isExpected := tt.expectedPaths[p]
assert.Equal(t, isExpected, true)
}
})

}
}
12 changes: 12 additions & 0 deletions testdata/parseExtension/parseExtension.go
@@ -0,0 +1,12 @@
package main

// @Router /without-extension [get]
func Fun() {}

// @Router /with-another-extension [get]
// @x-another-extension {"address": "http://backend"}
func Fun2() {}

// @Router /with-correct-extension [get]
// @x-google-backend {"address": "http://backend"}
func Fun3() {}