-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
Copy pathloadTheme.js
executable file
·118 lines (104 loc) · 3.33 KB
/
loadTheme.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
'use strict'
/**
* Module dependencies.
*/
const {
fs,
path: { resolve, parse },
moduleResolver: { getThemeResolver },
datatypes: { isString },
logger, chalk
} = require('@vuepress/shared-utils')
const ThemeAPI = require('./theme-api')
/**
* Resolve theme.
*
* Resolving Priority:
*
* 1. If the theme was a absolute path and that path exists, respect it
* as the theme directory.
* 2. If 'theme' directory located at vuepressDir exists, respect it as
* the theme directory.
* 3. If 'theme' was a shortcut string, resolve it from deps.
*
* @param {string} theme
* @param {string} sourceDir
* @param {string} vuepressDir
* @returns {ThemeAPI}
*/
module.exports = function loadTheme (ctx) {
const themeResolver = getThemeResolver()
const theme = resolveTheme(ctx, themeResolver)
if (!theme.path) {
throw new Error(`[vuepress] You must specify a theme, or create a local custom theme. \n For more details, refer to https://vuepress.vuejs.org/guide/custom-themes.html#custom-themes. \n`)
}
let applyTip = `Apply theme ${chalk.magenta(theme.name)}`
theme.entry.name = '@vuepress/internal-theme-entry-file'
let parentTheme = {}
if (theme.entry.extend) {
parentTheme = resolveTheme(ctx, themeResolver, true, theme.entry.extend)
parentTheme.entry.name = '@vuepress/internal-parent-theme-entry-file'
applyTip += chalk.gray(` (extends ${chalk.magenta(parentTheme.name)})`)
}
logger.tip(applyTip + ' ...')
logger.debug('theme', theme.name, theme.path)
logger.debug('parentTheme', parentTheme.name, parentTheme.path)
return new ThemeAPI(theme, parentTheme, ctx)
}
function normalizeThemePath (resolved) {
const { entry, name, fromDep } = resolved
if (fromDep) {
const packageRoot = require.resolve(`${name}/package.json`)
const { main } = require(packageRoot)
if (main.endsWith('.vue')) {
// For those cases that "main" field is set to an non-index file
// e.g. `layouts/Layout.vue`
return packageRoot
} else {
// For those cases that "index.js" is not at package root
// e.g. `lib/index.js` (#1362)
return parse(require.resolve(name)).dir
}
} else if (entry.endsWith('.js') || entry.endsWith('.vue')) {
return parse(entry).dir
} else {
return entry
}
}
function resolveTheme (ctx, resolver, ignoreLocal, theme) {
const { siteConfig, options, sourceDir, vuepressDir, pluginAPI } = ctx
const localThemePath = resolve(vuepressDir, 'theme')
theme = theme || siteConfig.theme || options.theme
let path
let name
let shortcut
let entry = {}
// 1. From local
if (!ignoreLocal
&& !fs.existsSync(theme)
&& fs.existsSync(localThemePath)
&& (fs.readdirSync(localThemePath)).length > 0
) {
path = localThemePath
name = shortcut = 'local'
logger.tip(`Apply local theme at ${chalk.gray(path)}...`)
// 2. From dep
} else if (isString(theme)) {
const resolved = resolver.resolve(theme, sourceDir)
if (resolved.entry === null) {
throw new Error(`Cannot resolve theme: ${theme}.`)
}
path = normalizeThemePath(resolved)
name = resolved.name
shortcut = resolved.shortcut
} else {
return {}
}
try {
entry = pluginAPI.normalizePlugin('theme', path, ctx.themeConfig)
} catch (e) {
logger.warn(e.message)
entry = {}
}
return { path, name, shortcut, entry }
}