/
adoc.go
125 lines (104 loc) · 2.83 KB
/
adoc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package lint
import (
"bytes"
"errors"
"fmt"
"os/exec"
"regexp"
"strings"
"github.com/errata-ai/vale/v3/internal/core"
"github.com/errata-ai/vale/v3/internal/nlp"
)
// NOTE: Asciidoctor converts "'" to "’".
//
// See #206.
var adocSanitizer = strings.NewReplacer(
"\u2018", "'",
"\u2019", "'",
"\u201C", "“",
"\u201D", "”",
"’", "'",
"’", "'")
// Convert listing blocks of the form `[source,.+]` to `[source]`
var reSource = regexp.MustCompile(`\[source,.+\]`)
var reComment = regexp.MustCompile(`// .+`)
func (l *Linter) lintADoc(f *core.File) error {
var html string
var err error
exe := core.Which([]string{"asciidoctor"})
if exe == "" {
return core.NewE100("lintAdoc", errors.New("asciidoctor not found"))
}
s, err := l.Transform(f)
if err != nil {
return err
}
s = adocSanitizer.Replace(s)
html, err = callAdoc(f, s, exe, l.Manager.Config.Asciidoctor)
if err != nil {
return core.NewE100(f.Path, err)
}
html = adocSanitizer.Replace(html)
body := reSource.ReplaceAllStringFunc(f.Content, func(m string) string {
offset := 0
if strings.HasSuffix(m, ",]") {
offset = 1
m = strings.Replace(m, ",]", "]", 1)
}
// NOTE: This is required to avoid finding matches in block attributes.
//
// See https://github.com/errata-ai/vale/issues/296.
parts := strings.Split(m, ",")
size := nlp.StrLen(parts[len(parts)-1])
span := strings.Repeat("*", size-2+offset)
return "[source, " + span + "]"
})
body = reComment.ReplaceAllStringFunc(body, func(m string) string {
// NOTE: This is required to avoid finding matches in line comments.
//
// See https://github.com/errata-ai/vale/issues/414.
//
// TODO: Multiple line comments are not handled correctly.
//
// https://docs.asciidoctor.org/asciidoc/latest/comments/
parts := strings.Split(m, "//")
span := strings.Repeat("*", nlp.StrLen(parts[1])-1)
return "// " + span
})
f.Content = body
return l.lintHTMLTokens(f, []byte(html), 0)
}
func callAdoc(_ *core.File, text, exe string, attrs map[string]string) (string, error) {
var out bytes.Buffer
var eut bytes.Buffer
var adocArgs = []string{
"-s",
"-a",
"notitle!",
"-a",
"attribute-missing=drop",
}
adocArgs = append(adocArgs, parseAttributes(attrs)...)
adocArgs = append(adocArgs, []string{"--safe-mode", "secure", "-"}...)
cmd := exec.Command(exe, adocArgs...)
cmd.Stdin = strings.NewReader(text)
cmd.Stdout = &out
cmd.Stderr = &eut
if err := cmd.Run(); err != nil {
return "", errors.New(eut.String())
}
return out.String(), nil
}
func parseAttributes(attrs map[string]string) []string {
var adocArgs []string
for k, v := range attrs {
entry := fmt.Sprintf("%s=%s", k, v)
if v == "YES" {
entry = k
} else if v == "NO" {
entry = k + "!"
}
adocArgs = append(adocArgs, []string{"-a", entry}...)
}
return adocArgs
}