mirror of
https://github.com/theoludwig/markdownlint-rule-relative-links.git
synced 2024-12-08 00:45:32 +01:00
feat: add relative-links
rule
This commit is contained in:
parent
221ded7d62
commit
4adef29333
73
src/index.js
73
src/index.js
@ -1,10 +1,81 @@
|
||||
'use strict'
|
||||
|
||||
const { pathToFileURL } = require('node:url')
|
||||
const fs = require('node:fs')
|
||||
|
||||
/**
|
||||
* Calls the provided function for each matching token.
|
||||
*
|
||||
* @param {Object} params RuleParams instance.
|
||||
* @param {string} type Token type identifier.
|
||||
* @param {Function} handler Callback function.
|
||||
* @returns {void}
|
||||
*/
|
||||
const filterTokens = (params, type, handler) => {
|
||||
for (const token of params.tokens) {
|
||||
if (token.type === type) {
|
||||
handler(token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a generic error object via the onError callback.
|
||||
*
|
||||
* @param {Object} onError RuleOnError instance.
|
||||
* @param {number} lineNumber Line number.
|
||||
* @param {string} [detail] Error details.
|
||||
* @param {string} [context] Error context.
|
||||
* @param {number[]} [range] Column and length of error.
|
||||
* @param {Object} [fixInfo] RuleOnErrorFixInfo instance.
|
||||
* @returns {void}
|
||||
*/
|
||||
const addError = (onError, lineNumber, detail, context, range, fixInfo) => {
|
||||
onError({
|
||||
lineNumber,
|
||||
detail,
|
||||
context,
|
||||
range,
|
||||
fixInfo
|
||||
})
|
||||
}
|
||||
|
||||
const EXTERNAL_PROTOCOLS = new Set([
|
||||
'http:',
|
||||
'https:',
|
||||
'mailto:',
|
||||
'tel:',
|
||||
'ftp:'
|
||||
])
|
||||
|
||||
const customRule = {
|
||||
names: ['relative-links'],
|
||||
description: 'Relative links should be valid',
|
||||
tags: ['links'],
|
||||
function: () => {}
|
||||
function: (params, onError) => {
|
||||
filterTokens(params, 'inline', (token) => {
|
||||
token.children.forEach((child) => {
|
||||
const { lineNumber, type, attrs } = child
|
||||
if (type === 'link_open') {
|
||||
attrs.forEach((attr) => {
|
||||
if (attr[0] === 'href') {
|
||||
const href = attr[1]
|
||||
const url = new URL(href, pathToFileURL(params.name))
|
||||
url.hash = ''
|
||||
const isRelative =
|
||||
href.startsWith('./') ||
|
||||
href.startsWith('../') ||
|
||||
!EXTERNAL_PROTOCOLS.has(url.protocol)
|
||||
if (isRelative && !fs.existsSync(url.pathname)) {
|
||||
const detail = `Link "${href}" is dead`
|
||||
addError(onError, lineNumber, detail)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = customRule
|
||||
|
Loading…
Reference in New Issue
Block a user