@dereekb/util 10.1.30 → 10.2.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.
Files changed (45) hide show
  1. package/fetch/LICENSE +21 -0
  2. package/fetch/index.cjs.d.ts +1 -0
  3. package/fetch/index.cjs.js +5480 -0
  4. package/fetch/index.esm.js +5448 -0
  5. package/fetch/package.json +15 -3
  6. package/fetch/src/lib/error.d.ts +7 -0
  7. package/fetch/src/lib/fetch.d.ts +5 -5
  8. package/fetch/src/lib/fetch.page.d.ts +116 -0
  9. package/fetch/src/lib/index.d.ts +1 -0
  10. package/fetch/src/lib/json.d.ts +17 -1
  11. package/index.cjs.js +1421 -1319
  12. package/index.esm.js +1560 -1437
  13. package/package.json +10 -5
  14. package/src/lib/date/date.d.ts +14 -0
  15. package/src/lib/model/model.d.ts +1 -0
  16. package/src/lib/number/round.d.ts +2 -1
  17. package/src/lib/object/object.equal.d.ts +2 -0
  18. package/src/lib/page/page.calculator.d.ts +6 -1
  19. package/src/lib/page/page.d.ts +0 -2
  20. package/src/lib/string/char.d.ts +4 -0
  21. package/src/lib/string/replace.d.ts +29 -1
  22. package/test/CHANGELOG.md +9 -0
  23. package/test/package.json +1 -1
  24. package/test/src/lib/jest.fail.d.ts +22 -3
  25. package/test/src/lib/jest.fail.js +29 -2
  26. package/test/src/lib/jest.fail.js.map +1 -1
  27. package/fetch/CHANGELOG.md +0 -931
  28. package/fetch/src/index.js +0 -5
  29. package/fetch/src/index.js.map +0 -1
  30. package/fetch/src/lib/error.js +0 -31
  31. package/fetch/src/lib/error.js.map +0 -1
  32. package/fetch/src/lib/fetch.js +0 -177
  33. package/fetch/src/lib/fetch.js.map +0 -1
  34. package/fetch/src/lib/fetch.type.js +0 -3
  35. package/fetch/src/lib/fetch.type.js.map +0 -1
  36. package/fetch/src/lib/index.js +0 -11
  37. package/fetch/src/lib/index.js.map +0 -1
  38. package/fetch/src/lib/json.js +0 -80
  39. package/fetch/src/lib/json.js.map +0 -1
  40. package/fetch/src/lib/provider.js +0 -9
  41. package/fetch/src/lib/provider.js.map +0 -1
  42. package/fetch/src/lib/timeout.js +0 -38
  43. package/fetch/src/lib/timeout.js.map +0 -1
  44. package/fetch/src/lib/url.js +0 -102
  45. package/fetch/src/lib/url.js.map +0 -1
package/index.cjs.js CHANGED
@@ -4,7 +4,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var extraSet = require('extra-set');
6
6
  var makeError = require('make-error');
7
- var lodash = require('lodash');
8
7
 
9
8
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
10
9
 
@@ -8261,6 +8260,12 @@ function firstAndLastCharacterOccurrence(input, find) {
8261
8260
  occurences
8262
8261
  };
8263
8262
  }
8263
+ /**
8264
+ * Returns true if the input string contains the character (or string) to find.
8265
+ */
8266
+ function stringContains(input, find) {
8267
+ return input.indexOf(find) !== -1;
8268
+ }
8264
8269
  /**
8265
8270
  * Replaces the last character with the replacement string if it is any of the input values.
8266
8271
  *
@@ -8378,6 +8383,54 @@ function findStringsRegexString(find) {
8378
8383
  const escapedInput = input.map(escapeStringForRegex);
8379
8384
  return escapedInput.join('|');
8380
8385
  }
8386
+ /**
8387
+ * Creates an EscapeStringCharactersFunction
8388
+ *
8389
+ * @param config
8390
+ * @returns
8391
+ */
8392
+ function escapeStringCharactersFunction(config) {
8393
+ const {
8394
+ escapeTargets: inputEscapeTargets,
8395
+ escapeCharacter
8396
+ } = config;
8397
+ const escapeTargets = inputEscapeTargets instanceof Set ? inputEscapeTargets : new Set(inputEscapeTargets);
8398
+ return input => {
8399
+ /**
8400
+ * Find index of all occurences in the input to replace/merge together.
8401
+ */
8402
+ const occurrences = findAllCharacterOccurences(escapeTargets, input);
8403
+ let result;
8404
+ switch (occurrences.length) {
8405
+ case 0:
8406
+ result = input;
8407
+ break;
8408
+ case 1:
8409
+ const charToReplace = input[occurrences[0]];
8410
+ result = replaceCharacterAtIndexWith(input, occurrences[0], escapeCharacter(charToReplace)); //Add an escape to the character
8411
+ break;
8412
+ default:
8413
+ const parts = [];
8414
+ const endAt = occurrences.length;
8415
+ let start = 0;
8416
+ let occurrence = 0;
8417
+ for (let i = 0; i < endAt; i += 1) {
8418
+ occurrence = occurrences[i];
8419
+ const char = input[occurrence];
8420
+ const sub = input.substring(start, occurrence);
8421
+ const part = sub + escapeCharacter(char);
8422
+ parts.push(part);
8423
+ start = occurrence + 1;
8424
+ }
8425
+ // add in the last substring
8426
+ parts.push(input.substring(start));
8427
+ // join all parts together
8428
+ result = parts.join('');
8429
+ break;
8430
+ }
8431
+ return result;
8432
+ };
8433
+ }
8381
8434
  /**
8382
8435
  * Escapes the input string to be usable in a Regex value.
8383
8436
  *
@@ -8385,44 +8438,12 @@ function findStringsRegexString(find) {
8385
8438
  *
8386
8439
  * @param input
8387
8440
  */
8388
- function escapeStringForRegex(input) {
8389
- /**
8390
- * index of all occurences in the input to replace/merge together.
8391
- */
8392
- const occurrences = findAllCharacterOccurences(REGEX_SPECIAL_CHARACTERS_SET, input);
8393
- let result;
8394
- function escapeCharacter(char) {
8441
+ const escapeStringForRegex = escapeStringCharactersFunction({
8442
+ escapeTargets: REGEX_SPECIAL_CHARACTERS_SET,
8443
+ escapeCharacter(char) {
8395
8444
  return `\\${char}`;
8396
8445
  }
8397
- switch (occurrences.length) {
8398
- case 0:
8399
- result = input;
8400
- break;
8401
- case 1:
8402
- const charToReplace = input[occurrences[0]];
8403
- result = replaceCharacterAtIndexWith(input, occurrences[0], escapeCharacter(charToReplace)); //Add an escape to the character
8404
- break;
8405
- default:
8406
- const parts = [];
8407
- const endAt = occurrences.length;
8408
- let start = 0;
8409
- let occurrence = 0;
8410
- for (let i = 0; i < endAt; i += 1) {
8411
- occurrence = occurrences[i];
8412
- const char = input[occurrence];
8413
- const sub = input.substring(start, occurrence);
8414
- const part = sub + escapeCharacter(char);
8415
- parts.push(part);
8416
- start = occurrence + 1;
8417
- }
8418
- // add in the last substring
8419
- parts.push(input.substring(start));
8420
- // join all parts together
8421
- result = parts.join('');
8422
- break;
8423
- }
8424
- return result;
8425
- }
8446
+ });
8426
8447
  function findAllCharacterOccurencesFunction(characterSet) {
8427
8448
  return (input, maxToReturn) => {
8428
8449
  const max = maxToReturn !== null && maxToReturn !== void 0 ? maxToReturn : Number.MAX_SAFE_INTEGER;
@@ -9655,6 +9676,16 @@ function makeDateMonthForMonthOfYear(monthOfYear) {
9655
9676
  function isDate(value) {
9656
9677
  return value instanceof Date || typeof value === 'object' && Object.prototype.toString.call(value) === '[object Date]';
9657
9678
  }
9679
+ /**
9680
+ * Returns true if the two input dates are equal.
9681
+ *
9682
+ * @param a
9683
+ * @param b
9684
+ * @returns
9685
+ */
9686
+ function isEqualDate(a, b) {
9687
+ return a.getTime() === b.getTime();
9688
+ }
9658
9689
 
9659
9690
  const FRACTIONAL_HOURS_PRECISION_FUNCTION = cutValueToPrecisionFunction(3);
9660
9691
  /**
@@ -11465,258 +11496,160 @@ function objectIsEmpty(obj) {
11465
11496
  }
11466
11497
 
11467
11498
  /**
11468
- * Performs a deep comparison to check if all values on the input filters are equal.
11499
+ * Returns the day of the week for the input day.
11500
+ *
11501
+ * Equivalent to date.getDay()
11502
+ *
11503
+ * @param date
11504
+ * @returns
11469
11505
  */
11470
- function areEqualPOJOValues(a, b) {
11471
- return lodash.isEqual(a, b);
11472
- }
11473
- function objectFieldEqualityChecker(config) {
11474
- const {
11475
- fields,
11476
- defaultEqualityFunction = (a, b) => a === b
11477
- } = config;
11478
- const _fields = new Map();
11479
- fields.forEach(input => {
11480
- let field;
11481
- if (typeof input === 'object') {
11482
- field = input;
11483
- } else {
11484
- field = {
11485
- fieldName: input,
11486
- isEqual: defaultEqualityFunction
11487
- };
11488
- }
11489
- _fields.set(field.fieldName, field);
11490
- });
11491
- const fn = (a, b) => {
11492
- const equalFields = [];
11493
- const unequalFields = [];
11494
- _fields.forEach((fieldConfig, fieldName) => {
11495
- const {
11496
- isEqual
11497
- } = fieldConfig;
11498
- isEqual(a[fieldName], b[fieldName]) ? equalFields.push(fieldName) : unequalFields.push(fieldName);
11499
- });
11500
- return {
11501
- a,
11502
- b,
11503
- isEqual: unequalFields.length === 0,
11504
- equalFields,
11505
- unequalFields
11506
- };
11507
- };
11508
- fn._fields = _fields;
11509
- return fn;
11506
+ function dayOfWeek(date) {
11507
+ return date.getDay();
11510
11508
  }
11511
-
11512
11509
  /**
11513
- * Creates a EqualityComparatorFunction that compares the two input values
11510
+ * Creates a DecisionFunction that checks whether or not the input day or days of
11514
11511
  *
11515
- * @param readKey
11512
+ * @param allowedDaysOfWeek
11516
11513
  * @returns
11517
11514
  */
11518
- function objectKeysEqualityComparatorFunction(readKey) {
11519
- const readKeysSet = readKeysSetFunction(readKey);
11520
- const readKeysArray = readKeysFunction(readKey);
11521
- return safeEqualityComparatorFunction((a, b) => {
11522
- if (a.length === b.length) {
11523
- if (a.length === 0) {
11524
- return true; // both the same/empty arrays
11525
- }
11526
-
11527
- const aKeys = readKeysSet(a);
11528
- const bKeys = readKeysArray(b);
11529
- if (aKeys.size === bKeys.length) {
11530
- return setContainsAllValues(aKeys, bKeys);
11531
- }
11532
- }
11533
- return false;
11515
+ function isInAllowedDaysOfWeekSet(allowedDaysOfWeek) {
11516
+ return isInSetDecisionFunction(allowedDaysOfWeek, x => {
11517
+ return typeof x === 'number' ? x : dayOfWeek(x);
11534
11518
  });
11535
11519
  }
11536
11520
  /**
11537
- * Creates a EqualityComparatorFunction that compares the two input values
11521
+ * Returns all days of the week starting from the given day up to the specified number of days.
11538
11522
  *
11539
- * @param readKey
11540
- * @returns
11523
+ * Returns 7 days by default.
11524
+ *
11525
+ * @param startingOn
11541
11526
  */
11542
- function objectKeyEqualityComparatorFunction(readKey) {
11543
- return safeEqualityComparatorFunction((a, b) => readKey(a) === readKey(b));
11544
- }
11545
-
11546
- function makeCopyModelFieldFunction(key, inputConfig) {
11547
- const config = inputConfig !== null && inputConfig !== void 0 ? inputConfig : {};
11548
- const hasDefault = objectHasKey(config, 'default');
11549
- const defaultValue = config.default;
11550
- return (from, target) => {
11551
- var _a;
11552
- if (objectHasKey(from, key)) {
11553
- target[key] = (_a = from[key]) !== null && _a !== void 0 ? _a : defaultValue;
11554
- } else if (hasDefault) {
11555
- target[key] = defaultValue;
11527
+ function daysOfWeekArray(startingOn = exports.Day.SUNDAY, maxDays = 7) {
11528
+ const days = [];
11529
+ let day = startingOn;
11530
+ while (days.length < maxDays) {
11531
+ days.push(day);
11532
+ if (day === exports.Day.SATURDAY) {
11533
+ day = exports.Day.SUNDAY;
11534
+ } else {
11535
+ day += 1;
11556
11536
  }
11557
- };
11537
+ }
11538
+ return days;
11558
11539
  }
11559
-
11560
- function makeModelMapFunctions(fields) {
11561
- const keys = filterKeyValueTuples(fields);
11562
- const conversionsByKey = keys.map(([key, field]) => [key, field]);
11563
- const fromConversions = conversionsByKey.map(([key, configs]) => [key, configs.from]);
11564
- const toConversions = conversionsByKey.map(([key, configs]) => [key, configs.to]);
11565
- const from = makeModelConversionFieldValuesFunction(fromConversions);
11566
- const to = makeModelConversionFieldValuesFunction(toConversions);
11540
+ /**
11541
+ * Enum for the days of the week.
11542
+ */
11543
+ exports.Day = void 0;
11544
+ (function (Day) {
11545
+ Day[Day["SUNDAY"] = 0] = "SUNDAY";
11546
+ Day[Day["MONDAY"] = 1] = "MONDAY";
11547
+ Day[Day["TUESDAY"] = 2] = "TUESDAY";
11548
+ Day[Day["WEDNESDAY"] = 3] = "WEDNESDAY";
11549
+ Day[Day["THURSDAY"] = 4] = "THURSDAY";
11550
+ Day[Day["FRIDAY"] = 5] = "FRIDAY";
11551
+ Day[Day["SATURDAY"] = 6] = "SATURDAY";
11552
+ })(exports.Day || (exports.Day = {}));
11553
+ function enabledDaysFromDaysOfWeek(input) {
11554
+ const set = new Set(input);
11567
11555
  return {
11568
- from,
11569
- to
11556
+ sunday: set.has(exports.Day.SUNDAY),
11557
+ monday: set.has(exports.Day.MONDAY),
11558
+ tuesday: set.has(exports.Day.TUESDAY),
11559
+ wednesday: set.has(exports.Day.WEDNESDAY),
11560
+ thursday: set.has(exports.Day.THURSDAY),
11561
+ friday: set.has(exports.Day.FRIDAY),
11562
+ saturday: set.has(exports.Day.SATURDAY)
11570
11563
  };
11571
11564
  }
11572
- function makeModelConversionFieldValuesFunction(fields) {
11573
- return (input, inputTarget, options) => {
11574
- const target = inputTarget !== null && inputTarget !== void 0 ? inputTarget : {};
11575
- if (input != null) {
11576
- let targetFields = fields;
11577
- // if options are provided, filter down.
11578
- if (options) {
11579
- const fieldsToMap = new Set(findPOJOKeys(input, {
11580
- keysFilter: options.fields,
11581
- valueFilter: options.definedOnly === false ? exports.KeyValueTypleValueFilter.NONE : exports.KeyValueTypleValueFilter.UNDEFINED
11582
- }));
11583
- targetFields = fields.filter(x => fieldsToMap.has(x[0]));
11584
- }
11585
- targetFields.forEach(([key, convert]) => target[key] = convert(input[key]));
11565
+ function daysOfWeekFromEnabledDays(input) {
11566
+ const daysOfWeek = [];
11567
+ if (input) {
11568
+ if (input.sunday) {
11569
+ daysOfWeek.push(exports.Day.SUNDAY);
11586
11570
  }
11587
- return target;
11588
- };
11589
- }
11590
- function modelFieldConversions(config) {
11591
- return mapObjectMap(config, x => modelFieldMapFunctions(x));
11592
- }
11593
- function modelFieldMapFunctions(config) {
11594
- return {
11595
- from: modelFieldMapFunction(config.from),
11596
- to: modelFieldMapFunction(config.to)
11597
- };
11571
+ if (input.monday) {
11572
+ daysOfWeek.push(exports.Day.MONDAY);
11573
+ }
11574
+ if (input.tuesday) {
11575
+ daysOfWeek.push(exports.Day.TUESDAY);
11576
+ }
11577
+ if (input.wednesday) {
11578
+ daysOfWeek.push(exports.Day.WEDNESDAY);
11579
+ }
11580
+ if (input.thursday) {
11581
+ daysOfWeek.push(exports.Day.THURSDAY);
11582
+ }
11583
+ if (input.friday) {
11584
+ daysOfWeek.push(exports.Day.FRIDAY);
11585
+ }
11586
+ if (input.saturday) {
11587
+ daysOfWeek.push(exports.Day.SATURDAY);
11588
+ }
11589
+ }
11590
+ return daysOfWeek;
11598
11591
  }
11599
11592
  /**
11600
- * Creates a ModelFieldMapFunction.
11593
+ * Returns an array of strinsg with each day of the week named.
11601
11594
  *
11602
- * @param config
11603
11595
  * @returns
11604
11596
  */
11605
- function modelFieldMapFunction(config) {
11606
- const convert = config.convert;
11607
- const convertMaybe = config.convertMaybe;
11608
- const defaultOutput = config.default;
11609
- const defaultInput = config.defaultInput;
11610
- const hasDefaultInput = defaultInput != null;
11611
- const getDefaultOutput = asGetter(defaultOutput);
11612
- const getDefaultInput = asGetter(defaultInput);
11613
- return input => {
11614
- let result;
11615
- if (isMaybeSo(input)) {
11616
- result = convert(input);
11617
- } else {
11618
- if (convertMaybe) {
11619
- result = convertMaybe(input !== null && input !== void 0 ? input : getDefaultInput());
11620
- } else if (hasDefaultInput) {
11621
- result = convert(getDefaultInput());
11622
- } else {
11623
- result = getDefaultOutput();
11624
- }
11625
- }
11626
- return result;
11627
- };
11628
- }
11629
- /**
11630
- * Converts the input to a ModelFieldConversions value.
11631
- *
11632
- * @param input
11633
- * @returns
11634
- */
11635
- function toModelFieldConversions(input) {
11636
- var _a;
11637
- const conversions = (_a = input.fieldConversions) !== null && _a !== void 0 ? _a : modelFieldConversions(input.fields);
11638
- return conversions;
11639
- }
11640
- function toModelMapFunctions(input) {
11641
- let mapFunctions;
11642
- if (input.mapFunctions != null) {
11643
- mapFunctions = input.mapFunctions;
11597
+ function getDaysOfWeekNames(sundayFirst = true, transform) {
11598
+ const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
11599
+ const sunday = 'Sunday';
11600
+ let dayOfWeekNames;
11601
+ if (sundayFirst) {
11602
+ dayOfWeekNames = [sunday, ...days];
11644
11603
  } else {
11645
- const conversions = toModelFieldConversions(input);
11646
- mapFunctions = makeModelMapFunctions(conversions);
11604
+ dayOfWeekNames = [...days, sunday];
11647
11605
  }
11648
- return mapFunctions;
11649
- }
11650
-
11651
- /**
11652
- * Field conversion that copies the same value across.
11653
- *
11654
- * @param defaultValue
11655
- * @returns
11656
- */
11657
- function copyField(defaultOutput) {
11658
- return {
11659
- from: {
11660
- default: defaultOutput,
11661
- convert: x => x
11662
- },
11663
- to: {
11664
- default: defaultOutput,
11665
- convert: x => x
11606
+ if (transform != null) {
11607
+ if (transform.abbreviation) {
11608
+ dayOfWeekNames = dayOfWeekNames.map(x => x.slice(0, 3));
11666
11609
  }
11667
- };
11610
+ if (transform.uppercase) {
11611
+ dayOfWeekNames = dayOfWeekNames.map(x => x.toUpperCase());
11612
+ }
11613
+ }
11614
+ return dayOfWeekNames;
11668
11615
  }
11669
-
11670
- function maybeMergeModelModifiers(input) {
11671
- const modifiers = asArray(input);
11672
- const allModifyData = filterMaybeValues(modifiers.map(x => x.modifyData));
11673
- const allModifyModel = filterMaybeValues(modifiers.map(x => x.modifyModel));
11674
- const modifyData = maybeMergeModifiers(allModifyData);
11675
- const modifyModel = maybeMergeModifiers(allModifyModel);
11676
- return {
11677
- modifyData,
11678
- modifyModel
11679
- };
11616
+ function daysOfWeekNameMap(transform) {
11617
+ const dayOfWeekNames = getDaysOfWeekNames(true, transform);
11618
+ return new Map(dayOfWeekNames.map((x, i) => [i, x]));
11680
11619
  }
11681
- function modifyModelMapFunctions(config) {
11682
- const {
11683
- copy,
11684
- copyModel = copy,
11685
- copyData = copy,
11686
- mapFunctions,
11687
- modifiers
11688
- } = config;
11689
- const {
11690
- from,
11691
- to
11692
- } = mapFunctions;
11693
- const {
11694
- modifyData,
11695
- modifyModel
11696
- } = maybeMergeModelModifiers(modifiers);
11697
- const modifyFrom = modifyModelMapFunction(from, modifyData, copyData);
11698
- const modifyTo = modifyModelMapFunction(to, modifyModel, copyModel);
11699
- return {
11700
- from: modifyFrom,
11701
- to: modifyTo
11620
+ function daysOfWeekNameFunction(transform) {
11621
+ const map = daysOfWeekNameMap(transform);
11622
+ return dayOfWeek => {
11623
+ var _a;
11624
+ return (_a = map.get(dayOfWeek)) !== null && _a !== void 0 ? _a : 'UNKNOWN';
11702
11625
  };
11703
11626
  }
11704
- /**
11705
- * Merges a ModifierFunction with a ModelMapFunction
11706
- *
11707
- * @param mapFn
11708
- * @param modifyModel
11709
- * @param copy
11710
- * @returns
11711
- */
11712
- function modifyModelMapFunction(mapFn, modifyModel, copy = true) {
11713
- return modifyModel ? (input, target, options) => {
11714
- const inputToMap = copy && input != null ? Object.assign({}, input) : input;
11715
- if (inputToMap != null) {
11716
- modifyModel(inputToMap);
11717
- }
11718
- return mapFn(inputToMap, target, options);
11719
- } : mapFn;
11627
+ function getDayTomorrow(day) {
11628
+ return getNextDay(day, 1);
11629
+ }
11630
+ function getDayYesterday(day) {
11631
+ return getPreviousDay(day, 1);
11632
+ }
11633
+ function getDayOffset(day, days) {
11634
+ if (days === 0) {
11635
+ return day;
11636
+ } else if (days < 0) {
11637
+ return getPreviousDay(day, days);
11638
+ } else {
11639
+ return getNextDay(day, days);
11640
+ }
11641
+ }
11642
+ function getPreviousDay(day, days = 1) {
11643
+ const offset = Math.abs(days) % 7;
11644
+ const cap = 7 - offset;
11645
+ return getNextDay(day, cap);
11646
+ }
11647
+ function getNextDay(day, days = 1) {
11648
+ let result = (day + days) % 7;
11649
+ if (result < 0) {
11650
+ result = 7 + result;
11651
+ }
11652
+ return result;
11720
11653
  }
11721
11654
 
11722
11655
  var isPrototypeOf$1 = objectIsPrototypeOf;
@@ -12680,43 +12613,6 @@ $({ target: 'Promise', stat: true, forced: FORCED_PROMISE_CONSTRUCTOR }, {
12680
12613
  }
12681
12614
  });
12682
12615
 
12683
- /**
12684
- * Creates a new ReadableStreamToStringFunction
12685
- * @param encoding
12686
- * @returns
12687
- */
12688
- function readableStreamToStringFunction(encoding) {
12689
- return stream => {
12690
- return readableStreamToBuffer(stream).then(x => x.toString(encoding));
12691
- };
12692
- }
12693
- /**
12694
- * ReadableStreamToStringFunction for Base64
12695
- */
12696
- const readableStreamToBase64 = readableStreamToStringFunction('base64');
12697
- /**
12698
- * Converts a ReadableStream to a Buffer promise.
12699
- *
12700
- * @param encoding
12701
- * @returns
12702
- */
12703
- function readableStreamToBuffer(stream) {
12704
- const chunks = [];
12705
- return new Promise((resolve, reject) => {
12706
- stream.on('data', chunk => chunks.push(Buffer.from(chunk)));
12707
- stream.on('error', err => reject(err));
12708
- stream.on('end', () => resolve(Buffer.concat(chunks)));
12709
- });
12710
- }
12711
-
12712
- function joinHostAndPort(config) {
12713
- if (config) {
12714
- return `${config.host}:${config.port}`;
12715
- } else {
12716
- return config;
12717
- }
12718
- }
12719
-
12720
12616
  function useCallback(use) {
12721
12617
  return __awaiter(this, void 0, void 0, function* () {
12722
12618
  return new Promise((resolve, reject) => {
@@ -13179,1198 +13075,1399 @@ function usePromise(input) {
13179
13075
  return useFn => _getter().then(useFn);
13180
13076
  }
13181
13077
 
13182
- exports.RelationChange = void 0;
13183
- (function (RelationChange) {
13184
- /**
13185
- * Adds a model to the relation. If the model already exists in
13186
- * the relation, the new one is used.
13187
- *
13188
- * Use INSERT to merge the two values together.
13189
- */
13190
- RelationChange["ADD"] = "add";
13191
- /**
13192
- * Sets the relation to be equal to the input.
13193
- */
13194
- RelationChange["SET"] = "set";
13195
- /**
13196
- * Variation of SET that performs REMOVE on the collection, and then follows it up with INSERT.
13197
- *
13198
- * This can allow the modification function to behave selectively with the items targeted for removal.
13199
- */
13200
- RelationChange["REMOVE_AND_INSERT"] = "remove_and_insert";
13201
- /**
13202
- * Removes a model from the relation.
13203
- */
13204
- RelationChange["REMOVE"] = "remove";
13205
- /**
13206
- * Updates an existing relation, if it exists.
13207
- * The existing object is merged with the update object.
13208
- */
13209
- RelationChange["UPDATE"] = "update";
13210
- /**
13211
- * Updates an existing relation, if it exists, or creates a new one.
13212
- */
13213
- RelationChange["INSERT"] = "insert";
13214
- })(exports.RelationChange || (exports.RelationChange = {}));
13215
- /**
13216
- * Utility class for modifying a collection of relational objects.
13217
- *
13218
- * For instance, a string collection of keys.
13219
- */
13220
- class ModelRelationUtility {
13221
- static modifyStringCollection(current, change, mods) {
13222
- return ModelRelationUtility.modifyCollection(current, change, mods, {
13223
- readKey: x => x,
13224
- merge: (a, b) => b
13225
- });
13078
+ function timePeriodCounter(timePeriodLength, lastTimePeriodStart) {
13079
+ function reset(inputStart) {
13080
+ const start = inputStart !== null && inputStart !== void 0 ? inputStart : new Date();
13081
+ fn._timePeriodCount = 0;
13082
+ fn._lastTimePeriodStart = start;
13083
+ fn._nextTimePeriodEnd = new Date(start.getTime() + timePeriodLength);
13084
+ return fn._nextTimePeriodEnd;
13226
13085
  }
13227
- static modifyCollection(current, change, mods, config) {
13228
- const {
13229
- mask,
13230
- readKey
13231
- } = config;
13232
- current = current !== null && current !== void 0 ? current : []; //init current if not set.
13233
- if (mask) {
13234
- const {
13235
- included: currentModify,
13236
- excluded: currentRetain
13237
- } = separateValues(current, mask);
13238
- const {
13239
- included: modModify
13240
- } = separateValues(mods, mask);
13241
- const modifiedResults = this._modifyCollectionWithoutMask(currentModify, change, modModify, config);
13242
- return this._mergeMaskResults(current, currentRetain, modifiedResults, readKey);
13086
+ const fn = () => {
13087
+ const now = new Date();
13088
+ if (now > fn._nextTimePeriodEnd) {
13089
+ reset(now);
13243
13090
  } else {
13244
- return this._modifyCollectionWithoutMask(current, change, mods, config);
13091
+ fn._timePeriodCount += 1;
13245
13092
  }
13093
+ return fn._timePeriodCount;
13094
+ };
13095
+ fn._timePeriodLength = timePeriodLength;
13096
+ reset(lastTimePeriodStart);
13097
+ fn._timePeriodCount = -1;
13098
+ fn._reset = reset;
13099
+ return fn;
13100
+ }
13101
+ class TimerCancelledError extends makeError.BaseError {
13102
+ constructor() {
13103
+ super(`The timer was destroyed before it was completed.`);
13246
13104
  }
13247
- /**
13248
- * The mask results are merged together.
13249
- *
13250
- * Order from the "current" is retained. Anything in currentRetain overrides modifiedResults.
13251
- */
13252
- static _mergeMaskResults(current, currentRetain, modifiedResults, readKey) {
13253
- return restoreOrderWithValues(current, [...currentRetain, ...modifiedResults], {
13254
- readKey
13255
- });
13256
- }
13257
- static _modifyCollectionWithoutMask(current, change, mods, config) {
13258
- const {
13259
- readKey,
13260
- merge,
13261
- shouldRemove
13262
- } = config;
13263
- const readType = config.readType;
13264
- function remove(rCurrent = current, rMods = mods) {
13265
- return ModelRelationUtility._modifyCollection(rCurrent, rMods, (x, y) => {
13266
- return ModelRelationUtility.removeFromCollection(x, y, readKey, shouldRemove);
13267
- }, readType);
13268
- }
13269
- function performAdd() {
13270
- return ModelRelationUtility._modifyCollection(current, mods, (x, y) => ModelRelationUtility.addToCollection(x, y, readKey), readType);
13271
- }
13272
- function performInsert() {
13273
- return ModelRelationUtility.insertCollection(current, mods, {
13274
- readKey,
13275
- readType,
13276
- merge
13277
- });
13278
- }
13279
- switch (change) {
13280
- case exports.RelationChange.SET:
13281
- current = []; // Set current before performing add.
13282
- return performAdd();
13283
- case exports.RelationChange.ADD:
13284
- return performAdd();
13285
- case exports.RelationChange.REMOVE:
13286
- return remove();
13287
- case exports.RelationChange.UPDATE:
13288
- return ModelRelationUtility.updateCollection(current, mods, {
13289
- readKey,
13290
- readType,
13291
- merge
13292
- });
13293
- case exports.RelationChange.REMOVE_AND_INSERT:
13294
- current = remove(current, current); // Remove all current values before performing an insert.
13295
- return performInsert();
13296
- case exports.RelationChange.INSERT:
13297
- return performInsert();
13105
+ }
13106
+ class TimerInstance {
13107
+ constructor(duration, startImmediately = true) {
13108
+ this._createdAt = new Date();
13109
+ this._startedAt = new Date();
13110
+ this._state = 'paused';
13111
+ this._promiseRef = promiseReference();
13112
+ this._duration = duration;
13113
+ if (startImmediately) {
13114
+ this.start();
13115
+ this._startedAt = this._createdAt;
13298
13116
  }
13299
13117
  }
13300
- static updateCollection(current, update, {
13301
- readKey,
13302
- readType,
13303
- merge
13304
- }) {
13305
- ModelRelationUtility._assertMergeProvided(merge);
13306
- return ModelRelationUtility._modifyCollection(current, update, (x, y) => ModelRelationUtility._updateSingleTypeCollection(x, y, {
13307
- readKey,
13308
- merge
13309
- }), readType);
13118
+ get state() {
13119
+ return this._state;
13310
13120
  }
13311
- static insertCollection(current, update, {
13312
- readKey,
13313
- readType,
13314
- merge
13315
- }) {
13316
- ModelRelationUtility._assertMergeProvided(merge);
13317
- return ModelRelationUtility._modifyCollection(current, update, (x, y) => ModelRelationUtility._insertSingleTypeCollection(x, y, {
13318
- readKey,
13319
- merge
13320
- }), readType);
13121
+ get createdAt() {
13122
+ return this._createdAt;
13321
13123
  }
13322
- /**
13323
- * Used to modify a collection which may be multi-type. If readType is provided, the collection is handled as a multi-type map.
13324
- */
13325
- static _modifyCollection(current, mods, modifyCollection, readType) {
13326
- if (readType) {
13327
- return ModelRelationUtility._modifyMultiTypeCollection(current, mods, readType, modifyCollection);
13328
- } else {
13329
- return modifyCollection(current, mods);
13330
- }
13124
+ get pausedAt() {
13125
+ return this._pausedAt;
13331
13126
  }
13332
- static _modifyMultiTypeCollection(input, mods, readType, modifyCollection) {
13333
- const inputMap = makeValuesGroupMap(input, readType);
13334
- const modsMap = makeValuesGroupMap(mods, readType);
13335
- const typesModified = new Set([...inputMap.keys(), ...modsMap.keys()]);
13336
- // Break the collections up into their individual types and process separately.
13337
- const modifiedSubcollections = Array.from(typesModified).map(type => {
13338
- var _a, _b;
13339
- const values = (_a = inputMap.get(type)) !== null && _a !== void 0 ? _a : [];
13340
- const mods = (_b = modsMap.get(type)) !== null && _b !== void 0 ? _b : [];
13341
- // Only modify if they've got changes for their type.
13342
- if (mods.length === 0) {
13343
- return values; // No mods, no change to those types.
13344
- } else {
13345
- return modifyCollection(values, mods);
13346
- }
13347
- });
13348
- // Rejoin all changes.
13349
- return modifiedSubcollections.reduce((x, y) => x.concat(y), []);
13127
+ get startedAt() {
13128
+ return this._startedAt;
13350
13129
  }
13351
- static _insertSingleTypeCollection(current, insert, {
13352
- readKey,
13353
- merge
13354
- }) {
13355
- const currentKeys = arrayToMap(current, readKey);
13356
- const updateValues = [];
13357
- const addValues = [];
13358
- insert.forEach(value => {
13359
- const key = readKey(value);
13360
- if (currentKeys.has(key)) {
13361
- updateValues.push(value);
13362
- } else {
13363
- addValues.push(value);
13364
- }
13365
- });
13366
- const added = ModelRelationUtility.addToCollection(current, addValues, readKey);
13367
- const results = ModelRelationUtility._updateSingleTypeCollection(added, updateValues, {
13368
- readKey,
13369
- merge
13370
- });
13371
- return results;
13130
+ get promise() {
13131
+ return this._promiseRef.promise;
13372
13132
  }
13373
- static _updateSingleTypeCollection(current, update, {
13374
- readKey,
13375
- merge
13376
- }) {
13377
- const keysToUpdate = arrayToMap(update, readKey);
13378
- const updateValues = [];
13379
- current.forEach(value => {
13380
- const key = readKey(value);
13381
- const mergeWith = keysToUpdate.get(key);
13382
- if (mergeWith != null) {
13383
- updateValues.push(merge(value, mergeWith));
13384
- }
13385
- });
13386
- // Add to merge all values and remove duplicates.
13387
- return ModelRelationUtility.addToCollection(current, updateValues, readKey);
13133
+ get duration() {
13134
+ return this._duration;
13388
13135
  }
13389
- static addToCollection(current, add, readKey) {
13390
- current = current !== null && current !== void 0 ? current : [];
13391
- return (add === null || add === void 0 ? void 0 : add.length) ? ModelRelationUtility.removeDuplicates([...add, ...current], readKey) : current; // Will keep any "added" before any existing ones.
13136
+ get durationRemaining() {
13137
+ let remaining;
13138
+ switch (this._state) {
13139
+ case 'complete':
13140
+ remaining = 0;
13141
+ break;
13142
+ case 'running':
13143
+ remaining = Math.max(0, this._duration - (new Date().getTime() - this._startedAt.getTime()));
13144
+ break;
13145
+ case 'paused':
13146
+ remaining = null;
13147
+ break;
13148
+ }
13149
+ return remaining;
13392
13150
  }
13393
-
13394
- static removeFromCollection(current, remove, readKey, shouldRemove) {
13395
- if (current === null || current === void 0 ? void 0 : current.length) {
13396
- if (shouldRemove) {
13397
- const currentKeyPairs = makeKeyPairs(current, readKey);
13398
- const map = new Map(currentKeyPairs);
13399
- remove.forEach(x => {
13400
- const key = readKey(x);
13401
- const removalTarget = map.get(key);
13402
- if (removalTarget && shouldRemove(removalTarget)) {
13403
- map.delete(key); // Remove from the map.
13404
- }
13405
- });
13406
-
13407
- return currentKeyPairs.filter(x => map.has(x[0])).map(x => x[1]); // Retain order, remove from map.
13408
- } else {
13409
- return ModelRelationUtility.removeKeysFromCollection(current, remove.map(readKey), readKey);
13410
- }
13411
- } else {
13412
- return [];
13151
+ start() {
13152
+ if (this._state === 'paused') {
13153
+ this._state = 'running';
13154
+ this._startedAt = new Date();
13155
+ this._enqueueCheck();
13413
13156
  }
13414
13157
  }
13415
- static removeKeysFromCollection(current, keysToRemove, readKey) {
13416
- return ModelRelationUtility.removeDuplicates(current, readKey, keysToRemove);
13158
+ stop() {
13159
+ if (this._state === 'running') {
13160
+ this._state = 'paused';
13161
+ this._pausedAt = new Date();
13162
+ }
13417
13163
  }
13418
- static removeDuplicates(relations, readKey, additionalKeys = []) {
13419
- return (relations === null || relations === void 0 ? void 0 : relations.length) ? filterUniqueValues(relations, readKey, additionalKeys) : [];
13164
+ reset() {
13165
+ if (this._state !== 'complete') {
13166
+ this._state = 'running';
13167
+ this._startedAt = new Date();
13168
+ this._enqueueCheck();
13169
+ }
13420
13170
  }
13421
- // MARK: Internal Utility
13422
- static _assertMergeProvided(merge) {
13423
- if (!merge) {
13424
- throw new Error('Merge was not provided.');
13171
+ setDuration(duration) {
13172
+ this._duration = duration;
13173
+ }
13174
+ destroy() {
13175
+ this._checkComplete();
13176
+ if (this._state === 'running') {
13177
+ const error = new TimerCancelledError();
13178
+ this._promiseRef.reject(error);
13179
+ this._state = 'complete'; // mark as complete
13425
13180
  }
13426
13181
  }
13427
- }
13428
13182
 
13183
+ _checkComplete() {
13184
+ if (this._state !== 'complete' && this.durationRemaining === 0) {
13185
+ this._state = 'complete';
13186
+ this._promiseRef.resolve();
13187
+ }
13188
+ }
13189
+ _enqueueCheck() {
13190
+ const durationRemaining = this.durationRemaining;
13191
+ if (durationRemaining != null && this._state !== 'complete') {
13192
+ setTimeout(() => {
13193
+ this._checkComplete();
13194
+ this._enqueueCheck();
13195
+ }, durationRemaining);
13196
+ }
13197
+ }
13198
+ }
13199
+ function timer(duration, startNow = true) {
13200
+ return new TimerInstance(duration, startNow);
13201
+ }
13429
13202
  /**
13430
- * Key used to signify
13203
+ * Toggles the input Timer's running state.
13204
+ *
13205
+ * @param timer
13206
+ * @param toggleRun
13431
13207
  */
13432
- const CATCH_ALL_HANDLE_RESULT_KEY = '__CATCH_ALL_HANDLE_RESULT_KEY__';
13433
- function handlerFactory(readKey) {
13434
- return () => {
13435
- let catchAll;
13436
- const map = new Map();
13437
- const set = (key, handle) => {
13438
- if (key === CATCH_ALL_HANDLE_RESULT_KEY) {
13439
- catchAll = handle;
13440
- } else {
13441
- setKeysOnMap(map, key, handle);
13208
+ function toggleTimerRunning(timer, toggleRun) {
13209
+ toggleRun = toggleRun != null ? toggleRun : timer.state !== 'running';
13210
+ if (toggleRun) {
13211
+ timer.start();
13212
+ } else {
13213
+ timer.stop();
13214
+ }
13215
+ }
13216
+ /**
13217
+ * Returns the approximate end date of the given timer. If a timer is already complete, it returns the time for now.
13218
+ */
13219
+ function approximateTimerEndDate(timer) {
13220
+ const durationRemaining = timer.durationRemaining;
13221
+ if (durationRemaining != null) {
13222
+ return new Date(Date.now() + durationRemaining);
13223
+ } else {
13224
+ return null;
13225
+ }
13226
+ }
13227
+
13228
+ exports.TimeAM = void 0;
13229
+ (function (TimeAM) {
13230
+ TimeAM["AM"] = "AM";
13231
+ TimeAM["PM"] = "PM";
13232
+ })(exports.TimeAM || (exports.TimeAM = {}));
13233
+ const DATE_NOW_VALUE = 'now';
13234
+ function dateFromLogicalDate(logicalDate) {
13235
+ let result;
13236
+ if (typeof logicalDate === 'string') {
13237
+ switch (logicalDate.toLocaleLowerCase()) {
13238
+ case DATE_NOW_VALUE:
13239
+ result = new Date();
13240
+ break;
13241
+ default:
13242
+ throw new Error(`Unknown logical date string "${logicalDate}"`);
13243
+ }
13244
+ } else {
13245
+ result = logicalDate;
13246
+ }
13247
+ return result;
13248
+ }
13249
+ function isLogicalDateStringCode(logicalDate) {
13250
+ let isLogicalDateStringCode = false;
13251
+ if (typeof logicalDate === 'string') {
13252
+ switch (logicalDate.toLocaleLowerCase()) {
13253
+ case DATE_NOW_VALUE:
13254
+ isLogicalDateStringCode = true;
13255
+ break;
13256
+ }
13257
+ }
13258
+ return isLogicalDateStringCode;
13259
+ }
13260
+
13261
+ /**
13262
+ * Performs a deep comparison to check if all values on the input filters are equal.
13263
+ *
13264
+ * Recursively compares Arrays, Objects, Maps, Sets, Primatives, and Dates.
13265
+ */
13266
+ function areEqualPOJOValues(a, b) {
13267
+ // check self
13268
+ if (a === b) {
13269
+ return true;
13270
+ }
13271
+ // check one value is nullish and other is not
13272
+ if ((a == null || b == null) && (a || b)) {
13273
+ return false;
13274
+ }
13275
+ // object check
13276
+ if (typeof a === 'object') {
13277
+ // check if they are arrays
13278
+ if (isIterable(a, false)) {
13279
+ if (Array.isArray(a)) {
13280
+ if (a.length !== b.length) {
13281
+ return false;
13282
+ }
13283
+ const firstInequalityIndex = a.findIndex((aValue, i) => {
13284
+ const bValue = b[i];
13285
+ return !areEqualPOJOValues(aValue, bValue);
13286
+ });
13287
+ return firstInequalityIndex === -1;
13288
+ } else if (a instanceof Set) {
13289
+ return setsAreEquivalent(a, b);
13290
+ } else if (a instanceof Map) {
13291
+ const bMap = b;
13292
+ if (a.size !== bMap.size) {
13293
+ return false;
13294
+ }
13295
+ const firstInequalityIndex = Array.from(a.entries()).findIndex(([key, aValue]) => {
13296
+ const bValue = bMap.get(key);
13297
+ return !areEqualPOJOValues(aValue, bValue);
13298
+ });
13299
+ return firstInequalityIndex === -1;
13442
13300
  }
13443
- };
13444
- const bindSet = (bindTo, key, handle) => {
13445
- const bindHandle = handle.bind(bindTo);
13446
- set(key, bindHandle);
13447
- };
13448
- const fn = build({
13449
- base: value => {
13450
- var _a;
13451
- const key = readKey(value);
13452
- const handler = (_a = key != null ? map.get(key) : undefined) !== null && _a !== void 0 ? _a : catchAll;
13453
- let handled = false;
13454
- if (handler) {
13455
- handled = handler(value);
13301
+ } else if (typeof b === 'object') {
13302
+ // check contructors/types
13303
+ const firstType = a === null || a === void 0 ? void 0 : a.constructor.name;
13304
+ const secondType = b === null || b === void 0 ? void 0 : b.constructor.name;
13305
+ if (firstType !== secondType) {
13306
+ return false; // false if not the same type
13307
+ }
13308
+ // check Date comparison
13309
+ if (isDate(a)) {
13310
+ return isEqualDate(a, b);
13311
+ }
13312
+ // check object comparison via keys
13313
+ const aObject = a;
13314
+ const bObject = b;
13315
+ const aKeys = Object.keys(aObject);
13316
+ const bKeys = Object.keys(bObject);
13317
+ // compare keys
13318
+ if (aKeys.length === bKeys.length) {
13319
+ const firstInequalityIndex = aKeys.findIndex(key => {
13320
+ const aKeyValue = aObject[key];
13321
+ const bKeyValue = bObject[key];
13322
+ return !areEqualPOJOValues(aKeyValue, bKeyValue);
13323
+ });
13324
+ if (firstInequalityIndex === -1) {
13325
+ return true; // is equal if no non-matching key/value pair is found
13456
13326
  }
13457
- return handled;
13458
- },
13459
- build: x => {
13460
- x.readKey = readKey;
13461
- x.set = set;
13462
- x.bindSet = bindSet;
13463
13327
  }
13328
+ }
13329
+ }
13330
+ // still not equal if down here
13331
+ return false;
13332
+ }
13333
+ function objectFieldEqualityChecker(config) {
13334
+ const {
13335
+ fields,
13336
+ defaultEqualityFunction = (a, b) => a === b
13337
+ } = config;
13338
+ const _fields = new Map();
13339
+ fields.forEach(input => {
13340
+ let field;
13341
+ if (typeof input === 'object') {
13342
+ field = input;
13343
+ } else {
13344
+ field = {
13345
+ fieldName: input,
13346
+ isEqual: defaultEqualityFunction
13347
+ };
13348
+ }
13349
+ _fields.set(field.fieldName, field);
13350
+ });
13351
+ const fn = (a, b) => {
13352
+ const equalFields = [];
13353
+ const unequalFields = [];
13354
+ _fields.forEach((fieldConfig, fieldName) => {
13355
+ const {
13356
+ isEqual
13357
+ } = fieldConfig;
13358
+ isEqual(a[fieldName], b[fieldName]) ? equalFields.push(fieldName) : unequalFields.push(fieldName);
13464
13359
  });
13465
- return fn;
13360
+ return {
13361
+ a,
13362
+ b,
13363
+ isEqual: unequalFields.length === 0,
13364
+ equalFields,
13365
+ unequalFields
13366
+ };
13466
13367
  };
13467
- }
13468
- function makeHandler(readKey) {
13469
- return handlerFactory(readKey)();
13470
- }
13471
- function catchAllHandlerKey() {
13472
- return CATCH_ALL_HANDLE_RESULT_KEY;
13368
+ fn._fields = _fields;
13369
+ return fn;
13473
13370
  }
13474
13371
 
13475
13372
  /**
13476
- * Creates a HandlerBindAccessor<T, K> for the input values.
13373
+ * Creates a EqualityComparatorFunction that compares the two input values
13477
13374
  *
13478
- * @param bindTo
13479
- * @param accessor
13375
+ * @param readKey
13480
13376
  * @returns
13481
13377
  */
13482
- function handlerBindAccessor(boundTo, accessor) {
13483
- return {
13484
- accessor,
13485
- boundTo,
13486
- set: (key, handle) => {
13487
- accessor.bindSet(boundTo, key, handle);
13378
+ function objectKeysEqualityComparatorFunction(readKey) {
13379
+ const readKeysSet = readKeysSetFunction(readKey);
13380
+ const readKeysArray = readKeysFunction(readKey);
13381
+ return safeEqualityComparatorFunction((a, b) => {
13382
+ if (a.length === b.length) {
13383
+ if (a.length === 0) {
13384
+ return true; // both the same/empty arrays
13385
+ }
13386
+
13387
+ const aKeys = readKeysSet(a);
13388
+ const bKeys = readKeysArray(b);
13389
+ if (aKeys.size === bKeys.length) {
13390
+ return setContainsAllValues(aKeys, bKeys);
13391
+ }
13488
13392
  }
13489
- };
13393
+ return false;
13394
+ });
13490
13395
  }
13491
13396
  /**
13492
- * Creates a HandlerSetFunction.
13397
+ * Creates a EqualityComparatorFunction that compares the two input values
13493
13398
  *
13494
- * @param accessor
13495
- * @param key
13399
+ * @param readKey
13496
13400
  * @returns
13497
13401
  */
13498
- function handlerSetFunction(accessor, key) {
13499
- const fn = handlerFunction => {
13500
- accessor.set(key, handlerFunction); // set the handler on the pre-defined key.
13402
+ function objectKeyEqualityComparatorFunction(readKey) {
13403
+ return safeEqualityComparatorFunction((a, b) => readKey(a) === readKey(b));
13404
+ }
13405
+
13406
+ function makeCopyModelFieldFunction(key, inputConfig) {
13407
+ const config = inputConfig !== null && inputConfig !== void 0 ? inputConfig : {};
13408
+ const hasDefault = objectHasKey(config, 'default');
13409
+ const defaultValue = config.default;
13410
+ return (from, target) => {
13411
+ var _a;
13412
+ if (objectHasKey(from, key)) {
13413
+ target[key] = (_a = from[key]) !== null && _a !== void 0 ? _a : defaultValue;
13414
+ } else if (hasDefault) {
13415
+ target[key] = defaultValue;
13416
+ }
13501
13417
  };
13418
+ }
13502
13419
 
13503
- fn.key = key;
13504
- return fn;
13420
+ function makeModelMapFunctions(fields) {
13421
+ const keys = filterKeyValueTuples(fields);
13422
+ const conversionsByKey = keys.map(([key, field]) => [key, field]);
13423
+ const fromConversions = conversionsByKey.map(([key, configs]) => [key, configs.from]);
13424
+ const toConversions = conversionsByKey.map(([key, configs]) => [key, configs.to]);
13425
+ const from = makeModelConversionFieldValuesFunction(fromConversions);
13426
+ const to = makeModelConversionFieldValuesFunction(toConversions);
13427
+ return {
13428
+ from,
13429
+ to
13430
+ };
13505
13431
  }
13506
- function handlerMappedSetFunction(accessor, key, mapFn) {
13507
- const handlerSet = handlerSetFunction(accessor, key);
13508
- return handlerFunction => {
13509
- // set an intermediary function that calls the target function. We don't use an arrow function so we have access to the "this", if bound.
13510
- handlerSet(function (value) {
13511
- const mapped = mapFn(value); // fowards "this" to the next call.
13512
- return handlerFunction.call(this, mapped);
13513
- });
13432
+ function makeModelConversionFieldValuesFunction(fields) {
13433
+ return (input, inputTarget, options) => {
13434
+ const target = inputTarget !== null && inputTarget !== void 0 ? inputTarget : {};
13435
+ if (input != null) {
13436
+ let targetFields = fields;
13437
+ // if options are provided, filter down.
13438
+ if (options) {
13439
+ const fieldsToMap = new Set(findPOJOKeys(input, {
13440
+ keysFilter: options.fields,
13441
+ valueFilter: options.definedOnly === false ? exports.KeyValueTypleValueFilter.NONE : exports.KeyValueTypleValueFilter.UNDEFINED
13442
+ }));
13443
+ targetFields = fields.filter(x => fieldsToMap.has(x[0]));
13444
+ }
13445
+ targetFields.forEach(([key, convert]) => target[key] = convert(input[key]));
13446
+ }
13447
+ return target;
13514
13448
  };
13515
13449
  }
13516
- function handlerMappedSetFunctionFactory(accessor, mapFn) {
13517
- return key => handlerMappedSetFunction(accessor, key, mapFn);
13450
+ function modelFieldConversions(config) {
13451
+ return mapObjectMap(config, x => modelFieldMapFunctions(x));
13518
13452
  }
13519
- function handlerConfigurerFactory(config) {
13520
- return handler => {
13521
- return (bindTo, configure) => {
13522
- const accessor = handlerBindAccessor(bindTo, handler);
13523
- const configurer = config.configurerForAccessor(accessor);
13524
- configure(configurer);
13525
- };
13453
+ function modelFieldMapFunctions(config) {
13454
+ return {
13455
+ from: modelFieldMapFunction(config.from),
13456
+ to: modelFieldMapFunction(config.to)
13526
13457
  };
13527
13458
  }
13528
-
13529
13459
  /**
13530
- * TypedServiceRegistry implementation.
13460
+ * Creates a ModelFieldMapFunction.
13461
+ *
13462
+ * @param config
13463
+ * @returns
13531
13464
  */
13532
- class TypedServiceRegistryInstance {
13533
- constructor() {
13534
- this._map = new Map();
13535
- }
13536
- registerServiceForType(type, service) {
13537
- const getter = asGetter(service);
13538
- this._map.set(type, getter);
13539
- }
13540
- serviceForType(type) {
13541
- const getter = this._map.get(type);
13542
- const service = getter === null || getter === void 0 ? void 0 : getter();
13543
- if (service == null) {
13544
- throw new Error(`no service registered for type "${type}"`);
13465
+ function modelFieldMapFunction(config) {
13466
+ const convert = config.convert;
13467
+ const convertMaybe = config.convertMaybe;
13468
+ const defaultOutput = config.default;
13469
+ const defaultInput = config.defaultInput;
13470
+ const hasDefaultInput = defaultInput != null;
13471
+ const getDefaultOutput = asGetter(defaultOutput);
13472
+ const getDefaultInput = asGetter(defaultInput);
13473
+ return input => {
13474
+ let result;
13475
+ if (isMaybeSo(input)) {
13476
+ result = convert(input);
13477
+ } else {
13478
+ if (convertMaybe) {
13479
+ result = convertMaybe(input !== null && input !== void 0 ? input : getDefaultInput());
13480
+ } else if (hasDefaultInput) {
13481
+ result = convert(getDefaultInput());
13482
+ } else {
13483
+ result = getDefaultOutput();
13484
+ }
13545
13485
  }
13546
- return service;
13547
- }
13486
+ return result;
13487
+ };
13548
13488
  }
13549
13489
  /**
13550
- * Creates a new TypedServiceRegistryInstance and registers the input types.
13490
+ * Converts the input to a ModelFieldConversions value.
13491
+ *
13492
+ * @param input
13551
13493
  * @returns
13552
13494
  */
13553
- function typedServiceRegistry(config) {
13554
- const instance = new TypedServiceRegistryInstance();
13555
- forEachKeyValue(config.services, {
13556
- forEach: ([key, service]) => {
13557
- instance.registerServiceForType(key, service);
13558
- }
13559
- });
13560
- return instance;
13561
- }
13562
-
13563
- class StoredDataError extends makeError.BaseError {
13564
- constructor(message) {
13565
- super(message);
13566
- }
13567
- }
13568
- class DataDoesNotExistError extends StoredDataError {
13569
- constructor(message) {
13570
- super(message);
13571
- }
13572
- }
13573
- class DataIsExpiredError extends StoredDataError {
13574
- constructor(data, message) {
13575
- super(message);
13576
- this.data = data;
13577
- }
13495
+ function toModelFieldConversions(input) {
13496
+ var _a;
13497
+ const conversions = (_a = input.fieldConversions) !== null && _a !== void 0 ? _a : modelFieldConversions(input.fields);
13498
+ return conversions;
13578
13499
  }
13579
-
13580
- class MemoryStorageInstance {
13581
- constructor() {
13582
- this._length = 0;
13583
- this._storage = {};
13584
- }
13585
- get length() {
13586
- return this._length;
13587
- }
13588
- key(index) {
13589
- var _a;
13590
- return (_a = Object.keys(this._storage)[index]) !== null && _a !== void 0 ? _a : null;
13591
- }
13592
- hasKey(key) {
13593
- return objectHasKey(this._storage, key);
13594
- }
13595
- getItem(key) {
13596
- var _a;
13597
- return (_a = this._storage[key]) !== null && _a !== void 0 ? _a : null;
13598
- }
13599
- setItem(key, item) {
13600
- if (item == null) {
13601
- this.removeItem(key);
13602
- } else {
13603
- if (!this.hasKey(key)) {
13604
- this._length = this._length + 1;
13605
- }
13606
- this._storage[key] = String(item);
13607
- }
13608
- }
13609
- removeItem(key) {
13610
- if (this.hasKey(key)) {
13611
- delete this._storage[key]; // Remove the property
13612
- this._length = this._length - 1;
13613
- }
13614
- }
13615
- clear() {
13616
- this._storage = {};
13617
- this._length = 0;
13500
+ function toModelMapFunctions(input) {
13501
+ let mapFunctions;
13502
+ if (input.mapFunctions != null) {
13503
+ mapFunctions = input.mapFunctions;
13504
+ } else {
13505
+ const conversions = toModelFieldConversions(input);
13506
+ mapFunctions = makeModelMapFunctions(conversions);
13618
13507
  }
13508
+ return mapFunctions;
13619
13509
  }
13620
- const SHARED_MEMORY_STORAGE = new MemoryStorageInstance();
13621
13510
 
13622
13511
  /**
13623
- * Limited Class/Interface for storing string values synchronously.
13624
- */
13625
- class SimpleStorageObject {}
13626
- /**
13627
- * Synchronous Class/Interface for storing string values.
13512
+ * Field conversion that copies the same value across.
13628
13513
  *
13629
- * Has the same interface as localStorage for the web.
13514
+ * @param defaultValue
13515
+ * @returns
13630
13516
  */
13631
- class StorageObject extends SimpleStorageObject {}
13632
- class FullStorageObject extends StorageObject {}
13633
- class StorageObjectUtility {
13634
- static allKeysFromStorageObject(storageObject, prefix) {
13635
- const length = storageObject.length;
13636
- let result;
13637
- if (length > 0) {
13638
- result = range({
13639
- start: 0,
13640
- end: length
13641
- }).map(x => storageObject.key(x)).filter(hasNonNullValue);
13642
- if (prefix) {
13643
- result = result.filter(x => x.startsWith(prefix));
13644
- }
13645
- } else {
13646
- result = [];
13517
+ function copyField(defaultOutput) {
13518
+ return {
13519
+ from: {
13520
+ default: defaultOutput,
13521
+ convert: x => x
13522
+ },
13523
+ to: {
13524
+ default: defaultOutput,
13525
+ convert: x => x
13647
13526
  }
13648
- return result;
13649
- }
13527
+ };
13650
13528
  }
13651
13529
 
13652
- /**
13653
- * Joins together various array of classes and only keeps the unique values.
13654
- *
13655
- * @param cssClasses
13656
- * @returns
13657
- */
13658
- function spaceSeparatedCssClasses(cssClasses) {
13659
- let result = '';
13660
- if (cssClasses) {
13661
- const allClasses = cssClassesSet(cssClasses);
13662
- result = joinStringsWithSpaces(Array.from(allClasses));
13663
- }
13664
- return result;
13530
+ function maybeMergeModelModifiers(input) {
13531
+ const modifiers = asArray(input);
13532
+ const allModifyData = filterMaybeValues(modifiers.map(x => x.modifyData));
13533
+ const allModifyModel = filterMaybeValues(modifiers.map(x => x.modifyModel));
13534
+ const modifyData = maybeMergeModifiers(allModifyData);
13535
+ const modifyModel = maybeMergeModifiers(allModifyModel);
13536
+ return {
13537
+ modifyData,
13538
+ modifyModel
13539
+ };
13540
+ }
13541
+ function modifyModelMapFunctions(config) {
13542
+ const {
13543
+ copy,
13544
+ copyModel = copy,
13545
+ copyData = copy,
13546
+ mapFunctions,
13547
+ modifiers
13548
+ } = config;
13549
+ const {
13550
+ from,
13551
+ to
13552
+ } = mapFunctions;
13553
+ const {
13554
+ modifyData,
13555
+ modifyModel
13556
+ } = maybeMergeModelModifiers(modifiers);
13557
+ const modifyFrom = modifyModelMapFunction(from, modifyData, copyData);
13558
+ const modifyTo = modifyModelMapFunction(to, modifyModel, copyModel);
13559
+ return {
13560
+ from: modifyFrom,
13561
+ to: modifyTo
13562
+ };
13665
13563
  }
13666
13564
  /**
13667
- * Joins together various array of classes and returns the set of unique CSS classes.
13565
+ * Merges a ModifierFunction with a ModelMapFunction
13668
13566
  *
13669
- * @param cssClasses
13567
+ * @param mapFn
13568
+ * @param modifyModel
13569
+ * @param copy
13670
13570
  * @returns
13671
13571
  */
13672
- function cssClassesSet(cssClasses) {
13673
- let result;
13674
- if (cssClasses) {
13675
- const arrayOfClasses = iterableToArray(cssClasses, false);
13676
- const arrayOfAllClassValues = arrayOfClasses.map(x => asArray(x).map(x => x.split(' ')).flat()).flat();
13677
- result = new Set(arrayOfAllClassValues);
13678
- } else {
13679
- result = new Set();
13680
- }
13681
- return result;
13572
+ function modifyModelMapFunction(mapFn, modifyModel, copy = true) {
13573
+ return modifyModel ? (input, target, options) => {
13574
+ const inputToMap = copy && input != null ? Object.assign({}, input) : input;
13575
+ if (inputToMap != null) {
13576
+ modifyModel(inputToMap);
13577
+ }
13578
+ return mapFn(inputToMap, target, options);
13579
+ } : mapFn;
13682
13580
  }
13683
13581
 
13684
13582
  /**
13685
- * Creates a SortByStringFunction that sorts values in ascending order.
13583
+ * Creates a new ReadableStreamToStringFunction
13584
+ * @param encoding
13585
+ * @returns
13686
13586
  */
13687
- function sortByStringFunction(readStringFn) {
13688
- return (a, b) => {
13689
- const as = readStringFn(a);
13690
- const bs = readStringFn(b);
13691
- return as.localeCompare(bs);
13587
+ function readableStreamToStringFunction(encoding) {
13588
+ return stream => {
13589
+ return readableStreamToBuffer(stream).then(x => x.toString(encoding));
13692
13590
  };
13693
13591
  }
13694
- const sortByLabelFunction = sortByStringFunction(x => x.label);
13695
-
13696
13592
  /**
13697
- * Creates a SearchStringFilterFunction
13593
+ * ReadableStreamToStringFunction for Base64
13594
+ */
13595
+ const readableStreamToBase64 = readableStreamToStringFunction('base64');
13596
+ /**
13597
+ * Converts a ReadableStream to a Buffer promise.
13698
13598
  *
13699
- * @param config
13599
+ * @param encoding
13700
13600
  * @returns
13701
13601
  */
13702
- function searchStringFilterFunction(config) {
13703
- const {
13704
- readStrings,
13705
- decisionFactory = caseInsensitiveFilterByIndexOfDecisionFactory
13706
- } = typeof config === 'function' ? {
13707
- readStrings: config
13708
- } : config;
13709
- return (filterText, values) => {
13710
- const decision = decisionFactory(filterText);
13711
- return values.filter(value => {
13712
- const searchResult = readStrings(value);
13713
- let match = false;
13714
- if (Array.isArray(searchResult)) {
13715
- match = searchResult.findIndex(decision) !== -1;
13716
- } else if (searchResult != null) {
13717
- match = decision(searchResult);
13718
- }
13719
- return match;
13720
- });
13721
- };
13602
+ function readableStreamToBuffer(stream) {
13603
+ const chunks = [];
13604
+ return new Promise((resolve, reject) => {
13605
+ stream.on('data', chunk => chunks.push(Buffer.from(chunk)));
13606
+ stream.on('error', err => reject(err));
13607
+ stream.on('end', () => resolve(Buffer.concat(chunks)));
13608
+ });
13722
13609
  }
13723
- /**
13724
- * SearchStringDecisionFunctionFactory that searches for string matches using the input search term/filter text.
13725
- *
13726
- * @param filterText
13727
- * @returns
13728
- */
13729
- const caseInsensitiveFilterByIndexOfDecisionFactory = filterText => {
13730
- const searchString = filterText.toLocaleLowerCase();
13731
- return string => string.toLocaleLowerCase().indexOf(searchString) !== -1;
13732
- };
13733
13610
 
13734
- const SPLIT_STRING_TREE_NODE_ROOT_VALUE = '';
13611
+ function joinHostAndPort(config) {
13612
+ if (config) {
13613
+ return `${config.host}:${config.port}`;
13614
+ } else {
13615
+ return config;
13616
+ }
13617
+ }
13618
+
13619
+ exports.RelationChange = void 0;
13620
+ (function (RelationChange) {
13621
+ /**
13622
+ * Adds a model to the relation. If the model already exists in
13623
+ * the relation, the new one is used.
13624
+ *
13625
+ * Use INSERT to merge the two values together.
13626
+ */
13627
+ RelationChange["ADD"] = "add";
13628
+ /**
13629
+ * Sets the relation to be equal to the input.
13630
+ */
13631
+ RelationChange["SET"] = "set";
13632
+ /**
13633
+ * Variation of SET that performs REMOVE on the collection, and then follows it up with INSERT.
13634
+ *
13635
+ * This can allow the modification function to behave selectively with the items targeted for removal.
13636
+ */
13637
+ RelationChange["REMOVE_AND_INSERT"] = "remove_and_insert";
13638
+ /**
13639
+ * Removes a model from the relation.
13640
+ */
13641
+ RelationChange["REMOVE"] = "remove";
13642
+ /**
13643
+ * Updates an existing relation, if it exists.
13644
+ * The existing object is merged with the update object.
13645
+ */
13646
+ RelationChange["UPDATE"] = "update";
13647
+ /**
13648
+ * Updates an existing relation, if it exists, or creates a new one.
13649
+ */
13650
+ RelationChange["INSERT"] = "insert";
13651
+ })(exports.RelationChange || (exports.RelationChange = {}));
13735
13652
  /**
13736
- * Creates a SplitStringTreeFactory with the configured splitter.
13653
+ * Utility class for modifying a collection of relational objects.
13737
13654
  *
13738
- * @param config
13739
- * @returns
13655
+ * For instance, a string collection of keys.
13740
13656
  */
13741
- function splitStringTreeFactory(config) {
13742
- const {
13743
- separator
13744
- } = config;
13745
- const fn = (input, existing) => {
13657
+ class ModelRelationUtility {
13658
+ static modifyStringCollection(current, change, mods) {
13659
+ return ModelRelationUtility.modifyCollection(current, change, mods, {
13660
+ readKey: x => x,
13661
+ merge: (a, b) => b
13662
+ });
13663
+ }
13664
+ static modifyCollection(current, change, mods, config) {
13746
13665
  const {
13747
- leafMeta,
13748
- nodeMeta,
13749
- values
13750
- } = input;
13751
- const result = existing !== null && existing !== void 0 ? existing : {
13752
- fullValue: SPLIT_STRING_TREE_NODE_ROOT_VALUE,
13753
- nodeValue: SPLIT_STRING_TREE_NODE_ROOT_VALUE,
13754
- children: {}
13755
- };
13756
- asArray(values).forEach(value => {
13757
- addToSplitStringTree(result, {
13758
- value,
13759
- leafMeta,
13760
- nodeMeta
13761
- }, config);
13666
+ mask,
13667
+ readKey
13668
+ } = config;
13669
+ current = current !== null && current !== void 0 ? current : []; //init current if not set.
13670
+ if (mask) {
13671
+ const {
13672
+ included: currentModify,
13673
+ excluded: currentRetain
13674
+ } = separateValues(current, mask);
13675
+ const {
13676
+ included: modModify
13677
+ } = separateValues(mods, mask);
13678
+ const modifiedResults = this._modifyCollectionWithoutMask(currentModify, change, modModify, config);
13679
+ return this._mergeMaskResults(current, currentRetain, modifiedResults, readKey);
13680
+ } else {
13681
+ return this._modifyCollectionWithoutMask(current, change, mods, config);
13682
+ }
13683
+ }
13684
+ /**
13685
+ * The mask results are merged together.
13686
+ *
13687
+ * Order from the "current" is retained. Anything in currentRetain overrides modifiedResults.
13688
+ */
13689
+ static _mergeMaskResults(current, currentRetain, modifiedResults, readKey) {
13690
+ return restoreOrderWithValues(current, [...currentRetain, ...modifiedResults], {
13691
+ readKey
13762
13692
  });
13763
- return result;
13764
- };
13765
- fn._separator = separator;
13766
- return fn;
13767
- }
13768
- function applySplitStringTreeWithMultipleValues(input) {
13769
- const {
13770
- entries,
13771
- factory,
13772
- existing
13773
- } = input;
13774
- let result = existing;
13775
- entries.forEach(entry => {
13776
- result = factory(entry, result);
13777
- });
13778
- if (!result) {
13779
- result = factory({
13780
- values: []
13693
+ }
13694
+ static _modifyCollectionWithoutMask(current, change, mods, config) {
13695
+ const {
13696
+ readKey,
13697
+ merge,
13698
+ shouldRemove
13699
+ } = config;
13700
+ const readType = config.readType;
13701
+ function remove(rCurrent = current, rMods = mods) {
13702
+ return ModelRelationUtility._modifyCollection(rCurrent, rMods, (x, y) => {
13703
+ return ModelRelationUtility.removeFromCollection(x, y, readKey, shouldRemove);
13704
+ }, readType);
13705
+ }
13706
+ function performAdd() {
13707
+ return ModelRelationUtility._modifyCollection(current, mods, (x, y) => ModelRelationUtility.addToCollection(x, y, readKey), readType);
13708
+ }
13709
+ function performInsert() {
13710
+ return ModelRelationUtility.insertCollection(current, mods, {
13711
+ readKey,
13712
+ readType,
13713
+ merge
13714
+ });
13715
+ }
13716
+ switch (change) {
13717
+ case exports.RelationChange.SET:
13718
+ current = []; // Set current before performing add.
13719
+ return performAdd();
13720
+ case exports.RelationChange.ADD:
13721
+ return performAdd();
13722
+ case exports.RelationChange.REMOVE:
13723
+ return remove();
13724
+ case exports.RelationChange.UPDATE:
13725
+ return ModelRelationUtility.updateCollection(current, mods, {
13726
+ readKey,
13727
+ readType,
13728
+ merge
13729
+ });
13730
+ case exports.RelationChange.REMOVE_AND_INSERT:
13731
+ current = remove(current, current); // Remove all current values before performing an insert.
13732
+ return performInsert();
13733
+ case exports.RelationChange.INSERT:
13734
+ return performInsert();
13735
+ }
13736
+ }
13737
+ static updateCollection(current, update, {
13738
+ readKey,
13739
+ readType,
13740
+ merge
13741
+ }) {
13742
+ ModelRelationUtility._assertMergeProvided(merge);
13743
+ return ModelRelationUtility._modifyCollection(current, update, (x, y) => ModelRelationUtility._updateSingleTypeCollection(x, y, {
13744
+ readKey,
13745
+ merge
13746
+ }), readType);
13747
+ }
13748
+ static insertCollection(current, update, {
13749
+ readKey,
13750
+ readType,
13751
+ merge
13752
+ }) {
13753
+ ModelRelationUtility._assertMergeProvided(merge);
13754
+ return ModelRelationUtility._modifyCollection(current, update, (x, y) => ModelRelationUtility._insertSingleTypeCollection(x, y, {
13755
+ readKey,
13756
+ merge
13757
+ }), readType);
13758
+ }
13759
+ /**
13760
+ * Used to modify a collection which may be multi-type. If readType is provided, the collection is handled as a multi-type map.
13761
+ */
13762
+ static _modifyCollection(current, mods, modifyCollection, readType) {
13763
+ if (readType) {
13764
+ return ModelRelationUtility._modifyMultiTypeCollection(current, mods, readType, modifyCollection);
13765
+ } else {
13766
+ return modifyCollection(current, mods);
13767
+ }
13768
+ }
13769
+ static _modifyMultiTypeCollection(input, mods, readType, modifyCollection) {
13770
+ const inputMap = makeValuesGroupMap(input, readType);
13771
+ const modsMap = makeValuesGroupMap(mods, readType);
13772
+ const typesModified = new Set([...inputMap.keys(), ...modsMap.keys()]);
13773
+ // Break the collections up into their individual types and process separately.
13774
+ const modifiedSubcollections = Array.from(typesModified).map(type => {
13775
+ var _a, _b;
13776
+ const values = (_a = inputMap.get(type)) !== null && _a !== void 0 ? _a : [];
13777
+ const mods = (_b = modsMap.get(type)) !== null && _b !== void 0 ? _b : [];
13778
+ // Only modify if they've got changes for their type.
13779
+ if (mods.length === 0) {
13780
+ return values; // No mods, no change to those types.
13781
+ } else {
13782
+ return modifyCollection(values, mods);
13783
+ }
13781
13784
  });
13785
+ // Rejoin all changes.
13786
+ return modifiedSubcollections.reduce((x, y) => x.concat(y), []);
13782
13787
  }
13783
- return result;
13784
- }
13785
- /**
13786
- * Adds a value to the target SplitStringTree.
13787
- *
13788
- * @param tree
13789
- * @param value
13790
- * @param separator
13791
- * @returns
13792
- */
13793
- function addToSplitStringTree(tree, inputValue, config) {
13794
- const {
13795
- separator,
13796
- mergeMeta
13797
- } = config;
13798
- const {
13799
- value,
13800
- leafMeta,
13801
- nodeMeta
13802
- } = inputValue;
13803
- function nextMeta(node, nextMeta) {
13804
- if (mergeMeta && node.meta != null) {
13805
- return mergeMeta(node.meta, nextMeta);
13788
+ static _insertSingleTypeCollection(current, insert, {
13789
+ readKey,
13790
+ merge
13791
+ }) {
13792
+ const currentKeys = arrayToMap(current, readKey);
13793
+ const updateValues = [];
13794
+ const addValues = [];
13795
+ insert.forEach(value => {
13796
+ const key = readKey(value);
13797
+ if (currentKeys.has(key)) {
13798
+ updateValues.push(value);
13799
+ } else {
13800
+ addValues.push(value);
13801
+ }
13802
+ });
13803
+ const added = ModelRelationUtility.addToCollection(current, addValues, readKey);
13804
+ const results = ModelRelationUtility._updateSingleTypeCollection(added, updateValues, {
13805
+ readKey,
13806
+ merge
13807
+ });
13808
+ return results;
13809
+ }
13810
+ static _updateSingleTypeCollection(current, update, {
13811
+ readKey,
13812
+ merge
13813
+ }) {
13814
+ const keysToUpdate = arrayToMap(update, readKey);
13815
+ const updateValues = [];
13816
+ current.forEach(value => {
13817
+ const key = readKey(value);
13818
+ const mergeWith = keysToUpdate.get(key);
13819
+ if (mergeWith != null) {
13820
+ updateValues.push(merge(value, mergeWith));
13821
+ }
13822
+ });
13823
+ // Add to merge all values and remove duplicates.
13824
+ return ModelRelationUtility.addToCollection(current, updateValues, readKey);
13825
+ }
13826
+ static addToCollection(current, add, readKey) {
13827
+ current = current !== null && current !== void 0 ? current : [];
13828
+ return (add === null || add === void 0 ? void 0 : add.length) ? ModelRelationUtility.removeDuplicates([...add, ...current], readKey) : current; // Will keep any "added" before any existing ones.
13829
+ }
13830
+
13831
+ static removeFromCollection(current, remove, readKey, shouldRemove) {
13832
+ if (current === null || current === void 0 ? void 0 : current.length) {
13833
+ if (shouldRemove) {
13834
+ const currentKeyPairs = makeKeyPairs(current, readKey);
13835
+ const map = new Map(currentKeyPairs);
13836
+ remove.forEach(x => {
13837
+ const key = readKey(x);
13838
+ const removalTarget = map.get(key);
13839
+ if (removalTarget && shouldRemove(removalTarget)) {
13840
+ map.delete(key); // Remove from the map.
13841
+ }
13842
+ });
13843
+
13844
+ return currentKeyPairs.filter(x => map.has(x[0])).map(x => x[1]); // Retain order, remove from map.
13845
+ } else {
13846
+ return ModelRelationUtility.removeKeysFromCollection(current, remove.map(readKey), readKey);
13847
+ }
13806
13848
  } else {
13807
- return nextMeta;
13849
+ return [];
13808
13850
  }
13809
13851
  }
13810
- const parts = value.split(separator);
13811
- let currentNode = tree;
13812
- parts.forEach(nodeValue => {
13813
- const existingChildNode = currentNode.children[nodeValue];
13814
- const childNode = existingChildNode !== null && existingChildNode !== void 0 ? existingChildNode : {
13815
- nodeValue,
13816
- children: {}
13817
- }; // use the existing node or create a new node
13818
- if (!existingChildNode) {
13819
- childNode.fullValue = currentNode.fullValue ? currentNode.fullValue + separator + nodeValue : nodeValue;
13820
- currentNode.children[nodeValue] = childNode;
13821
- }
13822
- // add the meta to the node
13823
- if (nodeMeta != null) {
13824
- childNode.meta = nextMeta(childNode, nodeMeta);
13825
- }
13826
- currentNode = childNode;
13827
- });
13828
- // add the meta to the leaf node
13829
- if (leafMeta != null) {
13830
- currentNode.meta = nextMeta(currentNode, leafMeta);
13852
+ static removeKeysFromCollection(current, keysToRemove, readKey) {
13853
+ return ModelRelationUtility.removeDuplicates(current, readKey, keysToRemove);
13831
13854
  }
13832
- return tree;
13833
- }
13834
- // MARK: Search
13835
- /**
13836
- * Returns the best match for the value in the tree, including the input tree value.
13837
- *
13838
- * Only returns a result if there is match of any kind.
13839
- *
13840
- * @param tree
13841
- * @param value
13842
- * @returns
13843
- */
13844
- function findBestSplitStringTreeMatch(tree, value) {
13845
- return lastValue(findBestSplitStringTreeMatchPath(tree, value));
13846
- }
13847
- /**
13848
- * Returns the best match for the value in the true, excluding the input tree value.
13849
- *
13850
- * Only returns a result if there is match of any kind.
13851
- *
13852
- * @param tree
13853
- * @param value
13854
- * @returns
13855
- */
13856
- function findBestSplitStringTreeChildMatch(tree, value) {
13857
- return lastValue(findBestSplitStringTreeChildMatchPath(tree, value));
13858
- }
13859
- /**
13860
- * Returns the best match for the value in the tree, including the input tree value.
13861
- *
13862
- * Only returns a result if there is match of any kind.
13863
- *
13864
- * @param tree
13865
- * @param value
13866
- * @returns
13867
- */
13868
- function findBestSplitStringTreeMatchPath(tree, value) {
13869
- let bestResult = findBestSplitStringTreeChildMatchPath(tree, value);
13870
- if (!bestResult && tree.fullValue && value.startsWith(tree.fullValue)) {
13871
- bestResult = [tree];
13855
+ static removeDuplicates(relations, readKey, additionalKeys = []) {
13856
+ return (relations === null || relations === void 0 ? void 0 : relations.length) ? filterUniqueValues(relations, readKey, additionalKeys) : [];
13872
13857
  }
13873
- return bestResult;
13874
- }
13875
- /**
13876
- * Returns the best match for the value in the true, excluding the input tree value.
13877
- *
13878
- * Only returns a result if there is match of any kind.
13879
- *
13880
- * @param tree
13881
- * @param value
13882
- * @returns
13883
- */
13884
- function findBestSplitStringTreeChildMatchPath(tree, value) {
13885
- const {
13886
- children
13887
- } = tree;
13888
- let bestMatchPath;
13889
- Object.entries(children).find(([_, child]) => {
13890
- var _a;
13891
- let stopScan = false;
13892
- if (value.startsWith(child.fullValue)) {
13893
- const bestChildPath = (_a = findBestSplitStringTreeChildMatchPath(child, value)) !== null && _a !== void 0 ? _a : [];
13894
- bestMatchPath = [child, ...bestChildPath];
13895
- stopScan = true;
13858
+ // MARK: Internal Utility
13859
+ static _assertMergeProvided(merge) {
13860
+ if (!merge) {
13861
+ throw new Error('Merge was not provided.');
13896
13862
  }
13897
- return stopScan;
13898
- });
13899
- return bestMatchPath;
13863
+ }
13900
13864
  }
13901
13865
 
13902
- /*eslint @typescript-eslint/no-explicit-any:"off"*/
13903
- // any is used with intent here, as the recursive TreeNode value requires its use to terminate.
13904
- function expandTreeFunction(config) {
13905
- var _a;
13906
- const makeNode = (_a = config.makeNode) !== null && _a !== void 0 ? _a : node => node;
13907
- const expandFn = (value, parent) => {
13908
- const depth = parent ? parent.depth + 1 : 0;
13909
- const treeNode = {
13910
- depth,
13911
- parent,
13912
- value
13866
+ /**
13867
+ * Key used to signify
13868
+ */
13869
+ const CATCH_ALL_HANDLE_RESULT_KEY = '__CATCH_ALL_HANDLE_RESULT_KEY__';
13870
+ function handlerFactory(readKey) {
13871
+ return () => {
13872
+ let catchAll;
13873
+ const map = new Map();
13874
+ const set = (key, handle) => {
13875
+ if (key === CATCH_ALL_HANDLE_RESULT_KEY) {
13876
+ catchAll = handle;
13877
+ } else {
13878
+ setKeysOnMap(map, key, handle);
13879
+ }
13913
13880
  };
13914
- const node = makeNode(treeNode);
13915
- const childrenValues = config.getChildren(value);
13916
- node.children = childrenValues ? childrenValues.map(x => expandFn(x, node)) : undefined;
13917
- return node;
13881
+ const bindSet = (bindTo, key, handle) => {
13882
+ const bindHandle = handle.bind(bindTo);
13883
+ set(key, bindHandle);
13884
+ };
13885
+ const fn = build({
13886
+ base: value => {
13887
+ var _a;
13888
+ const key = readKey(value);
13889
+ const handler = (_a = key != null ? map.get(key) : undefined) !== null && _a !== void 0 ? _a : catchAll;
13890
+ let handled = false;
13891
+ if (handler) {
13892
+ handled = handler(value);
13893
+ }
13894
+ return handled;
13895
+ },
13896
+ build: x => {
13897
+ x.readKey = readKey;
13898
+ x.set = set;
13899
+ x.bindSet = bindSet;
13900
+ }
13901
+ });
13902
+ return fn;
13918
13903
  };
13919
- return root => expandFn(root);
13920
13904
  }
13921
- /**
13922
- * Convenience function for expanding multiple values into trees then merging them together into a single array.
13923
- *
13924
- * @param values
13925
- * @param expandFn
13926
- * @returns
13927
- */
13928
- function expandTrees(values, expandFn) {
13929
- return values.map(expandFn);
13905
+ function makeHandler(readKey) {
13906
+ return handlerFactory(readKey)();
13930
13907
  }
13931
-
13932
- /**
13933
- * Traverses the tree and flattens it into all tree nodes.
13934
- */
13935
- function flattenTree(tree) {
13936
- return flattenTreeToArray(tree, []);
13908
+ function catchAllHandlerKey() {
13909
+ return CATCH_ALL_HANDLE_RESULT_KEY;
13937
13910
  }
13911
+
13938
13912
  /**
13939
- * Traverses the tree and pushes the nodes into the input array.
13913
+ * Creates a HandlerBindAccessor<T, K> for the input values.
13940
13914
  *
13941
- * @param tree
13942
- * @param array
13915
+ * @param bindTo
13916
+ * @param accessor
13943
13917
  * @returns
13944
13918
  */
13945
- function flattenTreeToArray(tree, array) {
13946
- return flattenTreeToArrayFunction()(tree, array);
13947
- }
13948
- function flattenTreeToArrayFunction(mapNodeFn) {
13949
- const mapNode = mapNodeFn !== null && mapNodeFn !== void 0 ? mapNodeFn : x => x;
13950
- const flattenFn = (tree, array = []) => {
13951
- array.push(mapNode(tree));
13952
- if (tree.children) {
13953
- tree.children.forEach(x => flattenFn(x, array));
13919
+ function handlerBindAccessor(boundTo, accessor) {
13920
+ return {
13921
+ accessor,
13922
+ boundTo,
13923
+ set: (key, handle) => {
13924
+ accessor.bindSet(boundTo, key, handle);
13954
13925
  }
13955
- return array;
13956
13926
  };
13957
- return flattenFn;
13958
- }
13959
- /**
13960
- * Convenience function for flattening multiple trees with a flatten function.
13961
- *
13962
- * @param trees
13963
- * @param flattenFn
13964
- * @returns
13965
- */
13966
- function flattenTrees(trees, flattenFn) {
13967
- const array = [];
13968
- trees.forEach(x => flattenFn(x, array));
13969
- return array;
13970
13927
  }
13971
-
13972
- /*eslint @typescript-eslint/no-explicit-any:"off"*/
13973
13928
  /**
13974
- * Creates an ExpandFlattenTree function.
13929
+ * Creates a HandlerSetFunction.
13975
13930
  *
13976
- * @param expand
13977
- * @param flatten
13931
+ * @param accessor
13932
+ * @param key
13978
13933
  * @returns
13979
13934
  */
13980
- function expandFlattenTreeFunction(expand, flatten) {
13981
- return values => {
13982
- return flattenTrees(expandTrees(values, expand), flatten);
13935
+ function handlerSetFunction(accessor, key) {
13936
+ const fn = handlerFunction => {
13937
+ accessor.set(key, handlerFunction); // set the handler on the pre-defined key.
13983
13938
  };
13984
- }
13985
13939
 
13986
- // MARK: Reduce
13987
- function reduceBooleansWithAnd(array, emptyArrayValue) {
13988
- return reduceBooleansWithAndFn(emptyArrayValue)(array);
13989
- }
13990
- function reduceBooleansWithOr(array, emptyArrayValue) {
13991
- return reduceBooleansWithOrFn(emptyArrayValue)(array);
13992
- }
13993
- function reduceBooleansWithAndFn(emptyArrayValue) {
13994
- return reduceBooleansFn((a, b) => a && b, emptyArrayValue);
13995
- }
13996
- function reduceBooleansWithOrFn(emptyArrayValue) {
13997
- return reduceBooleansFn((a, b) => a || b, emptyArrayValue);
13998
- }
13999
- function reduceBooleansFn(reduceFn, emptyArrayValue) {
14000
- const rFn = array => Boolean(array.reduce(reduceFn));
14001
- if (emptyArrayValue != null) {
14002
- return array => array.length ? rFn(array) : emptyArrayValue;
14003
- } else {
14004
- return rFn;
14005
- }
14006
- }
14007
- /**
14008
- * Creates a new BooleanFactory.
14009
- *
14010
- * @param config
14011
- * @returns
14012
- */
14013
- function booleanFactory(config) {
14014
- const {
14015
- chance: inputChance
14016
- } = config;
14017
- const chance = inputChance / 100;
14018
- return () => {
14019
- const roll = Math.random();
14020
- const result = roll <= chance;
14021
- return result;
13940
+ fn.key = key;
13941
+ return fn;
13942
+ }
13943
+ function handlerMappedSetFunction(accessor, key, mapFn) {
13944
+ const handlerSet = handlerSetFunction(accessor, key);
13945
+ return handlerFunction => {
13946
+ // set an intermediary function that calls the target function. We don't use an arrow function so we have access to the "this", if bound.
13947
+ handlerSet(function (value) {
13948
+ const mapped = mapFn(value); // fowards "this" to the next call.
13949
+ return handlerFunction.call(this, mapped);
13950
+ });
14022
13951
  };
14023
13952
  }
14024
- /**
14025
- * Returns a random boolean.
14026
- *
14027
- * @param chance Number between 0 and 100
14028
- * @returns
14029
- */
14030
- function randomBoolean(chance = 50) {
14031
- return booleanFactory({
14032
- chance
14033
- })();
13953
+ function handlerMappedSetFunctionFactory(accessor, mapFn) {
13954
+ return key => handlerMappedSetFunction(accessor, key, mapFn);
13955
+ }
13956
+ function handlerConfigurerFactory(config) {
13957
+ return handler => {
13958
+ return (bindTo, configure) => {
13959
+ const accessor = handlerBindAccessor(bindTo, handler);
13960
+ const configurer = config.configurerForAccessor(accessor);
13961
+ configure(configurer);
13962
+ };
13963
+ };
14034
13964
  }
14035
13965
 
14036
13966
  /**
14037
- * Returns the day of the week for the input day.
14038
- *
14039
- * Equivalent to date.getDay()
14040
- *
14041
- * @param date
14042
- * @returns
13967
+ * TypedServiceRegistry implementation.
14043
13968
  */
14044
- function dayOfWeek(date) {
14045
- return date.getDay();
13969
+ class TypedServiceRegistryInstance {
13970
+ constructor() {
13971
+ this._map = new Map();
13972
+ }
13973
+ registerServiceForType(type, service) {
13974
+ const getter = asGetter(service);
13975
+ this._map.set(type, getter);
13976
+ }
13977
+ serviceForType(type) {
13978
+ const getter = this._map.get(type);
13979
+ const service = getter === null || getter === void 0 ? void 0 : getter();
13980
+ if (service == null) {
13981
+ throw new Error(`no service registered for type "${type}"`);
13982
+ }
13983
+ return service;
13984
+ }
14046
13985
  }
14047
13986
  /**
14048
- * Creates a DecisionFunction that checks whether or not the input day or days of
14049
- *
14050
- * @param allowedDaysOfWeek
13987
+ * Creates a new TypedServiceRegistryInstance and registers the input types.
14051
13988
  * @returns
14052
13989
  */
14053
- function isInAllowedDaysOfWeekSet(allowedDaysOfWeek) {
14054
- return isInSetDecisionFunction(allowedDaysOfWeek, x => {
14055
- return typeof x === 'number' ? x : dayOfWeek(x);
13990
+ function typedServiceRegistry(config) {
13991
+ const instance = new TypedServiceRegistryInstance();
13992
+ forEachKeyValue(config.services, {
13993
+ forEach: ([key, service]) => {
13994
+ instance.registerServiceForType(key, service);
13995
+ }
14056
13996
  });
13997
+ return instance;
14057
13998
  }
14058
- /**
14059
- * Returns all days of the week starting from the given day up to the specified number of days.
14060
- *
14061
- * Returns 7 days by default.
14062
- *
14063
- * @param startingOn
14064
- */
14065
- function daysOfWeekArray(startingOn = exports.Day.SUNDAY, maxDays = 7) {
14066
- const days = [];
14067
- let day = startingOn;
14068
- while (days.length < maxDays) {
14069
- days.push(day);
14070
- if (day === exports.Day.SATURDAY) {
14071
- day = exports.Day.SUNDAY;
14072
- } else {
14073
- day += 1;
14074
- }
13999
+
14000
+ class StoredDataError extends makeError.BaseError {
14001
+ constructor(message) {
14002
+ super(message);
14075
14003
  }
14076
- return days;
14077
14004
  }
14078
- /**
14079
- * Enum for the days of the week.
14080
- */
14081
- exports.Day = void 0;
14082
- (function (Day) {
14083
- Day[Day["SUNDAY"] = 0] = "SUNDAY";
14084
- Day[Day["MONDAY"] = 1] = "MONDAY";
14085
- Day[Day["TUESDAY"] = 2] = "TUESDAY";
14086
- Day[Day["WEDNESDAY"] = 3] = "WEDNESDAY";
14087
- Day[Day["THURSDAY"] = 4] = "THURSDAY";
14088
- Day[Day["FRIDAY"] = 5] = "FRIDAY";
14089
- Day[Day["SATURDAY"] = 6] = "SATURDAY";
14090
- })(exports.Day || (exports.Day = {}));
14091
- function enabledDaysFromDaysOfWeek(input) {
14092
- const set = new Set(input);
14093
- return {
14094
- sunday: set.has(exports.Day.SUNDAY),
14095
- monday: set.has(exports.Day.MONDAY),
14096
- tuesday: set.has(exports.Day.TUESDAY),
14097
- wednesday: set.has(exports.Day.WEDNESDAY),
14098
- thursday: set.has(exports.Day.THURSDAY),
14099
- friday: set.has(exports.Day.FRIDAY),
14100
- saturday: set.has(exports.Day.SATURDAY)
14101
- };
14005
+ class DataDoesNotExistError extends StoredDataError {
14006
+ constructor(message) {
14007
+ super(message);
14008
+ }
14102
14009
  }
14103
- function daysOfWeekFromEnabledDays(input) {
14104
- const daysOfWeek = [];
14105
- if (input) {
14106
- if (input.sunday) {
14107
- daysOfWeek.push(exports.Day.SUNDAY);
14108
- }
14109
- if (input.monday) {
14110
- daysOfWeek.push(exports.Day.MONDAY);
14111
- }
14112
- if (input.tuesday) {
14113
- daysOfWeek.push(exports.Day.TUESDAY);
14114
- }
14115
- if (input.wednesday) {
14116
- daysOfWeek.push(exports.Day.WEDNESDAY);
14117
- }
14118
- if (input.thursday) {
14119
- daysOfWeek.push(exports.Day.THURSDAY);
14120
- }
14121
- if (input.friday) {
14122
- daysOfWeek.push(exports.Day.FRIDAY);
14010
+ class DataIsExpiredError extends StoredDataError {
14011
+ constructor(data, message) {
14012
+ super(message);
14013
+ this.data = data;
14014
+ }
14015
+ }
14016
+
14017
+ class MemoryStorageInstance {
14018
+ constructor() {
14019
+ this._length = 0;
14020
+ this._storage = {};
14021
+ }
14022
+ get length() {
14023
+ return this._length;
14024
+ }
14025
+ key(index) {
14026
+ var _a;
14027
+ return (_a = Object.keys(this._storage)[index]) !== null && _a !== void 0 ? _a : null;
14028
+ }
14029
+ hasKey(key) {
14030
+ return objectHasKey(this._storage, key);
14031
+ }
14032
+ getItem(key) {
14033
+ var _a;
14034
+ return (_a = this._storage[key]) !== null && _a !== void 0 ? _a : null;
14035
+ }
14036
+ setItem(key, item) {
14037
+ if (item == null) {
14038
+ this.removeItem(key);
14039
+ } else {
14040
+ if (!this.hasKey(key)) {
14041
+ this._length = this._length + 1;
14042
+ }
14043
+ this._storage[key] = String(item);
14123
14044
  }
14124
- if (input.saturday) {
14125
- daysOfWeek.push(exports.Day.SATURDAY);
14045
+ }
14046
+ removeItem(key) {
14047
+ if (this.hasKey(key)) {
14048
+ delete this._storage[key]; // Remove the property
14049
+ this._length = this._length - 1;
14126
14050
  }
14127
14051
  }
14128
- return daysOfWeek;
14052
+ clear() {
14053
+ this._storage = {};
14054
+ this._length = 0;
14055
+ }
14129
14056
  }
14057
+ const SHARED_MEMORY_STORAGE = new MemoryStorageInstance();
14058
+
14130
14059
  /**
14131
- * Returns an array of strinsg with each day of the week named.
14060
+ * Limited Class/Interface for storing string values synchronously.
14061
+ */
14062
+ class SimpleStorageObject {}
14063
+ /**
14064
+ * Synchronous Class/Interface for storing string values.
14132
14065
  *
14133
- * @returns
14066
+ * Has the same interface as localStorage for the web.
14134
14067
  */
14135
- function getDaysOfWeekNames(sundayFirst = true, transform) {
14136
- const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
14137
- const sunday = 'Sunday';
14138
- let dayOfWeekNames;
14139
- if (sundayFirst) {
14140
- dayOfWeekNames = [sunday, ...days];
14141
- } else {
14142
- dayOfWeekNames = [...days, sunday];
14143
- }
14144
- if (transform != null) {
14145
- if (transform.abbreviation) {
14146
- dayOfWeekNames = dayOfWeekNames.map(x => x.slice(0, 3));
14147
- }
14148
- if (transform.uppercase) {
14149
- dayOfWeekNames = dayOfWeekNames.map(x => x.toUpperCase());
14068
+ class StorageObject extends SimpleStorageObject {}
14069
+ class FullStorageObject extends StorageObject {}
14070
+ class StorageObjectUtility {
14071
+ static allKeysFromStorageObject(storageObject, prefix) {
14072
+ const length = storageObject.length;
14073
+ let result;
14074
+ if (length > 0) {
14075
+ result = range({
14076
+ start: 0,
14077
+ end: length
14078
+ }).map(x => storageObject.key(x)).filter(hasNonNullValue);
14079
+ if (prefix) {
14080
+ result = result.filter(x => x.startsWith(prefix));
14081
+ }
14082
+ } else {
14083
+ result = [];
14150
14084
  }
14085
+ return result;
14151
14086
  }
14152
- return dayOfWeekNames;
14153
- }
14154
- function daysOfWeekNameMap(transform) {
14155
- const dayOfWeekNames = getDaysOfWeekNames(true, transform);
14156
- return new Map(dayOfWeekNames.map((x, i) => [i, x]));
14157
- }
14158
- function daysOfWeekNameFunction(transform) {
14159
- const map = daysOfWeekNameMap(transform);
14160
- return dayOfWeek => {
14161
- var _a;
14162
- return (_a = map.get(dayOfWeek)) !== null && _a !== void 0 ? _a : 'UNKNOWN';
14163
- };
14164
- }
14165
- function getDayTomorrow(day) {
14166
- return getNextDay(day, 1);
14167
14087
  }
14168
- function getDayYesterday(day) {
14169
- return getPreviousDay(day, 1);
14088
+
14089
+ /**
14090
+ * Joins together various array of classes and only keeps the unique values.
14091
+ *
14092
+ * @param cssClasses
14093
+ * @returns
14094
+ */
14095
+ function spaceSeparatedCssClasses(cssClasses) {
14096
+ let result = '';
14097
+ if (cssClasses) {
14098
+ const allClasses = cssClassesSet(cssClasses);
14099
+ result = joinStringsWithSpaces(Array.from(allClasses));
14100
+ }
14101
+ return result;
14170
14102
  }
14171
- function getDayOffset(day, days) {
14172
- if (days === 0) {
14173
- return day;
14174
- } else if (days < 0) {
14175
- return getPreviousDay(day, days);
14103
+ /**
14104
+ * Joins together various array of classes and returns the set of unique CSS classes.
14105
+ *
14106
+ * @param cssClasses
14107
+ * @returns
14108
+ */
14109
+ function cssClassesSet(cssClasses) {
14110
+ let result;
14111
+ if (cssClasses) {
14112
+ const arrayOfClasses = iterableToArray(cssClasses, false);
14113
+ const arrayOfAllClassValues = arrayOfClasses.map(x => asArray(x).map(x => x.split(' ')).flat()).flat();
14114
+ result = new Set(arrayOfAllClassValues);
14176
14115
  } else {
14177
- return getNextDay(day, days);
14116
+ result = new Set();
14178
14117
  }
14118
+ return result;
14179
14119
  }
14180
- function getPreviousDay(day, days = 1) {
14181
- const offset = Math.abs(days) % 7;
14182
- const cap = 7 - offset;
14183
- return getNextDay(day, cap);
14120
+
14121
+ /**
14122
+ * Creates a SortByStringFunction that sorts values in ascending order.
14123
+ */
14124
+ function sortByStringFunction(readStringFn) {
14125
+ return (a, b) => {
14126
+ const as = readStringFn(a);
14127
+ const bs = readStringFn(b);
14128
+ return as.localeCompare(bs);
14129
+ };
14184
14130
  }
14185
- function getNextDay(day, days = 1) {
14186
- let result = (day + days) % 7;
14187
- if (result < 0) {
14188
- result = 7 + result;
14189
- }
14190
- return result;
14131
+ const sortByLabelFunction = sortByStringFunction(x => x.label);
14132
+
14133
+ /**
14134
+ * Creates a SearchStringFilterFunction
14135
+ *
14136
+ * @param config
14137
+ * @returns
14138
+ */
14139
+ function searchStringFilterFunction(config) {
14140
+ const {
14141
+ readStrings,
14142
+ decisionFactory = caseInsensitiveFilterByIndexOfDecisionFactory
14143
+ } = typeof config === 'function' ? {
14144
+ readStrings: config
14145
+ } : config;
14146
+ return (filterText, values) => {
14147
+ const decision = decisionFactory(filterText);
14148
+ return values.filter(value => {
14149
+ const searchResult = readStrings(value);
14150
+ let match = false;
14151
+ if (Array.isArray(searchResult)) {
14152
+ match = searchResult.findIndex(decision) !== -1;
14153
+ } else if (searchResult != null) {
14154
+ match = decision(searchResult);
14155
+ }
14156
+ return match;
14157
+ });
14158
+ };
14191
14159
  }
14160
+ /**
14161
+ * SearchStringDecisionFunctionFactory that searches for string matches using the input search term/filter text.
14162
+ *
14163
+ * @param filterText
14164
+ * @returns
14165
+ */
14166
+ const caseInsensitiveFilterByIndexOfDecisionFactory = filterText => {
14167
+ const searchString = filterText.toLocaleLowerCase();
14168
+ return string => string.toLocaleLowerCase().indexOf(searchString) !== -1;
14169
+ };
14192
14170
 
14193
- function timePeriodCounter(timePeriodLength, lastTimePeriodStart) {
14194
- function reset(inputStart) {
14195
- const start = inputStart !== null && inputStart !== void 0 ? inputStart : new Date();
14196
- fn._timePeriodCount = 0;
14197
- fn._lastTimePeriodStart = start;
14198
- fn._nextTimePeriodEnd = new Date(start.getTime() + timePeriodLength);
14199
- return fn._nextTimePeriodEnd;
14200
- }
14201
- const fn = () => {
14202
- const now = new Date();
14203
- if (now > fn._nextTimePeriodEnd) {
14204
- reset(now);
14205
- } else {
14206
- fn._timePeriodCount += 1;
14207
- }
14208
- return fn._timePeriodCount;
14171
+ const SPLIT_STRING_TREE_NODE_ROOT_VALUE = '';
14172
+ /**
14173
+ * Creates a SplitStringTreeFactory with the configured splitter.
14174
+ *
14175
+ * @param config
14176
+ * @returns
14177
+ */
14178
+ function splitStringTreeFactory(config) {
14179
+ const {
14180
+ separator
14181
+ } = config;
14182
+ const fn = (input, existing) => {
14183
+ const {
14184
+ leafMeta,
14185
+ nodeMeta,
14186
+ values
14187
+ } = input;
14188
+ const result = existing !== null && existing !== void 0 ? existing : {
14189
+ fullValue: SPLIT_STRING_TREE_NODE_ROOT_VALUE,
14190
+ nodeValue: SPLIT_STRING_TREE_NODE_ROOT_VALUE,
14191
+ children: {}
14192
+ };
14193
+ asArray(values).forEach(value => {
14194
+ addToSplitStringTree(result, {
14195
+ value,
14196
+ leafMeta,
14197
+ nodeMeta
14198
+ }, config);
14199
+ });
14200
+ return result;
14209
14201
  };
14210
- fn._timePeriodLength = timePeriodLength;
14211
- reset(lastTimePeriodStart);
14212
- fn._timePeriodCount = -1;
14213
- fn._reset = reset;
14202
+ fn._separator = separator;
14214
14203
  return fn;
14215
14204
  }
14216
- class TimerCancelledError extends makeError.BaseError {
14217
- constructor() {
14218
- super(`The timer was destroyed before it was completed.`);
14205
+ function applySplitStringTreeWithMultipleValues(input) {
14206
+ const {
14207
+ entries,
14208
+ factory,
14209
+ existing
14210
+ } = input;
14211
+ let result = existing;
14212
+ entries.forEach(entry => {
14213
+ result = factory(entry, result);
14214
+ });
14215
+ if (!result) {
14216
+ result = factory({
14217
+ values: []
14218
+ });
14219
14219
  }
14220
+ return result;
14220
14221
  }
14221
- class TimerInstance {
14222
- constructor(duration, startImmediately = true) {
14223
- this._createdAt = new Date();
14224
- this._startedAt = new Date();
14225
- this._state = 'paused';
14226
- this._promiseRef = promiseReference();
14227
- this._duration = duration;
14228
- if (startImmediately) {
14229
- this.start();
14230
- this._startedAt = this._createdAt;
14231
- }
14232
- }
14233
- get state() {
14234
- return this._state;
14235
- }
14236
- get createdAt() {
14237
- return this._createdAt;
14238
- }
14239
- get pausedAt() {
14240
- return this._pausedAt;
14241
- }
14242
- get startedAt() {
14243
- return this._startedAt;
14244
- }
14245
- get promise() {
14246
- return this._promiseRef.promise;
14247
- }
14248
- get duration() {
14249
- return this._duration;
14250
- }
14251
- get durationRemaining() {
14252
- let remaining;
14253
- switch (this._state) {
14254
- case 'complete':
14255
- remaining = 0;
14256
- break;
14257
- case 'running':
14258
- remaining = Math.max(0, this._duration - (new Date().getTime() - this._startedAt.getTime()));
14259
- break;
14260
- case 'paused':
14261
- remaining = null;
14262
- break;
14263
- }
14264
- return remaining;
14265
- }
14266
- start() {
14267
- if (this._state === 'paused') {
14268
- this._state = 'running';
14269
- this._startedAt = new Date();
14270
- this._enqueueCheck();
14271
- }
14272
- }
14273
- stop() {
14274
- if (this._state === 'running') {
14275
- this._state = 'paused';
14276
- this._pausedAt = new Date();
14277
- }
14278
- }
14279
- reset() {
14280
- if (this._state !== 'complete') {
14281
- this._state = 'running';
14282
- this._startedAt = new Date();
14283
- this._enqueueCheck();
14284
- }
14285
- }
14286
- setDuration(duration) {
14287
- this._duration = duration;
14288
- }
14289
- destroy() {
14290
- this._checkComplete();
14291
- if (this._state === 'running') {
14292
- const error = new TimerCancelledError();
14293
- this._promiseRef.reject(error);
14294
- this._state = 'complete'; // mark as complete
14222
+ /**
14223
+ * Adds a value to the target SplitStringTree.
14224
+ *
14225
+ * @param tree
14226
+ * @param value
14227
+ * @param separator
14228
+ * @returns
14229
+ */
14230
+ function addToSplitStringTree(tree, inputValue, config) {
14231
+ const {
14232
+ separator,
14233
+ mergeMeta
14234
+ } = config;
14235
+ const {
14236
+ value,
14237
+ leafMeta,
14238
+ nodeMeta
14239
+ } = inputValue;
14240
+ function nextMeta(node, nextMeta) {
14241
+ if (mergeMeta && node.meta != null) {
14242
+ return mergeMeta(node.meta, nextMeta);
14243
+ } else {
14244
+ return nextMeta;
14295
14245
  }
14296
14246
  }
14297
-
14298
- _checkComplete() {
14299
- if (this._state !== 'complete' && this.durationRemaining === 0) {
14300
- this._state = 'complete';
14301
- this._promiseRef.resolve();
14247
+ const parts = value.split(separator);
14248
+ let currentNode = tree;
14249
+ parts.forEach(nodeValue => {
14250
+ const existingChildNode = currentNode.children[nodeValue];
14251
+ const childNode = existingChildNode !== null && existingChildNode !== void 0 ? existingChildNode : {
14252
+ nodeValue,
14253
+ children: {}
14254
+ }; // use the existing node or create a new node
14255
+ if (!existingChildNode) {
14256
+ childNode.fullValue = currentNode.fullValue ? currentNode.fullValue + separator + nodeValue : nodeValue;
14257
+ currentNode.children[nodeValue] = childNode;
14302
14258
  }
14303
- }
14304
- _enqueueCheck() {
14305
- const durationRemaining = this.durationRemaining;
14306
- if (durationRemaining != null && this._state !== 'complete') {
14307
- setTimeout(() => {
14308
- this._checkComplete();
14309
- this._enqueueCheck();
14310
- }, durationRemaining);
14259
+ // add the meta to the node
14260
+ if (nodeMeta != null) {
14261
+ childNode.meta = nextMeta(childNode, nodeMeta);
14311
14262
  }
14263
+ currentNode = childNode;
14264
+ });
14265
+ // add the meta to the leaf node
14266
+ if (leafMeta != null) {
14267
+ currentNode.meta = nextMeta(currentNode, leafMeta);
14312
14268
  }
14269
+ return tree;
14313
14270
  }
14314
- function timer(duration, startNow = true) {
14315
- return new TimerInstance(duration, startNow);
14271
+ // MARK: Search
14272
+ /**
14273
+ * Returns the best match for the value in the tree, including the input tree value.
14274
+ *
14275
+ * Only returns a result if there is match of any kind.
14276
+ *
14277
+ * @param tree
14278
+ * @param value
14279
+ * @returns
14280
+ */
14281
+ function findBestSplitStringTreeMatch(tree, value) {
14282
+ return lastValue(findBestSplitStringTreeMatchPath(tree, value));
14316
14283
  }
14317
14284
  /**
14318
- * Toggles the input Timer's running state.
14285
+ * Returns the best match for the value in the true, excluding the input tree value.
14319
14286
  *
14320
- * @param timer
14321
- * @param toggleRun
14287
+ * Only returns a result if there is match of any kind.
14288
+ *
14289
+ * @param tree
14290
+ * @param value
14291
+ * @returns
14322
14292
  */
14323
- function toggleTimerRunning(timer, toggleRun) {
14324
- toggleRun = toggleRun != null ? toggleRun : timer.state !== 'running';
14325
- if (toggleRun) {
14326
- timer.start();
14327
- } else {
14328
- timer.stop();
14329
- }
14293
+ function findBestSplitStringTreeChildMatch(tree, value) {
14294
+ return lastValue(findBestSplitStringTreeChildMatchPath(tree, value));
14330
14295
  }
14331
14296
  /**
14332
- * Returns the approximate end date of the given timer. If a timer is already complete, it returns the time for now.
14297
+ * Returns the best match for the value in the tree, including the input tree value.
14298
+ *
14299
+ * Only returns a result if there is match of any kind.
14300
+ *
14301
+ * @param tree
14302
+ * @param value
14303
+ * @returns
14333
14304
  */
14334
- function approximateTimerEndDate(timer) {
14335
- const durationRemaining = timer.durationRemaining;
14336
- if (durationRemaining != null) {
14337
- return new Date(Date.now() + durationRemaining);
14338
- } else {
14339
- return null;
14305
+ function findBestSplitStringTreeMatchPath(tree, value) {
14306
+ let bestResult = findBestSplitStringTreeChildMatchPath(tree, value);
14307
+ if (!bestResult && tree.fullValue && value.startsWith(tree.fullValue)) {
14308
+ bestResult = [tree];
14340
14309
  }
14310
+ return bestResult;
14311
+ }
14312
+ /**
14313
+ * Returns the best match for the value in the true, excluding the input tree value.
14314
+ *
14315
+ * Only returns a result if there is match of any kind.
14316
+ *
14317
+ * @param tree
14318
+ * @param value
14319
+ * @returns
14320
+ */
14321
+ function findBestSplitStringTreeChildMatchPath(tree, value) {
14322
+ const {
14323
+ children
14324
+ } = tree;
14325
+ let bestMatchPath;
14326
+ Object.entries(children).find(([_, child]) => {
14327
+ var _a;
14328
+ let stopScan = false;
14329
+ if (value.startsWith(child.fullValue)) {
14330
+ const bestChildPath = (_a = findBestSplitStringTreeChildMatchPath(child, value)) !== null && _a !== void 0 ? _a : [];
14331
+ bestMatchPath = [child, ...bestChildPath];
14332
+ stopScan = true;
14333
+ }
14334
+ return stopScan;
14335
+ });
14336
+ return bestMatchPath;
14341
14337
  }
14342
14338
 
14343
- exports.TimeAM = void 0;
14344
- (function (TimeAM) {
14345
- TimeAM["AM"] = "AM";
14346
- TimeAM["PM"] = "PM";
14347
- })(exports.TimeAM || (exports.TimeAM = {}));
14348
- const DATE_NOW_VALUE = 'now';
14349
- function dateFromLogicalDate(logicalDate) {
14350
- let result;
14351
- if (typeof logicalDate === 'string') {
14352
- switch (logicalDate.toLocaleLowerCase()) {
14353
- case DATE_NOW_VALUE:
14354
- result = new Date();
14355
- break;
14356
- default:
14357
- throw new Error(`Unknown logical date string "${logicalDate}"`);
14339
+ /*eslint @typescript-eslint/no-explicit-any:"off"*/
14340
+ // any is used with intent here, as the recursive TreeNode value requires its use to terminate.
14341
+ function expandTreeFunction(config) {
14342
+ var _a;
14343
+ const makeNode = (_a = config.makeNode) !== null && _a !== void 0 ? _a : node => node;
14344
+ const expandFn = (value, parent) => {
14345
+ const depth = parent ? parent.depth + 1 : 0;
14346
+ const treeNode = {
14347
+ depth,
14348
+ parent,
14349
+ value
14350
+ };
14351
+ const node = makeNode(treeNode);
14352
+ const childrenValues = config.getChildren(value);
14353
+ node.children = childrenValues ? childrenValues.map(x => expandFn(x, node)) : undefined;
14354
+ return node;
14355
+ };
14356
+ return root => expandFn(root);
14357
+ }
14358
+ /**
14359
+ * Convenience function for expanding multiple values into trees then merging them together into a single array.
14360
+ *
14361
+ * @param values
14362
+ * @param expandFn
14363
+ * @returns
14364
+ */
14365
+ function expandTrees(values, expandFn) {
14366
+ return values.map(expandFn);
14367
+ }
14368
+
14369
+ /**
14370
+ * Traverses the tree and flattens it into all tree nodes.
14371
+ */
14372
+ function flattenTree(tree) {
14373
+ return flattenTreeToArray(tree, []);
14374
+ }
14375
+ /**
14376
+ * Traverses the tree and pushes the nodes into the input array.
14377
+ *
14378
+ * @param tree
14379
+ * @param array
14380
+ * @returns
14381
+ */
14382
+ function flattenTreeToArray(tree, array) {
14383
+ return flattenTreeToArrayFunction()(tree, array);
14384
+ }
14385
+ function flattenTreeToArrayFunction(mapNodeFn) {
14386
+ const mapNode = mapNodeFn !== null && mapNodeFn !== void 0 ? mapNodeFn : x => x;
14387
+ const flattenFn = (tree, array = []) => {
14388
+ array.push(mapNode(tree));
14389
+ if (tree.children) {
14390
+ tree.children.forEach(x => flattenFn(x, array));
14358
14391
  }
14392
+ return array;
14393
+ };
14394
+ return flattenFn;
14395
+ }
14396
+ /**
14397
+ * Convenience function for flattening multiple trees with a flatten function.
14398
+ *
14399
+ * @param trees
14400
+ * @param flattenFn
14401
+ * @returns
14402
+ */
14403
+ function flattenTrees(trees, flattenFn) {
14404
+ const array = [];
14405
+ trees.forEach(x => flattenFn(x, array));
14406
+ return array;
14407
+ }
14408
+
14409
+ /*eslint @typescript-eslint/no-explicit-any:"off"*/
14410
+ /**
14411
+ * Creates an ExpandFlattenTree function.
14412
+ *
14413
+ * @param expand
14414
+ * @param flatten
14415
+ * @returns
14416
+ */
14417
+ function expandFlattenTreeFunction(expand, flatten) {
14418
+ return values => {
14419
+ return flattenTrees(expandTrees(values, expand), flatten);
14420
+ };
14421
+ }
14422
+
14423
+ // MARK: Reduce
14424
+ function reduceBooleansWithAnd(array, emptyArrayValue) {
14425
+ return reduceBooleansWithAndFn(emptyArrayValue)(array);
14426
+ }
14427
+ function reduceBooleansWithOr(array, emptyArrayValue) {
14428
+ return reduceBooleansWithOrFn(emptyArrayValue)(array);
14429
+ }
14430
+ function reduceBooleansWithAndFn(emptyArrayValue) {
14431
+ return reduceBooleansFn((a, b) => a && b, emptyArrayValue);
14432
+ }
14433
+ function reduceBooleansWithOrFn(emptyArrayValue) {
14434
+ return reduceBooleansFn((a, b) => a || b, emptyArrayValue);
14435
+ }
14436
+ function reduceBooleansFn(reduceFn, emptyArrayValue) {
14437
+ const rFn = array => Boolean(array.reduce(reduceFn));
14438
+ if (emptyArrayValue != null) {
14439
+ return array => array.length ? rFn(array) : emptyArrayValue;
14359
14440
  } else {
14360
- result = logicalDate;
14441
+ return rFn;
14361
14442
  }
14362
- return result;
14363
14443
  }
14364
- function isLogicalDateStringCode(logicalDate) {
14365
- let isLogicalDateStringCode = false;
14366
- if (typeof logicalDate === 'string') {
14367
- switch (logicalDate.toLocaleLowerCase()) {
14368
- case DATE_NOW_VALUE:
14369
- isLogicalDateStringCode = true;
14370
- break;
14371
- }
14372
- }
14373
- return isLogicalDateStringCode;
14444
+ /**
14445
+ * Creates a new BooleanFactory.
14446
+ *
14447
+ * @param config
14448
+ * @returns
14449
+ */
14450
+ function booleanFactory(config) {
14451
+ const {
14452
+ chance: inputChance
14453
+ } = config;
14454
+ const chance = inputChance / 100;
14455
+ return () => {
14456
+ const roll = Math.random();
14457
+ const result = roll <= chance;
14458
+ return result;
14459
+ };
14460
+ }
14461
+ /**
14462
+ * Returns a random boolean.
14463
+ *
14464
+ * @param chance Number between 0 and 100
14465
+ * @returns
14466
+ */
14467
+ function randomBoolean(chance = 50) {
14468
+ return booleanFactory({
14469
+ chance
14470
+ })();
14374
14471
  }
14375
14472
 
14376
14473
  /**
@@ -14453,7 +14550,9 @@ function isFinalPage(page) {
14453
14550
  }
14454
14551
 
14455
14552
  /**
14456
- * Page calcuaktion context for calculating the amount to skip/etc.
14553
+ * Page calculation context for calculating the amount to skip/etc.
14554
+ *
14555
+ * @deprecated
14457
14556
  */
14458
14557
  class PageCalculator {
14459
14558
  constructor(config) {
@@ -14783,6 +14882,7 @@ exports.encodeBitwiseSet = encodeBitwiseSet;
14783
14882
  exports.encodeModelKeyTypePair = encodeModelKeyTypePair;
14784
14883
  exports.errorMessageContainsString = errorMessageContainsString;
14785
14884
  exports.errorMessageContainsStringFunction = errorMessageContainsStringFunction;
14885
+ exports.escapeStringCharactersFunction = escapeStringCharactersFunction;
14786
14886
  exports.escapeStringForRegex = escapeStringForRegex;
14787
14887
  exports.excludeValues = excludeValues;
14788
14888
  exports.excludeValuesFromArray = excludeValuesFromArray;
@@ -14924,6 +15024,7 @@ exports.isE164PhoneNumber = isE164PhoneNumber;
14924
15024
  exports.isE164PhoneNumberWithExtension = isE164PhoneNumberWithExtension;
14925
15025
  exports.isEmptyIterable = isEmptyIterable;
14926
15026
  exports.isEqualContext = isEqualContext;
15027
+ exports.isEqualDate = isEqualDate;
14927
15028
  exports.isEqualToValueDecisionFunction = isEqualToValueDecisionFunction;
14928
15029
  exports.isEvenNumber = isEvenNumber;
14929
15030
  exports.isFalseBooleanKeyArray = isFalseBooleanKeyArray;
@@ -15289,6 +15390,7 @@ exports.startOfDayForUTCDateInUTC = startOfDayForUTCDateInUTC;
15289
15390
  exports.stepsFromIndex = stepsFromIndex;
15290
15391
  exports.stepsFromIndexFunction = stepsFromIndexFunction;
15291
15392
  exports.stringCharactersToIndexRecord = stringCharactersToIndexRecord;
15393
+ exports.stringContains = stringContains;
15292
15394
  exports.stringFactoryFromFactory = stringFactoryFromFactory;
15293
15395
  exports.stringToLowercaseFunction = stringToLowercaseFunction;
15294
15396
  exports.stringToUppercaseFunction = stringToUppercaseFunction;