@@ -26,6 +26,7 @@ import (
2626 "go/printer"
2727 "go/token"
2828 "log"
29+ "path/filepath"
2930 "sort"
3031 "strings"
3132
@@ -41,6 +42,7 @@ type tocItem struct {
4142 UID string `yaml:"uid,omitempty"`
4243 Name string `yaml:"name,omitempty"`
4344 Items []* tocItem `yaml:"items,omitempty"`
45+ Href string `yaml:"href,omitempty"`
4446}
4547
4648func (t * tocItem ) addItem (i * tocItem ) {
@@ -92,24 +94,32 @@ func (i *item) addChild(c child) {
9294
9395var onlyGo = []string {"go" }
9496
97+ type result struct {
98+ pages map [string ]* page
99+ toc tableOfContents
100+ module * packages.Module
101+ }
102+
95103// parse parses the directory into a map of import path -> page and a TOC.
96104//
97105// glob is the path to parse, usually ending in `...`. glob is passed directly
98106// to packages.Load as-is.
99- func parse (glob string ) (map [string ]* page , tableOfContents , * packages.Module , error ) {
107+ //
108+ // extraFiles is a list of paths relative to the module root to include.
109+ func parse (glob string , extraFiles []string ) (* result , error ) {
100110 config := & packages.Config {
101111 Mode : packages .NeedName | packages .NeedSyntax | packages .NeedTypes | packages .NeedTypesInfo | packages .NeedModule ,
102112 Tests : true ,
103113 }
104114
105115 pkgs , err := packages .Load (config , glob )
106116 if err != nil {
107- return nil , nil , nil , fmt .Errorf ("packages.Load: %v" , err )
117+ return nil , fmt .Errorf ("packages.Load: %v" , err )
108118 }
109119 packages .PrintErrors (pkgs ) // Don't fail everything because of one package.
110120
111121 if len (pkgs ) == 0 {
112- return nil , nil , nil , fmt .Errorf ("pattern %q matched 0 packages" , glob )
122+ return nil , fmt .Errorf ("pattern %q matched 0 packages" , glob )
113123 }
114124
115125 pages := map [string ]* page {}
@@ -122,7 +132,7 @@ func parse(glob string) (map[string]*page, tableOfContents, *packages.Module, er
122132
123133 // First, collect all of the files grouped by package, including test
124134 // packages.
125- allPkgFiles := map [string ][]string {}
135+ goPkgFiles := map [string ][]string {}
126136 for _ , pkg := range pkgs {
127137 id := pkg .ID
128138 // See https://pkg.go.dev/golang.org/x/tools/go/packages#Config.
@@ -144,15 +154,15 @@ func parse(glob string) (map[string]*page, tableOfContents, *packages.Module, er
144154 for _ , f := range pkg .Syntax {
145155 name := pkg .Fset .File (f .Pos ()).Name ()
146156 if strings .HasSuffix (name , ".go" ) {
147- allPkgFiles [id ] = append (allPkgFiles [id ], name )
157+ goPkgFiles [id ] = append (goPkgFiles [id ], name )
148158 }
149159 }
150160 }
151161
152162 // Test files don't have Module set. Filter out packages in skipped modules.
153163 pkgFiles := map [string ][]string {}
154164 pkgNames := []string {}
155- for pkgPath , files := range allPkgFiles {
165+ for pkgPath , files := range goPkgFiles {
156166 skip := false
157167 for skipped := range skippedModules {
158168 if strings .HasPrefix (pkgPath , skipped ) {
@@ -175,26 +185,41 @@ func parse(glob string) (map[string]*page, tableOfContents, *packages.Module, er
175185 for _ , f := range pkgFiles [pkgPath ] {
176186 pf , err := parser .ParseFile (fset , f , nil , parser .ParseComments )
177187 if err != nil {
178- return nil , nil , nil , fmt .Errorf ("ParseFile: %v" , err )
188+ return nil , fmt .Errorf ("ParseFile: %v" , err )
179189 }
180190 parsedFiles = append (parsedFiles , pf )
181191 }
182192
183193 // Parse out GoDoc.
184194 docPkg , err := doc .NewFromFiles (fset , parsedFiles , pkgPath )
185195 if err != nil {
186- return nil , nil , nil , fmt .Errorf ("doc.NewFromFiles: %v" , err )
196+ return nil , fmt .Errorf ("doc.NewFromFiles: %v" , err )
187197 }
188198
189199 // Extra filter in case the file filtering didn't catch everything.
190200 if ! strings .HasPrefix (docPkg .ImportPath , module .Path ) {
191201 continue
192202 }
193203
194- toc = append ( toc , & tocItem {
204+ pkgTOCITem := & tocItem {
195205 UID : docPkg .ImportPath ,
196206 Name : docPkg .ImportPath ,
197- })
207+ }
208+ toc = append (toc , pkgTOCITem )
209+
210+ // If the package path == module path, add the extra files to the TOC
211+ // as a child of the module==pkg item.
212+ if pkgPath == module .Path {
213+ for _ , path := range extraFiles {
214+ base := filepath .Base (path )
215+ name := strings .TrimSuffix (base , filepath .Ext (base ))
216+ name = strings .Title (name )
217+ pkgTOCITem .addItem (& tocItem {
218+ Href : path ,
219+ Name : name ,
220+ })
221+ }
222+ }
198223
199224 pkgItem := & item {
200225 UID : docPkg .ImportPath ,
@@ -345,7 +370,12 @@ func parse(glob string) (map[string]*page, tableOfContents, *packages.Module, er
345370 sort .Strings (skipped )
346371 log .Printf ("Warning: Only processed %s@%s, skipped:\n %s\n " , module .Path , module .Version , strings .Join (skipped , "\n " ))
347372 }
348- return pages , toc , module , nil
373+
374+ return & result {
375+ pages : pages ,
376+ toc : toc ,
377+ module : module ,
378+ }, nil
349379}
350380
351381// processExamples converts the examples to []example.
0 commit comments