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.
- package/README.md +11 -0
- package/package.json +66 -0
- package/src/reactHooks/setDeepEqualState.ts +19 -0
- package/src/reactHooks/useLocationParameter.ts +46 -0
- package/src/reactHooks/useObjectDeepChangesCounter.ts +22 -0
- package/src/reactHooks/useObservableMap/useObservableMap.ts +21 -0
- package/src/reactHooks/useRecentChangeTimer.ts +42 -0
- package/src/reactHooks/useReload.ts +17 -0
- package/src/reactHooks/useVisualizedProcessesTree.ts +202 -0
- package/src/types/Boolean.ts +9 -0
- package/src/types/DeepPartial.ts +1 -0
- package/src/types/GlobalContext.ts +8 -0
- package/src/types/HexColorString.ts +9 -0
- package/src/types/ISOLang.ts +5 -0
- package/src/types/IsEqualUnion.ts +1 -0
- package/src/types/IterableWithIndexAccess.ts +4 -0
- package/src/types/Kilobits.ts +4 -0
- package/src/types/Network/Bits.ts +4 -0
- package/src/types/Network/Bps.ts +4 -0
- package/src/types/Network/Kbps.ts +4 -0
- package/src/types/Network/Mbps.ts +4 -0
- package/src/types/Number/AngleInDegrees.ts +3 -0
- package/src/types/Number/FiniteNumber.ts +11 -0
- package/src/types/Number/Integer.ts +14 -0
- package/src/types/Number/IntegerInString.ts +13 -0
- package/src/types/Number/Number.ts +15 -0
- package/src/types/Number/Portion.ts +4 -0
- package/src/types/Number/PositiveInteger.ts +30 -0
- package/src/types/Number/PositiveNumber.ts +4 -0
- package/src/types/Number/StringUnsignedInteger.ts +4 -0
- package/src/types/Number/UnsignedFiniteNumber.ts +13 -0
- package/src/types/Number/UnsignedInteger.ts +28 -0
- package/src/types/Object/Object.ts +20 -0
- package/src/types/Percent.ts +4 -0
- package/src/types/PixelPosition.ts +9 -0
- package/src/types/PixelSize.ts +9 -0
- package/src/types/Pixels.ts +4 -0
- package/src/types/RangeTuple.ts +1 -0
- package/src/types/Size.ts +8 -0
- package/src/types/Time/DaysCount.ts +6 -0
- package/src/types/Time/Hours.ts +4 -0
- package/src/types/Time/ISODateString/ISODateString.ts +16 -0
- package/src/types/Time/Milliseconds.ts +4 -0
- package/src/types/Time/Minutes.ts +4 -0
- package/src/types/Time/Seconds.ts +5 -0
- package/src/types/Time/Time.ts +13 -0
- package/src/types/Time/Timestamp.ts +6 -0
- package/src/types/Time/UnixTimeMs.ts +6 -0
- package/src/types/Time/UnixTimeSec.ts +11 -0
- package/src/types/Time/const.ts +24 -0
- package/src/types/any/AnyAsyncFunction.ts +2 -0
- package/src/types/any/AnyFunction.ts +2 -0
- package/src/types/assertions/ANY_VALUE.ts +2 -0
- package/src/types/assertions/isNever/isNever.ts +34 -0
- package/src/types/assertions/isTrue/isTrue.ts +13 -0
- package/src/utils/AbortableProcess.ts +160 -0
- package/src/utils/Array/createArray/createArray.ts +8 -0
- package/src/utils/Array/createIntegerSequenceArray/createIntegerSequenceArray.ts +3 -0
- package/src/utils/Array/getUniqueValues/getUniqueValues.ts +3 -0
- package/src/utils/Array/separateToArrays/separateToArrays.ts +24 -0
- package/src/utils/Array/shuffleArray/shuffleArray.ts +18 -0
- package/src/utils/CircularBuffer/CircularBuffer.ts +117 -0
- package/src/utils/DOM/blurDocument.ts +3 -0
- package/src/utils/DOM/unfocusDocument.ts +3 -0
- package/src/utils/Date/dateToUnixTimeSec/dateToUnixTimeSec.ts +6 -0
- package/src/utils/Date/isoDateStringToUnixTimeMs/isoDateStringToUnixTimeMs.ts +6 -0
- package/src/utils/Date/isoDateStringToUnixTimeSec/isoDateStringToUnixTimeSec.ts +7 -0
- package/src/utils/Date/unixTimeSecToIsoDateString/unixTimeSecToIsoDateString.ts +6 -0
- package/src/utils/Deque/Deque.ts +530 -0
- package/src/utils/DeviceDetection/isTouchScreenDevice/isTouchScreenDevice.ts +16 -0
- package/src/utils/Error/rethrowError/rethrowError.ts +8 -0
- package/src/utils/Error/wrapError.ts +32 -0
- package/src/utils/Function/callFirstThenOther/callFirstThenOther.ts +24 -0
- package/src/utils/Function/callFunctions/callFunctions.ts +11 -0
- package/src/utils/Function/callTimes/callTimes.ts +5 -0
- package/src/utils/Function/isFunction.ts +3 -0
- package/src/utils/Function/noop/index.ts +4 -0
- package/src/utils/Function/once/once.ts +32 -0
- package/src/utils/Function/subscribeUpdatesWithTimeout/index.ts +44 -0
- package/src/utils/Function/throttleFunction/throttleFunction.ts +18 -0
- package/src/utils/Function/throttleWithPromiseFunction/throttleWithPromiseFunction.ts +19 -0
- package/src/utils/Function/tryCatch/tryCatch.ts +13 -0
- package/src/utils/Latch/Latch.ts +63 -0
- package/src/utils/Map/ObservableMap/ObservableMap.ts +55 -0
- package/src/utils/Map/findMapsDifferences/findMapsDifferences.ts +35 -0
- package/src/utils/Map/mapGetOrSet/mapGetOrSet.ts +7 -0
- package/src/utils/Map/mapMapToArray/mapMapToArray.ts +6 -0
- package/src/utils/Map/mapMapValues/mapMapValues.ts +9 -0
- package/src/utils/Math/createSimpleMovingAverageSeries/createSimpleMovingAverageSeries.ts +22 -0
- package/src/utils/Math/mean/mean.ts +14 -0
- package/src/utils/Math/simpleMovingAverageUsingAccFabric/simpleMovingAverageUsingAccFabric.ts +29 -0
- package/src/utils/Math/sum/sum.ts +45 -0
- package/src/utils/MinHeap/MinHeap.ts +88 -0
- package/src/utils/MinHeapUniqueNumber/MinHeapUniqueNumber.ts +105 -0
- package/src/utils/MinMaxHeap/MinMaxHeap.ts +91 -0
- package/src/utils/Number/collectIntegerSequences/collectIntegerSequences.ts +36 -0
- package/src/utils/Number/numberToFixedPrecision/numberToFixedPrecision.ts +13 -0
- package/src/utils/Object/cloneObject/cloneObject.ts +3 -0
- package/src/utils/Object/deepEqual/deepEqual.ts +45 -0
- package/src/utils/Object/deleteUndefinedProperties/index.ts +13 -0
- package/src/utils/Object/entriesToObject/entriesToObject.ts +12 -0
- package/src/utils/Object/filterObject/filterObject.ts +18 -0
- package/src/utils/Object/forOwn/forOwn.ts +12 -0
- package/src/utils/Object/getObjectEntries/getObjectEntries.ts +3 -0
- package/src/utils/Object/getObjectKeys/getObjectKeys.ts +3 -0
- package/src/utils/Object/getObjectValues/index.ts +3 -0
- package/src/utils/Object/hasOwnProperty/hasOwnProperty.ts +3 -0
- package/src/utils/Object/invertObject/InvertedObject.ts +3 -0
- package/src/utils/Object/invertObject/invertObject.ts +15 -0
- package/src/utils/Object/isEmptyObject/index.ts +5 -0
- package/src/utils/Object/isObject/index.ts +8 -0
- package/src/utils/Object/mapObjectKeys/mapObjectKeys.ts +25 -0
- package/src/utils/Object/mapObjectValues/mapObjectValues.ts +16 -0
- package/src/utils/Object/mirrorObject/ObjectKeysMirror.ts +1 -0
- package/src/utils/Object/mirrorObject/mirrorObject.ts +7 -0
- package/src/utils/Pagination/DEFAULT_PAGE.ts +1 -0
- package/src/utils/Pagination/calculatePaginationParameters.ts +29 -0
- package/src/utils/Promise/promiseAll/promiseAll.ts +6 -0
- package/src/utils/Promise/restrictParallelCalls/restrictParallelCalls.ts +18 -0
- package/src/utils/Ranges/checkRangesAdjacent/checkRangesAdjacent.ts +23 -0
- package/src/utils/Ranges/checkRangesIntersection/checkRangesIntersection.ts +8 -0
- package/src/utils/Ranges/excludeRanges/excludeRanges.ts +42 -0
- package/src/utils/Ranges/getDistanceToRange/getDistanceToRange.ts +14 -0
- package/src/utils/Ranges/isRangeWithinRanges.ts +14 -0
- package/src/utils/Ranges/mapDateRangeToISODateStringRange/mapDateRangeToISODateStringRange.ts +7 -0
- package/src/utils/Ranges/mapISODateStringRangeToUnixTimeMsRange/mapISODateStringRangeToUnixTimeMsRange.ts +8 -0
- package/src/utils/Ranges/mapRange/mapRange.ts +13 -0
- package/src/utils/Ranges/mapUnixTimeMsRangeToISODateStringRange/mapUnixTimeMsRangeToISODateStringRange.ts +8 -0
- package/src/utils/Ranges/mergeRanges/mergeRanges.ts +34 -0
- package/src/utils/Signal/Signal.ts +47 -0
- package/src/utils/Signal/SignalCallback.ts +1 -0
- package/src/utils/Signal/combineSignalsIntoNewOne/combineSignalsIntoNewOne.ts +75 -0
- package/src/utils/Signal/subscribeSignalAndCallWithCurrentValue/subscribeSignalAndCallWithCurrentValue.ts +7 -0
- package/src/utils/Signal/useSignal.ts +10 -0
- package/src/utils/String/HexString/HEX_SYMBOLS.ts +1 -0
- package/src/utils/String/HexString/HexString.ts +2 -0
- package/src/utils/String/HexString/isHexString.ts +16 -0
- package/src/utils/String/NonEmptyString/NonEmptyString.ts +22 -0
- package/src/utils/String/endsWith/index.ts +6 -0
- package/src/utils/String/isString.ts +3 -0
- package/src/utils/binarySearch/binarySearch.ts +20 -0
- package/src/utils/binarySearchClosest/binarySearchClosest.ts +43 -0
- package/src/utils/createIncrementalIntegerGenerator.ts +7 -0
- package/src/utils/createRemoteDataProcessingWindow/createRemoteDataProcessingWindow.ts +157 -0
- package/src/utils/createSimultaneousOperationsHandler/createSimultaneousOperationsHandler.ts +65 -0
- package/src/utils/encryptDecryptString/encryptDecryptString.ts +34 -0
- package/src/utils/getPrimeNumbersWithEratosthenesSieve/getPrimeNumbersWithEratosthenesSieve.ts +21 -0
- package/src/utils/isPromise/isPromise.ts +30 -0
- package/src/utils/makeAsyncFunctionCallsSimultaneous/makeAsyncFunctionCallsSimultaneous.ts +64 -0
- package/src/utils/parallelsLimitPromise/index.ts +28 -0
- package/src/utils/parallelsLimitQueue/parallelsLimitQueue.ts +69 -0
- package/src/utils/prettyStringify/index.ts +3 -0
- package/src/utils/random/fnv1a/fnv1a.ts +87 -0
- package/src/utils/random/generateHashedFloats/generateHashedFloats.ts +28 -0
- package/src/utils/random/getRandomIntegerInARange/getRandomIntegerInARange.ts +3 -0
- package/src/utils/random/getSampleIndexByStringHash/getSampleIndexByStringHash.ts +10 -0
- package/src/utils/random/randomBoolean/randomBoolean.ts +3 -0
- package/src/utils/random/randomHexString/randomHexString.ts +12 -0
- package/src/utils/requestAnimationFrame/requestAnimationFramePromise/requestAnimationFramePromise.ts +7 -0
- package/src/utils/requestAnimationFrame/requestAnimationFrameThrottle/requestAnimationFrameThrottle.ts +6 -0
- package/src/utils/retryFunctionWrapper/retryFunctionWrapper.ts +40 -0
- package/src/utils/runParallelTimescalesProcessing/runParallelTimescalesProcessing.ts +113 -0
- package/src/utils/stringifyError.ts +3 -0
- package/src/utils/timers/promiseTimeout/promiseTimeout.ts +26 -0
- package/src/utils/timers/subscribeSyntheticInterval/subscribeSyntheticInterval.ts +47 -0
- 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 @@
|
|
|
1
|
+
export type RangeTuple<T> = [from: T, to: T];
|
|
@@ -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,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,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,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,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,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
|
+
}
|