aboutsummaryrefslogtreecommitdiff
path: root/node_modules/vuepress/lib/prepare
diff options
context:
space:
mode:
authorruki <waruqi@gmail.com>2018-11-08 00:38:48 +0800
committerruki <waruqi@gmail.com>2018-11-07 21:53:09 +0800
commit26105034da4fcce7ac883c899d781f016559310d (patch)
treec459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/vuepress/lib/prepare
parent2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff)
downloadxmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz
xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip
switch to vuepress
Diffstat (limited to 'node_modules/vuepress/lib/prepare')
-rw-r--r--node_modules/vuepress/lib/prepare/codegen.js74
-rw-r--r--node_modules/vuepress/lib/prepare/index.js51
-rw-r--r--node_modules/vuepress/lib/prepare/loadConfig.js56
-rw-r--r--node_modules/vuepress/lib/prepare/resolveOptions.js194
-rw-r--r--node_modules/vuepress/lib/prepare/util.js80
5 files changed, 455 insertions, 0 deletions
diff --git a/node_modules/vuepress/lib/prepare/codegen.js b/node_modules/vuepress/lib/prepare/codegen.js
new file mode 100644
index 00000000..52e85355
--- /dev/null
+++ b/node_modules/vuepress/lib/prepare/codegen.js
@@ -0,0 +1,74 @@
+const path = require('path')
+const { fileToComponentName, resolveComponents } = require('./util')
+
+exports.genRoutesFile = async function ({
+ siteData: { pages },
+ sourceDir,
+ pageFiles
+}) {
+ function genRoute ({ path: pagePath, key: componentName }, index) {
+ const file = pageFiles[index]
+ const filePath = path.resolve(sourceDir, file)
+ let code = `
+ {
+ name: ${JSON.stringify(componentName)},
+ path: ${JSON.stringify(pagePath)},
+ component: ThemeLayout,
+ beforeEnter: (to, from, next) => {
+ import(${JSON.stringify(filePath)}).then(comp => {
+ Vue.component(${JSON.stringify(componentName)}, comp.default)
+ next()
+ })
+ }
+ }`
+
+ const dncodedPath = decodeURIComponent(pagePath)
+ if (dncodedPath !== pagePath) {
+ code += `,
+ {
+ path: ${JSON.stringify(dncodedPath)},
+ redirect: ${JSON.stringify(pagePath)}
+ }`
+ }
+
+ if (/\/$/.test(pagePath)) {
+ code += `,
+ {
+ path: ${JSON.stringify(pagePath + 'index.html')},
+ redirect: ${JSON.stringify(pagePath)}
+ }`
+ }
+
+ return code
+ }
+
+ const notFoundRoute = `,
+ {
+ path: '*',
+ component: ThemeNotFound
+ }`
+
+ return (
+ `import ThemeLayout from '@themeLayout'\n` +
+ `import ThemeNotFound from '@themeNotFound'\n` +
+ `import { injectMixins } from '@app/util'\n` +
+ `import rootMixins from '@app/root-mixins'\n\n` +
+ `injectMixins(ThemeLayout, rootMixins)\n` +
+ `injectMixins(ThemeNotFound, rootMixins)\n\n` +
+ `export const routes = [${pages.map(genRoute).join(',')}${notFoundRoute}\n]`
+ )
+}
+
+exports.genComponentRegistrationFile = async function ({ sourceDir }) {
+ function genImport (file) {
+ const name = fileToComponentName(file)
+ const baseDir = path.resolve(sourceDir, '.vuepress/components')
+ const absolutePath = path.resolve(baseDir, file)
+ const code = `Vue.component(${JSON.stringify(name)}, () => import(${JSON.stringify(absolutePath)}))`
+ return code
+ }
+
+ const components = (await resolveComponents(sourceDir)) || []
+ return `import Vue from 'vue'\n` + components.map(genImport).join('\n')
+}
+
diff --git a/node_modules/vuepress/lib/prepare/index.js b/node_modules/vuepress/lib/prepare/index.js
new file mode 100644
index 00000000..7561f791
--- /dev/null
+++ b/node_modules/vuepress/lib/prepare/index.js
@@ -0,0 +1,51 @@
+const path = require('path')
+const fs = require('fs-extra')
+const resolveOptions = require('./resolveOptions')
+const { genRoutesFile, genComponentRegistrationFile } = require('./codegen')
+const { writeTemp, writeEnhanceTemp } = require('./util')
+const logger = require('../util/logger')
+const chalk = require('chalk')
+
+module.exports = async function prepare (sourceDir) {
+ // 1. load options
+ const options = await resolveOptions(sourceDir)
+
+ // 2. generate routes & user components registration code
+ const routesCode = await genRoutesFile(options)
+ const componentCode = await genComponentRegistrationFile(options)
+
+ await writeTemp('routes.js', [
+ componentCode,
+ routesCode
+ ].join('\n'))
+
+ // 3. generate siteData
+ const dataCode = `export const siteData = ${JSON.stringify(options.siteData, null, 2)}`
+ await writeTemp('siteData.js', dataCode)
+
+ // 4. handle user override
+ const overridePath = path.resolve(sourceDir, '.vuepress/override.styl').replace(/[\\]+/g, '/')
+ const hasUserOverride = fs.existsSync(overridePath)
+ await writeTemp('override.styl', hasUserOverride ? `@import(${JSON.stringify(overridePath)})` : ``)
+
+ const stylePath = path.resolve(sourceDir, '.vuepress/style.styl').replace(/[\\]+/g, '/')
+ const hasUserStyle = fs.existsSync(stylePath)
+ await writeTemp('style.styl', hasUserStyle ? `@import(${JSON.stringify(stylePath)})` : ``)
+
+ // Temporary tip, will be removed at next release.
+ if (hasUserOverride && !hasUserStyle) {
+ logger.tip(
+ `${chalk.magenta('override.styl')} has been split into 2 APIs, we recommend you upgrade to continue.\n` +
+ ` See: ${chalk.magenta('https://vuepress.vuejs.org/default-theme-config/#simple-css-override')}`
+ )
+ }
+
+ // 5. handle enhanceApp.js
+ const enhanceAppPath = path.resolve(sourceDir, '.vuepress/enhanceApp.js')
+ await writeEnhanceTemp('enhanceApp.js', enhanceAppPath)
+
+ // 6. handle the theme enhanceApp.js
+ await writeEnhanceTemp('themeEnhanceApp.js', options.themeEnhanceAppPath)
+
+ return options
+}
diff --git a/node_modules/vuepress/lib/prepare/loadConfig.js b/node_modules/vuepress/lib/prepare/loadConfig.js
new file mode 100644
index 00000000..aa913ba0
--- /dev/null
+++ b/node_modules/vuepress/lib/prepare/loadConfig.js
@@ -0,0 +1,56 @@
+const fs = require('fs-extra')
+const path = require('path')
+const yamlParser = require('js-yaml')
+const tomlParser = require('toml')
+
+module.exports = function loadConfig (vuepressDir, bustCache = true) {
+ const configPath = path.resolve(vuepressDir, 'config.js')
+ const configYmlPath = path.resolve(vuepressDir, 'config.yml')
+ const configTomlPath = path.resolve(vuepressDir, 'config.toml')
+
+ if (bustCache) {
+ delete require.cache[configPath]
+ }
+
+ // resolve siteConfig
+ let siteConfig = {}
+ if (fs.existsSync(configYmlPath)) {
+ siteConfig = parseConfig(configYmlPath)
+ } else if (fs.existsSync(configTomlPath)) {
+ siteConfig = parseConfig(configTomlPath)
+ } else if (fs.existsSync(configPath)) {
+ siteConfig = require(configPath)
+ }
+
+ return siteConfig
+}
+
+function parseConfig (file) {
+ const content = fs.readFileSync(file, 'utf-8')
+ const [extension] = /.\w+$/.exec(file)
+ let data
+
+ switch (extension) {
+ case '.yml':
+ case '.yaml':
+ data = yamlParser.safeLoad(content)
+ break
+
+ case '.toml':
+ data = tomlParser.parse(content)
+ // reformat to match config since TOML does not allow different data type
+ // https://github.com/toml-lang/toml#array
+ const format = []
+ if (data.head) {
+ Object.keys(data.head).forEach(meta => {
+ data.head[meta].forEach(values => {
+ format.push([meta, values])
+ })
+ })
+ }
+ data.head = format
+ break
+ }
+
+ return data || {}
+}
diff --git a/node_modules/vuepress/lib/prepare/resolveOptions.js b/node_modules/vuepress/lib/prepare/resolveOptions.js
new file mode 100644
index 00000000..9b97ca8e
--- /dev/null
+++ b/node_modules/vuepress/lib/prepare/resolveOptions.js
@@ -0,0 +1,194 @@
+const fs = require('fs-extra')
+const path = require('path')
+const globby = require('globby')
+const createMarkdown = require('../markdown')
+const loadConfig = require('./loadConfig')
+const { encodePath, fileToPath, sort, getGitLastUpdatedTimeStamp } = require('./util')
+const {
+ inferTitle,
+ extractHeaders,
+ parseFrontmatter
+} = require('../util/index')
+
+module.exports = async function resolveOptions (sourceDir) {
+ const vuepressDir = path.resolve(sourceDir, '.vuepress')
+ const siteConfig = loadConfig(vuepressDir)
+
+ // normalize head tag urls for base
+ const base = siteConfig.base || '/'
+ if (base !== '/' && siteConfig.head) {
+ siteConfig.head.forEach(tag => {
+ const attrs = tag[1]
+ if (attrs) {
+ for (const name in attrs) {
+ if (name === 'src' || name === 'href') {
+ const value = attrs[name]
+ if (value.charAt(0) === '/') {
+ attrs[name] = base + value.slice(1)
+ }
+ }
+ }
+ }
+ })
+ }
+
+ // resolve outDir
+ const outDir = siteConfig.dest
+ ? path.resolve(siteConfig.dest)
+ : path.resolve(sourceDir, '.vuepress/dist')
+
+ // resolve theme
+ const useDefaultTheme = (
+ !siteConfig.theme &&
+ !fs.existsSync(path.resolve(vuepressDir, 'theme'))
+ )
+ const defaultThemePath = path.resolve(__dirname, '../default-theme')
+ let themePath = null
+ let themeLayoutPath = null
+ let themeNotFoundPath = null
+ let themeEnhanceAppPath = null
+
+ if (useDefaultTheme) {
+ // use default theme
+ themePath = defaultThemePath
+ themeLayoutPath = path.resolve(defaultThemePath, 'Layout.vue')
+ themeNotFoundPath = path.resolve(defaultThemePath, 'NotFound.vue')
+ } else {
+ // resolve theme Layout
+ if (siteConfig.theme) {
+ // use external theme
+ try {
+ themeLayoutPath = require.resolve(`vuepress-theme-${siteConfig.theme}/Layout.vue`, {
+ paths: [
+ path.resolve(__dirname, '../../node_modules'),
+ path.resolve(sourceDir)
+ ]
+ })
+ themePath = path.dirname(themeLayoutPath)
+ } catch (e) {
+ throw new Error(`[vuepress] Failed to load custom theme "${
+ siteConfig.theme
+ }". File vuepress-theme-${siteConfig.theme}/Layout.vue does not exist.`)
+ }
+ } else {
+ // use custom theme
+ themePath = path.resolve(vuepressDir, 'theme')
+ themeLayoutPath = path.resolve(themePath, 'Layout.vue')
+ if (!fs.existsSync(themeLayoutPath)) {
+ throw new Error(`[vuepress] Cannot resolve Layout.vue file in .vuepress/theme.`)
+ }
+ }
+
+ // resolve theme NotFound
+ themeNotFoundPath = path.resolve(themePath, 'NotFound.vue')
+ if (!fs.existsSync(themeNotFoundPath)) {
+ themeNotFoundPath = path.resolve(defaultThemePath, 'NotFound.vue')
+ }
+
+ // resolve theme enhanceApp
+ themeEnhanceAppPath = path.resolve(themePath, 'enhanceApp.js')
+ if (!fs.existsSync(themeEnhanceAppPath)) {
+ themeEnhanceAppPath = null
+ }
+ }
+
+ // resolve theme config
+ const themeConfig = siteConfig.themeConfig || {}
+
+ // resolve algolia
+ const isAlgoliaSearch = (
+ themeConfig.algolia ||
+ Object.keys(siteConfig.locales && themeConfig.locales || {})
+ .some(base => themeConfig.locales[base].algolia)
+ )
+
+ // resolve markdown
+ const markdown = createMarkdown(siteConfig)
+
+ // resolve pageFiles
+ const patterns = ['**/*.md', '!.vuepress', '!node_modules']
+ if (siteConfig.dest) {
+ // #654 exclude dest folder when dest dir was set in
+ // sourceDir but not in '.vuepress'
+ const outDirRelative = path.relative(sourceDir, outDir)
+ if (!outDirRelative.includes('..')) {
+ patterns.push('!' + outDirRelative)
+ }
+ }
+ const pageFiles = sort(await globby(patterns, { cwd: sourceDir }))
+
+ // resolve lastUpdated
+ const shouldResolveLastUpdated = (
+ themeConfig.lastUpdated ||
+ Object.keys(siteConfig.locales && themeConfig.locales || {})
+ .some(base => themeConfig.locales[base].lastUpdated)
+ )
+
+ // resolve pagesData
+ const pagesData = await Promise.all(pageFiles.map(async (file) => {
+ const filepath = path.resolve(sourceDir, file)
+ const key = 'v-' + Math.random().toString(16).slice(2)
+ const data = {
+ key,
+ path: encodePath(fileToPath(file))
+ }
+
+ if (shouldResolveLastUpdated) {
+ data.lastUpdated = getGitLastUpdatedTimeStamp(filepath)
+ }
+
+ // extract yaml frontmatter
+ const content = await fs.readFile(filepath, 'utf-8')
+ const frontmatter = parseFrontmatter(content)
+ // infer title
+ const title = inferTitle(frontmatter)
+ if (title) {
+ data.title = title
+ }
+ const headers = extractHeaders(
+ frontmatter.content,
+ ['h2', 'h3'],
+ markdown
+ )
+ if (headers.length) {
+ data.headers = headers
+ }
+ if (Object.keys(frontmatter.data).length) {
+ data.frontmatter = frontmatter.data
+ }
+ if (frontmatter.excerpt) {
+ const { html } = markdown.render(frontmatter.excerpt)
+ data.excerpt = html
+ }
+ return data
+ }))
+
+ // resolve site data
+ const siteData = {
+ title: siteConfig.title || '',
+ description: siteConfig.description || '',
+ base,
+ pages: pagesData,
+ themeConfig,
+ locales: siteConfig.locales
+ }
+
+ const options = {
+ siteConfig,
+ siteData,
+ sourceDir,
+ outDir,
+ publicPath: base,
+ pageFiles,
+ pagesData,
+ themePath,
+ themeLayoutPath,
+ themeNotFoundPath,
+ themeEnhanceAppPath,
+ useDefaultTheme,
+ isAlgoliaSearch,
+ markdown
+ }
+
+ return options
+}
diff --git a/node_modules/vuepress/lib/prepare/util.js b/node_modules/vuepress/lib/prepare/util.js
new file mode 100644
index 00000000..efa96cc9
--- /dev/null
+++ b/node_modules/vuepress/lib/prepare/util.js
@@ -0,0 +1,80 @@
+const path = require('path')
+const spawn = require('cross-spawn')
+const fs = require('fs-extra')
+const globby = require('globby')
+
+const tempPath = path.resolve(__dirname, '../app/.temp')
+fs.ensureDirSync(tempPath)
+
+const tempCache = new Map()
+exports.writeTemp = async function (file, content) {
+ // cache write to avoid hitting the dist if it didn't change
+ const cached = tempCache.get(file)
+ if (cached !== content) {
+ await fs.writeFile(path.join(tempPath, file), content)
+ tempCache.set(file, content)
+ }
+}
+
+exports.writeEnhanceTemp = async function (destName, srcPath) {
+ await exports.writeTemp(
+ destName,
+ fs.existsSync(srcPath)
+ ? `export { default } from ${JSON.stringify(srcPath)}`
+ : `export default function () {}`
+ )
+}
+
+const indexRE = /(^|.*\/)(index|readme)\.md$/i
+const extRE = /\.(vue|md)$/
+
+exports.fileToPath = function (file) {
+ if (exports.isIndexFile(file)) {
+ // README.md -> /
+ // foo/README.md -> /foo/
+ return file.replace(indexRE, '/$1')
+ } else {
+ // foo.md -> /foo.html
+ // foo/bar.md -> /foo/bar.html
+ return `/${file.replace(extRE, '').replace(/\\/g, '/')}.html`
+ }
+}
+
+exports.fileToComponentName = function (file) {
+ let normalizedName = file
+ .replace(/\/|\\/g, '-')
+ .replace(extRE, '')
+ if (exports.isIndexFile(file)) {
+ normalizedName = normalizedName.replace(/readme$/i, 'index')
+ }
+ const pagePrefix = /\.md$/.test(file) ? `page-` : ``
+ return `${pagePrefix}${normalizedName}`
+}
+
+exports.isIndexFile = function (file) {
+ return indexRE.test(file)
+}
+
+exports.resolveComponents = async function (sourceDir) {
+ const componentDir = path.resolve(sourceDir, '.vuepress/components')
+ if (!fs.existsSync(componentDir)) {
+ return
+ }
+ return exports.sort(await globby(['**/*.vue'], { cwd: componentDir }))
+}
+
+exports.sort = function (arr) {
+ return arr.sort((a, b) => {
+ if (a < b) return -1
+ if (a > b) return 1
+ return 0
+ })
+}
+
+exports.encodePath = function (userpath) {
+ return userpath.split('/').map(item => encodeURIComponent(item)).join('/')
+}
+
+exports.getGitLastUpdatedTimeStamp = function (filepath) {
+ return parseInt(spawn.sync('git', ['log', '-1', '--format=%ct', filepath]).stdout.toString('utf-8')) * 1000
+}