mirror of
https://github.com/wahyd4/vuepress.git
synced 2026-08-09 05:16:23 +10:00
153 lines
3.8 KiB
JavaScript
153 lines
3.8 KiB
JavaScript
const { logger, fs, path: { resolve }} = require('@vuepress/shared-utils')
|
|
const readdirSync = dir => fs.existsSync(dir) && fs.readdirSync(dir) || []
|
|
|
|
module.exports = class ThemeAPI {
|
|
constructor (theme, parentTheme) {
|
|
this.theme = theme
|
|
this.parentTheme = parentTheme || {}
|
|
this.existsParentTheme = !!this.parentTheme.path
|
|
this.vuepressPlugin = {
|
|
name: '@vuepress/internal-theme-api',
|
|
alias: {}
|
|
}
|
|
this.init()
|
|
}
|
|
|
|
setAlias (alias) {
|
|
this.vuepressPlugin.alias = {
|
|
...this.vuepressPlugin.alias,
|
|
...alias
|
|
}
|
|
}
|
|
|
|
init () {
|
|
const alias = {
|
|
'@current-theme': this.theme.path
|
|
}
|
|
if (this.existsParentTheme) {
|
|
alias['@parent-theme'] = this.parentTheme.path
|
|
}
|
|
this.componentMap = this.getComponents()
|
|
this.layoutComponentMap = this.getLayoutComponentMap()
|
|
|
|
Object.keys(this.componentMap).forEach((name) => {
|
|
const { filename, path } = this.componentMap[name]
|
|
alias[`@theme/components/${filename}`] = path
|
|
})
|
|
|
|
Object.keys(this.layoutComponentMap).forEach((name) => {
|
|
const { filename, path } = this.layoutComponentMap[name]
|
|
alias[`@theme/layouts/${filename}`] = path
|
|
})
|
|
alias['@theme'] = this.theme.path
|
|
this.setAlias(alias)
|
|
}
|
|
|
|
getComponents () {
|
|
const componentDirs = [
|
|
resolve(this.theme.path, 'components')
|
|
]
|
|
if (this.existsParentTheme) {
|
|
componentDirs.unshift(
|
|
resolve(this.parentTheme.path, 'components'),
|
|
)
|
|
}
|
|
return resolveSFCs(componentDirs)
|
|
}
|
|
|
|
getLayoutComponentMap () {
|
|
const layoutDirs = [
|
|
resolve(this.theme.path, '.'),
|
|
resolve(this.theme.path, 'layouts')
|
|
]
|
|
if (this.existsParentTheme) {
|
|
layoutDirs.unshift(
|
|
resolve(this.parentTheme.path, '.'),
|
|
resolve(this.parentTheme.path, 'layouts'),
|
|
)
|
|
}
|
|
// built-in named layout or not.
|
|
const layoutComponentMap = resolveSFCs(layoutDirs)
|
|
|
|
const { Layout = {}, NotFound = {}} = layoutComponentMap
|
|
// layout component does not exist.
|
|
if (!Layout || !fs.existsSync(Layout.path)) {
|
|
const fallbackLayoutPath = resolve(__dirname, 'Layout.fallback.vue')
|
|
layoutComponentMap.Layout = {
|
|
filename: 'Layout.vue',
|
|
componentName: 'Layout',
|
|
path: fallbackLayoutPath,
|
|
isInternal: true
|
|
}
|
|
logger.warn(
|
|
`[vuepress] Cannot resolve Layout.vue file in \n ${Layout.path},`
|
|
+ `fallback to default layout: ${fallbackLayoutPath}`
|
|
)
|
|
}
|
|
if (!NotFound || !fs.existsSync(NotFound.path)) {
|
|
layoutComponentMap.NotFound = {
|
|
filename: 'NotFound.vue',
|
|
componentName: 'NotFound',
|
|
path: resolve(__dirname, '../app/components/NotFound.vue'),
|
|
isInternal: true
|
|
}
|
|
}
|
|
return layoutComponentMap
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resolve Vue SFCs, return a Map
|
|
*
|
|
* @param dirs
|
|
* @returns {*}
|
|
*/
|
|
|
|
function resolveSFCs (dirs) {
|
|
return dirs.map(
|
|
layoutDir => readdirSync(layoutDir)
|
|
.filter(filename => filename.endsWith('.vue'))
|
|
.map(filename => {
|
|
const componentName = getComponentName(filename)
|
|
return {
|
|
filename,
|
|
componentName,
|
|
isInternal: isInternal(componentName),
|
|
path: resolve(layoutDir, filename)
|
|
}
|
|
})
|
|
).reduce((arr, next) => {
|
|
arr.push(...next)
|
|
return arr
|
|
}, []).reduce((map, component) => {
|
|
map[component.componentName] = component
|
|
return map
|
|
}, {})
|
|
}
|
|
|
|
/**
|
|
* normalize component name
|
|
*
|
|
* @param {strin} filename
|
|
* @returns {string}
|
|
*/
|
|
|
|
function getComponentName (filename) {
|
|
filename = filename.slice(0, -4)
|
|
if (filename === '404') {
|
|
filename = 'NotFound'
|
|
}
|
|
return filename
|
|
}
|
|
|
|
/**
|
|
* Whether it's agreed layout component
|
|
*
|
|
* @param name
|
|
* @returns {boolean}
|
|
*/
|
|
|
|
function isInternal (name) {
|
|
return name === 'Layout' || name === 'NotFound'
|
|
}
|