diff --git a/README.md b/README.md index 2406e0d..4c43022 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# go-plantuml +# go-plantuml [![Build Status](https://github.com/bykof/go-plantuml/actions/workflows/test.yml/badge.svg)](https://github.com/bykof/go-plantuml/actions/workflows/test.yml/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/bykof/go-plantuml)](https://goreportcard.com/report/github.com/bykof/go-plantuml) [![go-recipes](https://raw.githubusercontent.com/nikolaydubina/go-recipes/main/badge.svg?raw=true)](https://github.com/nikolaydubina/go-recipes) @@ -42,6 +42,7 @@ Flags: -h, --help help for generate -o, --out string the graphfile (default "graph.puml") -r, --recursive traverse the given directories recursively + -x, --exclude exclude file matching given regex expression, not used if using -f flag ``` ## Example @@ -83,10 +84,10 @@ type ( func (address Address) FullAddress(withPostalCode bool) string { return fmt.Sprintf( - "%s %s %d", - PackageVariable, - AnotherPackageVariable, - StartingStreetNumber, + "%s %s %d", + PackageVariable, + AnotherPackageVariable, + StartingStreetNumber, ) } diff --git a/astParser/parser.go b/astParser/parser.go index 3830109..276ab66 100644 --- a/astParser/parser.go +++ b/astParser/parser.go @@ -9,12 +9,18 @@ import ( "os" "path/filepath" "reflect" + "regexp" "strings" "github.com/bykof/go-plantuml/domain" ) -func ParseDirectory(directoryPath string, recursive bool) domain.Packages { +func ParseDirectory(directoryPath string, opts ...ParserOptionFunc) domain.Packages { + options := &parserOptions{} + for _, opt := range opts { + opt(options) + } + var packages domain.Packages files, err := os.ReadDir(directoryPath) if err != nil { @@ -32,14 +38,15 @@ func ParseDirectory(directoryPath string, recursive bool) domain.Packages { for _, file := range files { fullPath := filepath.Join(directoryPath, file.Name()) if !file.IsDir() { - if filepath.Ext(file.Name()) != ".go" || strings.Contains(file.Name(), "_test") { + if isExcluded(file.Name(), options.excludedFilesRegex) { continue } + parsedPackage := ParseFile(fullPath) currentPackage = currentPackage.Add(parsedPackage) } else { - if recursive { - packages = append(packages, ParseDirectory(fullPath, recursive)...) + if options.recursive { + packages = append(packages, ParseDirectory(fullPath, opts...)...) } } } @@ -51,6 +58,26 @@ func ParseDirectory(directoryPath string, recursive bool) domain.Packages { return packages } +func isExcluded(fileName string, regex *regexp.Regexp) bool { + if filepath.Ext(fileName) != ".go" { + return true + } + + if strings.HasSuffix(fileName, "_test.go") { + return true + } + + if regex == nil { + return false + } + + if regex.Match([]byte(fileName)) { + return true + } + + return false +} + func ParseFile(filePath string) domain.Package { var domainPackage domain.Package diff --git a/astParser/parser_option.go b/astParser/parser_option.go new file mode 100644 index 0000000..3c9588a --- /dev/null +++ b/astParser/parser_option.go @@ -0,0 +1,25 @@ +package astParser + +import ( + "regexp" +) + +type parserOptions struct { + recursive bool + excludedFilesRegex *regexp.Regexp +} + +type ParserOptionFunc func(*parserOptions) + +func WithRecursive() func(*parserOptions) { + return func(opt *parserOptions) { + opt.recursive = true + } +} + +func WithFileExclusion(exclusionRegex string) func(*parserOptions) { + return func(opt *parserOptions) { + var re = regexp.MustCompile(exclusionRegex) + opt.excludedFilesRegex = re + } +} diff --git a/astParser/parser_option_test.go b/astParser/parser_option_test.go new file mode 100644 index 0000000..27fbd71 --- /dev/null +++ b/astParser/parser_option_test.go @@ -0,0 +1,51 @@ +package astParser + +import ( + "reflect" + "regexp" + "testing" +) + +func TestWithRecursive(t *testing.T) { + tests := []struct { + name string + want *parserOptions + }{ + {"positive", &parserOptions{recursive: true}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + op := &parserOptions{} + opt := WithRecursive() + opt(op) + if !reflect.DeepEqual(op, tt.want) { + t.Errorf("WithRecursive() = %v, want %v", op, tt.want) + } + }) + } +} + +func TestWithFileExclusion(t *testing.T) { + type args struct { + exclusionRegex string + } + tests := []struct { + name string + args args + want *parserOptions + }{ + {"positive", args{"^somefile.go$"}, &parserOptions{excludedFilesRegex: regexp.MustCompile("^somefile.go$")}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + op := &parserOptions{} + opt := WithFileExclusion(tt.args.exclusionRegex) + opt(op) + if !reflect.DeepEqual(op, tt.want) { + t.Errorf("WithRecursive() = %v, want %v", op, tt.want) + } + }) + } +} diff --git a/astParser/parser_test.go b/astParser/parser_test.go index 198a7f9..aa9b21c 100644 --- a/astParser/parser_test.go +++ b/astParser/parser_test.go @@ -1 +1,32 @@ package astParser + +import ( + "regexp" + "testing" +) + +func Test_isExcluded(t *testing.T) { + type args struct { + fileName string + regex *regexp.Regexp + } + tests := []struct { + name string + args args + want bool + }{ + {"positive_non_go_file_returns_true", args{"parser.js", nil}, true}, + {"positive_go_test_file_returns_true", args{"parser_test.go", nil}, true}, + {"positive_match_regex_returns_true", args{"parser_mock.go", regexp.MustCompile(`^.+_mock.go$`)}, true}, + {"positive_match_regex_due_to_dot_returns_true", args{"parser_mock|tmp.go", regexp.MustCompile(`^.+_mock.tmp.go$`)}, true}, + {"negative_go_file_no_regex_returns_false", args{"parser.go", nil}, false}, + {"negative_go_file_did_not_match_regex_returns_false", args{"parser_mick.go", regexp.MustCompile(`^.+_mock.go$`)}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isExcluded(tt.args.fileName, tt.args.regex); got != tt.want { + t.Errorf("isExcluded() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/generate.go b/cmd/generate.go index 0e041b1..88f6efa 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -15,6 +15,7 @@ var ( outPath string directories []string files []string + exclusion string recursive bool generateCmd = &cobra.Command{ Use: "generate", @@ -26,8 +27,17 @@ var ( packages = append(packages, astParser.ParseFile(file)) } + options := []astParser.ParserOptionFunc{} + if recursive { + options = append(options, astParser.WithRecursive()) + } + + if exclusion!=""{ + options = append(options, astParser.WithFileExclusion(exclusion)) + } + for _, directory := range directories { - packages = append(packages, astParser.ParseDirectory(directory, recursive)...) + packages = append(packages, astParser.ParseDirectory(directory, options...)...) } formattedPlantUML := formatter.FormatPlantUML(packages) @@ -68,5 +78,12 @@ func init() { false, "traverse the given directories recursively", ) + generateCmd.Flags().StringVarP( + &exclusion, + "exclude", + "x", + "", + "exclude file matching given regex expression, not used if using -f flag", + ) rootCmd.AddCommand(generateCmd) }