senaev-utils 1.0.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 (166) hide show
  1. package/README.md +11 -0
  2. package/package.json +66 -0
  3. package/src/reactHooks/setDeepEqualState.ts +19 -0
  4. package/src/reactHooks/useLocationParameter.ts +46 -0
  5. package/src/reactHooks/useObjectDeepChangesCounter.ts +22 -0
  6. package/src/reactHooks/useObservableMap/useObservableMap.ts +21 -0
  7. package/src/reactHooks/useRecentChangeTimer.ts +42 -0
  8. package/src/reactHooks/useReload.ts +17 -0
  9. package/src/reactHooks/useVisualizedProcessesTree.ts +202 -0
  10. package/src/types/Boolean.ts +9 -0
  11. package/src/types/DeepPartial.ts +1 -0
  12. package/src/types/GlobalContext.ts +8 -0
  13. package/src/types/HexColorString.ts +9 -0
  14. package/src/types/ISOLang.ts +5 -0
  15. package/src/types/IsEqualUnion.ts +1 -0
  16. package/src/types/IterableWithIndexAccess.ts +4 -0
  17. package/src/types/Kilobits.ts +4 -0
  18. package/src/types/Network/Bits.ts +4 -0
  19. package/src/types/Network/Bps.ts +4 -0
  20. package/src/types/Network/Kbps.ts +4 -0
  21. package/src/types/Network/Mbps.ts +4 -0
  22. package/src/types/Number/AngleInDegrees.ts +3 -0
  23. package/src/types/Number/FiniteNumber.ts +11 -0
  24. package/src/types/Number/Integer.ts +14 -0
  25. package/src/types/Number/IntegerInString.ts +13 -0
  26. package/src/types/Number/Number.ts +15 -0
  27. package/src/types/Number/Portion.ts +4 -0
  28. package/src/types/Number/PositiveInteger.ts +30 -0
  29. package/src/types/Number/PositiveNumber.ts +4 -0
  30. package/src/types/Number/StringUnsignedInteger.ts +4 -0
  31. package/src/types/Number/UnsignedFiniteNumber.ts +13 -0
  32. package/src/types/Number/UnsignedInteger.ts +28 -0
  33. package/src/types/Object/Object.ts +20 -0
  34. package/src/types/Percent.ts +4 -0
  35. package/src/types/PixelPosition.ts +9 -0
  36. package/src/types/PixelSize.ts +9 -0
  37. package/src/types/Pixels.ts +4 -0
  38. package/src/types/RangeTuple.ts +1 -0
  39. package/src/types/Size.ts +8 -0
  40. package/src/types/Time/DaysCount.ts +6 -0
  41. package/src/types/Time/Hours.ts +4 -0
  42. package/src/types/Time/ISODateString/ISODateString.ts +16 -0
  43. package/src/types/Time/Milliseconds.ts +4 -0
  44. package/src/types/Time/Minutes.ts +4 -0
  45. package/src/types/Time/Seconds.ts +5 -0
  46. package/src/types/Time/Time.ts +13 -0
  47. package/src/types/Time/Timestamp.ts +6 -0
  48. package/src/types/Time/UnixTimeMs.ts +6 -0
  49. package/src/types/Time/UnixTimeSec.ts +11 -0
  50. package/src/types/Time/const.ts +24 -0
  51. package/src/types/any/AnyAsyncFunction.ts +2 -0
  52. package/src/types/any/AnyFunction.ts +2 -0
  53. package/src/types/assertions/ANY_VALUE.ts +2 -0
  54. package/src/types/assertions/isNever/isNever.ts +34 -0
  55. package/src/types/assertions/isTrue/isTrue.ts +13 -0
  56. package/src/utils/AbortableProcess.ts +160 -0
  57. package/src/utils/Array/createArray/createArray.ts +8 -0
  58. package/src/utils/Array/createIntegerSequenceArray/createIntegerSequenceArray.ts +3 -0
  59. package/src/utils/Array/getUniqueValues/getUniqueValues.ts +3 -0
  60. package/src/utils/Array/separateToArrays/separateToArrays.ts +24 -0
  61. package/src/utils/Array/shuffleArray/shuffleArray.ts +18 -0
  62. package/src/utils/CircularBuffer/CircularBuffer.ts +117 -0
  63. package/src/utils/DOM/blurDocument.ts +3 -0
  64. package/src/utils/DOM/unfocusDocument.ts +3 -0
  65. package/src/utils/Date/dateToUnixTimeSec/dateToUnixTimeSec.ts +6 -0
  66. package/src/utils/Date/isoDateStringToUnixTimeMs/isoDateStringToUnixTimeMs.ts +6 -0
  67. package/src/utils/Date/isoDateStringToUnixTimeSec/isoDateStringToUnixTimeSec.ts +7 -0
  68. package/src/utils/Date/unixTimeSecToIsoDateString/unixTimeSecToIsoDateString.ts +6 -0
  69. package/src/utils/Deque/Deque.ts +530 -0
  70. package/src/utils/DeviceDetection/isTouchScreenDevice/isTouchScreenDevice.ts +16 -0
  71. package/src/utils/Error/rethrowError/rethrowError.ts +8 -0
  72. package/src/utils/Error/wrapError.ts +32 -0
  73. package/src/utils/Function/callFirstThenOther/callFirstThenOther.ts +24 -0
  74. package/src/utils/Function/callFunctions/callFunctions.ts +11 -0
  75. package/src/utils/Function/callTimes/callTimes.ts +5 -0
  76. package/src/utils/Function/isFunction.ts +3 -0
  77. package/src/utils/Function/noop/index.ts +4 -0
  78. package/src/utils/Function/once/once.ts +32 -0
  79. package/src/utils/Function/subscribeUpdatesWithTimeout/index.ts +44 -0
  80. package/src/utils/Function/throttleFunction/throttleFunction.ts +18 -0
  81. package/src/utils/Function/throttleWithPromiseFunction/throttleWithPromiseFunction.ts +19 -0
  82. package/src/utils/Function/tryCatch/tryCatch.ts +13 -0
  83. package/src/utils/Latch/Latch.ts +63 -0
  84. package/src/utils/Map/ObservableMap/ObservableMap.ts +55 -0
  85. package/src/utils/Map/findMapsDifferences/findMapsDifferences.ts +35 -0
  86. package/src/utils/Map/mapGetOrSet/mapGetOrSet.ts +7 -0
  87. package/src/utils/Map/mapMapToArray/mapMapToArray.ts +6 -0
  88. package/src/utils/Map/mapMapValues/mapMapValues.ts +9 -0
  89. package/src/utils/Math/createSimpleMovingAverageSeries/createSimpleMovingAverageSeries.ts +22 -0
  90. package/src/utils/Math/mean/mean.ts +14 -0
  91. package/src/utils/Math/simpleMovingAverageUsingAccFabric/simpleMovingAverageUsingAccFabric.ts +29 -0
  92. package/src/utils/Math/sum/sum.ts +45 -0
  93. package/src/utils/MinHeap/MinHeap.ts +88 -0
  94. package/src/utils/MinHeapUniqueNumber/MinHeapUniqueNumber.ts +105 -0
  95. package/src/utils/MinMaxHeap/MinMaxHeap.ts +91 -0
  96. package/src/utils/Number/collectIntegerSequences/collectIntegerSequences.ts +36 -0
  97. package/src/utils/Number/numberToFixedPrecision/numberToFixedPrecision.ts +13 -0
  98. package/src/utils/Object/cloneObject/cloneObject.ts +3 -0
  99. package/src/utils/Object/deepEqual/deepEqual.ts +45 -0
  100. package/src/utils/Object/deleteUndefinedProperties/index.ts +13 -0
  101. package/src/utils/Object/entriesToObject/entriesToObject.ts +12 -0
  102. package/src/utils/Object/filterObject/filterObject.ts +18 -0
  103. package/src/utils/Object/forOwn/forOwn.ts +12 -0
  104. package/src/utils/Object/getObjectEntries/getObjectEntries.ts +3 -0
  105. package/src/utils/Object/getObjectKeys/getObjectKeys.ts +3 -0
  106. package/src/utils/Object/getObjectValues/index.ts +3 -0
  107. package/src/utils/Object/hasOwnProperty/hasOwnProperty.ts +3 -0
  108. package/src/utils/Object/invertObject/InvertedObject.ts +3 -0
  109. package/src/utils/Object/invertObject/invertObject.ts +15 -0
  110. package/src/utils/Object/isEmptyObject/index.ts +5 -0
  111. package/src/utils/Object/isObject/index.ts +8 -0
  112. package/src/utils/Object/mapObjectKeys/mapObjectKeys.ts +25 -0
  113. package/src/utils/Object/mapObjectValues/mapObjectValues.ts +16 -0
  114. package/src/utils/Object/mirrorObject/ObjectKeysMirror.ts +1 -0
  115. package/src/utils/Object/mirrorObject/mirrorObject.ts +7 -0
  116. package/src/utils/Pagination/DEFAULT_PAGE.ts +1 -0
  117. package/src/utils/Pagination/calculatePaginationParameters.ts +29 -0
  118. package/src/utils/Promise/promiseAll/promiseAll.ts +6 -0
  119. package/src/utils/Promise/restrictParallelCalls/restrictParallelCalls.ts +18 -0
  120. package/src/utils/Ranges/checkRangesAdjacent/checkRangesAdjacent.ts +23 -0
  121. package/src/utils/Ranges/checkRangesIntersection/checkRangesIntersection.ts +8 -0
  122. package/src/utils/Ranges/excludeRanges/excludeRanges.ts +42 -0
  123. package/src/utils/Ranges/getDistanceToRange/getDistanceToRange.ts +14 -0
  124. package/src/utils/Ranges/isRangeWithinRanges.ts +14 -0
  125. package/src/utils/Ranges/mapDateRangeToISODateStringRange/mapDateRangeToISODateStringRange.ts +7 -0
  126. package/src/utils/Ranges/mapISODateStringRangeToUnixTimeMsRange/mapISODateStringRangeToUnixTimeMsRange.ts +8 -0
  127. package/src/utils/Ranges/mapRange/mapRange.ts +13 -0
  128. package/src/utils/Ranges/mapUnixTimeMsRangeToISODateStringRange/mapUnixTimeMsRangeToISODateStringRange.ts +8 -0
  129. package/src/utils/Ranges/mergeRanges/mergeRanges.ts +34 -0
  130. package/src/utils/Signal/Signal.ts +47 -0
  131. package/src/utils/Signal/SignalCallback.ts +1 -0
  132. package/src/utils/Signal/combineSignalsIntoNewOne/combineSignalsIntoNewOne.ts +75 -0
  133. package/src/utils/Signal/subscribeSignalAndCallWithCurrentValue/subscribeSignalAndCallWithCurrentValue.ts +7 -0
  134. package/src/utils/Signal/useSignal.ts +10 -0
  135. package/src/utils/String/HexString/HEX_SYMBOLS.ts +1 -0
  136. package/src/utils/String/HexString/HexString.ts +2 -0
  137. package/src/utils/String/HexString/isHexString.ts +16 -0
  138. package/src/utils/String/NonEmptyString/NonEmptyString.ts +22 -0
  139. package/src/utils/String/endsWith/index.ts +6 -0
  140. package/src/utils/String/isString.ts +3 -0
  141. package/src/utils/binarySearch/binarySearch.ts +20 -0
  142. package/src/utils/binarySearchClosest/binarySearchClosest.ts +43 -0
  143. package/src/utils/createIncrementalIntegerGenerator.ts +7 -0
  144. package/src/utils/createRemoteDataProcessingWindow/createRemoteDataProcessingWindow.ts +157 -0
  145. package/src/utils/createSimultaneousOperationsHandler/createSimultaneousOperationsHandler.ts +65 -0
  146. package/src/utils/encryptDecryptString/encryptDecryptString.ts +34 -0
  147. package/src/utils/getPrimeNumbersWithEratosthenesSieve/getPrimeNumbersWithEratosthenesSieve.ts +21 -0
  148. package/src/utils/isPromise/isPromise.ts +30 -0
  149. package/src/utils/makeAsyncFunctionCallsSimultaneous/makeAsyncFunctionCallsSimultaneous.ts +64 -0
  150. package/src/utils/parallelsLimitPromise/index.ts +28 -0
  151. package/src/utils/parallelsLimitQueue/parallelsLimitQueue.ts +69 -0
  152. package/src/utils/prettyStringify/index.ts +3 -0
  153. package/src/utils/random/fnv1a/fnv1a.ts +87 -0
  154. package/src/utils/random/generateHashedFloats/generateHashedFloats.ts +28 -0
  155. package/src/utils/random/getRandomIntegerInARange/getRandomIntegerInARange.ts +3 -0
  156. package/src/utils/random/getSampleIndexByStringHash/getSampleIndexByStringHash.ts +10 -0
  157. package/src/utils/random/randomBoolean/randomBoolean.ts +3 -0
  158. package/src/utils/random/randomHexString/randomHexString.ts +12 -0
  159. package/src/utils/requestAnimationFrame/requestAnimationFramePromise/requestAnimationFramePromise.ts +7 -0
  160. package/src/utils/requestAnimationFrame/requestAnimationFrameThrottle/requestAnimationFrameThrottle.ts +6 -0
  161. package/src/utils/retryFunctionWrapper/retryFunctionWrapper.ts +40 -0
  162. package/src/utils/runParallelTimescalesProcessing/runParallelTimescalesProcessing.ts +113 -0
  163. package/src/utils/stringifyError.ts +3 -0
  164. package/src/utils/timers/promiseTimeout/promiseTimeout.ts +26 -0
  165. package/src/utils/timers/subscribeSyntheticInterval/subscribeSyntheticInterval.ts +47 -0
  166. package/src/utils/waitForFunction/waitForFunction.ts +50 -0
@@ -0,0 +1,36 @@
1
+ import { Integer } from '../../../types/Number/Integer';
2
+ import { PositiveInteger } from '../../../types/Number/PositiveInteger';
3
+ import { UnsignedInteger } from '../../../types/Number/UnsignedInteger';
4
+
5
+ type IntegerSequence = {
6
+ start: UnsignedInteger;
7
+ length: PositiveInteger;
8
+ };
9
+
10
+ export function collectIntegerSequences(integers: Integer[]): IntegerSequence[] {
11
+ if (!integers.length) {
12
+ return [];
13
+ }
14
+
15
+ const sequences: IntegerSequence[] = [
16
+ {
17
+ start: integers[0],
18
+ length: 1,
19
+ },
20
+ ];
21
+
22
+ for (let i = 1; i < integers.length; i += 1) {
23
+ const lastSequence = sequences.at(-1)!;
24
+
25
+ if (lastSequence.start + lastSequence.length === integers[i]) {
26
+ lastSequence.length += 1;
27
+ } else {
28
+ sequences.push({
29
+ start: integers[i],
30
+ length: 1,
31
+ });
32
+ }
33
+ }
34
+
35
+ return sequences;
36
+ }
@@ -0,0 +1,13 @@
1
+ export function numberToFixedPrecision(number: number, precision = 4): string {
2
+ // Handle zero as a special case since Math.log10(0) returns -Infinity
3
+ if (number === 0) {
4
+ return '0';
5
+ }
6
+
7
+ const absNumber = Math.abs(number);
8
+ const log10 = Math.log10(absNumber);
9
+ const log10Int = Math.floor(log10);
10
+ const toFixed = Math.max(0, precision - log10Int);
11
+
12
+ return number.toFixed(toFixed);
13
+ }
@@ -0,0 +1,3 @@
1
+ export function cloneObject<T>(object: T): T {
2
+ return structuredClone(object);
3
+ }
@@ -0,0 +1,45 @@
1
+ import { isObject } from '../../../types/Object/Object';
2
+ import { getObjectKeys } from '../getObjectKeys/getObjectKeys';
3
+
4
+ /**
5
+ * Код взят отсюда https://gist.github.com/egardner/efd34f270cc33db67c0246e837689cb9
6
+ *
7
+ * Функция подходит только для сравнения объектов и массивов любой вложенности с примитивами внутри
8
+ *
9
+ * Не подходит для сравнения сложных объектов типа Date, Function, RegExp и т.п.
10
+ * Воспринимает их как простые объекты и сравнивает собственные перечисляемые свойства
11
+ *
12
+ * Выдает false при сравнении двух NaN
13
+ */
14
+ export function deepEqual<T>(actual: unknown, expected: T): actual is T {
15
+ if (actual === expected) {
16
+ return true;
17
+ }
18
+
19
+ if (!isObject(actual) || !isObject(expected)) {
20
+ return false;
21
+ }
22
+
23
+ if (Array.isArray(actual) !== Array.isArray(expected)) {
24
+ return false;
25
+ }
26
+
27
+ const actualKeys = getObjectKeys(actual);
28
+ const expectedKeys = getObjectKeys(expected);
29
+
30
+ if (actualKeys.length !== expectedKeys.length) {
31
+ return false;
32
+ }
33
+
34
+ for (const key of expectedKeys) {
35
+ if (!((key as string) in actual)) {
36
+ return false;
37
+ }
38
+
39
+ if (!deepEqual((actual as T)[key as keyof T], expected[key])) {
40
+ return false;
41
+ }
42
+ }
43
+
44
+ return true;
45
+ }
@@ -0,0 +1,13 @@
1
+ import { hasOwnProperty } from '../hasOwnProperty/hasOwnProperty';
2
+
3
+ export function deleteUndefinedProperties<T extends Record<string, unknown>>(obj: T): Partial<T> {
4
+ const result: Partial<T> = {};
5
+
6
+ for (const key in obj) {
7
+ if (hasOwnProperty(obj, key) && obj[key] !== undefined) {
8
+ result[key] = obj[key];
9
+ }
10
+ }
11
+
12
+ return result;
13
+ }
@@ -0,0 +1,12 @@
1
+ export function entriesToObject<Key extends string, Value>(entries: [Key, Value][]): Record<Key, Value> {
2
+ const object = {} as Record<Key, Value>;
3
+
4
+ entries.forEach(([
5
+ key,
6
+ value,
7
+ ]) => {
8
+ object[key] = value;
9
+ });
10
+
11
+ return object;
12
+ }
@@ -0,0 +1,18 @@
1
+ import { getObjectKeys } from '../getObjectKeys/getObjectKeys';
2
+
3
+ export function filterObject<O extends Record<string, unknown>>(
4
+ object: O,
5
+ filterFunction: (value: O[keyof O], key: keyof O) => boolean
6
+ ): O {
7
+ const resultObject = {} as O;
8
+
9
+ getObjectKeys(object).forEach((key) => {
10
+ const shouldRemainProperty = filterFunction(object[key], key);
11
+
12
+ if (shouldRemainProperty) {
13
+ resultObject[key] = object[key];
14
+ }
15
+ });
16
+
17
+ return resultObject;
18
+ }
@@ -0,0 +1,12 @@
1
+ import { hasOwnProperty } from '../hasOwnProperty/hasOwnProperty';
2
+
3
+ export function forOwn<Obj extends {}>(
4
+ obj: Obj,
5
+ fn: (value: Obj[keyof Obj], key: keyof Obj, sourceObj: Obj) => void
6
+ ): void {
7
+ for (const key in obj) {
8
+ if (hasOwnProperty(obj, key)) {
9
+ fn(obj[key], key, obj);
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ export function getObjectEntries<Key extends string, Value>(object: Record<Key, Value>): [Key, Value][] {
2
+ return Object.entries(object) as [Key, Value][];
3
+ }
@@ -0,0 +1,3 @@
1
+ export function getObjectKeys<T extends Record<string, unknown>>(object: T): (keyof T)[] {
2
+ return Object.keys(object);
3
+ }
@@ -0,0 +1,3 @@
1
+ export function getObjectValues<T extends Record<string, unknown>>(object: T): T[keyof T][] {
2
+ return Object.values(object) as T[keyof T][];
3
+ }
@@ -0,0 +1,3 @@
1
+ export function hasOwnProperty<O>(obj: O, key: string | number | symbol): key is keyof O {
2
+ return Object.prototype.hasOwnProperty.call(obj, key);
3
+ }
@@ -0,0 +1,3 @@
1
+ export type InvertedObject<T extends Record<string, string>> = {
2
+ [key in T[keyof T]]: keyof T;
3
+ };
@@ -0,0 +1,15 @@
1
+ import { InvertedObject } from './InvertedObject';
2
+
3
+ export function invertObject<T extends Record<string, string>>(object: T): InvertedObject<T> {
4
+ const nextObject = {} as InvertedObject<T>;
5
+
6
+ for (const key in object) {
7
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
8
+ const value = object[key];
9
+
10
+ (nextObject as Record<T[keyof T], keyof T>)[value] = key;
11
+ }
12
+ }
13
+
14
+ return nextObject;
15
+ }
@@ -0,0 +1,5 @@
1
+ import { getObjectKeys } from '../getObjectKeys/getObjectKeys';
2
+
3
+ export function isEmptyObject<T extends Record<string, unknown>>(object: T): boolean {
4
+ return !getObjectKeys(object).length;
5
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns 'true' if {@param value} is {@type object}
3
+ */
4
+ export function isObject<T extends Record<string, unknown> = Record<string, unknown>>(value: unknown): value is T {
5
+ const type = typeof value;
6
+
7
+ return Boolean(value) && (type === 'object' || type === 'function');
8
+ }
@@ -0,0 +1,25 @@
1
+ import { getObjectKeys } from '../getObjectKeys/getObjectKeys';
2
+
3
+ /**
4
+ * Функция принимает на вход первым агрументом объект и прогоняет все собственные свойства
5
+ * (ключ и значение в качестве аргументов) через функцию, которая приходит вторым аргументом.
6
+ * Эта функция для каждого свойства должна вернуть новый ключ для
7
+ * конкретного значения объекта.
8
+ *
9
+ * Функция возвращает новый объект, со старыми значениями и новыми ключами.
10
+ */
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ export function mapObjectKeys<T extends Record<string, any>, S extends string>(
13
+ object: T,
14
+ mapFunction: (key: keyof T, value: T[keyof T]) => S
15
+ ): Record<S, T[keyof T]> {
16
+ const resultObject = {} as Record<S, T[keyof T]>;
17
+
18
+ getObjectKeys(object).forEach((key) => {
19
+ const newKey = mapFunction(key, object[key]);
20
+
21
+ resultObject[newKey] = object[key];
22
+ });
23
+
24
+ return resultObject;
25
+ }
@@ -0,0 +1,16 @@
1
+ import { getObjectKeys } from '../getObjectKeys/getObjectKeys';
2
+
3
+ export function mapObjectValues<
4
+ T extends Record<string, unknown>,
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- only for util snd better typing
6
+ TMapFunc extends (value: T[keyof T], key: keyof T) => any,
7
+ R extends { [P in keyof T]: ReturnType<TMapFunc> },
8
+ >(object: T, mapFunction: TMapFunc): R {
9
+ const resultObject = {} as Record<string, unknown>;
10
+
11
+ getObjectKeys(object).forEach((key) => {
12
+ resultObject[key as string] = mapFunction(object[key], key);
13
+ });
14
+
15
+ return resultObject as R;
16
+ }
@@ -0,0 +1 @@
1
+ export type ObjectKeysMirror<T extends Record<string, unknown>> = { [key in keyof T]: key };
@@ -0,0 +1,7 @@
1
+ import { mapObjectValues } from '../mapObjectValues/mapObjectValues';
2
+
3
+ import { ObjectKeysMirror } from './ObjectKeysMirror';
4
+
5
+ export function mirrorObject<T extends Record<string, unknown>>(object: T): ObjectKeysMirror<T> {
6
+ return mapObjectValues(object, (_value, key) => key) as ObjectKeysMirror<T>;
7
+ }
@@ -0,0 +1 @@
1
+ export const DEFAULT_PAGE = 1;
@@ -0,0 +1,29 @@
1
+ import { PositiveInteger } from '../../types/Number/PositiveInteger';
2
+ import { UnsignedInteger } from '../../types/Number/UnsignedInteger';
3
+
4
+ import { DEFAULT_PAGE } from './DEFAULT_PAGE';
5
+
6
+ export const calculatePaginationParameters = ({
7
+ page,
8
+ pageSize,
9
+ totalCount,
10
+ }: {
11
+ page: UnsignedInteger;
12
+ pageSize: PositiveInteger;
13
+ totalCount: UnsignedInteger;
14
+ }): {
15
+ canGoToPreviousPage: boolean;
16
+ canGoToNextPage: boolean;
17
+ totalPages: UnsignedInteger;
18
+ } => {
19
+ const canGoToPreviousPage = page > DEFAULT_PAGE;
20
+
21
+ const totalPages = Math.ceil(totalCount / pageSize);
22
+ const isLastPage = page >= totalPages;
23
+
24
+ return {
25
+ canGoToPreviousPage,
26
+ canGoToNextPage: !isLastPage,
27
+ totalPages,
28
+ };
29
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Type-safe version of Promise.all(...)
3
+ */
4
+ export function promiseAll<T extends unknown[]>(promises: T): Promise<{ [K in keyof T]: Awaited<T[K]> }> {
5
+ return Promise.all(promises);
6
+ }
@@ -0,0 +1,18 @@
1
+ import { AnyAsyncFunction } from '../../../types/any/AnyAsyncFunction';
2
+
3
+ export function restrictParallelCalls<T extends AnyAsyncFunction>(callback: T, errorMessage?: string): T {
4
+ let isRunning = false;
5
+
6
+ return ((...args: Parameters<T>) => {
7
+ if (isRunning) {
8
+ throw new Error(`restrictParallelCalls${errorMessage ? ` errorMessage=[${errorMessage}]` : ''} previous call is not finished, do not call function in parallel`);
9
+ }
10
+
11
+ isRunning = true;
12
+ const promise = callback(...args);
13
+
14
+ return promise.finally(() => {
15
+ isRunning = false;
16
+ });
17
+ }) as T;
18
+ }
@@ -0,0 +1,23 @@
1
+ import { RangeTuple } from '../../../types/RangeTuple';
2
+
3
+ export function checkRangesAdjacent(
4
+ range1: RangeTuple<number>,
5
+ range2: RangeTuple<number>
6
+ ): boolean {
7
+ const [
8
+ min1,
9
+ max1,
10
+ ] = [
11
+ Math.min(range1[0], range1[1]),
12
+ Math.max(range1[0], range1[1]),
13
+ ];
14
+ const [
15
+ min2,
16
+ max2,
17
+ ] = [
18
+ Math.min(range2[0], range2[1]),
19
+ Math.max(range2[0], range2[1]),
20
+ ];
21
+
22
+ return max1 === min2 || max2 === min1;
23
+ }
@@ -0,0 +1,8 @@
1
+ import { RangeTuple } from '../../../types/RangeTuple';
2
+
3
+ export function checkRangesIntersection(
4
+ range1: RangeTuple<number>,
5
+ range2: RangeTuple<number>
6
+ ): boolean {
7
+ return range1[0] < range2[1] && range1[1] > range2[0];
8
+ }
@@ -0,0 +1,42 @@
1
+ type Range = [number, number];
2
+
3
+ export function excludeRanges(initialRange: Range, sortedRangesToExclude: Range[]): Range[] {
4
+ const [
5
+ start,
6
+ end,
7
+ ] = initialRange;
8
+
9
+ const result: Range[] = [];
10
+ let currentNumber = start;
11
+
12
+ for (const [
13
+ meetingStart,
14
+ meetingEnd,
15
+ ] of sortedRangesToExclude) {
16
+ if (meetingStart >= end) {
17
+ break;
18
+ }
19
+
20
+ if (meetingEnd <= start) {
21
+ continue;
22
+ }
23
+
24
+ if (meetingStart > currentNumber) {
25
+ result.push([
26
+ currentNumber,
27
+ meetingStart,
28
+ ]);
29
+ }
30
+
31
+ currentNumber = Math.max(currentNumber, meetingEnd);
32
+ }
33
+
34
+ if (currentNumber < end) {
35
+ result.push([
36
+ currentNumber,
37
+ end,
38
+ ]);
39
+ }
40
+
41
+ return result;
42
+ }
@@ -0,0 +1,14 @@
1
+ import { FiniteNumber } from '../../../types/Number/FiniteNumber';
2
+ import { RangeTuple } from '../../../types/RangeTuple';
3
+
4
+ export function getDistanceToRange(range: RangeTuple<FiniteNumber>, value: FiniteNumber): FiniteNumber {
5
+ if (value >= range[0] && value <= range[1]) {
6
+ return 0;
7
+ }
8
+
9
+ if (value < range[0]) {
10
+ return range[0] - value;
11
+ }
12
+
13
+ return range[1] - value;
14
+ }
@@ -0,0 +1,14 @@
1
+ type Range = [number, number];
2
+
3
+ export function isRangeWithinRanges(range: Range, ranges: Range[]) {
4
+ for (const [
5
+ start,
6
+ end,
7
+ ] of ranges) {
8
+ if (start <= range[0] && range[1] <= end) {
9
+ return true;
10
+ }
11
+ }
12
+
13
+ return false;
14
+ }
@@ -0,0 +1,7 @@
1
+ import { RangeTuple } from '../../../types/RangeTuple';
2
+ import { ISODateString } from '../../../types/Time/ISODateString/ISODateString';
3
+ import { mapRange } from '../mapRange/mapRange';
4
+
5
+ export function mapDateRangeToISODateStringRange(range: RangeTuple<Date>): RangeTuple<ISODateString> {
6
+ return mapRange(range, (date) => date.toISOString());
7
+ }
@@ -0,0 +1,8 @@
1
+ import { RangeTuple } from '../../../types/RangeTuple';
2
+ import { ISODateString } from '../../../types/Time/ISODateString/ISODateString';
3
+ import { UnixTimeMs } from '../../../types/Time/UnixTimeMs';
4
+ import { mapRange } from '../mapRange/mapRange';
5
+
6
+ export function mapISODateStringRangeToUnixTimeMsRange(range: RangeTuple<ISODateString>): RangeTuple<UnixTimeMs> {
7
+ return mapRange(range, (isoDateString) => new Date(isoDateString).getTime());
8
+ }
@@ -0,0 +1,13 @@
1
+ import { RangeTuple } from '../../../types/RangeTuple';
2
+
3
+ export function mapRange<A, F extends (
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ a: A, index: 0 | 1) => any, B extends ReturnType<F>>(
6
+ range: RangeTuple<A>,
7
+ func: F
8
+ ): RangeTuple<B> {
9
+ return [
10
+ func(range[0], 0),
11
+ func(range[1], 1),
12
+ ];
13
+ }
@@ -0,0 +1,8 @@
1
+ import { RangeTuple } from '../../../types/RangeTuple';
2
+ import { ISODateString } from '../../../types/Time/ISODateString/ISODateString';
3
+ import { UnixTimeMs } from '../../../types/Time/UnixTimeMs';
4
+ import { mapRange } from '../mapRange/mapRange';
5
+
6
+ export function mapUnixTimeMsRangeToISODateStringRange(range: RangeTuple<UnixTimeMs>): RangeTuple<ISODateString> {
7
+ return mapRange(range, (timestamp) => new Date(timestamp).toISOString());
8
+ }
@@ -0,0 +1,34 @@
1
+ type Range = [number, number];
2
+
3
+ export function mergeRanges(ranges: Range[]): Range[] {
4
+ if (!ranges.length) {
5
+ return [];
6
+ }
7
+
8
+ const stack: Range[] = [];
9
+
10
+ const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
11
+
12
+ const firstRange = sorted[0];
13
+
14
+ stack.push([
15
+ firstRange[0],
16
+ firstRange[1],
17
+ ]);
18
+
19
+ for (let i = 1; i < sorted.length; i++) {
20
+ const range = sorted[i];
21
+ const lastRange = stack.at(-1)!;
22
+
23
+ if (lastRange[1] < range[0]) {
24
+ stack.push([
25
+ range[0],
26
+ range[1],
27
+ ]);
28
+ } else if (lastRange[1] < range[1]) {
29
+ lastRange[1] = range[1];
30
+ }
31
+ }
32
+
33
+ return stack;
34
+ }
@@ -0,0 +1,47 @@
1
+ import { SignalCallback } from './SignalCallback';
2
+
3
+ /**
4
+ * EventEmitter with consistent value, alternative to BehaviorSubject from RxJS
5
+ *
6
+ * This class has been designed on a base of SolidJS reactive signal pattern https://www.solidjs.com/docs/latest/api#createsignal
7
+ * and signal-js EventEmitter library https://www.npmjs.com/package/signal-js
8
+ *
9
+ * Allows to create and combine business logic into reactive Signals and use them in React.context via useSignal hook
10
+ */
11
+ export class Signal<T> {
12
+ private readonly callbacks: Set<SignalCallback<T>> = new Set<SignalCallback<T>>();
13
+
14
+ public constructor(
15
+ private _value: T,
16
+ private readonly checkToEqualFunction: (currentValue: T, nextValue: T) => boolean = (currentValue, nextValue) =>
17
+ currentValue === nextValue
18
+ ) { }
19
+
20
+ public value(): T {
21
+ return this._value;
22
+ }
23
+
24
+ public subscribe(callback: SignalCallback<T>): VoidFunction {
25
+ this.callbacks.add(callback);
26
+
27
+ return () => {
28
+ this.unsubscribe(callback);
29
+ };
30
+ }
31
+
32
+ public next(nextValue: T): void {
33
+ if (this.checkToEqualFunction(this._value, nextValue)) {
34
+ return;
35
+ }
36
+
37
+ this._value = nextValue;
38
+
39
+ for (const callback of this.callbacks.values()) {
40
+ callback(nextValue);
41
+ }
42
+ }
43
+
44
+ public unsubscribe(callback: SignalCallback<T>): void {
45
+ this.callbacks.delete(callback);
46
+ }
47
+ }
@@ -0,0 +1 @@
1
+ export type SignalCallback<T> = (this: unknown, param: T) => void;
@@ -0,0 +1,75 @@
1
+ import { Signal } from '../Signal';
2
+
3
+ export type CombineSignalsIntoNewOneResult<T> = {
4
+ signal: Signal<T>;
5
+ teardown: VoidFunction;
6
+ };
7
+
8
+ export function combineSignalsIntoNewOne<T, A, B, C, D, E, F, G>(
9
+ signals: [Signal<A>, Signal<B>, Signal<C>, Signal<D>, Signal<E>, Signal<F>, Signal<G>],
10
+ combinator: (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => T,
11
+ checkToEqualFunction?: (currentValue: T, nextValue: T) => boolean,
12
+ ): CombineSignalsIntoNewOneResult<T>;
13
+
14
+ export function combineSignalsIntoNewOne<T, A, B, C, D, E, F>(
15
+ signals: [Signal<A>, Signal<B>, Signal<C>, Signal<D>, Signal<E>, Signal<F>],
16
+ combinator: (a: A, b: B, c: C, d: D, e: E, f: F) => T,
17
+ checkToEqualFunction?: (currentValue: T, nextValue: T) => boolean,
18
+ ): CombineSignalsIntoNewOneResult<T>;
19
+
20
+ export function combineSignalsIntoNewOne<T, A, B, C, D, E>(
21
+ signals: [Signal<A>, Signal<B>, Signal<C>, Signal<D>, Signal<E>],
22
+ combinator: (a: A, b: B, c: C, d: D, e: E) => T,
23
+ checkToEqualFunction?: (currentValue: T, nextValue: T) => boolean,
24
+ ): CombineSignalsIntoNewOneResult<T>;
25
+
26
+ export function combineSignalsIntoNewOne<T, A, B, C, D>(
27
+ signals: [Signal<A>, Signal<B>, Signal<C>, Signal<D>],
28
+ combinator: (a: A, b: B, c: C, d: D) => T,
29
+ checkToEqualFunction?: (currentValue: T, nextValue: T) => boolean,
30
+ ): CombineSignalsIntoNewOneResult<T>;
31
+
32
+ export function combineSignalsIntoNewOne<T, A, B, C>(
33
+ signals: [Signal<A>, Signal<B>, Signal<C>],
34
+ combinator: (a: A, b: B, c: C) => T,
35
+ checkToEqualFunction?: (currentValue: T, nextValue: T) => boolean,
36
+ ): CombineSignalsIntoNewOneResult<T>;
37
+
38
+ export function combineSignalsIntoNewOne<T, A, B>(
39
+ signals: [Signal<A>, Signal<B>],
40
+ combinator: (a: A, b: B) => T,
41
+ checkToEqualFunction?: (currentValue: T, nextValue: T) => boolean,
42
+ ): CombineSignalsIntoNewOneResult<T>;
43
+
44
+ export function combineSignalsIntoNewOne<T, A>(
45
+ signals: [Signal<A>],
46
+ combinator: (a: A) => T,
47
+ checkToEqualFunction?: (currentValue: T, nextValue: T) => boolean,
48
+ ): CombineSignalsIntoNewOneResult<T>;
49
+
50
+ export function combineSignalsIntoNewOne<T>(
51
+ signals: Signal<unknown>[],
52
+ combinator: (...args: unknown[]) => T,
53
+ checkToEqualFunction?: (currentValue: T, nextValue: T) => boolean
54
+ ): CombineSignalsIntoNewOneResult<T> {
55
+ const getAllValues = () => signals.map((signal) => signal.value());
56
+
57
+ const initialValue = combinator(...getAllValues());
58
+ const combinedSignal = new Signal(initialValue, checkToEqualFunction);
59
+
60
+ const unsubscribeFunctions: VoidFunction[] = signals.map((signal) =>
61
+ signal.subscribe(() => {
62
+ const nextValue = combinator(...getAllValues());
63
+
64
+ combinedSignal.next(nextValue);
65
+ }));
66
+
67
+ return {
68
+ signal: combinedSignal,
69
+ teardown() {
70
+ unsubscribeFunctions.forEach((unsubscribeFunction) => {
71
+ unsubscribeFunction();
72
+ });
73
+ },
74
+ };
75
+ }
@@ -0,0 +1,7 @@
1
+ import { Signal } from '../Signal';
2
+
3
+ export function subscribeSignalAndCallWithCurrentValue<T>(signal: Signal<T>, callback: (value: T) => void): VoidFunction {
4
+ callback(signal.value());
5
+
6
+ return signal.subscribe(callback);
7
+ }