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

import (
	
	
	
	
	
	

	
	
	
	
	
	
	
	
)

const (
	megabyte             = 1000 * 1000
	maxImportsPerPackage = 2000
Exported for tests.
	DocTooLargeReplacement = `<p>Documentation is too large to display.</p>`
)
MaxDocumentationHTML is a limit on the rendered documentation HTML size. The current limit of is based on the largest packages that pkg.go.dev has encountered. See https://golang.org/issue/40576. It is a variable for testing.
DocInfo returns information extracted from the package's documentation. This destroys p's AST; do not call any methods of p after it returns.
func ( *Package) ( context.Context,  string,  *source.Info,  *ModuleInfo) (
This is mostly copied from internal/fetch/fetch.go.
	defer derrors.Wrap(&, "godoc.Package.DocInfo(%q, %q, %q)", .ModulePath, .ResolvedVersion, )

	.renderCalled = true
	,  := .docPackage(, )
	if  != nil {
		return "", nil, nil, 
	}

	,  = dochtml.GetSymbols(, .Fset)
	if  != nil {
		return "", nil, nil, 
	}
	return doc.Synopsis(.Doc), .Imports, , nil
}
docPackage computes and returns a doc.Package.
func ( *Package) ( string,  *ModuleInfo) ( *doc.Package,  error) {
	defer derrors.Wrap(&, "docPackage(%q, %q, %q)", , .ModulePath, .ResolvedVersion)
	 := path.Join(.ModulePath, )
	if .ModulePath == stdlib.ModulePath {
		 = 
	}
	if .ModulePackages == nil {
		.ModulePackages = .ModulePackagePaths
	}
The "builtin" package in the standard library is a special case. We want to show documentation for all globals (not just exported ones), and avoid association of consts, vars, and factory functions with types since it's not helpful (see golang.org/issue/6645).
	var ,  bool
	if .ModulePath == stdlib.ModulePath &&  == "builtin" {
		 = true
		 = true
	}
Compute package documentation.
	var  doc.Mode
	if  {
		 |= doc.AllDecls
	}
	var  []*ast.File
	for ,  := range .Files {
		 = append(, .AST)
	}
	,  := doc.NewFromFiles(.Fset, , , )
	if  != nil {
		return nil, fmt.Errorf("doc.NewFromFiles: %v", )
	}

	if .ImportPath !=  {
		panic(fmt.Errorf("internal error: *doc.Package has an unexpected import path (%q != %q)", .ImportPath, ))
	}
	if  {
		for ,  := range .Types {
			.Consts, .Consts = append(.Consts, .Consts...), nil
			.Vars, .Vars = append(.Vars, .Vars...), nil
			.Funcs, .Funcs = append(.Funcs, .Funcs...), nil
		}
		sort.Slice(.Funcs, func(,  int) bool { return .Funcs[].Name < .Funcs[].Name })
	}
Process package imports.
	if len(.Imports) > maxImportsPerPackage {
		return nil, fmt.Errorf("%d imports found package %q; exceeds limit %d for maxImportsPerPackage", len(.Imports), , maxImportsPerPackage)
	}
	return , nil
}
renderOptions returns a RenderOptions for p.
func ( *Package) ( string,  *source.Info,  *ModuleInfo,
	 map[string]string) dochtml.RenderOptions {
	 := func( ast.Node) string {
		if  == nil {
			return ""
		}
		 := .Fset.Position(.Pos())
		if .Line == 0 { // invalid Position
			return ""
		}
		return .LineURL(path.Join(, .Filename), .Line)
	}
	 := func( string) string {
		if  == nil {
			return ""
		}
		return .FileURL(path.Join(, ))
	}

	return dochtml.RenderOptions{
		FileLinkFunc:     ,
		SourceLinkFunc:   ,
		ModInfo:          ,
		SinceVersionFunc: sinceVersionFunc(.ModulePath, ),
		Limit:            int64(MaxDocumentationHTML),
	}
}
sinceVersionFunc returns a func that reports the version when the symbol with name was first introduced. nameToVersion is a map of symbol name to the first version that symbol name was seen in the package. If the version when the symbol name was first introduced is the earliest version in nameToVersion, an empty string is returned. This is because we don't want to display that information on the main page to reduce clutter.
func ( string,  map[string]string) func( string) string {
	if  == nil {
		return func(string) string {
			return ""
		}
	}

	var  string
	for ,  := range  {
		if  == "" {
			 = 
			continue
		}
		if semver.Compare(, ) < 0 {
			 = 
		}
	}

	return func( string) string {
		if  == nil {
			return ""
		}
		 := []
		if  ==  {
			return ""
		}
This should never return an error.
			,  := stdlib.TagForVersion()
			return 
		}
		return 
	}
}
Render renders the documentation for the package. Rendering destroys p's AST; do not call any methods of p after it returns.
func ( *Package) ( context.Context,  string,
	 *source.Info,  *ModuleInfo,  map[string]string) ( *dochtml.Parts,  error) {
	.renderCalled = true

	,  := .docPackage(, )
	if  != nil {
		return nil, 
	}

	 := .renderOptions(, , , )
	,  := dochtml.Render(, .Fset, , )
	if errors.Is(, ErrTooLarge) {
		return &dochtml.Parts{Body: template.MustParseAndExecuteToHTML(DocTooLargeReplacement)}, nil
	}
	if  != nil {
		return nil, fmt.Errorf("dochtml.Render: %v", )
	}
	return , nil
}
RenderFromUnit is a convenience function that first decodes the source in the unit, which must exist, and then calls Render.
func ( context.Context,  *internal.Unit) ( *dochtml.Parts,  error) {
	,  := DecodePackage(.Documentation[0].Source)
	if  != nil {
		return nil, 
	}
	 := &ModuleInfo{
		ModulePath:      .ModulePath,
		ResolvedVersion: .Version,
		ModulePackages:  nil, // will be provided by docPkg
	}
	var  string
	if .ModulePath == stdlib.ModulePath {
		 = .Path
	} else if .Path != .ModulePath {
		 = .Path[len(.ModulePath)+1:]
	}
	return .Render(, , .SourceInfo, , nil)