зеркало из https://github.com/golang/pkgsite.git
218 строки
7.0 KiB
Go
218 строки
7.0 KiB
Go
// Copyright 2019 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 pagecheck implements HTML checkers for discovery site pages.
|
|
// It uses the general-purpose checkers in internal/testing/htmlcheck to define
|
|
// site-specific checkers.
|
|
package pagecheck
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"regexp"
|
|
|
|
"golang.org/x/pkgsite/internal/stdlib"
|
|
"golang.org/x/pkgsite/internal/testing/htmlcheck"
|
|
)
|
|
|
|
// Page describes a discovery site web page for a package, module or directory.
|
|
type Page struct {
|
|
ModulePath string
|
|
Suffix string // package or directory path after module path; empty for a module
|
|
Version string
|
|
FormattedVersion string
|
|
Title string
|
|
LicenseType string
|
|
LicenseFilePath string
|
|
IsLatest bool // is this the latest version of this module?
|
|
LatestLink string // href of "Go to latest" link
|
|
PackageURLFormat string // the relative package URL, with one %s for "@version"; also used for dirs
|
|
ModuleURL string // the relative module URL
|
|
}
|
|
|
|
// Overview describes the contents of the overview tab.
|
|
type Overview struct {
|
|
ModuleLink string // relative link to module page
|
|
ModuleLinkText string
|
|
RepoURL string
|
|
PackageURL string
|
|
ReadmeContent string
|
|
ReadmeSource string
|
|
}
|
|
|
|
var (
|
|
in = htmlcheck.In
|
|
inAll = htmlcheck.InAll
|
|
text = htmlcheck.HasText
|
|
exactText = htmlcheck.HasExactText
|
|
exactTextCollapsed = htmlcheck.HasExactTextCollapsed
|
|
attr = htmlcheck.HasAttr
|
|
href = htmlcheck.HasHref
|
|
)
|
|
|
|
// PackageHeader checks a details page header for a package.
|
|
func PackageHeader(p *Page, versionedURL bool) htmlcheck.Checker {
|
|
fv := p.FormattedVersion
|
|
if fv == "" {
|
|
fv = p.Version
|
|
}
|
|
curBreadcrumb := path.Base(p.Suffix)
|
|
if p.Suffix == "" {
|
|
curBreadcrumb = p.ModulePath
|
|
}
|
|
return in("",
|
|
in("span.DetailsHeader-breadcrumbCurrent", exactText(curBreadcrumb)),
|
|
in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
|
|
in("div.DetailsHeader-version", exactText(fv)),
|
|
versionBadge(p),
|
|
licenseInfo(p, packageURLPath(p, versionedURL)),
|
|
packageTabLinks(p, versionedURL),
|
|
moduleInHeader(p, versionedURL))
|
|
}
|
|
|
|
// ModuleHeader checks a details page header for a module.
|
|
func ModuleHeader(p *Page, versionedURL bool) htmlcheck.Checker {
|
|
fv := p.FormattedVersion
|
|
if fv == "" {
|
|
fv = p.Version
|
|
}
|
|
curBreadcrumb := p.ModulePath
|
|
if p.ModulePath == stdlib.ModulePath {
|
|
curBreadcrumb = "Standard library"
|
|
}
|
|
return in("",
|
|
in("span.DetailsHeader-breadcrumbCurrent", exactText(curBreadcrumb)),
|
|
in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
|
|
in("div.DetailsHeader-version", exactText(fv)),
|
|
versionBadge(p),
|
|
licenseInfo(p, moduleURLPath(p, versionedURL)),
|
|
moduleTabLinks(p, versionedURL))
|
|
}
|
|
|
|
// DirectoryHeader checks a details page header for a directory.
|
|
func DirectoryHeader(p *Page, versionedURL bool) htmlcheck.Checker {
|
|
fv := p.FormattedVersion
|
|
if fv == "" {
|
|
fv = p.Version
|
|
}
|
|
return in("",
|
|
in("span.DetailsHeader-breadcrumbCurrent", exactText(path.Base(p.Suffix))),
|
|
in("h1.DetailsHeader-title", exactTextCollapsed(p.Title)),
|
|
in("div.DetailsHeader-version", exactText(fv)),
|
|
// directory pages don't show a header badge
|
|
in("div.DetailsHeader-badge", in(".DetailsHeader-badge--unknown")),
|
|
licenseInfo(p, packageURLPath(p, versionedURL)),
|
|
// directory module links are always versioned (see b/144217401)
|
|
moduleInHeader(p, true))
|
|
}
|
|
|
|
// SubdirectoriesDetails checks the detail section of a subdirectories tab.
|
|
// If firstHref isn't empty, it and firstText should exactly match
|
|
// href and text of the first link in the Directories table.
|
|
func SubdirectoriesDetails(firstHref, firstText string) htmlcheck.Checker {
|
|
var link htmlcheck.Checker
|
|
if firstHref != "" {
|
|
link = in("table.Directories a", href(firstHref), exactText(firstText))
|
|
}
|
|
return in("",
|
|
in("th:nth-child(1)", text("^Path$")),
|
|
in("th:nth-child(2)", text("^Synopsis$")),
|
|
link)
|
|
}
|
|
|
|
// LicenseDetails checks the details section of a license tab.
|
|
func LicenseDetails(ltype, bodySubstring, source string) htmlcheck.Checker {
|
|
return in("",
|
|
in(".License",
|
|
text(regexp.QuoteMeta(ltype)),
|
|
text("This is not legal advice"),
|
|
in("a",
|
|
href("/license-policy"),
|
|
exactText("Read disclaimer.")),
|
|
in(".License-contents",
|
|
text(regexp.QuoteMeta(bodySubstring)))),
|
|
in(".License-source",
|
|
exactText("Source: "+source)))
|
|
}
|
|
|
|
// OverviewDetails checks the details section of an overview tab.
|
|
func OverviewDetails(ov *Overview) htmlcheck.Checker {
|
|
var pkg htmlcheck.Checker
|
|
if ov.PackageURL != "" {
|
|
pkg = in(".Overview-sourceCodeLink a:nth-of-type(2)",
|
|
href(ov.PackageURL),
|
|
exactText(ov.PackageURL))
|
|
}
|
|
return in("",
|
|
in("div.Overview-module > a",
|
|
href(ov.ModuleLink),
|
|
exactText(ov.ModuleLinkText)),
|
|
in(".Overview-sourceCodeLink a:nth-of-type(1)",
|
|
href(ov.RepoURL),
|
|
exactText(ov.RepoURL)),
|
|
pkg,
|
|
in(".Overview-readmeContent", text(ov.ReadmeContent)),
|
|
in(".Overview-readmeSource", exactText("Source: "+ov.ReadmeSource)))
|
|
}
|
|
|
|
// versionBadge checks the latest-version badge on a header.
|
|
func versionBadge(p *Page) htmlcheck.Checker {
|
|
class := "DetailsHeader-badge"
|
|
if p.IsLatest {
|
|
class += "--latest"
|
|
} else {
|
|
class += "--goToLatest"
|
|
}
|
|
return in("div.DetailsHeader-badge",
|
|
attr("class", `\b`+regexp.QuoteMeta(class)+`\b`), // the badge has this class too
|
|
in("a", href(p.LatestLink), exactText("Go to latest")))
|
|
}
|
|
|
|
// licenseInfo checks the license part of the info label in the header.
|
|
func licenseInfo(p *Page, urlPath string) htmlcheck.Checker {
|
|
if p.LicenseType == "" {
|
|
return in("[data-test-id=DetailsHeader-infoLabelLicense]", text("None detected"))
|
|
}
|
|
return in("[data-test-id=DetailsHeader-infoLabelLicense] a",
|
|
href(fmt.Sprintf("%s?tab=licenses#lic-0", urlPath)),
|
|
exactText(p.LicenseType))
|
|
}
|
|
|
|
// moduleInHeader checks the module part of the info label in the header.
|
|
func moduleInHeader(p *Page, versionedURL bool) htmlcheck.Checker {
|
|
modURL := moduleURLPath(p, versionedURL)
|
|
text := p.ModulePath
|
|
if p.ModulePath == stdlib.ModulePath {
|
|
text = "Standard library"
|
|
}
|
|
return in("a[data-test-id=DetailsHeader-infoLabelModule]", href(modURL), exactText(text))
|
|
}
|
|
|
|
// Check that all the navigation tabs link to the same package at the same version.
|
|
func packageTabLinks(p *Page, versionedURL bool) htmlcheck.Checker {
|
|
return inAll("a.DetailsNav-link[href]",
|
|
attr("href", "^"+regexp.QuoteMeta(packageURLPath(p, versionedURL))))
|
|
}
|
|
|
|
// Check that all the navigation tabs link to the same module at the same version.
|
|
func moduleTabLinks(p *Page, versionedURL bool) htmlcheck.Checker {
|
|
return inAll("a.DetailsNav-link[href]",
|
|
attr("href", "^"+regexp.QuoteMeta(moduleURLPath(p, versionedURL))))
|
|
}
|
|
|
|
func packageURLPath(p *Page, versioned bool) string {
|
|
v := ""
|
|
if versioned {
|
|
v = "@" + p.Version
|
|
}
|
|
return fmt.Sprintf(p.PackageURLFormat, v)
|
|
}
|
|
|
|
func moduleURLPath(p *Page, versioned bool) string {
|
|
if versioned {
|
|
return p.ModuleURL + "@" + p.Version
|
|
}
|
|
return p.ModuleURL
|
|
}
|