77 "io"
88 "os"
99 "path/filepath"
10+ "slices"
1011 "sort"
1112 "strings"
1213
@@ -33,6 +34,7 @@ func NewMermaidWriter(opts ...MermaidOption) *MermaidWriter {
3334 m := & MermaidWriter {
3435 MinEdgeName : minEdgeName ,
3536 SpecifiedPackageName : specifiedPackageName ,
37+ UseV0Semantics : true ,
3638 }
3739
3840 for _ , opt := range opts {
@@ -53,9 +55,9 @@ func WithSpecifiedPackageName(specifiedPackageName string) MermaidOption {
5355 }
5456}
5557
56- func WithV0Semantics () MermaidOption {
58+ func WithV0Semantics (useV0Semantics bool ) MermaidOption {
5759 return func (o * MermaidWriter ) {
58- o .UseV0Semantics = true
60+ o .UseV0Semantics = useV0Semantics
5961 }
6062}
6163
@@ -131,7 +133,8 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
131133 }
132134
133135 var deprecatedPackage string
134- deprecatedChannels := []string {}
136+ deprecatedChannelIDs := []string {}
137+ decoratedBundleIDs := map [string ][]string {"deprecated" : {}, "skipped" : {}, "deprecatedskipped" : {}}
135138 linkID := 0
136139 skippedLinkIDs := []string {}
137140
@@ -154,7 +157,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
154157 }
155158
156159 if depByChannel .Has (filteredChannel .Name ) {
157- deprecatedChannels = append (deprecatedChannels , channelID )
160+ deprecatedChannelIDs = append (deprecatedChannelIDs , channelID )
158161 }
159162
160163 // sort edges by decreasing version
@@ -169,29 +172,45 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
169172
170173 skippedEntities := sets.Set [string ]{}
171174
175+ const (
176+ captureNewEntry = true
177+ processExisting = false
178+ )
179+ handleSemantics := func (edge string , linkID int , captureNew bool ) {
180+ if writer .UseV0Semantics {
181+ if captureNew {
182+ if skippedEntities .Has (edge ) {
183+ skippedLinkIDs = append (skippedLinkIDs , fmt .Sprintf ("%d" , linkID ))
184+ } else {
185+ skippedEntities .Insert (edge )
186+ }
187+ } else {
188+ if skippedEntities .Has (edge ) {
189+ skippedLinkIDs = append (skippedLinkIDs , fmt .Sprintf ("%d" , linkID ))
190+ }
191+ }
192+ }
193+ }
194+
172195 for _ , ce := range sortedEntries {
173- bundleDecoration := ""
196+ entryID := fmt .Sprintf ("%s-%s" , channelID , ce .Name )
197+ fmt .Fprintf (pkgBuilder , " %s[%q]\n " , entryID , ce .Name )
198+
199+ // mermaid allows specification of only a single decoration class, so any combinations must be independently represented
174200 switch {
175201 case depByBundle .Has (ce .Name ) && skippedEntities .Has (ce .Name ):
176- bundleDecoration = ":::depandskip"
202+ decoratedBundleIDs [ "deprecatedskipped" ] = append ( decoratedBundleIDs [ "deprecatedskipped" ], entryID )
177203 case depByBundle .Has (ce .Name ):
178- bundleDecoration = "::: deprecated"
204+ decoratedBundleIDs [ "deprecated" ] = append ( decoratedBundleIDs [ " deprecated"], entryID )
179205 case skippedEntities .Has (ce .Name ):
180- bundleDecoration = "::: skipped"
206+ decoratedBundleIDs [ "skipped" ] = append ( decoratedBundleIDs [ " skipped"], entryID )
181207 }
182208
183- entryID := fmt .Sprintf ("%s-%s" , channelID , ce .Name )
184- fmt .Fprintf (pkgBuilder , " %s[%q]%s\n " , entryID , ce .Name , bundleDecoration )
185-
186209 if len (ce .Skips ) > 0 {
187210 for _ , s := range ce .Skips {
188211 skipsID := fmt .Sprintf ("%s-%s" , channelID , s )
189212 fmt .Fprintf (pkgBuilder , " %s[%q]-- %s --> %s[%q]\n " , skipsID , s , "skip" , entryID , ce .Name )
190- if skippedEntities .Has (s ) {
191- skippedLinkIDs = append (skippedLinkIDs , fmt .Sprintf ("%d" , linkID ))
192- } else {
193- skippedEntities .Insert (s )
194- }
213+ handleSemantics (s , linkID , captureNewEntry )
195214 linkID ++
196215 }
197216 }
@@ -202,9 +221,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
202221 if skipRange (versionMap [edgeName .Name ]) {
203222 skipRangeID := fmt .Sprintf ("%s-%s" , channelID , edgeName .Name )
204223 fmt .Fprintf (pkgBuilder , " %s[%q]-- \" %s(%s)\" --> %s[%q]\n " , skipRangeID , edgeName .Name , "skipRange" , ce .SkipRange , entryID , ce .Name )
205- if skippedEntities .Has (ce .Name ) {
206- skippedLinkIDs = append (skippedLinkIDs , fmt .Sprintf ("%d" , linkID ))
207- }
224+ handleSemantics (ce .Name , linkID , processExisting )
208225 linkID ++
209226 }
210227 }
@@ -216,9 +233,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
216233 if len (ce .Replaces ) > 0 {
217234 replacesID := fmt .Sprintf ("%s-%s" , channelID , ce .Replaces )
218235 fmt .Fprintf (pkgBuilder , " %s[%q]-- %s --> %s[%q]\n " , replacesID , ce .Replaces , "replace" , entryID , ce .Name )
219- if skippedEntities .Has (ce .Name ) {
220- skippedLinkIDs = append (skippedLinkIDs , fmt .Sprintf ("%d" , linkID ))
221- }
236+ handleSemantics (ce .Name , linkID , processExisting )
222237 linkID ++
223238 }
224239 }
@@ -229,7 +244,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
229244 _ , _ = out .Write ([]byte ("graph LR\n " ))
230245 _ , _ = out .Write ([]byte (" classDef deprecated fill:#E8960F\n " ))
231246 _ , _ = out .Write ([]byte (" classDef skipped stroke:#FF0000,stroke-width:4px\n " ))
232- _ , _ = out .Write ([]byte (" classDef depandskip fill:#E8960 ,stroke:#FF0000,stroke-width:4px\n " ))
247+ _ , _ = out .Write ([]byte (" classDef deprecatedskipped fill:#E8960F ,stroke:#FF0000,stroke-width:4px\n " ))
233248 pkgNames := []string {}
234249 for pname := range pkgs {
235250 pkgNames = append (pkgNames , pname )
@@ -248,14 +263,23 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
248263 _ , _ = out .Write ([]byte (fmt .Sprintf ("style %s fill:#989695\n " , deprecatedPackage )))
249264 }
250265
251- if len (deprecatedChannels ) > 0 {
252- for _ , deprecatedChannel := range deprecatedChannels {
266+ if len (deprecatedChannelIDs ) > 0 {
267+ for _ , deprecatedChannel := range deprecatedChannelIDs {
253268 _ , _ = out .Write ([]byte (fmt .Sprintf ("style %s fill:#DCD0FF\n " , deprecatedChannel )))
254269 }
255270 }
256271
272+ // express the decoration classes
273+ for key := range decoratedBundleIDs {
274+ if len (decoratedBundleIDs [key ]) > 0 {
275+ b := slices .Clone (decoratedBundleIDs [key ])
276+ slices .Sort (b )
277+ _ , _ = out .Write ([]byte (fmt .Sprintf ("class %s %s\n " , strings .Join (b , "," ), key )))
278+ }
279+ }
280+
257281 if len (skippedLinkIDs ) > 0 {
258- _ , _ = out .Write ([]byte ("linkStyle " + strings .Join (skippedLinkIDs , "," ) + " stroke:#FF0000,stroke-width:3px,stroke-dasharray:5;" ))
282+ _ , _ = out .Write ([]byte ("linkStyle " + strings .Join (skippedLinkIDs , "," ) + " stroke:#FF0000,stroke-width:3px,stroke-dasharray:5;\n " ))
259283 }
260284
261285 return nil
0 commit comments