-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
check: Verify sidebar navigation for missing links and mismatched lin…
- Loading branch information
Showing
14 changed files
with
606 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package sidenavigation | ||
|
||
import ( | ||
"golang.org/x/net/html" | ||
) | ||
|
||
type Category struct { | ||
Name string | ||
Node *html.Node | ||
|
||
DataSourceLinks []*Link | ||
ExternalLinks []*Link | ||
GuideLinks []*Link | ||
ResourceLinks []*Link | ||
} | ||
|
||
func NewCategory(name string, listNode *html.Node) *Category { | ||
category := &Category{ | ||
DataSourceLinks: make([]*Link, 0), | ||
ExternalLinks: make([]*Link, 0), | ||
GuideLinks: make([]*Link, 0), | ||
Name: name, | ||
Node: listNode, | ||
ResourceLinks: make([]*Link, 0), | ||
} | ||
|
||
category.processList() | ||
|
||
return category | ||
} | ||
|
||
func (category *Category) processList() { | ||
for child := category.Node.FirstChild; child != nil; child = child.NextSibling { | ||
if isListItem(child) { | ||
category.processListItem(child) | ||
} | ||
} | ||
} | ||
|
||
func (category *Category) processListItem(node *html.Node) { | ||
linkNode := childLinkNode(node) | ||
|
||
if linkNode == nil { | ||
return | ||
} | ||
|
||
link := NewLink(linkNode) | ||
listNode := childUnorderedListNode(node) | ||
|
||
if listNode == nil { | ||
switch link.Type { | ||
case LinkTypeDataSource: | ||
category.DataSourceLinks = append(category.DataSourceLinks, link) | ||
case LinkTypeExternal: | ||
category.ExternalLinks = append(category.ExternalLinks, link) | ||
case LinkTypeGuide: | ||
category.GuideLinks = append(category.GuideLinks, link) | ||
case LinkTypeResource: | ||
category.ResourceLinks = append(category.ResourceLinks, link) | ||
} | ||
|
||
return | ||
} | ||
|
||
// Categories can contain one single subcategory (e.g. Service Name > Resources) | ||
subCategory := NewCategory(link.Text, listNode) | ||
|
||
category.DataSourceLinks = append(category.DataSourceLinks, subCategory.DataSourceLinks...) | ||
category.ExternalLinks = append(category.ExternalLinks, subCategory.ExternalLinks...) | ||
category.GuideLinks = append(category.GuideLinks, subCategory.GuideLinks...) | ||
category.ResourceLinks = append(category.ResourceLinks, subCategory.ResourceLinks...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package sidenavigation | ||
|
||
import ( | ||
"golang.org/x/net/html" | ||
) | ||
|
||
func childLinkNode(node *html.Node) *html.Node { | ||
for child := node.FirstChild; child != nil; child = child.NextSibling { | ||
if isLink(child) { | ||
return child | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func childText(node *html.Node) string { | ||
if node.Type == html.TextNode { | ||
return node.Data | ||
} | ||
|
||
for child := node.FirstChild; child != nil; child = child.NextSibling { | ||
return childText(child) | ||
} | ||
|
||
return "" | ||
} | ||
|
||
func childUnorderedListNode(node *html.Node) *html.Node { | ||
for child := node.FirstChild; child != nil; child = child.NextSibling { | ||
if isUnorderedList(child) { | ||
return child | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func isLink(node *html.Node) bool { | ||
if node.Type != html.ElementNode { | ||
return false | ||
} | ||
|
||
return node.Data == "a" | ||
} | ||
|
||
func isListItem(node *html.Node) bool { | ||
if node.Type != html.ElementNode { | ||
return false | ||
} | ||
|
||
return node.Data == "li" | ||
} | ||
|
||
func isUnorderedList(node *html.Node) bool { | ||
if node.Type != html.ElementNode { | ||
return false | ||
} | ||
|
||
return node.Data == "ul" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package sidenavigation | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"golang.org/x/net/html" | ||
) | ||
|
||
type Link struct { | ||
Text string | ||
Type LinkType | ||
Url string | ||
} | ||
|
||
type LinkType int | ||
|
||
const ( | ||
LinkTypeAnchor LinkType = iota | ||
LinkTypeExternal | ||
LinkTypeDataSource | ||
LinkTypeGuide | ||
LinkTypeResource | ||
) | ||
|
||
func (typ LinkType) String() string { | ||
return [...]string{"Anchor", "External", "Data Source", "Guide", "Resource"}[typ] | ||
} | ||
|
||
func NewLink(node *html.Node) *Link { | ||
link := &Link{ | ||
Text: childText(node), | ||
} | ||
|
||
for _, attr := range node.Attr { | ||
if attr.Key == "href" { | ||
link.Url = attr.Val | ||
|
||
if strings.HasPrefix(link.Url, "#") { | ||
link.Type = LinkTypeAnchor | ||
} else if strings.Contains(link.Url, "/d/") { | ||
link.Type = LinkTypeDataSource | ||
} else if strings.Contains(link.Url, "/guides/") { | ||
link.Type = LinkTypeGuide | ||
} else if strings.Contains(link.Url, "/r/") { | ||
link.Type = LinkTypeResource | ||
} else { | ||
link.Type = LinkTypeExternal | ||
} | ||
|
||
break | ||
} | ||
} | ||
|
||
return link | ||
} | ||
|
||
func (link *Link) Validate(expectedProviderName string) error { | ||
if link.Type != LinkTypeDataSource && link.Type != LinkTypeResource { | ||
return nil | ||
} | ||
|
||
var linkTypeUrlPart string | ||
|
||
switch link.Type { | ||
case LinkTypeDataSource: | ||
linkTypeUrlPart = "d" | ||
case LinkTypeResource: | ||
linkTypeUrlPart = "r" | ||
} | ||
|
||
if !strings.Contains(link.Url, "/") { | ||
return fmt.Errorf("link URL (%s) is missing / separators, should be in form: /docs/providers/PROVIDER/%s/NAME.html", link.Url, linkTypeUrlPart) | ||
} | ||
|
||
urlParts := strings.Split(link.Url, "/") | ||
|
||
if len(urlParts) < 6 { | ||
return fmt.Errorf("link URL (%s) is missing path parts, e.g. /docs/providers/PROVIDER/%s/NAME.html", link.Url, linkTypeUrlPart) | ||
} else if len(urlParts) > 6 { | ||
return fmt.Errorf("link URL (%s) has too many path parts, should be in form: /docs/providers/PROVIDER/%s/NAME.html", link.Url, linkTypeUrlPart) | ||
} | ||
|
||
urlProviderName := urlParts[3] | ||
|
||
if expectedProviderName != "" && urlProviderName != expectedProviderName { | ||
return fmt.Errorf("link URL (%s) has incorrect provider name (%s), expected: %s", link.Url, urlProviderName, expectedProviderName) | ||
} | ||
|
||
urlResourceName := urlParts[len(urlParts)-1] | ||
urlResourceName = strings.TrimSuffix(urlResourceName, ".html") | ||
|
||
if expectedProviderName != "" { | ||
expectedText := fmt.Sprintf("%s_%s", expectedProviderName, urlResourceName) | ||
if link.Text != expectedText { | ||
return fmt.Errorf("link URL (%s) has incorrect text (%s), expected: %s", link.Url, link.Text, expectedText) | ||
} | ||
} else { | ||
expectedSuffix := fmt.Sprintf("_%s", urlResourceName) | ||
if !strings.HasSuffix(link.Text, expectedSuffix) { | ||
return fmt.Errorf("link URL (%s) has incorrect text (%s), expected: PROVIDER%s", link.Url, link.Text, expectedSuffix) | ||
} | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.