Skip to content

Commit

Permalink
Add file line numbers to errors (#48)
Browse files Browse the repository at this point in the history
* Add line numbers to errors

Signed-off-by: Saswata Mukherjee <[email protected]>

* Implement suggestions

Signed-off-by: Saswata Mukherjee <[email protected]>
  • Loading branch information
saswatamcode authored Jul 2, 2021
1 parent ce7adf8 commit 2fac898
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 14 deletions.
12 changes: 6 additions & 6 deletions pkg/mdformatter/linktransformer/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ type validator struct {
}

type futureKey struct {
filepath, dest string
filepath, dest, lineNumbers string
}

type futureResult struct {
Expand Down Expand Up @@ -234,7 +234,7 @@ func MustNewValidator(logger log.Logger, linksValidateConfig []byte, anchorDir s
}

func (v *validator) TransformDestination(ctx mdformatter.SourceContext, destination []byte) (_ []byte, err error) {
v.visit(ctx.Filepath, string(destination))
v.visit(ctx.Filepath, string(destination), ctx.LineNumbers)
return destination, nil
}

Expand Down Expand Up @@ -266,19 +266,19 @@ func (v *validator) Close(ctx mdformatter.SourceContext) error {
f := v.destFutures[k]
if err := f.resultFn(); err != nil {
if f.cases == 1 {
merr.Add(errors.Wrapf(err, "%v", path))
merr.Add(errors.Wrapf(err, "%v:%v", path, k.lineNumbers))
continue
}
merr.Add(errors.Wrapf(err, "%v (%v occurrences)", path, f.cases))
merr.Add(errors.Wrapf(err, "%v:%v (%v occurrences)", path, k.lineNumbers, f.cases))
}
}
return merr.Err()
}

func (v *validator) visit(filepath string, dest string) {
func (v *validator) visit(filepath string, dest string, lineNumbers string) {
v.futureMu.Lock()
defer v.futureMu.Unlock()
k := futureKey{filepath: filepath, dest: dest}
k := futureKey{filepath: filepath, dest: dest, lineNumbers: lineNumbers}
if _, ok := v.destFutures[k]; ok {
v.destFutures[k].cases++
return
Expand Down
10 changes: 5 additions & 5 deletions pkg/mdformatter/linktransformer/link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,10 @@ func TestValidator_TransformDestination(t *testing.T) {
testutil.NotOk(t, err)

testutil.Equals(t, fmt.Sprintf("%v: 4 errors: "+
"%v: link ../test2/invalid-local-links.md, normalized to: %v/repo/docs/test2/invalid-local-links.md: file not found; "+
"%v: link ../test/invalid-local-links.md#not-yolo, normalized to: link %v/repo/docs/test/invalid-local-links.md#not-yolo, existing ids: [yolo]: file exists, but does not have such id; "+
"%v: link ../test/doc.md, normalized to: %v/repo/docs/test/doc.md: file not found; "+
"%v: link #not-yolo, normalized to: link %v/repo/docs/test/invalid-local-links.md#not-yolo, existing ids: [yolo]: file exists, but does not have such id",
"%v:3: link ../test2/invalid-local-links.md, normalized to: %v/repo/docs/test2/invalid-local-links.md: file not found; "+
"%v:3: link ../test/invalid-local-links.md#not-yolo, normalized to: link %v/repo/docs/test/invalid-local-links.md#not-yolo, existing ids: [yolo]: file exists, but does not have such id; "+
"%v:3: link ../test/doc.md, normalized to: %v/repo/docs/test/doc.md: file not found; "+
"%v:3: link #not-yolo, normalized to: link %v/repo/docs/test/invalid-local-links.md#not-yolo, existing ids: [yolo]: file exists, but does not have such id",
tmpDir+filePath, relDirPath+filePath, tmpDir, relDirPath+filePath, tmpDir, relDirPath+filePath, tmpDir, relDirPath+filePath, tmpDir), err.Error())
})

Expand All @@ -271,7 +271,7 @@ func TestValidator_TransformDestination(t *testing.T) {
MustNewValidator(logger, []byte(""), anchorDir),
))
testutil.NotOk(t, err)
testutil.Equals(t, fmt.Sprintf("%v%v: %v%v: \"https://bwplotka.dev/does-not-exists\" not accessible; status code 404: Not Found", tmpDir, filePath, relDirPath, filePath), err.Error())
testutil.Equals(t, fmt.Sprintf("%v%v: %v%v:1: \"https://bwplotka.dev/does-not-exists\" not accessible; status code 404: Not Found", tmpDir, filePath, relDirPath, filePath), err.Error())
})

t.Run("check valid & 404 link with validate config", func(t *testing.T) {
Expand Down
4 changes: 3 additions & 1 deletion pkg/mdformatter/mdformatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ import (
type SourceContext struct {
context.Context

Filepath string
Filepath string
LineNumbers string
}

type FrontMatterTransformer interface {
Expand Down Expand Up @@ -348,6 +349,7 @@ func (f *Formatter) Format(file *os.File, out io.Writer) error {
wrapped: markdown.NewRenderer(),
sourceCtx: sourceCtx,
link: f.link, cb: f.cb,
frontMatterLen: len(frontMatter),
}
if err := goldmark.New(
goldmark.WithExtensions(extension.GFM),
Expand Down
37 changes: 35 additions & 2 deletions pkg/mdformatter/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package mdformatter
import (
"bytes"
"io"
"regexp"
"strconv"

"github.com/efficientgo/tools/core/pkg/merrors"
"github.com/yuin/goldmark/ast"
Expand All @@ -29,8 +31,9 @@ type transformer struct {

sourceCtx SourceContext

link LinkTransformer
cb CodeBlockTransformer
link LinkTransformer
cb CodeBlockTransformer
frontMatterLen int
}

func (t *transformer) Render(w io.Writer, source []byte, node ast.Node) error {
Expand Down Expand Up @@ -75,6 +78,7 @@ func (t *transformer) Render(w io.Writer, source []byte, node ast.Node) error {
if token.Attr[i].Key != "src" {
continue
}
t.sourceCtx.LineNumbers = getLinkLines(source, []byte(token.Attr[i].Val), t.frontMatterLen)
dest, err := t.link.TransformDestination(t.sourceCtx, []byte(token.Attr[i].Val))
if err != nil {
return ast.WalkStop, err
Expand All @@ -87,6 +91,7 @@ func (t *transformer) Render(w io.Writer, source []byte, node ast.Node) error {
if token.Attr[i].Key != "href" {
continue
}
t.sourceCtx.LineNumbers = getLinkLines(source, []byte(token.Attr[i].Val), t.frontMatterLen)
dest, err := t.link.TransformDestination(t.sourceCtx, []byte(token.Attr[i].Val))
if err != nil {
return ast.WalkStop, err
Expand All @@ -111,6 +116,7 @@ func (t *transformer) Render(w io.Writer, source []byte, node ast.Node) error {
if !entering || t.link == nil {
return ast.WalkSkipChildren, nil
}
t.sourceCtx.LineNumbers = getLinkLines(source, typedNode.Destination, t.frontMatterLen)
typedNode.Destination, err = t.link.TransformDestination(t.sourceCtx, typedNode.Destination)
if err != nil {
return ast.WalkStop, err
Expand All @@ -119,6 +125,7 @@ func (t *transformer) Render(w io.Writer, source []byte, node ast.Node) error {
if !entering || t.link == nil || typedNode.AutoLinkType != ast.AutoLinkURL {
return ast.WalkSkipChildren, nil
}
t.sourceCtx.LineNumbers = getLinkLines(source, typedNode.URL(source), t.frontMatterLen)
dest, err := t.link.TransformDestination(t.sourceCtx, typedNode.URL(source))
if err != nil {
return ast.WalkStop, err
Expand All @@ -135,6 +142,7 @@ func (t *transformer) Render(w io.Writer, source []byte, node ast.Node) error {
if !entering || t.link == nil {
return ast.WalkSkipChildren, nil
}
t.sourceCtx.LineNumbers = getLinkLines(source, typedNode.Destination, t.frontMatterLen)
typedNode.Destination, err = t.link.TransformDestination(t.sourceCtx, typedNode.Destination)
if err != nil {
return ast.WalkStop, err
Expand Down Expand Up @@ -178,3 +186,28 @@ func replaceContent(b *ast.BaseBlock, lastSegmentStop int, content []byte) {
s.Append(text.NewSegment(lastSegmentStop, lastSegmentStop+len(content)))
b.SetLines(s)
}

// getLinkLines returns line numbers in source where link is present.
func getLinkLines(source []byte, link []byte, lenfm int) string {
var targetLines string
sourceLines := bytes.Split(source, []byte("\n"))
// frontMatter is present so would need to account for `---` lines.
if lenfm > 0 {
lenfm += 2
}
// Using regex, as two links may have same host but diff params. Same in case of local links.
linkRe := regexp.MustCompile(`(^|[^/\-~&=#?@%a-zA-Z0-9])` + string(link) + `($|[^/\-~&=#?@%a-zA-Z0-9])`)
for i, line := range sourceLines {
if linkRe.Match(line) {
// Easier to just return int slice, but then cannot use it in futureKey.
// https://golang.org/ref/spec#Map_types.
add := strconv.Itoa(i + 1 + lenfm)
if targetLines != "" {
add = "," + strconv.Itoa(i+1+lenfm)
}
targetLines += add
}
}
// If same link is found multiple times returns string like *,*,*...
return targetLines
}

0 comments on commit 2fac898

Please sign in to comment.