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,28 @@
1
+ /**
2
+ * Целое неотрицательное число
3
+ */
4
+ export type UnsignedInteger = number;
5
+
6
+ export function isUnsignedInteger(value: unknown): value is UnsignedInteger {
7
+ if (!Number.isInteger(value)) {
8
+ return false;
9
+ }
10
+
11
+ return (value as UnsignedInteger) >= 0;
12
+ }
13
+
14
+ export function assertUnsignedInteger(number: unknown, errorMessage: string = ''): asserts number is UnsignedInteger {
15
+ if (!isUnsignedInteger(number)) {
16
+ throw new Error(`Expected unsigned integer (whole number >= 0), got ${number}${errorMessage ? ` errorMessage=[${errorMessage}]` : ''}`);
17
+ }
18
+ }
19
+
20
+ export function convertAndAssertUnsignedInteger(value: unknown): UnsignedInteger {
21
+ const result = Number(value);
22
+
23
+ if (isUnsignedInteger(result)) {
24
+ return result;
25
+ }
26
+
27
+ throw new Error(`value=[${value}] is not unsigned integer`);
28
+ }
@@ -0,0 +1,20 @@
1
+ export function isObject<T extends Record<string, unknown> = Record<string, unknown>>(value: unknown): value is T {
2
+ const type = typeof value;
3
+
4
+ return Boolean(value) && (type === 'object' || type === 'function');
5
+ }
6
+
7
+ export function assertObject<T extends Record<string, unknown> = Record<string, unknown>>(
8
+ value: unknown,
9
+ message?: string
10
+ ): asserts value is T {
11
+ if (!isObject(value)) {
12
+ let errorMessage = 'assertObject error';
13
+
14
+ if (message !== undefined) {
15
+ errorMessage += ` message=[${message}]`;
16
+ }
17
+
18
+ throw new Error(errorMessage);
19
+ }
20
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Доля в процентах от 0 до 100
3
+ */
4
+ export type Percent = number;
@@ -0,0 +1,9 @@
1
+ import { Pixels } from './Pixels';
2
+
3
+ /**
4
+ * Позиция чего-либо в пикселях
5
+ */
6
+ export type PixelPosition = {
7
+ x: Pixels;
8
+ y: Pixels;
9
+ };
@@ -0,0 +1,9 @@
1
+ import { Pixels } from './Pixels';
2
+
3
+ /**
4
+ * Размеры чего-либо в пикселях
5
+ */
6
+ export type PixelSize = {
7
+ width: Pixels;
8
+ height: Pixels;
9
+ };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Размер в пикселях
3
+ */
4
+ export type Pixels = number;
@@ -0,0 +1 @@
1
+ export type RangeTuple<T> = [from: T, to: T];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @deprecated
3
+ * use PixelSize or another strict type
4
+ */
5
+ export type Size = {
6
+ width: number;
7
+ height: number;
8
+ };
@@ -0,0 +1,6 @@
1
+ import { Integer } from '../Number/Integer';
2
+
3
+ /**
4
+ * Количество дней
5
+ */
6
+ export type DaysCount = Integer;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Время в часах
3
+ */
4
+ export type Hours = number;
@@ -0,0 +1,16 @@
1
+ // use date.toISOString() method to convert date to this type
2
+
3
+ // 💁‍♂️ 2025-01-01T07:29:12.263Z
4
+ export type ISODateString = ReturnType<Date['toISOString']>;
5
+
6
+ export function isISODateString(date: string): boolean {
7
+ const parsedDate = new Date(date);
8
+
9
+ return !isNaN(parsedDate.getTime()) && date === parsedDate.toISOString();
10
+ }
11
+
12
+ export function assertISODateString(date: string, errorMessage?: string): asserts date is ISODateString {
13
+ if (!isISODateString(date)) {
14
+ throw new Error(`date=[${date}] is not a valid ISO date string${errorMessage ? ` errorMessage=[${errorMessage}]` : ''}`);
15
+ }
16
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Время в миллисекундах
3
+ */
4
+ export type Milliseconds = number;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Время в минутах
3
+ */
4
+ export type Minutes = number;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Time in seconds
3
+ * Could be non integer
4
+ */
5
+ export type Seconds = number;
@@ -0,0 +1,13 @@
1
+ import { Hours } from './Hours';
2
+ import { Milliseconds } from './Milliseconds';
3
+ import { Minutes } from './Minutes';
4
+ import { Seconds } from './Seconds';
5
+
6
+ export const MS_IN_SEC: Milliseconds = 1000;
7
+ export const SEC_IN_MIN: Seconds = 60;
8
+ export const MIN_IN_HOUR: Minutes = 60;
9
+ export const HOUR_IN_DAY: Hours = 24;
10
+
11
+ export const SEC_IN_HOUR: Seconds = MIN_IN_HOUR * SEC_IN_MIN;
12
+ export const SEC_IN_DAY: Seconds = HOUR_IN_DAY * SEC_IN_HOUR;
13
+ export const MS_IN_DAY: Milliseconds = SEC_IN_DAY * MS_IN_SEC;
@@ -0,0 +1,6 @@
1
+ import { Milliseconds } from './Milliseconds';
2
+
3
+ /**
4
+ * Тип для js-таймстампа в мс (с начала эпохи)
5
+ */
6
+ export type Timestamp = Milliseconds;
@@ -0,0 +1,6 @@
1
+ import { Milliseconds } from './Milliseconds';
2
+
3
+ /**
4
+ * Количество миллисекунд, прошедших с 00:00:00 Thursday, 1 January 1970 по UTC
5
+ */
6
+ export type UnixTimeMs = Milliseconds;
@@ -0,0 +1,11 @@
1
+ import { Integer } from '../Number/Integer';
2
+
3
+ import { Seconds } from './Seconds';
4
+
5
+ /**
6
+ * https://en.wikipedia.org/wiki/Unix_time
7
+ *
8
+ * Number of seconds since 00:00:00 Thursday, 1 January 1970 UTC
9
+ * Always integer
10
+ */
11
+ export type UnixTimeSec = Seconds & Integer;
@@ -0,0 +1,24 @@
1
+ import { DaysCount } from './DaysCount';
2
+ import { Hours } from './Hours';
3
+ import { Milliseconds } from './Milliseconds';
4
+ import { Minutes } from './Minutes';
5
+ import { Seconds } from './Seconds';
6
+
7
+ export const DAYS_IN_NOT_LEAP_YEAR: DaysCount = 365;
8
+ export const DAYS_IN_WEEK: DaysCount = 7;
9
+ export const DAYS_IN_AVERAGE_MONTH: DaysCount = 7;
10
+
11
+ export const HOURS_IN_DAY: Hours = 24;
12
+
13
+ export const MINUTES_IN_HOUR: Minutes = 60;
14
+ export const MINUTES_IN_DAY: Minutes = MINUTES_IN_HOUR * HOURS_IN_DAY;
15
+ export const MINUTES_IN_WEEK: Minutes = MINUTES_IN_DAY * DAYS_IN_WEEK;
16
+
17
+ export const SECONDS_IN_MINUTE: Seconds = 60;
18
+ export const SECONDS_IN_HOUR: Seconds = SECONDS_IN_MINUTE * MINUTES_IN_HOUR;
19
+ export const SECONDS_IN_DAY: Seconds = SECONDS_IN_HOUR * HOURS_IN_DAY;
20
+ export const SECONDS_IN_YEAR: Seconds = SECONDS_IN_DAY * DAYS_IN_NOT_LEAP_YEAR;
21
+
22
+ export const MILLISECONDS_IN_SECOND: Milliseconds = 1000;
23
+ export const MILLISECONDS_IN_MINUTE: Milliseconds = MILLISECONDS_IN_SECOND * SECONDS_IN_MINUTE;
24
+ export const MILLISECONDS_IN_DAY: Milliseconds = HOURS_IN_DAY * MINUTES_IN_HOUR * SECONDS_IN_MINUTE * MILLISECONDS_IN_SECOND;
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export type AnyAsyncFunction = (...args: any[]) => Promise<any>;
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export type AnyFunction = (...args: any[]) => any;
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export const ANY_VALUE: any = undefined;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Функция используется для проверки, что переданный ей аргумент имеет тип
3
+ * never. Это позволяет на уровне статических проверок увидеть, что
4
+ * при изменении enum была пропущена обработка одного из вариантов.
5
+ *
6
+ * @example
7
+ * enum Test {
8
+ * one,
9
+ * two,
10
+ * tree
11
+ * }
12
+ *
13
+ * function success(arg: Test) {
14
+ * switch(arg) {
15
+ * case Test.one:
16
+ * case Test.two:
17
+ * case Test.tree: // <---
18
+ * return;
19
+ * default:
20
+ * isNever(arg);
21
+ * }
22
+ * }
23
+ *
24
+ * function fail(arg: Test) {
25
+ * switch(arg) {
26
+ * case Test.one:
27
+ * case Test.two:
28
+ * return;
29
+ * default:
30
+ * isNever(arg); <-- type error "Test.tree is not never"
31
+ * }
32
+ * }
33
+ */
34
+ export function isNever(_: never) {}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Used for checking type assertions
3
+ *
4
+ *
5
+ * type IsEqualUnion<T, U> = [T] extends [U] ? [U] extends [T] ? true : false : false;
6
+ *
7
+ * type StringLiteralA = 'a' | 'b' | 'c';
8
+ *
9
+ * type StringLiteralB = 'a' | 'b' | 'c';
10
+ *
11
+ * isTrue(ANY_VALUE as IsEqualUnion<StringLiteralA, StringLiteralB>);
12
+ */
13
+ export function isTrue(_: true) {}
@@ -0,0 +1,160 @@
1
+ import { PositiveInteger } from '../types/Number/PositiveInteger';
2
+ import { UnsignedInteger } from '../types/Number/UnsignedInteger';
3
+ import { UnixTimeMs } from '../types/Time/UnixTimeMs';
4
+
5
+ import { createIncrementalIntegerGenerator } from './createIncrementalIntegerGenerator';
6
+ import { callFunctions } from './Function/callFunctions/callFunctions';
7
+ import { Latch, LatchCallback } from './Latch/Latch';
8
+ import { Signal } from './Signal/Signal';
9
+
10
+ export type AbortableProcessAbortReason = string | undefined;
11
+
12
+ export type VisualizedProcessesTree = {
13
+ name: string;
14
+ id: UnsignedInteger;
15
+ status: string | undefined;
16
+ startTimestamp: UnixTimeMs;
17
+ children: VisualizedProcessesTree[];
18
+ };
19
+
20
+ export type VisualizedProcessesTreeChangeAdd = {
21
+ type: 'add';
22
+ id: PositiveInteger;
23
+ name: string;
24
+ startTimestamp: UnixTimeMs;
25
+ parentId: PositiveInteger;
26
+ };
27
+
28
+ export type VisualizedProcessesTreeChangeStatus = {
29
+ type: 'status';
30
+ id: PositiveInteger;
31
+ status: string | undefined;
32
+ };
33
+ export type VisualizedProcessesTreeChangeDelete = {
34
+ type: 'delete';
35
+ id: PositiveInteger;
36
+ };
37
+
38
+ export type VisualizedProcessesTreeChange =
39
+ | VisualizedProcessesTreeChangeAdd
40
+ | VisualizedProcessesTreeChangeStatus
41
+ | VisualizedProcessesTreeChangeDelete;
42
+
43
+ export type VisualizedProcessesTreeChangeCallback = (change: VisualizedProcessesTreeChange) => void;
44
+
45
+ const incrementalIntegerGenerator = createIncrementalIntegerGenerator();
46
+
47
+ export type AbortableProcessStatus = string;
48
+
49
+ export class AbortableProcess {
50
+ public readonly id = incrementalIntegerGenerator();
51
+
52
+ private readonly abortLatch = new Latch<AbortableProcessAbortReason>();
53
+
54
+ private readonly children = new Set<AbortableProcess>();
55
+
56
+ private readonly startTimestamp: UnixTimeMs = Date.now();
57
+
58
+ private _status = new Signal<AbortableProcessStatus>('');
59
+
60
+ private _visualizedProcessesTreeSubscribers = new Set<VisualizedProcessesTreeChangeCallback>();
61
+
62
+ public constructor(private readonly name: string) {
63
+ this.abortLatch.subscribe(() => {
64
+ this.dispatchVisualizedProcessesTreeChange({
65
+ type: 'delete',
66
+ id: this.id,
67
+ });
68
+ });
69
+
70
+ this._status.subscribe((nextStatus) => {
71
+ this.dispatchVisualizedProcessesTreeChange({
72
+ type: 'status',
73
+ id: this.id,
74
+ status: nextStatus,
75
+ });
76
+ });
77
+ }
78
+
79
+ public isAborted(): boolean {
80
+ return this.abortLatch.isDispatched();
81
+ }
82
+
83
+ public abort(reason: AbortableProcessAbortReason): void {
84
+ this.abortLatch.dispatch(reason);
85
+ }
86
+
87
+ public subscribeAbort(callback: LatchCallback<AbortableProcessAbortReason>): VoidFunction {
88
+ return this.abortLatch.subscribe(callback);
89
+ }
90
+
91
+ public unsubscribe(callback: LatchCallback<AbortableProcessAbortReason>): void {
92
+ this.abortLatch.unsubscribe(callback);
93
+ }
94
+
95
+ public setStatus(status: AbortableProcessStatus): void {
96
+ this._status.next(status);
97
+ }
98
+
99
+ public child({
100
+ name,
101
+ parentNewStatus,
102
+ }: {
103
+ name: string;
104
+ parentNewStatus?: AbortableProcessStatus;
105
+ }): AbortableProcess {
106
+ const childProcess = new AbortableProcess(name);
107
+
108
+ if (parentNewStatus) {
109
+ this.setStatus(parentNewStatus);
110
+ }
111
+
112
+ this.abortLatch.subscribe(() => {
113
+ childProcess.abort('PARENT_ABORT');
114
+ });
115
+
116
+ childProcess.subscribeVisualizedProcessesTreeChange(this.dispatchVisualizedProcessesTreeChange);
117
+
118
+ this.children.add(childProcess);
119
+ this.dispatchVisualizedProcessesTreeChange({
120
+ type: 'add',
121
+ id: childProcess.id,
122
+ name,
123
+ parentId: this.id,
124
+ startTimestamp: childProcess.startTimestamp,
125
+ });
126
+
127
+ childProcess.subscribeAbort(() => {
128
+ this.children.delete(childProcess);
129
+ });
130
+
131
+ return childProcess;
132
+ }
133
+
134
+ public subscribeVisualizedProcessesTreeChange(callback: VisualizedProcessesTreeChangeCallback): VoidFunction {
135
+ this._visualizedProcessesTreeSubscribers.add(callback);
136
+
137
+ return () => {
138
+ this._visualizedProcessesTreeSubscribers.delete(callback);
139
+ };
140
+ }
141
+
142
+ public toJSON(): VisualizedProcessesTree {
143
+ const result: VisualizedProcessesTree = {
144
+ name: this.name,
145
+ id: this.id,
146
+ status: this._status.value(),
147
+ startTimestamp: this.startTimestamp,
148
+ children: Array.from(
149
+ this.children.values(),
150
+ (process) => process.toJSON()
151
+ ),
152
+ };
153
+
154
+ return result;
155
+ }
156
+
157
+ private readonly dispatchVisualizedProcessesTreeChange = (change: VisualizedProcessesTreeChange): void => {
158
+ callFunctions(this._visualizedProcessesTreeSubscribers, change);
159
+ };
160
+ }
@@ -0,0 +1,8 @@
1
+ import { UnsignedInteger } from '../../../types/Number/UnsignedInteger';
2
+
3
+ interface CreateArray {
4
+ (length: UnsignedInteger): undefined[];
5
+ <T>(length: UnsignedInteger, value: T): T[];
6
+ }
7
+
8
+ export const createArray: CreateArray = <T>(length: UnsignedInteger, value?: T) => Array.from({ length }, () => value);
@@ -0,0 +1,3 @@
1
+ import { Integer } from '../../../types/Number/Integer';
2
+
3
+ export const createIntegerSequenceArray = (start: Integer, end: Integer): Integer[] => Array.from({ length: end - start + 1 }, (_, i) => start + i);
@@ -0,0 +1,3 @@
1
+ export function getUniqueValues<T>(array: ReadonlyArray<T>): T[] {
2
+ return array.filter((value, index, arr) => arr.indexOf(value) === index);
3
+ }
@@ -0,0 +1,24 @@
1
+ export function separateToArrays<T>(
2
+ array: Iterable<T>,
3
+ separateFunction: (value: T, index: number, currentArray: Iterable<T>) => boolean
4
+ ): [T[], T[]] {
5
+ const appropriate: T[] = [];
6
+ const inappropriate: T[] = [];
7
+
8
+ let index = 0;
9
+
10
+ for (const value of array) {
11
+ if (separateFunction(value, index, array)) {
12
+ appropriate.push(value as T);
13
+ } else {
14
+ inappropriate.push(value);
15
+ }
16
+
17
+ index++;
18
+ }
19
+
20
+ return [
21
+ appropriate,
22
+ inappropriate,
23
+ ];
24
+ }
@@ -0,0 +1,18 @@
1
+ export function shuffleArray <T>(array: T[]) {
2
+ let currentIndex = array.length;
3
+
4
+ while (currentIndex !== 0) {
5
+ // Pick a remaining element...
6
+ const randomIndex = Math.floor(Math.random() * currentIndex);
7
+
8
+ currentIndex--;
9
+
10
+ [
11
+ array[currentIndex],
12
+ array[randomIndex],
13
+ ] = [
14
+ array[randomIndex],
15
+ array[currentIndex],
16
+ ];
17
+ }
18
+ }
@@ -0,0 +1,117 @@
1
+ import { UnsignedInteger } from '../../types/Number/UnsignedInteger';
2
+
3
+ /**
4
+ * Lightweight circular buffer implementation
5
+ *
6
+ * More advanced implementation is Deque
7
+ */
8
+ export class CircularBuffer<T> {
9
+ public length = 0;
10
+
11
+ private readonly capacity: number;
12
+ private readonly buffer: (T | undefined)[];
13
+ private head = 0;
14
+ private tail = 0;
15
+
16
+ public constructor(capacity: number) {
17
+ this.capacity = capacity;
18
+ this.buffer = new Array(capacity);
19
+ }
20
+
21
+ public *[Symbol.iterator](): IterableIterator<T> {
22
+ for (let i = 0; i < this.length; i++) {
23
+ const index = (this.head + i) % this.capacity;
24
+ const item = this.buffer[index];
25
+
26
+ yield item!;
27
+ }
28
+ }
29
+
30
+ public at(index: number): T | undefined {
31
+ if (this.length === 0) {
32
+ return undefined;
33
+ }
34
+
35
+ if (index < 0) {
36
+ index = this.length + index;
37
+ }
38
+
39
+ if (index < 0 || index >= this.length) {
40
+ return undefined;
41
+ }
42
+
43
+ return this.buffer[(this.head + index) % this.capacity];
44
+ }
45
+
46
+ public push(item: T): void {
47
+ this.buffer[this.tail] = item;
48
+ this.tail = (this.tail + 1) % this.capacity;
49
+ if (this.length < this.capacity) {
50
+ this.length++;
51
+ } else {
52
+ this.head = (this.head + 1) % this.capacity;
53
+ }
54
+ }
55
+
56
+ public pop(): T | undefined {
57
+ if (this.length === 0) {
58
+ return undefined;
59
+ }
60
+
61
+ this.tail = (this.tail - 1 + this.capacity) % this.capacity;
62
+ const item = this.buffer[this.tail];
63
+
64
+ this.buffer[this.tail] = undefined;
65
+ this.length--;
66
+
67
+ return item;
68
+ }
69
+
70
+ public popCount(count: UnsignedInteger): T[] {
71
+ const resultCount = Math.min(count, this.length);
72
+
73
+ const items: T[] = [];
74
+
75
+ for (let i = 0; i < resultCount; i++) {
76
+ items.push(this.pop()!);
77
+ }
78
+
79
+ return items;
80
+ }
81
+
82
+ public shift(): T | undefined {
83
+ if (this.length === 0) {
84
+ return undefined;
85
+ }
86
+
87
+ const item = this.buffer[this.head];
88
+
89
+ this.buffer[this.head] = undefined;
90
+ this.head = (this.head + 1) % this.capacity;
91
+ this.length--;
92
+
93
+ return item;
94
+ }
95
+
96
+ public shiftCount(count: UnsignedInteger): T[] {
97
+ const resultCount = Math.min(count, this.length);
98
+
99
+ const items: T[] = [];
100
+
101
+ for (let i = 0; i < resultCount; i++) {
102
+ items.push(this.shift()!);
103
+ }
104
+
105
+ return items;
106
+ }
107
+
108
+ public unshift(item: T): void {
109
+ this.head = (this.head - 1 + this.capacity) % this.capacity;
110
+ this.buffer[this.head] = item;
111
+ if (this.length < this.capacity) {
112
+ this.length++;
113
+ } else {
114
+ this.tail = (this.tail - 1 + this.capacity) % this.capacity;
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,3 @@
1
+ export function blurDocument(): void {
2
+ (document.activeElement as HTMLElement)?.blur();
3
+ }
@@ -0,0 +1,3 @@
1
+ import { blurDocument } from './blurDocument';
2
+
3
+ export const unfocusDocument = blurDocument;
@@ -0,0 +1,6 @@
1
+ import { MS_IN_SEC } from '../../../types/Time/Time';
2
+ import { UnixTimeSec } from '../../../types/Time/UnixTimeSec';
3
+
4
+ export function dateToUnixTimeSec(date: Date): UnixTimeSec {
5
+ return Math.floor(date.getTime() / MS_IN_SEC);
6
+ }
@@ -0,0 +1,6 @@
1
+ import { ISODateString } from '../../../types/Time/ISODateString/ISODateString';
2
+ import { UnixTimeMs } from '../../../types/Time/UnixTimeMs';
3
+
4
+ export function isoDateStringToUnixTimeMs(date: ISODateString): UnixTimeMs {
5
+ return new Date(date).getTime();
6
+ }
@@ -0,0 +1,7 @@
1
+ import { ISODateString } from '../../../types/Time/ISODateString/ISODateString';
2
+ import { UnixTimeSec } from '../../../types/Time/UnixTimeSec';
3
+ import { isoDateStringToUnixTimeMs } from '../isoDateStringToUnixTimeMs/isoDateStringToUnixTimeMs';
4
+
5
+ export function isoDateStringToUnixTimeSec(date: ISODateString): UnixTimeSec {
6
+ return Math.floor(isoDateStringToUnixTimeMs(date) / 1000);
7
+ }
@@ -0,0 +1,6 @@
1
+ import { ISODateString } from '../../../types/Time/ISODateString/ISODateString';
2
+ import { UnixTimeSec } from '../../../types/Time/UnixTimeSec';
3
+
4
+ export function unixTimeSecToIsoDateString(time: UnixTimeSec): ISODateString {
5
+ return new Date(time * 1000).toISOString();
6
+ }