repochecker/grammalecte: Check resolution.md

This commit is contained in:
nemunaire 2022-11-24 13:10:19 +01:00
parent 1f3f0fd55b
commit 80422daffb
4 changed files with 232 additions and 19 deletions

View File

@ -286,10 +286,19 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: The file is empty!"), theme))
} else if e.Resolution, err = GetFileContent(i, writeup); err != nil {
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: %w", err), theme))
} else if e.Resolution, err = ProcessMarkdown(i, e.Resolution, epath); err != nil {
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: error during markdown processing: %w", err), theme))
} else {
resolutionFound = true
// Call checks hooks
for _, h := range hooks.mdTextHooks {
for _, err := range h(e.Resolution, exceptions.GetFileExceptions("resolution.md")) {
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: %w", err)))
}
}
if e.Resolution, err = ProcessMarkdown(i, e.Resolution, epath); err != nil {
errs = append(errs, NewExerciceError(e, fmt.Errorf("resolution.md: error during markdown processing: %w", err), theme))
} else {
resolutionFound = true
}
}
}

View File

@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"log"
"strings"
"unicode"
"srs.epita.fr/fic-server/admin/sync"
@ -52,21 +51,6 @@ func GrammalecteCheckHint(hint *fic.EHint, exceptions *sync.CheckExceptions) (er
return
}
func GrammalecteCheckMDText(str string, exceptions *sync.CheckExceptions) (errs []error) {
if exceptions != nil {
for k := range *exceptions {
tmp := strings.SplitN(k, ":", 3)
if len(tmp) == 3 && tmp[1] == "quote" {
str = strings.Replace(str, tmp[2], "une citation a été remplacée ici", -1)
}
}
}
errs = append(errs, grammalecte("", str, 0, exceptions, &CommonOpts)...)
return
}
func GrammalecteCheckGrammar(data interface{}, exceptions *sync.CheckExceptions) []error {
if s, ok := data.(string); ok {
return grammalecte("", s, 0, exceptions, &CommonOpts)

View File

@ -0,0 +1,85 @@
package main
import (
"bytes"
"strings"
"srs.epita.fr/fic-server/admin/sync"
"srs.epita.fr/fic-server/repochecker/grammalecte/void"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
func GrammalecteCheckMDText(str string, exceptions *sync.CheckExceptions) (errs []error) {
if exceptions != nil {
for k := range *exceptions {
tmp := strings.SplitN(k, ":", 3)
if len(tmp) == 3 && tmp[1] == "quote" {
str = strings.Replace(str, tmp[2], "une citation a été remplacée ici", -1)
}
}
}
checker := &grammarChecker{
exceptions: exceptions,
}
voidRenderer := void.NewVoidRenderer()
markdown := goldmark.New(
goldmark.WithParserOptions(
parser.WithASTTransformers(
util.Prioritized(checker, 200),
),
),
goldmark.WithRenderer(
renderer.NewRenderer(
renderer.WithNodeRenderers(
util.Prioritized(voidRenderer, 30),
),
),
),
)
var buf bytes.Buffer
if err := markdown.Convert([]byte(str), &buf); err != nil {
errs = append(errs, err)
}
errs = append(errs, checker.errs...)
errs = append(errs, voidRenderer.Errors()...)
errs = append(errs, grammalecte("", buf.String(), 0, exceptions, &CommonOpts)...)
return
}
type grammarChecker struct {
exceptions *sync.CheckExceptions
errs []error
}
func (t *grammarChecker) Transform(doc *ast.Document, reader text.Reader, pc parser.Context) {
ast.Walk(doc, func(node ast.Node, enter bool) (ast.WalkStatus, error) {
if !enter {
return ast.WalkContinue, nil
}
switch child := node.(type) {
case *ast.Image:
if len(child.Title) > 0 {
t.errs = append(t.errs, grammalecte("", string(child.Title), 0, t.exceptions, &CommonOpts)...)
}
case *ast.Link:
if len(child.Title) > 0 {
t.errs = append(t.errs, grammalecte("", string(child.Title), 0, t.exceptions, &CommonOpts)...)
}
}
return ast.WalkContinue, nil
})
}

View File

@ -0,0 +1,135 @@
package void
import (
"bytes"
"fmt"
"github.com/yuin/goldmark/ast"
goldrender "github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/util"
)
type VoidRenderer struct {
Writer html.Writer
errs []error
}
func NewVoidRenderer() *VoidRenderer {
return &VoidRenderer{
Writer: html.DefaultWriter,
}
}
// RegisterFuncs implements NodeRenderer.RegisterFuncs .
func (r *VoidRenderer) RegisterFuncs(reg goldrender.NodeRendererFuncRegisterer) {
reg.Register(ast.KindParagraph, r.renderParagraph)
reg.Register(ast.KindAutoLink, r.renderAutoLink)
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
reg.Register(ast.KindRawHTML, r.renderRawHTML)
reg.Register(ast.KindImage, r.renderImage)
reg.Register(ast.KindText, r.renderText)
reg.Register(ast.KindString, r.renderString)
}
func (r *VoidRenderer) Errors() []error {
return r.errs
}
func (r *VoidRenderer) renderParagraph(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
_, _ = w.WriteString("\n")
return ast.WalkContinue, nil
}
func (r *VoidRenderer) renderAutoLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
_, _ = w.WriteString(`lien hypertexte`)
return ast.WalkContinue, nil
}
func (r *VoidRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
_, _ = w.WriteString(`code remplacé`)
return ast.WalkSkipChildren, nil
}
func (r *VoidRenderer) renderRawHTML(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
_, _ = w.WriteString(`bloc HTML remplacé`)
return ast.WalkSkipChildren, nil
}
func (r *VoidRenderer) renderImage(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
_, _ = w.WriteString(`.`)
return ast.WalkContinue, nil
}
n := node.(*ast.Image)
// Check there is a correct image alt
alt := nodeToText(n, source)
if len(bytes.Fields(alt)) <= 1 {
r.errs = append(r.errs, fmt.Errorf("No valid image alternative defined for %q", n.Destination))
return ast.WalkContinue, nil
}
return ast.WalkContinue, nil
}
func nodeToText(n ast.Node, source []byte) []byte {
var buf bytes.Buffer
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
if s, ok := c.(*ast.String); ok && s.IsCode() {
buf.Write(s.Text(source))
} else if !c.HasChildren() {
buf.Write(util.EscapeHTML(c.Text(source)))
} else {
buf.Write(nodeToText(c, source))
}
}
return buf.Bytes()
}
func (r *VoidRenderer) renderText(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
n := node.(*ast.Text)
segment := n.Segment
if n.IsRaw() {
r.Writer.RawWrite(w, segment.Value(source))
} else {
r.Writer.Write(w, segment.Value(source))
r.Writer.Write(w, []byte(" "))
}
return ast.WalkContinue, nil
}
func (r *VoidRenderer) renderString(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
n := node.(*ast.String)
if n.IsCode() {
_, _ = w.Write(n.Value)
} else {
if n.IsRaw() {
r.Writer.RawWrite(w, n.Value)
} else {
r.Writer.Write(w, n.Value)
r.Writer.Write(w, []byte("\n"))
}
}
return ast.WalkContinue, nil
}