noflo 1.4.2 → 1.5.0

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.
Files changed (89) hide show
  1. package/.ecrc +3 -0
  2. package/.eslintignore +2 -0
  3. package/{CHANGES.md → CHANGELOG.md} +520 -523
  4. package/README.md +1 -1
  5. package/bin/noflo-cache-preheat +17 -15
  6. package/components/Graph.d.ts +50 -15
  7. package/components/Graph.js +94 -68
  8. package/examples/http/HelloController.js +9 -6
  9. package/examples/spreadsheet/parse.fbp +3 -3
  10. package/lib/AsCallback.d.ts +22 -9
  11. package/lib/AsCallback.js +69 -18
  12. package/lib/AsComponent.d.ts +1 -1
  13. package/lib/AsComponent.js +5 -3
  14. package/lib/BaseNetwork.d.ts +16 -6
  15. package/lib/BaseNetwork.js +65 -31
  16. package/lib/BasePort.d.ts +39 -12
  17. package/lib/BasePort.js +34 -6
  18. package/lib/Component.d.ts +8 -8
  19. package/lib/Component.js +23 -20
  20. package/lib/ComponentLoader.d.ts +3 -4
  21. package/lib/ComponentLoader.js +9 -10
  22. package/lib/IP.d.ts +12 -8
  23. package/lib/IP.js +6 -4
  24. package/lib/InPort.d.ts +81 -10
  25. package/lib/InPort.js +83 -19
  26. package/lib/InternalSocket.d.ts +53 -7
  27. package/lib/InternalSocket.js +51 -14
  28. package/lib/LegacyNetwork.d.ts +12 -2
  29. package/lib/LegacyNetwork.js +5 -5
  30. package/lib/Network.d.ts +13 -2
  31. package/lib/Network.js +10 -10
  32. package/lib/NoFlo.d.ts +13 -13
  33. package/lib/NoFlo.js +29 -27
  34. package/lib/OutPort.d.ts +74 -32
  35. package/lib/OutPort.js +79 -23
  36. package/lib/Platform.d.ts +1 -1
  37. package/lib/Platform.js +9 -4
  38. package/lib/Ports.d.ts +14 -21
  39. package/lib/Ports.js +11 -13
  40. package/lib/ProcessInput.d.ts +5 -9
  41. package/lib/ProcessInput.js +8 -9
  42. package/lib/ProcessOutput.d.ts +2 -2
  43. package/lib/ProcessOutput.js +5 -5
  44. package/lib/loader/NodeJs.d.ts +0 -1
  45. package/lib/loader/NodeJs.js +104 -105
  46. package/lib/loader/register.d.ts +1 -1
  47. package/lib/loader/register.js +8 -4
  48. package/package.json +16 -11
  49. package/spec/.eslintrc +5 -2
  50. package/spec/AsCallback.js +9 -13
  51. package/spec/AsComponent.js +10 -4
  52. package/spec/AsPromise.js +38 -0
  53. package/spec/CommonJS.cjs +10 -0
  54. package/spec/ComponentLoader.js +2 -38
  55. package/spec/ESModule.mjs +11 -0
  56. package/spec/Network.js +32 -11
  57. package/spec/NetworkSync.js +892 -0
  58. package/spec/Scoping.js +27 -42
  59. package/spec/Subgraph.js +6 -11
  60. package/spec/fixtures/componentloader/components/Output.js +1 -1
  61. package/spec/fixtures/componentloader/components/Repeat.ts +1 -1
  62. package/spec/fixtures/componentloader/components/RepeatAsync.coffee +1 -1
  63. package/spec/fixtures/componentloader/node_modules/example/components/Forward.js +1 -1
  64. package/spec/fixtures/componentloader/node_modules/example/package.json +1 -1
  65. package/spec/fixtures/componentloader/package.json +1 -1
  66. package/spec/fixtures/componentloader/spec/Repeat.yaml +1 -1
  67. package/src/.eslintrc +9 -2
  68. package/src/components/Graph.js +105 -71
  69. package/src/lib/AsCallback.js +71 -16
  70. package/src/lib/AsComponent.js +4 -3
  71. package/src/lib/BaseNetwork.js +48 -15
  72. package/src/lib/BasePort.js +43 -9
  73. package/src/lib/Component.js +8 -8
  74. package/src/lib/ComponentLoader.js +3 -4
  75. package/src/lib/IP.js +7 -4
  76. package/src/lib/InPort.js +86 -21
  77. package/src/lib/InternalSocket.js +49 -9
  78. package/src/lib/LegacyNetwork.js +2 -2
  79. package/src/lib/Network.js +2 -2
  80. package/src/lib/NoFlo.js +15 -13
  81. package/src/lib/OutPort.js +83 -22
  82. package/src/lib/Platform.js +9 -4
  83. package/src/lib/Ports.js +9 -11
  84. package/src/lib/ProcessInput.js +7 -9
  85. package/src/lib/ProcessOutput.js +1 -1
  86. package/src/lib/loader/NodeJs.js +122 -116
  87. package/src/lib/loader/register.js +2 -2
  88. /package/{karma.config.js → karma.config.cjs} +0 -0
  89. /package/{webpack.config.js → webpack.config.cjs} +0 -0
package/src/lib/InPort.js CHANGED
@@ -1,35 +1,55 @@
1
1
  // NoFlo - Flow-Based Programming for JavaScript
2
2
  // (c) 2014-2017 Flowhub UG
3
3
  // NoFlo may be freely distributed under the MIT license
4
- import BasePort from './BasePort';
4
+ import BasePort from './BasePort.js';
5
5
 
6
6
  // ## NoFlo inport
7
7
  //
8
8
  // Input Port (inport) implementation for NoFlo components. These
9
9
  // ports are the way a component receives Information Packets.
10
+ /**
11
+ * @typedef InPortOptions
12
+ * @property {any} [default]
13
+ * @property {Array<any>} [values]
14
+ * @property {boolean} [control]
15
+ * @property {boolean} [triggering]
16
+ */
17
+ /**
18
+ * @callback HasValidationCallback
19
+ * @param {import("./IP").default} ip
20
+ * @returns {boolean}
21
+ */
22
+ /**
23
+ * @typedef {import("./BasePort").BaseOptions & InPortOptions} PortOptions
24
+ */
25
+
10
26
  export default class InPort extends BasePort {
27
+ /**
28
+ * @param {PortOptions} [options]
29
+ */
11
30
  constructor(options = {}) {
12
31
  const opts = options;
13
32
  if (opts.control == null) { opts.control = false; }
14
33
  if (opts.scoped == null) { opts.scoped = true; }
15
34
  if (opts.triggering == null) { opts.triggering = true; }
16
35
 
17
- if (opts.process) {
18
- throw new Error('InPort process callback is deprecated. Please use Process API');
19
- }
20
-
21
- if (opts.handle) {
22
- throw new Error('InPort handle callback is deprecated. Please use Process API');
23
- }
24
-
25
36
  super(opts);
26
37
 
38
+ const baseOptions = this.options;
39
+ this.options = /** @type {PortOptions} */ (baseOptions);
40
+
41
+ /** @type {import("./Component").Component|null} */
27
42
  this.nodeInstance = null;
28
43
 
29
44
  this.prepareBuffer();
30
45
  }
31
46
 
32
- // Assign a delegate for retrieving data should this inPort
47
+ /**
48
+ * Assign a delegate for retrieving data should this inPort
49
+ *
50
+ * @param {import("./InternalSocket").InternalSocket} socket
51
+ * @param {number|null} [localId]
52
+ */
33
53
  attachSocket(socket, localId = null) {
34
54
  // have a default value.
35
55
  if (this.hasDefault()) {
@@ -47,11 +67,17 @@ export default class InPort extends BasePort {
47
67
  socket.on('ip', (ip) => this.handleIP(ip, localId));
48
68
  }
49
69
 
50
- handleIP(packet, index) {
70
+ /**
71
+ * @param {import("./IP").default} packet
72
+ * @param {number|null} [index]
73
+ */
74
+ handleIP(packet, index = null) {
51
75
  if (this.options.control && (packet.type !== 'data')) { return; }
52
76
  const ip = packet;
53
77
  ip.owner = this.nodeInstance;
54
- if (this.isAddressable()) { ip.index = index; }
78
+ if (this.isAddressable()) {
79
+ ip.index = index;
80
+ }
55
81
  if (ip.datatype === 'all') {
56
82
  // Stamp non-specific IP objects with port datatype
57
83
  ip.datatype = this.getDataType();
@@ -68,6 +94,11 @@ export default class InPort extends BasePort {
68
94
  this.emit('ip', ip, index);
69
95
  }
70
96
 
97
+ /**
98
+ * @param {string} event
99
+ * @param {any} payload
100
+ * @param {number} [id]
101
+ */
71
102
  handleSocketEvent(event, payload, id) {
72
103
  // Emit port event
73
104
  if (this.isAddressable()) {
@@ -134,6 +165,9 @@ export default class InPort extends BasePort {
134
165
  return this.buffer;
135
166
  }
136
167
 
168
+ /**
169
+ * @param {any} data
170
+ */
137
171
  validateData(data) {
138
172
  if (!this.options.values) { return; }
139
173
  if (this.options.values.indexOf(data) === -1) {
@@ -188,14 +222,25 @@ export default class InPort extends BasePort {
188
222
  return buf.shift();
189
223
  }
190
224
 
191
- // Fetches a packet from the port
192
- get(scope, index) {
225
+ /**
226
+ * Fetches a packet from the port
227
+ * @param {string|null} scope
228
+ * @param {number|null} [index]
229
+ */
230
+ get(scope, index = null) {
193
231
  const res = this.getFromBuffer(scope, index);
194
232
  if (res !== undefined) { return res; }
195
233
  // Try to find an IIP instead
196
234
  return this.getFromBuffer(null, index, true);
197
235
  }
198
236
 
237
+ /**
238
+ * Fetches a packet from the port
239
+ * @param {string|null} scope
240
+ * @param {number|null} index
241
+ * @param {HasValidationCallback} validate
242
+ * @param {boolean} [initial]
243
+ */
199
244
  hasIPinBuffer(scope, index, validate, initial = false) {
200
245
  const buf = this.getBuffer(scope, index, initial);
201
246
  if (!(buf != null ? buf.length : undefined)) { return false; }
@@ -205,31 +250,51 @@ export default class InPort extends BasePort {
205
250
  return false;
206
251
  }
207
252
 
253
+ /**
254
+ * @param {number|null} index
255
+ * @param {HasValidationCallback} validate
256
+ */
208
257
  hasIIP(index, validate) {
209
258
  return this.hasIPinBuffer(null, index, validate, true);
210
259
  }
211
260
 
212
- // Returns true if port contains packet(s) matching the validator
261
+ /**
262
+ * Returns true if port contains packet(s) matching the validator
263
+ * @param {string|null} scope
264
+ * @param {number|null|HasValidationCallback} index
265
+ * @param {HasValidationCallback} [validate]
266
+ */
213
267
  has(scope, index, validate) {
214
268
  let valid = validate;
215
- let idx = index;
216
- if (!this.isAddressable()) {
217
- valid = idx;
269
+ /** @type {number|null} */
270
+ let idx;
271
+ if (typeof index === 'function') {
272
+ valid = /** @type {HasValidationCallback} */ (index);
218
273
  idx = null;
274
+ } else {
275
+ idx = index;
219
276
  }
220
277
  if (this.hasIPinBuffer(scope, idx, valid)) { return true; }
221
278
  if (this.hasIIP(idx, valid)) { return true; }
222
279
  return false;
223
280
  }
224
281
 
225
- // Returns the number of data packets in an inport
226
- length(scope, index) {
282
+ /**
283
+ * Returns the number of data packets in an inport
284
+ * @param {string|null} scope
285
+ * @param {number|null} [index]
286
+ * @returns {number}
287
+ */
288
+ length(scope, index = null) {
227
289
  const buf = this.getBuffer(scope, index);
228
290
  if (!buf) { return 0; }
229
291
  return buf.length;
230
292
  }
231
293
 
232
- // Tells if buffer has packets or not
294
+ /**
295
+ * Tells if buffer has packets or not
296
+ * @param {string|null} scope
297
+ */
233
298
  ready(scope) {
234
299
  return this.length(scope) > 0;
235
300
  }
@@ -3,7 +3,8 @@
3
3
  // (c) 2011-2012 Henri Bergius, Nemein
4
4
  // NoFlo may be freely distributed under the MIT license
5
5
  import { EventEmitter } from 'events';
6
- import IP from './IP';
6
+ import IP from './IP.js';
7
+ import { makeAsync } from './Platform.js';
7
8
 
8
9
  function legacyToIp(event, payload) {
9
10
  // No need to wrap modern IP Objects
@@ -44,6 +45,13 @@ function ipToLegacy(ip) {
44
45
  }
45
46
  }
46
47
 
48
+ /**
49
+ * @typedef SocketError
50
+ * @property {Error} error
51
+ * @property {string} [id]
52
+ * @property {import("fbp-graph/lib/Types").GraphNodeMetadata} [metadata]
53
+ */
54
+
47
55
  // ## Internal Sockets
48
56
  //
49
57
  // The default communications mechanism between NoFlo processes is
@@ -52,10 +60,16 @@ function ipToLegacy(ip) {
52
60
  // events so that the packets can be caught to the inport of the
53
61
  // connected process.
54
62
  export class InternalSocket extends EventEmitter {
63
+ /**
64
+ * @private
65
+ */
55
66
  regularEmitEvent(event, data) {
56
67
  this.emit(event, data);
57
68
  }
58
69
 
70
+ /**
71
+ * @private
72
+ */
59
73
  debugEmitEvent(event, data) {
60
74
  try {
61
75
  this.emit(event, data);
@@ -70,25 +84,51 @@ export class InternalSocket extends EventEmitter {
70
84
  if (this.listeners('error').length === 0) { throw error; }
71
85
 
72
86
  this.emit('error', {
73
- id: this.to.process.id,
87
+ id: this.to ? this.to.process.id : null,
74
88
  error,
75
89
  metadata: this.metadata,
76
90
  });
77
91
  }
78
92
  }
79
93
 
80
- constructor(metadata = {}) {
94
+ /**
95
+ * @typedef InternalSocketOptions
96
+ * @property {boolean} [debug] - Whether to catch exceptions caused by IP transmission
97
+ * @property {boolean} [async] - Whether IP transmission should be asynchronous
98
+ */
99
+
100
+ /**
101
+ * @param {import("fbp-graph/lib/Types").GraphEdgeMetadata} [metadata]
102
+ * @param {InternalSocketOptions} [options]
103
+ */
104
+ constructor(metadata = {}, options = {}) {
81
105
  super();
82
106
  this.metadata = metadata;
83
107
  this.brackets = [];
84
108
  this.connected = false;
85
109
  this.dataDelegate = null;
86
- this.debug = false;
87
- this.emitEvent = this.regularEmitEvent;
110
+ this.debug = options.debug || false;
111
+ this.async = options.async || false;
88
112
  this.from = null;
89
113
  this.to = null;
90
114
  }
91
115
 
116
+ emitEvent(event, data) {
117
+ if (this.debug) {
118
+ if (this.async) {
119
+ makeAsync(() => this.debugEmitEvent(event, data));
120
+ return;
121
+ }
122
+ this.debugEmitEvent(event, data);
123
+ return;
124
+ }
125
+ if (this.async) {
126
+ makeAsync(() => this.regularEmitEvent(event, data));
127
+ return;
128
+ }
129
+ this.regularEmitEvent(event, data);
130
+ }
131
+
92
132
  // ## Socket connections
93
133
  //
94
134
  // Sockets that are attached to the ports of processes may be
@@ -223,7 +263,6 @@ export class InternalSocket extends EventEmitter {
223
263
  // notification to the developer.
224
264
  setDebug(active) {
225
265
  this.debug = active;
226
- this.emitEvent = this.debug ? this.debugEmitEvent : this.regularEmitEvent;
227
266
  }
228
267
 
229
268
  // ## Socket identifiers
@@ -291,9 +330,10 @@ export class InternalSocket extends EventEmitter {
291
330
  }
292
331
 
293
332
  /**
294
- * @param {Object} [metadata]
333
+ * @param {import("fbp-graph/lib/Types").GraphEdgeMetadata} [metadata]
334
+ * @param {InternalSocketOptions} [options]
295
335
  * @returns {InternalSocket}
296
336
  */
297
- export function createSocket(metadata = {}) {
298
- return new InternalSocket(metadata);
337
+ export function createSocket(metadata = {}, options = {}) {
338
+ return new InternalSocket(metadata, options);
299
339
  }
@@ -2,8 +2,8 @@
2
2
  // (c) 2013-2018 Flowhub UG
3
3
  // (c) 2011-2012 Henri Bergius, Nemein
4
4
  // NoFlo may be freely distributed under the MIT license
5
- import { BaseNetwork } from './BaseNetwork';
6
- import { deprecated } from './Platform';
5
+ import { BaseNetwork } from './BaseNetwork.js';
6
+ import { deprecated } from './Platform.js';
7
7
 
8
8
  /* eslint-disable
9
9
  import/prefer-default-export,
@@ -2,8 +2,8 @@
2
2
  // (c) 2013-2018 Flowhub UG
3
3
  // (c) 2011-2012 Henri Bergius, Nemein
4
4
  // NoFlo may be freely distributed under the MIT license
5
- import { BaseNetwork } from './BaseNetwork';
6
- import { deprecated } from './Platform';
5
+ import { BaseNetwork } from './BaseNetwork.js';
6
+ import { deprecated } from './Platform.js';
7
7
 
8
8
  /* eslint-disable
9
9
  no-param-reassign,
package/src/lib/NoFlo.js CHANGED
@@ -52,6 +52,8 @@ import { graph } from 'fbp-graph';
52
52
  // immediate execution
53
53
  // * `flowtrace`: (default: NULL) Flowtrace instance to create a retroactive debugging
54
54
  // trace of the network run.
55
+ // * `asyncDelivery`: (default: FALSE) Whether Information Packets should be
56
+ // delivered asynchronously.
55
57
  // * `subscribeGraph`: (default: FALSE) Whether the network should monitor the underlying
56
58
  // graph for changes
57
59
  //
@@ -61,9 +63,9 @@ import { graph } from 'fbp-graph';
61
63
  //
62
64
  // The options object can also be used for setting ComponentLoader options in this
63
65
  // network.
64
- import { Network } from './Network';
65
- import { LegacyNetwork } from './LegacyNetwork';
66
- import { deprecated } from './Platform';
66
+ import { Network } from './Network.js';
67
+ import { LegacyNetwork } from './LegacyNetwork.js';
68
+ import { deprecated } from './Platform.js';
67
69
 
68
70
  export {
69
71
  graph,
@@ -76,7 +78,7 @@ export {
76
78
  //
77
79
  // NoFlo works on both Node.js and the browser. Because some dependencies are different,
78
80
  // we need a way to detect which we're on.
79
- export { isBrowser } from './Platform';
81
+ export { isBrowser } from './Platform.js';
80
82
 
81
83
  // ### Component Loader
82
84
  //
@@ -84,33 +86,33 @@ export { isBrowser } from './Platform';
84
86
  // NoFlo components. Component Loader uses [fbp-manifest](https://github.com/flowbased/fbp-manifest)
85
87
  // to find components and graphs by traversing the NPM dependency tree from a given root
86
88
  // directory on the file system.
87
- export { ComponentLoader } from './ComponentLoader';
89
+ export { ComponentLoader } from './ComponentLoader.js';
88
90
 
89
91
  // ### Component baseclasses
90
92
  //
91
93
  // These baseclasses can be used for defining NoFlo components.
92
- export { Component } from './Component';
94
+ export { Component } from './Component.js';
93
95
 
94
96
  // ### NoFlo ports
95
97
  //
96
98
  // These classes are used for instantiating ports on NoFlo components.
97
- export { InPorts, OutPorts } from './Ports';
99
+ export { InPorts, OutPorts } from './Ports.js';
98
100
 
99
- export { default as InPort } from './InPort';
100
- export { default as OutPort } from './OutPort';
101
+ export { default as InPort } from './InPort.js';
102
+ export { default as OutPort } from './OutPort.js';
101
103
 
102
104
  // ### NoFlo sockets
103
105
  //
104
106
  // The NoFlo [internalSocket](InternalSocket.html) is used for connecting ports of
105
107
  // different components together in a network.
106
- import * as internalSocket from './InternalSocket';
108
+ import * as internalSocket from './InternalSocket.js';
107
109
 
108
110
  export { internalSocket };
109
111
 
110
112
  // ### Information Packets
111
113
  //
112
114
  // NoFlo Information Packets are defined as "IP" objects.
113
- export { default as IP } from './IP';
115
+ export { default as IP } from './IP.js';
114
116
 
115
117
  /**
116
118
  * @callback NetworkCallback
@@ -221,7 +223,7 @@ export function saveFile(graphInstance, file, callback) {
221
223
  // // Do something with results
222
224
  // });
223
225
  //
224
- export { asCallback, asPromise } from './AsCallback';
226
+ export { asCallback, asPromise } from './AsCallback.js';
225
227
 
226
228
  // ## Generating components from JavaScript functions
227
229
  //
@@ -235,4 +237,4 @@ export { asCallback, asPromise } from './AsCallback';
235
237
  // });
236
238
  // };
237
239
  //
238
- export { asComponent } from './AsComponent';
240
+ export { asComponent } from './AsComponent.js';
@@ -1,26 +1,24 @@
1
1
  // NoFlo - Flow-Based Programming for JavaScript
2
2
  // (c) 2014-2017 Flowhub UG
3
3
  // NoFlo may be freely distributed under the MIT license
4
- import BasePort from './BasePort';
5
- import IP from './IP';
4
+ import BasePort from './BasePort.js';
5
+ import IP from './IP.js';
6
6
 
7
7
  // ## NoFlo outport
8
8
  //
9
9
  // Outport Port (outport) implementation for NoFlo components.
10
10
  // These ports are the way a component sends Information Packets.
11
11
  /**
12
- * @typedef {Object} OutportOptions - Options for configuring outports
13
- * @property {string} [description='']
14
- * @property {string} [datatype='all']
15
- * @property {string} [schema=null]
16
- * @property {boolean} [required=false]
17
- * @property {boolean} [caching=false]
18
- * @property {boolean} [scoped=true]
12
+ * @typedef OutPortOptions
13
+ * @property {boolean} [caching]
14
+ */
15
+ /**
16
+ * @typedef {import("./BasePort").BaseOptions & OutPortOptions} PortOptions
19
17
  */
20
18
 
21
19
  export default class OutPort extends BasePort {
22
20
  /**
23
- * @param {OutportOptions} options - Options for the outport
21
+ * @param {PortOptions} options - Options for the outport
24
22
  */
25
23
  constructor(options = {}) {
26
24
  const opts = options;
@@ -29,16 +27,28 @@ export default class OutPort extends BasePort {
29
27
  opts.caching = false;
30
28
  }
31
29
  super(opts);
30
+
31
+ const baseOptions = this.options;
32
+ this.options = /** @type {PortOptions} */ (baseOptions);
33
+
34
+ /** @type {Object<string, IP>} */
32
35
  this.cache = {};
33
36
  }
34
37
 
38
+ /**
39
+ * @param {import("./InternalSocket").InternalSocket} socket
40
+ * @param {number|null} [index]
41
+ */
35
42
  attach(socket, index = null) {
36
43
  super.attach(socket, index);
37
- if (this.isCaching() && (this.cache[index] != null)) {
38
- this.send(this.cache[index], index);
44
+ if (this.isCaching() && (this.cache[`${index}`] != null)) {
45
+ this.send(this.cache[`${index}`], index);
39
46
  }
40
47
  }
41
48
 
49
+ /**
50
+ * @param {number|null} [index]
51
+ */
42
52
  connect(index = null) {
43
53
  const sockets = this.getSockets(index);
44
54
  this.checkRequired(sockets);
@@ -48,6 +58,10 @@ export default class OutPort extends BasePort {
48
58
  });
49
59
  }
50
60
 
61
+ /**
62
+ * @param {string} group
63
+ * @param {number|null} [index]
64
+ */
51
65
  beginGroup(group, index = null) {
52
66
  const sockets = this.getSockets(index);
53
67
  this.checkRequired(sockets);
@@ -57,11 +71,15 @@ export default class OutPort extends BasePort {
57
71
  });
58
72
  }
59
73
 
74
+ /**
75
+ * @param {any} data
76
+ * @param {number|null} [index]
77
+ */
60
78
  send(data, index = null) {
61
79
  const sockets = this.getSockets(index);
62
80
  this.checkRequired(sockets);
63
- if (this.isCaching() && (data !== this.cache[index])) {
64
- this.cache[index] = data;
81
+ if (this.isCaching() && (data !== this.cache[`${index}`])) {
82
+ this.cache[`${index}`] = data;
65
83
  }
66
84
  sockets.forEach((socket) => {
67
85
  if (!socket) { return; }
@@ -69,6 +87,9 @@ export default class OutPort extends BasePort {
69
87
  });
70
88
  }
71
89
 
90
+ /**
91
+ * @param {number|null} [index]
92
+ */
72
93
  endGroup(index = null) {
73
94
  const sockets = this.getSockets(index);
74
95
  this.checkRequired(sockets);
@@ -78,6 +99,9 @@ export default class OutPort extends BasePort {
78
99
  });
79
100
  }
80
101
 
102
+ /**
103
+ * @param {number|null} [index]
104
+ */
81
105
  disconnect(index = null) {
82
106
  const sockets = this.getSockets(index);
83
107
  this.checkRequired(sockets);
@@ -87,14 +111,24 @@ export default class OutPort extends BasePort {
87
111
  });
88
112
  }
89
113
 
90
- sendIP(type, data, options, index, autoConnect = true) {
114
+ /**
115
+ * @param {string|IP} type
116
+ * @param {any} [data]
117
+ * @param {import("./IP").IPOptions} [options]
118
+ * @param {number|null} [index]
119
+ * @param {boolean} [autoConnect]
120
+ */
121
+ sendIP(type, data, options, index = null, autoConnect = true) {
122
+ /** @type {IP} */
91
123
  let ip;
92
124
  let idx = index;
93
125
  if (IP.isIP(type)) {
94
- ip = type;
126
+ ip = /** @type {IP} */ (type);
95
127
  idx = ip.index;
96
- } else {
128
+ } else if (typeof type === 'string') {
97
129
  ip = new IP(type, data, options);
130
+ } else {
131
+ throw new Error('Unknown type for IP type');
98
132
  }
99
133
  const sockets = this.getSockets(idx);
100
134
  this.checkRequired(sockets);
@@ -108,9 +142,9 @@ export default class OutPort extends BasePort {
108
142
  ip.schema = this.getSchema();
109
143
  }
110
144
 
111
- const cachedData = this.cache[idx] != null ? this.cache[idx].data : undefined;
145
+ const cachedData = this.cache[`${idx}`] != null ? this.cache[`${idx}`].data : undefined;
112
146
  if (this.isCaching() && data !== cachedData) {
113
- this.cache[idx] = ip;
147
+ this.cache[`${idx}`] = ip;
114
148
  }
115
149
  let pristine = true;
116
150
  sockets.forEach((socket) => {
@@ -126,30 +160,57 @@ export default class OutPort extends BasePort {
126
160
  return this;
127
161
  }
128
162
 
163
+ /**
164
+ * @param {string|null} data
165
+ * @param {import("./IP").IPOptions} options
166
+ * @param {number|null} [index]
167
+ */
129
168
  openBracket(data = null, options = {}, index = null) {
130
169
  return this.sendIP('openBracket', data, options, index);
131
170
  }
132
171
 
172
+ /**
173
+ * @param {any} data
174
+ * @param {import("./IP").IPOptions} options
175
+ * @param {number|null} [index]
176
+ */
133
177
  data(data, options = {}, index = null) {
134
178
  return this.sendIP('data', data, options, index);
135
179
  }
136
180
 
181
+ /**
182
+ * @param {string|null} data
183
+ * @param {import("./IP").IPOptions} options
184
+ * @param {number|null} [index]
185
+ */
137
186
  closeBracket(data = null, options = {}, index = null) {
138
187
  return this.sendIP('closeBracket', data, options, index);
139
188
  }
140
189
 
190
+ /**
191
+ * @param {Array<import("./InternalSocket").InternalSocket|void>} sockets
192
+ */
141
193
  checkRequired(sockets) {
142
194
  if ((sockets.length === 0) && this.isRequired()) {
143
195
  throw new Error(`${this.getId()}: No connections available`);
144
196
  }
145
197
  }
146
198
 
199
+ /**
200
+ * @param {number|null} index
201
+ * @returns {Array<import("./InternalSocket").InternalSocket|void>}
202
+ */
147
203
  getSockets(index) {
148
204
  // Addressable sockets affect only one connection at time
149
205
  if (this.isAddressable()) {
150
- if (index === null) { throw new Error(`${this.getId()} Socket ID required`); }
151
- if (!this.sockets[index]) { return []; }
152
- return [this.sockets[index]];
206
+ if (index === null) {
207
+ throw new Error(`${this.getId()} Socket ID required`);
208
+ }
209
+ const idx = /** @type {number} */ (index);
210
+ if (!this.sockets[idx]) {
211
+ return [];
212
+ }
213
+ return [this.sockets[idx]];
153
214
  }
154
215
  // Regular sockets affect all outbound connections
155
216
  return this.sockets;
@@ -41,12 +41,17 @@ export function deprecated(message) {
41
41
  * @param {Function} func
42
42
  * @returns {void}
43
43
  */
44
- export function makeAsync(func) {
44
+ export function makeAsync(func, sameLoop = false) {
45
45
  if (isBrowser()) {
46
+ // FIXME: Browsers don't have setImmediate yet so can't do same loop
46
47
  setTimeout(func, 0);
47
48
  return;
48
49
  }
49
- setImmediate(() => {
50
- func();
51
- });
50
+ if (sameLoop) {
51
+ setImmediate(() => {
52
+ func();
53
+ });
54
+ return;
55
+ }
56
+ process.nextTick(func);
52
57
  }