@polylith/core 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EventBus.js +1 -1
- package/Registry.js +133 -4
- package/Service.js +1 -1
- package/ServiceObject.js +62 -0
- package/package.json +4 -4
package/EventBus.js
CHANGED
package/Registry.js
CHANGED
|
@@ -1,31 +1,74 @@
|
|
|
1
1
|
import { ServiceOject } from "./ServiceObject.js";
|
|
2
2
|
import { makeEventable} from "./Eventable.js";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* This calls is the implementation of the serices registry. There will be a
|
|
6
|
+
* single global instance of this class.
|
|
7
|
+
*/
|
|
4
8
|
export class Registry {
|
|
9
|
+
/** Constructor for the registry */
|
|
5
10
|
constructor () {
|
|
6
11
|
this.services = {};
|
|
7
12
|
|
|
8
13
|
makeEventable(this);
|
|
9
14
|
}
|
|
10
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Call this method to construct a new service object.
|
|
18
|
+
* @param {String} [name] if pass this is the name of the sercice object
|
|
19
|
+
* service objects can be anonymous
|
|
20
|
+
* @returns the newly created sercice object
|
|
21
|
+
*/
|
|
11
22
|
createServiceObject(name) {
|
|
12
23
|
var result = new ServiceOject(name);
|
|
13
24
|
|
|
14
25
|
return result;
|
|
15
26
|
}
|
|
16
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Call this method to register a new service object. The serice object can '
|
|
30
|
+
* be subscribed to fromn the registry by the given name.
|
|
31
|
+
*
|
|
32
|
+
* @param {String} name the namke of the object being registered.
|
|
33
|
+
* @param {ServiceOject} serviceObject the service object being registered.
|
|
34
|
+
*/
|
|
17
35
|
register(name, serviceObject) {
|
|
18
36
|
this.services[name] = serviceObject;
|
|
19
37
|
}
|
|
20
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Call this method to remove the service object from the registry. Any
|
|
41
|
+
* references thos this service will be retained.
|
|
42
|
+
*
|
|
43
|
+
* @param {String} name the name of the service to remove
|
|
44
|
+
*/
|
|
21
45
|
unregister(name) {
|
|
22
46
|
delete this.services[name];
|
|
23
47
|
}
|
|
24
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Call this method to get a reference to the service object.
|
|
51
|
+
*
|
|
52
|
+
* @param {String} name the registered name of the service object
|
|
53
|
+
* @returns {ServiceOject} the registered service object, ot false if it was
|
|
54
|
+
* not found.
|
|
55
|
+
*/
|
|
25
56
|
subscribe(name) {
|
|
26
57
|
return this.services[name];
|
|
27
58
|
}
|
|
28
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Call this method to create and register a service object and then
|
|
62
|
+
* implement methods on it. The created service object will be added as a
|
|
63
|
+
* member of the implementation object named serviceObject and the methods
|
|
64
|
+
* fire, listen and unlisten will be added as well. When called these
|
|
65
|
+
* methods will operate directly on the service object.
|
|
66
|
+
*
|
|
67
|
+
* @param {String} serviceName the name of the service being implemented.
|
|
68
|
+
* @param {Object} obj the implementation object for the given methods
|
|
69
|
+
* @param {Array.<String>} methodList the list of methods to add. These will
|
|
70
|
+
* be bound to the passed implementation object.
|
|
71
|
+
*/
|
|
29
72
|
makeService(serviceName, obj, methodList) {
|
|
30
73
|
obj.serviceObject = new ServiceOject(serviceName);
|
|
31
74
|
|
|
@@ -52,6 +95,17 @@ export class Registry {
|
|
|
52
95
|
}
|
|
53
96
|
}
|
|
54
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Call this method to extend the service object with a new list of methods.
|
|
100
|
+
* If not already impementated the methods fire, listen and unlisten will be
|
|
101
|
+
* added to the implementation object. If the service doesn't exist, it will
|
|
102
|
+
* be created. It will not be registered.
|
|
103
|
+
*
|
|
104
|
+
* @param {String} serviceName the name of the service being extended
|
|
105
|
+
* @param {*} obj the object implementing the methods
|
|
106
|
+
* @param {Array.<String>} methodList the list of methods to add. These will
|
|
107
|
+
* be bound to the passed implementation object.
|
|
108
|
+
*/
|
|
55
109
|
extendService(serviceName, obj, methodList) {
|
|
56
110
|
var serviceObject = this.subscribe(serviceName);
|
|
57
111
|
|
|
@@ -76,14 +130,27 @@ export class Registry {
|
|
|
76
130
|
}
|
|
77
131
|
}
|
|
78
132
|
|
|
79
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Call this method to invoke a method on all the passed service.
|
|
135
|
+
*
|
|
136
|
+
* @param {Array.<String>} serviceNames
|
|
137
|
+
* @param {String} which the name of the method to call
|
|
138
|
+
* @param {Function} if provided will call the function with the result of
|
|
139
|
+
* the service call
|
|
140
|
+
* @param {...any} args the arguments to pass to the invoked method
|
|
141
|
+
* @returns {Promise.<any>} an array of any promises that were returned from
|
|
142
|
+
* the called methods.
|
|
143
|
+
*/
|
|
144
|
+
callAll(serviceNames, which, processResult, ...args) {
|
|
80
145
|
var promises = [];
|
|
81
146
|
|
|
82
147
|
serviceNames.forEach(function (name) {
|
|
83
148
|
var serviceObject = this.services[name];
|
|
84
149
|
if (!serviceObject) return;
|
|
85
|
-
|
|
86
150
|
var result = serviceObject.invoke.apply(serviceObject, [which, ...args]);
|
|
151
|
+
|
|
152
|
+
if (processResult) processResult(serviceObject, result)
|
|
153
|
+
|
|
87
154
|
if (result && result.then) {
|
|
88
155
|
promises.push(result);
|
|
89
156
|
}
|
|
@@ -92,17 +159,79 @@ export class Registry {
|
|
|
92
159
|
return promises;
|
|
93
160
|
}
|
|
94
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Call this method to add the wait method to a service object
|
|
164
|
+
*
|
|
165
|
+
* @param {ServiceOject} serviceObject the service object to add the method
|
|
166
|
+
* to
|
|
167
|
+
* @param {*} result the result of the start method
|
|
168
|
+
*/
|
|
169
|
+
addWaitMethod(serviceObject, result) {
|
|
170
|
+
var promise = result?.then ? result : Promise.resolve(true);
|
|
171
|
+
|
|
172
|
+
serviceObject.waitStarted = function() {
|
|
173
|
+
return promise;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Call this method to verify that all services have their required services
|
|
179
|
+
* registered. Any services that does not have all requirements will be
|
|
180
|
+
* removed from the registry
|
|
181
|
+
*/
|
|
182
|
+
checkRequirements() {
|
|
183
|
+
var more = true;
|
|
184
|
+
|
|
185
|
+
while (!more) {
|
|
186
|
+
let names = Object.keys(this.services);
|
|
187
|
+
let toRemove = [];
|
|
188
|
+
|
|
189
|
+
names.forEach(function(name) {
|
|
190
|
+
var service = this.services[name];
|
|
191
|
+
var required = service.required;
|
|
192
|
+
|
|
193
|
+
var missing = required.some(function(requirement) {
|
|
194
|
+
if (!requirement in this.services) {
|
|
195
|
+
console.error(`reqiuirement ${requirement} for service ${name} missing. Service removed`)
|
|
196
|
+
}
|
|
197
|
+
return !(requirement in this.services);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
if (missing) toRemove.push(name);
|
|
201
|
+
}, this);
|
|
202
|
+
|
|
203
|
+
more = toRemove.length != 0;
|
|
204
|
+
toRemove.forEach(function(name) {
|
|
205
|
+
delete this.services[name];
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Call this method to initiate the startup sequence. The startup sequence
|
|
212
|
+
* is to first invoke the start method on all the specified registered
|
|
213
|
+
* services. Then, after all returtned promises have settled, the ready
|
|
214
|
+
* method will be invoked. The ready method is assumed to be synchronous
|
|
215
|
+
*
|
|
216
|
+
* @param {String} [prefix] if passed, only sevice that start with the
|
|
217
|
+
* given prefix will have the start process run.
|
|
218
|
+
*
|
|
219
|
+
* @returns a promise that will be resolved when the startup sequence is
|
|
220
|
+
* completed.
|
|
221
|
+
*/
|
|
95
222
|
async start(prefix = '') {
|
|
96
223
|
var names = Object.keys(this.services);
|
|
97
224
|
|
|
225
|
+
this.checkRequirements();
|
|
226
|
+
|
|
98
227
|
var services = names.filter(function(name) {
|
|
99
228
|
return name.indexOf(prefix) === 0;
|
|
100
229
|
}, this);
|
|
101
230
|
|
|
102
|
-
var promises = this.callAll(services, 'start');
|
|
231
|
+
var promises = this.callAll(services, 'start', this.addWaitMethod.bind(this));
|
|
103
232
|
return Promise.allSettled(promises)
|
|
104
233
|
.then(function () {
|
|
105
|
-
this.callAll(services, 'ready');
|
|
234
|
+
this.callAll(services, 'ready', false);
|
|
106
235
|
this.fire('ready', prefix);
|
|
107
236
|
}.bind(this));
|
|
108
237
|
}
|
package/Service.js
CHANGED
|
@@ -25,7 +25,7 @@ export class Service {
|
|
|
25
25
|
if (this[name]) {
|
|
26
26
|
methods[name] = this[name].bind(this);
|
|
27
27
|
} else {
|
|
28
|
-
console.warn('method', name, 'not implemented on service', this.
|
|
28
|
+
console.warn('method', name, 'not implemented on service', this.serviceName ? this.serviceName : '<unnamed service>')
|
|
29
29
|
}
|
|
30
30
|
}, this);
|
|
31
31
|
|
package/ServiceObject.js
CHANGED
|
@@ -1,14 +1,36 @@
|
|
|
1
1
|
import { EventBus } from './EventBus.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The registry creates an instance of this class for every created service.
|
|
5
|
+
* Service implementations will extend this object by adding methods and events.
|
|
6
|
+
* Service objects are eventable objects, and inherit from the EventBus object
|
|
7
|
+
*/
|
|
3
8
|
export class ServiceOject extends EventBus {
|
|
9
|
+
/**
|
|
10
|
+
* Constructor for the service object
|
|
11
|
+
* @param {String} name the name of the service being registered.
|
|
12
|
+
*/
|
|
4
13
|
constructor(name) {
|
|
5
14
|
super('service:');
|
|
6
15
|
|
|
7
16
|
this.name = name;
|
|
8
17
|
this.bound = true;
|
|
9
18
|
this.methods = [];
|
|
19
|
+
this.required = [];
|
|
10
20
|
}
|
|
11
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Call this method to add a method to the serviceobject that will directly
|
|
24
|
+
* call the event listener for an event. This is a much faster
|
|
25
|
+
* implementation of event handling in the case where there is a single
|
|
26
|
+
* listener. If there is more than a single listener this method will
|
|
27
|
+
* fallback to calling fire.
|
|
28
|
+
*
|
|
29
|
+
* @private
|
|
30
|
+
* @param {String} name the name of the event being bound to a listener.
|
|
31
|
+
* This will be the name of the creted method
|
|
32
|
+
* @param {Function} method the function to call when the method is called
|
|
33
|
+
*/
|
|
12
34
|
assignMethod(name, method) {
|
|
13
35
|
// if there is already a listener, unbind and force invoking
|
|
14
36
|
var bind = this.bound || !this.listeners[name];
|
|
@@ -23,12 +45,21 @@ export class ServiceOject extends EventBus {
|
|
|
23
45
|
this.methods.push(name);
|
|
24
46
|
}
|
|
25
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Call this method to unbind the method and make it instead fire an event.
|
|
50
|
+
* when called
|
|
51
|
+
*
|
|
52
|
+
* @param {String} name the name of the method to unbind
|
|
53
|
+
*/
|
|
26
54
|
unbindMethod(name) {
|
|
27
55
|
if (this[name]) {
|
|
28
56
|
this[name] = this.invoke.bind(this, name)
|
|
29
57
|
}
|
|
30
58
|
}
|
|
31
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Call this method to unbind all methods and prevent future binding.
|
|
62
|
+
*/
|
|
32
63
|
unbind() {
|
|
33
64
|
this.bound = false;
|
|
34
65
|
this.methods.forEach(function(name) {
|
|
@@ -36,6 +67,13 @@ export class ServiceOject extends EventBus {
|
|
|
36
67
|
}, this)
|
|
37
68
|
}
|
|
38
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Call this method to bind a number of methods to the service object.
|
|
72
|
+
*
|
|
73
|
+
* @param {Object} methods a map of methods to implement. The key is the
|
|
74
|
+
* method name, the value is the method to call.
|
|
75
|
+
*
|
|
76
|
+
*/
|
|
39
77
|
implement(methods) {
|
|
40
78
|
var names = Object.keys(methods);
|
|
41
79
|
|
|
@@ -49,7 +87,31 @@ export class ServiceOject extends EventBus {
|
|
|
49
87
|
}, this);
|
|
50
88
|
}
|
|
51
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Call this method to safely invoke a method. This is a semantic function
|
|
92
|
+
* to conceptually separate methods from events, although they are
|
|
93
|
+
* implemented the same.
|
|
94
|
+
*
|
|
95
|
+
* @param {String} name the name of the method
|
|
96
|
+
* @param {...any} args the paramaters to pass
|
|
97
|
+
* @returns
|
|
98
|
+
*/
|
|
52
99
|
invoke(name, ...args) {
|
|
53
100
|
return this.fire(name, ...args);
|
|
54
101
|
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Call this method to add a list of service names that this service
|
|
105
|
+
* depends on
|
|
106
|
+
*
|
|
107
|
+
* @param {*} services array of services
|
|
108
|
+
*/
|
|
109
|
+
require(services) {
|
|
110
|
+
this.required = [...this.required, ...services];
|
|
111
|
+
|
|
112
|
+
this.required = [...new Set(this.required)];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
55
117
|
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polylith/core",
|
|
3
3
|
"access": "public",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.10",
|
|
5
5
|
"description": "Core of the client-side polylith framework",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/Ondoher/polylith",
|
|
10
|
-
"directory": "packages/
|
|
10
|
+
"directory": "packages/core"
|
|
11
11
|
},
|
|
12
|
-
"scripts": {
|
|
12
|
+
"scripts": {
|
|
13
13
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
14
14
|
},
|
|
15
15
|
"author": "Glenn Anderson",
|
|
@@ -18,4 +18,4 @@
|
|
|
18
18
|
"uuid": "^8.3.2"
|
|
19
19
|
},
|
|
20
20
|
"type": "module"
|
|
21
|
-
}
|
|
21
|
+
}
|