@zelgadis87/utils-core 5.5.0-beta.2 → 5.5.0-beta.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/.rollup/index.cjs +58 -4
- package/.rollup/index.cjs.map +1 -1
- package/.rollup/index.d.ts +65 -4
- package/.rollup/index.mjs +58 -4
- package/.rollup/index.mjs.map +1 -1
- package/.rollup/tsconfig.tsbuildinfo +1 -1
- package/CHANGELOG.md +16 -0
- package/package.json +1 -1
- package/src/Optional.ts +15 -4
- package/src/lazy/Lazy.ts +7 -3
- package/src/upgrade/DataUpgrader.ts +45 -2
- package/src/upgrade/DataUpgraderBuilder.ts +7 -0
package/.rollup/index.d.ts
CHANGED
|
@@ -102,7 +102,9 @@ declare class Optional<T> implements TOptional<T> {
|
|
|
102
102
|
private _value;
|
|
103
103
|
private constructor();
|
|
104
104
|
getRawValue(): T | undefined;
|
|
105
|
+
/** @deprecated[2026.04.07]: Replace with {@link getOrElseThrow} (drop-in replacement with no arguments) */
|
|
105
106
|
get(): T;
|
|
107
|
+
getOrElseThrow(): T;
|
|
106
108
|
getOrElseThrow(errorProducer: TProducer<Error>): T;
|
|
107
109
|
set(t: T): void;
|
|
108
110
|
protected setNullable(t: T | null | undefined): void | this;
|
|
@@ -141,6 +143,7 @@ declare class Optional<T> implements TOptional<T> {
|
|
|
141
143
|
|
|
142
144
|
type TOptional<T> = {
|
|
143
145
|
/**
|
|
146
|
+
* @deprecated[2026.04.07]: Replace with {@link getOrElseThrow} (drop-in replacement with no arguments)
|
|
144
147
|
* @returns the currently stored value, if any; throws {@link ErrorGetEmptyOptional} otherwise;
|
|
145
148
|
*/
|
|
146
149
|
get(): T;
|
|
@@ -149,9 +152,10 @@ type TOptional<T> = {
|
|
|
149
152
|
*/
|
|
150
153
|
getRawValue(): T | undefined;
|
|
151
154
|
/**
|
|
152
|
-
* @returns the currently stored value, if any; throws the error generated by errorProducer otherwise;
|
|
155
|
+
* @returns the currently stored value, if any; throws {@link ErrorGetEmptyOptional} if no errorProducer is provided, or the error generated by errorProducer otherwise;
|
|
153
156
|
*/
|
|
154
|
-
getOrElseThrow
|
|
157
|
+
getOrElseThrow(): T;
|
|
158
|
+
getOrElseThrow(errorProducer: TProducer<Error>): T;
|
|
155
159
|
/**
|
|
156
160
|
* Places a new value inside this optional. Throws {@link ErrorSetEmptyOptional} if t is null or undefined.
|
|
157
161
|
*/
|
|
@@ -188,7 +192,10 @@ type TOptional<T> = {
|
|
|
188
192
|
filter(predicate: TPredicate<T>): TOptional<T>;
|
|
189
193
|
};
|
|
190
194
|
type TEmptyOptional<T> = TOptional<T> & {
|
|
195
|
+
/** @deprecated[2026.04.07]: Replace with {@link getOrElseThrow} (drop-in replacement with no arguments) */
|
|
191
196
|
get(): never;
|
|
197
|
+
getOrElseThrow(): never;
|
|
198
|
+
getOrElseThrow(errorProducer: TProducer<Error>): never;
|
|
192
199
|
isEmpty(): true;
|
|
193
200
|
isPresent(): false;
|
|
194
201
|
apply<RP = void, RE = void>(callbackIfPresent: TFunction<T, RP>, callbackIfEmpty: TProducer<RE>): RE;
|
|
@@ -207,7 +214,10 @@ type TEmptyOptional<T> = TOptional<T> & {
|
|
|
207
214
|
orElseProduceNullableAndApply: <R>(newValueProducer: TProducer<R | null | undefined>) => TOptional<R>;
|
|
208
215
|
};
|
|
209
216
|
type TPresentOptional<T> = TOptional<T> & {
|
|
217
|
+
/** @deprecated[2026.04.07]: Replace with {@link getOrElseThrow} (drop-in replacement with no arguments) */
|
|
210
218
|
get(): T;
|
|
219
|
+
getOrElseThrow(): T;
|
|
220
|
+
getOrElseThrow(errorProducer: TProducer<Error>): T;
|
|
211
221
|
isEmpty(): false;
|
|
212
222
|
isPresent(): true;
|
|
213
223
|
apply<RP = void, RE = void>(callbackIfPresent: TFunction<T, RP>, callbackIfEmpty: TProducer<RE>): RP;
|
|
@@ -1408,6 +1418,7 @@ declare class Lazy<T> {
|
|
|
1408
1418
|
ifPresent(fn: (t: T) => void): void;
|
|
1409
1419
|
ifEmpty(fn: () => void): void;
|
|
1410
1420
|
apply(fnPresent: (t: T) => void, fnEmpty: () => void): void;
|
|
1421
|
+
mapOrElse<R>(onPresent: (t: T) => R, onEmpty: () => R): R;
|
|
1411
1422
|
protected empty(): void;
|
|
1412
1423
|
static of<T>(generator: () => T): Lazy<T>;
|
|
1413
1424
|
}
|
|
@@ -1676,6 +1687,13 @@ type TAddTransition<T extends readonly TTransitionRecord[], From extends number,
|
|
|
1676
1687
|
* - Duplicate transition definitions
|
|
1677
1688
|
* - Backward transitions (e.g., version 2 → 1)
|
|
1678
1689
|
*
|
|
1690
|
+
* ## Architectural Convention
|
|
1691
|
+
*
|
|
1692
|
+
* The built DataUpgrader is the **single point of versioning** for your data. Never bypass it
|
|
1693
|
+
* with manual `$version` checks — `upgrade()` is idempotent (no-op on latest version) and
|
|
1694
|
+
* accepts the full `Vstar` union, returning the current latest version. See {@link DataUpgrader}
|
|
1695
|
+
* for the full type aliasing conventions (`Vstar` union, no-suffix alias, adding new versions).
|
|
1696
|
+
*
|
|
1679
1697
|
* @example
|
|
1680
1698
|
* ```typescript
|
|
1681
1699
|
* // Step 1: Define all historical versions with $version discriminator
|
|
@@ -1778,6 +1796,49 @@ interface IDataUpgrader<XStar extends TUpgradable, XLatest extends XStar> {
|
|
|
1778
1796
|
* finding the shortest upgrade path and applying transformations. This is particularly useful for
|
|
1779
1797
|
* handling persisted data that may be in any historical format.
|
|
1780
1798
|
*
|
|
1799
|
+
* ## Architectural Conventions
|
|
1800
|
+
*
|
|
1801
|
+
* ### Type Aliasing
|
|
1802
|
+
* ```typescript
|
|
1803
|
+
* // Xstar = union of ALL known versions (upgrader input type)
|
|
1804
|
+
* type TMyData_Vstar = TMyData_V1 | TMyData_V2 | TMyData_V3;
|
|
1805
|
+
*
|
|
1806
|
+
* // No suffix = alias for the CURRENT latest version (upgrader output type)
|
|
1807
|
+
* type TMyData = TMyData_V3;
|
|
1808
|
+
* // When adding V4 later, update Vstar and change the alias:
|
|
1809
|
+
* // type TMyData_Vstar = TMyData_V1 | TMyData_V2 | TMyData_V3 | TMyData_V4;
|
|
1810
|
+
* // type TMyData = TMyData_V4;
|
|
1811
|
+
* ```
|
|
1812
|
+
*
|
|
1813
|
+
* ### Always Run the Upgrader
|
|
1814
|
+
*
|
|
1815
|
+
* **Every piece of serialized data must be treated as potentially any old version.**
|
|
1816
|
+
*
|
|
1817
|
+
* Never inspect `$version` manually and skip the upgrader. Always feed raw parsed data
|
|
1818
|
+
* directly into `upgrade()`. The upgrader is **idempotent** — calling it on data already
|
|
1819
|
+
* at the latest version is a no-op that returns immediately. Bypassing it creates fragile
|
|
1820
|
+
* fast paths that break when new versions are introduced.
|
|
1821
|
+
*
|
|
1822
|
+
* ```typescript
|
|
1823
|
+
* // ✅ CORRECT — always delegate to the upgrader
|
|
1824
|
+
* const raw = JSON.parse(json) as TMyData_Vstar;
|
|
1825
|
+
* const current = await upgrader.upgrade(raw);
|
|
1826
|
+
*
|
|
1827
|
+
* // ❌ WRONG — manual version check bypasses the upgrader
|
|
1828
|
+
* const raw = JSON.parse(json);
|
|
1829
|
+
* if (raw.$version === 3) {
|
|
1830
|
+
* // This works today, breaks silently when V4 is added
|
|
1831
|
+
* }
|
|
1832
|
+
* ```
|
|
1833
|
+
*
|
|
1834
|
+
* ### Adding a New Version
|
|
1835
|
+
*
|
|
1836
|
+
* 1. Define the new version type with `$version: N`
|
|
1837
|
+
* 2. Add it to the `Vstar` union
|
|
1838
|
+
* 3. Change the no-suffix alias to point to the new version
|
|
1839
|
+
* 4. Add a transition from the previous latest to the new version
|
|
1840
|
+
* 5. Existing code that calls `upgrade()` requires zero changes
|
|
1841
|
+
*
|
|
1781
1842
|
* **Key Use Case:** Reading serialized data of unknown version and migrating it transparently.
|
|
1782
1843
|
*
|
|
1783
1844
|
* @example
|
|
@@ -1787,9 +1848,9 @@ interface IDataUpgrader<XStar extends TUpgradable, XLatest extends XStar> {
|
|
|
1787
1848
|
* type TSerializedData_V2 = { name: string; age: number; $version: 2 };
|
|
1788
1849
|
* type TSerializedData_V3 = { name: string; age: number; email: string; $version: 3 };
|
|
1789
1850
|
*
|
|
1790
|
-
* // Step 2: Create union
|
|
1851
|
+
* // Step 2: Create Vstar union (all versions) and current-version alias (latest only)
|
|
1791
1852
|
* type TSerializedData_Vstar = TSerializedData_V1 | TSerializedData_V2 | TSerializedData_V3;
|
|
1792
|
-
* type TSerializedData = TSerializedData_V3;
|
|
1853
|
+
* type TSerializedData = TSerializedData_V3; // Update this when adding V4
|
|
1793
1854
|
*
|
|
1794
1855
|
* // Step 3: Create upgrader with transition functions
|
|
1795
1856
|
* const upgrader = DataUpgrader.create<TSerializedData_Vstar, TSerializedData>(3)
|
package/.rollup/index.mjs
CHANGED
|
@@ -222,10 +222,11 @@ class Optional {
|
|
|
222
222
|
getRawValue() {
|
|
223
223
|
return this._value;
|
|
224
224
|
}
|
|
225
|
+
/** @deprecated[2026.04.07]: Replace with {@link getOrElseThrow} (drop-in replacement with no arguments) */
|
|
225
226
|
get() {
|
|
226
|
-
return this.getOrElseThrow(
|
|
227
|
+
return this.getOrElseThrow();
|
|
227
228
|
}
|
|
228
|
-
getOrElseThrow(errorProducer) {
|
|
229
|
+
getOrElseThrow(errorProducer = () => new ErrorGetEmptyOptional()) {
|
|
229
230
|
if (this.isEmpty())
|
|
230
231
|
throw errorProducer();
|
|
231
232
|
return this._value;
|
|
@@ -1585,6 +1586,9 @@ class Lazy {
|
|
|
1585
1586
|
fnEmpty();
|
|
1586
1587
|
}
|
|
1587
1588
|
}
|
|
1589
|
+
mapOrElse(onPresent, onEmpty) {
|
|
1590
|
+
return this._initialized ? onPresent(this._value) : onEmpty();
|
|
1591
|
+
}
|
|
1588
1592
|
empty() {
|
|
1589
1593
|
this._initialized = false;
|
|
1590
1594
|
}
|
|
@@ -3797,6 +3801,49 @@ const VERSION_FIELD = "$version";
|
|
|
3797
3801
|
* finding the shortest upgrade path and applying transformations. This is particularly useful for
|
|
3798
3802
|
* handling persisted data that may be in any historical format.
|
|
3799
3803
|
*
|
|
3804
|
+
* ## Architectural Conventions
|
|
3805
|
+
*
|
|
3806
|
+
* ### Type Aliasing
|
|
3807
|
+
* ```typescript
|
|
3808
|
+
* // Xstar = union of ALL known versions (upgrader input type)
|
|
3809
|
+
* type TMyData_Vstar = TMyData_V1 | TMyData_V2 | TMyData_V3;
|
|
3810
|
+
*
|
|
3811
|
+
* // No suffix = alias for the CURRENT latest version (upgrader output type)
|
|
3812
|
+
* type TMyData = TMyData_V3;
|
|
3813
|
+
* // When adding V4 later, update Vstar and change the alias:
|
|
3814
|
+
* // type TMyData_Vstar = TMyData_V1 | TMyData_V2 | TMyData_V3 | TMyData_V4;
|
|
3815
|
+
* // type TMyData = TMyData_V4;
|
|
3816
|
+
* ```
|
|
3817
|
+
*
|
|
3818
|
+
* ### Always Run the Upgrader
|
|
3819
|
+
*
|
|
3820
|
+
* **Every piece of serialized data must be treated as potentially any old version.**
|
|
3821
|
+
*
|
|
3822
|
+
* Never inspect `$version` manually and skip the upgrader. Always feed raw parsed data
|
|
3823
|
+
* directly into `upgrade()`. The upgrader is **idempotent** — calling it on data already
|
|
3824
|
+
* at the latest version is a no-op that returns immediately. Bypassing it creates fragile
|
|
3825
|
+
* fast paths that break when new versions are introduced.
|
|
3826
|
+
*
|
|
3827
|
+
* ```typescript
|
|
3828
|
+
* // ✅ CORRECT — always delegate to the upgrader
|
|
3829
|
+
* const raw = JSON.parse(json) as TMyData_Vstar;
|
|
3830
|
+
* const current = await upgrader.upgrade(raw);
|
|
3831
|
+
*
|
|
3832
|
+
* // ❌ WRONG — manual version check bypasses the upgrader
|
|
3833
|
+
* const raw = JSON.parse(json);
|
|
3834
|
+
* if (raw.$version === 3) {
|
|
3835
|
+
* // This works today, breaks silently when V4 is added
|
|
3836
|
+
* }
|
|
3837
|
+
* ```
|
|
3838
|
+
*
|
|
3839
|
+
* ### Adding a New Version
|
|
3840
|
+
*
|
|
3841
|
+
* 1. Define the new version type with `$version: N`
|
|
3842
|
+
* 2. Add it to the `Vstar` union
|
|
3843
|
+
* 3. Change the no-suffix alias to point to the new version
|
|
3844
|
+
* 4. Add a transition from the previous latest to the new version
|
|
3845
|
+
* 5. Existing code that calls `upgrade()` requires zero changes
|
|
3846
|
+
*
|
|
3800
3847
|
* **Key Use Case:** Reading serialized data of unknown version and migrating it transparently.
|
|
3801
3848
|
*
|
|
3802
3849
|
* @example
|
|
@@ -3806,9 +3853,9 @@ const VERSION_FIELD = "$version";
|
|
|
3806
3853
|
* type TSerializedData_V2 = { name: string; age: number; $version: 2 };
|
|
3807
3854
|
* type TSerializedData_V3 = { name: string; age: number; email: string; $version: 3 };
|
|
3808
3855
|
*
|
|
3809
|
-
* // Step 2: Create union
|
|
3856
|
+
* // Step 2: Create Vstar union (all versions) and current-version alias (latest only)
|
|
3810
3857
|
* type TSerializedData_Vstar = TSerializedData_V1 | TSerializedData_V2 | TSerializedData_V3;
|
|
3811
|
-
* type TSerializedData = TSerializedData_V3;
|
|
3858
|
+
* type TSerializedData = TSerializedData_V3; // Update this when adding V4
|
|
3812
3859
|
*
|
|
3813
3860
|
* // Step 3: Create upgrader with transition functions
|
|
3814
3861
|
* const upgrader = DataUpgrader.create<TSerializedData_Vstar, TSerializedData>(3)
|
|
@@ -3948,6 +3995,13 @@ function isUpgradable(obj) {
|
|
|
3948
3995
|
* - Duplicate transition definitions
|
|
3949
3996
|
* - Backward transitions (e.g., version 2 → 1)
|
|
3950
3997
|
*
|
|
3998
|
+
* ## Architectural Convention
|
|
3999
|
+
*
|
|
4000
|
+
* The built DataUpgrader is the **single point of versioning** for your data. Never bypass it
|
|
4001
|
+
* with manual `$version` checks — `upgrade()` is idempotent (no-op on latest version) and
|
|
4002
|
+
* accepts the full `Vstar` union, returning the current latest version. See {@link DataUpgrader}
|
|
4003
|
+
* for the full type aliasing conventions (`Vstar` union, no-suffix alias, adding new versions).
|
|
4004
|
+
*
|
|
3951
4005
|
* @example
|
|
3952
4006
|
* ```typescript
|
|
3953
4007
|
* // Step 1: Define all historical versions with $version discriminator
|