Skip to content

Commit

Permalink
feat: detect dead links
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Feb 17, 2021
1 parent f484f9a commit 74f5ada
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 14 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
2 changes: 1 addition & 1 deletion src/node/build/bundle.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
37 changes: 33 additions & 4 deletions src/node/markdownToVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ 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 })

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))
Expand All @@ -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),
Expand All @@ -59,7 +87,8 @@ export function createMarkdownToVueRenderFn(

const result = {
vueSrc,
pageData
pageData,
deadLinks
}
cache.set(src, result)
return result
Expand Down
19 changes: 15 additions & 4 deletions src/node/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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$/
Expand All @@ -24,18 +24,19 @@ 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$/],
...vueOptions
})

let siteData = site
let hasDeadLinks = false

const vitePressPlugin: Plugin = {
name: 'vitepress',
Expand Down Expand Up @@ -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.`)
}
},

Expand Down
3 changes: 3 additions & 0 deletions src/node/utils/slash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function slash(p: string): string {
return p.replace(/\\/g, '/')
}
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6090,10 +6090,10 @@ [email protected]:
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"
Expand Down

0 comments on commit 74f5ada

Please sign in to comment.