Skip to content

Commit 80cb1d5

Browse files
committed
refactor: shortcutPackageResolver
1 parent d6c3832 commit 80cb1d5

File tree

13 files changed

+476
-251
lines changed

13 files changed

+476
-251
lines changed

packages/@vuepress/core/lib/plugin-api/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const instantiateOption = require('./override/instantiateOption')
88
const { flattenPlugin, normalizePluginsConfig } = require('./util')
99
const { PLUGIN_OPTION_MAP } = require('./constants')
1010
const {
11-
shortcutPackageResolver: { resolvePlugin },
11+
moduleResolver: { getPluginResolver },
1212
datatypes: { assertTypes, isPlainObject },
1313
env: { isDebug },
1414
logger, chalk
@@ -24,6 +24,7 @@ module.exports = class PluginAPI {
2424
this._pluginContext = context
2525
this._pluginQueue = []
2626
this._initialized = false
27+
this._pluginResolver = getPluginResolver()
2728
this.initializeOptions(PLUGIN_OPTION_MAP)
2829
}
2930

@@ -113,8 +114,8 @@ module.exports = class PluginAPI {
113114
*/
114115

115116
normalizePlugin (pluginRaw, pluginOptions = {}) {
116-
let plugin = resolvePlugin(pluginRaw)
117-
if (!plugin.module) {
117+
let plugin = this._pluginResolver.resolve(pluginRaw)
118+
if (!plugin.entry) {
118119
console.warn(`[vuepress] cannot resolve plugin "${pluginRaw}"`)
119120
return this
120121
}

packages/@vuepress/core/lib/plugin-api/util.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const { logger, chalk, datatypes: { assertTypes }} = require('@vuepress/shared-u
88

99
/**
1010
* flatten your plugin config by passing in name, options and context.
11+
*
1112
* @param {function|object} module
1213
* @param {string} name
1314
* @param {string} hortcut
@@ -16,7 +17,7 @@ const { logger, chalk, datatypes: { assertTypes }} = require('@vuepress/shared-u
1617
*/
1718

1819
exports.flattenPlugin = function (
19-
{ module: config, name, shortcut, isLocal },
20+
{ entry: config, name, shortcut, fromDep },
2021
pluginOptions,
2122
pluginContext,
2223
self
@@ -45,17 +46,18 @@ exports.flattenPlugin = function (
4546
}
4647

4748
// respect name in local plugin config
48-
name = isLocal && config.name || name
49+
name = fromDep && name || config.name
4950
return Object.assign({}, config, {
5051
name,
51-
shortcut: isLocal ? null : shortcut,
52+
shortcut: fromDep ? shortcut : null,
5253
enabled,
5354
$$options: pluginOptions /* used for test */
5455
})
5556
}
5657

5758
/**
5859
* Normalize plugins config in `.vuepress/config.js`
60+
*
5961
* @param pluginsConfig
6062
*/
6163

packages/@vuepress/core/lib/prepare/loadTheme.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
const {
88
fs, path,
9-
shortcutPackageResolver: { resolveTheme },
9+
moduleResolver: { getThemeResolver },
1010
datatypes: { isString },
1111
logger, chalk
1212
} = require('@vuepress/shared-utils')
@@ -31,6 +31,7 @@ const {
3131
module.exports = async function loadTheme (ctx) {
3232
const { siteConfig, cliOptions, sourceDir, vuepressDir, pluginAPI } = ctx
3333
const theme = siteConfig.theme || cliOptions.theme
34+
const themeResolver = getThemeResolver()
3435

3536
const localThemePath = path.resolve(vuepressDir, 'theme')
3637
const useLocalTheme =
@@ -47,7 +48,8 @@ module.exports = async function loadTheme (ctx) {
4748
themePath = localThemePath
4849
logger.tip(`\nApply theme located at ${chalk.gray(themePath)}...`)
4950
} else if (isString(theme)) {
50-
const { module: modulePath, name, shortcut } = resolveTheme(theme, sourceDir)
51+
const { entry: modulePath, name, shortcut } = themeResolver.resolve(theme, sourceDir)
52+
5153
if (modulePath.endsWith('.js') || modulePath.endsWith('.vue')) {
5254
themePath = path.parse(modulePath).dir
5355
} else {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
name: 'a'
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
jest.mock('vuepress-plugin-a')
2+
jest.mock('@org/vuepress-plugin-a')
3+
jest.mock('@vuepress/plugin-a')
4+
5+
jest.mock('vuepress-theme-a')
6+
jest.mock('@org/vuepress-theme-a')
7+
jest.mock('@vuepress/theme-a')
8+
9+
import path from 'path'
10+
import {
11+
getThemeResolver,
12+
getPluginResolver,
13+
resolveScopePackage
14+
} from '../lib/moduleResolver'
15+
import hash from 'hash-sum'
16+
17+
const MOCK_RELATIVE = '../../../../__mocks__'
18+
19+
function loadMockModule (name) {
20+
return require(`${MOCK_RELATIVE}/${name}`)
21+
}
22+
23+
function resolveMockModule (name) {
24+
return path.resolve(__dirname, `${MOCK_RELATIVE}/${name}`)
25+
}
26+
27+
const fixturesDir = path.resolve(__dirname, 'fixtures')
28+
const themeResolver = getThemeResolver(fixturesDir)
29+
const pluginResolver = getPluginResolver(fixturesDir)
30+
31+
const prevCwd = process.cwd()
32+
beforeAll(() => {
33+
process.chdir(path.resolve(__dirname, 'fixtures'))
34+
})
35+
36+
afterAll(() => {
37+
process.chdir(prevCwd)
38+
})
39+
40+
describe('resolveScopePackage', () => {
41+
test('corrent format', () => {
42+
const pkg = resolveScopePackage('@vuepress/plugin-a')
43+
expect(pkg.org).toBe('vuepress')
44+
expect(pkg.name).toBe('plugin-a')
45+
})
46+
47+
test('incorrect format', () => {
48+
const pkg2 = resolveScopePackage('vuepress/plugin-a')
49+
expect(pkg2).toBe(null)
50+
51+
const pkg3 = resolveScopePackage('vuepress-plugin-a')
52+
expect(pkg3).toBe(null)
53+
})
54+
})
55+
56+
const getBaseAsserts = (type) => [
57+
{ input: 'a', output: ['a', `vuepress-${type}-a`] },
58+
{ input: `vuepress-${type}-a`, output: ['a', `vuepress-${type}-a`] },
59+
{ input: '@vuepress/a', output: ['@vuepress/a', `@vuepress/${type}-a`] },
60+
{ input: '@org/a', output: ['@org/a', `@org/vuepress-${type}-a`] }
61+
]
62+
63+
describe('normalizeRequest', () => {
64+
const normalizeRequest = pluginResolver.normalizeRequest.bind(pluginResolver)
65+
66+
test('base', () => {
67+
const asserts = [
68+
{ input: null, output: [null, null] },
69+
{ input: undefined, output: [null, null] },
70+
...getBaseAsserts('plugin')
71+
]
72+
73+
for (const { input, output } of asserts) {
74+
const { shortcut, name } = normalizeRequest(input)
75+
expect([shortcut, name]).toEqual(output)
76+
}
77+
})
78+
79+
test('object', () => {
80+
const req = {}
81+
const { name, shortcut } = normalizeRequest(req)
82+
expect(shortcut).toBe(`anonymous-${hash(req)}`)
83+
expect(name).toBe(`vuepress-plugin-anonymous-${hash(req)}`)
84+
})
85+
86+
test('object - should respect name', () => {
87+
const req = { name: 'a' }
88+
const { name, shortcut } = normalizeRequest(req)
89+
expect(shortcut).toBe('a')
90+
expect(name).toBe(`vuepress-plugin-a`)
91+
})
92+
})
93+
94+
describe('resolvePlugin', () => {
95+
const resolvePlugin = pluginResolver.resolve.bind(pluginResolver)
96+
97+
test('function', () => {
98+
const plugin = () => {
99+
/* noop */
100+
}
101+
const resolved = resolvePlugin(plugin)
102+
expect(resolved.entry).toBe(plugin)
103+
expect(resolved.fromDep).toBe(false)
104+
})
105+
106+
test('object', () => {
107+
const plugin = {}
108+
const resolved = resolvePlugin(plugin)
109+
expect(resolved.entry).toBe(plugin)
110+
expect(resolved.fromDep).toBe(false)
111+
})
112+
113+
test('from dep', () => {
114+
const asserts = getBaseAsserts('plugin')
115+
for (const { input, output } of asserts) {
116+
const [, name] = output
117+
const resolved = resolvePlugin(input)
118+
expect(resolved.entry).toBe(loadMockModule(name))
119+
}
120+
})
121+
122+
test('relative path', () => {
123+
const resolved = resolvePlugin('./plugin-a')
124+
expect(resolved.entry).toBe(require('./fixtures/plugin-a'))
125+
})
126+
127+
test('aosolute path', () => {
128+
const resolved = resolvePlugin(path.resolve(__dirname, 'fixtures/plugin-a'))
129+
expect(resolved.entry).toBe(require('./fixtures/plugin-a'))
130+
})
131+
132+
test('plugin that cannot be resolved', () => {
133+
expect(resolvePlugin('c').entry).toBe(null)
134+
})
135+
})
136+
137+
describe('resolveTheme', () => {
138+
const resolveTheme = themeResolver.resolve.bind(themeResolver)
139+
140+
test('from dep', () => {
141+
const asserts = getBaseAsserts('theme')
142+
for (const { input, output } of asserts) {
143+
const [, name] = output
144+
const resolved = resolveTheme(input)
145+
expect(resolved.entry).toBe(resolveMockModule(name))
146+
}
147+
})
148+
149+
test('relative path', () => {
150+
const resolved = resolveTheme('./theme-a')
151+
expect(resolved.entry).toBe(path.resolve(__dirname, './fixtures/theme-a'))
152+
})
153+
154+
test('absolute path', () => {
155+
const resolved = resolveTheme(path.resolve(__dirname, 'fixtures/theme-a'))
156+
expect(resolved.entry).toBe(path.resolve(__dirname, './fixtures/theme-a'))
157+
})
158+
159+
test('theme that cannot be resolved', () => {
160+
expect(resolveTheme('c').entry).toBe(null)
161+
})
162+
})

packages/@vuepress/shared-utils/__tests__/shortcutPackageResolver.spec.js

Lines changed: 0 additions & 129 deletions
This file was deleted.

0 commit comments

Comments
 (0)