Files
vuepress/packages/@vuepress/markdown/index.js
T

172 lines
4.0 KiB
JavaScript

'use strict'
/**
* Module dependencies.
*/
const Config = require('markdown-it-chain')
const LRUCache = require('lru-cache')
const highlight = require('./lib/highlight')
const { PLUGINS, REQUIRED_PLUGINS } = require('./lib/constant')
const highlightLinesPlugin = require('./lib/highlightLines')
const preWrapperPlugin = require('./lib/preWrapper')
const lineNumbersPlugin = require('./lib/lineNumbers')
const componentPlugin = require('./lib/component')
const hoistScriptStylePlugin = require('./lib/hoist')
const convertRouterLinkPlugin = require('./lib/link')
const snippetPlugin = require('./lib/snippet')
const tocPlugin = require('./lib/tableOfContents')
const emojiPlugin = require('markdown-it-emoji')
const anchorPlugin = require('markdown-it-anchor')
const { slugify: _slugify, logger, chalk, hash } = require('@vuepress/shared-utils')
/**
* Create markdown by config.
*/
module.exports = (markdown = {}) => {
const {
externalLinks,
anchor,
toc,
lineNumbers,
beforeInstantiate,
afterInstantiate
} = markdown
// allow user config slugify
const slugify = markdown.slugify || _slugify
// using chainedAPI
const config = new Config()
config
.options
.html(true)
.highlight(highlight)
.end()
.plugin(PLUGINS.COMPONENT)
.use(componentPlugin)
.end()
.plugin(PLUGINS.HIGHLIGHT_LINES)
.use(highlightLinesPlugin)
.end()
.plugin(PLUGINS.PRE_WRAPPER)
.use(preWrapperPlugin)
.end()
.plugin(PLUGINS.SNIPPET)
.use(snippetPlugin)
.end()
.plugin(PLUGINS.CONVERT_ROUTER_LINK)
.use(convertRouterLinkPlugin, [Object.assign({
target: '_blank',
rel: 'noopener noreferrer'
}, externalLinks)])
.end()
.plugin(PLUGINS.HOIST_SCRIPT_STYLE)
.use(hoistScriptStylePlugin)
.end()
.plugin(PLUGINS.EMOJI)
.use(emojiPlugin)
.end()
.plugin(PLUGINS.ANCHOR)
.use(anchorPlugin, [Object.assign({
slugify,
permalink: true,
permalinkBefore: true,
permalinkSymbol: '#'
}, anchor)])
.end()
.plugin(PLUGINS.TOC)
.use(tocPlugin, [toc])
.end()
if (lineNumbers) {
config
.plugin(PLUGINS.LINE_NUMBERS)
.use(lineNumbersPlugin)
}
beforeInstantiate && beforeInstantiate(config)
const md = config.toMd(require('markdown-it'), markdown)
afterInstantiate && afterInstantiate(md)
// override parse to allow cache
const parse = md.parse
const cache = new LRUCache({ max: 1000 })
md.parse = (src, env) => {
const key = hash(src + env.relPath)
const cached = cache.get(key)
if (cached) {
return cached
} else {
const tokens = parse.call(md, src, env)
cache.set(key, tokens)
return tokens
}
}
module.exports.dataReturnable(md)
// expose slugify
md.slugify = slugify
return md
}
module.exports.dataReturnable = function dataReturnable (md) {
// override render to allow custom plugins return data
const render = md.render
md.render = (...args) => {
md.$data = {}
md.$data.__data_block = {}
md.$dataBlock = md.$data.__data_block
const html = render.call(md, ...args)
return {
html,
data: md.$data,
dataBlockString: toDataBlockString(md.$dataBlock)
}
}
}
function toDataBlockString (ob) {
if (Object.keys(ob).length === 0) {
return ''
}
return `<data>${JSON.stringify(ob)}</data>`
}
function isRequiredPlugin (plugin) {
return REQUIRED_PLUGINS.includes(plugin)
}
function removePlugin (config, plugin) {
logger.debug(`Built-in markdown-it plugin ${chalk.green(plugin)} was removed.`)
config.plugins.delete(plugin)
}
function removeAllBuiltInPlugins (config) {
Object.keys(PLUGINS).forEach(key => {
if (!isRequiredPlugin(PLUGINS[key])) {
removePlugin(config, PLUGINS[key])
}
})
}
module.exports.isRequiredPlugin = isRequiredPlugin
module.exports.removePlugin = removePlugin
module.exports.removeAllBuiltInPlugins = removeAllBuiltInPlugins
module.exports.PLUGINS = PLUGINS