@zelgadis87/utils-core 4.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/dist/Lazy.d.ts +21 -0
- package/dist/LazyAsync.d.ts +23 -0
- package/dist/Logger.d.ts +21 -0
- package/dist/Optional.d.ts +70 -0
- package/dist/async/CancelableDeferred.d.ts +17 -0
- package/dist/async/Deferred.d.ts +27 -0
- package/dist/async/RateThrottler.d.ts +12 -0
- package/dist/async/Semaphore.d.ts +10 -0
- package/dist/async/index.d.ts +4 -0
- package/dist/index.d.ts +11 -0
- package/dist/random/index.d.ts +2 -0
- package/dist/random/randomInterval.d.ts +1 -0
- package/dist/random/randomPercentage.d.ts +1 -0
- package/dist/sorting/ComparisonChain.d.ts +57 -0
- package/dist/sorting/Sorter.d.ts +100 -0
- package/dist/sorting/index.d.ts +4 -0
- package/dist/sorting/types.d.ts +5 -0
- package/dist/time/RandomTimeDuration.d.ts +9 -0
- package/dist/time/TimeBase.d.ts +38 -0
- package/dist/time/TimeDuration.d.ts +81 -0
- package/dist/time/TimeFrequency.d.ts +10 -0
- package/dist/time/TimeInstant.d.ts +137 -0
- package/dist/time/TimeInstantBuilder.d.ts +77 -0
- package/dist/time/TimeUnit.d.ts +17 -0
- package/dist/time/index.d.ts +6 -0
- package/dist/time/types.d.ts +26 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/arrays.d.ts +33 -0
- package/dist/types/booleans.d.ts +2 -0
- package/dist/types/functions.d.ts +20 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/json.d.ts +6 -0
- package/dist/types/nulls.d.ts +8 -0
- package/dist/types/numbers.d.ts +31 -0
- package/dist/types/promises.d.ts +6 -0
- package/dist/types/records.d.ts +14 -0
- package/dist/types/strings.d.ts +40 -0
- package/dist/upgrade/DataUpgrader.d.ts +22 -0
- package/dist/upgrade/errors.d.ts +12 -0
- package/dist/upgrade/getTransitionsPath.d.ts +3 -0
- package/dist/upgrade/index.d.ts +2 -0
- package/dist/upgrade/types.d.ts +31 -0
- package/dist/utils/asError.d.ts +1 -0
- package/dist/utils/bindThis.d.ts +1 -0
- package/dist/utils/constant.d.ts +8 -0
- package/dist/utils/entries.d.ts +4 -0
- package/dist/utils/groupBy.d.ts +7 -0
- package/dist/utils/iff.d.ts +8 -0
- package/dist/utils/index.d.ts +22 -0
- package/dist/utils/indexBy.d.ts +7 -0
- package/dist/utils/jsonCloneDeep.d.ts +2 -0
- package/dist/utils/math.d.ts +9 -0
- package/dist/utils/noop.d.ts +1 -0
- package/dist/utils/omit.d.ts +2 -0
- package/dist/utils/pad.d.ts +3 -0
- package/dist/utils/pluralize.d.ts +1 -0
- package/dist/utils/round.d.ts +8 -0
- package/dist/utils/sortBy.d.ts +7 -0
- package/dist/utils/throttle.d.ts +3 -0
- package/dist/utils/uniq.d.ts +1 -0
- package/dist/utils/uniqBy.d.ts +2 -0
- package/dist/utils/uniqByKey.d.ts +1 -0
- package/dist/utils/upsert.d.ts +0 -0
- package/dist/utils/withTryCatch.d.ts +2 -0
- package/dist/utils/withTryCatchAsync.d.ts +2 -0
- package/dist/utils/wrap.d.ts +1 -0
- package/esbuild/index.cjs +2670 -0
- package/esbuild/index.mjs +2518 -0
- package/package.json +159 -0
- package/src/Lazy.ts +77 -0
- package/src/LazyAsync.ts +100 -0
- package/src/Logger.ts +44 -0
- package/src/Optional.ts +172 -0
- package/src/async/CancelableDeferred.ts +36 -0
- package/src/async/Deferred.ts +84 -0
- package/src/async/RateThrottler.ts +46 -0
- package/src/async/Semaphore.ts +45 -0
- package/src/async/index.ts +6 -0
- package/src/index.ts +13 -0
- package/src/random/index.ts +3 -0
- package/src/random/randomInterval.ts +4 -0
- package/src/random/randomPercentage.ts +6 -0
- package/src/sorting/ComparisonChain.ts +209 -0
- package/src/sorting/Sorter.ts +357 -0
- package/src/sorting/index.ts +5 -0
- package/src/sorting/types.ts +7 -0
- package/src/time/RandomTimeDuration.ts +21 -0
- package/src/time/TimeBase.ts +113 -0
- package/src/time/TimeDuration.ts +296 -0
- package/src/time/TimeFrequency.ts +28 -0
- package/src/time/TimeInstant.ts +488 -0
- package/src/time/TimeInstantBuilder.ts +126 -0
- package/src/time/TimeUnit.ts +43 -0
- package/src/time/index.ts +8 -0
- package/src/time/types.ts +56 -0
- package/src/types/arrays.ts +89 -0
- package/src/types/booleans.ts +8 -0
- package/src/types/functions.ts +27 -0
- package/src/types/index.ts +18 -0
- package/src/types/json.ts +5 -0
- package/src/types/nulls.ts +33 -0
- package/src/types/numbers.ts +80 -0
- package/src/types/promises.ts +23 -0
- package/src/types/records.ts +21 -0
- package/src/types/strings.ts +143 -0
- package/src/upgrade/DataUpgrader.ts +100 -0
- package/src/upgrade/errors.ts +25 -0
- package/src/upgrade/getTransitionsPath.ts +89 -0
- package/src/upgrade/index.ts +4 -0
- package/src/upgrade/types.ts +36 -0
- package/src/utils/asError.ts +12 -0
- package/src/utils/bindThis.ts +4 -0
- package/src/utils/constant.ts +9 -0
- package/src/utils/entries.ts +13 -0
- package/src/utils/groupBy.ts +39 -0
- package/src/utils/iff.ts +26 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/indexBy.ts +36 -0
- package/src/utils/jsonCloneDeep.ts +31 -0
- package/src/utils/math.ts +44 -0
- package/src/utils/noop.ts +2 -0
- package/src/utils/omit.ts +8 -0
- package/src/utils/pad.ts +20 -0
- package/src/utils/pluralize.ts +20 -0
- package/src/utils/round.ts +24 -0
- package/src/utils/sortBy.ts +27 -0
- package/src/utils/throttle.ts +10 -0
- package/src/utils/uniq.ts +6 -0
- package/src/utils/uniqBy.ts +15 -0
- package/src/utils/uniqByKey.ts +5 -0
- package/src/utils/upsert.ts +2 -0
- package/src/utils/withTryCatch.ts +10 -0
- package/src/utils/withTryCatchAsync.ts +6 -0
- package/src/utils/wrap.ts +4 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
|
|
2
|
+
import { TMaybe } from "../types";
|
|
3
|
+
import { TTransition, TTransitionMatrix, TUpgradable } from "./types";
|
|
4
|
+
|
|
5
|
+
const DEBUG_ENABLED = false;
|
|
6
|
+
|
|
7
|
+
export default function getTransitionsPath<
|
|
8
|
+
XStar extends TUpgradable,
|
|
9
|
+
XFromNumber extends XStar[ "$version" ],
|
|
10
|
+
XToNumber extends XStar[ "$version" ]
|
|
11
|
+
>(
|
|
12
|
+
matrix: TTransitionMatrix<XStar>,
|
|
13
|
+
from: XFromNumber,
|
|
14
|
+
to: XToNumber
|
|
15
|
+
): TMaybe<TTransition<XStar, XFromNumber, XToNumber>[]> {
|
|
16
|
+
return internalGetTransitionsPath( matrix, from, to, 0, DEBUG_ENABLED );
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function internalGetTransitionsPath<
|
|
20
|
+
XStar extends TUpgradable,
|
|
21
|
+
XFromNumber extends XStar[ "$version" ],
|
|
22
|
+
XToNumber extends XStar[ "$version" ]
|
|
23
|
+
>(
|
|
24
|
+
matrix: TTransitionMatrix<XStar>,
|
|
25
|
+
from: XFromNumber,
|
|
26
|
+
to: XToNumber,
|
|
27
|
+
depth: number,
|
|
28
|
+
debug: boolean,
|
|
29
|
+
): TMaybe<TTransition<XStar, any, any>[]> {
|
|
30
|
+
|
|
31
|
+
debugLog( debug, depth, from, to, 'Search started.' );
|
|
32
|
+
|
|
33
|
+
const transitionsTo = matrix[ to ];
|
|
34
|
+
if ( !transitionsTo ) {
|
|
35
|
+
debugLog( debug, depth, from, to, 'No transitions available to this version' );
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check if there is a transition that goes directly from from to to.
|
|
40
|
+
const exactTransition = transitionsTo[ from ];
|
|
41
|
+
if ( exactTransition ) {
|
|
42
|
+
debugLog( debug, depth, from, to, 'Found exact transition.' );
|
|
43
|
+
return [ exactTransition ];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Otherwise, recursively search for the min path.
|
|
47
|
+
const keys = Object.keys( transitionsTo );
|
|
48
|
+
return keys.reduce( ( curBestPath: TMaybe<TTransition<XStar, any, any>[]>, transitionKey: string ) => {
|
|
49
|
+
const transition = transitionsTo[ transitionKey as unknown as XStar[ "$version" ] ]!;
|
|
50
|
+
const path = internalGetTransitionsPath( matrix, from, transition.from, depth + 1, debug );
|
|
51
|
+
if ( path === null ) {
|
|
52
|
+
debugLog( debug, depth + 1, from, transition.from, 'No path found.' );
|
|
53
|
+
return curBestPath;
|
|
54
|
+
} else {
|
|
55
|
+
if ( curBestPath === null || curBestPath.length > path.length + 1 ) {
|
|
56
|
+
debugLog( debug, depth + 1, from, transition.from, 'New best path found: ' + printTransitions( path ) );
|
|
57
|
+
return [ ...path, transition ];
|
|
58
|
+
} else {
|
|
59
|
+
return curBestPath;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}, null as TMaybe<TTransition<XStar, any, any>[]> );
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function debugLog(
|
|
67
|
+
enabled: boolean,
|
|
68
|
+
depth: number,
|
|
69
|
+
from: number,
|
|
70
|
+
to: number,
|
|
71
|
+
message: string
|
|
72
|
+
) {
|
|
73
|
+
if ( !enabled )
|
|
74
|
+
return;
|
|
75
|
+
// istanbul ignore next
|
|
76
|
+
// eslint-disable-next-line no-restricted-globals
|
|
77
|
+
console.info(
|
|
78
|
+
'#'.repeat( depth + 1 ),
|
|
79
|
+
from + ' -> ' + to,
|
|
80
|
+
message
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function printTransitions( transitions: TTransition<any, any, any>[] ): string {
|
|
85
|
+
return transitions.reduce( ( ret, cur ) => {
|
|
86
|
+
return ret + " -> " + cur.to;
|
|
87
|
+
}, "" + transitions[ 0 ].from );
|
|
88
|
+
}
|
|
89
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
import { TFunction, TJsonObject, TPromisable } from "../types";
|
|
3
|
+
|
|
4
|
+
export type TUpgradable = TJsonObject & { $version: number };
|
|
5
|
+
|
|
6
|
+
export type TUpgradableAtVersion<XStar extends TUpgradable, N extends XStar[ "$version" ]> = Extract<XStar, { $version: N }>;
|
|
7
|
+
|
|
8
|
+
export type TVersionMap<
|
|
9
|
+
XStar extends TUpgradable,
|
|
10
|
+
> = {
|
|
11
|
+
[ XVersionNumber in XStar[ "$version" ] ]: TUpgradableAtVersion<XStar, XVersionNumber>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type TPossibleVersion<XStar extends TUpgradable> = XStar[ "$version" ] & number;
|
|
15
|
+
export type TPossibleFromVersion<XStar extends TUpgradable, XLatest extends XStar> = Exclude<TPossibleVersion<XStar>, XLatest[ "$version" ]>;
|
|
16
|
+
export type TUpgradeFunction<
|
|
17
|
+
XStar extends TUpgradable,
|
|
18
|
+
XFrom extends XStar,
|
|
19
|
+
XTo extends XStar,
|
|
20
|
+
> = TFunction<Readonly<TVersionMap<XStar>[ XFrom[ "$version" ] ]>, TPromisable<TVersionMap<XStar>[ XTo[ "$version" ] ]>>;
|
|
21
|
+
export type TTransition<
|
|
22
|
+
XStar extends TUpgradable,
|
|
23
|
+
XFromNumber extends XStar[ "$version" ],
|
|
24
|
+
XToNumber extends XStar[ "$version" ],
|
|
25
|
+
XFrom extends Extract<XStar, { $version: XFromNumber }> = Extract<XStar, { $version: XFromNumber }>,
|
|
26
|
+
XTo extends Extract<XStar, { $version: XToNumber }> = Extract<XStar, { $version: XToNumber }>,
|
|
27
|
+
> = {
|
|
28
|
+
from: XFromNumber;
|
|
29
|
+
to: XToNumber;
|
|
30
|
+
apply: TUpgradeFunction<XStar, XFrom, XTo>;
|
|
31
|
+
};
|
|
32
|
+
export type TTransitionMatrix<XStar extends TUpgradable> = Partial<{
|
|
33
|
+
[ XTo in XStar[ "$version" ] ]: Partial<{
|
|
34
|
+
[ XFrom in XStar[ "$version" ] ]: TTransition<XStar, XFrom, XTo>
|
|
35
|
+
}>
|
|
36
|
+
}>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
export default function asError( e: unknown ): Error {
|
|
3
|
+
if ( e === undefined || e === null )
|
|
4
|
+
return new Error( 'Void message' );
|
|
5
|
+
if ( e instanceof Error )
|
|
6
|
+
return e;
|
|
7
|
+
if ( typeof e === 'string' )
|
|
8
|
+
return new Error( e );
|
|
9
|
+
if ( e instanceof String )
|
|
10
|
+
return new Error( e.toString() );
|
|
11
|
+
return new Error( JSON.stringify( e ) );
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function constant<T>( v: T ): () => T { return () => v; }
|
|
2
|
+
export function identity<T>( t: T ) { return t; }
|
|
3
|
+
export default constant;
|
|
4
|
+
|
|
5
|
+
export const constantNull = constant( null );
|
|
6
|
+
export const constantTrue = constant( true );
|
|
7
|
+
export const constantFalse = constant( false );
|
|
8
|
+
export const constantZero = constant( 0 );
|
|
9
|
+
export const constantOne = constant( 1 );
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TFunction } from "../types";
|
|
2
|
+
|
|
3
|
+
export function dictToEntries<V, K extends string = string>( obj: Record<K, V> ): [K, V][] {
|
|
4
|
+
return Object.entries( obj ) as [K, V][];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function entriesToDict<V, K extends string = string>( entries: [K, V][] ): Record<K, V> {
|
|
8
|
+
return Object.fromEntries( entries ) as Record<K, V>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function mapEntries<K1 extends string, V1, K2 extends string, V2>( dict: Record<K1, V1>, mapper: TFunction<[K1, V1], [K2, V2]> ): Record<K2, V2> {
|
|
12
|
+
return entriesToDict( dictToEntries( dict ).map( ( entry ) => mapper( entry ) ) );
|
|
13
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
import { TFunction, TKeysOfType } from "../types";
|
|
3
|
+
|
|
4
|
+
export function groupByString<V, K extends TKeysOfType<V, string>>( arr: V[], field: K ): Record<V[K] & string, V[]> {
|
|
5
|
+
return groupByStringWith( arr, t => t[ field ] as string );
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function groupByNumber<V, K extends TKeysOfType<V, number>>( arr: V[], field: K ): Record<V[K] & number, V[]> {
|
|
9
|
+
return groupByNumberWith( arr, t => t[ field ] as number );
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function groupBySymbol<V, K extends TKeysOfType<V, symbol>>( arr: V[], field: K ): Record<V[K] & symbol, V[]> {
|
|
13
|
+
return groupBySymbolWith( arr, t => t[ field ] as symbol );
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function groupByStringWith<V, K extends string>( arr: V[], getter: TFunction<V, K> ): Record<K, V[]> {
|
|
17
|
+
return doGroupByWith<K, V>( arr, getter );
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function groupByNumberWith<V, K extends number>( arr: V[], getter: TFunction<V, K> ): Record<K, V[]> {
|
|
21
|
+
return doGroupByWith<K, V>( arr, getter );
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function groupBySymbolWith<V, K extends symbol>( arr: V[], getter: TFunction<V, K> ): Record<K, V[]> {
|
|
25
|
+
return doGroupByWith<K, V>( arr, getter );
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function doGroupByWith<K extends string | number | symbol, V>( arr: V[], getter: TFunction<V, K> ): Record<K, V[]> {
|
|
29
|
+
return arr.reduce( ( dict, cur ) => {
|
|
30
|
+
const key = getter( cur );
|
|
31
|
+
if ( key !== null && key !== undefined ) {
|
|
32
|
+
const arr = dict[ key ] ?? [];
|
|
33
|
+
arr.push( cur );
|
|
34
|
+
dict[ key ] = arr;
|
|
35
|
+
}
|
|
36
|
+
return dict;
|
|
37
|
+
}, {} as Record<K, V[]> );
|
|
38
|
+
}
|
|
39
|
+
|
package/src/utils/iff.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { TPredicate } from "../types";
|
|
2
|
+
|
|
3
|
+
type TBooleanOrPredicate = boolean | TPredicate<void>;
|
|
4
|
+
type TIff<T> = {
|
|
5
|
+
elseIf<R>( pred: TBooleanOrPredicate, valueIfTrue: R ): TIff<T | R>;
|
|
6
|
+
otherwise<R>( valueIfElse: R ): T | R;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function iff<T>( firstPredicate: TBooleanOrPredicate, valueIfTrue: T ) {
|
|
10
|
+
|
|
11
|
+
if ( firstPredicate === true || ( firstPredicate instanceof Function && firstPredicate() === true ) ) {
|
|
12
|
+
const ret: TIff<T> = {
|
|
13
|
+
elseIf: () => ret,
|
|
14
|
+
otherwise: () => valueIfTrue
|
|
15
|
+
};
|
|
16
|
+
return ret;
|
|
17
|
+
} else {
|
|
18
|
+
const ret: TIff<T> = {
|
|
19
|
+
elseIf: <R>( elseIf: TBooleanOrPredicate, valueIfElseIfTrue: R ) => iff<R>( elseIf, valueIfElseIfTrue ),
|
|
20
|
+
otherwise: <R>( valueIfElse: R ) => valueIfElse
|
|
21
|
+
};
|
|
22
|
+
return ret;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
export { default as asError } from './asError';
|
|
3
|
+
export { default as bindThis } from './bindThis';
|
|
4
|
+
export * from './constant.js';
|
|
5
|
+
export * from './entries.js';
|
|
6
|
+
export * from './groupBy.js';
|
|
7
|
+
export { default as iff } from './iff';
|
|
8
|
+
export * from './indexBy.js';
|
|
9
|
+
export { default as jsonCloneDeep } from './jsonCloneDeep';
|
|
10
|
+
export * from './math.js';
|
|
11
|
+
export { default as noop } from './noop';
|
|
12
|
+
export { default as omit } from './omit';
|
|
13
|
+
export { default as pad } from './pad';
|
|
14
|
+
export { default as pluralize } from './pluralize';
|
|
15
|
+
export * from './round.js';
|
|
16
|
+
export { default as sortBy } from './sortBy';
|
|
17
|
+
export { default as throttle } from './throttle';
|
|
18
|
+
export { default as uniq } from './uniq';
|
|
19
|
+
export { default as uniqBy } from './uniqBy';
|
|
20
|
+
export { default as uniqByKey } from './uniqByKey';
|
|
21
|
+
export { default as withTryCatch } from './withTryCatch';
|
|
22
|
+
export { default as withTryCatchAsync } from './withTryCatchAsync';
|
|
23
|
+
export { default as wrap } from './wrap';
|
|
24
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
import { TFunction, TKeysOfType } from "../types";
|
|
3
|
+
|
|
4
|
+
export function indexByString<V, K extends TKeysOfType<V, string>>( arr: V[], field: K ): Record<V[K] & string, V> {
|
|
5
|
+
return indexByStringWith( arr, t => t[ field ] as string );
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function indexByNumber<V, K extends TKeysOfType<V, number>>( arr: V[], field: K ): Record<V[K] & number, V> {
|
|
9
|
+
return indexByNumberWith( arr, t => t[ field ] as number );
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function indexBySymbol<V, K extends TKeysOfType<V, symbol>>( arr: V[], field: K ): Record<V[K] & symbol, V> {
|
|
13
|
+
return indexBySymbolWith( arr, t => t[ field ] as symbol );
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function indexByStringWith<V>( arr: V[], getter: TFunction<V, string> ): Record<string, V> {
|
|
17
|
+
return doIndexByWith<string, V>( arr, getter );
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function indexByNumberWith<V>( arr: V[], getter: TFunction<V, number> ): Record<number, V> {
|
|
21
|
+
return doIndexByWith<number, V>( arr, getter );
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function indexBySymbolWith<V>( arr: V[], getter: TFunction<V, symbol> ): Record<symbol, V> {
|
|
25
|
+
return doIndexByWith<symbol, V>( arr, getter );
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function doIndexByWith<K extends string | number | symbol, V>( arr: V[], getter: TFunction<V, K> ): Record<K, V> {
|
|
29
|
+
return arr.reduce( ( dict, cur ) => {
|
|
30
|
+
const key = getter( cur );
|
|
31
|
+
if ( key !== null && key !== undefined )
|
|
32
|
+
dict[ key ] = cur;
|
|
33
|
+
return dict;
|
|
34
|
+
}, {} as Record<K, V> );
|
|
35
|
+
}
|
|
36
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { TJsonObject, TJsonSerializable } from "../types";
|
|
2
|
+
|
|
3
|
+
export default function jsonCloneDeep<A extends TJsonSerializable>( a: A ): A {
|
|
4
|
+
|
|
5
|
+
// Handle the 3 simple types, and null or undefined
|
|
6
|
+
if ( null === a || "object" !== typeof a ) return a;
|
|
7
|
+
|
|
8
|
+
if ( a instanceof Date ) {
|
|
9
|
+
// Handle Date
|
|
10
|
+
return new Date( a.getTime() ) as unknown as A;
|
|
11
|
+
} else if ( a instanceof Array ) {
|
|
12
|
+
// Handle Array
|
|
13
|
+
const copy = [] as unknown[];
|
|
14
|
+
for ( let i = 0, len = a.length; i < len; i++ ) {
|
|
15
|
+
copy[ i ] = jsonCloneDeep( a[ i ] );
|
|
16
|
+
}
|
|
17
|
+
return copy as A;
|
|
18
|
+
} else if ( a instanceof Object ) {
|
|
19
|
+
// Handle Object
|
|
20
|
+
const copy = {} as Record<string | number | symbol, unknown>;
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
22
|
+
for ( let attr in ( a as TJsonObject ) ) {
|
|
23
|
+
if ( a.hasOwnProperty( attr ) )
|
|
24
|
+
copy[ attr ] = jsonCloneDeep( a[ attr ] );
|
|
25
|
+
}
|
|
26
|
+
return copy as A;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
throw new Error( "Unable to copy obj! Its type isn't supported." );
|
|
30
|
+
|
|
31
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { TReadableArray } from "../types/arrays.js";
|
|
2
|
+
|
|
3
|
+
export function clamp( n: number, min: number, max: number ): number {
|
|
4
|
+
if ( min === null || max === null || n === null || isNaN( min ) || isNaN( max ) || isNaN( n ) || min > max )
|
|
5
|
+
throw new Error();
|
|
6
|
+
if ( n > max ) {
|
|
7
|
+
return max;
|
|
8
|
+
} else if ( n < min ) {
|
|
9
|
+
return min;
|
|
10
|
+
} else {
|
|
11
|
+
return n;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function average( arr: TReadableArray<number> ): number {
|
|
16
|
+
const f = 1 / arr.length;
|
|
17
|
+
return arr.reduce( ( tot, cur ) => tot + ( cur * f ), 0 );
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function sum( arr: TReadableArray<number> ): number {
|
|
21
|
+
return arr.reduce( ( tot, cur ) => tot + cur, 0 );
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function sumBy<T>( arr: TReadableArray<T>, getter: ( t: T ) => number ): number {
|
|
25
|
+
return sum( arr.map( getter ) );
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function min( arr: TReadableArray<number> ): number {
|
|
29
|
+
if ( arr.length === 0 ) throw new Error( 'Cannot calculate value on empty array' );
|
|
30
|
+
return arr.reduce( ( min, cur ) => cur < min ? cur : min );
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function minBy<T>( arr: TReadableArray<T>, getter: ( t: T ) => number ): number {
|
|
34
|
+
return min( arr.map( getter ) );
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function max( arr: TReadableArray<number> ): number {
|
|
38
|
+
if ( arr.length === 0 ) throw new Error( 'Cannot calculate value on empty array' );
|
|
39
|
+
return arr.reduce( ( max, cur ) => cur > max ? cur : max );
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function maxBy<T>( arr: TReadableArray<T>, getter: ( t: T ) => number ): number {
|
|
43
|
+
return max( arr.map( getter ) );
|
|
44
|
+
}
|
package/src/utils/pad.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ensureDefined } from "../types/nulls.js";
|
|
2
|
+
import { repeat } from "../types/strings.js";
|
|
3
|
+
|
|
4
|
+
export default function pad( str: string, n: number, char: string, where: 'left' | 'right' = 'left' ): string {
|
|
5
|
+
const length = ensureDefined( str ).length;
|
|
6
|
+
if ( length >= ensureDefined( n ) ) return str;
|
|
7
|
+
|
|
8
|
+
if ( ensureDefined( char ).length !== 1 )
|
|
9
|
+
throw new Error( 'Illegal pad character' );
|
|
10
|
+
const padding = repeat( char, n - length );
|
|
11
|
+
return ( where === 'left' ? padding : '' ) + str + ( where === 'right' ? padding : '' );
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function padLeft( str: string, n: number, char: string ): string {
|
|
15
|
+
return pad( str, n, char, 'left' );
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function padRight( str: string, n: number, char: string ): string {
|
|
19
|
+
return pad( str, n, char, 'right' );
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
export default function pluralize( n: number, singular: string, plural?: string ): string {
|
|
3
|
+
|
|
4
|
+
if ( !singular || !singular.length )
|
|
5
|
+
throw new Error();
|
|
6
|
+
if ( n === 1 )
|
|
7
|
+
return singular;
|
|
8
|
+
|
|
9
|
+
plural = plural ?? singular + 's';
|
|
10
|
+
|
|
11
|
+
const firstUppercase = singular.charAt( 0 ) === singular.charAt( 0 ).toUpperCase();
|
|
12
|
+
if ( firstUppercase ) {
|
|
13
|
+
const PLURAL = plural.toUpperCase();
|
|
14
|
+
const isAllUppercase = plural === PLURAL;
|
|
15
|
+
plural = isAllUppercase ? PLURAL : plural.charAt( 0 ).toUpperCase() + plural.slice( 1 ).toLowerCase();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return plural;
|
|
19
|
+
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
type TRoundMode = 'toNearest' | 'toLower' | 'toUpper' | 'towardsZero' | 'awayFromZero';
|
|
3
|
+
type TIntegerNumber = number;
|
|
4
|
+
|
|
5
|
+
const roundModes: Record<TRoundMode, ( n: number ) => TIntegerNumber> = {
|
|
6
|
+
'toNearest': Math.round,
|
|
7
|
+
'toLower': Math.floor,
|
|
8
|
+
'toUpper': Math.ceil,
|
|
9
|
+
'towardsZero': n => n > 0 ? Math.floor( n ) : Math.ceil( n ),
|
|
10
|
+
'awayFromZero': n => n > 0 ? Math.ceil( n ) : Math.floor( n ),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function round( n: number, precision: number = 0, mode: TRoundMode = 'toNearest' ) {
|
|
14
|
+
const base = 10;
|
|
15
|
+
const power = Math.pow( base, precision );
|
|
16
|
+
return roundModes[ mode ]( n * power ) / power;
|
|
17
|
+
}
|
|
18
|
+
export default round;
|
|
19
|
+
export const roundToNearest = ( n: number, precision: number = 0 ) => round( n, precision, 'toNearest' );
|
|
20
|
+
export const roundToLower = ( n: number, precision: number = 0 ) => round( n, precision, 'toLower' );
|
|
21
|
+
export const roundToUpper = ( n: number, precision: number = 0 ) => round( n, precision, 'toUpper' );
|
|
22
|
+
export const roundTowardsZero = ( n: number, precision: number = 0 ) => round( n, precision, 'towardsZero' );
|
|
23
|
+
export const roundAwayFromZero = ( n: number, precision: number = 0 ) => round( n, precision, 'awayFromZero' );
|
|
24
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TFunction, TKeysOfType } from "../types";
|
|
2
|
+
|
|
3
|
+
type TKeyOrGetter<T> = T extends Record<string, unknown> ? TKeysOfType<T, number> & keyof T | TFunction<T, number | null> : TFunction<T, number | null>;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated[2023-11-01]: Use {@link Sorter} instead.
|
|
7
|
+
*/
|
|
8
|
+
export default function sortBy<T>( keyOrGetter: TKeyOrGetter<T>, direction: 'ASC' | 'DESC' = 'ASC', nulls: 'FIRST' | 'LAST' = 'LAST' ) {
|
|
9
|
+
const directionNum = direction === 'ASC' ? -1 : 1;
|
|
10
|
+
const nullsNum = nulls === 'LAST' ? -1 : 1;
|
|
11
|
+
const sortByNum = ( a: number | null | undefined, b: number | null | undefined ) => {
|
|
12
|
+
if ( a === b )
|
|
13
|
+
return -1;
|
|
14
|
+
const aDefined = !( a === null || a === undefined || isNaN( a ) );
|
|
15
|
+
const bDefined = !( b === null || b === undefined || isNaN( b ) );
|
|
16
|
+
if ( !aDefined && !bDefined )
|
|
17
|
+
return -1;
|
|
18
|
+
if ( aDefined !== bDefined )
|
|
19
|
+
return nullsNum * ( aDefined ? 1 : -1 );
|
|
20
|
+
return ( a! > b! ? -1 : 1 ) * directionNum;
|
|
21
|
+
}
|
|
22
|
+
if ( typeof keyOrGetter === "function" ) {
|
|
23
|
+
return ( a: T, b: T ) => sortByNum( keyOrGetter( a ), keyOrGetter( b ) );
|
|
24
|
+
} else {
|
|
25
|
+
return ( a: T, b: T ) => sortByNum( a[ keyOrGetter as keyof T ] as number, b[ keyOrGetter as keyof T ] as number );
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RateThrottler } from "../async";
|
|
2
|
+
import TimeFrequency from "../time/TimeFrequency";
|
|
3
|
+
import { TPromisable } from "../types";
|
|
4
|
+
|
|
5
|
+
export default function throttle<TParams extends unknown[], R>( fn: (...params: TParams) => TPromisable<R>, frequence: TimeFrequency ): (...params: TParams) => Promise<R> {
|
|
6
|
+
const semaphore = new RateThrottler( frequence );
|
|
7
|
+
return (...t: TParams): Promise<R> => {
|
|
8
|
+
return semaphore.execute<R>( async () => fn( ...t ) );
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { TFunction } from "../types";
|
|
2
|
+
|
|
3
|
+
export default function uniqBy<T, K>( arr: T[], getter: TFunction<T, K> ): T[] {
|
|
4
|
+
return arr.reduce( ( dict, cur ) => {
|
|
5
|
+
const key = getter( cur );
|
|
6
|
+
if ( dict.keys.includes( key ) ) {
|
|
7
|
+
return dict;
|
|
8
|
+
} else {
|
|
9
|
+
return {
|
|
10
|
+
keys: [ ...dict.keys, key ],
|
|
11
|
+
values: [ ...dict.values, cur ]
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}, { keys: [], values: [] } as { keys: K[], values: T[] } ).values;
|
|
15
|
+
}
|