@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.
Files changed (134) hide show
  1. package/dist/Lazy.d.ts +21 -0
  2. package/dist/LazyAsync.d.ts +23 -0
  3. package/dist/Logger.d.ts +21 -0
  4. package/dist/Optional.d.ts +70 -0
  5. package/dist/async/CancelableDeferred.d.ts +17 -0
  6. package/dist/async/Deferred.d.ts +27 -0
  7. package/dist/async/RateThrottler.d.ts +12 -0
  8. package/dist/async/Semaphore.d.ts +10 -0
  9. package/dist/async/index.d.ts +4 -0
  10. package/dist/index.d.ts +11 -0
  11. package/dist/random/index.d.ts +2 -0
  12. package/dist/random/randomInterval.d.ts +1 -0
  13. package/dist/random/randomPercentage.d.ts +1 -0
  14. package/dist/sorting/ComparisonChain.d.ts +57 -0
  15. package/dist/sorting/Sorter.d.ts +100 -0
  16. package/dist/sorting/index.d.ts +4 -0
  17. package/dist/sorting/types.d.ts +5 -0
  18. package/dist/time/RandomTimeDuration.d.ts +9 -0
  19. package/dist/time/TimeBase.d.ts +38 -0
  20. package/dist/time/TimeDuration.d.ts +81 -0
  21. package/dist/time/TimeFrequency.d.ts +10 -0
  22. package/dist/time/TimeInstant.d.ts +137 -0
  23. package/dist/time/TimeInstantBuilder.d.ts +77 -0
  24. package/dist/time/TimeUnit.d.ts +17 -0
  25. package/dist/time/index.d.ts +6 -0
  26. package/dist/time/types.d.ts +26 -0
  27. package/dist/tsconfig.tsbuildinfo +1 -0
  28. package/dist/types/arrays.d.ts +33 -0
  29. package/dist/types/booleans.d.ts +2 -0
  30. package/dist/types/functions.d.ts +20 -0
  31. package/dist/types/index.d.ts +12 -0
  32. package/dist/types/json.d.ts +6 -0
  33. package/dist/types/nulls.d.ts +8 -0
  34. package/dist/types/numbers.d.ts +31 -0
  35. package/dist/types/promises.d.ts +6 -0
  36. package/dist/types/records.d.ts +14 -0
  37. package/dist/types/strings.d.ts +40 -0
  38. package/dist/upgrade/DataUpgrader.d.ts +22 -0
  39. package/dist/upgrade/errors.d.ts +12 -0
  40. package/dist/upgrade/getTransitionsPath.d.ts +3 -0
  41. package/dist/upgrade/index.d.ts +2 -0
  42. package/dist/upgrade/types.d.ts +31 -0
  43. package/dist/utils/asError.d.ts +1 -0
  44. package/dist/utils/bindThis.d.ts +1 -0
  45. package/dist/utils/constant.d.ts +8 -0
  46. package/dist/utils/entries.d.ts +4 -0
  47. package/dist/utils/groupBy.d.ts +7 -0
  48. package/dist/utils/iff.d.ts +8 -0
  49. package/dist/utils/index.d.ts +22 -0
  50. package/dist/utils/indexBy.d.ts +7 -0
  51. package/dist/utils/jsonCloneDeep.d.ts +2 -0
  52. package/dist/utils/math.d.ts +9 -0
  53. package/dist/utils/noop.d.ts +1 -0
  54. package/dist/utils/omit.d.ts +2 -0
  55. package/dist/utils/pad.d.ts +3 -0
  56. package/dist/utils/pluralize.d.ts +1 -0
  57. package/dist/utils/round.d.ts +8 -0
  58. package/dist/utils/sortBy.d.ts +7 -0
  59. package/dist/utils/throttle.d.ts +3 -0
  60. package/dist/utils/uniq.d.ts +1 -0
  61. package/dist/utils/uniqBy.d.ts +2 -0
  62. package/dist/utils/uniqByKey.d.ts +1 -0
  63. package/dist/utils/upsert.d.ts +0 -0
  64. package/dist/utils/withTryCatch.d.ts +2 -0
  65. package/dist/utils/withTryCatchAsync.d.ts +2 -0
  66. package/dist/utils/wrap.d.ts +1 -0
  67. package/esbuild/index.cjs +2670 -0
  68. package/esbuild/index.mjs +2518 -0
  69. package/package.json +159 -0
  70. package/src/Lazy.ts +77 -0
  71. package/src/LazyAsync.ts +100 -0
  72. package/src/Logger.ts +44 -0
  73. package/src/Optional.ts +172 -0
  74. package/src/async/CancelableDeferred.ts +36 -0
  75. package/src/async/Deferred.ts +84 -0
  76. package/src/async/RateThrottler.ts +46 -0
  77. package/src/async/Semaphore.ts +45 -0
  78. package/src/async/index.ts +6 -0
  79. package/src/index.ts +13 -0
  80. package/src/random/index.ts +3 -0
  81. package/src/random/randomInterval.ts +4 -0
  82. package/src/random/randomPercentage.ts +6 -0
  83. package/src/sorting/ComparisonChain.ts +209 -0
  84. package/src/sorting/Sorter.ts +357 -0
  85. package/src/sorting/index.ts +5 -0
  86. package/src/sorting/types.ts +7 -0
  87. package/src/time/RandomTimeDuration.ts +21 -0
  88. package/src/time/TimeBase.ts +113 -0
  89. package/src/time/TimeDuration.ts +296 -0
  90. package/src/time/TimeFrequency.ts +28 -0
  91. package/src/time/TimeInstant.ts +488 -0
  92. package/src/time/TimeInstantBuilder.ts +126 -0
  93. package/src/time/TimeUnit.ts +43 -0
  94. package/src/time/index.ts +8 -0
  95. package/src/time/types.ts +56 -0
  96. package/src/types/arrays.ts +89 -0
  97. package/src/types/booleans.ts +8 -0
  98. package/src/types/functions.ts +27 -0
  99. package/src/types/index.ts +18 -0
  100. package/src/types/json.ts +5 -0
  101. package/src/types/nulls.ts +33 -0
  102. package/src/types/numbers.ts +80 -0
  103. package/src/types/promises.ts +23 -0
  104. package/src/types/records.ts +21 -0
  105. package/src/types/strings.ts +143 -0
  106. package/src/upgrade/DataUpgrader.ts +100 -0
  107. package/src/upgrade/errors.ts +25 -0
  108. package/src/upgrade/getTransitionsPath.ts +89 -0
  109. package/src/upgrade/index.ts +4 -0
  110. package/src/upgrade/types.ts +36 -0
  111. package/src/utils/asError.ts +12 -0
  112. package/src/utils/bindThis.ts +4 -0
  113. package/src/utils/constant.ts +9 -0
  114. package/src/utils/entries.ts +13 -0
  115. package/src/utils/groupBy.ts +39 -0
  116. package/src/utils/iff.ts +26 -0
  117. package/src/utils/index.ts +24 -0
  118. package/src/utils/indexBy.ts +36 -0
  119. package/src/utils/jsonCloneDeep.ts +31 -0
  120. package/src/utils/math.ts +44 -0
  121. package/src/utils/noop.ts +2 -0
  122. package/src/utils/omit.ts +8 -0
  123. package/src/utils/pad.ts +20 -0
  124. package/src/utils/pluralize.ts +20 -0
  125. package/src/utils/round.ts +24 -0
  126. package/src/utils/sortBy.ts +27 -0
  127. package/src/utils/throttle.ts +10 -0
  128. package/src/utils/uniq.ts +6 -0
  129. package/src/utils/uniqBy.ts +15 -0
  130. package/src/utils/uniqByKey.ts +5 -0
  131. package/src/utils/upsert.ts +2 -0
  132. package/src/utils/withTryCatch.ts +10 -0
  133. package/src/utils/withTryCatchAsync.ts +6 -0
  134. package/src/utils/wrap.ts +4 -0
@@ -0,0 +1,357 @@
1
+ import { TBiFunction, TConditionalParameterOptions, TFunction, TKeysOfType, TPositiveNumber, TReadableArray, isDefined, isNullOrUndefined } from "../types";
2
+ import { identity } from "../utils/constant.js";
3
+ import { TComparisonDirection, TComparisonFunction, TComparisonResult, TStrictComparisonResult } from "./types.js";
4
+
5
+ type TCompareValuesOptions = {
6
+ nullsFirst: boolean;
7
+ };
8
+ type TCompareFunctionOptions = {
9
+ nullsFirst: boolean;
10
+ direction: TComparisonDirection;
11
+ };
12
+
13
+ const defaultCompareValuesOptions = {
14
+ nullsFirst: false,
15
+ } as const satisfies Partial<TCompareValuesOptions>;
16
+ const defaultCompareFunctionOptions: TCompareFunctionOptions = {
17
+ ...defaultCompareValuesOptions,
18
+ direction: 'ASC',
19
+ } as const satisfies Partial<TCompareFunctionOptions>;
20
+
21
+ const naturalOrderComparison = <V>( a: V, b: V ) => a < b ? -1 : 1;
22
+
23
+ function compareValues<V>( a: V, b: V, cmp: TBiFunction<V, V, TComparisonResult>, { nullsFirst }: TCompareValuesOptions ): TComparisonResult {
24
+ if ( a === b )
25
+ return 0;
26
+
27
+ const nullA = isNullOrUndefined( a );
28
+ const nullB = isNullOrUndefined( b );
29
+ if ( nullA && nullB )
30
+ return 0;
31
+ if ( nullA !== nullB )
32
+ return ( nullA === nullsFirst ) ? -1 : 1;
33
+
34
+ // A & B are defined and are different.
35
+ return cmp( a, b );
36
+ }
37
+
38
+ function compareFunction<T, V>( fn: TFunction<T, V>, cmp: TBiFunction<V, V, TStrictComparisonResult>, { nullsFirst, direction }: TCompareFunctionOptions ): TComparisonFunction<T> {
39
+ return ( a: T, b: T ) => applyDirection( compareValues<V>( fn( a ), fn( b ), cmp, { nullsFirst } ), direction );
40
+ }
41
+
42
+ function applyDirection( res: TComparisonResult, direction: TComparisonDirection ): TComparisonResult {
43
+ return res * ( direction === 'ASC' ? 1 : -1 ) as TComparisonResult
44
+ }
45
+
46
+ function combine<T, R, S>( f: TFunction<T, R>, g: TFunction<R, S> ): TFunction<T, S> {
47
+ return ( t: T ) => g( f( t ) );
48
+ }
49
+
50
+ function reverse<T>( fn: TComparisonFunction<T> ): TComparisonFunction<T> {
51
+ return ( a: T, b: T ) => fn( a, b ) * -1 as TComparisonResult;
52
+ }
53
+
54
+ const chain = <T>( fns: ReadonlyArray<TComparisonFunction<T>>, cmpFn: TComparisonFunction<T> ): TSorter<T> => {
55
+ return doCreateWithFunctions( [...fns, cmpFn] );
56
+ }
57
+
58
+ const transformAndChain = <T, R>( fns: ReadonlyArray<TComparisonFunction<T>>, transform: TFunction<T, R>, cmpFn: TComparisonFunction<R> ): TSorter<T> => {
59
+ const fn: TComparisonFunction<T> = ( a: T, b: T ) => cmpFn( transform( a ), transform( b ) );
60
+ return chain( fns, fn );
61
+ }
62
+ const compareStrings = <T, R extends string>( fns: ReadonlyArray<TComparisonFunction<T>>, transform: TFunction<T, R>, options: TConditionalParameterOptions<TStringComparisonOptions, typeof defaultStringComparisonOptions> = {} ) => {
63
+ const { nullsFirst, direction, ignoreCase } = { ...defaultStringComparisonOptions, ...options };
64
+ if ( ignoreCase )
65
+ transform = combine<T, R, R>( transform, t => t.toLowerCase() as R );
66
+ return chain( fns, compareFunction( transform, naturalOrderComparison, { nullsFirst, direction } ) );
67
+ };
68
+ const compareNumbers = <T, R extends number>( fns: ReadonlyArray<TComparisonFunction<T>>, transform: TFunction<T, R>, options: TConditionalParameterOptions<TNumberComparisonOptions, typeof defaultNumberComparisonOptions> = {} ) => {
69
+ const { nullsFirst, direction } = { ...defaultNumberComparisonOptions, ...options };
70
+ return chain( fns, compareFunction( transform, naturalOrderComparison, { nullsFirst, direction } ) );
71
+ };
72
+ const compareDates = <T, R extends Date>( fns: ReadonlyArray<TComparisonFunction<T>>, transform: TFunction<T, R>, options: TConditionalParameterOptions<TDateComparisonOptions, typeof defaultDateComparisonOptions> = {} ) => {
73
+ const { nullsFirst, direction } = { ...defaultDateComparisonOptions, ...options };
74
+ return chain( fns, compareFunction( transform, naturalOrderComparison, { nullsFirst, direction } ) );
75
+ };
76
+ const compareBooleans = <T, R extends boolean>( fns: ReadonlyArray<TComparisonFunction<T>>, transform: TFunction<T, R>, options: TConditionalParameterOptions<TBooleanComparisonOptions, typeof defaultBooleanComparisonOptions> ) => {
77
+ const { nullsFirst, truesFirst } = { ...defaultBooleanComparisonOptions, ...options };
78
+ return chain( fns, compareFunction( transform, naturalOrderComparison, { nullsFirst, direction: truesFirst ? 'DESC' : 'ASC' } ) );
79
+ };
80
+ const prioritizeSet = <T, R>( fns: ReadonlyArray<TComparisonFunction<T>>, transform: TFunction<T, R>, set: ReadonlyArray<R>, reversed = false ) => {
81
+ return compareBooleans( fns, ( t: T ) => {
82
+ const r = transform( t );
83
+ return isDefined( r ) && set.includes( r );
84
+ }, { truesFirst: !reversed, nullsFirst: false } );
85
+ }
86
+ const prioritizeArray = <T, R>( fns: ReadonlyArray<TComparisonFunction<T>>, transform: TFunction<T, R>, arr: ReadonlyArray<R>, reversed = false ) => {
87
+ return compareNumbers( fns, ( t: T ) => {
88
+ const r = transform( t );
89
+ if ( !isDefined( r ) ) return Number.MAX_VALUE;
90
+ const indexOf = arr.indexOf( r );
91
+ return indexOf === -1 ? Number.MAX_VALUE : indexOf;
92
+ }, { direction: reversed ? 'DESC' : 'ASC', nullsFirst: false } );
93
+ }
94
+
95
+ const next = <T, R>( fns: ReadonlyArray<TComparisonFunction<T>>, transform: TFunction<T, R> ): TSorterStepFull<R, TSorter<T>> => {
96
+ const using = <X>( transformToX: TFunction<R, X> ) => {
97
+ return next( fns, combine( transform, transformToX ) ) satisfies TSorterStepFull<X, TSorter<T>> as any;
98
+ };
99
+ const retAsChainable = {
100
+ chain( chain: TComparable<R> ) {
101
+ return transformAndChain( fns, transform, chain.compare );
102
+ },
103
+ } as const satisfies TSorterStepForChainables<R, TSorter<T>>;
104
+ const retAsUsing = {
105
+ using,
106
+ } as const satisfies TSorterStepForUsing<R, TSorter<T>>;
107
+ const retAsPrioritizable = {
108
+ prioritizing( arr: Array<R>, _options: TConditionalParameterOptions<TPrioritizeOptions, typeof defaultPrioritizeOptions> = {} ) {
109
+ return prioritizeArray( fns, transform, arr );
110
+ },
111
+ deprioritizing( arr: Array<R>, _options: TConditionalParameterOptions<TPrioritizeOptions, typeof defaultPrioritizeOptions> = {} ) {
112
+ return prioritizeArray( fns, transform, arr, true );
113
+ },
114
+ prioritizingWithEqualWeight( arr: Array<R>, _options: TConditionalParameterOptions<TPrioritizeOptions, typeof defaultPrioritizeOptions> = {} ) {
115
+ return prioritizeSet( fns, transform, arr );
116
+ },
117
+ deprioritizingWithEqualWeight( arr: Array<R>, _options: TConditionalParameterOptions<TPrioritizeOptions, typeof defaultPrioritizeOptions> = {} ) {
118
+ return prioritizeSet( fns, transform, arr, true );
119
+ },
120
+ } as const satisfies TSorterStepForPrioritizable<any, TSorter<T>>;
121
+ const retForRecords = {
122
+ ...retAsUsing,
123
+ usingStrings: field => using( t => t[field] ),
124
+ usingNumbers: field => using( t => t[field] ),
125
+ usingBooleans: field => using( t => t[field] ),
126
+ usingDates: field => using( t => t[field] ),
127
+ } as const satisfies TSorterStepForRecords<R, TSorter<T>>;
128
+ const retForNumbers = {
129
+ ...retAsUsing,
130
+ inAscendingOrder( opts: { nullsFirst?: boolean } = {} ) {
131
+ return compareNumbers( fns, transform as TFunction<T, number>, { direction: 'ASC', ...opts } );
132
+ },
133
+ inDescendingOrder( opts: { nullsFirst?: boolean } = {} ) {
134
+ return compareNumbers( fns, transform as TFunction<T, number>, { direction: 'DESC', ...opts } );
135
+ },
136
+ } as const satisfies TSorterStepForNumbers<R, TSorter<T>>;
137
+ const retForStrings = {
138
+ ...retAsUsing,
139
+ inLexographicalOrder( opts: { nullsFirst?: boolean } = {} ) {
140
+ return compareStrings( fns, transform as TFunction<T, string>, { direction: 'ASC', ignoreCase: false, ...opts } );
141
+ },
142
+ inLexographicalOrderIgnoringCase( opts: { nullsFirst?: boolean } = {} ) {
143
+ return compareStrings( fns, transform as TFunction<T, string>, { direction: 'ASC', ignoreCase: true, ...opts } );
144
+ },
145
+ inReverseLexographicalOrder( opts: { nullsFirst?: boolean } = {} ) {
146
+ return compareStrings( fns, transform as TFunction<T, string>, { direction: 'DESC', ignoreCase: false, ...opts } );
147
+ },
148
+ inReverseLexographicalOrderIgnoringCase( opts: { nullsFirst?: boolean } = {} ) {
149
+ return compareStrings( fns, transform as TFunction<T, string>, { direction: 'DESC', ignoreCase: true, ...opts } );
150
+ },
151
+ } as const satisfies TSorterStepForStrings<R, TSorter<T>>;
152
+ const retForBooleans = {
153
+ ...retAsUsing,
154
+ truesFirst( opts: { nullsFirst?: boolean } = {} ) {
155
+ return compareBooleans( fns, transform as TFunction<T, boolean>, { truesFirst: true, ...opts } );
156
+ },
157
+ falsesFirst( opts: { nullsFirst?: boolean } = {} ) {
158
+ return compareBooleans( fns, transform as TFunction<T, boolean>, { truesFirst: false, ...opts } );
159
+ },
160
+ } as const satisfies TSorterStepForBooleans<R, TSorter<T>>;
161
+ const retForDates = {
162
+ ...retAsUsing,
163
+ mostAncientFirst( opts: { nullsFirst?: boolean } = {} ) {
164
+ return compareDates( fns, transform as TFunction<T, Date>, { direction: 'ASC', ...opts } );
165
+ },
166
+ mostRecentFirst( opts: { nullsFirst?: boolean } = {} ) {
167
+ return compareDates( fns, transform as TFunction<T, Date>, { direction: 'DESC', ...opts } );
168
+ },
169
+ } as const satisfies TSorterStepForDates<R, TSorter<T>>;
170
+ return {
171
+ ...retAsPrioritizable,
172
+ ...retAsChainable,
173
+ ...retForRecords,
174
+ ...retForNumbers,
175
+ ...retForStrings,
176
+ ...retForBooleans,
177
+ ...retForDates,
178
+ } as const satisfies TSorterStepFull<R, TSorter<T>>;
179
+ };
180
+
181
+ const createComparisonFunction = <T>( fns: ReadonlyArray<TComparisonFunction<T>> ): TComparisonFunction<T> => {
182
+ return ( a: T, b: T ) => {
183
+ let cmp: TComparisonResult = 0, i: number = 0;
184
+ while ( i < fns.length && cmp === 0 ) {
185
+ cmp = fns[i++]( a, b );
186
+ }
187
+ return cmp;
188
+ }
189
+ };
190
+
191
+ const compare = <T>( fns: ReadonlyArray<TComparisonFunction<T>>, a: T, b: T ): TComparisonResult => {
192
+ return createComparisonFunction( fns )( a, b );
193
+ };
194
+
195
+ const sort = <T>( fns: ReadonlyArray<TComparisonFunction<T>>, arr: TReadableArray<T> ): Array<T> => {
196
+ const comparisonFn = createComparisonFunction( fns );
197
+ return [...arr].sort( comparisonFn );
198
+ };
199
+
200
+ const top = <T>( fns: ReadonlyArray<TComparisonFunction<T>>, arr: TReadableArray<T>, n: TPositiveNumber ): Array<T> => {
201
+ return sort( fns, arr ).slice( 0, Math.max( 0, n ) );
202
+ };
203
+
204
+ const bottom = <T>( fns: ReadonlyArray<TComparisonFunction<T>>, arr: TReadableArray<T>, n: TPositiveNumber ): Array<T> => {
205
+ return sort( fns, arr ).slice( -Math.max( 0, n ) ).reverse();
206
+ };
207
+
208
+ const first = <T>( fns: ReadonlyArray<TComparisonFunction<T>>, arr: TReadableArray<T> ): T | null => {
209
+ return arr.length ? top( fns, arr, 1 )[0] : null;
210
+ };
211
+
212
+ const last = <T>( fns: ReadonlyArray<TComparisonFunction<T>>, arr: TReadableArray<T> ): T | null => {
213
+ return arr.length ? bottom( fns, arr, 1 )[0] : null;
214
+ };
215
+
216
+ function doCreateEmpty<T>(): TSorterStarter<T> {
217
+ // If we have no comparison functions, return an object that only has chain methods.
218
+ return next( [], x => x ) satisfies TSorterStepFull<T, TSorter<T>> as unknown as TSorterStarter<T>;
219
+ }
220
+
221
+ function doCreateWithFunctions<T>( fns: ReadonlyArray<TComparisonFunction<T>> ): TSorter<T> {
222
+ // If we have some comparison functions, return an object that has chain methods and ending methods.
223
+ return {
224
+ get then() {
225
+ return next( fns, identity ) satisfies TSorterStepFull<T, TSorter<T>> as any;
226
+ },
227
+ reversed() {
228
+ return doCreateWithFunctions( [...fns.map( reverse )] );
229
+ },
230
+ compare: ( a: T, b: T ) => {
231
+ return compare( fns, a, b )
232
+ },
233
+ sort: ( arr: TReadableArray<T> ): Array<T> => {
234
+ return sort( fns, arr );
235
+ },
236
+ top: ( arr: TReadableArray<T>, n: TPositiveNumber ): Array<T> => {
237
+ return top( fns, arr, n );
238
+ },
239
+ bottom: ( arr: TReadableArray<T>, n: TPositiveNumber ): Array<T> => {
240
+ return bottom( fns, arr, n );
241
+ },
242
+ first: ( arr: TReadableArray<T> ): T | null => {
243
+ return first( fns, arr );
244
+ },
245
+ last: ( arr: TReadableArray<T> ): T | null => {
246
+ return last( fns, arr );
247
+ },
248
+ } as const satisfies TSorter<T>;
249
+ }
250
+
251
+ type TComparable<T> = { compare: TComparisonFunction<T> };
252
+
253
+ export type TSorter<T> = {
254
+ get then(): TSorterStep<T, TSorter<T>>;
255
+ reversed: () => TSorter<T>;
256
+
257
+ compare: TComparisonFunction<T>;
258
+ sort: ( arr: TReadableArray<T> ) => Array<T>;
259
+ top: ( arr: TReadableArray<T>, n: TPositiveNumber ) => Array<T>;
260
+ bottom: ( arr: TReadableArray<T>, n: TPositiveNumber ) => Array<T>;
261
+ first: ( arr: TReadableArray<T> ) => T | null;
262
+ last: ( arr: TReadableArray<T> ) => T | null;
263
+ }
264
+
265
+ type TSorterStepForRecords<T, Ret> = {
266
+ usingStrings: ( field: TKeysOfType<T, string> ) => TSorterStep<string, Ret>;
267
+ usingNumbers: ( field: TKeysOfType<T, number> ) => TSorterStep<number, Ret>;
268
+ usingBooleans: ( field: TKeysOfType<T, boolean> ) => TSorterStep<boolean, Ret>;
269
+ usingDates: ( field: TKeysOfType<T, Date> ) => TSorterStep<Date, Ret>;
270
+ };
271
+ type TSorterStepForNumbers<_T, Ret> = {
272
+ inAscendingOrder( opts?: { nullsFirst?: boolean } ): Ret;
273
+ inDescendingOrder( opts?: { nullsFirst?: boolean } ): Ret;
274
+ };
275
+ type TSorterStepForStrings<_T, Ret> = {
276
+ inLexographicalOrder( opts?: { nullsFirst?: boolean } ): Ret;
277
+ inLexographicalOrderIgnoringCase( opts?: { nullsFirst?: boolean } ): Ret;
278
+ inReverseLexographicalOrder( opts?: { nullsFirst?: boolean } ): Ret;
279
+ inReverseLexographicalOrderIgnoringCase( opts?: { nullsFirst?: boolean } ): Ret;
280
+ };
281
+ type TSorterStepForBooleans<_T, Ret> = {
282
+ truesFirst( opts?: { nullsFirst?: boolean } ): Ret;
283
+ falsesFirst( opts?: { nullsFirst?: boolean } ): Ret;
284
+ };
285
+ type TSorterStepForDates<_T, Ret> = {
286
+ mostAncientFirst( opts?: { nullsFirst?: boolean } ): Ret;
287
+ mostRecentFirst( opts?: { nullsFirst?: boolean } ): Ret;
288
+ };
289
+ type TSorterStepForChainables<T, Ret> = {
290
+ chain: ( chain: TComparable<T> ) => Ret;
291
+ };
292
+ type TSorterStepForUsing<T, Ret> = {
293
+ using: <X>( transform: TFunction<T, X> ) => TSorterStep<X, Ret>;
294
+ };
295
+ type TSorterStepForPrioritizable<T extends string | number, Ret> = {
296
+ prioritizing( arr: T[], options?: TConditionalParameterOptions<TPrioritizeOptions, typeof defaultPrioritizeOptions> ): Ret;
297
+ deprioritizing( arr: Array<T>, options?: TConditionalParameterOptions<TPrioritizeOptions, typeof defaultPrioritizeOptions> ): Ret;
298
+ prioritizingWithEqualWeight( arr: T[], options?: TConditionalParameterOptions<TPrioritizeOptions, typeof defaultPrioritizeOptions> ): Ret;
299
+ deprioritizingWithEqualWeight( arr: Array<T>, options?: TConditionalParameterOptions<TPrioritizeOptions, typeof defaultPrioritizeOptions> ): Ret;
300
+ };
301
+ type TSorterStep<T, Ret> = {}
302
+ & ( T extends Record<string | number | symbol, unknown> ? TSorterStepForRecords<T, Ret> : {} )
303
+ & ( T extends number ? TSorterStepForNumbers<T, Ret> : {} )
304
+ & ( T extends string ? TSorterStepForStrings<T, Ret> : {} )
305
+ & ( T extends boolean ? TSorterStepForBooleans<T, Ret> : {} )
306
+ & ( T extends Date ? TSorterStepForDates<T, Ret> : {} )
307
+ & ( T extends string ? TSorterStepForPrioritizable<string, Ret> : {} ) // Allowing all types of strings here is needed because literal types extending strings create compilation problems with method signatures (T[] where T = 'A' | 'B' becomes 'A'[] & 'B'[])
308
+ & ( T extends number ? TSorterStepForPrioritizable<number, Ret> : {} ) // Allowing all types of numbers here is needed because literal types extending numbers create compilation problems with method signatures (T[] where T = 1 | 2 becomes 1[] & 2[])
309
+ & TSorterStepForChainables<T, Ret>
310
+ & TSorterStepForUsing<T, Ret>
311
+ ;
312
+ type TSorterStepFull<T, Ret> = TSorterStepForRecords<T, Ret>
313
+ & TSorterStepForNumbers<T, Ret>
314
+ & TSorterStepForStrings<T, Ret>
315
+ & TSorterStepForBooleans<T, Ret>
316
+ & TSorterStepForDates<T, Ret>
317
+ & TSorterStepForChainables<T, Ret>
318
+ & TSorterStepForUsing<T, Ret>
319
+ ;
320
+ type TSorterStarter<T> = TSorterStep<T, TSorter<T>>;
321
+ export type TSorterBuilder<T> = ( builder: TSorterStarter<T> ) => TSorter<T>;
322
+
323
+ type TStringComparisonOptions = TCompareFunctionOptions & { ignoreCase: boolean };
324
+ const defaultStringComparisonOptions = { ...defaultCompareFunctionOptions, ignoreCase: false } as const satisfies Partial<TStringComparisonOptions>;
325
+
326
+ type TNumberComparisonOptions = TCompareFunctionOptions;
327
+ const defaultNumberComparisonOptions = { ...defaultCompareFunctionOptions } as const satisfies Partial<TNumberComparisonOptions>;
328
+
329
+ type TDateComparisonOptions = TCompareFunctionOptions;
330
+ const defaultDateComparisonOptions = { ...defaultCompareFunctionOptions } as const satisfies Partial<TDateComparisonOptions>;
331
+
332
+ type TBooleanComparisonOptions = TCompareValuesOptions & { truesFirst: boolean };
333
+ const defaultBooleanComparisonOptions = { ...defaultCompareValuesOptions } as const satisfies Partial<TBooleanComparisonOptions>;
334
+
335
+ type TPrioritizeOptions = {};
336
+ const defaultPrioritizeOptions = {} as const satisfies Partial<TPrioritizeOptions>;
337
+
338
+ /**
339
+ * @deprecated[2023-10-19]: Use {@link Sorter.createFor} instead.
340
+ **/
341
+ export function createSorterFor<T>() {
342
+ return doCreateEmpty<T>();
343
+ }
344
+
345
+ export const Sorter = {
346
+ createFor: <T>() => doCreateEmpty<T>(),
347
+ sort: <T>( arr: TReadableArray<T>, builder: TSorterBuilder<T> ) => builder( doCreateEmpty() ).sort( arr ),
348
+ top: <T>( arr: TReadableArray<T>, n: TPositiveNumber, builder: TSorterBuilder<T> ) => builder( doCreateEmpty() ).top( arr, n ),
349
+ bottom: <T>( arr: TReadableArray<T>, n: TPositiveNumber, builder: TSorterBuilder<T> ) => builder( doCreateEmpty() ).bottom( arr, n ),
350
+ first: <T>( arr: TReadableArray<T>, builder: TSorterBuilder<T> ) => builder( doCreateEmpty() ).first( arr ),
351
+ last: <T>( arr: TReadableArray<T>, builder: TSorterBuilder<T> ) => builder( doCreateEmpty() ).last( arr ),
352
+ };
353
+ /**
354
+ * @deprecated[2023-11-01]: Use {@link Sorter} instead.
355
+ **/
356
+ export const Sorting = Sorter;
357
+ export default Sorter;
@@ -0,0 +1,5 @@
1
+
2
+ export * from './types.js';
3
+ export { default as ComparisonChain } from './ComparisonChain.js';
4
+ export * from './Sorter.js';
5
+ export * from './types.js';
@@ -0,0 +1,7 @@
1
+ import { TBiFunction } from "../types/functions.js";
2
+
3
+
4
+ export type TComparisonResult = -1 | 0 | 1;
5
+ export type TStrictComparisonResult = -1 | 1;
6
+ export type TComparisonFunction<T> = TBiFunction<T, T, TComparisonResult>;
7
+ export type TComparisonDirection = 'ASC' | 'DESC';
@@ -0,0 +1,21 @@
1
+ import randomInterval from "../random/randomInterval.js";
2
+ import TimeDuration from "./TimeDuration.js";
3
+ import TimeUnit from "./TimeUnit.js";
4
+
5
+ function randomize( unit: TimeUnit ) {
6
+ return ( a: number, b: number ) => {
7
+ return TimeDuration.fromMs( randomInterval( unit.toMs( a ), unit.toMs( b ) ) );
8
+ }
9
+ }
10
+
11
+ export default class RandomTimeDuration {
12
+
13
+ private constructor() {}
14
+
15
+ public static ms = randomize( TimeUnit.MILLISECONDS );
16
+ public static seconds = randomize( TimeUnit.SECONDS );
17
+ public static minutes = randomize( TimeUnit.MINUTES );
18
+ public static hours = randomize( TimeUnit.HOURS );
19
+ public static days = randomize( TimeUnit.DAYS );
20
+
21
+ }
@@ -0,0 +1,113 @@
1
+ import TimeUnit from "./TimeUnit";
2
+
3
+ export default abstract class TimeBase<T> {
4
+
5
+ private readonly _ms: number;
6
+
7
+ protected constructor(
8
+ value: number,
9
+ unit: TimeUnit
10
+ ) {
11
+ this._ms = unit.toMs( value );
12
+ }
13
+
14
+ protected abstract create( value: number, unit: TimeUnit ): T;
15
+
16
+ public get ms(): number {
17
+ return this._ms / TimeUnit.MILLISECONDS.multiplier;
18
+ }
19
+
20
+ public get seconds(): number {
21
+ return this._ms / TimeUnit.SECONDS.multiplier;
22
+ }
23
+
24
+ public get minutes(): number {
25
+ return this._ms / TimeUnit.MINUTES.multiplier;
26
+ }
27
+
28
+ public get hours(): number {
29
+ return this._ms / TimeUnit.HOURS.multiplier;
30
+ }
31
+
32
+ public get days(): number {
33
+ return this._ms / TimeUnit.DAYS.multiplier;
34
+ }
35
+
36
+ public addMs( milliseconds: number ): T {
37
+ return this.addUnits( milliseconds, TimeUnit.MILLISECONDS );
38
+ }
39
+
40
+ public addSeconds( seconds: number ): T {
41
+ return this.addUnits( seconds, TimeUnit.SECONDS );
42
+ }
43
+
44
+ public addMinutes( minutes: number ): T {
45
+ return this.addUnits( minutes, TimeUnit.MINUTES );
46
+ }
47
+
48
+ public addHours( hours: number ): T {
49
+ return this.addUnits( hours, TimeUnit.HOURS );
50
+ }
51
+
52
+ public addDays( days: number ): T {
53
+ return this.addUnits( days, TimeUnit.DAYS );
54
+ }
55
+
56
+ public removeDays( days: number ): T {
57
+ return this.removeUnits( days, TimeUnit.DAYS );
58
+ }
59
+
60
+ public addUnits( n: number, unit: TimeUnit ): T {
61
+ return this.create( this._ms + unit.toMs( n ), TimeUnit.MILLISECONDS );
62
+ }
63
+
64
+ public removeMs( milliseconds: number ): T {
65
+ return this.addUnits( -milliseconds, TimeUnit.MILLISECONDS );
66
+ }
67
+
68
+ public removeSeconds( seconds: number ): T {
69
+ return this.addUnits( -seconds, TimeUnit.SECONDS );
70
+ }
71
+
72
+ public removeMinutes( minutes: number ): T {
73
+ return this.addUnits( -minutes, TimeUnit.MINUTES );
74
+ }
75
+
76
+ public removeHours( hours: number ): T {
77
+ return this.addUnits( -hours, TimeUnit.HOURS );
78
+ }
79
+
80
+ public removeUnits( n: number, unit: TimeUnit ): T {
81
+ return this.addUnits( -n, unit );
82
+ }
83
+
84
+ public getUnit( unit: TimeUnit ): number {
85
+ return this._ms / unit.multiplier;
86
+ }
87
+
88
+ protected toUnits(): { days: number, hours: number, minutes: number, seconds: number } {
89
+ return {
90
+ days: Math.floor( ( this._ms / TimeUnit.DAYS.multiplier ) ),
91
+ hours: Math.floor( ( this._ms / TimeUnit.HOURS.multiplier ) % 24 ),
92
+ minutes: Math.floor( ( this._ms / TimeUnit.MINUTES.multiplier ) % 60 ),
93
+ seconds: Math.floor( ( this._ms / TimeUnit.SECONDS.multiplier ) % 60 ),
94
+ };
95
+ }
96
+
97
+ protected static toMs( units: { days?: number, hours?: number, minutes?: number, seconds?: number, ms?: number } ): number {
98
+ if ( !units )
99
+ throw new Error( 'Invalid units given' );
100
+ let ms = 0
101
+ ms += units.ms ?? 0 * TimeUnit.MILLISECONDS.multiplier;
102
+ ms += ( units.seconds ?? 0 ) * TimeUnit.SECONDS.multiplier;
103
+ ms += ( units.minutes ?? 0 ) * TimeUnit.MINUTES.multiplier;
104
+ ms += ( units.hours ?? 0 ) * TimeUnit.HOURS.multiplier;
105
+ ms += ( units.days ?? 0 ) * TimeUnit.DAYS.multiplier;
106
+ return ms;
107
+ }
108
+
109
+ public toJSON() {
110
+ return this._ms;
111
+ }
112
+
113
+ }