github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/test_helpers/docs.go (about)

     1  package test_helpers
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"regexp"
     7  	"strings"
     8  )
     9  
    10  var punctuationRE = regexp.MustCompile(`[^\w\-\s]`)
    11  var linkRE = regexp.MustCompile(`\]\(([\w:/#\-\.]*)\)`)
    12  
    13  type Doc struct {
    14  	Name string
    15  	URLs []string
    16  	path string
    17  }
    18  
    19  func (doc Doc) Path(root string) string {
    20  	return filepath.Join(root, doc.path)
    21  }
    22  
    23  type Docs []Doc
    24  
    25  func (d Docs) DocWithName(name string) Doc {
    26  	for _, doc := range d {
    27  		if doc.Name == name {
    28  			return doc
    29  		}
    30  	}
    31  	return Doc{}
    32  }
    33  
    34  func (d Docs) DocWithURL(url string) Doc {
    35  	for _, doc := range d {
    36  		for _, u := range doc.URLs {
    37  			if u == url {
    38  				return doc
    39  			}
    40  		}
    41  	}
    42  	return Doc{}
    43  }
    44  
    45  var DOCS = Docs{
    46  	{"index.md", []string{"https://onsi.github.io/ginkgo/"}, "docs/index.md"},
    47  	{"MIGRATING_TO_V2.md", []string{"https://onsi.github.io/ginkgo/MIGRATING_TO_V2"}, "docs/MIGRATING_TO_V2.md"},
    48  	{"README.md", []string{"https://github.com/onsi/ginkgo", "https://github.com/onsi/ginkgo/blob/master/README.md"}, "README.md"},
    49  }
    50  
    51  type Anchors struct {
    52  	Docs       Docs
    53  	DocAnchors map[string][]string
    54  }
    55  
    56  func (a Anchors) IsResolvable(docName string, link string) bool {
    57  	var anchorSet []string
    58  	var expectedAnchor string
    59  	if strings.HasPrefix(link, "#") {
    60  		anchorSet = a.DocAnchors[docName]
    61  		expectedAnchor = strings.TrimPrefix(link, "#")
    62  	} else {
    63  		components := strings.Split(link, "#")
    64  		doc := a.Docs.DocWithURL(components[0])
    65  		if doc.Name == "" {
    66  			//allow external links
    67  			return true
    68  		}
    69  		if len(components) == 1 {
    70  			//allow links to the doc with no anchor
    71  			return true
    72  		}
    73  		expectedAnchor = components[1]
    74  		anchorSet = a.DocAnchors[doc.Name]
    75  	}
    76  
    77  	for _, anchor := range anchorSet {
    78  		if anchor == expectedAnchor {
    79  			return true
    80  		}
    81  	}
    82  
    83  	return false
    84  }
    85  
    86  func LoadAnchors(docs Docs, rootPath string) (Anchors, error) {
    87  	out := Anchors{
    88  		Docs:       docs,
    89  		DocAnchors: map[string][]string{},
    90  	}
    91  	for _, doc := range docs {
    92  		anchors, err := loadMarkdownHeadingAnchors(doc.Path(rootPath))
    93  		if err != nil {
    94  			return Anchors{}, err
    95  		}
    96  		out.DocAnchors[doc.Name] = anchors
    97  	}
    98  	return out, nil
    99  }
   100  
   101  func loadMarkdownHeadingAnchors(filename string) ([]string, error) {
   102  	headings, err := LoadMarkdownHeadings(filename)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	var anchors []string
   108  	for _, heading := range headings {
   109  		heading = punctuationRE.ReplaceAllString(heading, "")
   110  		heading = strings.ToLower(heading)
   111  		heading = strings.ReplaceAll(heading, " ", "-")
   112  		anchors = append(anchors, heading)
   113  	}
   114  
   115  	return anchors, nil
   116  }
   117  
   118  func LoadMarkdownHeadings(filename string) ([]string, error) {
   119  	b, err := os.ReadFile(filename)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	headings := []string{}
   124  	lines := strings.Split(string(b), "\n")
   125  	for _, line := range lines {
   126  		line = strings.TrimLeft(line, " ")
   127  		line = strings.TrimRight(line, " ")
   128  		if !strings.HasPrefix(line, "#") {
   129  			continue
   130  		}
   131  		line = strings.TrimLeft(line, "# ")
   132  		headings = append(headings, line)
   133  	}
   134  	return headings, nil
   135  }
   136  
   137  func LoadMarkdownLinks(filename string) ([]string, error) {
   138  	b, err := os.ReadFile(filename)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	links := []string{}
   143  	lines := strings.Split(string(b), "\n")
   144  
   145  	for _, line := range lines {
   146  		matches := linkRE.FindAllStringSubmatch(line, -1)
   147  		for _, match := range matches {
   148  			if match[1] != "" {
   149  				links = append(links, match[1])
   150  			}
   151  		}
   152  	}
   153  
   154  	return links, nil
   155  }