Git Product home page Git Product logo

goplantuml's Introduction

godoc reference Go Report Card codecov License: MIT GitHub release Mentioned in Awesome Go DUMELS Diagram

GoPlantUML V2

GoPlantUML is an open-source tool developed to streamline the process of generating PlantUML diagrams from Go source code. With GoPlantUML, developers can effortlessly visualize the structure and relationships within their Go projects, aiding in code comprehension and documentation. By parsing Go source code and producing PlantUML diagrams, GoPlantUML empowers developers to create clear and concise visual representations of their codebase architecture, package dependencies, and function interactions. This tool simplifies the documentation process and enhances collaboration among team members by providing a visual overview of complex Go projects. GoPlantUML is actively maintained and welcomes contributions from the Go community.

Want to try it on your code?

Take a look at www.dumels.com. We have created dumels using this library.

Code of Conduct

Please, review the code of conduct here.

Prerequisites

golang 1.17 or above

Installing

go get github.com/jfeliu007/goplantuml/parser
go install github.com/jfeliu007/goplantuml/cmd/goplantuml@latest

This will install the command goplantuml in your GOPATH bin folder.

Usage

goplantuml [-recursive] path/to/gofiles path/to/gofiles2
goplantuml [-recursive] path/to/gofiles path/to/gofiles2 > diagram_file_name.puml
Usage of goplantuml:
  -aggregate-private-members
        Show aggregations for private members. Ignored if -show-aggregations is not used.
  -hide-connections
        hides all connections in the diagram
  -hide-fields
        hides fields
  -hide-methods
        hides methods
  -ignore string
        comma separated list of folders to ignore
  -notes string
        Comma separated list of notes to be added to the diagram
  -output string
        output file path. If omitted, then this will default to standard output
  -recursive
        walk all directories recursively
  -show-aggregations
        renders public aggregations even when -hide-connections is used (do not render by default)
  -show-aliases
        Shows aliases even when -hide-connections is used
  -show-compositions
        Shows compositions even when -hide-connections is used
  -show-connection-labels
        Shows labels in the connections to identify the connections types (e.g. extends, implements, aggregates, alias of
  -show-implementations
        Shows implementations even when -hide-connections is used
  -show-options-as-note
        Show a note in the diagram with the none evident options ran with this CLI
  -title string
        Title of the generated diagram
  -hide-private-members
        Hides all private members (fields and methods)

Example

goplantuml $GOPATH/src/github.com/jfeliu007/goplantuml/parser
// echoes

@startuml
namespace parser {
    class Struct {
        + Functions []*Function
        + Fields []*Parameter
        + Type string
        + Composition []string
        + Extends []string

    }
    class LineStringBuilder {
        + WriteLineWithDepth(depth int, str string) 

    }
    class ClassParser {
        - structure <font color=blue>map</font>[string]<font color=blue>map</font>[string]*Struct
        - currentPackageName string
        - allInterfaces <font color=blue>map</font>[string]<font color=blue>struct</font>{}
        - allStructs <font color=blue>map</font>[string]<font color=blue>struct</font>{}

        - structImplementsInterface(st *Struct, inter *Struct) 
        - parsePackage(node ast.Node) 
        - parseFileDeclarations(node ast.Decl) 
        - addMethodToStruct(s *Struct, method *ast.Field) 
        - getFunction(f *ast.FuncType, name string) 
        - addFieldToStruct(s *Struct, field *ast.Field) 
        - addToComposition(s *Struct, fType string) 
        - addToExtends(s *Struct, fType string) 
        - getOrCreateStruct(name string) 
        - getStruct(structName string) 
        - getFieldType(exp ast.Expr, includePackageName bool) 

        + Render() 

    }
    class Parameter {
        + Name string
        + Type string

    }
    class Function {
        + Name string
        + Parameters []*Parameter
        + ReturnValues []string

    }
}
strings.Builder *-- parser.LineStringBuilder


@enduml
goplantuml $GOPATH/src/github.com/jfeliu007/goplantuml/parser > ClassDiagram.puml
// Generates a file ClassDiagram.puml with the previous specifications

There are two different relationships considered in goplantuml:

  • Interface implementation
  • Type Composition

The following example contains interface implementations and composition. Notice how the signature of the functions

package testingsupport

//MyInterface only has one method, notice the signature return value
type MyInterface interface {
	foo() bool
}

//MyStruct1 will implement the foo() bool function so it will have an "extends" association with MyInterface
type MyStruct1 struct {
}

func (s1 *MyStruct1) foo() bool {
	return true
}

//MyStruct2 will be directly composed of MyStruct1 so it will have a composition relationship with it
type MyStruct2 struct {
	MyStruct1
}

//MyStruct3 will have a foo() function but the return value is not a bool, so it will not have any relationship with MyInterface
type MyStruct3 struct {
    Foo MyStruct1
}

func (s3 *MyStruct3) foo() {

}

This will be generated from the previous code

@startuml
namespace testingsupport {
    interface MyInterface  {
        - foo() bool

    }
    class MyStruct1 << (S,Aquamarine) >> {
        - foo() bool

    }
    class MyStruct2 << (S,Aquamarine) >> {
    }
    class MyStruct3 << (S,Aquamarine) >> {
        - foo() 

        + Foo MyStruct1

    }
}
testingsupport.MyStruct1 *-- testingsupport.MyStruct2

testingsupport.MyInterface <|-- testingsupport.MyStruct1

testingsupport.MyStruct3 o-- testingsupport.MyStruct1

@enduml

alt text

Diagram using www.dumels.com

UML Diagram

Diagram rendered in plantuml online server

UML Diagram

For instructions on how to render these diagrams locally using plantuml please visit https://plantuml.com

goplantuml's People

Contributors

csams avatar ferhatelmas avatar heidelberger avatar jfeliu007 avatar morrislaw avatar rohinivsenthil avatar weters avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

goplantuml's Issues

Class diagram needs to be updated.

Now that we can ignore folders, we need to update the diagram to not include the testing_support subfolder. Also add this instruction in the Contributions file

Enhancement: Additional CLI options to control rendered output -no-edges

Add the CLI flag
-no-edges
to hide/exclude all edges
This would be useful to allow the output to be used as a template. E.g. So that custom edges can be added manually, but without having to manually remove all of the default edges.
Also, since edges impact diagram layout (Class location), temporarily eliminating the edges can be useful for simplifying graph layout (e.g. to locate a particular Class/node)

Testing and Logs

Hi,

First of all this is an excellent go-uml tool. Thanks for this awesome work.

One issue: I generated a puml file. But when I pasted in server, it fails to show any output.
Then I had to change the puml file going through syntax and all to make this work. Is it possible to automate this just as to start a puml server instance locally and run this at once. And if display is failing, what could be the issues? Right now I don't even see any logs either.

Regards,
Sandip

Invalid edge for simple type

I'm seeing the following invalid puml generated:

[]float64 #.. config.NumSlice

I think the go code that is causing the above line is this:

type NumSlice []float64

FYI: This error seems very similar to #49, but still exists despite the recent fixes for #49 and #50.

Add type alias relationship

When we have the following

type TheType struct {
}

type Alias TheType

There is no relationship being represented.

We might benefit from such relationship. Imagine the following code

type AnotherStruct struct {
    Alias
}

In this case, you would get the following diagram

test

But a better options would be to add a relationship from Alias to TheType stating that Alias is an alias for TheType. The following is the proposed relationship.

test

That would be achieved by using the #.. relationship in plantuml. Also, it would be nice to have the type being specified with a T to represent that it is a Type and not a structure

I will use << (T, #FF7700) >> for this

Support top-level functions

I have requested the same for bykof/go-plantuml, but open the same ticket here:

It would be nice if goplantuml would support top-level functions (instead of only methods).

The main problem will be the decision on how to represent these, as UML ususally doesn't provide a notion of top-level functions.

One possibility would be to misuse a class for that purpose. See this discussion about such a topic.

I have prepared a rough idea how that could be achieved.

For the following classes:

// mypackage/functions.go
package mypackage

func Function1() []string {
  return []string{}
}

func Function2(param1, param2 string) {
}
// otherpackage.functions.go
package otherpackage

func New() MyStruct {
  return MyStruct{}
}

func Frobnicate(subject []string) {
}
// otherpackage/mystruct.go
package otherpackage

import (
  "fmt"

  "my.domain/rough/mypackage"
)

type MyStruct struct {
  Name string
}

func (s *MyStruct) DoSomething() {
  v := mypackage.Function1()
  fmt.Println(v)
}

func (s *MyStruct) GetSomething() string {
  return s.Name
}

the following puml file could be generated:

@startuml
title Rough idea
namespace mypackage {
  class mypackage.functions << (F, blanchedalmond) >> {
    + Function1() []string
    + Function2(string, string)
  }
}
namespace otherpackage {
  class otherpackage.MyStruct << (S, aquamarine) >> {
    + Name string
    + DoSomething()
    + GetSomething() string
  }

  class otherpackage.functions << (F, blanchedalmond) >> {
    + New() MyStruct
    + Frobnicate([]string)
  }
}

otherpackage.MyStruct uses --> mypackage.functions
@enduml

which would be rendered as:

dummy

Here a class with the dummy name "functions" is generated inside each package to hold all global functions of that package. To differentiate between this function "holder" and real structs I added the "F" symbol to function "holder" as the "S" is applied for structs already. Maybe the functions "holder" could also be specified as "abstract".

As MyStruct calls mypackage.Function1 in its DoSomething() method I added a "usage"-association between them.

Enhancement: Additional CLI options to control rendered -no-methods

Provide the CLI flag
-no-methods
to hide/exclude Classes' "methods"
This would be useful for simplifying/filtering the output. E.g. Reducing the size of the Class nodes (by including less intra-Class detail) simplifies the graph layout, and makes it easier to trace inter-Class relationships during an API review of the coupling between Classes.

Add output path parameter

Add an extra parameter to the CLI to allow for an output path instead of having to redirect.
-output

Reduce cyclomatic complexities

The go report card is A+ but there are cyclomatic complexities that need to be resolved. It would be nice if we can take care of it.

Some complicated constructs render inclorrectly

After running the parser on the ast library I noticed that this is rendered

"ast.<font color=blue>func</font>(string, reflect.Value) bool" #.. "ast.FieldFilter"

from

func(string, reflect.Value) bool FieldFilter

The problem is that the rendering is incorrect since i takes

ast.<font color=blue>func</font>(string, reflect

as the namespace name when it has to be ast

I am thinking the problem is in the dot between reflect and Value. I am not sure how to fix this because I was expecting plantuml to do this correctly. But I would have to research plantuml to see what to do in these situations.

Subpackages are not properly visualized

lets say I have following package structure.

- cmd
- api
  - v1
- packageA
  - packageA1
  - packageA2
- packageB
  - packageB1
  - packageB2

currently it does not draw the nesting of packages, meaning the outcome is not accurate.

It also doesn't name the packages accordingly if for example it is only the v1 package within api.

I would expect it to render as api/v1 for example so it is easy traceable where the package resides.

Bug: parsing and rendering of named imports

I think I have discovered 2 related problems with the way that named imports are being parsed and rendered.

Problem 1

func (p *ClassParser) parseImports(impt *ast.ImportSpec) is the func which maps import statements' names to the import path. Since the imports map is global and shared across all packages for an entire puml diagram, and since the map associates each name with only 1 import path, it results incorrect parsing/rendering in the following scenario:

  • Any parsing run which has 2+ files which each import different import paths, but give them the same name, will result in the name being associated with only the last of the imported paths. This can result in inaccurate alias connections in the rendered graph, since some of the classes which use the same import name will be connected to an import path that they don't actually import, and will not be connected to the import path they do actually import.

In order to fix this problem, you will have to perform parsing and rendering of named imports, and of other code constructs that use the import name/alias, in a way that correctly associates the import name with the import path associated with that import name in that file (and without assuming that the import name is associated with a single, unique import path across the entire set of parsed files/packages).

Problem 2

Related to the problem above, func (p *ClassParser) parseImports(impt *ast.ImportSpec) is called from func (p *ClassParser) parsePackage(node ast.Node), which iterates over an unsorted map of the package's files. Therefore:

  • Any single package that has 2 files which each import different import paths, but give them the same name, will result in the name being randomly associated with only one of the imported paths. This causes the same problem(s) as in Problem 1 (above), and also additionally causes non-repeatable output (see #61), since the 'last' import path parsed will vary from run to run.

To fix the non-repeatability (#61) portion of the problem you will need to parse the go files in a repeatable order within func (p *ClassParser) parsePackage(node ast.Node).

{packageName} shows in edge output

I'm seeing the following invalid puml generated:

[]{packageName}GroupConfig #.. mock.GroupConfigs

I think the go code that is causing the above line is this:

var errNoDataFound = errors.New("No data found in the db")

type GroupConfigs []GroupConfig

type GroupConfig struct {
	Name string
	Jobs []string
}

I'm not sure why the above code would cause a problem, but there are no other code references to either GroupConfig or GroupConfigs so it seems like the only code that could possibly be related to the invalid puml output above.

FYI: This error seems possibly-related to #3, but since #3 has no details and is closed, I'm submitting this as a separate issue.

errors are not considered primitives

When error is used as a field in the functions, their fullName gets rendered as if it was part of the current package. "error" should be considered a primitive since it is a built in interface. Also the files in the vendors library are getting rendered. We need to skip the vendors folder when analysing the tree since they should not be considered part of the project.

Invalid edge for type

I'm seeing the following invalid puml generated:

<font color=blue>func</font>() []*servicebridgeerrors.Error #.. utils.StructureValidatorMethod

I think the go code that is causing the above line is this:

type StructureValidatorMethod func(interface{}) []*servicebridgeerrors.Error

Extend relationships do not get computed if the signature contains omitted types.

Say an interface is defined as this

type Inter interface {
    interfaceFunction(string, string)
}

If a struct defines this functions with the following signature

func (s *structure) interfaceFunction(a, b string) {
    ...
}

Then we fail to understand that it implements the interface.
We need to infer the parameters type from parameters when they do not have it in the Type field. Maybe we need to keep do a second pass backwards after the parameters are processed to fill in the blanks.

Enhancement: Render Header/Title and/or Legend

It'd be very helpful if the rendered puml diagram included a diagram title and/or a diagram-level legend (maybe a puml note?) with info about the diagram.

Optionally, 1+ new CLI flag could be added to disable the title, legend, etc. (in full and/or in part).

Suggested Diagram Metadata

  • Diagram Title
    E.g. Something related to the target golang package's full import path.
  • Render-time info (e.g. date/time rendered)
  • Rendering options
    E.g. Indicating any non-default rendering options were used to render the diagram (but possibly excluding any self-evident options, such as -label-edges).
  • (optionally) Git-related info (e.g. git branch that was rendered)

Rationale

When generating multiple diagrams (for different packages, or for the same package but with different CLI options, such as with and without -recursive or -hide-fields), the diagrams' contents are currently ambiguous, because they don't indicate whether content (subpackages, edges, fields, etc.) that is missing from the diagram is missing because of goplantuml CLI options, or because of the underlying package's source code.

With the above items included (automatically by default or via optional CLI flag) in each diagram's rendered content, the generated diagram's content would be self-documenting, unambiguous, and useful as a standalone design or review artifact.

Also, having goplantuml render the Title, Legend, etc. would prevent the need for post-rendering manual addition of such info, and also allow goplantuml to retain control over the formatting and content of the Title and Legend (e.g. when a new CLI flag is added to goplantuml, you would be able to decide what effect, if any, it should have on the Title and Legend).

However, retaining the ability to disable/hide the Title, Legend, etc. would be good, since it would allow generated diagrams to be included in documents, web pages, etc. which might want to control captions, titles, etc. separately from the diagram's image file.

Extended Interface not correctly visualized

The code from the golang.org website:

package main

type ReadWriter interface {
	Read(b Buffer) bool
	Write(b Buffer) bool
}

type File interface {
	ReadWriter  // same as adding the methods of ReadWriter
	Locker      // same as adding the methods of Locker
	Close()
}

type LockedFile interface {
	Locker
	File        // illegal: Lock, Unlock not unique
	Lock()      // illegal: Lock not unique
}

leads to the following uml code:

@startuml
namespace main {
    interface ReadWriter  {
        + Read(b Buffer) bool
        + Write(b Buffer) bool

    }
    interface File  {
        + Close() 

    }
    interface LockedFile  {
        + Lock() 

    }
}


@enduml

I think there should be some kind of extend or maybe a copy of all the methods from ReadWriter/Locker to File.

Some extends are not being generated.

When classes implement interfaces from other packages that contain in their function parameters classes from the same package, the function signatures do not match to equal. They need to match to equal

Repeatable output (idempotent output)

goplantuml should generate identical output when repeatedly executed against identical inputs/targets.

For example, when running the following 3 commands, the diff should detect no differences.

goplantuml -recursive . > goplantuml.a.puml
goplantuml -recursive . > goplantuml.b.puml
diff goplantuml.a.puml goplantuml.b.puml

However, currently the diff detects many differences between the 2 files.

Such non-idempotent output makes the output less usable for a variety of purposes. For example:

  • Since the diagram layout may potentially be affected by the order in which Classes and edges are defined in the output, plantuml/graphviz may potentially render different diagrams for output generated from identical source code (e.g. the 2 puml files generated above).
  • If output is committed to SCM, reviewing changes is nearly impossible (with the current non-idempotent output).
  • If output is manually modified (and then committed), it is more difficult to retain the manual revisions when updating the file (using goplantuml) when the underlying packages' source code changes.
  • It is more difficult to review the effects on the output of any CLI options that modify the output (e.g. #51, #53, #54, #55, #56, #57, #58, #60).

And if there is some reason or benefit from the current behavior (i.e. randomized output), then a new CLI flag could be added to give the user a choice between idempotent vs randomized output. However, I think that idempotent output should be the default behavior.

Enhancement: Additional CLI options to control rendered output -label-edges

Provide the CLI flag
-label-edges
To include text labels on all rendered edges/arrows
This would make arrows with different heads/tails easier to distinguish from each other.
(E.g. When multiple edges all start or end at the same Class, it can be difficult to identify which head/tail type a particular arrow has.)

Composition doesn't work

If I try to run the example in the README.md, the composition with MyStruct3 is not rendered (using go v1.12.6):

XL713e8m3BtlAte45HFnkX2yc7ZWn1TC78O4rhbr1wBykymOqG3IKzFszRtNffQ48TVKJ8b6MYqA2IGjLUfgdTPe2EuC-YXgOIraRKx65RG3pY78DuUR4uqmbP8X9Cbxr4S49M8GmXcnPgzgDx4c_hTc2h1Vubt34N6GoKQ2liLKYgGflUMiFNto1HST-xtFThZ9AefWfXcpCMoWv8zvPEyXbUhYN_G4

How to reproduce

save the following to a file:

package testingsupport

//MyInterface only has one method, notice the signature return value
type MyInterface interface {
	foo() bool
}

//MyStruct1 will implement the foo() bool function so it will have an "extends" association with MyInterface
type MyStruct1 struct {
}

func (s1 *MyStruct1) foo() bool {
	return true
}

//MyStruct2 will be direclty composed of MyStruct1 so it will have a composition relationship with it
type MyStruct2 struct {
	MyStruct1
}

//MyStruct3 will have a foo() function but the return value is not a bool, so it will not have any relationship with MyInterface
type MyStruct3 struct {
    Foo MyStruct1
}

func (s3 *MyStruct3) foo() {

}

Then generate the plantuml:

goplantuml ./

The diagram I get is the following:

@startuml
namespace testingsupport {
    interface MyInterface  {
        - foo() bool

    }
    class MyStruct1 << (S,Aquamarine) >> {
        - foo() bool

    }
    class MyStruct2 << (S,Aquamarine) >> {
    }
    class MyStruct3 << (S,Aquamarine) >> {
        + Foo MyStruct1

        - foo() 

    }
}
testingsupport.MyStruct1 *-- testingsupport.MyStruct2

testingsupport.MyInterface <|-- testingsupport.MyStruct1

@enduml

Enhancement: Additional CLI options to control rendered output -only-edgeless

Provide the CLI flag
-only-edgeless
To hide/exclude all Classes with any edges/arrows
This would be useful for simplifying/filtering the output. E.g. To easily identify un-connected Classes during an API review.
(E.g. Un-connected Classes often get 'scattered', with seemingly haphazard locations, based on where they 'fit' between connected Classes and their edges/arrows. Hiding edges and/or edged-Classes can reduce or eliminate such haphazard layouts, which is useful in certain situations.)

panic: runtime error: index out of range at class_parser.go:196

Certain projects cause goplantuml to crash with the following error:

panic: runtime error: index out of range

goroutine 1 [running]:
github.com/jfeliu007/goplantuml/parser.(*ClassParser).handleGenDecl(0xc00004c140, 0xc00004ce80)
        /Users/justinw/go/src/github.com/jfeliu007/goplantuml/parser/class_parser.go:196 +0x13f3
github.com/jfeliu007/goplantuml/parser.(*ClassParser).parseFileDeclarations(0xc00004c140, 0x1133f40, 0xc00004ce80)
        /Users/justinw/go/src/github.com/jfeliu007/goplantuml/parser/class_parser.go:162 +0x81
github.com/jfeliu007/goplantuml/parser.(*ClassParser).parsePackage(0xc00004c140, 0x11331c0, 0xc000011590)
        /Users/justinw/go/src/github.com/jfeliu007/goplantuml/parser/class_parser.go:132 +0x207
github.com/jfeliu007/goplantuml/parser.(*ClassParser).parseDirectory(0xc00004c140, 0xc0000b8f00, 0x47, 0x47, 0x120e380)
        /Users/justinw/go/src/github.com/jfeliu007/goplantuml/parser/class_parser.go:153 +0xfa
github.com/jfeliu007/goplantuml/parser.NewClassDiagram.func1(0xc0000b8f00, 0x47, 0x1134cc0, 0xc00010dba0, 0x0, 0x0, 0x0, 0xc000125ab0)
        /Users/justinw/go/src/github.com/jfeliu007/goplantuml/parser/class_parser.go:89 +0x105
path/filepath.walk(0xc0000b8f00, 0x47, 0x1134cc0, 0xc00010dba0, 0xc00000c060, 0x0, 0x0)
        /usr/local/go/src/path/filepath/path.go:362 +0xe3
path/filepath.walk(0xc0000bc3c0, 0x40, 0x1134cc0, 0xc00010dad0, 0xc00000c060, 0x0, 0x0)
        /usr/local/go/src/path/filepath/path.go:382 +0x300
path/filepath.walk(0xc00001a180, 0x3c, 0x1134cc0, 0xc0000925b0, 0xc00000c060, 0x0, 0x20)
        /usr/local/go/src/path/filepath/path.go:382 +0x300
path/filepath.Walk(0xc00001a180, 0x3c, 0xc00000c060, 0x10a1d28, 0x0)
        /usr/local/go/src/path/filepath/path.go:404 +0xff
github.com/jfeliu007/goplantuml/parser.NewClassDiagram(0xc0000420c0, 0x1, 0x1, 0x120daa0, 0x0, 0x0, 0x1, 0xc0000420b0, 0xc00007ef20, 0x1010be4)
        /Users/justinw/go/src/github.com/jfeliu007/goplantuml/parser/class_parser.go:78 +0x424
main.main()
        /Users/justinw/go/src/github.com/jfeliu007/goplantuml/cmd/goplantuml/main.go:34 +0x228

Struct Fields are not part of the diagram

Hi there!

First of all, nice work, like the idea of this repo!

I noticed, that this code looks like this:

image

But I would have expected something like this:

image

which would correspond to this PlantUML:

@startuml
namespace plantuml {
    class Phone << (S,Aquamarine) >> {
        + Value string
        + IsMobile bool

    }
    class Person << (S,Aquamarine) >> {
        + Birthday Birthday
        + Phones []Phone

    }
    class Birthday << (S,Aquamarine) >> {
        + Time time.Time

    }
    Phone <|-- Person
    Birthday <|-- Person
}
@enduml

I would like to use this tool to create a quick ERD for an upcoming project. And doing this by code enables me to quickly generate these models.

My proposal:

If displaying links based on struct fields is not considered a standard, could this at least be added as an CLI option?

Enhancement: Additional CLI options to control rendered output -no-fields

Provide the CLI flag
-no-fields
To hide/exclude Classes' "fields"
This would be useful for simplifying/filtering the output. E.g. Reducing the size of the Class nodes (by including less intra-Class detail) simplifies the graph layout, and makes it easier to trace inter-Class relationships during an API review of the coupling between Classes.

Add more examples to the Readme file

We need to have more example explaining how it works. More specifically, how are interface implementation and compositions get translated into the diagram.

Enhancement: Additional CLI options to control rendered output

It would be nice if the cmd class supported some additional CLI flags to enable the CLI to be used to quickly generate common variations of the current output.

The benefit of having CLI flags such as the following would be that someone could easily render several different diagrams/graphs of the same golang package(s), since each variant diagram has different PROs and CONs as an exploratory (and/or explanatory) visualization.

Suggested rendering options:

  • -no-fields: to hide/exclude Classes' "fields"
    This would be useful for simplifying/filtering the output. E.g. Reducing the size of the Class nodes (by including less intra-Class detail) simplifies the graph layout, and makes it easier to trace inter-Class relationships during an API review of the coupling between Classes.
  • -no-methods: to hide/exclude Classes' "methods"
    Same rationale as previous, but for methods/functions instead of fields.
  • -no-fields -no-methods: to hide/exclude all inner members of Classes
    Same rationale as previous, but for both methods/functions and fields.
    Hiding all intra-Class detail makes the graph much easier to use for identifying inter-Class coupling, etc.
  • -no-edges: to hide/exclude all edges
    This would be useful to allow the output to be used as a template. E.g. So that custom edges can be added manually, but without having to manually remove all of the default edges.
    Also, since edges impact diagram layout (Class location), temporarily eliminating the edges can be useful for simplifying graph layout (e.g. to locate a particular Class/node).
  • -no-edgeless: to hide/exclude all Classes without any edges/arrows
    This would be useful for simplifying/filtering the output. E.g. To easily exclude un-connected Classes during an API review of the coupling between Classes.
    (When there are many un-connected Classes, they can clutter up the diagram making it harder to trace the relationships between the connected Classes.)
  • -only-edgeless: to hide/exclude all Classes with any edges/arrows
    This would be useful for simplifying/filtering the output. E.g. To easily identify un-connected Classes during an API review.
    (E.g. Un-connected Classes often get 'scattered', with seemingly haphazard locations, based on where they 'fit' between connected Classes and their edges/arrows. Hiding edges and/or edged-Classes can reduce or eliminate such haphazard layouts, which is useful in certain situations.)
  • -label-edges: to include text labels on all rendered edges/arrows
    This would make arrows with different heads/tails easier to distinguish from each other.
    (E.g. When multiple edges all start or end at the same Class, it can be difficult to identify which head/tail type a particular arrow has.)

Note: For all of the hiding/filtering options above, you have 2 implementation options: either exclude 'hidden' graph content from the output completely, OR render the hidden content as you normally would, except as commented-out puml (so the diagram rendering would ignore hidden content, but the hidden content could be selectively un-hidden manually). Or you could give the user the choice between those 2 options by adding an additional -excluded-as-comments CLI flag (or similar).

Related: Similar to enhancement #28, but for additional CLI switches.

Newline at end of output

Currently, when ran in a shell, the output from the program looks like this:

dave@davespc$ goplantuml foobar.go
@startuml
...
...
...
@endumldave@davespc$ 

Note that the @enduml tag is printed without a trailing newline, causing it to be smashed into the shell prompt.

It would be a slightly nicer experience if the output contained a trailing newline.

Better detection or prevention of invalid output

There have been a few issues in the past (e.g. #3, #50, #49) where the plantuml output contained invalid syntax/content. It might be a good idea to add some output filtering and/or monitoring to automatically detect and/or filter and/or comment out portions of the output that will prevent plantuml from rendering the rest of the output.

For example, from #50 (by @jfeliu007):

This is definitely a bug. {{packageName}} is use to to have a placeholder to later substitute the package name by the real name since many go file prefer to name imports using aliases.

Issues like those described in #49, #50 and #3 could be prevented from causing un-renderable output by filtering out (or commenting out) any lines that contain occurrences of certain known patterns.

For example:

goplantuml -recursive . | grep -v '{packageName}' | grep -F -v '<font color=blue>func</font>()' > goplantuml.recursive.puml

Such lines could alternatively be commented-out (instead of stripped) (e.g. using sed).

Either of the above workarounds could be done manually by the user (using grep and/or sed or similar), except a novice user is unlikely to know what patterns to strip/convert. And (as issue #32 demonstrates) some users don't know enough about plantuml to effectively identify and manually correct such errors in the output.

Instead, goplantuml could internally perform equivalent filtering/commenting, so that users don't have to.

Also, it would be a better user experience if goplantuml automatically prevented a handful of errors from making the entire output un-renderable. E.g. For the first project I used goplantuml on, it generated >5000 lines of output that contained only 2 invalid lines. Simply removing or commenting-out those 2 lines made the rest of the diagram renderable and useful (though slightly incomplete due to the 2 missing edges/arrows).

Also, additional functional tests could be added to this repo (targeting a wider variety of OSS golang packages) and use similar pattern detection to detect whether goplantuml generates any such invalid output is generated. Such tests would likely detect functional regressions in goplantuml (e.g. when new versions of golang are released).

Enhancement: Additional CLI options to control rendered output -no-edgeless

Provide the CLI flag
-no-edgeless
To hide/exclude all Classes without any edges/arrows
This would be useful for simplifying/filtering the output. E.g. To easily exclude un-connected Classes during an API review of the coupling between Classes.
(When there are many un-connected Classes, they can clutter up the diagram making it harder to trace the relationships between the connected Classes.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.