diff options
Diffstat (limited to 'node_modules/vuepress/lib/util')
| -rw-r--r-- | node_modules/vuepress/lib/util/index.js | 83 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/util/logger.js | 47 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/util/parseHeaders.js | 56 | ||||
| -rw-r--r-- | node_modules/vuepress/lib/util/shared.js | 7 |
4 files changed, 193 insertions, 0 deletions
diff --git a/node_modules/vuepress/lib/util/index.js b/node_modules/vuepress/lib/util/index.js new file mode 100644 index 00000000..52044a8f --- /dev/null +++ b/node_modules/vuepress/lib/util/index.js @@ -0,0 +1,83 @@ +const { deeplyParseHeaders } = require('./parseHeaders') + +exports.normalizeHeadTag = function (tag) { + if (typeof tag === 'string') { + tag = [tag] + } + const tagName = tag[0] + return { + tagName, + attributes: tag[1] || {}, + innerHTML: tag[2] || '', + closeTag: !(tagName === 'meta' || tagName === 'link') + } +} + +exports.applyUserWebpackConfig = function (userConfig, config, isServer) { + const merge = require('webpack-merge') + if (typeof userConfig === 'object') { + return merge(config, userConfig) + } + if (typeof userConfig === 'function') { + const res = userConfig(config, isServer) + if (res && typeof res === 'object') { + return merge(config, res) + } + } + return config +} + +exports.inferTitle = function (frontmatter) { + if (frontmatter.data.home) { + return 'Home' + } + if (frontmatter.data.title) { + return deeplyParseHeaders(frontmatter.data.title) + } + const match = frontmatter.content.trim().match(/^#+\s+(.*)/m) + if (match) { + return deeplyParseHeaders(match[1]) + } +} + +exports.parseFrontmatter = function (content) { + const matter = require('gray-matter') + const toml = require('toml') + + return matter(content, { + excerpt_separator: '<!-- more -->', + engines: { + toml: toml.parse.bind(toml), + excerpt: false + } + }) +} + +const LRU = require('lru-cache') +const cache = LRU({ max: 1000 }) + +exports.extractHeaders = function (content, include = [], md) { + const key = content + include.join(',') + const hit = cache.get(key) + if (hit) { + return hit + } + + const tokens = md.parse(content, {}) + + const res = [] + tokens.forEach((t, i) => { + if (t.type === 'heading_open' && include.includes(t.tag)) { + const title = tokens[i + 1].content + const slug = t.attrs.find(([name]) => name === 'id')[1] + res.push({ + level: parseInt(t.tag.slice(1), 10), + title: deeplyParseHeaders(title), + slug: slug || md.slugify(title) + }) + } + }) + + cache.set(key, res) + return res +} diff --git a/node_modules/vuepress/lib/util/logger.js b/node_modules/vuepress/lib/util/logger.js new file mode 100644 index 00000000..84e07e86 --- /dev/null +++ b/node_modules/vuepress/lib/util/logger.js @@ -0,0 +1,47 @@ +const chalk = require('chalk') + +const logger = {} + +const logTypes = { + success: { + color: 'green', + label: 'DONE' + }, + error: { + color: 'red', + label: 'FAIL' + }, + warn: { + color: 'yellow', + label: 'WARN' + }, + tip: { + color: 'cyan', + label: 'TIP' + }, + wait: { + color: 'blue', + label: 'WAIT' + } +} + +const getLoggerFn = (color, label) => (msg, log = true) => { + let newLine = false + if (msg.startsWith('\n')) { + if (log) msg = msg.slice(1) + newLine = true + } + msg = chalk.reset.inverse.bold[color](` ${label} `) + ' ' + msg + if (log) { + console.log(newLine ? '\n' + msg : msg) + } else { + return msg + } +} + +for (const type in logTypes) { + const { color, label } = logTypes[type] + logger[type] = getLoggerFn(color, label) +} + +module.exports = logger diff --git a/node_modules/vuepress/lib/util/parseHeaders.js b/node_modules/vuepress/lib/util/parseHeaders.js new file mode 100644 index 00000000..2c9fe641 --- /dev/null +++ b/node_modules/vuepress/lib/util/parseHeaders.js @@ -0,0 +1,56 @@ +// Since VuePress needs to extract the header from the markdown source +// file and display it in the sidebar or title (#238), this file simply +// removes some unnecessary elements to make header displays well at +// sidebar or title. +// +// But header's parsing in the markdown content is done by the markdown +// loader based on markdown-it. markdown-it parser will will always keep +// HTML in headers, so in VuePress, after being parsed by the markdiwn +// loader, the raw HTML in headers will finally be parsed by Vue-loader. +// so that we can write HTML/Vue in the header. One exception is the HTML +// wrapped by <code>(markdown token: '`') tag. + +const { compose } = require('./shared') + +const parseEmojis = str => { + const emojiData = require('markdown-it-emoji/lib/data/full.json') + return String(str).replace(/:(.+?):/g, (placeholder, key) => emojiData[key] || placeholder) +} + +const unescapeHtml = html => String(html) + .replace(/"/g, '"') + .replace(/'/g, '\'') + .replace(/:/g, ':') + .replace(/</g, '<') + .replace(/>/g, '>') + +const removeMarkdownTokens = str => String(str) + .replace(/\[(.*)\]\(.*\)/, '$1') // []() + .replace(/(`|\*{1,3}|_)(.*?[^\\])\1/g, '$2') // `{t}` | *{t}* | **{t}** | ***{t}*** | _{t}_ + .replace(/(\\)(\*|_|`|\!)/g, '$2') // remove escape char '\' + +const trim = str => str.trim() + +// This method remove the raw HTML but reserve the HTML wrapped by `<code>`. +// e.g. +// Input: "<a> b", Output: "b" +// Input: "`<a>` b", Output: "`<a>` b" +exports.removeNonCodeWrappedHTML = (str) => { + return String(str).replace(/(^|[^><`])<.*>([^><`]|$)/g, '$1$2') +} + +// Unescape html, parse emojis and remove some md tokens. +exports.parseHeaders = compose( + unescapeHtml, + parseEmojis, + removeMarkdownTokens, + trim +) + +// Also clean the html that isn't wrapped by code. +// Because we want to support using VUE components in headers. +// e.g. https://vuepress.vuejs.org/guide/using-vue.html#badge +exports.deeplyParseHeaders = compose( + exports.removeNonCodeWrappedHTML, + exports.parseHeaders, +) diff --git a/node_modules/vuepress/lib/util/shared.js b/node_modules/vuepress/lib/util/shared.js new file mode 100644 index 00000000..023f63bd --- /dev/null +++ b/node_modules/vuepress/lib/util/shared.js @@ -0,0 +1,7 @@ +exports.compose = (...processors) => { + if (processors.length === 0) return input => input + if (processors.length === 1) return processors[0] + return processors.reduce((prev, next) => { + return (...args) => next(prev(...args)) + }) +} |
