blob: b3cb983ed08eac768edc35d1bf38b4ece40bb2c4 [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 returns a section of the dochtml, based on the template from
// internal/fetch/dochtml.
//
// This package is intended to aid frontend development for the unit page,
// and is a temporary solution for prototyping the new designs. It is not
// intended for use in production.
package godoc
import (
"fmt"
"go/ast"
"html"
"regexp"
"github.com/google/safehtml"
"github.com/google/safehtml/uncheckedconversions"
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/fetch/dochtml"
)
// SectionType is a section of the docHTML.
type SectionType uint32
const (
// SidenavSection is the section of the docHTML starting at
// dochtml.IdentifierSidenav and ending at the last </nav> tag in the
// docHTML. This is inclusive of SideNavMobile.
SidenavSection SectionType = iota
// SidenavMobileSection is the section of the docHTML starting at
// dochtml.IdentifierMobileNavStart and ending at the last </nav> tag in the
// docHTML.
SidenavMobileSection
// BodySection is the section of the docHTML starting at
// dochtml.IdentifierBody and ending at the last </div> tag in the
// docHTML.
BodySection
)
// Parse return the section of docHTML specified by section. It is expected that
// docHTML was generated using the template in internal/fetch/dochtml.
func Parse(docHTML safehtml.HTML, section SectionType) (_ safehtml.HTML, err error) {
defer derrors.Wrap(&err, "Parse(docHTML, %q)", section)
switch section {
case SidenavSection:
return findHTML(docHTML, dochtml.IdentifierSidenavStart)
case SidenavMobileSection:
return findHTML(docHTML, dochtml.IdentifierSidenavMobileStart)
case BodySection:
return findHTML(docHTML, dochtml.IdentifierBodyStart)
default:
return safehtml.HTML{}, derrors.NotFound
}
}
func findHTML(docHTML safehtml.HTML, identifier string) (_ safehtml.HTML, err error) {
defer derrors.Wrap(&err, "findHTML(%q)", identifier)
var closeTag string
switch identifier {
case dochtml.IdentifierBodyStart:
closeTag = dochtml.IdentifierBodyEnd
default:
closeTag = dochtml.IdentifierSidenavEnd
}
// The regex is greedy, so it will capture the last matching closeTag in
// the docHTML.
//
// For the sidenav, this will capture both the mobile and main
// sidenav sections. For the body, this will capture all content up the
// last </div> tag in the HTML.
reg := fmt.Sprintf("(%s(.|\n)*%s)", identifier, closeTag)
b := regexp.MustCompile(reg).FindString(html.UnescapeString(docHTML.String()))
return uncheckedconversions.HTMLFromStringKnownToSatisfyTypeContract(string(b)), nil
}
// 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
}
f.Body = nil
}
decls = append(decls, d)
}
pf.Comments = nil
pf.Decls = decls
}