import { addError, filterTokens } from 'markdownlint-rule-helpers' import { getRange, quotePrecedesLinkOpen } from '../helpers/utils' import { escapeRegExp } from 'lodash-es' import type { RuleParams, RuleErrorCallback, MarkdownToken, Rule } from '../../types' export const linkQuotation: Rule = { names: ['GHD043', 'link-quotation'], description: 'Internal link titles must not be surrounded by quotations', tags: ['links', 'url'], parser: 'markdownit', function: (params: RuleParams, onError: RuleErrorCallback) => { filterTokens(params, 'inline', (token: MarkdownToken) => { const { children } = token if (!children) return let previous_child: MarkdownToken = children[0] let inLinkWithPrecedingQuotes = false let linkUrl = '' let content: string[] = [] for (let i = 1; i < children.length; i++) { const child = children[i] if (child.type === 'link_open' && quotePrecedesLinkOpen(previous_child.content || '')) { if (!child.attrs) continue inLinkWithPrecedingQuotes = true linkUrl = escapeRegExp(child.attrs[0][1]) } else if (inLinkWithPrecedingQuotes && child.type === 'text') { content.push(escapeRegExp((child.content || '').trim())) } else if (inLinkWithPrecedingQuotes && child.type === 'code_inline') { content.push(`\`${escapeRegExp((child.content || '').trim())}\``) } else if (child.type === 'link_close') { const title = content.join(' ') const regex = new RegExp(`"\\[${title}\\]\\(${linkUrl}\\)({%.*%})?(!|\\.|\\?|,)?"`) if (regex.test(child.line)) { const matchResult = child.line.match(regex) if (!matchResult) continue const match = matchResult[0] const range = getRange(child.line, match) if (!range) continue let newLine = match if (newLine.startsWith('"')) { newLine = newLine.slice(1) } if (newLine.endsWith('"')) { newLine = newLine.slice(0, -1) } if (newLine.endsWith('".')) { newLine = `${newLine.slice(0, -2)}.` } const lineNumber = child.lineNumber addError( onError, lineNumber, 'Remove quotes surrounding the link title.', match, range, { lineNumber, editColumn: range[0], deleteCount: range[1], insertText: newLine, }, ) } inLinkWithPrecedingQuotes = false content = [] linkUrl = '' } previous_child = child } }) }, }