jupyter-ijavascript-utils 1.37.0 → 1.40.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.
- package/DOCS.md +4 -0
- package/Dockerfile +1 -1
- package/README.md +4 -0
- package/package.json +2 -1
- package/src/array.js +209 -2
- package/src/format.js +74 -0
- package/src/object.js +258 -60
- package/src/plantuml.js +1 -1
package/DOCS.md
CHANGED
|
@@ -75,6 +75,10 @@ Give it a try here:
|
|
|
75
75
|
|
|
76
76
|
## What's New
|
|
77
77
|
|
|
78
|
+
* 1.40 - {@link module:array.extract|array.extract} and {@link module:array.applyArrayValues|array.applyArrayValues} to allow for extracting values from arrays, transforming them on a separate process and applying them deeply and safely
|
|
79
|
+
* 1.39 - {@link module:format.extractWords|format.exportWords} - to identify distinct words in strings using unicode character properties
|
|
80
|
+
* 1.38 - {@link module:object.extractObjectProperty|object.extractObjectProperty} / {@link module:object.applyPropertyValue|object.applyPropertyValue} to allow for extracting values from arrays, transforming them on a separate process and applying them back
|
|
81
|
+
* 1.37 - {@link module:format.replaceString|format.replaceString} as convenience for replacing only a single string.
|
|
78
82
|
* 1.36 - {@link module:format.replaceStrings|format.replaceStrings} to allow for replacement dictionaries and tuplets
|
|
79
83
|
* 1.35 - {@link module:object.extractObjectProperties|extractObjectProperties} / {@link module:object.extractObjectProperty|extractObjectProperty} - to do horizontal transposes on objects
|
|
80
84
|
* 1.34 - {@link module:format.mapArrayDomain|format.mapArrayDomain} and add notes in the header of {@link module:random|random} on using non-uniform distributions.
|
package/Dockerfile
CHANGED
package/README.md
CHANGED
|
@@ -55,6 +55,10 @@ This is not intended to be the only way to accomplish many of these tasks, and a
|
|
|
55
55
|
|
|
56
56
|
# What's New
|
|
57
57
|
|
|
58
|
+
* 1.40 - array.extract and array.applyArrayValue to allow for extracting values from arrays, transforming them on a separate process and applying them back
|
|
59
|
+
* 1.39 - format.exportWords - to identify distinct words in strings using unicode character properties
|
|
60
|
+
* 1.38 - object.extract / object.apply
|
|
61
|
+
* 1.37 - {@link module:format.replaceString|format.replaceString} as convenience for replacing only a single string.
|
|
58
62
|
* 1.36 - replaceStrings to allow for replacement dictionaries and tuplets
|
|
59
63
|
* 1.35 - object.extractObjectProperties / object.extractObjectProperty - to do horizontal transposes on objects
|
|
60
64
|
* 1.34 - format.mapArrayDomain and add notes in to random on using non-uniform distributions.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyter-ijavascript-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.40.0",
|
|
4
4
|
"description": "Utilities for working with iJavaScript - a Jupyter Kernel",
|
|
5
5
|
"homepage": "https://jupyter-ijavascript-utils.onrender.com/",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"test:debug": "TZ=UTC node --inspect-brk node_modules/jest/bin/jest.js --runInBand",
|
|
18
18
|
"test:coverage": "TZ=UTC jest src --collectCoverage",
|
|
19
19
|
"test:watch:coverage": "TZ=UTC jest src --watch --collectCoverage",
|
|
20
|
+
"doc:taffy": "npm install taffydb && npm run doc",
|
|
20
21
|
"docs": "npm run doc",
|
|
21
22
|
"doc": "npm run prep:docdash && node_modules/.bin/jsdoc -c ./jsdoc.json -u ./tutorials ./DOCS.md",
|
|
22
23
|
"prep:docdash": "cp docResources/docdash/layout.tmpl node_modules/docdash/tmpl/layout.tmpl && rm -rf docResources/notebooks/node_modules",
|
package/src/array.js
CHANGED
|
@@ -27,6 +27,10 @@ require('./_types/global');
|
|
|
27
27
|
* * {@link module:array.pickRows|array.pickRows} - picks a row from a 2d array
|
|
28
28
|
* * {@link module:array.pickColumns|array.pickColumns} - picks a column from a 2d array
|
|
29
29
|
* * {@link module:array.pick|array.pick} - picks either/or rows and columns
|
|
30
|
+
* * {@link module:array.extract|array.extract} - synonym to array.pick to pick either a row or column from an array
|
|
31
|
+
* * Applying a value
|
|
32
|
+
* * {@link module:array.applyArrayValue|array.applyArrayValue} - applies a value deeply into an array safely
|
|
33
|
+
* * {@link module:array.applyArrayValues|array.applyArrayValues} - applies a value / multiple values deeply into an array safely
|
|
30
34
|
* * Understanding Values
|
|
31
35
|
* * {@link module:array.isMultiDimensional|array.isMultiDimensional} - determines if an array is multi-dimensional
|
|
32
36
|
*
|
|
@@ -150,6 +154,7 @@ module.exports.peekLast = function peekLast(targetArray, defaultVal = null) {
|
|
|
150
154
|
* @param {Array} array2d - 2d array to pick from [row][column]
|
|
151
155
|
* @param {...Number} rowIndices - Indexes of the row to return, [0...length-1]
|
|
152
156
|
* @returns - Array with only those rows
|
|
157
|
+
* @see {@link module:array.pick|array.pick} - pick either rows or columns
|
|
153
158
|
* @example
|
|
154
159
|
* data = [
|
|
155
160
|
* ['john', 23, 'purple'],
|
|
@@ -179,6 +184,7 @@ module.exports.pickRows = function pickRows(array2d, ...rowIndices) {
|
|
|
179
184
|
* @param {Array} array2d - 2d array to pick from [row][column]
|
|
180
185
|
* @param {...any} columns - Indexes of the columns to pick the values from: [0...row.length-1]
|
|
181
186
|
* @returns - Array with all rows, and only those columns
|
|
187
|
+
* @see {@link module:array.pick|array.pick} - pick either rows or columns
|
|
182
188
|
* @example
|
|
183
189
|
* data = [
|
|
184
190
|
* ['john', 23, 'purple'],
|
|
@@ -210,8 +216,9 @@ module.exports.pickColumns = function pickColumns(array2d, ...columns) {
|
|
|
210
216
|
* @param {Number[]} [options.rows = null] - indices of the rows to pick
|
|
211
217
|
* @param {Number[]} [options.columns = null] - indices of the columns to pick.
|
|
212
218
|
* @returns {Array} - 2d array of only the rows and columns chosen.
|
|
213
|
-
* @see {@link module:
|
|
214
|
-
* @see {@link module:
|
|
219
|
+
* @see {@link module:array.pickRows|array.pickRows} - picking rows
|
|
220
|
+
* @see {@link module:array.pickColumns|array.pickColumns} - picking columns
|
|
221
|
+
* @see {@link module:array.applyArrayValues|array.applyArrayValues} - applies a value / multiple values deeply into an array safely
|
|
215
222
|
* @returns - 2dArray of the columns and rows requested
|
|
216
223
|
* @example
|
|
217
224
|
* data = [
|
|
@@ -250,6 +257,206 @@ module.exports.pick = function pick(array2d, options) {
|
|
|
250
257
|
return results;
|
|
251
258
|
};
|
|
252
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Convenience function for picking specific rows and columns from a 2d array.
|
|
262
|
+
*
|
|
263
|
+
* Alias of {@link module:array.pick|array.pick}
|
|
264
|
+
*
|
|
265
|
+
* Please also see [Danfo.js](https://danfo.jsdata.org/) for working with DataFrames.
|
|
266
|
+
*
|
|
267
|
+
* @param {Array} array2d - 2d array to pick from [row][column]
|
|
268
|
+
* @param {Object} options - options on which to pick
|
|
269
|
+
* @param {Number[]} [options.rows = null] - indices of the rows to pick
|
|
270
|
+
* @param {Number[]} [options.columns = null] - indices of the columns to pick.
|
|
271
|
+
* @returns {Array} - 2d array of only the rows and columns chosen.
|
|
272
|
+
* @see {@link module:array.pickRows} - picking rows
|
|
273
|
+
* @see {@link module:array.pickColumns} - picking columns
|
|
274
|
+
* @returns - 2dArray of the columns and rows requested
|
|
275
|
+
* @example
|
|
276
|
+
* data = [
|
|
277
|
+
* ['john', 23, 'purple'],
|
|
278
|
+
* ['jane', 32, 'red'],
|
|
279
|
+
* ['ringo', 27, 'green']
|
|
280
|
+
* ];
|
|
281
|
+
*
|
|
282
|
+
* utils.array.pick(data, {rows: [0, 1]});
|
|
283
|
+
* //-- [['john', 23, 'purple'], ['jane', 32, 'red']];
|
|
284
|
+
*
|
|
285
|
+
* utils.array.pick(data, {columns: [0, 2]});
|
|
286
|
+
* //-- [['john', 'purple'], ['jane', 'red'], ['ringo', 'green']];
|
|
287
|
+
*
|
|
288
|
+
* utils.array.pick(data, {rows:[0, 1], columns:[0, 2]});
|
|
289
|
+
* //-- [['john', 'purple'], ['jane', 'red']];
|
|
290
|
+
*/
|
|
291
|
+
module.exports.extract = module.exports.pick;
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Applies deeply onto an array safely - in-place using dot-notation paths
|
|
295
|
+
* even if the child paths don't exist.
|
|
296
|
+
*
|
|
297
|
+
* While tthis can be as simple as safely applying a value even if targetObj may be null
|
|
298
|
+
*
|
|
299
|
+
* ```
|
|
300
|
+
* targetObj = [1, 2, null, 4, 5];
|
|
301
|
+
*
|
|
302
|
+
* utils.object.applyPropertyValue(targetObj, '[2]', 3);
|
|
303
|
+
* // [1, 2, 3, 4, 5]
|
|
304
|
+
* // equivalent to targetObj[2] = 3;
|
|
305
|
+
* ```
|
|
306
|
+
*
|
|
307
|
+
* This is much more safely working with deeply nested objects
|
|
308
|
+
*
|
|
309
|
+
* ```
|
|
310
|
+
* targetObj = [{
|
|
311
|
+
* name: 'john smith',
|
|
312
|
+
* class: {
|
|
313
|
+
* name: 'ECON_101',
|
|
314
|
+
* professor: {
|
|
315
|
+
* last_name: 'Winklemeyer'
|
|
316
|
+
* }
|
|
317
|
+
* }
|
|
318
|
+
* }];
|
|
319
|
+
*
|
|
320
|
+
* utils.object.applyPropertyValue(targetObj, '[0].class.professor.first_name', 'René');
|
|
321
|
+
* // [{
|
|
322
|
+
* // name: 'john smith',
|
|
323
|
+
* // class: {
|
|
324
|
+
* // name: 'ECON_101',
|
|
325
|
+
* // professor: {
|
|
326
|
+
* // last_name: 'Winklemeyer',
|
|
327
|
+
* // first_name: 'René' // <- Added
|
|
328
|
+
* // }
|
|
329
|
+
* // }
|
|
330
|
+
* // }];
|
|
331
|
+
* ```
|
|
332
|
+
*
|
|
333
|
+
* or creating intermediary objects along the path - if they did not exist first.
|
|
334
|
+
*
|
|
335
|
+
* ```
|
|
336
|
+
* targetObj = [{
|
|
337
|
+
* name: 'john smith'
|
|
338
|
+
* }];
|
|
339
|
+
* utils.object.applyPropertyValue(targetObj, '[0].class.professor.first_name', 'René');
|
|
340
|
+
* [{
|
|
341
|
+
* name: 'john smith',
|
|
342
|
+
* class: {
|
|
343
|
+
* professor: {
|
|
344
|
+
* first_name: 'René'
|
|
345
|
+
* }
|
|
346
|
+
* }
|
|
347
|
+
* }];
|
|
348
|
+
* ```
|
|
349
|
+
*
|
|
350
|
+
* @param {Array} collection - array to apply the value to
|
|
351
|
+
* @param {string} path - dot notation path to set the value, ex: 'geo', or 'states[0].prop'
|
|
352
|
+
* @param {any} value - value to set
|
|
353
|
+
* @returns {Array} - the base array
|
|
354
|
+
* @see {@link module:array.pick|array.pick} - to pick a row or column into an array
|
|
355
|
+
* @see {@link module:array.applyArrayValues|array.applyArrayValues} - applies an array safely and deeply onto another array of values
|
|
356
|
+
*/
|
|
357
|
+
module.exports.applyArrayValue = function applyArrayValue(collection, path, value) {
|
|
358
|
+
// const signature = 'applyArrayValue(collection, path, value)';
|
|
359
|
+
|
|
360
|
+
if (!collection) return collection;
|
|
361
|
+
if (!path) return collection;
|
|
362
|
+
|
|
363
|
+
const cleanPath = String(path)
|
|
364
|
+
.replace(/\[/g, '.')
|
|
365
|
+
.replace(/\]/g, '.')
|
|
366
|
+
.replace(/[.]+/g, '.')
|
|
367
|
+
.replace(/^[.]+/, '')
|
|
368
|
+
.replace(/[.]$/, '');
|
|
369
|
+
|
|
370
|
+
const splitPath = cleanPath.split('.');
|
|
371
|
+
const terminalIndex = splitPath.length - 1;
|
|
372
|
+
|
|
373
|
+
return splitPath
|
|
374
|
+
.reduce((currentVal, prop, currentIndex) => {
|
|
375
|
+
//-- can no longer occur
|
|
376
|
+
// if (!prop) throw Error(`${signature}:Unable to set value with path:${path}`);
|
|
377
|
+
|
|
378
|
+
const isLeaf = currentIndex === terminalIndex;
|
|
379
|
+
if (isLeaf) {
|
|
380
|
+
// eslint-disable-next-line no-param-reassign
|
|
381
|
+
currentVal[prop] = value;
|
|
382
|
+
// if (value === undefined) {
|
|
383
|
+
// delete currentVal[prop];
|
|
384
|
+
// } else {
|
|
385
|
+
// currentVal[prop] = value;
|
|
386
|
+
// }
|
|
387
|
+
return collection;
|
|
388
|
+
}
|
|
389
|
+
//-- not a leaf
|
|
390
|
+
if (!currentVal[prop]) {
|
|
391
|
+
// eslint-disable-next-line no-param-reassign
|
|
392
|
+
currentVal[prop] = {};
|
|
393
|
+
}
|
|
394
|
+
return currentVal[prop];
|
|
395
|
+
}, collection);
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Converse from the extractPropertyValue, this takes a value / set of values
|
|
400
|
+
* and applies the values for each index in the collection.
|
|
401
|
+
*
|
|
402
|
+
* for example:
|
|
403
|
+
*
|
|
404
|
+
* ```
|
|
405
|
+
* weather = [{ id: 1, city: 'Seattle', month: 'Aug', precip: 0.87 },
|
|
406
|
+
* { id: 3, city: 'New York', month: 'Apr', precip: 3.94 },
|
|
407
|
+
* { id: 6, city: 'Chicago', month: 'Apr', precip: 3.62 }];
|
|
408
|
+
*
|
|
409
|
+
* cities = utils.object.extractObjectProperty('city');
|
|
410
|
+
* // ['Seattle', 'New York', 'Chicago'];
|
|
411
|
+
*
|
|
412
|
+
* //-- async process to geocode
|
|
413
|
+
* geocodedCities = geocodeCity(cities);
|
|
414
|
+
* // [{ city: 'Seattle', state: 'WA', country: 'USA' },
|
|
415
|
+
* // { city: 'New York', state: 'NY', country: 'USA' },
|
|
416
|
+
* // { city: 'Chicago', state: 'IL', country: 'USA' }]
|
|
417
|
+
*
|
|
418
|
+
* utils.applyArrayValues(weather, 'geo', geocodedCities);
|
|
419
|
+
* // [{ id: 1, city: 'Seattle', month: 'Aug', precip: 0.87, geo: { city: 'Seattle', state: 'WA', country: 'USA' } },
|
|
420
|
+
* // { id: 3, city: 'New York', month: 'Apr', precip: 3.94, geo: { city: 'New York', state: 'NY', country: 'USA' } },
|
|
421
|
+
* // { id: 6, city: 'Chicago', month: 'Apr', precip: 3.62, geo: { city: 'Chicago', state: 'IL', country: 'USA' } }];
|
|
422
|
+
*
|
|
423
|
+
* Note that traditional [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
|
|
424
|
+
* works best for if you are working with objects completely in memory.
|
|
425
|
+
*
|
|
426
|
+
* But this helps quite a bit if the action of mapping / transforming values
|
|
427
|
+
* needs to be separate from the extraction / application of values back.
|
|
428
|
+
*
|
|
429
|
+
* @param {Array} collection - array to apply the value to on each index
|
|
430
|
+
* @param {string} path - dot notation path to set the value within each index, ex: 'geo', or 'states[0].prop'
|
|
431
|
+
* @param {any} value - the value that should be set at that path.
|
|
432
|
+
* @returns {Object}
|
|
433
|
+
* @see {@link module:array.applyArrayValue|array.applyArrayValue} - to apply a single value to a single object
|
|
434
|
+
* @see {@link module:array.pick|array.pick} - to pick a row or column into an array
|
|
435
|
+
*/
|
|
436
|
+
module.exports.applyArrayValues = function applyArrayValues(collection, path, valueList) {
|
|
437
|
+
// const signature = 'applyValue(objectList, path, valueList)';
|
|
438
|
+
if (!collection || !path) {
|
|
439
|
+
//-- do nothing
|
|
440
|
+
return collection;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const cleanCollection = Array.isArray(collection) ? collection : [collection];
|
|
444
|
+
const cleanValueList = Array.isArray(valueList) ? valueList : Array(cleanCollection.length).fill(valueList);
|
|
445
|
+
|
|
446
|
+
// if (cleanCollection.length !== cleanValueList) throw Error(
|
|
447
|
+
// `${signature}: objectList.length[${cleanCollection.length}] does not match valueList.length[${cleanValueList.length}]`
|
|
448
|
+
// );
|
|
449
|
+
const minLength = Math.min(cleanCollection.length, cleanValueList.length);
|
|
450
|
+
|
|
451
|
+
for (let i = 0; i < minLength; i += 1) {
|
|
452
|
+
const obj = cleanCollection[i];
|
|
453
|
+
const val = cleanValueList[i];
|
|
454
|
+
ArrayUtils.applyArrayValue(obj, path, val);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return collection;
|
|
458
|
+
};
|
|
459
|
+
|
|
253
460
|
/**
|
|
254
461
|
* Creates an array of a specific size and default value
|
|
255
462
|
*
|
package/src/format.js
CHANGED
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
* * {@link module:format.consoleLines|format.consoleLines(...)} - same as limit lines, only console.logs the string out.
|
|
21
21
|
* * {@link module:format.wordWrap|format.wordWrap(str, options)} - breaks apart string by line length
|
|
22
22
|
* * {@link module:format.lineCount|format.lineCount(str, options)} - counts the number of lines in a string
|
|
23
|
+
* * Replacing values in Strings
|
|
24
|
+
* * {@link module:format.replaceString|format.replaceString(string, stringTupletsOrMap)} - applies replace from a collection of [matcher, replacement] tuplets or map based on key-> values
|
|
25
|
+
* * {@link module:format.replaceStrings|format.replaceStrings(stringsArray, stringTupletsOrMap)} - applies replaceString on an array of values
|
|
23
26
|
* * Formatting Time
|
|
24
27
|
* * {@link module:format.millisecondDuration|format.millisecondDuration}
|
|
25
28
|
* * Mapping Values
|
|
@@ -38,6 +41,8 @@
|
|
|
38
41
|
* * {@link module:format.parseNumber|format.parseNumber(val, locale)} - converts a value to a number
|
|
39
42
|
* * Identifying values
|
|
40
43
|
* * {@link module:format.isEmptyValue|format.isEmptyValue} - determine if a value is not 'empty'
|
|
44
|
+
* * Extracting values
|
|
45
|
+
* * {@link module:format.extractWords|format.extractWords} - to extract the words from a string
|
|
41
46
|
*
|
|
42
47
|
* @module format
|
|
43
48
|
* @exports format
|
|
@@ -1214,6 +1219,7 @@ module.exports.lineCount = function lineCount(str, newlineCharacter = '\n') {
|
|
|
1214
1219
|
* // 'and jill came tumbling after' ]
|
|
1215
1220
|
*
|
|
1216
1221
|
* //-- or use tuplets of [find, replace] with regular expressions
|
|
1222
|
+
* //-- and strings not in tuplets are simply removed.
|
|
1217
1223
|
* replaceValues = [['jack', 'john'], [/\s+jill/i, ' ringo'], ' down'];
|
|
1218
1224
|
* utils.format.replaceStrings(targetStrings, replaceValues);
|
|
1219
1225
|
* expected = [
|
|
@@ -1267,3 +1273,71 @@ module.exports.replaceStrings = function replaceStrings(targetStr, stringTuplets
|
|
|
1267
1273
|
? result
|
|
1268
1274
|
: result.replace(replaceSearch, replaceWith), stringToClean));
|
|
1269
1275
|
};
|
|
1276
|
+
|
|
1277
|
+
/**
|
|
1278
|
+
* Conveience function for calling {@link module:format.replaceStrings|format.replaceStrings} -
|
|
1279
|
+
* giving and receiving a single value (instead of an array of values).
|
|
1280
|
+
* @param {String} targetStr - A Single string to replace values on.
|
|
1281
|
+
* @param {Array|Map<string|RegExp,string>} stringTupletsOrMap - [[search, replace]] or Map<String|RegExp,String>
|
|
1282
|
+
* @returns {string} - the targetStr with the values replaced
|
|
1283
|
+
* @see {@link module:format.replaceStrings}
|
|
1284
|
+
*/
|
|
1285
|
+
module.exports.replaceString = function replaceString(targetStr, stringTupletsOrMap) {
|
|
1286
|
+
if (Array.isArray(targetStr)) {
|
|
1287
|
+
throw Error('replaceString(targetStr, stringTupletsOrMap): targetStr was sent an array - please use replaceStrings instead');
|
|
1288
|
+
}
|
|
1289
|
+
return FormatUtils.replaceStrings([targetStr], stringTupletsOrMap)[0];
|
|
1290
|
+
};
|
|
1291
|
+
|
|
1292
|
+
/**
|
|
1293
|
+
* Identify an array of words each from a string.
|
|
1294
|
+
*
|
|
1295
|
+
* Note that this uses the new [Unicode Properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape)
|
|
1296
|
+
* using `\p{L}` to identify characters based on unicode properties.
|
|
1297
|
+
*
|
|
1298
|
+
* For example:
|
|
1299
|
+
*
|
|
1300
|
+
* ```
|
|
1301
|
+
* strs = 'I am Modern "major-general".';
|
|
1302
|
+
* FormatUtils.extractWords(strs);
|
|
1303
|
+
* // ['I', 'am', 'Modern', 'major', 'general'];
|
|
1304
|
+
* ```
|
|
1305
|
+
*
|
|
1306
|
+
* you can also include additional characters that will no longer be considered word boundaries.
|
|
1307
|
+
*
|
|
1308
|
+
* ```
|
|
1309
|
+
* strs = 'I am Modern "major-general".';
|
|
1310
|
+
* FormatUtils.extractWords(strs);
|
|
1311
|
+
* // ['I', 'am', 'Modern', 'major-general'];
|
|
1312
|
+
* ```
|
|
1313
|
+
*
|
|
1314
|
+
* arrays of strings are also supported
|
|
1315
|
+
*
|
|
1316
|
+
* ```
|
|
1317
|
+
* strs = ['letras mayúsculas de tamaño igual a las minúsculas',
|
|
1318
|
+
* 'الاختراع، ومايكل هارت'];
|
|
1319
|
+
* FormatUtils.extractWords(strs);
|
|
1320
|
+
* // [ 'letras', 'mayúsculas', 'de', 'tamaño', 'igual', 'a', 'las', 'minúsculas', 'الاختراع', 'ومايكل', 'هارت'];
|
|
1321
|
+
* ```
|
|
1322
|
+
*
|
|
1323
|
+
* @param {String|String[]} strToExtractFrom - collection of strings to extract words from
|
|
1324
|
+
* @param {String} additionalNonBreakingCharacters - each char in this string will not be treated as a word boundry
|
|
1325
|
+
* @returns {string[]} - collection of words
|
|
1326
|
+
*/
|
|
1327
|
+
module.exports.extractWords = function extractWords(strToExtractFrom, additionalNonBreakingCharacters) {
|
|
1328
|
+
if (!strToExtractFrom) return strToExtractFrom;
|
|
1329
|
+
|
|
1330
|
+
const cleanNonBreaking = additionalNonBreakingCharacters
|
|
1331
|
+
? additionalNonBreakingCharacters
|
|
1332
|
+
: '';
|
|
1333
|
+
|
|
1334
|
+
const regex = cleanNonBreaking
|
|
1335
|
+
? new RegExp(`[${additionalNonBreakingCharacters}\\p{L}]+`, 'gu')
|
|
1336
|
+
: /\p{L}+/ug; // -- old attempt/[A-Za-zÀ-ÖØ-öø-ÿ]+/g;
|
|
1337
|
+
|
|
1338
|
+
const cleanStrings = Array.isArray(strToExtractFrom)
|
|
1339
|
+
? strToExtractFrom
|
|
1340
|
+
: [strToExtractFrom];
|
|
1341
|
+
|
|
1342
|
+
return cleanStrings.reduce((result, str) => [...result, ...((str || '').match(regex) || [])], []);
|
|
1343
|
+
};
|
package/src/object.js
CHANGED
|
@@ -13,29 +13,33 @@ const FormatUtils = require('./format');
|
|
|
13
13
|
* * {@link module:object.generateSchema|generateSchema()} - generate a schema / describe properties of a list of objects
|
|
14
14
|
* * {@link module:object.findWithoutProperties|findWithoutProperties()} - find objects without ALL the properties specified
|
|
15
15
|
* * {@link module:object.findWithoutProperties|findWithProperties()} - find objects with any of the properties specified
|
|
16
|
-
* * {@link module:object.setPropertyDefaults|setPropertyDefaults()} - sets values for objects that don't currently have the property
|
|
17
16
|
* * {@link module:object.propertyValueSample|propertyValueSample(collection)} - finds non-empty values for all properties found in the collection
|
|
18
|
-
* * Manipulating objects
|
|
19
|
-
* * {@link module:object.assign|objAssign(object, property, value)} - Applies properties to an object in functional programming style.
|
|
20
|
-
* * {@link module:object.assignEntities|objAssignEntities(object, [property, value])} - Applies properties to an object using Array values - [key,value]
|
|
21
|
-
* * {@link module:object.augment|augment(object, augmentFn)} - Applies properties to an object similar to Map
|
|
22
|
-
* * {@link module:object.augmentInherit|augmentInherit(object, augmentFn)} - Applies properties to a collection of objects, 'remembering' the last value - useful for 1d to *D lists.
|
|
23
|
-
* * {@link module:object.selectObjectProperties|selectObjectProperties()} - keep only specific properties
|
|
24
|
-
* * {@link module:object.filterObjectProperties|filterObjectProperties()} - remove specific properties
|
|
25
|
-
* * {@link module:object.mapProperties|mapProperties(collection, fn, ...properties)} - map multiple properties at once (like parseInt, or toString)
|
|
26
|
-
* * {@link module:object.formatProperties|formatProperties(collection, propertyTranslation)} - map specific properties (ex: toString, toNumber, etc)
|
|
27
|
-
* * {@link module:object.union|union(objectList1, objectList2)} - Unites the properties of two collections of objects.
|
|
28
17
|
* * Fetch child properties from related objects
|
|
29
18
|
* * {@link module:object.fetchObjectProperty|fetchObjectProperty(object, string)} - use dot notation to bring a child property onto a parent
|
|
30
19
|
* * {@link module:object.fetchObjectProperties|fetchObjectProperties(object, string[])} - use dot notation to bring multiple child properties onto a parent
|
|
31
20
|
* * {@link module:object.join|join(array, index, map, fn)} - join a collection against a map by a given index
|
|
32
21
|
* * {@link module:object.joinProperties|join(array, index, map, ...fields)} - join a collection, and copy properties over from the mapped object.
|
|
22
|
+
* * Fetch values safely
|
|
33
23
|
* * {@link module:object.propertyFromList|propertyFromList(array, propertyName)} - fetches a specific property from all objects in a list
|
|
34
24
|
* * {@link module:object.extractObjectProperty|extractObjectProperty(list, propertyNameOrFn)} - extracts a property or fn across all objects in list.
|
|
35
25
|
* * {@link module:object.extractObjectProperties|extractObjectProperties(list, propertyNameOrFnMap)} - extracts multiple propertie or fn across all objects in list.
|
|
26
|
+
* * Apply deep values safely
|
|
27
|
+
* * {@link module:object.assign|objAssign(object, property, value)} - Applies properties to an object in functional programming style.
|
|
28
|
+
* * {@link module:object.augment|augment(object, augmentFn)} - Applies properties to an object similar to Map
|
|
29
|
+
* * {@link module:object.assignEntities|objAssignEntities(object, [property, value])} - Applies properties to an object using Array values - [key,value]
|
|
30
|
+
* * {@link module:object.setPropertyDefaults|setPropertyDefaults()} - sets values for objects that don't currently have the property
|
|
31
|
+
* * {@link module:object.applyPropertyValue|object.applyPropertyValue} - safely apply a value deeply and safely
|
|
32
|
+
* * {@link module:object.applyPropertyValues|object.applyPropertyValues} - apply an array of values safely and deeply against a list of objects.
|
|
33
|
+
* * Manipulating objects
|
|
34
|
+
* * {@link module:object.augmentInherit|augmentInherit(object, augmentFn)} - Applies properties to a collection of objects, 'remembering' the last value - useful for 1d to *D lists.
|
|
35
|
+
* * {@link module:object.selectObjectProperties|selectObjectProperties()} - keep only specific properties
|
|
36
|
+
* * {@link module:object.filterObjectProperties|filterObjectProperties()} - remove specific properties
|
|
37
|
+
* * {@link module:object.mapProperties|mapProperties(collection, fn, ...properties)} - map multiple properties at once (like parseInt, or toString)
|
|
38
|
+
* * {@link module:object.formatProperties|formatProperties(collection, propertyTranslation)} - map specific properties (ex: toString, toNumber, etc)
|
|
39
|
+
* * {@link module:object.union|union(objectList1, objectList2)} - Unites the properties of two collections of objects.
|
|
36
40
|
* * Rename properties
|
|
37
41
|
* * {@link module:object.cleanProperties|cleanProperties()} - correct inaccessible property names in a list of objects - in place
|
|
38
|
-
*
|
|
42
|
+
* * {@link module:object.cleanProperties2|cleanProperties2()} - correct inaccessible property names in a list of objects - on a cloned list
|
|
39
43
|
* * {@link module:object.cleanPropertyNames|cleanPropertyNames()} - create a translation of inaccessible names to accessible ones
|
|
40
44
|
* * {@link module:object.cleanPropertyName|cleanPropertyName()} - create a translation of a specific property name to be accessible.
|
|
41
45
|
* * {@link module:object.renameProperties|renameProperties()} - Use a translation from old property names to new ones
|
|
@@ -498,46 +502,6 @@ module.exports.filterObjectProperties = function filterObjectProperties(list, pr
|
|
|
498
502
|
});
|
|
499
503
|
};
|
|
500
504
|
|
|
501
|
-
/**
|
|
502
|
-
* Options for fetching object properties
|
|
503
|
-
* @typedef {Object} FetchObjectOptions
|
|
504
|
-
* @property {Boolean} safeAccess - whether to safely access, even if the path cannot be found
|
|
505
|
-
* @property {Boolean} append - whether to only return the properties (default) or append
|
|
506
|
-
*/
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Fetches multiple properties from an object or list of objects.
|
|
510
|
-
* @param {Object | Object[]} list - collection of objects to reduce
|
|
511
|
-
* @param {Map<String,any>} propertyNames - Object with the keys as the properties
|
|
512
|
-
* and the values using dot notation to access related records and properties
|
|
513
|
-
* (ex: {parentName: 'somePropertyObject.parent.parent.name', childName: 'child.Name'})
|
|
514
|
-
* @param {FetchObjectOptions} options - {@link module:object~FetchObjectOptions|See FetchObjectOptions}
|
|
515
|
-
* @returns {Object[]} - objects with the properties resolved
|
|
516
|
-
* (ex: {parentname, childName, etc.})
|
|
517
|
-
*/
|
|
518
|
-
module.exports.fetchObjectProperties = function fetchObjectProperties(list, propertyNames, options = {}) {
|
|
519
|
-
const {
|
|
520
|
-
//-- whether to safely access even if object path cannot be found
|
|
521
|
-
safeAccess = false,
|
|
522
|
-
|
|
523
|
-
//-- whether to fetch only those specific properties, or append to the object
|
|
524
|
-
append = false
|
|
525
|
-
} = options;
|
|
526
|
-
|
|
527
|
-
if (!list) return [];
|
|
528
|
-
const targetList = Array.isArray(list) ? list : [list];
|
|
529
|
-
|
|
530
|
-
const props = Object.getOwnPropertyNames(propertyNames);
|
|
531
|
-
|
|
532
|
-
return targetList.map((obj) => {
|
|
533
|
-
const result = append ? { ...obj } : {};
|
|
534
|
-
props.forEach((prop) => {
|
|
535
|
-
result[prop] = ObjectUtils.fetchObjectProperty(obj, propertyNames[prop], safeAccess);
|
|
536
|
-
});
|
|
537
|
-
return result;
|
|
538
|
-
});
|
|
539
|
-
};
|
|
540
|
-
|
|
541
505
|
/**
|
|
542
506
|
* Similar to a transpose, this finds all the values of a particular property
|
|
543
507
|
* within a list of objects.
|
|
@@ -558,7 +522,9 @@ module.exports.fetchObjectProperties = function fetchObjectProperties(list, prop
|
|
|
558
522
|
* @param {Function | String} propertyOrFn - Name of the property or accessor function
|
|
559
523
|
* @returns {Array} - single array the values stored in propertyOrFn across all objects in objectList.
|
|
560
524
|
* @see {@link module:aggregate.unique|unique()} to see all the unique values stored
|
|
561
|
-
* @see {@link module:object.extractObjectProperties|extractObjectProperties
|
|
525
|
+
* @see {@link module:object.extractObjectProperties|object.extractObjectProperties} - to extract into array vectors
|
|
526
|
+
* @see {@link module:object.fetchObjectProperty|object.fetchObjectProperty} - to extract a deep value and optionally throw if not found
|
|
527
|
+
* @see {@link module:object.applyPropertyValue|object.applyPropertyValue} - to apply a single value to a single object using dot notation safely
|
|
562
528
|
*/
|
|
563
529
|
module.exports.extractObjectProperty = function extractObjectProperty(list, propertyOrFn) {
|
|
564
530
|
let cleanList = !list ? [] : Array.isArray(list) ? list : [list];
|
|
@@ -600,6 +566,8 @@ module.exports.extractObjectProperty = function extractObjectProperty(list, prop
|
|
|
600
566
|
* @param {Map<Function | String>} propertyOrFnMap - Name of the property or accessor function
|
|
601
567
|
* @returns {Object} - Object with the keys in the map as properties - extracting the values across all in list.
|
|
602
568
|
* @see {@link module:object.extractObjectProperty|extractObjectProperty(list, propertyNameOrFn)} to see all the values stored for a single property.
|
|
569
|
+
* @see {@link module:object.applyPropertyValues|object.applyPropertyValues} - to safely and deeply apply the list of values extracted to a list of objects.
|
|
570
|
+
* @see {@link module:object.fetchObjectProperties} - to fetch multiple properties at once into objects
|
|
603
571
|
*/
|
|
604
572
|
module.exports.extractObjectProperties = function extractObjectProperties(list, propertyOrFnMap) {
|
|
605
573
|
let propertyEntries = [];
|
|
@@ -625,36 +593,266 @@ module.exports.extractObjectProperties = function extractObjectProperties(list,
|
|
|
625
593
|
const results = {};
|
|
626
594
|
propertyEntries.forEach(([propertyName, propertyOrFn]) => {
|
|
627
595
|
results[propertyName] = ObjectUtils.extractObjectProperty(list, propertyOrFn || propertyName);
|
|
628
|
-
// const fn = ObjectUtils.evaluateFunctionOrProperty(propertyOrFn);
|
|
629
|
-
// results[propertyName] = cleanList.map(fn);
|
|
630
596
|
});
|
|
631
597
|
|
|
632
598
|
return results;
|
|
633
599
|
};
|
|
634
600
|
|
|
601
|
+
/**
|
|
602
|
+
* Options for fetching object properties
|
|
603
|
+
* @typedef {Object} FetchObjectOptions
|
|
604
|
+
* @property {Boolean} safeAccess - whether to safely access, even if the path cannot be found
|
|
605
|
+
*/
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Fetches multiple properties from an object or list of objects.
|
|
609
|
+
*
|
|
610
|
+
* ```
|
|
611
|
+
* testObj = {
|
|
612
|
+
* name: 'john',
|
|
613
|
+
* courses: [{ name: 'econ-101' }]
|
|
614
|
+
* }
|
|
615
|
+
* utils.object.fetchObjectProperty(testObj,
|
|
616
|
+
* { 'courseName': 'courses[0].?name', personName: 'name' });
|
|
617
|
+
* // { courseName: 'econ-101', personName: 'john' }
|
|
618
|
+
* ```
|
|
619
|
+
*
|
|
620
|
+
* @param {Object | Object[]} list - collection of objects to reduce
|
|
621
|
+
* @param {Object<String,any>} propertyNames - Object with the keys as as properties to return,
|
|
622
|
+
* and the values using dot notation to access related records and properties
|
|
623
|
+
* (ex: {parentName: 'somePropertyObject.parent.parent.name', childName: 'child.Name'})
|
|
624
|
+
* @param {FetchObjectOptions} options - {@link module:object~FetchObjectOptions|See FetchObjectOptions}
|
|
625
|
+
* @returns {Object[]} - objects with the properties resolved
|
|
626
|
+
* (ex: {parentname, childName, etc.})
|
|
627
|
+
* @see {@link module:object.fetchObjectProperty|object.fetchObjectProperty} - to safely fetch a single value
|
|
628
|
+
* @see {@link module:object.applyPropertyValues|object.applyPropertyValues} - to safely and deeply apply the list of values extracted to a list of objects.
|
|
629
|
+
* @see {@link module:object.extractObjectProperties|object.extractObjectProperties} - to extract into array vectors instead of objects
|
|
630
|
+
*/
|
|
631
|
+
module.exports.fetchObjectProperties = function fetchObjectProperties(list, propertyNames, options = {}) {
|
|
632
|
+
if (!list) return [];
|
|
633
|
+
const targetList = Array.isArray(list) ? list : [list];
|
|
634
|
+
|
|
635
|
+
const {
|
|
636
|
+
//-- whether to fetch only those specific properties, or append to the object
|
|
637
|
+
append = false
|
|
638
|
+
} = options;
|
|
639
|
+
|
|
640
|
+
const props = Object.getOwnPropertyNames(propertyNames);
|
|
641
|
+
|
|
642
|
+
return targetList.map((obj) => {
|
|
643
|
+
const result = append ? { ...obj } : {};
|
|
644
|
+
props.forEach((prop) => {
|
|
645
|
+
result[prop] = ObjectUtils.fetchObjectProperty(obj, propertyNames[prop], options);
|
|
646
|
+
});
|
|
647
|
+
return result;
|
|
648
|
+
});
|
|
649
|
+
};
|
|
650
|
+
|
|
635
651
|
/**
|
|
636
652
|
* Accesses a property using a string
|
|
653
|
+
*
|
|
654
|
+
* ```
|
|
655
|
+
* testObj = {
|
|
656
|
+
* name: 'john',
|
|
657
|
+
* courses: [{ name: 'econ-101' }]
|
|
658
|
+
* }
|
|
659
|
+
* utils.object.fetchObjectProperty(testObj, 'courses[0].?name');
|
|
660
|
+
* // 'econ-101'
|
|
661
|
+
* ```
|
|
662
|
+
*
|
|
663
|
+
* note that the options allow for safe property access
|
|
664
|
+
*
|
|
665
|
+
* ```
|
|
666
|
+
* testObj = {
|
|
667
|
+
* name: 'john',
|
|
668
|
+
* courses: [{ name: 'econ-101' }]
|
|
669
|
+
* }
|
|
670
|
+
* utils.object.fetchObjectProperty(testObj, 'courses[0].courseId');
|
|
671
|
+
* // throws an error
|
|
672
|
+
*
|
|
673
|
+
* utils.object.fetchObjectProperty(testObj, 'courses[0].?courseId');
|
|
674
|
+
* // null - because of optional condition operator
|
|
675
|
+
*
|
|
676
|
+
* utils.object.fetchObjectProperty(testObj, 'courses[0].courseId', { safeAccess: true });
|
|
677
|
+
* // null - because of the safe access option
|
|
678
|
+
* ```
|
|
679
|
+
*
|
|
637
680
|
* @param {Object} obj - object to access the properties on
|
|
638
681
|
* @param {String} propertyAccess - dot notation for the property to access
|
|
639
682
|
* (ex: `parent.obj.Name`)
|
|
640
683
|
* @param {FetchObjectOptions} options - {@link module:object~FetchObjectOptions|See FetchObjectOptions}
|
|
641
684
|
* @returns {any} - the value accessed at the end ofthe property chain
|
|
685
|
+
* @see {@link module:object.fetchObjectProperties} - to fetch multiple properties at once into objects
|
|
686
|
+
* @see {@link module:object.extractObjectProperty|object.extractObjectProperty} - to safely extract a deep value without options
|
|
687
|
+
* @see {@link module:object.applyPropertyValue|object.applyPropertyValue} - to apply a single value to a single object using dot notation safely
|
|
642
688
|
*/
|
|
643
|
-
module.exports.fetchObjectProperty = function fetchObjectProperty(obj, propertyAccess,
|
|
689
|
+
module.exports.fetchObjectProperty = function fetchObjectProperty(obj, propertyAccess, options = {}) {
|
|
644
690
|
if (!obj || !propertyAccess) return null;
|
|
691
|
+
const {
|
|
692
|
+
//-- whether to safely access even if object path cannot be found
|
|
693
|
+
safeAccess = false
|
|
694
|
+
} = options;
|
|
645
695
|
|
|
646
|
-
|
|
647
|
-
|
|
696
|
+
const cleanPropertyAccess = String(propertyAccess)
|
|
697
|
+
.replace(/\[/g, '.')
|
|
698
|
+
.replace(/\]/g, '.')
|
|
699
|
+
.replace(/[.]+/g, '.')
|
|
700
|
+
.replace(/^[.]+/, '')
|
|
701
|
+
.replace(/[.]$/, '');
|
|
702
|
+
|
|
703
|
+
return cleanPropertyAccess.split('.')
|
|
648
704
|
.reduce((currentVal, prop) => {
|
|
705
|
+
let isElvis = false;
|
|
706
|
+
let cleanProp = prop;
|
|
707
|
+
if (prop && prop.length > 0 && prop[0] === '?') {
|
|
708
|
+
isElvis = true;
|
|
709
|
+
cleanProp = prop.slice(1);
|
|
710
|
+
}
|
|
649
711
|
if (currentVal) {
|
|
650
|
-
return currentVal[
|
|
651
|
-
} else if (safeAccess ||
|
|
712
|
+
return currentVal[cleanProp];
|
|
713
|
+
} else if (safeAccess || isElvis) {
|
|
652
714
|
return null;
|
|
653
715
|
}
|
|
654
716
|
throw Error(`Invalid property ${propertyAccess} [${prop}] does not exist - safeAccess:${safeAccess}`);
|
|
655
717
|
}, obj);
|
|
656
718
|
};
|
|
657
719
|
|
|
720
|
+
/**
|
|
721
|
+
* Applies a target value onto a source object in-place safely - using dot-notation paths.
|
|
722
|
+
*
|
|
723
|
+
* This can be as simple as safely applying a value even if targetObj may be null
|
|
724
|
+
* ```
|
|
725
|
+
* targetObj = { id: 1, city: 'Seattle', month: 'Aug', precip: 0.87 };
|
|
726
|
+
* utils.object.applyPropertyValue(targetObj, 'state', 'WA');
|
|
727
|
+
* // { id: 1, city: 'Seattle', month: 'Aug', precip: 0.87, state: 'WA };
|
|
728
|
+
* ```
|
|
729
|
+
*
|
|
730
|
+
* working with deeply nested objects
|
|
731
|
+
* ```
|
|
732
|
+
* targetObj = { name: 'john smith', class: { name: 'ECON_101', professor: { last_name: 'Winklemeyer' }} };
|
|
733
|
+
* utils.object.applyPropertyValue(targetObj, 'class.professor.first_name', 'René');
|
|
734
|
+
* // { name: 'john smith', class: { name: 'ECON_101', professor: { last_name: 'Winklemeyer', first_name: 'René' }} };
|
|
735
|
+
* ```
|
|
736
|
+
*
|
|
737
|
+
* or safely working with arrays of values
|
|
738
|
+
* ```
|
|
739
|
+
* targetObj = { name: 'john smith', classes: [{ name: 'ECON_101' }] };
|
|
740
|
+
* utils.object.applyPropertyValue(targetObj, 'classes[0].grade', 'A');
|
|
741
|
+
* // { name: 'john smith', classes: [{ name: 'ECON_101', grade: 'A' }] };
|
|
742
|
+
* ```
|
|
743
|
+
*
|
|
744
|
+
* @param {Object} obj - object to apply the value to
|
|
745
|
+
* @param {string} path - dot notation path to set the value, ex: 'geo', or 'states[0].prop'
|
|
746
|
+
* @param {any} value - value to set
|
|
747
|
+
* @returns {Object} - the object the value was applied to
|
|
748
|
+
* @see {@link module:object.applyPropertyValues|object.applyPropertyValues} - to safely and deeply apply the list of values extracted to a list of objects.
|
|
749
|
+
* @see {@link module:object.extractObjectProperty|object.extractObjectProperty} - to safely extract a deep value
|
|
750
|
+
* @see {@link module:object.fetchObjectProperty|object.fetchObjectProperty} - to extract a deep value and optionally throw if not found
|
|
751
|
+
*/
|
|
752
|
+
module.exports.applyPropertyValue = function applyPropertyValue(obj, path, value) {
|
|
753
|
+
// const signature = 'applyPropertyValue(obj, path, value)';
|
|
754
|
+
|
|
755
|
+
if (!obj) return obj;
|
|
756
|
+
if (!path) return obj;
|
|
757
|
+
|
|
758
|
+
const cleanPath = String(path)
|
|
759
|
+
.replace(/\[/g, '.')
|
|
760
|
+
.replace(/\]/g, '.')
|
|
761
|
+
.replace(/[.]+/g, '.')
|
|
762
|
+
.replace(/^[.]+/, '')
|
|
763
|
+
.replace(/[.]$/, '');
|
|
764
|
+
|
|
765
|
+
const splitPath = cleanPath.split('.');
|
|
766
|
+
const terminalIndex = splitPath.length - 1;
|
|
767
|
+
|
|
768
|
+
return splitPath
|
|
769
|
+
.reduce((currentVal, prop, currentIndex) => {
|
|
770
|
+
//-- can no longer occur
|
|
771
|
+
// if (!prop) throw Error(`${signature}:Unable to set value with path:${path}`);
|
|
772
|
+
|
|
773
|
+
const isLeaf = currentIndex === terminalIndex;
|
|
774
|
+
if (isLeaf) {
|
|
775
|
+
// eslint-disable-next-line no-param-reassign
|
|
776
|
+
currentVal[prop] = value;
|
|
777
|
+
// if (value === undefined) {
|
|
778
|
+
// delete currentVal[prop];
|
|
779
|
+
// } else {
|
|
780
|
+
// currentVal[prop] = value;
|
|
781
|
+
// }
|
|
782
|
+
return obj;
|
|
783
|
+
}
|
|
784
|
+
//-- not a leaf
|
|
785
|
+
if (!currentVal[prop]) {
|
|
786
|
+
// eslint-disable-next-line no-param-reassign
|
|
787
|
+
currentVal[prop] = {};
|
|
788
|
+
}
|
|
789
|
+
return currentVal[prop];
|
|
790
|
+
}, obj);
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* Opposite of the extractObjectProperty, this takes a value / set of values
|
|
795
|
+
* and applies them along a given path on each of the target objects.
|
|
796
|
+
*
|
|
797
|
+
* for example:
|
|
798
|
+
*
|
|
799
|
+
* ```
|
|
800
|
+
* weather = [{ id: 1, city: 'Seattle', month: 'Aug', precip: 0.87 },
|
|
801
|
+
* { id: 3, city: 'New York', month: 'Apr', precip: 3.94 },
|
|
802
|
+
* { id: 6, city: 'Chicago', month: 'Apr', precip: 3.62 }];
|
|
803
|
+
*
|
|
804
|
+
* cities = utils.object.extractObjectProperty('city');
|
|
805
|
+
* // ['Seattle', 'New York', 'Chicago'];
|
|
806
|
+
*
|
|
807
|
+
* //-- async process to geocode
|
|
808
|
+
* geocodedCities = geocodeCity(cities);
|
|
809
|
+
* // [{ city: 'Seattle', state: 'WA', country: 'USA' },
|
|
810
|
+
* // { city: 'New York', state: 'NY', country: 'USA' },
|
|
811
|
+
* // { city: 'Chicago', state: 'IL', country: 'USA' }]
|
|
812
|
+
*
|
|
813
|
+
* utils.applyPropertyValues(weather, 'geo', geocodedCities);
|
|
814
|
+
* [{ id: 1, city: 'Seattle', month: 'Aug', precip: 0.87, geo: { city: 'Seattle', state: 'WA', country: 'USA' } },
|
|
815
|
+
* { id: 3, city: 'New York', month: 'Apr', precip: 3.94, geo: { city: 'New York', state: 'NY', country: 'USA' } },
|
|
816
|
+
* { id: 6, city: 'Chicago', month: 'Apr', precip: 3.62, geo: { city: 'Chicago', state: 'IL', country: 'USA' } }];
|
|
817
|
+
*
|
|
818
|
+
* Note that traditional [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
|
|
819
|
+
* works best for if you are working with objects completely in memory.
|
|
820
|
+
*
|
|
821
|
+
* But this helps quite a bit if the action of mapping / transforming values
|
|
822
|
+
* needs to be separate from the extraction / application of values back.
|
|
823
|
+
*
|
|
824
|
+
* @param {Object} obj - object to apply the value to
|
|
825
|
+
* @param {string} path - dot notation path to set the value, ex: 'geo', or 'states[0].prop'
|
|
826
|
+
* @param {any} value - the value that should be set at that path.
|
|
827
|
+
* @returns {Object}
|
|
828
|
+
* @see {@link module:object.applyPropertyValue} - to apply a single value to a single object
|
|
829
|
+
* @see {@link module:object.fetchObjectProperties} - to fetch multiple properties at once into objects
|
|
830
|
+
* @see {@link module:object.extractObjectProperties|object.extractObjectProperties} - to extract properties into array vectors instead of objects
|
|
831
|
+
*/
|
|
832
|
+
module.exports.applyPropertyValues = function applyPropertyValues(objectList, path, valueList) {
|
|
833
|
+
// const signature = 'applyPropertyValues(objectList, path, valueList)';
|
|
834
|
+
if (!objectList || !path) {
|
|
835
|
+
//-- do nothing
|
|
836
|
+
return objectList;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const cleanObjectList = Array.isArray(objectList) ? objectList : [objectList];
|
|
840
|
+
const cleanValueList = Array.isArray(valueList) ? valueList : Array(cleanObjectList.length).fill(valueList);
|
|
841
|
+
|
|
842
|
+
// if (cleanObjectList.length !== cleanValueList) throw Error(
|
|
843
|
+
// `${signature}: objectList.length[${cleanObjectList.length}] does not match valueList.length[${cleanValueList.length}]`
|
|
844
|
+
// );
|
|
845
|
+
const minLength = Math.min(cleanObjectList.length, cleanValueList.length);
|
|
846
|
+
|
|
847
|
+
for (let i = 0; i < minLength; i += 1) {
|
|
848
|
+
const obj = cleanObjectList[i];
|
|
849
|
+
const val = cleanValueList[i];
|
|
850
|
+
ObjectUtils.applyPropertyValue(obj, path, val);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return objectList;
|
|
854
|
+
};
|
|
855
|
+
|
|
658
856
|
/**
|
|
659
857
|
* Translates specific properties to a new value on an object, or collection of objects.
|
|
660
858
|
*
|
package/src/plantuml.js
CHANGED
|
@@ -214,7 +214,7 @@ module.exports.render = function render(plantUMLText, plantUMLOptions) {
|
|
|
214
214
|
const targetURL = this.generateURL(plantUMLText, plantUMLOptions);
|
|
215
215
|
if (showURL || debug) console.log(`url:${targetURL}`);
|
|
216
216
|
|
|
217
|
-
const result = await fetch(targetURL);
|
|
217
|
+
const result = await global.fetch(targetURL);
|
|
218
218
|
|
|
219
219
|
if (format === 'png') {
|
|
220
220
|
const buf = await result.buffer();
|