apos-docs
Version:
Documentation static site generator built with Eleventy.
119 lines (100 loc) • 3.95 kB
JavaScript
// markdown-it plugin for:
// 1. adding target="_blank" to external links
// 2. normalize internal links
const path = require('path')
module.exports = (md, opts) => {
let eleventyConfig = opts.eleventyConfig
let config = opts.config
let site = opts.site
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
const token = tokens[idx]
const hrefIndex = token.attrIndex('href')
if (hrefIndex >= 0) {
const hrefAttr = token.attrs[hrefIndex]
const url = hrefAttr[1]
const isOutbound = /^(?:[a-z]+:)?\/\//.test(url)
if (isOutbound) {
if (!site.url || !url.startsWith(site.url)) {
token.attrSet('target', '_blank')
token.attrSet('rel', 'noopener noreferrer')
}
} else if (!url.startsWith('#') && !url.startsWith('mailto:')) {
normalizeHref(hrefAttr, env, token, true, false)
}
}
return self.renderToken(tokens, idx, options)
}
const defaultRender = md.renderer.rules.image
md.renderer.rules.image = (tokens, idx, options, env, self) => {
const token = tokens[idx]
const hrefIndex = token.attrIndex('src')
if (hrefIndex >= 0) {
const hrefAttr = token.attrs[hrefIndex]
const url = hrefAttr[1]
const isOutbound = /^(?:[a-z]+:)?\/\//.test(url)
if (!isOutbound) {
normalizeHref(hrefAttr, env, token, false, true)
}
}
return defaultRender(tokens, idx, options, env, self)
}
function normalizeHref(hrefAttr, env, token, addAttr, isImage) {
let url = hrefAttr[1]
const parsed = new URL(url, 'http://a.com')
let cleanUrl = url.replace(/\#.*$/, '').replace(/\?.*$/, '')
applyBase = true
// TODO: It would be better if images outside the docs were copied into the docs folder to be hosted with the site.
let repo = isImage ? site.repo.replace('github', 'raw.githubusercontent').replace('/tree/', '/') : site.repo
// Remove markdown extension.
let isMarkdown = /(?:(readme))?.(md)$/i;
if (isMarkdown.test(cleanUrl)) {
cleanUrl = cleanUrl.replace(isMarkdown, "");
}
// Check if there's an extension.
let hasExt = /\.([0-9a-z]+)(?:[\?#]|$)/i;
if (!hasExt.test(cleanUrl)) {
// Add trailing slash if missing.
cleanUrl = cleanUrl.replace(/\/?(\?|#|$)/, '/$1');
}
// Fix absolute input links inside docs folder.
let isPageAbsolute = new RegExp(`^\/${site.docs}`);
if (isPageAbsolute.test(cleanUrl)) {
cleanUrl = cleanUrl.replace(isPageAbsolute, "");
} else {
let isAbsolute = /^\//
if (!isAbsolute.test(cleanUrl)) {
if (env.page.inputPath === `./${config.dir.input}/README.md`) {
cleanUrl = path.posix.join('/', path.posix.dirname(env.page.inputPath), '..', cleanUrl)
} else {
cleanUrl = path.posix.join('/', path.posix.dirname(env.page.inputPath), cleanUrl)
}
if (cleanUrl.startsWith(`/${config.dir.input}`)) {
cleanUrl = cleanUrl.replace(`/${config.dir.input}`, '')
} else if (cleanUrl === '/') {
} else {
// The url points somewhere in the repo outside the pages. Rewrite links to GitHub.
cleanUrl = cleanUrl.replace(/^\//, repo)
applyBase = false
if (addAttr) {
token.attrSet('target', '_blank')
token.attrSet('rel', 'noopener noreferrer')
}
}
} else if (!/^\/$/.test(cleanUrl)) { // Exclude '/'
// The url points somewhere in the repo outside the pages. Rewrite links to GitHub.
cleanUrl = cleanUrl.replace(/^\//, repo)
applyBase = false
if (addAttr) {
token.attrSet('target', '_blank')
token.attrSet('rel', 'noopener noreferrer')
}
}
}
url = cleanUrl + parsed.search + parsed.hash
url = decodeURI(url)
if (applyBase) {
url = eleventyConfig.getFilter("url")(url);
}
hrefAttr[1] = url
}
}