@zelgadis87/utils-core 4.5.0 → 4.6.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 (65) hide show
  1. package/esbuild/index.cjs +149 -249
  2. package/esbuild/{index.mjs → index.js} +147 -262
  3. package/esbuild/package.json +39 -0
  4. package/package.json +14 -102
  5. package/src/async/Semaphore.ts +8 -6
  6. package/src/time/TimeDuration.ts +22 -11
  7. package/src/time/TimeInstant.ts +38 -21
  8. package/src/utils/arrays/groupBy.ts +11 -11
  9. package/src/utils/random.ts +9 -3
  10. package/src/utils/records.ts +12 -0
  11. package/dist/Logger.d.ts +0 -21
  12. package/dist/Optional.d.ts +0 -70
  13. package/dist/async/CancelableDeferred.d.ts +0 -17
  14. package/dist/async/Deferred.d.ts +0 -34
  15. package/dist/async/RateThrottler.d.ts +0 -13
  16. package/dist/async/Semaphore.d.ts +0 -14
  17. package/dist/async/index.d.ts +0 -4
  18. package/dist/index.d.ts +0 -8
  19. package/dist/lazy/Lazy.d.ts +0 -22
  20. package/dist/lazy/LazyAsync.d.ts +0 -24
  21. package/dist/lazy/index.d.ts +0 -2
  22. package/dist/sorting/ComparisonChain.d.ts +0 -57
  23. package/dist/sorting/Sorter.d.ts +0 -100
  24. package/dist/sorting/index.d.ts +0 -4
  25. package/dist/sorting/types.d.ts +0 -5
  26. package/dist/time/RandomTimeDuration.d.ts +0 -9
  27. package/dist/time/TimeBase.d.ts +0 -38
  28. package/dist/time/TimeDuration.d.ts +0 -79
  29. package/dist/time/TimeFrequency.d.ts +0 -10
  30. package/dist/time/TimeInstant.d.ts +0 -171
  31. package/dist/time/TimeInstantBuilder.d.ts +0 -77
  32. package/dist/time/TimeRange.d.ts +0 -11
  33. package/dist/time/TimeUnit.d.ts +0 -17
  34. package/dist/time/index.d.ts +0 -7
  35. package/dist/time/types.d.ts +0 -26
  36. package/dist/tsconfig.tsbuildinfo +0 -1
  37. package/dist/upgrade/DataUpgrader.d.ts +0 -22
  38. package/dist/upgrade/errors.d.ts +0 -12
  39. package/dist/upgrade/getTransitionsPath.d.ts +0 -3
  40. package/dist/upgrade/index.d.ts +0 -2
  41. package/dist/upgrade/types.d.ts +0 -31
  42. package/dist/utils/arrays/groupBy.d.ts +0 -9
  43. package/dist/utils/arrays/indexBy.d.ts +0 -7
  44. package/dist/utils/arrays/statistics.d.ts +0 -8
  45. package/dist/utils/arrays/uniqBy.d.ts +0 -4
  46. package/dist/utils/arrays.d.ts +0 -57
  47. package/dist/utils/booleans.d.ts +0 -2
  48. package/dist/utils/empties.d.ts +0 -17
  49. package/dist/utils/errors/withTryCatch.d.ts +0 -3
  50. package/dist/utils/errors.d.ts +0 -3
  51. package/dist/utils/functions/constant.d.ts +0 -10
  52. package/dist/utils/functions/iff.d.ts +0 -8
  53. package/dist/utils/functions.d.ts +0 -31
  54. package/dist/utils/index.d.ts +0 -13
  55. package/dist/utils/json.d.ts +0 -11
  56. package/dist/utils/nulls.d.ts +0 -8
  57. package/dist/utils/numbers/round.d.ts +0 -8
  58. package/dist/utils/numbers.d.ts +0 -34
  59. package/dist/utils/primitives.d.ts +0 -3
  60. package/dist/utils/promises.d.ts +0 -6
  61. package/dist/utils/random.d.ts +0 -2
  62. package/dist/utils/records/entries.d.ts +0 -4
  63. package/dist/utils/records.d.ts +0 -21
  64. package/dist/utils/strings/StringParts.d.ts +0 -32
  65. package/dist/utils/strings.d.ts +0 -17
@@ -0,0 +1,39 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/package",
3
+ "name": "@zelgadis87/utils-core",
4
+ "version": "4.5.0",
5
+ "author": "Zelgadis87",
6
+ "license": "ISC",
7
+ "private": false,
8
+ "files": [
9
+ "/src",
10
+ "/dist",
11
+ "/esbuild"
12
+ ],
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./esbuild/index.js",
18
+ "require": "./esbuild/index.cjs"
19
+ }
20
+ },
21
+ "packageManager": "pnpm@10.0.0+sha512.b8fef5494bd3fe4cbd4edabd0745df2ee5be3e4b0b8b08fa643aa3e4c6702ccc0f00d68fa8a8c9858a735a0032485a44990ed2810526c875e416f001b17df12b",
22
+ "devDependencies": {
23
+ "@stylistic/eslint-plugin-ts": "catalog:",
24
+ "@typescript-eslint/eslint-plugin": "catalog:",
25
+ "@typescript-eslint/parser": "catalog:",
26
+ "@vitest/coverage-v8": "catalog:",
27
+ "@vitest/ui": "catalog:",
28
+ "esbuild": "catalog:",
29
+ "eslint": "catalog:",
30
+ "nx": "catalog:",
31
+ "rimraf": "catalog:",
32
+ "typescript": "catalog:",
33
+ "typescript-eslint": "^8.20.0",
34
+ "vitest": "catalog:"
35
+ },
36
+ "dependencies": {
37
+ "small-date": "^2.0.1"
38
+ }
39
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@zelgadis87/utils-core",
4
- "version": "4.5.0",
4
+ "version": "4.6.0",
5
5
  "author": "Zelgadis87",
6
6
  "license": "ISC",
7
7
  "private": false,
@@ -10,117 +10,29 @@
10
10
  "/dist",
11
11
  "/esbuild"
12
12
  ],
13
- "wireit": {
14
- "build:ts": {
15
- "command": "tsc --emitDeclarationOnly",
16
- "clean": "if-file-deleted",
17
- "files": [
18
- "./src/**"
19
- ],
20
- "output": [
21
- "./dist/**"
22
- ]
23
- },
24
- "build:cjs": {
25
- "command": "esbuild src/index.ts --bundle --platform=node --target=node18 --format=cjs --outfile=esbuild/index.cjs",
26
- "clean": "if-file-deleted",
27
- "files": [
28
- "./src/**"
29
- ],
30
- "output": [
31
- "./esbuild/index.cjs"
32
- ]
33
- },
34
- "build:esm": {
35
- "command": "esbuild src/index.ts --bundle --platform=node --target=node18 --format=esm --outfile=esbuild/index.mjs",
36
- "clean": "if-file-deleted",
37
- "files": [
38
- "./src/**"
39
- ],
40
- "output": [
41
- "./esbuild/index.mjs"
42
- ]
43
- },
44
- "build": {
45
- "dependencies": [
46
- "build:ts",
47
- "build:cjs",
48
- "build:esm"
49
- ]
50
- },
51
- "test": {
52
- "command": "vitest run --passWithNoTests",
53
- "clean": true,
54
- "files": [
55
- "./src/**/*.ts",
56
- "./test/**/*.spec.ts"
57
- ],
58
- "output": []
59
- },
60
- "test:coverage": {
61
- "command": "vitest run --coverage --passWithNoTests",
62
- "clean": true,
63
- "files": [
64
- "./src/**/*.ts",
65
- "./test/**/*.spec.ts"
66
- ],
67
- "output": [
68
- "./coverage/*.*"
69
- ]
70
- },
71
- "lint:strict": {
72
- "command": "eslint .",
73
- "dependencies": [],
74
- "clean": false,
75
- "files": [
76
- "./*.ts"
77
- ],
78
- "output": []
79
- },
80
- "check": {
81
- "dependencies": [
82
- "lint:strict",
83
- "test"
84
- ]
85
- }
86
- },
87
13
  "types": "./dist/index.d.ts",
88
14
  "exports": {
89
15
  ".": {
90
16
  "types": "./dist/index.d.ts",
91
- "import": "./esbuild/index.mjs",
17
+ "import": "./esbuild/index.js",
92
18
  "require": "./esbuild/index.cjs"
93
19
  }
94
20
  },
95
21
  "devDependencies": {
96
- "@stylistic/eslint-plugin-ts": "2.9.0",
97
- "@typescript-eslint/eslint-plugin": "8.12.2",
98
- "@typescript-eslint/parser": "8.12.2",
99
- "@vitest/coverage-v8": "^2.1.4",
100
- "@vitest/ui": "^2.1.4",
101
- "esbuild": "^0.24.0",
102
- "eslint": "^9.13.0",
103
- "rimraf": "^6.0.1",
104
- "typescript": "^5.6.3",
105
- "vitest": "^2.1.4",
106
- "wireit": "^0.14.9"
22
+ "@stylistic/eslint-plugin-ts": "2.13.0",
23
+ "@typescript-eslint/eslint-plugin": "8.20.0",
24
+ "@typescript-eslint/parser": "8.20.0",
25
+ "@vitest/coverage-v8": "2.1.8",
26
+ "@vitest/ui": "2.1.8",
27
+ "esbuild": "0.24.2",
28
+ "eslint": "9.18.0",
29
+ "nx": "20.3.2",
30
+ "rimraf": "6.0.1",
31
+ "typescript": "5.7.3",
32
+ "typescript-eslint": "^8.20.0",
33
+ "vitest": "2.1.8"
107
34
  },
108
35
  "dependencies": {
109
36
  "small-date": "^2.0.1"
110
- },
111
- "scripts": {
112
- "clean": "rimraf .wireit dist esbuild coverage",
113
- "build": "wireit",
114
- "lint": "pnpm eslint .",
115
- "lint:errors": "pnpm lint --quiet",
116
- "lint:strict": "wireit",
117
- "test": "wireit",
118
- "test:watch": "vitest dev --passWithNoTests",
119
- "test:ui": "vitest dev --ui --coverage --passWithNoTests",
120
- "test:coverage": "wireit",
121
- "test:production": "pnpm test -- -- --allowOnly=false",
122
- "check": "wireit",
123
- "preversion": "pnpm build && pnpm test:production",
124
- "prepublish": "pnpm build && pnpm test:production"
125
37
  }
126
38
  }
@@ -6,7 +6,11 @@ export class Semaphore {
6
6
  private readonly _queuedRequests: Deferred<void>[];
7
7
  private _inProgress = 0;
8
8
 
9
- constructor(
9
+ /** Creates a new Semaphore with a single slot. */
10
+ public constructor();
11
+ /** Creates a new Semaphore with the specified amounts of slots. */
12
+ public constructor( availableSlots: number );
13
+ public constructor(
10
14
  private _availableSlots: number = 1
11
15
  ) {
12
16
  this._queuedRequests = [];
@@ -28,19 +32,17 @@ export class Semaphore {
28
32
  private _releaseSlot() {
29
33
  const waitingSlotToResolve = this._queuedRequests.shift();
30
34
  if ( waitingSlotToResolve ) {
35
+ // Let the next request start.
31
36
  waitingSlotToResolve.resolve();
32
37
  } else {
38
+ // Free a slot.
33
39
  this._availableSlots += 1;
34
40
  this._inProgress -= 1;
35
41
  }
36
42
  }
37
43
 
38
44
  public async execute<T>( fn: TAsyncProducer<T> | TProducer<T>, cooldown: TimeDuration = TimeDuration.ZERO ) {
39
- return this._awaitSlot()
40
- .then( () => fn() )
41
- .finally( () => {
42
- void cooldown.promise().then( () => this._releaseSlot() );
43
- } );
45
+ return this._awaitSlot().then( fn ).finally( () => { void cooldown.delay( () => this._releaseSlot() ); } );
44
46
  }
45
47
 
46
48
  public get availableSlots() {
@@ -46,18 +46,17 @@ export class TimeDuration extends TimeBase<TimeDuration> {
46
46
  }
47
47
 
48
48
  /**
49
- * Returns the current duration in a human readable format, prioritizing the most significant unit of time and excluding the rest.
50
- * @todo[2023-06] Should allow more customization options
51
- * @todo[2023-06] By default should show the secondary unit only when actually needed (eg, 1h 20m & 3h, instead of 1h 20m & 3h 28m)
52
- * @todo[2023-06] Should not allow negative durations, as this is a duration and not an instant.
53
- * @returns the duration, with only the most significant units displayed as a human readable string, eg: 1d 20h, 10m 30s.
49
+ * Returns the current duration in a human readable format, prioritizing the most significant unit of time and excluding the rest.
50
+ * @todo[2023-06] Should allow more customization options
51
+ * @todo[2023-06] By default should show the secondary unit only when actually needed (eg, 1h 20m & 3h, instead of 1h 20m & 3h 28m)
52
+ * @todo[2023-06] Should not allow negative durations, as this is a duration and not an instant.
53
+ * @returns the duration, with only the most significant units displayed as a human readable string, eg: 1d 20h, 10m 30s.
54
54
  */
55
55
  public get formatted(): string {
56
56
  const format = ( x: number, u1: string, y: number, u2: string ): string => `${x}${u1} ${pad( y.toString(), 2, '0' )}${u2}`;
57
57
  const units = this.toUnits();
58
58
 
59
- if ( units.days >= 1 )
60
- return format( units.days, 'd', units.hours, 'h' );
59
+ if ( units.days >= 1 ) return format( units.days, 'd', units.hours, 'h' );
61
60
  else if ( units.hours >= 1 )
62
61
  return format( units.hours, 'h', units.minutes, 'm' );
63
62
  else if ( units.minutes >= 1 )
@@ -85,8 +84,7 @@ export class TimeDuration extends TimeBase<TimeDuration> {
85
84
  return setTimeout( cb, this.ms );
86
85
  }
87
86
 
88
-
89
- public promise(): ICancelablePromise<void> {
87
+ public cancelablePromise(): ICancelablePromise<void> {
90
88
  const deferred = new Deferred<void>;
91
89
  if ( this.ms > 0 ) {
92
90
  this.timeout( () => deferred.resolve() );
@@ -96,8 +94,21 @@ export class TimeDuration extends TimeBase<TimeDuration> {
96
94
  return deferred.asCancelablePromise();
97
95
  }
98
96
 
99
- public delay( cb: () => unknown ): ICancelable {
100
- const deferred = this.promise();
97
+ public promise(): Promise<void> {
98
+ if ( this.isEmpty() )
99
+ return Promise.resolve();
100
+
101
+ const deferred = new Deferred<void>;
102
+ this.timeout( () => deferred.resolve() );
103
+ return deferred.asPromise();
104
+ }
105
+
106
+ public delay( cb: () => unknown ): void {
107
+ void this.promise().then( () => cb() );
108
+ }
109
+
110
+ public cancelableDelay( cb: () => unknown ): ICancelable {
111
+ const deferred = this.cancelablePromise();
101
112
  void deferred.then( () => {
102
113
  cb();
103
114
  }, err => {
@@ -33,6 +33,16 @@ export class TimeInstant extends TimeBase<TimeInstant> {
33
33
  return TimeDuration.fromMs( Math.abs( this.ms - Date.now() ) );
34
34
  }
35
35
 
36
+ public timeLeftFrom( instant: TimeInstant ): TimeDuration {
37
+ const distance = this.ms - instant.ms;
38
+ return TimeDuration.fromMs( Math.max( distance, 0 ) );
39
+ }
40
+
41
+ public timeLeftFromNow(): TimeDuration {
42
+ const distance = this.ms - Date.now();
43
+ return TimeDuration.fromMs( Math.max( distance, 0 ) );
44
+ }
45
+
36
46
  public distanceFromStartOfDay(): TimeDuration {
37
47
  return this.distanceFrom( this.atStartOfDay() );
38
48
  }
@@ -49,16 +59,20 @@ export class TimeInstant extends TimeBase<TimeInstant> {
49
59
  return this.atTime( { hours: 23, minutes: 59, seconds: 59, milliseconds: 999 } );
50
60
  }
51
61
 
52
- public promise(): ICancelablePromise<void> {
53
- const ms = this.ms - Date.now();
54
- const duration = TimeDuration.fromMs( Math.max( ms, 0 ) );
55
- return duration.promise();
62
+ public promise(): Promise<void> {
63
+ return this.timeLeftFromNow().promise();
64
+ }
65
+
66
+ public cancelablePromise(): ICancelablePromise<void> {
67
+ return this.timeLeftFromNow().cancelablePromise();
56
68
  }
57
69
 
58
- public delay( cb: () => unknown ): ICancelable {
59
- const ms = this.ms - Date.now();
60
- const duration = TimeDuration.fromMs( Math.max( ms, 0 ) );
61
- return duration.delay( cb );
70
+ public delay( cb: () => unknown ): void {
71
+ return this.timeLeftFromNow().delay( cb );
72
+ }
73
+
74
+ public cancelableDelay( cb: () => unknown ): ICancelable {
75
+ return this.timeLeftFromNow().cancelableDelay( cb );
62
76
  }
63
77
 
64
78
  public ensureInTheFuture() {
@@ -191,22 +205,25 @@ export class TimeInstant extends TimeBase<TimeInstant> {
191
205
  }
192
206
 
193
207
  /**
194
- * @deprecated[04/07/2023]: Use distanceFromNow instead
195
- */
208
+ * @deprecated: Use {@link distanceFromNow} instead
209
+ */
210
+ // TODO[2023-07-04, Deprecated]: Remove this method in a future version
196
211
  public fromNow(): TimeDuration {
197
212
  return TimeDuration.ms( this.ms - Date.now() );
198
213
  }
199
214
 
200
215
  /**
201
- * @deprecated[04/07/2023]: Use distanceFrom instead
202
- */
216
+ * @deprecated: Use {@link distanceFrom} instead
217
+ */
218
+ // TODO[2023-07-04, Deprecated]: Remove this method in a future version
203
219
  public from( instant: TimeInstant ): TimeDuration {
204
220
  return TimeDuration.ms( this.ms - instant.ms );
205
221
  }
206
222
 
207
223
  /**
208
- * @deprecated[04/07/2023]: Use distanceFromUnixTimestamp instead
209
- */
224
+ * @deprecated: Use {@link distanceFromUnixTimestamp} instead
225
+ */
226
+ // TODO[2023-07-04, Deprecated]: Remove this method in a future version
210
227
  public fromTimestamp( timestamp: number ): TimeDuration {
211
228
  return TimeDuration.ms( this.ms - timestamp );
212
229
  }
@@ -260,8 +277,8 @@ export class TimeInstant extends TimeBase<TimeInstant> {
260
277
  }
261
278
 
262
279
  /**
263
- * @deprecated[19/07/2023] Use {@link fromParameters} instead.
264
- */
280
+ * @deprecated[19/07/2023] Use {@link fromParameters} instead.
281
+ */
265
282
  public static fromUnits( { date, month, year, hours, minutes, seconds }: { date: number, month: number, year: number, hours?: number, minutes?: number, seconds?: number } ): TimeInstant {
266
283
  const dt = Date.UTC( year, month - 1, date, hours ?? 0, minutes ?? 0, seconds ?? 0 );
267
284
  if ( isNaN( dt ) )
@@ -334,15 +351,15 @@ export class TimeInstant extends TimeBase<TimeInstant> {
334
351
  }
335
352
 
336
353
  /**
337
- * Returns the week number represented by this instant, according to the ISO 8601 standard.
354
+ * Returns the week number represented by this instant, according to the ISO 8601 standard.
338
355
  * Please note that the instant and the week number could be of two different years, eg the friday 1st january is actually part of week 52 of the previous year.
339
- */
356
+ */
340
357
  public get weekNumber(): { weekNumber: TWeekNumber, year: number } {
341
358
  /**
342
359
  * According to the ISO 8601 Standard, week number 1 is defined as the week containing the 4th of january (or, equivalently, the week that contains the first Thursday of the year).
343
360
  * As such, we basically have to count how many Thursdays there has been in this year.
344
361
  * Please note that the thursdayOfThisWeek could be in the previous year.
345
- */
362
+ */
346
363
  const date = this.toDate();
347
364
  const oneDay = 1000 * 60 * 60 * 24;
348
365
  const thursdayOfThisWeek = new Date( date.getFullYear(), date.getMonth(), date.getDate() + 4 - ( date.getDay() || 7 ), 14, 0, 0 );
@@ -353,8 +370,8 @@ export class TimeInstant extends TimeBase<TimeInstant> {
353
370
  }
354
371
 
355
372
  /**
356
- * This method is used to provide a better DX when inspecting a TimeInstant object in DevTools.
357
- */
373
+ * This method is used to provide a better DX when inspecting a TimeInstant object in DevTools.
374
+ */
358
375
  protected get _time() {
359
376
  return this.asHumanTimestamp();
360
377
  }
@@ -1,40 +1,40 @@
1
1
 
2
- import { TFunction, TKeysOfType } from "..";
2
+ import { TFunction, TKeysOfType, TReadableArray } from "..";
3
3
 
4
- export function groupByString<V, K extends TKeysOfType<V, string>>( arr: V[], field: K ): Record<V[K] & string, V[]> {
4
+ export function groupByString<V, K extends TKeysOfType<V, string>>( arr: TReadableArray<V>, field: K ): Record<V[ K ] & string, V[]> {
5
5
  return groupByStringWith( arr, t => t[ field ] as string );
6
6
  }
7
7
 
8
- export function groupByNumber<V, K extends TKeysOfType<V, number>>( arr: V[], field: K ): Record<V[K] & number, V[]> {
8
+ export function groupByNumber<V, K extends TKeysOfType<V, number>>( arr: TReadableArray<V>, field: K ): Record<V[ K ] & number, V[]> {
9
9
  return groupByNumberWith( arr, t => t[ field ] as number );
10
10
  }
11
11
 
12
- export function groupByBoolean<V, K extends TKeysOfType<V, boolean>>( arr: V[], field: K ): Record<"true" | "false", V[]> {
12
+ export function groupByBoolean<V, K extends TKeysOfType<V, boolean>>( arr: TReadableArray<V>, field: K ): Record<"true" | "false", V[]> {
13
13
  return groupByBooleanWith( arr, t => t[ field ] as boolean );
14
14
  }
15
15
 
16
- export function groupBySymbol<V, K extends TKeysOfType<V, symbol>>( arr: V[], field: K ): Record<V[K] & symbol, V[]> {
16
+ export function groupBySymbol<V, K extends TKeysOfType<V, symbol>>( arr: TReadableArray<V>, field: K ): Record<V[ K ] & symbol, V[]> {
17
17
  return groupBySymbolWith( arr, t => t[ field ] as symbol );
18
18
  }
19
19
 
20
- export function groupByStringWith<V, K extends string>( arr: V[], getter: TFunction<V, K> ): Record<K, V[]> {
20
+ export function groupByStringWith<V, K extends string>( arr: TReadableArray<V>, getter: TFunction<V, K> ): Record<K, V[]> {
21
21
  return doGroupByWith<K, V>( arr, getter );
22
22
  }
23
23
 
24
- export function groupByNumberWith<V, K extends number>( arr: V[], getter: TFunction<V, K> ): Record<K, V[]> {
24
+ export function groupByNumberWith<V, K extends number>( arr: TReadableArray<V>, getter: TFunction<V, K> ): Record<K, V[]> {
25
25
  return doGroupByWith<K, V>( arr, getter );
26
26
  }
27
27
 
28
- export function groupByBooleanWith<V, K extends boolean>( arr: V[], getter: TFunction<V, K> ): Record<"true" | "false", V[]> {
28
+ export function groupByBooleanWith<V, K extends boolean>( arr: TReadableArray<V>, getter: TFunction<V, K> ): Record<"true" | "false", V[]> {
29
29
  return doGroupByWith<"true" | "false", V>( arr, item => getter( item ) ? "true" : "false" );
30
30
  }
31
31
 
32
- export function groupBySymbolWith<V, K extends symbol>( arr: V[], getter: TFunction<V, K> ): Record<K, V[]> {
32
+ export function groupBySymbolWith<V, K extends symbol>( arr: TReadableArray<V>, getter: TFunction<V, K> ): Record<K, V[]> {
33
33
  return doGroupByWith<K, V>( arr, getter );
34
34
  }
35
35
 
36
- function doGroupByWith<K extends string | number | symbol, V>( arr: V[], getter: TFunction<V, K> ): Record<K, V[]> {
37
- return arr.reduce( ( dict, cur ) => {
36
+ function doGroupByWith<K extends string | number | symbol, V>( arr: TReadableArray<V>, getter: TFunction<V, K> ): Record<K, V[]> { // TODO[2025-01-03, Native]: Migrate to native @ https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/#object.groupby-and-map.groupby
37
+ return [ ...arr ].reduce( ( dict, cur ) => {
38
38
  const key = getter( cur );
39
39
  if ( key !== null && key !== undefined ) {
40
40
  const arr = dict[ key ] ?? [];
@@ -1,9 +1,15 @@
1
+ import { TPositiveNumber } from "./numbers.ts";
1
2
 
3
+ /** @deprecated[2025-01-14]: Use {@link randomNumberInInterval} instead. */
4
+ export const randomInterval = ( min: number, max: number ): number => randomNumberInInterval( min, max );
2
5
 
3
- export function randomInterval( min: number, max: number ): number {
6
+ /** @deprecated[2025-01-14]: Use {@link randomNumberInInterval} / 100 instead. */
7
+ export const randomPercentage = ( min: number, max: number ): number => randomNumberInInterval( min, max ) / 100;
8
+
9
+ export function randomNumberInInterval( min: number, max: number ): number {
4
10
  return Math.floor( Math.random() * ( max - min + 1 ) + min );
5
11
  }
6
12
 
7
- export function randomPercentage( min: number, max: number ): number {
8
- return randomInterval( min, max ) / 100;
13
+ export const randomId = ( length: TPositiveNumber ): string => {
14
+ return Math.random().toString(36).substring(2, length + 2);
9
15
  }
@@ -26,3 +26,15 @@ export type TConditionalParameterOptions<T, R> = TConditionalParameter<TOptionsW
26
26
  * Given a type T, replaces all fields of type From to fields of type To.
27
27
  */
28
28
  export type TReplaceType<T, From, To> = { [ K in keyof T ]: T[ K ] extends From ? To : T[ K ]; };
29
+
30
+ /**
31
+ * Given a type T, make field K required instead of optional.
32
+ */
33
+ export type TWithRequiredProperty<T, K extends keyof T> = T & {
34
+ [ Property in K ]-?: T[ Property ];
35
+ };
36
+
37
+ /**
38
+ * Given a type T, make all fields required instead of optional.
39
+ */
40
+ export type TWithRequiredProperties<T> = Required<T>;
package/dist/Logger.d.ts DELETED
@@ -1,21 +0,0 @@
1
- declare const LEVELS: readonly ["log", "debug", "info", "warn", "error"];
2
- type TLogLevel = keyof Console & typeof LEVELS[number];
3
- export type TLoggerOpts = {
4
- console: Console;
5
- enabled: boolean;
6
- minLevel: Uppercase<TLogLevel>;
7
- };
8
- export declare class Logger {
9
- readonly name: string;
10
- private enabled;
11
- private console;
12
- private minLevel;
13
- constructor(name: string, args?: Partial<TLoggerOpts>);
14
- get log(): (...args: any[]) => void;
15
- get debug(): (...args: any[]) => void;
16
- get info(): (...args: any[]) => void;
17
- get warn(): (...args: any[]) => void;
18
- get error(): (...args: any[]) => void;
19
- private logWrap;
20
- }
21
- export default Logger;
@@ -1,70 +0,0 @@
1
- import { TConsumer, TFunction, TPredicate, TProducer, TVoidFunction } from "./utils/functions.js";
2
- export declare class Optional<T> implements TOptional<T> {
3
- private _present;
4
- private _value;
5
- private constructor();
6
- get rawValue(): T | undefined;
7
- get(): T | never;
8
- set(t: T): void;
9
- clear(): void;
10
- isEmpty(): this is TEmptyOptional<T>;
11
- isPresent(): this is TPresentOptional<T>;
12
- ifEmpty(callback: TVoidFunction): void;
13
- ifPresent(callback: TConsumer<T>): void;
14
- apply(callbackIfPresent: TConsumer<T>, callbackIfEmpty: TVoidFunction): void;
15
- orElse(newValue: T | null | undefined): any;
16
- orElseGet(produceValue: TProducer<T | null | undefined>): TOptional<T>;
17
- orElseThrow(produceError: TProducer<Error>): TPresentOptional<T>;
18
- mapTo<R>(mapper: TFunction<T, R | null | undefined>): any;
19
- flatMapTo<R>(mapper: TFunction<T, TOptional<R>>): any;
20
- filter(predicate: TPredicate<T>): this | TEmptyOptional<T>;
21
- static empty<T>(): TEmptyOptional<T>;
22
- static of<T>(t: T): TPresentOptional<T>;
23
- static ofNullable<T>(t: T | null | undefined): TOptional<T>;
24
- }
25
- export default Optional;
26
- export type TOptional<T> = {
27
- readonly rawValue: T | undefined;
28
- /**
29
- * @returns the currently stored value, if any; throws {@link ErrorGetEmptyOptional} otherwise;
30
- */
31
- get(): T | never;
32
- /**
33
- * Places a new value inside this optional. Throws {@link ErrorSetEmptyOptional} if t is null or undefined.
34
- */
35
- set(t: T): void;
36
- /**
37
- * Clears the current value from this optional, if any.
38
- */
39
- clear(): void;
40
- isEmpty(): boolean;
41
- isPresent(): boolean;
42
- ifEmpty: (callback: TVoidFunction) => void;
43
- ifPresent: (callback: TConsumer<T>) => void;
44
- apply(callbackIfPresent: TConsumer<T>, callbackIfEmpty: TVoidFunction): void;
45
- orElse: ((newValue: T | null | undefined) => TOptional<T>);
46
- orElseGet: (produceValue: TProducer<T | null | undefined>) => TOptional<T>;
47
- orElseThrow: (produceError: TProducer<Error>) => TPresentOptional<T>;
48
- mapTo<R>(mapper: TFunction<T, R>): TOptional<R>;
49
- flatMapTo<R>(mapper: TFunction<T, TOptional<R>>): TOptional<R>;
50
- filter(predicate: TPredicate<T>): TOptional<T>;
51
- };
52
- export type TEmptyOptional<T> = TOptional<T> & {
53
- readonly rawValue: undefined;
54
- isEmpty(): true;
55
- isPresent(): false;
56
- };
57
- export type TPresentOptional<T> = TOptional<T> & {
58
- readonly rawValue: T;
59
- isEmpty(): false;
60
- isPresent(): true;
61
- };
62
- export declare class ErrorGetEmptyOptional extends Error {
63
- constructor();
64
- }
65
- export declare class ErrorSetEmptyOptional extends Error {
66
- constructor();
67
- }
68
- export declare class ErrorCannotInstantiatePresentOptionalWithEmptyValue extends Error {
69
- constructor();
70
- }
@@ -1,17 +0,0 @@
1
- import Deferred from "./Deferred.js";
2
- interface ICancelablePromise<T> extends Promise<T> {
3
- cancel(): void;
4
- }
5
- /** @deprecated use Deferred instead. */
6
- export default class CancelableDeferred<T = void> extends Deferred<T> implements ICancelablePromise<T> {
7
- private _canceled;
8
- get canceled(): boolean;
9
- constructor();
10
- cancel(): void;
11
- protected createInternals(): {
12
- promise: Promise<T>;
13
- resolve: (value: T) => void;
14
- reject: (reason: Error) => void;
15
- };
16
- }
17
- export {};
@@ -1,34 +0,0 @@
1
- export interface ICancelable {
2
- cancel(): void;
3
- }
4
- export interface ICancelablePromise<T> extends Promise<T>, ICancelable {
5
- }
6
- export declare class DeferredCanceledError extends Error {
7
- constructor();
8
- }
9
- export declare class Deferred<T = void> implements ICancelablePromise<T> {
10
- private _pending;
11
- private readonly _internals;
12
- get pending(): boolean;
13
- /** @deprecated: Use resolve, then and catch directly; use asPromise to return a promise type. */
14
- get promise(): Promise<T>;
15
- constructor();
16
- resolve(val: T): void;
17
- reject(reason: Error): void;
18
- cancel(): void;
19
- resolveIfPending(val: T): void;
20
- rejectIfPending(reason: Error): void;
21
- cancelIfPending(): void;
22
- then<R = T, S = T>(onFulfilled: ((value: T) => R | PromiseLike<R>) | null | undefined, onRejected?: ((reason: Error) => S | PromiseLike<S>) | null | undefined): Promise<R | S>;
23
- catch<R = T>(onRejected: ((reason: Error) => R | PromiseLike<R>) | null | undefined): Promise<T | R>;
24
- finally(onfinally: (() => void) | null | undefined): Promise<T>;
25
- asPromise(): Promise<T>;
26
- asCancelablePromise(): ICancelablePromise<T>;
27
- protected createInternals(): {
28
- promise: Promise<T>;
29
- resolve: (value: T) => void;
30
- reject: (reason: Error) => void;
31
- };
32
- get [Symbol.toStringTag](): string;
33
- }
34
- export default Deferred;
@@ -1,13 +0,0 @@
1
- import { TFunction, TPromisable } from "..";
2
- import TimeFrequency from "../time/TimeFrequency";
3
- type TPromiseFactory<T, R> = TFunction<T, Promise<R>>;
4
- export declare class RateThrottler {
5
- private readonly _frequency;
6
- private readonly _availableSlots;
7
- private readonly _waitingRequests;
8
- constructor(_frequency: TimeFrequency);
9
- get cooldown(): import("..").TimeDuration;
10
- execute<T>(fn: TPromiseFactory<void, T>): Promise<T>;
11
- }
12
- export default RateThrottler;
13
- export declare function throttle<TParams extends unknown[], R>(fn: (...params: TParams) => TPromisable<R>, frequence: TimeFrequency): (...params: TParams) => Promise<R>;
@@ -1,14 +0,0 @@
1
- import { TAsyncProducer, TProducer, TimeDuration } from "..";
2
- export declare class Semaphore {
3
- private _availableSlots;
4
- private readonly _queuedRequests;
5
- private _inProgress;
6
- constructor(_availableSlots?: number);
7
- private _awaitSlot;
8
- private _releaseSlot;
9
- execute<T>(fn: TAsyncProducer<T> | TProducer<T>, cooldown?: TimeDuration): Promise<T>;
10
- get availableSlots(): number;
11
- get queueSize(): number;
12
- get inProgressSize(): number;
13
- }
14
- export default Semaphore;
@@ -1,4 +0,0 @@
1
- export * from './CancelableDeferred.ts';
2
- export * from './Deferred';
3
- export * from './RateThrottler';
4
- export * from './Semaphore';