blob: 0925d11b7035de11ab53bcba994149e689bf3e19 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package godoc is for rendering Go documentation.
package godoc
import (
"go/ast"
"go/token"
"strings"
"golang.org/x/pkgsite/internal/godoc/dochtml"
)
var ErrTooLarge = dochtml.ErrTooLarge
type ModuleInfo = dochtml.ModuleInfo
// A Package contains package-level information needed to render Go documentation.
type Package struct {
Fset *token.FileSet
encPackage
renderCalled bool
}
// encPackage holds the fields of Package that can be directly encoded.
//
// If you add any fields, run go generate on this package.
//
// If you remove a field, you will have to hand-edit encode_ast.go
// just to make this package compile before running go generate.
// Do not remove the field name from the "Fields of" comment, however,
// or existing encoded data will decode incorrectly.
//
// If you rename a field, the field's values in existing encoded
// data will be lost. Renaming a field is like deleting the old field
// and adding a new one.
type encPackage struct { // fields that can be directly encoded
Files []*File
ModulePackagePaths map[string]bool
}
// A File contains everything needed about a source file to render documentation.
type File struct {
Name string // full file pathname relative to zip content directory
AST *ast.File
}
// NewPackage returns a new Package with the given fset and set of module package paths.
func NewPackage(fset *token.FileSet, modPaths map[string]bool) *Package {
return &Package{
Fset: fset,
encPackage: encPackage{
ModulePackagePaths: modPaths,
},
}
}
// AddFile adds a file to the Package. After it returns, the contents of the ast.File
// are unsuitable for anything other than the methods of this package.
func (p *Package) AddFile(f *ast.File, removeNodes bool) {
filename := p.Fset.Position(f.Package).Filename
// Don't trim anything from a test file or one in a XXX_test package; it
// may be part of a playable example.
if removeNodes && !strings.HasSuffix(filename, "_test.go") && !strings.HasSuffix(f.Name.Name, "_test") {
removeUnusedASTNodes(f)
}
p.Files = append(p.Files, &File{
Name: filename,
AST: f,
})
}
// removeUnusedASTNodes removes parts of the AST not needed for documentation.
// It doesn't remove unexported consts, vars or types, although it probably could.
func removeUnusedASTNodes(pf *ast.File) {
var decls []ast.Decl
for _, d := range pf.Decls {
if f, ok := d.(*ast.FuncDecl); ok {
// Remove all unexported functions and function bodies.
if f.Name == nil || !ast.IsExported(f.Name.Name) {
continue
}
// Remove the function body, unless it's an example.
// The doc contains example bodies.
if !strings.HasPrefix(f.Name.Name, "Example") {
f.Body = nil
}
}
decls = append(decls, d)
}
// Don't remove pf.Comments; they may contain Notes.
pf.Decls = decls
}