mdlinks

package module
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2022 License: MIT Imports: 11 Imported by: 0

README

This repository provides Go package, command-line tool, and a GitHub Action that can verify cross-document links in a collection of markdown files.

Code scans markdown files for domain-less links and checks if referenced files exist. For example, if a file “doc1.md” has a link with “../img.png” target, this tool will check whether the “img.png” file exists in a “doc1.md” file parent directory.

If a link references an existing markdown document and has a fragment part, this tool checks that such a link points to an existing markdown header, following similar (but not exactly matching) rules of unique ID generating as GitHub markdown rendering.

For example, use the #table-of-contents link fragment to reference the “Table of Contents” header.

Using special symbols or extra formatting in the header will likely produce an ID that differs from what GitHub could have generated.

Command-line tool

Install it like:

go install github.com/artyom/mdlinks/cmd/mdlinks@latest

GitHub Action

When using default settings (scan the repository root directory, look for *.md files), you can use this action like this:

on:
  push:
  pull_request:

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: artyom/mdlinks@main

You can customize what directory to scan and which files to match:

- uses: artyom/mdlinks@main
  with:
    dir: 'docs'
    glob: '*.markdown'

Documentation

Overview

Package mdlinks provides functions to verify cross document links in a set of markdown files.

Example
package main

import (
	"errors"
	"fmt"
	"testing/fstest"

	"github.com/artyom/mdlinks"
)

const Doc1 = `
# Document One

Text with a [broken link](non-existing-file.md).
`

const Doc2 = `
# Document Two

Example of [internal](#document-two),
and [external](../doc1.md#document-one) links.

No such [reference][1].

[1]: #invalid-ref
`

func main() {
	fs := make(fstest.MapFS) // in real scenario this will likely be os.DirFS(dir)
	writeFile(fs, "doc1.md", Doc1)
	writeFile(fs, "subdir/doc2.md", Doc2)
	err := mdlinks.CheckFS(fs, "*.md")
	var e *mdlinks.BrokenLinksError
	if errors.As(err, &e) {
		for _, link := range e.Links {
			fmt.Println(link)
		}
	}
}

func writeFile(fs fstest.MapFS, name, body string) {
	fs[name] = &fstest.MapFile{Data: []byte(body)}
}
Output:

doc1.md: link "non-existing-file.md" points to a non-existing file
subdir/doc2.md: link "#invalid-ref" points to a non-existing local slug

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckFS

func CheckFS(fsys fs.FS, pat string) error

CheckFS walks file system fsys looking for files with their base names matching pattern pat (e.g. “*.md”). It parses such files as markdown, looks for local urls (urls that don't have schema and domain), and reports if it finds any urls pointing to non-existing files.

If error returned is a *BrokenLinksError, it describes found files with broken links.

Types

type BrokenLink struct {
	File string // file path, relative to directory/filesystem scanned; uses '/' as a separator
	Link LinkInfo
	// contains filtered or unexported fields
}

BrokenLink describes broken markdown link and the file it belongs to.

func (BrokenLink) Reason

func (b BrokenLink) Reason() string

func (BrokenLink) String

func (b BrokenLink) String() string

type BrokenLinksError

type BrokenLinksError struct {
	Links []BrokenLink
}

BrokenLinksError is an error type returned by this package functions to report found broken links.

Usage example:

err := mdlinks.CheckFS(os.DirFS(dir), "*.md")
var e *mdlinks.BrokenLinksError
if errors.As(err, &e) {
    for _, link := range e.Links {
        log.Println(link)
    }
}

func (*BrokenLinksError) Error

func (e *BrokenLinksError) Error() string

type Checker added in v0.4.0

type Checker struct {
	// Matcher takes /-separated paths when CheckFS method traverses filesystem
	// (see documentation on fs.WalkDirFunc, its first argument). If Matcher
	// returns a non-nil error, CheckFS stops and returns this error. If
	// Matcher returns true, file is considered an utf-8 markdown document and
	// is processed.
	Matcher func(path string) (bool, error)
}

Checker allows checks customization.

Usage example:

c := &mdlinks.Checker{
    Matcher: func(s string) (bool, error) { return path.Ext(s) == ".md", nil },
}
err := c.CheckFS(os.DirFS(dir))

func (*Checker) CheckFS added in v0.4.0

func (c *Checker) CheckFS(fsys fs.FS) error

CheckFS walks file system fsys looking for files using the Matcher function. It parses matched files as markdown, looks for local urls (urls that don't have schema and domain), and reports if it finds any urls pointing to non-existing files.

If error returned is a *BrokenLinksError, it describes found files with broken links.

type LinkInfo

type LinkInfo struct {
	Raw       string // as seen in the source, usually “some/path#fragment”
	Path      string // only the path part of the link
	Fragment  string // only the fragment part of the link, without '#'
	LineStart int    // number of the first line of the context (usually paragraph)
	LineEnd   int    // number of the last line of the context (usually paragraph)
}

LinkInfo describes markdown link

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL