jupyter-ijavascript-utils 1.14.2 → 1.15.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 CHANGED
@@ -1,6 +1,8 @@
1
1
  # Overview
2
2
 
3
- This is a simple Library for using Jupyter with the IJavaScript kernel.
3
+ This is a library to help people that understand JavaScript
4
+ to leverage for using Jupyter with the iJavaScript kernel
5
+ as a way to load and explore data, and ultimately tell compelling stories with visuals.
4
6
 
5
7
  Jupyter is a way to programmatically explore a subject and interleave text and markdown to make Data Driven Documents.
6
8
 
@@ -44,6 +46,7 @@ This is not intended to be the only way to accomplish many of these tasks, and a
44
46
 
45
47
  ## What's New
46
48
 
49
+ * 1.15 - provide {@link module:object.formatProperties|object.formatProperties} - as a way to quickly convert to string, number, etc.
47
50
  * 1.14 - provide {@link module:object.mapProperties|object.mapProperties()} and {@link module:format.compactNumber|format.compactNumber()}
48
51
  * 1.13 - provide {@link module:random|utils.random()} to genrate random values
49
52
  * 1.12 - provide `utils.table(...)` instead of `new utils.TableGenerator(...)`
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  </a>
8
8
  <img src="https://img.shields.io/badge/Coverage-98-green" />
9
9
  <a href="https://github.com/paulroth3d/jupyter-ijavascript-utils" alt="npm">
10
- <img src="https://img.shields.io/badge/npm-%5E1.14-red" />
10
+ <img src="https://img.shields.io/badge/npm-%5E1.15-red" />
11
11
  </a>
12
12
  </p>
13
13
 
@@ -46,6 +46,7 @@ This is not intended to be the only way to accomplish many of these tasks, and a
46
46
 
47
47
  # What's New
48
48
 
49
+ * 1.15 - provide object.formatProperties - as a way to quickly convert to string, number, etc.
49
50
  * 1.14 - provide format.compactNumber and object.mapProperties
50
51
  * 1.13 - provide utils.random() to genrate random values
51
52
  * 1.12 - provide `utils.table(...)` instead of `new utils.TableGenerator(...)`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyter-ijavascript-utils",
3
- "version": "1.14.2",
3
+ "version": "1.15.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",
@@ -18,6 +18,8 @@ const IJSUtils = require('./ijs');
18
18
 
19
19
  const ArrayUtils = require('./array');
20
20
 
21
+ const FormatUtils = require('./format');
22
+
21
23
  const { createSort } = require('./array');
22
24
 
23
25
  /**
@@ -613,27 +615,11 @@ class TableGenerator {
613
615
  return this;
614
616
  }
615
617
 
618
+ const cleanedFormatter = FormatUtils.prepareFormatterObject(obj);
619
+
616
620
  const fnMap = new Map();
617
- Object.getOwnPropertyNames(obj).forEach((key) => {
618
- if ((typeof obj[key]) === 'string') {
619
- let fn;
620
- const str = obj[key].toLowerCase();
621
- if (str === 'string') {
622
- fn = (val) => String(val);
623
- } else if (str === 'number') {
624
- fn = (val) => Number(val);
625
- } else if (str === 'boolean') {
626
- fn = (val) => val ? 'true' : 'false';
627
- } else {
628
- throw Error(`TableGenerator.format: property ${key} formatter of ${str} is unsupported. Only (String, Number, Boolean) are supported`);
629
- }
630
- fnMap.set(key, fn);
631
- } else {
632
- if ((typeof obj[key]) !== 'function') {
633
- throw (Error(`Formatter properties must be functions. [${key}]`));
634
- }
635
- fnMap.set(key, obj[key]);
636
- }
621
+ Object.getOwnPropertyNames(cleanedFormatter).forEach((key) => {
622
+ fnMap.set(key, cleanedFormatter[key]);
637
623
  });
638
624
 
639
625
  this.#formatterFn = ({ value, property }) => fnMap.has(property)
package/src/format.js CHANGED
@@ -632,3 +632,72 @@ module.exports.compactNumber = function compactNumber(num, digits = 0) {
632
632
 
633
633
  return (num / siValue).toFixed(digits) + siKey;
634
634
  };
635
+
636
+ module.exports.safeConvertString = function safeConvertString(val) {
637
+ try {
638
+ return String(val);
639
+ } catch (err) {
640
+ //-- I cannot find a way to reliably throw an error, but keep it in case it does
641
+ /* istanbul ignore next */
642
+ return null;
643
+ }
644
+ };
645
+
646
+ module.exports.safeConvertFloat = function safeConvertFloat(val) {
647
+ try {
648
+ return Number.parseFloat(val);
649
+ } catch (err) {
650
+ //-- I cannot find a way to reliably throw an error, but keep it in case it does
651
+ /* istanbul ignore next */
652
+ return null;
653
+ }
654
+ };
655
+
656
+ module.exports.safeConvertInteger = function safeConvertInteger(val) {
657
+ try {
658
+ return Number.parseInt(val, 10);
659
+ } catch (err) {
660
+ //-- I cannot find a way to reliably throw an error, but keep it in case it does
661
+ /* istanbul ignore next */
662
+ return null;
663
+ }
664
+ };
665
+
666
+ module.exports.safeConvertBoolean = function safeConvertBoolean(val) {
667
+ if (typeof val === 'string') {
668
+ return val.toUpperCase() === 'TRUE';
669
+ }
670
+ return val ? true : false;
671
+ };
672
+
673
+ module.exports.prepareFormatterObject = function prepareFormatterObject(formatterObject) {
674
+ //-- @TODO: find way to reliably say that the propertyTranslation is an object
675
+ // propertyTranslations.constructor.name !== 'Object'
676
+ if (!formatterObject) {
677
+ throw Error(['ObjectUtils.formatProperties(collection, propertyTranslations): propertyTranslations must be an object, ',
678
+ 'with the properties matching those to be formatted, and values as functions returning the new value'].join(''));
679
+ }
680
+
681
+ const translationKeys = Array.from(Object.keys(formatterObject));
682
+
683
+ const result = ({ ...formatterObject });
684
+
685
+ translationKeys.forEach((key) => {
686
+ const translationVal = formatterObject[key];
687
+ if (typeof translationVal === 'function') {
688
+ //-- do nothing
689
+ } else if (translationVal === 'string') {
690
+ result[key] = FormatUtils.safeConvertString;
691
+ } else if (translationVal === 'number' || translationVal === 'float') {
692
+ result[key] = FormatUtils.safeConvertFloat;
693
+ } else if (translationVal === 'int' || translationVal === 'integer') {
694
+ result[key] = FormatUtils.safeConvertInteger;
695
+ } else if (translationVal === 'boolean') {
696
+ result[key] = FormatUtils.safeConvertBoolean;
697
+ } else {
698
+ result[key] = () => translationVal;
699
+ }
700
+ });
701
+
702
+ return result;
703
+ };
package/src/object.js CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  const schemaGenerator = require('generate-schema');
4
4
 
5
+ const FormatUtils = require('./format');
6
+
5
7
  /**
6
8
  * Utility for working with and massaging javascript objects.
7
9
  *
@@ -18,6 +20,7 @@ const schemaGenerator = require('generate-schema');
18
20
  * * {@link module:object.selectObjectProperties|selectObjectProperties()} - keep only specific properties
19
21
  * * {@link module:object.filterObjectProperties|filterObjectProperties()} - remove specific properties
20
22
  * * {@link module:object.mapProperties|mapProperties(collection, fn, ...properties)} - map multiple properties at once (like parseInt, or toString)
23
+ * * {@link module:object.formatProperties|formatProperties(collection, propertyTranslation)} - map specific properties (ex: toString, toNumber, etc)
21
24
  * * Fetch child properties from related objects
22
25
  * * {@link module:object.fetchObjectProperty|fetchObjectProperty(object, string)} - use dot notation to bring a child property onto a parent
23
26
  * * {@link module:object.fetchObjectProperties|fetchObjectProperties(object, string[])} - use dot notation to bring multiple child properties onto a parent
@@ -146,7 +149,8 @@ module.exports.objAssignEntities = function objAssignEntities(obj, entities) {
146
149
  * Runs a map over a collection, and adds properties the the objects.
147
150
  *
148
151
  * @param {Object | Array<Object>} objCollection - object or collection of objects to augment
149
- * @param {Function} mappingFn - (record) => {Object} mapping function
152
+ * @param {Function | Object} mappingFn - (record) => {Object} mapping function <br />
153
+ * or object with properties to create
150
154
  * @param {Boolean} [inPlace=false] - whether to update the collection in place (true) or cloned (false)
151
155
  * @returns {Array<Object>} - collection of records with the fields merged
152
156
  * @example
@@ -439,6 +443,82 @@ module.exports.fetchObjectProperty = function fetchObjectProperty(obj, propertyA
439
443
  }, obj);
440
444
  };
441
445
 
446
+ /**
447
+ * Translates specific properties to a new value on an object, or collection of objects.
448
+ *
449
+ * The properties defined in the `propertyTranslations` argument is then the property to be updated. (All other properties remain the same)
450
+ *
451
+ * You can either provide a function accepting the current value and returning the new value (any) => any
452
+ *
453
+ * Or you can provide one of the common shorthands:
454
+ *
455
+ * * 'string'
456
+ * * 'float' or 'number'
457
+ * * 'int' or 'integer'
458
+ * * 'boolean'
459
+ *
460
+ * ```
461
+ * data = [
462
+ * {station: 'A', isFahreinheit: 'true', offset: '0', temp: 98, type: 'F', descr: '0123'},
463
+ * {station: 'A', isFahreinheit: 'TRUE', offset: '2', temp: 99, type: 'F', descr: '0123456'},
464
+ * {station: 'A', isFahreinheit: 'false', offset: '3', temp: 100, type: 'F', descr: '0123456789'}
465
+ * ];
466
+ *
467
+ * utils.object.format(data, ({
468
+ * //-- to a literal value
469
+ * type: 'C',
470
+ * //-- convert it to 'string', 'number' || 'float', 'int' || 'integer', 'boolean'
471
+ * offset: 'number',
472
+ * isFahreinheit: 'boolean',
473
+ * //-- or convert the value with a function accepting the current value
474
+ * //-- and returning the new value
475
+ * temp: (val) => (val - 32) * 0.5556
476
+ * }));
477
+ *
478
+ * // [
479
+ * // { station: 'A', isFahreinheit: true, offset: 0, temp: 36.669599999999996, type: 'C', descr: '0123' },
480
+ * // { station: 'A', isFahreinheit: true, offset: 2, temp: 37.2252, type: 'C', descr: '0123456' },
481
+ * // { station: 'A', isFahreinheit: false, offset: 3, temp: 37.7808, type: 'C', descr: '0123456789' }
482
+ * // ];
483
+ * ```
484
+ *
485
+ * **Please note, you can pass a single object to be cleaned**,<br /> but it will be returned as an array of one object.
486
+ *
487
+ * ```
488
+ * data = [{station: 'A', isFahreinheit: 'TRUE', offset: '2', temp: 99, type: 'F', descr: '0123456'}];
489
+ *
490
+ * utils.object.format(data, ({
491
+ * //-- convert it to 'string', 'number' || 'float', 'int' || 'integer', 'boolean'
492
+ * offset: 'number',
493
+ * isFahreinheit: 'boolean'
494
+ * }));
495
+ *
496
+ * // [{station: 'A', isFahreinheit: true, offset: 2, temp: 99, type: 'F', descr: '0123456'}];
497
+ * ```
498
+ *
499
+ * @param {Object} collection - the list of objects to update specific properties
500
+ * @param {Object} propertyTranslations - An object with property names as the properties to update <br />
501
+ * and the values as a function ((any) => any) accepting the current value, returning the new value.
502
+ * @returns {Object[]} - collection of objects transformed
503
+ * @see {@link module:object.augment|augment(collection, fn)} - to add in new properties
504
+ * @see {@link TableGenerator#formatter} - for other examples
505
+ */
506
+ module.exports.formatProperties = function formatProperties(collection, propertyTranslations) {
507
+ const cleanCollection = !collection ? []
508
+ : Array.isArray(collection) ? collection : [collection];
509
+
510
+ propertyTranslations = FormatUtils.prepareFormatterObject(propertyTranslations);
511
+ const translationKeys = Array.from(Object.keys(propertyTranslations));
512
+
513
+ return cleanCollection.map((obj) => {
514
+ const clone = { ...obj };
515
+ translationKeys.forEach((key) => {
516
+ clone[key] = propertyTranslations[key](clone[key]);
517
+ });
518
+ return clone;
519
+ });
520
+ };
521
+
442
522
  /**
443
523
  * returns a map of the types of fields stored
444
524
  * @see generateSchema