vaporous 0.0.11 → 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
@@ -238,8 +238,8 @@ class Vaporous {
238
238
  * @param {string} target - Field name containing array to expand
239
239
  * @returns {Vaporous} - Returns this instance for chaining
240
240
  */
241
- mvexpand(target) {
242
- return transformations.mvexpand.call(this, target);
241
+ mvexpand(...targets) {
242
+ return transformations.mvexpand.call(this, targets);
243
243
  }
244
244
 
245
245
  // ========================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vaporous",
3
- "version": "0.0.11",
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": {
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
  }
@@ -155,7 +158,7 @@ async function doIf(condition, callback) {
155
158
  if (proceed) {
156
159
  const clone = this.clone()
157
160
  const task = await callback(clone)
158
- task.begin()
161
+ await task.begin()
159
162
  this.events = clone.events
160
163
  }
161
164
  return this;
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
 
@@ -1,324 +0,0 @@
1
-
2
- <html>
3
- <head>
4
- <meta name="viewport" content="width=device-width, initial-scale=0.5">
5
- <style>
6
- @import url('https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap');
7
-
8
- /* Apply Roboto to all elements */
9
- * {
10
- font-family: 'Roboto', Arial, sans-serif !important;
11
- }
12
-
13
- body {
14
- font-family: 'Roboto', Arial, sans-serif;
15
- }
16
-
17
- /* Chart-specific styles */
18
- .chart,
19
- .chart-container,
20
- canvas,
21
- svg,
22
- .chartjs-render-monitor {
23
- font-family: 'Roboto', Arial, sans-serif !important;
24
- }
25
-
26
- /* Third-party library overrides */
27
- .ag-theme-quartz,
28
- .ag-cell,
29
- .ag-header-cell,
30
- .tabulator,
31
- .tabulator-cell,
32
- .tabulator-header {
33
- font-family: 'Roboto', Arial, sans-serif !important;
34
- }
35
-
36
- body {
37
- margin: 0;
38
- padding: 16px;
39
- }
40
-
41
- .tabBar {
42
- display: flex;
43
- overflow: auto;
44
- box-shadow:
45
- 0 3px 12px rgba(0, 0, 0, 0.09),
46
- 0 6px 18px rgba(0, 0, 0, 0.06);
47
- min-height: 32px;
48
- margin-bottom: 24px;
49
- margin-top: 8px;
50
- margin-left: 8px;
51
- margin-right: 8px;
52
- position: relative;
53
- background: #fff;
54
- align-items: center;
55
- }
56
-
57
- .tabs {
58
- border-radius: 8px;
59
- padding: 8px 20px;
60
- cursor: pointer;
61
- background: none;
62
- border: none;
63
- outline: none;
64
- font-size: 1rem;
65
- color: #555;
66
- transition: all 0.3s ease-in-out;
67
- text-align: center;
68
- margin: 12px;
69
- position: relative;
70
- z-index: 1;
71
- }
72
-
73
- .tabs:not(.selectedTab):hover {
74
- color: #1976d2;
75
- }
76
-
77
- .selectedTab {
78
- color: #fff;
79
- font-weight: bold;
80
- }
81
-
82
- .selectedTab::before {
83
- content: '';
84
- position: absolute;
85
- background: #1976d2;
86
- border-radius: 8px;
87
- z-index: -1;
88
- top: 0;
89
- left: 0;
90
- width: 100%;
91
- height: 100%;
92
- transition: transform 0.3s ease-in-out;
93
- box-shadow:
94
- 0 4px 16px rgba(25, 118, 210, 0.3),
95
- 0 8px 24px rgba(25, 118, 210, 0.2);
96
- animation: slideInFromLeft 0.3s ease-in-out forwards;
97
- }
98
-
99
- .selectedTab.slideFromRight::before {
100
- animation: slideInFromRight 0.3s ease-in-out forwards;
101
- }
102
-
103
- @keyframes slideInFromLeft {
104
- 0% {
105
- transform: translateX(-100%);
106
- opacity: 0;
107
- }
108
-
109
- 100% {
110
- transform: translateX(0);
111
- opacity: 1;
112
- }
113
- }
114
-
115
- @keyframes slideInFromRight {
116
- 0% {
117
- transform: translateX(100%);
118
- opacity: 0;
119
- }
120
-
121
- 100% {
122
- transform: translateX(0);
123
- opacity: 1;
124
- }
125
- }
126
-
127
- #content {
128
- display: flex;
129
- flex-wrap: wrap;
130
- padding: 0px;
131
- gap: 8px;
132
- justify-content: flex-start;
133
- }
134
-
135
- .parentHolder {
136
- display: flex;
137
- margin: 2px;
138
- border: 1px solid #d3d3d3;
139
- }
140
-
141
- .parentHolder::after {
142
- border: 2px solid red;
143
- /* Change color and width as needed */
144
- pointer-events: none;
145
- z-index: 2;
146
- }
147
-
148
- .tabContent {
149
- opacity: 1;
150
- transition: opacity 0.3s,
151
- }
152
-
153
- .graphTitle {
154
- opacity: 0.7;
155
- text-align: center;
156
- display: 'flex';
157
- }
158
-
159
- .tableHolder {
160
- margin-top: 8px;
161
- width: 100%;
162
- /* height: 600px; */
163
- /* overflow: auto; */
164
- }
165
-
166
- #extendedDescription {
167
- text-align: center;
168
- opacity: 0.7;
169
- margin-bottom: 16px;
170
- }
171
- </style>
172
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
173
- <script src="https://cdn.jsdelivr.net/npm/ag-grid-community@34.2.0/dist/ag-grid-community.min.js"></script>
174
-
175
-
176
- <script type="text/javascript">
177
-
178
- const classSafe = (name) => name.replace(/[^a-zA-Z0-9]/g, "_")
179
-
180
- var selectedTab = classSafe("User Stats")
181
- var previousTab = null
182
- const tokens = {}
183
- const visualisationData = [[{"columnDefinitions":[{"field":"gender"},{"field":"avgHeight"}],"rowData":[{"gender":"female","avgHeight":177.5666666666667},{"gender":"male","avgHeight":173.15249999999997}],"title":"Average height"}],[{"type":"line","data":{"labels":["female","male"],"datasets":[{"label":"avgHeight","data":[177.5666666666667,173.15249999999997],"pointRadius":0}]},"options":{"scales":{"y":{"type":"linear","display":true,"position":"left","min":173.15249999999997,"max":[177.5666666666667]},"x":{"type":"category","ticks":{"display":false}}},"responsive":true,"plugins":{"legend":{"display":true,"position":"bottom"},"title":{"display":false,"text":"Average height"}}}}]]
184
- const tabOrder = ["User_Stats"]
185
-
186
- const _sort = (order, data, ...keys) => {
187
- return data.sort((a, b) => {
188
- let directive = 0;
189
-
190
- keys.some(key => {
191
- directive = typeof a[key] === 'number' ? a[key] - b[key] : a[key].localeCompare(b[key])
192
- if (order === 'dsc') directive = directive * -1
193
- if (directive !== 0) return true;
194
- })
195
-
196
- return directive;
197
- })
198
- }
199
- const createElement = (name, type, visualisationOptions, eventData, { trellis, trellisName = "", columnDefinitions }) => {
200
-
201
- if (classSafe(visualisationOptions.tab) !== selectedTab) return;
202
-
203
- if (visualisationOptions.extendedDescription) {
204
- const descriptions = document.getElementById('extendedDescription')
205
- const thisDescription = document.createElement('div')
206
- thisDescription.innerHTML = visualisationOptions.extendedDescription
207
- descriptions.appendChild(thisDescription)
208
- }
209
-
210
- eventData = visualisationData[eventData]
211
-
212
- // TODO: migrate trellis functionality from here to tograph
213
- if (trellis) {
214
- let pairs = trellisName.map((name, i) => [name, eventData[i]]);
215
- pairs = pairs.sort((a, b) => a[0].localeCompare(b[0]))
216
-
217
- // Unzip back into separate arrays
218
- trellisName = pairs.map(p => p[0]);
219
- eventData = pairs.map(p => p[1]);
220
- }
221
-
222
- const columnCount = visualisationOptions.columns || 2
223
-
224
- eventData.forEach((trellisData, i) => {
225
- const parentHolder = document.createElement('div')
226
-
227
- const titleDiv = document.createElement('div')
228
- titleDiv.classList.add('graphTitle')
229
- parentHolder.appendChild(titleDiv)
230
-
231
- if (trellisData.options) {
232
- titleDiv.textContent = trellisData.options.plugins.title.text
233
- } else {
234
- titleDiv.textContent = trellisData.title
235
- }
236
-
237
- document.getElementById('content').appendChild(parentHolder)
238
-
239
- parentHolder.style = `flex: 0 0 calc(${100 / columnCount}% - 8px); max-width: calc(${100 / columnCount}% - 8px);`
240
- if (type === 'Table') {
241
- const tableDiv = document.createElement('div')
242
- tableDiv.classList.add('tableHolder')
243
- document.documentElement.style.setProperty("--ag-spacing", `4px`);
244
-
245
-
246
- // Need to do column defintiions here
247
- parentHolder.appendChild(tableDiv)
248
- new agGrid.createGrid(tableDiv, {
249
- suppressFieldDotNotation: true,
250
- rowData: trellisData.rowData,
251
- // Columns to be displayed (Should match rowData properties)
252
- columnDefs: trellisData.columnDefinitions,
253
- defaultColDef: {
254
- flex: 1,
255
- resizable: true,
256
- sortable: true,
257
- filter: true
258
- },
259
- domLayout: 'autoHeight',
260
- enableCellTextSelection: true,
261
- // suppressHorizontalScroll: false,
262
- // autoSizeStrategy: {
263
- // type: 'fitGridWidth',
264
- // defaultMinWidth: 100
265
- // }
266
- });
267
- } else {
268
- const graphEntity = document.createElement('canvas')
269
- parentHolder.appendChild(graphEntity)
270
- new Chart(graphEntity, trellisData)
271
- }
272
-
273
- })
274
- }
275
-
276
- function drawVis(tab) {
277
- if (tab) {
278
- if (selectedTab) {
279
- document.getElementById(selectedTab).classList.remove('selectedTab')
280
- document.getElementById(selectedTab).classList.remove('slideFromRight')
281
- previousTab = selectedTab
282
- }
283
- selectedTab = tab
284
- } else if (true) {
285
- selectedTab = classSafe('User Stats')
286
- }
287
-
288
- if (selectedTab) {
289
- const selectedElement = document.getElementById(selectedTab)
290
- selectedElement.classList.add('selectedTab')
291
-
292
- // Determine slide direction based on tab positions
293
- if (previousTab) {
294
- const previousIndex = tabOrder.indexOf(previousTab)
295
- const currentIndex = tabOrder.indexOf(selectedTab)
296
-
297
- if (currentIndex < previousIndex) {
298
- // Moving to left tab, slide from right
299
- selectedElement.classList.add('slideFromRight')
300
- }
301
- // For right movement or first load, use default slideFromLeft animation
302
- }
303
- }
304
- document.getElementById('content').innerHTML = ''
305
- document.getElementById('extendedDescription').innerHTML = ''
306
- createElement('Average height', 'Table', {"tab":"User Stats","columns":2} ,0, {"xPrimary":"gender","columnDefinitions":[["gender","avgHeight"]]}),createElement('Average height', 'Line', {"tab":"User Stats","columns":2} ,1, {"xPrimary":"gender","columnDefinitions":[["gender","avgHeight"]]})
307
- }
308
-
309
- document.addEventListener("DOMContentLoaded", function(event) {
310
- drawVis()
311
- });
312
-
313
- </script>
314
- </head>
315
- <body>
316
- <div class='tabBar'>
317
- <div id=User_Stats class='tabs' onclick="drawVis('User_Stats')">User Stats</div>
318
- </div>
319
-
320
- <div id='extendedDescription'></div>
321
- <div id='content'></div>
322
- </body>
323
- </html>
324
-