@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 CHANGED
@@ -7,7 +7,7 @@ export class EventBus {
7
7
  }
8
8
 
9
9
  listen (eventName, cb) {
10
- var listenerId = uuid.v1();
10
+ var listenerId = uuid.v4();
11
11
  var name = this.prefix + eventName;
12
12
 
13
13
  this.listeners[name] = this.listeners[name] || [];
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
- callAll(serviceNames, which, ...args) {
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.name ? this.name : '<unnamed service>')
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.8",
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/client/core"
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
+ }