github.com/argots/stencil@v0.0.2/pkg/stencil/markdown.go (about)

     1  package stencil
     2  
     3  import (
     4  	"bufio"
     5  	"regexp"
     6  	"strings"
     7  )
     8  
     9  // Markdown implements the markdown functionality.
    10  type Markdown struct {
    11  	*Stencil
    12  }
    13  
    14  // CopyMarkdownSnippets first treats the url as a markdown stripping out
    15  // everything but code fences with names matching the provided regex.
    16  // The name of the code fence is the first word after the triple backquote.
    17  //
    18  // Note that standard go templates are still executed on top of this
    19  // so the embedded code can use any stencil function.
    20  func (m *Markdown) CopyMarkdownSnippets(key, localPath, url, regex string) error {
    21  	m.Printf("copying %s (snippets %s) to %s, key (%s)\n", url, regex, localPath, key)
    22  
    23  	key = key + "(regex: " + regex + ")"
    24  	m.Objects.addFile(key, localPath, url)
    25  
    26  	data, err := m.executeFilter(url, func(md string) (string, error) {
    27  		return m.FilterMarkdown(md, regex)
    28  	})
    29  	if err != nil {
    30  		return m.Errorf("Error reading %s %v\n", url, err)
    31  	}
    32  
    33  	return m.Write(localPath, []byte(data), 0666)
    34  }
    35  
    36  func (m *Markdown) FilterMarkdown(data, regex string) (string, error) {
    37  	result := ""
    38  	if regex == "" {
    39  		regex = ".*"
    40  	}
    41  
    42  	re, err := regexp.Compile(regex)
    43  	if err != nil {
    44  		return "", err
    45  	}
    46  
    47  	m.forEachCodeFence(data, func(name, code string) {
    48  		if re.MatchString(name) {
    49  			result += code
    50  		}
    51  	})
    52  
    53  	return result, nil
    54  }
    55  
    56  func (m *Markdown) forEachCodeFence(md string, visit func(name, code string)) {
    57  	re := regexp.MustCompile("(?msU)^```(.*)^```$")
    58  	for _, fence := range re.FindAllString(md, -1) {
    59  		fence = strings.Trim(fence, "`")
    60  		scanner := bufio.NewScanner(strings.NewReader(fence))
    61  		scanner.Scan()
    62  		name := scanner.Text()
    63  		visit(strings.TrimSpace(name), fence[len(name)+1:])
    64  	}
    65  }