Skip to content

Commit 44c4ed9

Browse files
author
Ovidiu Barabula
committed
feat(core): remove plugin validation responsability from plugin manager and use installable
1 parent e6d7bd9 commit 44c4ed9

File tree

2 files changed

+91
-55
lines changed

2 files changed

+91
-55
lines changed

src/plugin-manager/index.spec.ts

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
import { assert, expect } from 'chai';
22
import 'mocha';
3+
import ConfigManager from '../config-manager';
4+
import ConfigWizard from '../config-wizard';
35
import TaskManager from '../task-manager';
46
import PluginManager, { ERRORS } from './index';
57

68
describe('PluginManager', () => {
7-
const taskManager = TaskManager();
8-
const validPlugin = {
9-
install: () => true,
10-
};
9+
let taskManager;
10+
let configWizard;
11+
let validPlugin;
12+
13+
beforeEach(async () => {
14+
taskManager = TaskManager({
15+
hooks: ['before', 'midway', 'after'],
16+
});
17+
configWizard = ConfigWizard(await ConfigManager());
18+
validPlugin = { install: () => true };
19+
});
20+
1121

1222
it('instantiates', () => {
13-
const pluginManager = PluginManager(taskManager);
23+
const pluginManager = PluginManager(taskManager, configWizard);
1424
expect(pluginManager).to.be.an('object')
15-
.to.contain.keys('use', 'validate');
25+
.to.contain.keys('use');
1626
});
1727

1828

@@ -23,24 +33,54 @@ describe('PluginManager', () => {
2333
});
2434

2535

26-
it('throws if plugin is undefined or not an object', () => {
27-
assert.throws(() => PluginManager(taskManager).validate(undefined), ERRORS.PLUGIN_INVALID);
36+
it('throws if not passed ConfigWizard instance', () => {
37+
assert.throws(() => PluginManager(taskManager), ERRORS.NO_CONFIG_WIZARD);
38+
assert.throws(() => PluginManager(taskManager, {}), ERRORS.NO_CONFIG_WIZARD);
39+
assert.throws(() => PluginManager(taskManager, 1), ERRORS.NO_CONFIG_WIZARD);
2840
});
2941

3042

31-
it('throws if plugin doesn\'t have .install() method', () => {
32-
assert.throws(() => PluginManager(taskManager).validate({}), ERRORS.PLUGIN_NOT_INSTALLABLE);
43+
it('calls taskManager.getSubscribers() method if plugin is valid', () => {
44+
let called = false;
45+
46+
const taskManagerStub = {
47+
add: () => undefined,
48+
getSubscribers: () => called = true,
49+
run: () => undefined,
50+
};
51+
const pluginManager = PluginManager(taskManagerStub, configWizard);
52+
pluginManager.use(validPlugin);
53+
expect(called).to.be.true;
3354
});
3455

3556

36-
it('calls taskManager.add() method if plugin is valid', () => {
57+
it('calls configWizard.getSubscriber() method if plugin is valid', () => {
3758
let called = false;
38-
const pluginManager = PluginManager({
39-
add: () => called = true,
40-
run: () => undefined,
41-
});
4259

60+
const configManagerStub = {
61+
addQuestionnaire: () => undefined,
62+
getSubscriber: () => called = true,
63+
start: () => undefined,
64+
};
65+
66+
const pluginManager = PluginManager(taskManager, configManagerStub);
4367
pluginManager.use(validPlugin);
4468
expect(called).to.be.true;
4569
});
70+
71+
72+
it('passes taskSubscribers and configSubscriber arguments to plugin.install() method', () => {
73+
const pluginStub = {
74+
install(taskSubscribers, configSubscriber) {
75+
expect(taskSubscribers)
76+
.to.be.be.an('object')
77+
.to.not.be.empty;
78+
expect(configSubscriber)
79+
.to.be.be.a('function');
80+
},
81+
};
82+
83+
const pluginManager = PluginManager(taskManager, configWizard);
84+
pluginManager.use(pluginStub);
85+
});
4686
});

src/plugin-manager/index.ts

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,82 +5,78 @@
55
* @since 0.1.0
66
*/
77

8+
import { IConfigWizard, QuestionnaireSubscriber } from '../config-wizard';
89
import { TaskManager, TaskSubscriber } from '../task-manager';
9-
10+
import Installable, { InstallableObject } from './installable';
1011

1112
export interface Plugin {
12-
install(subscribers: TaskSubscriber): void;
13+
name: string;
14+
description?: string;
15+
install(taskSubscribers: TaskSubscriber, configSubscriber: QuestionnaireSubscriber): Promise<void>;
1316
}
1417

1518
export interface PluginManager {
16-
use(plugin: Plugin | string): void;
19+
use(plugin: Plugin | InstallableObject): Promise<void>;
1720
validate?(plugin: Plugin): boolean;
1821
}
1922

2023

2124
// Custom error messages
2225
export const ERRORS = {
23-
NO_TASK_MANAGER: 'PluginManager requires first argument to be a TaskManager instance',
24-
PLUGIN_INVALID: 'PluginManager> Invalid plugin: should be an object',
25-
PLUGIN_NOT_INSTALLABLE: 'PluginManager> Invalid plugin: .install() method is missing',
26+
NO_CONFIG_WIZARD: 'PluginManager() requires second argument to be a ConfigWizard instance',
27+
NO_TASK_MANAGER: 'PluginManager() requires first argument to be a TaskManager instance',
2628
};
2729

2830

2931
/**
3032
* PluginManager constructor
3133
*/
32-
function PluginManager(taskManager: TaskManager): PluginManager {
34+
function PluginManager(taskManager: TaskManager, configWizard: IConfigWizard): PluginManager {
3335
if (
3436
typeof taskManager === 'undefined' ||
3537
typeof taskManager !== 'object' ||
36-
!taskManager.hasOwnProperty('add')
38+
!taskManager.hasOwnProperty('getSubscribers')
3739
) {
3840
throw new Error(ERRORS.NO_TASK_MANAGER);
3941
}
4042

41-
42-
/**
43-
* Validate plugin
44-
* @param plugin Plugin object
45-
*/
46-
function validate(plugin: Plugin): boolean {
47-
if (typeof plugin === 'undefined' || typeof plugin !== 'object') {
48-
throw new Error(ERRORS.PLUGIN_INVALID);
49-
}
50-
51-
if (!plugin.hasOwnProperty('install') || typeof plugin.install !== 'function') {
52-
throw new Error(ERRORS.PLUGIN_NOT_INSTALLABLE);
53-
}
54-
55-
return true;
43+
if (
44+
typeof configWizard === 'undefined' ||
45+
typeof configWizard !== 'object' ||
46+
!configWizard.hasOwnProperty('getSubscriber')
47+
) {
48+
throw new Error(ERRORS.NO_CONFIG_WIZARD);
5649
}
5750

5851

5952
/**
6053
* Register plugin
6154
* @param plugin Plugin object
6255
*/
63-
function use(plugin: Plugin): void {
64-
validate(plugin);
65-
taskManager.add(plugin);
56+
async function use(plugin: Plugin | InstallableObject): Promise<void> {
57+
// TODO: Add support for plugin as string
58+
// TODO: When plugin is of type string, look for plugin in node_modules
59+
60+
// Get task subscribers
61+
const taskSubscribers: TaskSubscriber = taskManager.getSubscribers();
62+
// Get config wizard questionnaire subscriber
63+
const configSubscriber: QuestionnaireSubscriber = configWizard.getSubscriber();
64+
65+
await Installable(plugin)
66+
.install(
67+
// Provide the plugin with the following:
68+
// Subscribers object for task hook subscription
69+
taskSubscribers,
70+
// Config Wizard questionnaire registrar
71+
configSubscriber,
72+
);
6673
}
6774

6875

69-
// Creating the public API object
70-
let publicApi: PluginManager = {
76+
// Return public API
77+
return Object.freeze({
7178
use,
72-
};
73-
74-
75-
// Adding private methods to public API in test environment
76-
/* test:start */
77-
publicApi = {...publicApi,
78-
validate,
79-
};
80-
/* test:end */
81-
82-
83-
return Object.freeze(publicApi);
79+
});
8480
}
8581

8682
export default PluginManager;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy