1
0
Fork 0
telegraf/tools/readme_linter/main.go

150 lines
3.3 KiB
Go
Raw Permalink Normal View History

package main
import (
"bufio"
"bytes"
"flag"
"os"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
func main() {
sourceFlag := flag.Bool("source", false, "include location of linter code that failed assertion")
quiet := flag.Bool("quiet", false, "only print failed assertion but no pass information")
flag.Parse()
var err error
pass := true
for _, filename := range flag.Args() {
var filePass bool
filePass, err = checkFile(filename, guessPluginType(filename), *sourceFlag, *quiet)
if err != nil {
panic(err)
}
pass = pass && filePass
}
if !pass {
os.Exit(1)
}
}
type ruleFunc func(*T, ast.Node) error
type rulesMap map[plugin][]ruleFunc
var rules rulesMap
func init() {
rules = make(rulesMap)
// Rules for all plugin types
all := []ruleFunc{
firstSection,
metadata,
configSection,
relativeTelegrafLinks,
noLongLinesInParagraphs(80),
}
for i := pluginInput; i <= pluginParser; i++ {
rules[i] = all
}
// Rules for input plugins
rules[pluginInput] = append(rules[pluginInput], []ruleFunc{
requiredSectionsClose([]string{
"Example Output",
"Metrics",
"Global configuration options",
}),
}...)
// Rules for output plugins
rules[pluginOutput] = append(rules[pluginOutput], []ruleFunc{
requiredSectionsClose([]string{
"Global configuration options",
}),
}...)
// Rules for processor pluings
rules[pluginProcessor] = append(rules[pluginProcessor], []ruleFunc{
requiredSectionsClose([]string{
"Global configuration options",
}),
}...)
// Rules for aggregator pluings
rules[pluginAggregator] = append(rules[pluginAggregator], []ruleFunc{
requiredSectionsClose([]string{
"Global configuration options",
}),
}...)
}
func checkFile(filename string, pluginType plugin, sourceFlag, quiet bool) (bool, error) {
md, err := os.ReadFile(filename)
if err != nil {
return false, err
}
// Goldmark returns locations as offsets. We want line
// numbers. Find the newlines in the file so we can translate
// later.
scanner := bufio.NewScanner(bytes.NewReader(md))
scanner.Split(bufio.ScanRunes)
offset := 0
newlineOffsets := make([]int, 0)
for scanner.Scan() {
if scanner.Text() == "\n" {
newlineOffsets = append(newlineOffsets, offset)
}
offset++
}
p := goldmark.DefaultParser()
// We need goldmark to parse tables, otherwise they show up as
// paragraphs. Since tables often have long lines and we check for long
// lines in paragraphs, without table parsing there are false positive long
// lines in tables.
//
// The tableParagraphTransformer is an extension and not part of the default
// parser so we add it. There may be an easier way to do it, but this works:
p.AddOptions(
parser.WithParagraphTransformers(
util.Prioritized(extension.NewTableParagraphTransformer(), 99),
),
)
r := text.NewReader(md)
root := p.Parse(r)
rules := rules[pluginType]
tester := T{
filename: filename,
markdown: md,
newlineOffsets: newlineOffsets,
sourceFlag: sourceFlag,
pluginType: pluginType,
}
for _, rule := range rules {
err = rule(&tester, root)
if err != nil {
return false, err
}
}
if !quiet {
tester.printPassFail()
}
return tester.pass(), nil
}