Skip to content

Commit 9a50862

Browse files
committed
feat: refine plugin API
1 parent 8b0adcb commit 9a50862

28 files changed

+327
-232
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = '@org/vuepress-plugin-a'
1+
module.exports = {}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = '@org/vuepress-plugin-b'
1+
module.exports = {}

__mocks__/@vuepress/plugin-a.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {}

__mocks__/vuepress-plugin-a.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = 'vuepress-plugin-a'
1+
module.exports = {}

__mocks__/vuepress-plugin-b.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = 'vuepress-plugin-b'
1+
module.exports = {}

packages/@vuepress/core/__test__/plugin-api/Tapable.spec.js renamed to packages/@vuepress/core/__test__/plugin-api/Options.spec.js

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
11
// TODO change to ES6 import
22
// https://github.com/facebook/jest/issues/6835
33

4-
const Tapable = require('../../lib/plugin-api/core/Tapable')
4+
const Option = require('../../lib/plugin-api/Option')
55

6-
describe('Tapable', () => {
7-
test('shoould tapable record the key', () => {
8-
const tapable = new Tapable('option')
9-
expect(tapable.key).toBe('option')
6+
describe('Option', () => {
7+
test('shoould option record the key', () => {
8+
const option = new Option('option')
9+
expect(option.key).toBe('option')
1010
})
1111

1212
test('should \'tap\' work', () => {
13-
const tapable = new Tapable('option')
14-
tapable.tap('plugin-a', 'a')
15-
tapable.tap('plugin-b', 'b')
16-
expect(tapable.items).toEqual([
13+
const option = new Option('option')
14+
option.tap('plugin-a', 'a')
15+
option.tap('plugin-b', 'b')
16+
expect(option.items).toEqual([
1717
{ value: 'a', name: 'plugin-a' },
1818
{ value: 'b', name: 'plugin-b' }
1919
])
20-
expect(tapable.values).toEqual(['a', 'b'])
20+
expect(option.values).toEqual(['a', 'b'])
2121
})
2222

2323
test('should \'tap\' resolve array value', () => {
24-
const tapable = new Tapable('option')
25-
tapable.tap('plugin-a', ['a-1', 'a-2'])
26-
tapable.tap('plugin-b', 'b')
27-
expect(tapable.items).toEqual([
24+
const option = new Option('option')
25+
option.tap('plugin-a', ['a-1', 'a-2'])
26+
option.tap('plugin-b', 'b')
27+
expect(option.items).toEqual([
2828
{ value: 'a-1', name: 'plugin-a' },
2929
{ value: 'a-2', name: 'plugin-a' },
3030
{ value: 'b', name: 'plugin-b' }
3131
])
32-
expect(tapable.values).toEqual(['a-1', 'a-2', 'b'])
32+
expect(option.values).toEqual(['a-1', 'a-2', 'b'])
3333
})
3434

3535
test('should \'run\' work', async () => {
36-
const tapable = new Tapable('option')
36+
const option = new Option('option')
3737
const handler1 = jest.fn()
3838
const handler2 = jest.fn()
3939

40-
tapable.tap('plugin-a', handler1)
41-
tapable.tap('plugin-b', handler2)
40+
option.tap('plugin-a', handler1)
41+
option.tap('plugin-b', handler2)
4242

43-
await tapable.run(1, 2)
43+
await option.run(1, 2)
4444
expect(handler1.mock.calls).toHaveLength(1)
4545
expect(handler2.mock.calls).toHaveLength(1)
4646
expect(handler1.mock.calls[0][0]).toBe(1)
@@ -50,14 +50,14 @@ describe('Tapable', () => {
5050
})
5151

5252
test('should \'parallelRun\' work', async () => {
53-
const tapable = new Tapable('option')
53+
const option = new Option('option')
5454
const handler1 = jest.fn()
5555
const handler2 = jest.fn()
5656

57-
tapable.tap('plugin-a', handler1)
58-
tapable.tap('plugin-b', handler2)
57+
option.tap('plugin-a', handler1)
58+
option.tap('plugin-b', handler2)
5959

60-
await tapable.parallelRun(1, 2)
60+
await option.parallelRun(1, 2)
6161
expect(handler1.mock.calls).toHaveLength(1)
6262
expect(handler2.mock.calls).toHaveLength(1)
6363
expect(handler1.mock.calls[0][0]).toBe(1)
Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,15 @@
11
jest.mock('vuepress-plugin-a')
22
jest.mock('@org/vuepress-plugin-a')
33

4-
const {
5-
resolvePlugin,
6-
resolveScopePackage
7-
} = require('../../lib/plugin-api/util')
8-
9-
// const Plugin = require('../../lib/plugin-api/index')
10-
11-
describe('resolvePlugin', () => {
12-
test('should resolve scope packages correctly', () => {
13-
const pkg1 = resolveScopePackage('@vuepress/plugin-a')
14-
expect(pkg1.org).toBe('vuepress')
15-
expect(pkg1.name).toBe('plugin-a')
16-
const pkg2 = resolveScopePackage('vuepress/plugin-a')
17-
expect(pkg2).toBe(null)
18-
const pkg3 = resolveScopePackage('vuepress-plugin-a')
19-
expect(pkg3).toBe(null)
20-
})
21-
22-
test('shoould return raw when function or object is given', () => {
23-
const plugin1 = () => {}
24-
const plugin2 = {}
25-
expect(resolvePlugin(plugin1)).toBe(plugin1)
26-
expect(resolvePlugin(plugin2)).toBe(plugin2)
27-
})
28-
29-
// https://jestjs.io/docs/en/manual-mocks#mocking-node-modules
30-
test('shoould resolve fullname correctly', () => {
31-
expect(resolvePlugin('vuepress-plugin-a')).toBe('vuepress-plugin-a')
32-
expect(resolvePlugin('@org/vuepress-plugin-a')).toBe('@org/vuepress-plugin-a')
33-
})
34-
35-
// https://jestjs.io/docs/en/manual-mocks#mocking-node-modules
36-
test('shoould resolve shortcut correctly', () => {
37-
expect(resolvePlugin('a')).toBe('vuepress-plugin-a')
38-
expect(resolvePlugin('@org/a')).toBe('@org/vuepress-plugin-a')
39-
// special shortcut for vuepress
40-
expect(resolvePlugin('@vuepress/a')).toBe('@vuepress/plugin-a')
4+
const Plugin = require('../../lib/plugin-api/index')
5+
const { PLUGIN_OPTION_MAP } = require('../../lib/plugin-api/constants')
6+
7+
describe('Plugin', () => {
8+
test('should resolve scope packages correctly.', () => {
9+
const plugin = new Plugin()
10+
const readyHandler = () => {}
11+
plugin.registerOption(PLUGIN_OPTION_MAP.READY.key, readyHandler)
12+
expect(plugin.options.ready.values).toHaveLength(1)
13+
expect(plugin.options.ready.values[0]).toBe(readyHandler)
4114
})
4215
})
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
jest.mock('vuepress-plugin-a')
2+
jest.mock('@org/vuepress-plugin-a')
3+
4+
const {
5+
resolvePlugin,
6+
hydratePlugin,
7+
resolveScopePackage
8+
} = require('../../lib/plugin-api/util')
9+
10+
function resolveMockModule (name) {
11+
return require(`../../../../../__mocks__/${name}`)
12+
}
13+
14+
// const Plugin = require('../../lib/plugin-api/index')
15+
16+
describe('resolvePlugin', () => {
17+
test('should resolve scope packages correctly.', () => {
18+
const pkg1 = resolveScopePackage('@vuepress/plugin-a')
19+
expect(pkg1.org).toBe('vuepress')
20+
expect(pkg1.name).toBe('plugin-a')
21+
22+
const pkg2 = resolveScopePackage('vuepress/plugin-a')
23+
expect(pkg2).toBe(null)
24+
25+
const pkg3 = resolveScopePackage('vuepress-plugin-a')
26+
expect(pkg3).toBe(null)
27+
})
28+
29+
test('shoould resolve local plugin as expected.', () => {
30+
const plugin1 = () => {}
31+
const plugin2 = {}
32+
expect(resolvePlugin(plugin1)).toEqual({ name: 'plugin1', shortcut: 'plugin1', config: plugin1 })
33+
expect(resolvePlugin(plugin2)).toEqual({ name: 'anonymous-1', shortcut: 'anonymous-1', config: plugin2 })
34+
})
35+
36+
test('shoould resolve fullname usage correctly.', () => {
37+
let plugin = resolvePlugin('vuepress-plugin-a')
38+
expect(plugin.name).toBe('vuepress-plugin-a')
39+
expect(plugin.shortcut).toBe('a')
40+
expect(plugin.config).toBe(resolveMockModule('vuepress-plugin-a'))
41+
42+
plugin = resolvePlugin('@org/vuepress-plugin-a')
43+
expect(plugin.name).toBe('@org/vuepress-plugin-a')
44+
expect(plugin.shortcut).toBe('@org/a')
45+
expect(plugin.config).toBe(resolveMockModule('@org/vuepress-plugin-a'))
46+
})
47+
48+
test('shoould resolve shortcut usage correctly.', () => {
49+
// normal package
50+
let plugin = resolvePlugin('a')
51+
expect(plugin.name).toBe('vuepress-plugin-a')
52+
expect(plugin.shortcut).toBe('a')
53+
expect(plugin.config).toBe(resolveMockModule('vuepress-plugin-a'))
54+
55+
// scope packages
56+
plugin = resolvePlugin('@org/a')
57+
expect(plugin.name).toBe('@org/vuepress-plugin-a')
58+
expect(plugin.shortcut).toBe('@org/a')
59+
expect(plugin.config).toBe(resolveMockModule('@org/vuepress-plugin-a'))
60+
61+
// special case for @vuepress package
62+
plugin = resolvePlugin('@vuepress/a')
63+
expect(plugin.name).toBe('@vuepress/plugin-a')
64+
expect(plugin.shortcut).toBe('@vuepress/a')
65+
expect(plugin.config).toBe(resolveMockModule('@vuepress/plugin-a'))
66+
})
67+
68+
test('shoould return null when plugin cannot be resolved.', () => {
69+
expect(resolvePlugin('c')).toEqual({ name: 'c', shortcut: 'c', config: null })
70+
})
71+
})
72+
73+
describe('hydratePlugin', () => {
74+
test('shoould hydrate plugin correctly', () => {
75+
const plugin = { name: 'a', shortcut: 'a', config: { enhanceAppFiles: 'file' }}
76+
const hydratedPlugin = hydratePlugin(plugin, {}, {})
77+
expect(hydratedPlugin.name).toBe('a')
78+
expect(hydratedPlugin.shortcut).toBe('a')
79+
expect(hydratedPlugin.enabled).toBe(true)
80+
expect(hydratedPlugin.enhanceAppFiles).toBe('file')
81+
})
82+
83+
test('shoould set \'enabled\' to false when \'pluginOptions\' is set to false.', () => {
84+
const plugin = { name: 'a', shortcut: 'a', config: {}}
85+
const hydratedPlugin = hydratePlugin(plugin, false, {})
86+
expect(hydratedPlugin.name).toBe('a')
87+
expect(hydratedPlugin.shortcut).toBe('a')
88+
expect(hydratedPlugin.enabled).toBe(false)
89+
})
90+
91+
test('shoould hydrate functional plugin correctly.', () => {
92+
const config = jest.fn(() => ({ enhanceAppFiles: 'file' }))
93+
const plugin = { name: 'a', shortcut: 'a', config }
94+
const pluginOptions = {}
95+
const pluginContext = {}
96+
const hydratedPlugin = hydratePlugin(plugin, pluginOptions, pluginContext)
97+
expect(hydratedPlugin.name).toBe('a')
98+
expect(hydratedPlugin.shortcut).toBe('a')
99+
expect(hydratedPlugin.enabled).toBe(true)
100+
expect(hydratedPlugin.enhanceAppFiles).toBe('file')
101+
expect(config.mock.calls).toHaveLength(1)
102+
expect(config.mock.calls[0][0]).toBe(pluginOptions)
103+
expect(Object.getPrototypeOf(config.mock.calls[0][1])).toBe(pluginContext)
104+
})
105+
})

packages/@vuepress/core/lib/build.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ module.exports = async function build (sourceDir, cliOptions = {}) {
9494
)
9595
}
9696

97-
await options.plugin.hooks.generated.run()
97+
await options.plugin.options.generated.run()
9898

9999
// DONE.
100100
const relativeDir = path.relative(process.cwd(), outDir)

packages/@vuepress/core/lib/dev.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ module.exports = async function dev (sourceDir, cliOptions = {}) {
2424

2525
// setup watchers to update options and dynamically generated files
2626
const update = () => {
27-
options.plugin.hooks.updated.run()
27+
options.plugin.options.updated.run()
2828
prepare(sourceDir).catch(err => {
2929
console.error(logger.error(chalk.red(err.stack), false))
3030
})

0 commit comments

Comments
 (0)