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