Rules#

gomarklint currently runs the following checks (ordered as executed):

Rule keyWhat it detectsNotes / Options
final-blank-lineMissing final blank line at EOFDefault on
unclosed-code-blockUnclosed fenced code blocks (```)Default on
empty-alt-textImage syntax with an empty alt textDefault on
heading-levelInvalid heading level progression (e.g., H2 → H4 skip)Default on. Option: minLevel (default 2)
fenced-code-languageFenced code blocks without a language identifierDefault on
duplicate-headingDuplicate headings within one fileDefault on
no-multiple-blank-linesMultiple consecutive blank linesDefault on
no-setext-headingsSetext heading used instead of ATX styleDefault on
single-h1More than one H1 heading in a fileDefault on
blanks-around-headingsHeadings not surrounded by blank linesDefault on
no-bare-urlsHTTP/HTTPS URLs written as bare text instead of proper Markdown linksDefault on
no-empty-linksLinks or images with an empty destination ([](), [](#), [](<>))Default on
no-emphasis-as-headingBold/italic text used as a heading substitute instead of ATX headingsDefault on. Punctuation-ending spans (. , ; : ! ? 。 、 ; : ! ?) are excluded
blanks-around-listsLists not surrounded by blank linesDefault on
blanks-around-fencesFenced code blocks not surrounded by blank linesDefault on
no-hard-tabsHard tab characters (\t) outside fenced code blocks and inline codeDefault on
no-trailing-punctuationHeading text ending with a punctuation characterDefault on. Option: punctuation (default ".,;:!") — the full set of characters to flag; e.g. set ".,;:!?" to also flag question headings
consistent-code-fenceInconsistent fenced code block marker (``` vs ~~~)Default on. Option: style (consistent | backtick | tilde, default consistent)
consistent-emphasis-styleInconsistent emphasis marker (*text* vs _text_)Default on. Option: style (consistent | asterisk | underscore, default consistent)
consistent-list-markerInconsistent unordered list marker (- vs * vs +)Default on. Option: style (consistent | dash | asterisk | plus, default consistent)
max-line-lengthLines exceeding the configured maximum lengthDefault off. Option: lineLength (default 80)
external-linkExternal links that fail HTTP validationDefault off. Options: timeoutSeconds (default 5), skipPatterns (regex list)
link-fragmentsInternal fragment links (#section) that do not resolve to a headingDefault off. Options: slug-algorithm (default github), slug-params (for custom algorithm)

link-fragments validates that every internal fragment link in a document resolves to an actual heading slug. It supports multiple slug algorithms to match the platform where the Markdown is published.

slug-algorithm#

Set slug-algorithm to the name of the platform you are writing for. Each platform is an independent named value — you do not need to know which underlying algorithm it maps to.

Supported platforms:

ValuePlatformlowercasepreserve-unicodespace-replacementstrip-charscollapse-separatorsNotes
githubGitHub (default)-Unicode punctuation/symbolsgithub-slugger; consecutive spaces → consecutive hyphens
gitlabGitLab-[^\p{L}\p{N}_-]goldmark slugify; collapses consecutive separators unlike GitHub
zennZenn-preserves all non-space charsmarkdown-it-anchor default; anchors are percent-encoded in HTML
qiitaQiita-[^\p{Word}\- ]downcase.gsub(/[^\p{Word}\- ]/u, "").tr(" ", "-"); consecutive hyphens preserved
hugoHugo-Unicode punctuation/symbolsautoHeadingIDType: github (default); equivalent to github-slugger
vitepressVitePresspartial-NFKD, strip combining chars, then punctuation→-Accented Latin normalized to ASCII (é→e); CJK preserved
docusaurusDocusaurus-Unicode punctuation/symbolsUses github-slugger directly
gatsbyGatsby-Unicode punctuation/symbolsgatsby-remark-autolink-headers uses github-slugger
astroAstro-Unicode punctuation/symbolsDocumented as GitHub-compatible in Astro official docs
starlightStarlight-Unicode punctuation/symbolsStarlight (Astro-based); same algorithm as astro
nuxt-contentNuxt Content-Unicode punctuation/symbolsUses rehype-slug (github-slugger wrapper)
pandocPandoc (auto_identifiers)-[^a-zA-Z0-9_-]auto_identifiers extension; strips non-ASCII. Non-ASCII-only headings produce an empty slug — links to them cannot be verified statically; see FAQ
pandoc-gfmPandoc (gfm_auto_identifiers)-Unicode punctuation/symbolsgfm_auto_identifiers extension; equivalent to GitHub
quartoQuarto-[^a-zA-Z0-9_-]Uses auto_identifiers extension by default; same as pandoc
kramdownkramdown-[^a-zA-Z0-9 -]header_ids extension default. Non-ASCII-only headings produce an empty slug — links to them cannot be verified statically; see FAQ
mkdocsMkDocs-NFKD then ASCII-encodePython-Markdown toc.py default; uslugify variant preserves Unicode. Non-ASCII-only headings produce an empty slug — links to them cannot be verified statically; see FAQ
docfxDocFX-[^a-zA-Z0-9-_.]Markdig AutoIdentifiers; does not lowercase
mdbookmdBook-non-alphanumeric except _ and - (Rust is_alphanumeric())CJK preserved via Unicode alphanumeric check
giteaGitea-Unicode punctuation/symbolsgoldmark-based; identical to GitHub algorithm. Gitea adds user-content- to the DOM id for CSP isolation, but users write fragments without that prefix (e.g. #hello-world)
forgejoForgejo-Unicode punctuation/symbolsFork of Gitea; identical algorithm
sphinxSphinx-NFKD then ASCII then [^a-z0-9]+-Digits-only or non-Latin-only headings produce an empty slug; Sphinx falls back to id1, id2, … at build time — gomarklint cannot verify links to these headings statically; see FAQ
eleventyEleventy-@sindresorhus/slugify (transliterate to approximate ASCII)Used via IdAttributePlugin. Characters with no ASCII equivalent (CJK, etc.) are stripped — non-ASCII-only headings produce an empty slug; see FAQ
azure-devopsAzure DevOps Wiki-non-RFC-3986-unreserved chars percent-encodedUnicode Zs category → -; non-ASCII preserved as percent-encoded
mystMyST Parser-Unicode punctuation/symbolsMyST-Parser (Python/Sphinx); documented as GitHub-compatible
customParameterized engine — see below

Custom algorithm#

Use slug-algorithm: "custom" with slug-params for platforms not covered by the built-in presets:

"link-fragments": {
  "enabled": true,
  "slug-algorithm": "custom",
  "slug-params": {
    "lowercase": true,
    "preserve-unicode": true,
    "space-replacement": "-",
    "strip-chars": "[^\\w\\- ]",
    "collapse-separators": true
  }
}
ParameterTypeDescription
lowercaseboolLowercase the heading before processing (default true)
preserve-unicodeboolKeep non-ASCII characters in the slug (default true)
space-replacementstringCharacter to replace spaces — "-" or "_" (default "-")
strip-charsstringRegex matching characters to remove after space replacement
collapse-separatorsboolCollapse consecutive separators and trim leading/trailing (default false)

Note: strip-chars uses Go’s regexp syntax. \w matches ASCII [0-9A-Za-z_] only. To match Unicode word characters use \p{L}, \p{N}, etc.

Execution details#

  • Files/dirs are expanded with ignore patterns from config.
  • Per-file issues are sorted by line asc before printing.
  • Line count is computed as \n count + 1 for reporting.