feat: detect dead links

pull/245/head
Evan You 4 years ago
parent f484f9a9e5
commit 74f5adafcd

@ -87,7 +87,6 @@
"polka": "^0.5.2",
"prismjs": "^1.23.0",
"sirv": "^1.0.11",
"slash": "^3.0.0",
"vite": "^2.0.0-beta.70",
"vue": "^3.0.5"
},

@ -1,6 +1,6 @@
import ora from 'ora'
import path from 'path'
import slash from 'slash'
import { slash } from '../utils/slash'
import { APP_PATH } from '../alias'
import { SiteConfig } from '../config'
import { RollupOutput } from 'rollup'

@ -5,7 +5,8 @@ import LRUCache from 'lru-cache'
import { createMarkdownRenderer, MarkdownOptions } from './markdown/markdown'
import { deeplyParseHeader } from './utils/parseHeader'
import { PageData, HeadConfig } from '../../types/shared'
import slash from 'slash'
import { slash } from './utils/slash'
import chalk from 'chalk'
const debug = require('debug')('vitepress:md')
const cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 })
@ -13,13 +14,16 @@ const cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 })
interface MarkdownCompileResult {
vueSrc: string
pageData: PageData
deadLinks: string[]
}
export function createMarkdownToVueRenderFn(
root: string,
options: MarkdownOptions = {}
options: MarkdownOptions = {},
pages: string[]
) {
const md = createMarkdownRenderer(root, options)
pages = pages.map((p) => slash(p.replace(/\.md$/, '')))
return (src: string, file: string): MarkdownCompileResult => {
const relativePath = slash(path.relative(root, file))
@ -40,7 +44,31 @@ export function createMarkdownToVueRenderFn(
.replace(/import\.meta/g, 'import.<wbr/>meta')
.replace(/process\.env/g, 'process.<wbr/>env')
// TODO validate data.links?
// validate data.links
const deadLinks = []
if (data.links) {
const dir = path.dirname(file)
for (let url of data.links) {
url = url.replace(/[?#].*$/, '').replace(/\.(html|md)$/, '')
if (url.endsWith('/')) url += `index`
const resolved = slash(
url.startsWith('/')
? url.slice(1)
: path.relative(root, path.resolve(dir, url))
)
if (!pages.includes(resolved)) {
console.warn(
chalk.yellow(
`\n(!) Found dead link ${chalk.cyan(
url
)} in file ${chalk.white.dim(file)}`
)
)
deadLinks.push(url)
}
}
}
const pageData: PageData = {
title: inferTitle(frontmatter, content),
description: inferDescription(frontmatter),
@ -59,7 +87,8 @@ export function createMarkdownToVueRenderFn(
const result = {
vueSrc,
pageData
pageData,
deadLinks
}
cache.set(src, result)
return result

@ -4,7 +4,7 @@ import { SiteConfig, resolveSiteData } from './config'
import { createMarkdownToVueRenderFn } from './markdownToVue'
import { APP_PATH, SITE_DATA_REQUEST_PATH } from './alias'
import createVuePlugin from '@vitejs/plugin-vue'
import slash from 'slash'
import { slash } from './utils/slash'
import { OutputAsset, OutputChunk } from 'rollup'
const hashRE = /\.(\w+)\.js$/
@ -24,11 +24,11 @@ const isPageChunk = (
export function createVitePressPlugin(
root: string,
{ configPath, alias, markdown, site, vueOptions }: SiteConfig,
{ configPath, alias, markdown, site, vueOptions, pages }: SiteConfig,
ssr = false,
pageToHashMap?: Record<string, string>
): Plugin[] {
const markdownToVue = createMarkdownToVueRenderFn(root, markdown)
const markdownToVue = createMarkdownToVueRenderFn(root, markdown, pages)
const vuePlugin = createVuePlugin({
include: [/\.vue$/, /\.md$/],
@ -36,6 +36,7 @@ export function createVitePressPlugin(
})
let siteData = site
let hasDeadLinks = false
const vitePressPlugin: Plugin = {
name: 'vitepress',
@ -71,7 +72,17 @@ export function createVitePressPlugin(
transform(code, id) {
if (id.endsWith('.md')) {
// transform .md files into vueSrc so plugin-vue can handle it
return markdownToVue(code, id).vueSrc
const { vueSrc, deadLinks } = markdownToVue(code, id)
if (deadLinks.length) {
hasDeadLinks = true
}
return vueSrc
}
},
renderStart() {
if (hasDeadLinks) {
throw new Error(`One or more pages contain dead links.`)
}
},

@ -0,0 +1,3 @@
export function slash(p: string): string {
return p.replace(/\\/g, '/')
}

@ -6090,10 +6090,10 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
vite@^2.0.0-beta.67:
version "2.0.0-beta.67"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.0.0-beta.67.tgz#2d4e7a62a925539448bd18154008afb2b4484a07"
integrity sha512-QNxIRajidVG3ejikBUb17NgCV1bJ9UyKHBdItgw1O/ljQ1hBoph5I2/DrviqV4G9H3WP7teXk5vwQWuCVS9fqQ==
vite@^2.0.0-beta.70:
version "2.0.0"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.0.0.tgz#156f35eadaa7947629aa8a24eb23129b07116ee3"
integrity sha512-rNli5g0DaQ6+btlRqkmaR06neWaJGApmt40gocqrYDNi2XoEXYQgKiHSWzMeUgc1Cdva2HduqazaE+RaKjBpdQ==
dependencies:
esbuild "^0.8.34"
postcss "^8.2.1"

Loading…
Cancel
Save