aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/api/api.go171
1 files changed, 92 insertions, 79 deletions
diff --git a/internal/api/api.go b/internal/api/api.go
index fbc00e61..f7ab8882 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -47,7 +47,6 @@ func ServePackage(w http.ResponseWriter, r *http.Request, ds internal.DataSource
return err
}
- // Use GetUnit to get the requested data.
fs := internal.WithMain
if params.Licenses {
fs |= internal.WithLicenses
@@ -65,84 +64,9 @@ func ServePackage(w http.ResponseWriter, r *http.Request, ds internal.DataSource
return fmt.Errorf("%w: %s", derrors.Unknown, err.Error())
}
- // Process documentation, including synopsis.
- // Although unit.Documentation is a slice, it will
- // have at most one item, the documentation matching
- // the build context bc.
- synopsis := ""
- var docs string
- goos := params.GOOS
- goarch := params.GOARCH
- if len(unit.Documentation) > 0 {
- d := unit.Documentation[0]
- synopsis = d.Synopsis
- // Return the more precise GOOS/GOARCH.
- // If the user didn't provide them, use the unit's.
- // If the user did, assume what they provided is at
- // least as specific as the unit's, and use it.
- if goos == "" {
- goos = d.GOOS
- }
- if goarch == "" {
- goarch = d.GOARCH
- }
- if params.Doc != "" {
- // d.Source is an encoded AST. Decode it, then use
- // go/doc (not pkgsite's renderer) to generate the
- // result.
- gpkg, err := godoc.DecodePackage(d.Source)
- if err != nil {
- return fmt.Errorf("%w: %s", derrors.Unknown, err.Error())
- }
- innerPath := internal.Suffix(unit.Path, unit.ModulePath)
- modInfo := &godoc.ModuleInfo{ModulePath: unit.ModulePath, ResolvedVersion: unit.Version}
- dpkg, err := gpkg.DocPackage(innerPath, modInfo)
- if err != nil {
- return err
- }
- var r renderer
- var sb strings.Builder
- switch params.Doc {
- case "text":
- r = newTextRenderer(gpkg.Fset, &sb)
- case "md", "markdown":
- r = newMarkdownRenderer(gpkg.Fset, &sb)
- case "html":
- r = newHTMLRenderer(gpkg.Fset, &sb)
- default:
- return fmt.Errorf("%w: bad doc format: need one of 'text', 'md', 'markdown' or 'html'", derrors.InvalidArgument)
- }
- // TODO(jba): add a param to omit examples
- const includeExamples = true
- if err := renderDoc(dpkg, r, includeExamples); err != nil {
- return fmt.Errorf("%w: %s", derrors.Unknown, err.Error())
- }
- docs = sb.String()
- }
- }
-
- imports := unit.Imports
- var licenses []License
- for _, l := range unit.LicenseContents {
- licenses = append(licenses, License{
- Types: l.Metadata.Types,
- FilePath: l.Metadata.FilePath,
- Contents: string(l.Contents),
- })
- }
-
- resp := Package{
- Path: unit.Path,
- ModulePath: unit.ModulePath,
- ModuleVersion: unit.Version,
- Synopsis: synopsis,
- IsStandardLibrary: stdlib.Contains(unit.ModulePath),
- IsLatest: unit.Version == unit.LatestVersion,
- GOOS: goos,
- GOARCH: goarch,
- Docs: docs,
- Imports: imports,
- Licenses: licenses,
+ resp, err := unitToPackage(unit, params)
+ if err != nil {
+ return err
}
return serveJSON(w, http.StatusOK, resp)
@@ -594,3 +518,92 @@ func paginate[T any](all []T, lp ListParams, defaultLimit int) (PaginatedRespons
NextPageToken: nextToken,
}, nil
}
+
+// unitToPackage processes unit documentation into a Package struct.
+func unitToPackage(unit *internal.Unit, params PackageParams) (*Package, error) {
+ // Although unit.Documentation is a slice, it will
+ // have at most one item, the documentation matching
+ // the build context.
+ synopsis := ""
+ var docs string
+ goos := params.GOOS
+ goarch := params.GOARCH
+ if len(unit.Documentation) > 0 {
+ d := unit.Documentation[0]
+ synopsis = d.Synopsis
+ // Return the more precise GOOS/GOARCH.
+ // If the user didn't provide them, use the unit's.
+ // If the user did, assume what they provided is at
+ // least as specific as the unit's, and use it.
+ if goos == "" {
+ goos = d.GOOS
+ }
+ if goarch == "" {
+ goarch = d.GOARCH
+ }
+ if params.Doc != "" {
+ var err error
+ const examples = true // TODO(jba): make examples configurable.
+ docs, err = renderDocumentation(unit, d, params.Doc, examples)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ var licenses []License
+ for _, l := range unit.LicenseContents {
+ licenses = append(licenses, License{
+ Types: l.Metadata.Types,
+ FilePath: l.Metadata.FilePath,
+ Contents: string(l.Contents),
+ })
+ }
+
+ return &Package{
+ Path: unit.Path,
+ ModulePath: unit.ModulePath,
+ ModuleVersion: unit.Version,
+ Synopsis: synopsis,
+ IsStandardLibrary: stdlib.Contains(unit.ModulePath),
+ IsLatest: unit.Version == unit.LatestVersion,
+ GOOS: goos,
+ GOARCH: goarch,
+ Docs: docs,
+ Imports: unit.Imports,
+ Licenses: licenses,
+ }, nil
+}
+
+// renderDocumentation renders the provided unit into the specified format.
+func renderDocumentation(unit *internal.Unit, d *internal.Documentation, format string, examples bool) (string, error) {
+ // d.Source is an encoded AST. Decode it, then use
+ // go/doc (not pkgsite's renderer) to generate the
+ // result.
+ gpkg, err := godoc.DecodePackage(d.Source)
+ if err != nil {
+ return "", fmt.Errorf("%w: %s", derrors.Unknown, err.Error())
+ }
+ innerPath := internal.Suffix(unit.Path, unit.ModulePath)
+ modInfo := &godoc.ModuleInfo{ModulePath: unit.ModulePath, ResolvedVersion: unit.Version}
+ dpkg, err := gpkg.DocPackage(innerPath, modInfo)
+ if err != nil {
+ return "", err
+ }
+ var r renderer
+ var sb strings.Builder
+ switch format {
+ case "text":
+ r = newTextRenderer(gpkg.Fset, &sb)
+ case "md", "markdown":
+ r = newMarkdownRenderer(gpkg.Fset, &sb)
+ case "html":
+ r = newHTMLRenderer(gpkg.Fset, &sb)
+ default:
+ return "", fmt.Errorf("%w: bad doc format: need one of 'text', 'md', 'markdown' or 'html'", derrors.InvalidArgument)
+ }
+ if err := renderDoc(dpkg, r, examples); err != nil {
+ return "", fmt.Errorf("%w: %s", derrors.Unknown, err.Error())
+ }
+ return sb.String(), nil
+}