Skip to content

Commit

Permalink
Merge pull request #331 from dklimpel/html_anchors
Browse files Browse the repository at this point in the history
feat: anchor link checks support HTML tags like `<a name="foo"></a>`
  • Loading branch information
tcort authored Nov 5, 2024
2 parents 014ff95 + 51fc856 commit 0348390
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 5 deletions.
27 changes: 25 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,32 @@ function performSpecialReplacements(str, opts) {
return str;
}

function removeCodeBlocks(markdown) {
return markdown.replace(/^```[\S\s]+?^```$/gm, '');
}

function extractHtmlSections(markdown) {
markdown =
// remove code blocks
removeCodeBlocks(markdown)
// remove HTML comments
.replace(/<!--[\S\s]+?-->/gm, '')
// remove single line code (if not escaped with "\")
.replace(/(?<!\\)`[\S\s]+?(?<!\\)`/gm, '');

const regexAllId = /<(?<tag>[^\s]+).*?id=["'](?<id>[^"']*?)["'].*?>/gmi;
const regexAName = /<a.*?name=["'](?<name>[^"']*?)["'].*?>/gmi;

const sections = []
.concat(Array.from(markdown.matchAll(regexAllId), (match) => match.groups.id))
.concat(Array.from(markdown.matchAll(regexAName), (match) => match.groups.name));

return sections
}

function extractSections(markdown) {
// First remove code blocks.
markdown = markdown.replace(/^```[\S\s]+?^```$/mg, '');
markdown = removeCodeBlocks(markdown);

const sectionTitles = markdown.match(/^#+ .*$/gm) || [];

Expand Down Expand Up @@ -106,7 +129,7 @@ module.exports = function markdownLinkCheck(markdown, opts, callback) {
}

const links = markdownLinkExtractor(markdown);
const sections = extractSections(markdown);
const sections = extractSections(markdown).concat(extractHtmlSections(markdown));
const linksCollection = [...new Set(links)]
const bar = (opts.showProgressBar) ?
new ProgressBar('Checking... [:bar] :percent', {
Expand Down
41 changes: 39 additions & 2 deletions test/hash-links.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
# Foo

<!-- markdownlint-disable MD033 -->
<a id="tomato"></a>
<a id="tomato_id"></a>
<a name="tomato_name"></a>

<a id='tomato_id_single_quote'></a>
<a name='tomato_name_single_quote'></a>

<div id="onion"></div>
<div id="onion_outer">
<div id="onion_inner"></div>
</div>

<!--
<a id="tomato_comment"></a>
-->

<!-- markdownlint-enable MD033 -->

This is a test.

HTML anchor in code `<a id="tomato_code"></a>` should be ignored.

<!-- markdownlint-disable-next-line MD033 -->
Ignore escaped backticks \`<a id="tomato_escaped_backticks"></a>\`. Link should work.

## Bar

The title is [Foo](#foo).
Expand All @@ -20,7 +39,25 @@ To test a failure. Link that [does not exist](#does-not-exist).

There is no section named [Potato](#potato).

There is an anchor named [Tomato](#tomato).
There is an anchor named with `id` [Tomato](#tomato_id).

There is an anchor named with `name` [Tomato](#tomato_name).

There is an anchor named with `id` [Tomato in single quote](#tomato_id_single_quote).

There is an anchor named with `name` [Tomato in single quote](#tomato_name_single_quote).

There is an anchor in code [Tomato in code](#tomato_code).

There is an anchor in escaped code [Tomato in escaped backticks](#tomato_escaped_backticks).

There is an anchor in HTML comment [Tomato in comment](#tomato_comment).

There is an anchor in single div [Onion](#onion).

There is an anchor in outer div [Onion outer](#onion_outer).

There is an anchor in inner div [Onion inner](#onion_inner).

## Header with special char at end ✨

Expand Down
11 changes: 10 additions & 1 deletion test/markdown-link-check.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,16 @@ describe('markdown-link-check', function () {
{ link: '#bar', statusCode: 200, err: null, status: 'alive' },
{ link: '#does-not-exist', statusCode: 404, err: null, status: 'dead' },
{ link: '#potato', statusCode: 404, err: null, status: 'dead' },
{ link: '#tomato', statusCode: 404, err: null, status: 'dead' },
{ link: '#tomato_id', statusCode: 200, err: null, status: 'alive' },
{ link: '#tomato_name', statusCode: 200, err: null, status: 'alive' },
{ link: '#tomato_id_single_quote', statusCode: 200, err: null, status: 'alive' },
{ link: '#tomato_name_single_quote', statusCode: 200, err: null, status: 'alive' },
{ link: '#tomato_code', statusCode: 404, err: null, status: 'dead' },
{ link: '#tomato_escaped_backticks', statusCode: 200, err: null, status: 'alive' },
{ link: '#tomato_comment', statusCode: 404, err: null, status: 'dead' },
{ link: '#onion', statusCode: 200, err: null, status: 'alive' },
{ link: '#onion_outer', statusCode: 200, err: null, status: 'alive' },
{ link: '#onion_inner', statusCode: 200, err: null, status: 'alive' },
{ link: '#header-with-special-char-at-end-', statusCode: 200, err: null, status: 'alive' },
{ link: '#header-with-multiple-special-chars-at-end-', statusCode: 200, err: null, status: 'alive' },
{ link: '#header-with-special--char', statusCode: 200, err: null, status: 'alive' },
Expand Down

0 comments on commit 0348390

Please sign in to comment.