noflo 1.4.3 → 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 -527
  4. package/README.md +1 -1
  5. package/bin/noflo-cache-preheat +4 -4
  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 +64 -9
  25. package/lib/InPort.js +72 -13
  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 +64 -13
  35. package/lib/OutPort.js +73 -15
  36. package/lib/Platform.d.ts +1 -1
  37. package/lib/Platform.js +9 -4
  38. package/lib/Ports.d.ts +11 -12
  39. package/lib/Ports.js +8 -4
  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 -2
  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 +74 -13
  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 +77 -14
  82. package/src/lib/Platform.js +9 -4
  83. package/src/lib/Ports.js +6 -2
  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,7 +1,7 @@
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
  //
@@ -9,9 +9,16 @@ import BasePort from './BasePort';
9
9
  // ports are the way a component receives Information Packets.
10
10
  /**
11
11
  * @typedef InPortOptions
12
+ * @property {any} [default]
13
+ * @property {Array<any>} [values]
12
14
  * @property {boolean} [control]
13
15
  * @property {boolean} [triggering]
14
16
  */
17
+ /**
18
+ * @callback HasValidationCallback
19
+ * @param {import("./IP").default} ip
20
+ * @returns {boolean}
21
+ */
15
22
  /**
16
23
  * @typedef {import("./BasePort").BaseOptions & InPortOptions} PortOptions
17
24
  */
@@ -28,12 +35,21 @@ export default class InPort extends BasePort {
28
35
 
29
36
  super(opts);
30
37
 
38
+ const baseOptions = this.options;
39
+ this.options = /** @type {PortOptions} */ (baseOptions);
40
+
41
+ /** @type {import("./Component").Component|null} */
31
42
  this.nodeInstance = null;
32
43
 
33
44
  this.prepareBuffer();
34
45
  }
35
46
 
36
- // 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
+ */
37
53
  attachSocket(socket, localId = null) {
38
54
  // have a default value.
39
55
  if (this.hasDefault()) {
@@ -51,11 +67,17 @@ export default class InPort extends BasePort {
51
67
  socket.on('ip', (ip) => this.handleIP(ip, localId));
52
68
  }
53
69
 
54
- handleIP(packet, index) {
70
+ /**
71
+ * @param {import("./IP").default} packet
72
+ * @param {number|null} [index]
73
+ */
74
+ handleIP(packet, index = null) {
55
75
  if (this.options.control && (packet.type !== 'data')) { return; }
56
76
  const ip = packet;
57
77
  ip.owner = this.nodeInstance;
58
- if (this.isAddressable()) { ip.index = index; }
78
+ if (this.isAddressable()) {
79
+ ip.index = index;
80
+ }
59
81
  if (ip.datatype === 'all') {
60
82
  // Stamp non-specific IP objects with port datatype
61
83
  ip.datatype = this.getDataType();
@@ -72,6 +94,11 @@ export default class InPort extends BasePort {
72
94
  this.emit('ip', ip, index);
73
95
  }
74
96
 
97
+ /**
98
+ * @param {string} event
99
+ * @param {any} payload
100
+ * @param {number} [id]
101
+ */
75
102
  handleSocketEvent(event, payload, id) {
76
103
  // Emit port event
77
104
  if (this.isAddressable()) {
@@ -138,6 +165,9 @@ export default class InPort extends BasePort {
138
165
  return this.buffer;
139
166
  }
140
167
 
168
+ /**
169
+ * @param {any} data
170
+ */
141
171
  validateData(data) {
142
172
  if (!this.options.values) { return; }
143
173
  if (this.options.values.indexOf(data) === -1) {
@@ -192,14 +222,25 @@ export default class InPort extends BasePort {
192
222
  return buf.shift();
193
223
  }
194
224
 
195
- // Fetches a packet from the port
196
- 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) {
197
231
  const res = this.getFromBuffer(scope, index);
198
232
  if (res !== undefined) { return res; }
199
233
  // Try to find an IIP instead
200
234
  return this.getFromBuffer(null, index, true);
201
235
  }
202
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
+ */
203
244
  hasIPinBuffer(scope, index, validate, initial = false) {
204
245
  const buf = this.getBuffer(scope, index, initial);
205
246
  if (!(buf != null ? buf.length : undefined)) { return false; }
@@ -209,31 +250,51 @@ export default class InPort extends BasePort {
209
250
  return false;
210
251
  }
211
252
 
253
+ /**
254
+ * @param {number|null} index
255
+ * @param {HasValidationCallback} validate
256
+ */
212
257
  hasIIP(index, validate) {
213
258
  return this.hasIPinBuffer(null, index, validate, true);
214
259
  }
215
260
 
216
- // 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
+ */
217
267
  has(scope, index, validate) {
218
268
  let valid = validate;
219
- let idx = index;
220
- if (!this.isAddressable()) {
221
- valid = idx;
269
+ /** @type {number|null} */
270
+ let idx;
271
+ if (typeof index === 'function') {
272
+ valid = /** @type {HasValidationCallback} */ (index);
222
273
  idx = null;
274
+ } else {
275
+ idx = index;
223
276
  }
224
277
  if (this.hasIPinBuffer(scope, idx, valid)) { return true; }
225
278
  if (this.hasIIP(idx, valid)) { return true; }
226
279
  return false;
227
280
  }
228
281
 
229
- // Returns the number of data packets in an inport
230
- 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) {
231
289
  const buf = this.getBuffer(scope, index);
232
290
  if (!buf) { return 0; }
233
291
  return buf.length;
234
292
  }
235
293
 
236
- // Tells if buffer has packets or not
294
+ /**
295
+ * Tells if buffer has packets or not
296
+ * @param {string|null} scope
297
+ */
237
298
  ready(scope) {
238
299
  return this.length(scope) > 0;
239
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,8 +1,8 @@
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
  //
@@ -27,16 +27,28 @@ export default class OutPort extends BasePort {
27
27
  opts.caching = false;
28
28
  }
29
29
  super(opts);
30
+
31
+ const baseOptions = this.options;
32
+ this.options = /** @type {PortOptions} */ (baseOptions);
33
+
34
+ /** @type {Object<string, IP>} */
30
35
  this.cache = {};
31
36
  }
32
37
 
38
+ /**
39
+ * @param {import("./InternalSocket").InternalSocket} socket
40
+ * @param {number|null} [index]
41
+ */
33
42
  attach(socket, index = null) {
34
43
  super.attach(socket, index);
35
- if (this.isCaching() && (this.cache[index] != null)) {
36
- this.send(this.cache[index], index);
44
+ if (this.isCaching() && (this.cache[`${index}`] != null)) {
45
+ this.send(this.cache[`${index}`], index);
37
46
  }
38
47
  }
39
48
 
49
+ /**
50
+ * @param {number|null} [index]
51
+ */
40
52
  connect(index = null) {
41
53
  const sockets = this.getSockets(index);
42
54
  this.checkRequired(sockets);
@@ -46,6 +58,10 @@ export default class OutPort extends BasePort {
46
58
  });
47
59
  }
48
60
 
61
+ /**
62
+ * @param {string} group
63
+ * @param {number|null} [index]
64
+ */
49
65
  beginGroup(group, index = null) {
50
66
  const sockets = this.getSockets(index);
51
67
  this.checkRequired(sockets);
@@ -55,11 +71,15 @@ export default class OutPort extends BasePort {
55
71
  });
56
72
  }
57
73
 
74
+ /**
75
+ * @param {any} data
76
+ * @param {number|null} [index]
77
+ */
58
78
  send(data, index = null) {
59
79
  const sockets = this.getSockets(index);
60
80
  this.checkRequired(sockets);
61
- if (this.isCaching() && (data !== this.cache[index])) {
62
- this.cache[index] = data;
81
+ if (this.isCaching() && (data !== this.cache[`${index}`])) {
82
+ this.cache[`${index}`] = data;
63
83
  }
64
84
  sockets.forEach((socket) => {
65
85
  if (!socket) { return; }
@@ -67,6 +87,9 @@ export default class OutPort extends BasePort {
67
87
  });
68
88
  }
69
89
 
90
+ /**
91
+ * @param {number|null} [index]
92
+ */
70
93
  endGroup(index = null) {
71
94
  const sockets = this.getSockets(index);
72
95
  this.checkRequired(sockets);
@@ -76,6 +99,9 @@ export default class OutPort extends BasePort {
76
99
  });
77
100
  }
78
101
 
102
+ /**
103
+ * @param {number|null} [index]
104
+ */
79
105
  disconnect(index = null) {
80
106
  const sockets = this.getSockets(index);
81
107
  this.checkRequired(sockets);
@@ -85,14 +111,24 @@ export default class OutPort extends BasePort {
85
111
  });
86
112
  }
87
113
 
88
- 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} */
89
123
  let ip;
90
124
  let idx = index;
91
125
  if (IP.isIP(type)) {
92
- ip = type;
126
+ ip = /** @type {IP} */ (type);
93
127
  idx = ip.index;
94
- } else {
128
+ } else if (typeof type === 'string') {
95
129
  ip = new IP(type, data, options);
130
+ } else {
131
+ throw new Error('Unknown type for IP type');
96
132
  }
97
133
  const sockets = this.getSockets(idx);
98
134
  this.checkRequired(sockets);
@@ -106,9 +142,9 @@ export default class OutPort extends BasePort {
106
142
  ip.schema = this.getSchema();
107
143
  }
108
144
 
109
- const cachedData = this.cache[idx] != null ? this.cache[idx].data : undefined;
145
+ const cachedData = this.cache[`${idx}`] != null ? this.cache[`${idx}`].data : undefined;
110
146
  if (this.isCaching() && data !== cachedData) {
111
- this.cache[idx] = ip;
147
+ this.cache[`${idx}`] = ip;
112
148
  }
113
149
  let pristine = true;
114
150
  sockets.forEach((socket) => {
@@ -124,30 +160,57 @@ export default class OutPort extends BasePort {
124
160
  return this;
125
161
  }
126
162
 
163
+ /**
164
+ * @param {string|null} data
165
+ * @param {import("./IP").IPOptions} options
166
+ * @param {number|null} [index]
167
+ */
127
168
  openBracket(data = null, options = {}, index = null) {
128
169
  return this.sendIP('openBracket', data, options, index);
129
170
  }
130
171
 
172
+ /**
173
+ * @param {any} data
174
+ * @param {import("./IP").IPOptions} options
175
+ * @param {number|null} [index]
176
+ */
131
177
  data(data, options = {}, index = null) {
132
178
  return this.sendIP('data', data, options, index);
133
179
  }
134
180
 
181
+ /**
182
+ * @param {string|null} data
183
+ * @param {import("./IP").IPOptions} options
184
+ * @param {number|null} [index]
185
+ */
135
186
  closeBracket(data = null, options = {}, index = null) {
136
187
  return this.sendIP('closeBracket', data, options, index);
137
188
  }
138
189
 
190
+ /**
191
+ * @param {Array<import("./InternalSocket").InternalSocket|void>} sockets
192
+ */
139
193
  checkRequired(sockets) {
140
194
  if ((sockets.length === 0) && this.isRequired()) {
141
195
  throw new Error(`${this.getId()}: No connections available`);
142
196
  }
143
197
  }
144
198
 
199
+ /**
200
+ * @param {number|null} index
201
+ * @returns {Array<import("./InternalSocket").InternalSocket|void>}
202
+ */
145
203
  getSockets(index) {
146
204
  // Addressable sockets affect only one connection at time
147
205
  if (this.isAddressable()) {
148
- if (index === null) { throw new Error(`${this.getId()} Socket ID required`); }
149
- if (!this.sockets[index]) { return []; }
150
- 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]];
151
214
  }
152
215
  // Regular sockets affect all outbound connections
153
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
  }
package/src/lib/Ports.js CHANGED
@@ -3,8 +3,8 @@
3
3
  // (c) 2014-2017 Flowhub UG
4
4
  // NoFlo may be freely distributed under the MIT license
5
5
  import { EventEmitter } from 'events';
6
- import InPort from './InPort';
7
- import OutPort from './OutPort';
6
+ import InPort from './InPort.js';
7
+ import OutPort from './OutPort.js';
8
8
 
9
9
  /**
10
10
  * @typedef {import("./BasePort").BaseOptions} PortOptions
@@ -85,6 +85,8 @@ export class InPorts extends Ports {
85
85
  */
86
86
  constructor(ports = {}) {
87
87
  super(ports, InPort);
88
+ const basePorts = this.ports;
89
+ this.ports = /** @type {Object<string, InPort>} */ (basePorts);
88
90
  }
89
91
  }
90
92
 
@@ -97,6 +99,8 @@ export class OutPorts extends Ports {
97
99
  */
98
100
  constructor(ports = {}) {
99
101
  super(ports, OutPort);
102
+ const basePorts = this.ports;
103
+ this.ports = /** @type {Object<string, OutPort>} */ (basePorts);
100
104
  }
101
105
 
102
106
  connect(name, socketId) {