vaporous 0.0.10 → 0.0.12

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/Vaporous.js CHANGED
@@ -85,7 +85,7 @@ class Vaporous {
85
85
  * @returns {Vaporous} - Returns this instance for chaining
86
86
  */
87
87
  method(operation, name, options) {
88
- return core.method.call(this, operation, name, options);
88
+ return processing.method.call(this, operation, name, options);
89
89
  }
90
90
 
91
91
  /**
@@ -108,13 +108,17 @@ class Vaporous {
108
108
 
109
109
  /**
110
110
  * Execute all queued operations
111
- * @param {string} [stageName] - Optional stage name for logging
112
- * @returns {Promise<Vaporous>} - Returns this instance for chaining
111
+ * @param {string} [stageName] - Optional stage name for logging
112
+ * @returns {Promise<Vaporous>} - Returns this instance for chaining
113
113
  */
114
- async begin(stageName) {
115
- return await core.begin.call(this, stageName);
114
+ begin(stageName) {
115
+ return core.begin.call(this, stageName);
116
116
  }
117
117
 
118
+ /**
119
+ * Serialize the Vaporous instance to a plain object
120
+ * @returns {Object} - Serialized instance data
121
+ */
118
122
  serialise({ } = {}) {
119
123
  return core.serialise.call(this);
120
124
  }
@@ -167,6 +171,7 @@ class Vaporous {
167
171
  /**
168
172
  * Evaluate and modify each event
169
173
  * @param {Function} modifier - Function that receives an event and returns modifications to apply
174
+ * @param {boolean} [discard] - Whether to discard the event if modifier returns falsy
170
175
  * @returns {Vaporous} - Returns this instance for chaining
171
176
  */
172
177
  eval(modifier, discard) {
@@ -233,8 +238,8 @@ class Vaporous {
233
238
  * @param {string} target - Field name containing array to expand
234
239
  * @returns {Vaporous} - Returns this instance for chaining
235
240
  */
236
- mvexpand(target) {
237
- return transformations.mvexpand.call(this, target);
241
+ mvexpand(...targets) {
242
+ return transformations.mvexpand.call(this, targets);
238
243
  }
239
244
 
240
245
  // ========================================
@@ -246,15 +251,15 @@ class Vaporous {
246
251
  * @private
247
252
  */
248
253
  _fileScan(directory) {
249
- return fileOperations._fileScan?.call(this, directory);
254
+ return fileOperations._fileScan.call(this, directory);
250
255
  }
251
256
 
252
257
  /**
253
258
  * Internal file load helper
254
259
  * @private
255
260
  */
256
- async _fileLoad(events, delim, parser) {
257
- return await fileOperations._fileLoad?.call(this, events, delim, parser);
261
+ _fileLoad(events, delim, parser) {
262
+ return fileOperations._fileLoad.call(this, events, delim, parser);
258
263
  }
259
264
 
260
265
  /**
@@ -263,7 +268,7 @@ class Vaporous {
263
268
  * @returns {Vaporous} - Returns this instance for chaining
264
269
  */
265
270
  fileScan(directory) {
266
- return fileOperations.fileScan?.call(this, directory) || this;
271
+ return fileOperations.fileScan.call(this, directory);
267
272
  }
268
273
 
269
274
  /**
@@ -271,8 +276,8 @@ class Vaporous {
271
276
  * @param {Function} parser - Parser function for CSV rows
272
277
  * @returns {Vaporous} - Returns this instance for chaining
273
278
  */
274
- async csvLoad(parser) {
275
- return await fileOperations.csvLoad?.call(this, parser) || this;
279
+ csvLoad(parser) {
280
+ return fileOperations.csvLoad.call(this, parser);
276
281
  }
277
282
 
278
283
  /**
@@ -281,8 +286,8 @@ class Vaporous {
281
286
  * @param {Function} parser - Parser function for lines
282
287
  * @returns {Vaporous} - Returns this instance for chaining
283
288
  */
284
- async fileLoad(delim, parser) {
285
- return await fileOperations.fileLoad?.call(this, delim, parser) || this;
289
+ fileLoad(delim, parser) {
290
+ return fileOperations.fileLoad.call(this, delim, parser);
286
291
  }
287
292
 
288
293
  /**
@@ -291,7 +296,7 @@ class Vaporous {
291
296
  * @returns {Vaporous} - Returns this instance for chaining
292
297
  */
293
298
  writeFile(title) {
294
- return fileOperations.writeFile?.call(this, title) || this;
299
+ return fileOperations.writeFile.call(this, title);
295
300
  }
296
301
 
297
302
  /**
@@ -300,7 +305,7 @@ class Vaporous {
300
305
  * @returns {Vaporous} - Returns this instance for chaining
301
306
  */
302
307
  output(...args) {
303
- return fileOperations.output?.call(this, ...args) || this;
308
+ return fileOperations.output.call(this, ...args);
304
309
  }
305
310
 
306
311
  // ========================================
@@ -321,7 +326,7 @@ class Vaporous {
321
326
  * @returns {Vaporous} - Returns this instance for chaining
322
327
  */
323
328
  stats(...args) {
324
- return statistics.stats?.call(this, ...args) || this;
329
+ return statistics.stats.call(this, ...args);
325
330
  }
326
331
 
327
332
  /**
@@ -330,7 +335,7 @@ class Vaporous {
330
335
  * @returns {Vaporous} - Returns this instance for chaining
331
336
  */
332
337
  eventstats(...args) {
333
- return statistics.eventstats?.call(this, ...args) || this;
338
+ return statistics.eventstats.call(this, ...args);
334
339
  }
335
340
 
336
341
  /**
@@ -338,7 +343,7 @@ class Vaporous {
338
343
  * @private
339
344
  */
340
345
  _streamstats(...args) {
341
- return statistics._streamstats?.call(this, ...args) || this;
346
+ return statistics._streamstats.call(this, ...args);
342
347
  }
343
348
 
344
349
  /**
@@ -347,7 +352,7 @@ class Vaporous {
347
352
  * @returns {Vaporous} - Returns this instance for chaining
348
353
  */
349
354
  streamstats(...args) {
350
- return statistics.streamstats?.call(this, ...args) || this;
355
+ return statistics.streamstats.call(this, ...args);
351
356
  }
352
357
 
353
358
  /**
@@ -358,7 +363,7 @@ class Vaporous {
358
363
  * @returns {Vaporous} - Returns this instance for chaining
359
364
  */
360
365
  delta(field, remapField, ...bys) {
361
- return statistics.delta?.call(this, field, remapField, ...bys) || this;
366
+ return statistics.delta.call(this, field, remapField, ...bys);
362
367
  }
363
368
 
364
369
  // ========================================
@@ -370,7 +375,7 @@ class Vaporous {
370
375
  * @private
371
376
  */
372
377
  _checkpoint(operation, name, data, options) {
373
- return checkpoints._checkpoint?.call(this, operation, name, data, options) || this;
378
+ return checkpoints._checkpoint.call(this, operation, name, data, options);
374
379
  }
375
380
 
376
381
  /**
@@ -381,7 +386,7 @@ class Vaporous {
381
386
  * @returns {Vaporous} - Returns this instance for chaining
382
387
  */
383
388
  checkpoint(operation, name, options) {
384
- return checkpoints.checkpoint?.call(this, operation, name, options) || this;
389
+ return checkpoints.checkpoint.call(this, operation, name, options);
385
390
  }
386
391
 
387
392
  /**
@@ -392,7 +397,7 @@ class Vaporous {
392
397
  * @returns {Vaporous} - Returns this instance for chaining
393
398
  */
394
399
  filterIntoCheckpoint(checkpointName, funct, options) {
395
- return checkpoints.filterIntoCheckpoint?.call(this, checkpointName, funct, options) || this;
400
+ return checkpoints.filterIntoCheckpoint.call(this, checkpointName, funct, options);
396
401
  }
397
402
 
398
403
  /**
@@ -402,8 +407,8 @@ class Vaporous {
402
407
  * @param {string} partitionBy - Field to partition by
403
408
  * @returns {Vaporous} - Returns this instance for chaining
404
409
  */
405
- async storedCheckpoint(operation, name, partitionBy) {
406
- return await checkpoints.storedCheckpoint?.call(this, operation, name, partitionBy) || this;
410
+ storedCheckpoint(operation, name, partitionBy) {
411
+ return checkpoints.storedCheckpoint.call(this, operation, name, partitionBy);
407
412
  }
408
413
 
409
414
  // ========================================
@@ -416,7 +421,7 @@ class Vaporous {
416
421
  * @returns {Vaporous} - Returns this instance for chaining
417
422
  */
418
423
  toGraph(...keys) {
419
- return visualization.toGraph?.call(this, ...keys) || this;
424
+ return visualization.toGraph.call(this, ...keys);
420
425
  }
421
426
 
422
427
  /**
@@ -427,16 +432,17 @@ class Vaporous {
427
432
  * @returns {Vaporous} - Returns this instance for chaining
428
433
  */
429
434
  build(title, type, options) {
430
- return visualization.build?.call(this, title, type, options) || this;
435
+ return visualization.build.call(this, title, type, options);
431
436
  }
432
437
 
433
438
  /**
434
439
  * Render visualizations
440
+ * @param {string} location - Location to render visualizations
435
441
  * @param {Object} [options] - Optional render options
436
442
  * @returns {Vaporous} - Returns this instance for chaining
437
443
  */
438
- render(options) {
439
- return visualization.render?.call(this, options) || this;
444
+ render(location, options) {
445
+ return visualization.render.call(this, location, options);
440
446
  }
441
447
 
442
448
  // ========================================
@@ -449,7 +455,7 @@ class Vaporous {
449
455
  * @returns {Vaporous} - Returns this instance for chaining
450
456
  */
451
457
  load_http(options) {
452
- return http.load_http?.call(this, options) || this;
458
+ return http.load_http.call(this, options);
453
459
  }
454
460
 
455
461
  // ========================================
@@ -463,7 +469,7 @@ class Vaporous {
463
469
  * @returns {Vaporous} - Returns this instance for chaining
464
470
  */
465
471
  interval(callback, ms) {
466
- return processing.interval?.call(this, callback, ms) || this;
472
+ return processing.interval.call(this, callback, ms);
467
473
  }
468
474
 
469
475
  /**
@@ -474,19 +480,35 @@ class Vaporous {
474
480
  * @returns {Vaporous} - Returns this instance for chaining
475
481
  */
476
482
  parallel(concurrency, callback, options) {
477
- return processing.parallel?.call(this, concurrency, callback, options) || this;
483
+ return processing.parallel.call(this, concurrency, callback, options);
478
484
  }
479
485
 
486
+ /**
487
+ * Recursively process events
488
+ * @param {Function} callback - Function to execute recursively
489
+ * @returns {Vaporous} - Returns this instance for chaining
490
+ */
480
491
  recurse(callback) {
481
- return processing.recurse?.call(this, callback)
492
+ return processing.recurse.call(this, callback);
482
493
  }
483
494
 
495
+ /**
496
+ * Debug events by executing a callback
497
+ * @param {Function} callback - Debug callback function
498
+ * @returns {Vaporous} - Returns this instance for chaining
499
+ */
484
500
  debug(callback) {
485
- return core.debug.call(this, callback)
501
+ return core.debug.call(this, callback);
486
502
  }
487
503
 
504
+ /**
505
+ * Conditionally execute a callback
506
+ * @param {Function|boolean} condition - Condition to evaluate or boolean value
507
+ * @param {Function} callback - Function to execute if condition is true
508
+ * @returns {Vaporous} - Returns this instance for chaining
509
+ */
488
510
  doIf(condition, callback) {
489
- return processing.doIf.call(this, condition, callback)
511
+ return processing.doIf.call(this, condition, callback);
490
512
  }
491
513
  }
492
514
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vaporous",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Transition data to different structured states for analytical processing",
5
5
  "main": "Vaporous.js",
6
6
  "scripts": {
@@ -10,6 +10,8 @@
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
12
  "dayjs": "^1.11.18",
13
+ "http-proxy-agent": "^7.0.2",
14
+ "https-proxy-agent": "^7.0.6",
13
15
  "papaparse": "^5.5.3",
14
16
  "split2": "^4.2.0"
15
17
  }
package/src/core.js CHANGED
@@ -1,23 +1,4 @@
1
1
  module.exports = {
2
- method(operation, name, options) {
3
- const operations = {
4
- create: () => {
5
- this.savedMethods[name] = options
6
- },
7
- retrieve: () => {
8
- if (!this.savedMethods[name]) throw new Error('Method not found ' + name)
9
- this.savedMethods[name](this, options)
10
- },
11
- delete: () => {
12
- delete this.savedMethods[name]
13
- }
14
- }
15
-
16
- operations[operation]()
17
- if (operation !== 'retrieve') return this;
18
- return this;
19
- },
20
-
21
2
  async debug(callback) {
22
3
  await callback(this)
23
4
  return this;
@@ -71,20 +52,12 @@ module.exports = {
71
52
  const Vaporous = require('../Vaporous').Vaporous;
72
53
  const cloneInstance = new Vaporous()
73
54
 
74
- const excludeStructualClone = ['loggers', 'intervals']
75
- const excludeCompletely = ['_isExecuting']
76
-
77
- Object.keys(this).forEach(key => {
78
- if (excludeCompletely.includes(key)) return;
79
- cloneInstance[key] = (deep && !excludeStructualClone.includes(key)) ? structuredClone(this[key]) : this[key]
80
- })
81
-
82
- const purge = ['checkpoints', 'events']
83
-
84
- purge.forEach(purgeItem => {
85
- cloneInstance[purgeItem] = []
55
+ Object.keys(this).forEach(prop => {
56
+ cloneInstance[prop] = this[prop]
86
57
  })
87
58
 
59
+ cloneInstance.processingQueue = []
60
+ cloneInstance._isExecuting = false
88
61
  return cloneInstance
89
62
  },
90
63
 
package/src/http.js CHANGED
@@ -3,59 +3,64 @@ const httpsLib = require('https')
3
3
  const { HttpProxyAgent } = require('http-proxy-agent')
4
4
  const { HttpsProxyAgent } = require('https-proxy-agent')
5
5
 
6
+ const request = async ({ uri, method, headers, body, options = {} }) => {
7
+ const response = await new Promise((resolve, reject) => {
8
+ const isHTTPs = uri.startsWith('https')
9
+ const lib = isHTTPs ? httpsLib : httpLib
10
+ const { hostname, port, pathname, search } = new URL(uri)
11
+ const path = pathname + (search || '')
6
12
 
7
- async function load_http() {
13
+ const options = {
14
+ method,
15
+ hostname,
16
+ port,
17
+ path,
18
+ headers
19
+ }
8
20
 
9
- for (let event of this.events) {
10
- const { _http_req_uri,
11
- _http_req_method,
12
- _http_req_headers,
13
- _http_req_body } = event
14
-
15
-
16
- const task = new Promise((resolve, reject) => {
17
- const lib = _http_req_uri.startsWith('https') ? httpsLib : httpLib
18
- const { hostname, port, pathname, search } = new URL(_http_req_uri)
19
- const path = pathname + (search || '')
20
-
21
- const options = {
22
- method: _http_req_method,
23
- hostname,
24
- port,
25
- path,
26
- headers: _http_req_headers
27
- }
28
-
29
- const proxy = process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy
30
-
31
- if (proxy) {
32
- const isHttps = _http_req_uri.startsWith('https')
33
- options.agent = isHttps ? new HttpsProxyAgent(proxy) : new HttpProxyAgent(proxy)
34
- }
35
-
36
- const req = lib.request(options, res => {
37
- let body = '';
38
-
39
- res.on('data', data => {
40
- body += data
41
- })
42
-
43
- res.on('end', () => {
44
- event._http_res_body = body
45
- event._http_res_status = res.statusCode
46
- event._http_res_headers = res.headers
47
- resolve(body)
48
- })
21
+ const proxy = isHTTPs ? (process.env.https_proxy || process.env.HTTPS_PROXY) : (process.env.http_proxy || process.env.HTTP_PROXY)
22
+
23
+ if (proxy) options.agent = isHTTPs ? new HttpsProxyAgent(proxy) : new HttpProxyAgent(proxy)
24
+
25
+ const req = lib.request(options, res => {
26
+ let body = '';
27
+
28
+ res.on('data', data => {
29
+ body += data
30
+ })
31
+
32
+ res.on('end', () => {
33
+ resolve({ body, statusCode: res.statusCode, headers: res.headers })
49
34
  })
35
+ })
50
36
 
51
- if (_http_req_body) req.write(_http_req_body)
52
- req.end()
37
+ if (body) req.write(body)
38
+ req.end()
39
+ })
40
+
41
+ if (response.statusCode === 307) {
42
+ return request({ uri: response.headers.location, method, headers, body, options })
43
+ }
44
+
45
+ return response;
46
+ }
47
+
48
+ async function load_http() {
49
+
50
+ for (let event of this.events) {
51
+ const res = await request({
52
+ uri: event._http_req_uri,
53
+ method: event._http_req_method,
54
+ headers: event._http_req_headers,
55
+ body: event._http_req_body
53
56
  })
54
57
 
55
- await task
58
+ event._http_res_status = res.statusCode
59
+ event._http_res_headers = res.headers
60
+ event._http_res_body = res.body
56
61
  }
57
62
 
58
- return this;
63
+ return this
59
64
  }
60
65
 
61
66
  module.exports = {
package/src/processing.js CHANGED
@@ -31,8 +31,9 @@ async function parallel(target, { multiThread = false } = {}, callbackPath) {
31
31
  const instance = new Vaporous({ loggers })
32
32
  instance.events = thisEvent
33
33
 
34
- const task = await funct(instance)
35
- tasks.push(task.begin())
34
+ const task = funct(instance).begin()
35
+ tasks.push(task)
36
+ await task
36
37
 
37
38
  await processSingleThread()
38
39
  }
@@ -135,9 +136,11 @@ async function recurse(funct) {
135
136
  for (let event of this.events) {
136
137
  const target = new Vaporous({ loggers: this.loggers })
137
138
  target.events = [event]
139
+ event._recursion = true
138
140
 
139
141
  const localRecursion = async (target) => {
140
- const val = await funct(target)
142
+ const executionChain = funct(target)
143
+ const val = await executionChain.begin()
141
144
  if (val.events[0]._recursion) return localRecursion(target)
142
145
  return val
143
146
  }
@@ -150,9 +153,35 @@ async function recurse(funct) {
150
153
  return this;
151
154
  }
152
155
 
153
- function doIf(condition, callback) {
154
- const proceed = condition(this)
155
- if (proceed) callback(this)
156
+ async function doIf(condition, callback) {
157
+ const proceed = await condition(this)
158
+ if (proceed) {
159
+ const clone = this.clone()
160
+ const task = await callback(clone)
161
+ await task.begin()
162
+ this.events = clone.events
163
+ }
164
+ return this;
165
+ }
166
+
167
+ async function method(operation, name, options) {
168
+ const operations = {
169
+ create: () => {
170
+ this.savedMethods[name] = options
171
+ },
172
+ retrieve: async () => {
173
+ if (!this.savedMethods[name]) throw new Error('Method not found ' + name)
174
+ const clone = this.clone()
175
+ const task = await clone.savedMethods[name](clone, options)
176
+ await task.begin()
177
+ this.events = clone.events
178
+ },
179
+ delete: () => {
180
+ delete this.savedMethods[name]
181
+ }
182
+ }
183
+
184
+ await operations[operation]()
156
185
  return this;
157
186
  }
158
187
 
@@ -160,5 +189,6 @@ module.exports = {
160
189
  parallel,
161
190
  interval,
162
191
  recurse,
163
- doIf
192
+ doIf,
193
+ method
164
194
  }
package/src/statistics.js CHANGED
@@ -41,7 +41,9 @@ module.exports = {
41
41
  const reference = map[key]._statsRaw[aggregation.field]
42
42
 
43
43
  if (aggregation.sortable) {
44
- sortedCache[aggregation.field] = reference.slice().sort((a, b) => a - b)
44
+ if (sortedCache[aggregation.field] === undefined) {
45
+ sortedCache[aggregation.field] = reference.slice().sort((a, b) => a - b)
46
+ }
45
47
  result[outputField] = aggregation.calculate(sortedCache[aggregation.field])
46
48
  } else {
47
49
  result[outputField] = aggregation.calculate(reference)
@@ -60,27 +60,28 @@ module.exports = {
60
60
  return this;
61
61
  },
62
62
 
63
- mvexpand(target) {
63
+ mvexpand(targets) {
64
64
 
65
65
  const arr = []
66
66
  this.events.forEach(event => {
67
67
  if (event instanceof Array) {
68
- if (!!target) throw new Error('Cannot mvexpand an array to a target')
68
+ if (targets.length !== 0) throw new Error('Cannot mvexpand on a target value when source data is array')
69
+
69
70
  event.forEach((item, i) => {
70
- item.i = i
71
+ item._mvExpand = i
71
72
  arr.push(item)
72
73
  })
73
74
  } else {
75
+ // Identify max iterations
76
+ const max = targets.reduce((prev, curr) => Math.max(prev, event[curr].length), 0)
74
77
 
75
-
76
- if (!event[target]) return arr.push(event)
77
- event[target].forEach((item, i) => {
78
- arr.push({
79
- ...event,
80
- [target]: item,
81
- [`_mvExpand_${target}`]: i
78
+ for (let i = 0; i < max; i++) {
79
+ const obj = { ...event, _mvExpand: i }
80
+ targets.forEach(target => {
81
+ obj[target] = event[target][i]
82
82
  })
83
- })
83
+ arr.push(obj)
84
+ }
84
85
  }
85
86
  })
86
87
 
@@ -372,12 +372,14 @@ module.exports = {
372
372
  return this;
373
373
  },
374
374
 
375
- render(location = './Vaporous_generation.html', { tabOrder } = {}) {
375
+ render(location = './Vaporous_generation.html', options = {}) {
376
376
 
377
377
 
378
378
  const classSafe = (name) => name.replace(/[^a-zA-Z0-9]/g, "_")
379
379
 
380
- if (tabOrder) this.tabs = tabOrder
380
+ if (typeof options === 'function') options = options()
381
+
382
+ if (options.tabOrder) this.tabs = options.tabOrder
381
383
 
382
384
  const createElement = (name, type, visualisationOptions, eventData, { trellis, trellisName = "", columnDefinitions }) => {
383
385