@zelgadis87/utils-core 5.0.2 → 5.0.4

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/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": "5.0.2",
4
+ "version": "5.0.4",
5
5
  "author": "Zelgadis87",
6
6
  "license": "ISC",
7
7
  "private": false,
@@ -22,15 +22,15 @@
22
22
  "@stylistic/eslint-plugin-ts": "4.2.0",
23
23
  "@typescript-eslint/eslint-plugin": "8.26.1",
24
24
  "@typescript-eslint/parser": "8.26.1",
25
- "@vitest/coverage-v8": "3.0.8",
26
- "@vitest/ui": "3.0.8",
27
- "esbuild": "0.19.2",
25
+ "@vitest/coverage-v8": "3.2.4",
26
+ "@vitest/ui": "3.2.4",
27
+ "esbuild": "0.25.8",
28
28
  "eslint": "9.22.0",
29
- "nx": "21.1.2",
29
+ "nx": "21.3.5",
30
30
  "rimraf": "6.0.1",
31
- "typescript": "5.8.2",
31
+ "typescript": "5.8.3",
32
32
  "typescript-eslint": "8.26.1",
33
- "vitest": "3.0.8"
33
+ "vitest": "3.2.4"
34
34
  },
35
35
  "dependencies": {
36
36
  "small-date": "^2.0.1"
package/src/Optional.ts CHANGED
@@ -33,6 +33,13 @@ export class Optional<T> implements TOptional<T> {
33
33
  this._present = true;
34
34
  }
35
35
 
36
+ protected setNullable( t: T | null | undefined ) {
37
+ if ( isDefined( t ) ) {
38
+ return this.set( t );
39
+ }
40
+ return this;
41
+ }
42
+
36
43
  public clear() {
37
44
  this._value = undefined;
38
45
  this._present = false;
@@ -61,32 +68,78 @@ export class Optional<T> implements TOptional<T> {
61
68
  }
62
69
  }
63
70
 
64
- public orElse( newValue: T ) {
71
+ public orElseReturn( newValue: T ): T {
65
72
  if ( this.isPresent() ) {
66
- return this._value;
73
+ return this.get();
67
74
  } else {
68
75
  return newValue;
69
76
  }
70
77
  }
71
- public orElseGet( newValueProducer: TProducer<T> ) {
78
+ public orElse = this.orElseReturn.bind( this );
79
+
80
+ public orElseProduce( newValueProducer: TProducer<T> ): T {
72
81
  if ( this.isPresent() ) {
73
- return this._value;
82
+ return this.get();
74
83
  } else {
75
84
  return newValueProducer();
76
85
  }
77
86
  }
87
+ public orElseGet = this.orElseProduce.bind( this );
88
+
89
+ public orElseReturnAndApply( newValue: T ): T {
90
+ if ( this.isPresent() ) {
91
+ return this.get();
92
+ } else {
93
+ this.set( newValue );
94
+ return newValue;
95
+ }
96
+ }
97
+
98
+ public orElseProduceAndApply( newValueProducer: TProducer<T> ): T {
99
+ if ( this.isPresent() ) {
100
+ return this.get();
101
+ } else {
102
+ const newValue = newValueProducer();
103
+ this.set( newValue );
104
+ return newValue;
105
+ }
106
+ }
107
+
108
+ public orElseReturnNullableAndApply( newValue: T | null | undefined ): TOptional<T> {
109
+ if ( this.isPresent() ) {
110
+ return this;
111
+ } else {
112
+ this.setNullable( newValue );
113
+ return this;
114
+ }
115
+ }
116
+
117
+ public orElseProduceNullableAndApply( newValueProducer: TProducer<T | null | undefined> ): TOptional<T> {
118
+ if ( this.isPresent() ) {
119
+ return this;
120
+ } else {
121
+ const newValue = newValueProducer();
122
+ this.setNullable( newValue );
123
+ return this;
124
+ }
125
+ }
78
126
 
79
- public orElseNullable( newValue: T | null | undefined ) {
127
+ public orElseReturnNullable( newValue: T | null | undefined ) {
80
128
  if ( this.isEmpty() ) return Optional.ofNullable( newValue );
81
129
  return this as TPresentOptional<T>;
82
130
  }
83
- public orElseGetNullable( newValueProducer: TProducer<T | null | undefined> ) {
131
+ public orElseNullable = this.orElseReturnNullable.bind( this );
132
+
133
+
134
+ public orElseProduceNullable( newValueProducer: TProducer<T | null | undefined> ) {
84
135
  if ( this.isEmpty() ) {
85
136
  const newValue = newValueProducer();
86
137
  return Optional.ofNullable( newValue );
87
138
  }
88
139
  return this as TPresentOptional<T>;
89
140
  }
141
+ public orElseGetNullable = this.orElseProduceNullable.bind( this );
142
+
90
143
 
91
144
  public orElseThrow( errorProducer: TProducer<Error> ) {
92
145
  if ( this.isEmpty() )
@@ -127,24 +180,28 @@ export default Optional;
127
180
  export type TOptional<T> = {
128
181
 
129
182
  /**
130
- * @returns the currently stored value, if any; throws {@link ErrorGetEmptyOptional} otherwise;
131
- */
183
+ * @returns the currently stored value, if any; throws {@link ErrorGetEmptyOptional} otherwise;
184
+ */
132
185
  get(): T;
186
+
133
187
  /**
134
- * @returns the currently stored value, if any; returns undefined otherwise;
135
- */
188
+ * @returns the currently stored value, if any; returns undefined otherwise;
189
+ */
136
190
  getRawValue(): T | undefined;
191
+
137
192
  /**
138
- * @returns the currently stored value, if any; throws the error generated by errorProducer otherwise;
139
- */
193
+ * @returns the currently stored value, if any; throws the error generated by errorProducer otherwise;
194
+ */
140
195
  getOrElseThrow: ( errorProducer: TProducer<Error> ) => T;
196
+
141
197
  /**
142
- * Places a new value inside this optional. Throws {@link ErrorSetEmptyOptional} if t is null or undefined.
143
- */
198
+ * Places a new value inside this optional. Throws {@link ErrorSetEmptyOptional} if t is null or undefined.
199
+ */
144
200
  set( t: T ): void;
201
+
145
202
  /**
146
- * Clears the current value from this optional, if any.
147
- */
203
+ * Clears the current value from this optional, if any.
204
+ */
148
205
  clear(): void;
149
206
  isEmpty(): boolean;
150
207
  isPresent(): boolean;
@@ -153,10 +210,25 @@ export type TOptional<T> = {
153
210
  ifPresent: ( callback: TConsumer<T> ) => void;
154
211
  apply( callbackIfPresent: TConsumer<T>, callbackIfEmpty: TVoidFunction ): void;
155
212
 
213
+ /** @deprecated[2025.07.25]: Replace with {@link orElseReturn} (drop-in replacement) */
156
214
  orElse: ( newValue: T ) => T;
215
+ /** @deprecated[2025.07.25]: Replace with {@link orElseProduce} (drop-in replacement) */
157
216
  orElseGet: ( newValueProducer: TProducer<T> ) => T;
217
+ /** @deprecated[2025.07.25]: Replace with {@link orElseReturnNullabe} (drop-in replacement) */
158
218
  orElseNullable: ( newValue: T | null | undefined ) => TOptional<T>;
219
+ /** @deprecated[2025.07.25]: Replace with {@link orElseProduceNullable} (drop-in replacement) */
159
220
  orElseGetNullable: ( newValueProducer: TProducer<T | null | undefined> ) => TOptional<T>;
221
+
222
+ orElseReturn: ( newValue: T ) => T;
223
+ orElseProduce: ( newValueProducer: TProducer<T> ) => T;
224
+ orElseReturnNullable: ( newValue: T | null | undefined ) => TOptional<T>;
225
+ orElseProduceNullable: ( newValueProducer: TProducer<T | null | undefined> ) => TOptional<T>;
226
+
227
+ orElseReturnAndApply: ( newValue: T ) => T;
228
+ orElseProduceAndApply: ( newValueProducer: TProducer<T> ) => T;
229
+ orElseReturnNullableAndApply: ( newValue: T | null | undefined ) => TOptional<T>;
230
+ orElseProduceNullableAndApply: ( newValueProducer: TProducer<T | null | undefined> ) => TOptional<T>;
231
+
160
232
  orElseThrow: ( errorProducer: TProducer<Error> ) => TPresentOptional<T>;
161
233
 
162
234
  mapTo<R>( mapper: TFunction<T, R> ): TOptional<R>;
@@ -1,6 +1,6 @@
1
1
  import { randomNumberInInterval } from "../utils/random.js";
2
2
  import TimeDuration from "./TimeDuration.js";
3
- import TimeUnit from "./TimeUnit.js";
3
+ import { TimeUnit } from "./TimeUnit.js";
4
4
 
5
5
  function randomize( unit: TimeUnit ) {
6
6
  return ( a: number, b: number ) => {
@@ -1,4 +1,12 @@
1
- import TimeUnit from "./TimeUnit";
1
+ import { TimeUnit } from "./TimeUnit";
2
+
3
+ export type TTimeInUnits = {
4
+ milliseconds: number;
5
+ seconds: number;
6
+ minutes: number;
7
+ hours: number;
8
+ days: number;
9
+ }
2
10
 
3
11
  export default abstract class TimeBase<T> {
4
12
 
@@ -13,22 +21,37 @@ export default abstract class TimeBase<T> {
13
21
 
14
22
  protected abstract create( value: number, unit: TimeUnit ): T;
15
23
 
24
+ /**
25
+ * Total number of milliseconds, rounded down.
26
+ */
16
27
  public get ms(): number {
17
28
  return Math.floor( this._ms / TimeUnit.MILLISECONDS.multiplier );
18
29
  }
19
30
 
31
+ /**
32
+ * Total number of seconds, rounded down.
33
+ */
20
34
  public get seconds(): number {
21
35
  return Math.floor( this._ms / TimeUnit.SECONDS.multiplier );
22
36
  }
23
37
 
38
+ /**
39
+ * Total number of minutes, rounded down.
40
+ */
24
41
  public get minutes(): number {
25
42
  return Math.floor( this._ms / TimeUnit.MINUTES.multiplier );
26
43
  }
27
44
 
45
+ /**
46
+ * Total number of hours, rounded down.
47
+ */
28
48
  public get hours(): number {
29
49
  return Math.floor( this._ms / TimeUnit.HOURS.multiplier );
30
50
  }
31
51
 
52
+ /**
53
+ * Total number of days, rounded down.
54
+ */
32
55
  public get days(): number {
33
56
  return Math.floor( this._ms / TimeUnit.DAYS.multiplier );
34
57
  }
@@ -85,20 +108,21 @@ export default abstract class TimeBase<T> {
85
108
  return this._ms / unit.multiplier;
86
109
  }
87
110
 
88
- protected toUnits(): { days: number, hours: number, minutes: number, seconds: number } {
111
+ protected toUnits(): TTimeInUnits {
89
112
  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 ),
113
+ milliseconds: this.ms % TimeUnit.SECONDS.multiplier,
114
+ seconds: Math.floor( this.seconds % 60 ),
115
+ minutes: Math.floor( this.minutes % 60 ),
116
+ hours: Math.floor( this.hours % 24 ),
117
+ days: Math.floor( this.days ),
94
118
  };
95
119
  }
96
120
 
97
- protected static toMs( units: { days?: number, hours?: number, minutes?: number, seconds?: number, ms?: number } ): number {
121
+ protected static unitsToMs( units: Partial<TTimeInUnits> ): number {
98
122
  if ( !units )
99
123
  throw new Error( 'Invalid units given' );
100
124
  let ms = 0
101
- ms += units.ms ?? 0 * TimeUnit.MILLISECONDS.multiplier;
125
+ ms += ( units.milliseconds ?? 0 ) * TimeUnit.MILLISECONDS.multiplier;
102
126
  ms += ( units.seconds ?? 0 ) * TimeUnit.SECONDS.multiplier;
103
127
  ms += ( units.minutes ?? 0 ) * TimeUnit.MINUTES.multiplier;
104
128
  ms += ( units.hours ?? 0 ) * TimeUnit.HOURS.multiplier;
@@ -1,9 +1,9 @@
1
1
  import Deferred, { DeferredCanceledError, ICancelable, ICancelablePromise } from "../async/Deferred.js";
2
2
  import { TComparisonResult } from "../sorting/_index.js";
3
3
  import { TIntervalHandle, TMaybe, TTimeoutHandle, ensureNonNegativeNumber, ensurePositiveNumber, pad } from "../utils/_index.js";
4
- import TimeBase from "./TimeBase";
4
+ import TimeBase, { type TTimeInUnits } from "./TimeBase";
5
5
  import TimeInstant from "./TimeInstant";
6
- import TimeUnit from "./TimeUnit";
6
+ import { TimeUnit } from "./TimeUnit";
7
7
 
8
8
  export class TimeDuration extends TimeBase<TimeDuration> {
9
9
 
@@ -183,6 +183,10 @@ export class TimeDuration extends TimeBase<TimeDuration> {
183
183
  return this.ms > 0;
184
184
  }
185
185
 
186
+ public override toUnits() {
187
+ return super.toUnits();
188
+ }
189
+
186
190
  /**
187
191
  * This method is used to provide a better DX when inspecting a TimeInstant object in DevTools.
188
192
  */
@@ -198,7 +202,7 @@ export class TimeDuration extends TimeBase<TimeDuration> {
198
202
  const match = humanTime.trim().match( /^(?:([0-9]+)d|)\s*(?:([0-9]+)h|)\s*(?:([0-9]+)m|)\s*(?:([0-9]+)s|)$/ );
199
203
  if ( match ) {
200
204
  const [ _, days, hours, minutes, seconds ] = match;
201
- return new TimeDuration( TimeBase.toMs( { days: Number( days ?? 0 ), hours: Number( hours ?? 0 ), minutes: Number( minutes ?? 0 ), seconds: Number( seconds ?? 0 ) } ), TimeUnit.MILLISECONDS );
205
+ return new TimeDuration( TimeBase.unitsToMs( { days: Number( days ?? 0 ), hours: Number( hours ?? 0 ), minutes: Number( minutes ?? 0 ), seconds: Number( seconds ?? 0 ) } ), TimeUnit.MILLISECONDS );
202
206
  }
203
207
  throw new Error( 'Failed to parse time: ' + humanTime );
204
208
  }
@@ -263,6 +267,10 @@ export class TimeDuration extends TimeBase<TimeDuration> {
263
267
  return TimeDuration.ms( ms );
264
268
  }
265
269
 
270
+ public static fromUnits( parameters: Partial<TTimeInUnits> ): TimeDuration {
271
+ return TimeDuration.ms( TimeBase.unitsToMs( parameters ) );
272
+ }
273
+
266
274
  }
267
275
 
268
276
  export type TPredefinedTimeDuration = 0 | 50 | 100 | 150 | 200 | 250 | 300 | 500 | 1000 | 1500 | 2000 | 2500 | 5000;
@@ -4,7 +4,7 @@ import { TComparisonResult } from "../sorting/_index.js";
4
4
  import TimeBase from "./TimeBase";
5
5
  import TimeDuration from "./TimeDuration";
6
6
  import { TTimeInstantBuilder, TTimeInstantCreationParameters, createTimeInstantFromParameters, timeInstantBuilder } from "./TimeInstantBuilder.js";
7
- import TimeUnit from "./TimeUnit";
7
+ import { TimeUnit } from "./TimeUnit";
8
8
  import { TDayOfMonth, TDayOfWeek, TIso8601DateString, TIso8601DateUtcString, TMonth, TWeekNumber } from "./types";
9
9
 
10
10
  export class TimeInstant extends TimeBase<TimeInstant> {
@@ -1,5 +1,5 @@
1
1
 
2
- export default class TimeUnit {
2
+ export class TimeUnit {
3
3
 
4
4
  private constructor(
5
5
  public readonly multiplier: number
@@ -29,15 +29,10 @@ export default class TimeUnit {
29
29
  return this.toUnit( value, TimeUnit.DAYS );
30
30
  }
31
31
 
32
- public toWeeks( value: number ): number {
33
- return this.toUnit( value, TimeUnit.WEEKS );
34
- }
35
-
36
32
  public static readonly MILLISECONDS = new TimeUnit( 1 );
37
33
  public static readonly SECONDS = new TimeUnit( 1000 * TimeUnit.MILLISECONDS.multiplier );
38
34
  public static readonly MINUTES = new TimeUnit( 60 * TimeUnit.SECONDS.multiplier );
39
35
  public static readonly HOURS = new TimeUnit( 60 * TimeUnit.MINUTES.multiplier );
40
36
  public static readonly DAYS = new TimeUnit( 24 * TimeUnit.HOURS.multiplier );
41
- public static readonly WEEKS = new TimeUnit( 7 * TimeUnit.DAYS.multiplier );
42
37
 
43
38
  }
@@ -1,9 +1,10 @@
1
1
 
2
2
  export { default as RandomTimeDuration } from './RandomTimeDuration.js';
3
- export { TPredefinedTimeDuration, TValidTimeDuration, TimeDuration, isAllowedTimeDuration } from './TimeDuration.js';
3
+ export * from './TimeBase.js';
4
+ export { isAllowedTimeDuration, TimeDuration, TPredefinedTimeDuration, TValidTimeDuration } from './TimeDuration.js';
4
5
  export { default as TimeFrequency } from './TimeFrequency.js';
5
6
  export * from './TimeInstant.js';
6
7
  export * from './TimeRange.js';
7
- export { default as TimeUnit } from './TimeUnit.js';
8
+ export * from './TimeUnit.js';
8
9
  export * from './types.js';
9
10
 
@@ -17,14 +17,14 @@ export function isError( e: unknown ): e is Error {
17
17
  return e instanceof Error;
18
18
  }
19
19
 
20
- export function printErrorMessage( error: Error ): string {
21
- const maybeCause = error.cause ? printErrorMessage( asError( error.cause ) ) : null;
20
+ export function getMessageFromError( error: Error ): string {
21
+ const maybeCause = error.cause ? getMessageFromError( asError( error.cause ) ) : null;
22
22
  const cause = maybeCause ? `\ncaused by: ${maybeCause}` : '';
23
23
  return `${error.name}: ${error.message}${cause}`;
24
24
  }
25
25
 
26
- export function printErrorStack( error: Error ): string {
27
- const maybeCause = error.cause ? printErrorStack( asError( error.cause ) ) : null;
26
+ export function getStackFromError( error: Error ): string {
27
+ const maybeCause = error.cause ? getStackFromError( asError( error.cause ) ) : null;
28
28
  const cause = maybeCause ? `\ncaused by: ${maybeCause}` : '';
29
29
  const stack = error.stack && error.stack.includes( error.message ) ? error.stack : error.message + ' ' + ( error.stack ?? '' );
30
30
  return `${error.name}: ${stack}${cause}`;