1
0
mirror of synced 2025-12-22 11:26:57 -05:00
Files
docs/src/content-linter/lib/linting-rules/internal-links-no-lang.ts
2025-10-06 16:07:33 +00:00

57 lines
2.3 KiB
TypeScript

// @ts-ignore - markdownlint-rule-helpers doesn't have TypeScript declarations
import { filterTokens } from 'markdownlint-rule-helpers'
import { addFixErrorDetail, getRange } from '../helpers/utils'
import { allLanguageKeys } from '@/languages/lib/languages'
import type { RuleParams, RuleErrorCallback, Rule } from '../../types'
export const internalLinksNoLang: Rule = {
names: ['GHD002', 'internal-links-no-lang'],
description: 'Internal links must not have a hardcoded language code',
tags: ['links', 'url'],
parser: 'markdownit',
function: (params: RuleParams, onError: RuleErrorCallback) => {
// Using 'any' type for token as markdownlint-rule-helpers doesn't provide TypeScript types
filterTokens(params, 'inline', (token: any) => {
for (const child of token.children) {
if (child.type !== 'link_open') continue
// Example child.attrs:
// [
// ['href', 'get-started'], ['target', '_blank'],
// ['rel', 'canonical'],
// ]
// Attribute arrays are tuples of [attributeName, attributeValue] from markdownit parser
const hrefsMissingSlashes = child.attrs
// The attribute could also be `target` or `rel`
.filter((attr: [string, string]) => attr[0] === 'href')
.filter((attr: [string, string]) => attr[1].startsWith('/') || !attr[1].startsWith('//'))
// Filter out link paths that start with language code
.filter((attr: [string, string]) =>
allLanguageKeys.some((lang) => attr[1].split('/')[1] === lang),
)
// Get the link path from the attribute
.map((attr: [string, string]) => attr[1])
// Create errors for each link path that includes a language code
for (const linkPath of hrefsMissingSlashes) {
const range = getRange(child.line, linkPath)
const languageCode = linkPath.split('/')[1]
const replaceChar = linkPath === `/${languageCode}` ? '/' : ''
addFixErrorDetail(
onError,
child.lineNumber,
linkPath.replace(`/${languageCode}`, replaceChar),
linkPath,
range,
{
lineNumber: child.lineNumber,
editColumn: child.line.indexOf(linkPath) + 1,
deleteCount: 3,
},
)
}
}
})
},
}