jupyter-ijavascript-utils 1.54.0 → 1.55.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
@@ -74,6 +74,7 @@ Give it a try here:
74
74
  [![Binder:what can I do with this](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/paulroth3d/jupyter-ijavascript-utils/main?labpath=example.ipynb)
75
75
 
76
76
  ## What's New
77
+ * 1.55 - #76, #77, #74, #78
77
78
  * 1.54 - additional Date logic, and formatting. #70 #71 #72
78
79
  * 1.53 - additional docs and examples for {@link module:color|color/colour} package.
79
80
  * 1.52 - print a date to ISO in local time with {@link module:date.toLocalISO|date.toLocalISO}
package/Dockerfile CHANGED
@@ -1,3 +1,3 @@
1
1
  # syntax=docker/dockerfile:1
2
2
 
3
- FROM darkbluestudios/jupyter-ijavascript-utils:binder_1.53.0
3
+ FROM darkbluestudios/jupyter-ijavascript-utils:binder_1.55.0
package/README.md CHANGED
@@ -54,6 +54,7 @@ This is not intended to be the only way to accomplish many of these tasks, and a
54
54
  ![Screenshot of example notebook](docResources/img/mainExampleNotebook.png)
55
55
 
56
56
  # What's New
57
+ * 1.55 - #76, #77, #74, #78
57
58
  * 1.54 - additional Date logic, and formatting. #70 #71 #72
58
59
  * 1.53 - additional docs and examples for color/colour package.
59
60
  * 1.52 - print a date to ISO in local time with date.toLocalISO
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyter-ijavascript-utils",
3
- "version": "1.54.0",
3
+ "version": "1.55.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",
package/src/chain.js CHANGED
@@ -513,6 +513,7 @@ class ChainContainer {
513
513
 
514
514
  /**
515
515
  * Closes the chain and returns the current value.
516
+ * @param {Function} [functor = null] - optional function (similar to {@link module:chain.chain|chain.chain})
516
517
  * @returns {any}
517
518
  * @see {@link ChainContainer#chain}
518
519
  * @example
@@ -522,8 +523,22 @@ class ChainContainer {
522
523
  * .close();
523
524
  *
524
525
  * // 5
526
+ *
527
+ * //-- or pass an optional function on close
528
+ *
529
+ * doubler = (num) => num + num;
530
+ *
531
+ * utils.chain(3)
532
+ * .chain(doubler)
533
+ * .close(doubler);
534
+ * // 12
535
+ *
525
536
  */
526
- close() {
537
+ close(functor) {
538
+ if ((typeof functor) === 'function') {
539
+ this.value = this.chain(functor).value;
540
+ }
541
+
527
542
  return this.value;
528
543
  }
529
544
 
package/src/date.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * * {@link module:date.isValid|date.isValid(date)} - whether the date provided is an invalid date
7
7
  * * Parse
8
8
  * * {@link module:date.parse|date.parse(String)} - parse a date and throw an exception if it is not a valid date
9
- * * TimeZones
9
+ * * Timezones
10
10
  * * {@link module:date.toLocalISO|date.toLocalISO} - prints in 8601 format with timezone offset based on a tz entry - like america/chicago
11
11
  * * {@link module:date.getTimezoneOffset|date.getTimezoneOffset(String)} - gets the number of milliseconds offset for a given timezone
12
12
  * * {@link module:date.correctForTimezone|date.correctForTimezone(Date, String)} - meant to correct a date already off from UTC to the correct time
@@ -51,7 +51,7 @@
51
51
  * @exports date
52
52
  * @see {@link https://stackoverflow.com/questions/15141762/how-to-initialize-a-javascript-date-to-a-particular-time-zone}
53
53
  * @see {@link https://www.youtube.com/watch?v=2rnIHsqABfM&t=750s|epochShifting}
54
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTimeZones|MDN TimeZone Names}
54
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTimezones|MDN Timezone Names}
55
55
  */
56
56
  module.exports = {};
57
57
  const DateUtils = module.exports;
@@ -181,7 +181,7 @@ module.exports.durationLong = function durationLong(epochDifference) {
181
181
  };
182
182
 
183
183
  /**
184
- * @typedef {Object} TimeZoneEntry
184
+ * @typedef {Object} TimezoneEntry
185
185
  * @property {String} tz - the name of the timezone
186
186
  * @property {Function} formatter - formats a date to that local timezone
187
187
  * @property {Number} epoch - the difference in milliseconds from that tz to UTC
@@ -189,22 +189,22 @@ module.exports.durationLong = function durationLong(epochDifference) {
189
189
  */
190
190
 
191
191
  /**
192
- * Collection of TimeZoneEntries by the tz string
192
+ * Collection of TimezoneEntries by the tz string
193
193
  * @private
194
- * @type {Map<String,TimeZoneEntry>}
194
+ * @type {Map<String,TimezoneEntry>}
195
195
  */
196
- module.exports.timeZoneOffsetMap = new Map();
196
+ module.exports.timezoneOffsetMap = new Map();
197
197
 
198
198
  /**
199
- * Fetches or creates a TimeZoneEntry
199
+ * Fetches or creates a TimezoneEntry
200
200
  * @private
201
- * @param {String} timeZoneStr - tz database entry for the timezone
202
- * @returns {TimeZoneEntry}
201
+ * @param {String} timezoneStr - tz database entry for the timezone
202
+ * @returns {TimezoneEntry}
203
203
  */
204
- module.exports.getTimezoneEntry = function getTimezoneEntry(timeZoneStr) {
205
- const cleanTz = String(timeZoneStr).toLowerCase();
206
- if (DateUtils.timeZoneOffsetMap.has(cleanTz)) {
207
- return DateUtils.timeZoneOffsetMap.get(cleanTz);
204
+ module.exports.getTimezoneEntry = function getTimezoneEntry(timezoneStr) {
205
+ const cleanTz = String(timezoneStr).toLowerCase();
206
+ if (DateUtils.timezoneOffsetMap.has(cleanTz)) {
207
+ return DateUtils.timezoneOffsetMap.get(cleanTz);
208
208
  }
209
209
  const d = new Date(Date.UTC(2025, 0, 1, 0, 0, 0));
210
210
 
@@ -239,7 +239,7 @@ module.exports.getTimezoneEntry = function getTimezoneEntry(timeZoneStr) {
239
239
  result[type] = value;
240
240
  return result;
241
241
  }, {});
242
- // const impactedDate = new Date(d.toLocaleString('en-US', { timeZone: timeZoneStr }));
242
+ // const impactedDate = new Date(d.toLocaleString('en-US', { timezone: timezoneStr }));
243
243
  const dateStr = `${dm.year}-${DateUtils.padTime(dm.month)}-${DateUtils.padTime(dm.day)}T${
244
244
  DateUtils.padTime(dm.hour)}:${DateUtils.padTime(dm.minute)}:${DateUtils.padTime(dm.second)}.${
245
245
  DateUtils.padTime(dm.fractionalSecond, 3)}`;
@@ -260,7 +260,7 @@ module.exports.getTimezoneEntry = function getTimezoneEntry(timeZoneStr) {
260
260
 
261
261
  const result = ({ tz: cleanTz, formatter, epoch: diff, offset });
262
262
 
263
- DateUtils.timeZoneOffsetMap.set(cleanTz, result);
263
+ DateUtils.timezoneOffsetMap.set(cleanTz, result);
264
264
 
265
265
  return result;
266
266
  };
@@ -274,69 +274,180 @@ module.exports.getTimezoneEntry = function getTimezoneEntry(timeZoneStr) {
274
274
  * See {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones|the list of TZ database time zones}
275
275
  * for the full list of options.
276
276
  *
277
- * @param {String} timeZoneStr - a timezone string like "America/Toronto"
278
- * @returns {TimeZoneEntry} - the number of milliseconds between UTC and that timezone
277
+ * @param {String} timezoneStr - a timezone string like "America/Toronto"
278
+ * @returns {TimezoneEntry} - the number of milliseconds between UTC and that timezone
279
279
  */
280
- module.exports.getTimezoneOffset = function getTimezoneOffset(timeZoneStr) {
281
- return DateUtils.getTimezoneEntry(timeZoneStr).epoch;
280
+ module.exports.getTimezoneOffset = function getTimezoneOffset(timezoneStr) {
281
+ return DateUtils.getTimezoneEntry(timezoneStr).epoch;
282
282
  };
283
283
 
284
284
  /**
285
- * JavaScript always stores dates in UTC, but the data you imported may have lost the timezone information.
285
+ * CorrectForTimezone is the opposite of {@link module:date.epochShift|date.epochShift}.
286
+ * (This subtracts the timezone offset to a date, where the other adds the offset)
286
287
  *
287
- * Use this to correct the timezone to the correct time UTC.
288
+ * Use this when a date string is read by javascript, BUT the timezone is not sent or passed.
288
289
  *
289
- * For Example:
290
+ * For example, something VERY IMPORTANT happened at '2/1/2025, 2:15:41 PM EST', ISO '2025-02-01T20:15:41.000Z', epoch: 1738440941000.
291
+ *
292
+ * But the dates from the database don't include the timezone.
293
+ * (Note that `Z` is conceptually equivalent of +0000)
294
+ *
295
+ * If I create a date in javaScript WITHOUT the timezone, it assumes my local timezone.
290
296
  *
291
297
  * ```
292
- * // the date we originally pulled from the database
293
- * // but thetimezone of the database was america/Toronto but not in UTC
294
- * dateStr = '2024-12-06 18:00';
298
+ * dTest = new Date('2025-02-01T20:15:41.000'); // -- DID NOT INCLUDE Timezone, so it assumes local timezone
299
+ * ({ epoch: dTest2.getTime(), iso: dTest.toISOString(), local: dTest.toLocaleString() });
295
300
  *
296
- * // we may have done this:
297
- * myDate = new Date(dateStr);
301
+ * //-- time is INCORRECT, what should be the ISO time, is the local time.
302
+ * // local: '2/1/2025, 8:15:41 PM', iso: '2025-02-02T02:15:41.000Z', epoch: 1738440941000
303
+ * ```
298
304
  *
299
- * // but now calling toISOString() is incorrect
300
- * myDate.toISOString(); // '2024-12-06T18:00:00.0000'
305
+ * It assumed that the local time was 8pm instead of that as the ISO / GMT time.
306
+ *
307
+ * To correct this, I just call epoch shift
301
308
  *
302
- * // it should be:
303
- * correctedDate = utils.date.correctForTimezone('america/Toronto');
304
- * correctedDate.toISOString(); // '2024-12-06T13:00:00.00.000' -- the correct time UTC
309
+ * ```
310
+ * dTest = new Date('2025-02-01T20:15:41.000'); // -- DID NOT INCLUDE Timezone, so it assumes local timezone
311
+ * dTest2 = utils.date.epochShift(dTest, 'us/central'); //-- correct for my local timezone
312
+ * ({ epoch: dTest2.getTime(), iso: dTest.toISOString(), local: dTest.toLocaleString() });
313
+ *
314
+ * //-- time is CORRECT
315
+ * // local: '2/1/2025, 2:15:41 PM', iso: '2025-02-01T20:15:41.000Z', epoch: 1738440941000
305
316
  * ```
306
317
  *
307
318
  * See {@link https://en.wikipedia.org/wiki/List_of_tz_database_time_zones|the list of TZ database time zones}
308
319
  * for the full list of timezone options.
309
320
  *
310
321
  * @param {Date} date - the date to be corrected in a new instance
311
- * @param {String} timeZoneStr - tz database name for the timezone
312
- * @returns {Date} - copy of the date corrected
322
+ * @param {String} localTimezoneStr - tz database name for YOUR current machine's timezone
323
+ * @returns {Date} - new instance of a corrected date back to UTC
324
+ * @see {@link module:date.correctForOtherTimezone|date.correctForOtherTimezone} - if the date given is "local" but for another timezone
325
+ * @see {@link module:date.toLocalISO|date.toLocalISO} - if you want to print a date to another timezone
313
326
  */
314
- module.exports.correctForTimezone = function correctForTimezone(date, timeZoneStr) {
315
- const { epoch } = DateUtils.getTimezoneEntry(timeZoneStr);
316
- return new Date(date.getTime() + epoch);
327
+ module.exports.correctForTimezone = function correctForTimezone(date, localTimezoneStr) {
328
+ const { epoch } = DateUtils.getTimezoneEntry(localTimezoneStr);
329
+ return new Date(date.getTime() - epoch);
317
330
  };
318
331
 
319
332
  /**
333
+ * This helps you correct a "local date" from another timezone.
334
+ *
335
+ * For example, if you got '2:15 PM' from a machine that is in eastern.
336
+ *
337
+ * Combination of {@link module:date.correctForTimezone|date.correctForTimezone}
338
+ * and {@link module:date.epochShift|date.epochShift}
339
+ *
340
+ * For example, say you got a timezone string like this: `2024-12-27 13:30:00`
341
+ *
342
+ * You know the timezone of the source is in `us/eastern`, but you are in `us/central`.
343
+ *
344
+ * If you just use `Date.parse(dateString), it assumes `1:30 Central` - not `1:30 Eastern`
345
+ *
346
+ * We can correct it like this:
347
+ *
348
+ * ```
349
+ * dateStr = '2024-12-27 13:30:00';
350
+ * d = new Date(Date.parse(dateStr));
351
+ *
352
+ * //-- the source was from 'us/eastern' timezone (-0500)
353
+ * sourceTimezone = 'us/eastern';
354
+ *
355
+ * //-- we are currently in 'us/central' timezone (-0600)
356
+ * //-- this matters because of the Date.parse() done before
357
+ * localTimezone = 'us/central'; // (change if yours is different)
358
+ *
359
+ * utils.date.correctForOtherTimezone( d, sourceTimezone, localTimezone);
360
+ *
361
+ * //-- correctly converted it to the correct local time
362
+ * // 2024-12-28T18:30:00.000Z
363
+ * ```
364
+ *
365
+ * @param {Date} date - the date to be corrected in a new instance
366
+ * @param {string} sourceTimezone - the timezone of the source information
367
+ * @param {string} localTimezone - the timezone of this local machine
368
+ * @returns {Date} - new date that is corrected to UTC
369
+ * @see {@link module:date.toLocalISO|date.toLocalISO} - if you want to print a date to another timezone
370
+ */
371
+ module.exports.correctForOtherTimezone = function correctForTimezones(date, sourceTimezone, localTimezone) {
372
+ return DateUtils.correctForTimezone(
373
+ DateUtils.epochShift(date, sourceTimezone),
374
+ localTimezone
375
+ );
376
+ };
377
+
378
+ /**
379
+ * EpochShift is the opposite of {@link module:date.correctForTimezone|date.correctForTimezone}.
380
+ * (This adds the timezone offset, where the other subtracts the offset)
381
+ *
382
+ * Use this if you somehow have a date that needs to be shifted by the timezone offset.
383
+ *
384
+ * This is rarely useful in itself, but in combination with the {@link module:date.correctForTimezone|date.correctForTimezone}
385
+ * you can use this to correct for "local dates" but are in another timezone than you are in.
386
+ *
387
+ * (For example, you got a local date for 2:15 PM EST, but your current computer is in CST)
388
+ *
389
+ * JavaScript dates only have three ways of importing dates:
390
+ *
391
+ * * Parse the date assuming local timezone
392
+ * * Parse the date using [ISO 8601 formats](https://www.iso.org/iso-8601-date-and-time-format.html)
393
+ * * This option DOES provide an option for providing a timezone offset (ex: `-0500`)
394
+ *
395
+ * Since this is the opposite of {@link module:date.correctForTimezone|date.correctForTimezone}, this can be useful.
396
+ *
397
+ * But most likely, you'd like to use either:
398
+ *
399
+ * * {@link module:date.correctForTimezone|date.correctForTimezone} or
400
+ * * {@link module:date.correctForTimezones|date.correctForTimezones}.
401
+ *
402
+ * ---
403
+ *
320
404
  * Epoch shift a date, so the utcDate is no longer correct,
321
405
  * but many other functions behave closer to expected.
322
406
  *
407
+ * Once you epoch shift the date, then time stored in the date is incorrect (because it always points to GMT)
408
+ *
409
+ * For example, using `.toIsoString()` or anything with Intl.DateTimeFormat etc - will all give you incorrect results.
410
+ *
323
411
  * See {@link https://stackoverflow.com/a/15171030|here why this might not be what you want}
324
412
  *
413
+ * --
414
+ *
415
+ * Sometimes though, some libraries use the "getMonth()", "getDate()" of the date, and do not support using timezones.
416
+ *
417
+ * That is when this shines.
418
+ *
419
+ * ```
420
+ * timeStamp = 1738437341000;
421
+ * d = new Date(timeStamp);
422
+ * d.toIsoString(); // 2025-02-01T19:15:41.000Z
423
+ * `current time is: ${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}` // 'current time is: 2025-2-1'
424
+ *
425
+ *
426
+ * ```
427
+ *
325
428
  * @param {Date} date - date to shift
326
- * @param {String} timeZoneStr - the tz database name of the timezone
429
+ * @param {String} timezoneStr - the tz database name of the timezone
327
430
  * @returns {Date}
431
+ * @see {@link module:date.toEpochShiftedISO|date.toEpochShiftedISO} - this will print the
432
+ * "local time" of an epoch shifted date.
328
433
  * @see {@link module:date.toLocalISO|date.toLocalISO} - consider as an alternative.
329
434
  * This prints the correct time, without updating the date object.
435
+ * @see {@link module:date.correctForTimezone|date.correctForTimezone} - once shifted,
436
+ * this allows you to shift a date back to GMT time.
330
437
  */
331
- module.exports.epochShift = function epochShift(date, timeZoneStr) {
332
- const { epoch } = DateUtils.getTimezoneEntry(timeZoneStr);
333
- return new Date(date.getTime() - epoch);
438
+ module.exports.epochShift = function epochShift(date, timezoneStr) {
439
+ const { epoch } = DateUtils.getTimezoneEntry(timezoneStr);
440
+ return new Date(date.getTime() + epoch);
334
441
  };
335
442
 
336
443
  /**
337
- * Prints a date in 8601 format to a timezone (with +H:MM offset)
444
+ * Prints a date in 8601 format to a timezone (with +H:MM offset) using
445
+ * [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat).
338
446
  *
339
- * Consider this as an alternative to epochShifting.
447
+ * The date accepted here is assumed to already have the internal clock set to GMT.
448
+ *
449
+ * If you do epochShift, then use {@link module:date.toEpochShiftedISO|date.toEpochShiftedISO}
450
+ * and pass the timezone the timezone the date is epoch shifted to.
340
451
  *
341
452
  * ```
342
453
  * d = Date.parse('2024-12-27 13:30:00');
@@ -346,14 +457,55 @@ module.exports.epochShift = function epochShift(date, timeZoneStr) {
346
457
  * ```
347
458
  *
348
459
  * @param {Date} date - date to print
349
- * @param {String} timeZoneStr - the tz database name of the timezone
460
+ * @param {String} timezoneStr - the tz database name of the timezone
350
461
  * @returns {String} - ISO format with timezone offset
351
462
  */
352
- module.exports.toLocalISO = function toLocalISO(date, timeZoneStr) {
353
- const { formatter, offset } = DateUtils.getTimezoneEntry(timeZoneStr);
463
+ module.exports.toLocalISO = function toLocalISO(date, timezoneStr) {
464
+ const { formatter, offset } = DateUtils.getTimezoneEntry(timezoneStr);
354
465
  return `${formatter(date)}${offset}`;
355
466
  };
356
467
 
468
+ module.exports.toIsoStringNoTimezone = function toIsoStringNoTimezone(date) {
469
+ return `${
470
+ date.getFullYear()
471
+ }-${
472
+ String(date.getMonth() + 1).padStart(2, '0')
473
+ }-${
474
+ String(date.getDate()).padStart(2, '0')
475
+ }T${
476
+ String(date.getHours()).padStart(2, '0')
477
+ }:${
478
+ String(date.getMinutes()).padStart(2, '0')
479
+ }:${
480
+ String(date.getSeconds()).padStart(2, '0')
481
+ }.${
482
+ String(date.getMilliseconds()).padStart(3, '0')
483
+ }`;
484
+ };
485
+
486
+ /**
487
+ * Print a date that has been epoch shifted.
488
+ *
489
+ * Dates in JavaScript are always stored in GMT, although you can format it to different times with
490
+ * [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat).
491
+ *
492
+ * Once you epoch shift the date, then time stored in the date is incorrect (because it always points to GMT)
493
+ *
494
+ * For example, using `.toIsoString()` or anything with Intl.DateTimeFormat etc - will all give you incorrect results.
495
+ *
496
+ * If you want an ISO format for an epoch shifted date, you'll need something like this.
497
+ *
498
+ * @param {Date} date - Date to Print
499
+ * @param {String} timezoneStr - the tz database name of the timezone the date is shifted to
500
+ * @returns {String} date in the format of `YYYY-MM-DDTHH:mm:SS.MMMM[+-]TZ`
501
+ * @see {@link module:date.correctForTimezone|date.correctForTimezone} - to shift the date back to GMT
502
+ * @see {@link module:date.toLocalISO|date.toLocalISO} - if the date is not epoch shifted as this uses Intl.DateTimeFormat
503
+ */
504
+ module.exports.toEpochShiftedISO = function toEpochShiftedISO(date, timezoneStr) {
505
+ const { offset } = DateUtils.getTimezoneEntry(timezoneStr);
506
+ return `${DateUtils.toIsoStringNoTimezone(date)}${offset}`;
507
+ };
508
+
357
509
  /**
358
510
  * Clones a date.
359
511
  *
@@ -421,7 +573,7 @@ module.exports.overwrite = function overwrite(dateToUpdate, newDateEpoch) {
421
573
  * @param {Number} [options.minutes=0] - number of minutes to add
422
574
  * @param {Number} [options.hours=0] - number of minutes to add
423
575
  * @param {Number} [options.seconds=0] - number of seconds to add
424
- * @returns {Date} -
576
+ * @returns {Date} - Date with the interval added in
425
577
  */
426
578
  module.exports.add = function add(dateValue, options = null) {
427
579
  if (!options) return dateValue;
@@ -503,8 +655,9 @@ module.exports.startOfDay = function endOfDay(dateValue) {
503
655
  * @param {Number} [options.years=0] - increments the calendar year (as opposed to adding 365.25 days)
504
656
  * @param {Number} [options.months=0] - increments the calendar month (as opposed to adding in 30 days)
505
657
  * @returns {Date[]} - collection of dates (count long)
506
- * @see {@link module:Date.add|utils.date.add}
507
- * @see {@link module:date.generateDateSequence} - finish at an endingDate instead of # of iterations
658
+ * @see {@link module:date.add|utils.date.add}
659
+ * @see {@link module:date.generateDateSequence|date.generateDateSequence} - finish at an endingDate instead of # of iterations
660
+ * @see {@link module:date~DateRange.fromList|DateRange.fromList} - to create Date Ranges from these dates.
508
661
  */
509
662
  module.exports.arrange = function arrange(startDate, count, options) {
510
663
  if (!DateUtils.isValid(startDate)) {
@@ -553,10 +706,11 @@ module.exports.arrange = function arrange(startDate, count, options) {
553
706
  * @param {Number} [options.years=0] - increments the calendar year (as opposed to adding 365.25 days)
554
707
  * @param {Number} [options.months=0] - increments the calendar month (as opposed to adding in 30 days)
555
708
  * @returns {Date[]} - sequence of dates from startDate to endDate
556
- * @see {@link module:Date.add|utils.date.add}
557
- * @see {@link module:date.arrange} - run a set of iterations instead of stopping at endDate
709
+ * @see {@link module:date.add|utils.date.add}
710
+ * @see {@link module:date.arrange|date.arrange} - run a set of iterations instead of stopping at endDate
711
+ * @see {@link module:date~DateRange.fromList|DateRange.fromList} - to create Date Ranges from these dates.
558
712
  */
559
- module.exports.generateDateSequence = function generateDateSequencde(startDate, endDate, options) {
713
+ module.exports.generateDateSequence = function generateDateSequence(startDate, endDate, options) {
560
714
  const results = [];
561
715
 
562
716
  if (!DateUtils.isValid(startDate)) {
@@ -581,7 +735,28 @@ module.exports.generateDateSequence = function generateDateSequencde(startDate,
581
735
  };
582
736
 
583
737
  /**
584
- * Represents a Range between two times
738
+ * Represents a Range between two timestamps.
739
+ *
740
+ * * Creating Date Range
741
+ * * {@link module:date~DateRange.fromList|fromList} - given a list of dates, make range bins for those dates.
742
+ * * {@link module:date~DateRange#reinitialize|reinitialize} - initialize the dateRange in-place with new start/end dates
743
+ * * {@link module:date~DateRange#shiftStart|shiftStart} - shifts the start of the range by hours,minutes,years, etc.
744
+ * * {@link module:date~DateRange#shiftEnd|shiftEnd} - shifts the start of the range by hours,minutes,years, etc.
745
+ *
746
+ * * Understanding the Date Range
747
+ * * {@link module:date~DateRange#contains|contains} - if a date is within this range.
748
+ * * {@link module:date~DateRange#startDate|startDate} - the starting date of the range
749
+ * * {@link module:date~DateRange#endDate|endingDate} - the ending date of the range
750
+ * * {@link module:date~DateRange.startAndEndOfDay|startAndEndOfDay} - Creates a DateRange covering the start and end of a day
751
+ * * {@link module:date~DateRange#overlaps|overlaps} - whether this DateRange overlaps another DateRange
752
+ * * {@link module:date~DateRange#isValid|isValid} - Whether the start and end times of this range are both valid dates
753
+ * * Durations
754
+ * * {@link module:date~DateRange#duration|duration} - Epoch duration (milliseconds) between the start and end timestamps
755
+ * * {@link module:date~DateRange#durationString|durationString} - creates a long duration description
756
+ * * {@link module:date~DateRange#durationISO|durationISO} - returns the duration as a string formatted '0:01:00:00.0000'
757
+ * * String Representation
758
+ * * {@link module:date~DateRange#toString|toString} - String conversion of the DateRange
759
+ * * {@link module:date~DateRange#toLocaleString|toLocaleString} - Creates a locale string describing the DateRange
585
760
  */
586
761
  class DateRange {
587
762
  /**
@@ -619,12 +794,18 @@ class DateRange {
619
794
  * // {start: 2025-03-01TT00:00:00, end: 2025-04-01TT00:00:00}]
620
795
  * ```
621
796
  *
797
+ * (Note: you can also use {@link module:date.arrange|date.arrange} or
798
+ * {@link module:date.generateDateSequence|date.generateDateSequence}
799
+ * to come up with the list of those dates)
800
+ *
622
801
  * (If gaps are desired - ex: April to May and next one June to July,
623
802
  * the simplest is to remove the dates from the resulting list.)
624
803
  *
625
804
  * @param {Date[]} dateList - list of dates
626
805
  * @returns {DateRange[]} - list of dateList.length-1 dateRanges,
627
806
  * where the end of the firstRange is the start of the next.
807
+ * @see {@link module:date.arrange|date.arrange} - to create dates by adding a value multiple times
808
+ * @see {@link module:date.generateDateSequence|date.generateDateSequence} - to create dates between a start and an end date
628
809
  */
629
810
  static fromList(dateSequence) {
630
811
  if (dateSequence.length < 2) return [];
@@ -666,6 +847,10 @@ class DateRange {
666
847
  *
667
848
  * This is very useful for determining overlapping dates.
668
849
  *
850
+ * (Alternatively, you can define a list of dates, and use
851
+ * {@link module:date~DateRange.fromList|DateRange.fromList}
852
+ * to create the bins from those dates)
853
+ *
669
854
  * @param {Date} targetDate - date to use to find the start and end UTC for
670
855
  * @returns {DateRange}
671
856
  */
@@ -756,7 +941,7 @@ class DateRange {
756
941
  * @param {Number} [options.years=0] - increments the calendar year (as opposed to adding 365.25 days)
757
942
  * @param {Number} [options.months=0] - increments the calendar month (as opposed to adding in 30 days)
758
943
  * @param {*} inPlace
759
- * @returns
944
+ * @returns {DateRange} - this DateRange if (inPlace=true), a new instance if (inPlace=false)
760
945
  */
761
946
  shiftStart(options, inPlace = false) {
762
947
  if (inPlace) {
@@ -798,7 +983,7 @@ class DateRange {
798
983
  * @param {Number} [options.years=0] - increments the calendar year (as opposed to adding 365.25 days)
799
984
  * @param {Number} [options.months=0] - increments the calendar month (as opposed to adding in 30 days)
800
985
  * @param {*} inPlace
801
- * @returns
986
+ * @returns {DateRange} - this DateRange if (inPlace=true), a new instance if (inPlace=false)
802
987
  */
803
988
  shiftEnd(options, inPlace = false) {
804
989
  if (inPlace) {
package/src/format.js CHANGED
@@ -43,6 +43,8 @@
43
43
  * * {@link module:format.isEmptyValue|format.isEmptyValue} - determine if a value is not 'empty'
44
44
  * * Extracting values
45
45
  * * {@link module:format.extractWords|format.extractWords} - to extract the words from a string
46
+ * * Making Printing Easier
47
+ * * {@link module:format.clearOutput|format.clearOutput} - has the output cleared. Helpful for setting variables, or importing libraries.
46
48
  *
47
49
  * @module format
48
50
  * @exports format
package/src/hashMap.js CHANGED
@@ -5,6 +5,7 @@ const FormatUtils = require('./format');
5
5
  *
6
6
  * * Modifying
7
7
  * * {@link module:hashMap.add|hashMap.add(map, key, value):Map} - Add a value to a map and return the Map
8
+ * * {@link module:hashMap.update|hashMap.update(map, key, function)} - use a function to get/set a value on a map
8
9
  * * {@link module:hashMap.union|hashMap.union(targetMap, additionalMap, canOverwrite)} - merges two maps and ignores or overwrites with conflicts
9
10
  * * Cloning
10
11
  * * {@link module:hashMap.clone|hashMap.clone(map):Map} - Clones a given Map
@@ -50,6 +51,48 @@ module.exports.add = function add(map, key, value) {
50
51
  return map;
51
52
  };
52
53
 
54
+ /**
55
+ * Use this for times where you want to update a value
56
+ *
57
+ * ```
58
+ * key = 'somethingToIncrement';
59
+ * defaultValue = null;
60
+ *
61
+ * const initialMap = new Map([
62
+ * [key, defaultValue]
63
+ * ]);
64
+ * // Map([[ 'somethingToIncrement', null ]]);
65
+ *
66
+ * const functor = (value) => { //, key, map) => {
67
+ * if (!value) return 1;
68
+ * return value + 1;
69
+ * };
70
+ *
71
+ * HashMapUtil.getSet(initialMap, key, functor);
72
+ * HashMapUtil.getSet(initialMap, key, functor);
73
+ * HashMapUtil.getSet(initialMap, key, functor);
74
+ * HashMapUtil.getSet(initialMap, key, functor);
75
+ * HashMapUtil.getSet(initialMap, key, functor);
76
+ *
77
+ * initialMap.get(key); // 5
78
+ * ```
79
+ *
80
+ * @param {Map} map - map to get and set values from
81
+ * @param {any} key - they key to GET and SET the value (unless setKey is provided)
82
+ * @param {Function} functor - the function called with the arguments below - returning the value to set
83
+ * @param {any} functor.value - the first argument is the current value
84
+ * @param {any} functor.key - the second argument is the key passed
85
+ * @param {any} functor.map - the third argument is the map being acted upon
86
+ * @param {any} [setKey = null] - optional separate key to use to set the updated value
87
+ * @returns {Map}
88
+ */
89
+ module.exports.getSet = function getSet(map, key, functor, setKey = null) {
90
+ const cleanSetKey = setKey || key;
91
+ map.set(cleanSetKey, functor(map.get(key), key, map));
92
+ return map;
93
+ };
94
+ module.exports.update = module.exports.getSet;
95
+
53
96
  /**
54
97
  * Clones a Map
55
98
  * @param {Map} target - Map to clone
package/src/ijs.js CHANGED
@@ -23,6 +23,10 @@ require('./_types/global');
23
23
  * * Rendering
24
24
  * * {@link module:ijs.markdown|ijs.markdown} - Render output as markdown
25
25
  * * {@link module:ijs.htmlScript|ijs.htmlScript} - Leverage external libraries like D3, Leaflet, etc.
26
+ * * Printing
27
+ * * {@link module:ijs.noOutputNeeded|ijs.noOutputNeeded} - clears the output to declutter results (like importing libraries, or functions)
28
+ * * {@link module:ijs.initializePageBreaks|ijs.initializePageBreaks} - call at least once to allow pageBreaks when rendering PDFs
29
+ * * {@link module:ijs.printPageBreak|ijs.printPageBreak} - call to print a page break when rendering PDFs
26
30
  *
27
31
  * For example:
28
32
  *
@@ -577,3 +581,84 @@ module.exports.htmlScript = function htmlScripts(
577
581
 
578
582
  return results;
579
583
  };
584
+
585
+ /**
586
+ * Clears the output.
587
+ *
588
+ * (This is useful to put after importing libraries,
589
+ * or defining a list of functions)
590
+ */
591
+ module.exports.noOutputNeeded = function clearOutput(outputText = '') {
592
+ //-- you must be in iJavaScript container to rendeer
593
+ const context = IJSUtils.detectContext();
594
+
595
+ if (!context) {
596
+ return;
597
+ }
598
+
599
+ context.$$.text(outputText);
600
+ };
601
+ module.exports.clearOutput = module.exports.noOutputNeeded;
602
+
603
+ /**
604
+ * Required to be called first - in order to write page-breaks in the html results.
605
+ *
606
+ * (For Example:)
607
+ *
608
+ * Assume you have the following cells:
609
+ *
610
+ * ```
611
+ * * Some Text
612
+ * * utils.ijs.initializePageBreaks()
613
+ * * some other text
614
+ * * utils.ijs.printPageBreak();
615
+ * * end of document
616
+ * ```
617
+ *
618
+ * When you print to HTML and then render to PDF, you'll see the following:
619
+ *
620
+ * ```
621
+ * * Some Text
622
+ * * utils.ijs.initializePageBreaks()
623
+ *
624
+ * //-- page break
625
+ *
626
+ * * some other text
627
+ * * utils.ijs.printPageBreak();
628
+ *
629
+ * //-- page break
630
+ *
631
+ * * end of document
632
+ * ```
633
+ */
634
+ module.exports.initializePageBreaks = function initializePageBreaks() {
635
+ //-- you must be in iJavaScript container to rendeer
636
+ const context = IJSUtils.detectContext();
637
+
638
+ if (!context) {
639
+ return;
640
+ }
641
+
642
+ context.$$.html(`<style>
643
+ @media print {
644
+ .pagebreak { page-break-before: always; } /* page-break-after works, as well */
645
+ }
646
+ </style>
647
+ <div class="pagebreak"></div>
648
+ `);
649
+ };
650
+
651
+ /**
652
+ * After the {@see module:ijs.initializePageBreaks|utils.ijs.initializePageBreaks} is called,
653
+ * this will create another page break.
654
+ */
655
+ module.exports.printPageBreak = function printPageBreak() {
656
+ //-- you must be in iJavaScript container to rendeer
657
+ const context = IJSUtils.detectContext();
658
+
659
+ if (!context) {
660
+ return;
661
+ }
662
+
663
+ context.$$.html('<div class="pagebreak"></div>');
664
+ };