unthrown 5.7.0 → 5.9.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/index.cjs +250 -33
- package/dist/index.d.cts +185 -8
- package/dist/index.d.mts +185 -8
- package/dist/index.mjs +247 -34
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1788,6 +1788,24 @@ declare function fromExecutor<T = never, E = never>(executor: (settle: Settle<T,
|
|
|
1788
1788
|
* @internal
|
|
1789
1789
|
*/
|
|
1790
1790
|
type AllOk<Rs extends readonly unknown[], Ts extends readonly unknown[]> = number extends Rs["length"] ? Ts[number][] : Ts;
|
|
1791
|
+
/**
|
|
1792
|
+
* A `[key, error]` pair from a record aggregate, correlated per key.
|
|
1793
|
+
*
|
|
1794
|
+
* @remarks
|
|
1795
|
+
* `-?` because the mapped type is homomorphic: an optional input key would
|
|
1796
|
+
* otherwise carry its optionality through and put `undefined` in the entry
|
|
1797
|
+
* union, breaking the documented `([key, error]) => …` destructure. An entry
|
|
1798
|
+
* whose error channel is `never` (an infallible input — every `@unthrown/drizzle`
|
|
1799
|
+
* read) is dropped rather than emitted as an uninhabited `[K, never]` arm, which
|
|
1800
|
+
* a `switch` over the key would still have to write a dead case for.
|
|
1801
|
+
*
|
|
1802
|
+
* @internal
|
|
1803
|
+
*/
|
|
1804
|
+
type DictErrEntry<R> = { [K in keyof R]-?: [ErrOf<R[K]>] extends [never] ? never : readonly [K, ErrOf<R[K]>]; }[keyof R];
|
|
1805
|
+
/** The {@link AsyncResult} counterpart of {@link DictErrEntry}. @internal */
|
|
1806
|
+
type AsyncDictErrEntry<R> = { [K in keyof R]-?: [AsyncErrOf<R[K]>] extends [never] ? never : readonly [K, AsyncErrOf<R[K]>]; }[keyof R];
|
|
1807
|
+
/** A non-empty readonly list — `merge` runs only when an `Err` was collected. @internal */
|
|
1808
|
+
type NonEmpty<T> = readonly [T, ...T[]];
|
|
1791
1809
|
/** A record of `Result`s — the input to {@link allFromDict}. */
|
|
1792
1810
|
type ResultRecord = Record<string, Result$1<unknown, unknown>>;
|
|
1793
1811
|
/** A record of `AsyncResult`s — the input to {@link allFromDictAsync}. */
|
|
@@ -1802,7 +1820,8 @@ type AsyncResultRecord = Record<string, AsyncResult$1<unknown, unknown>>;
|
|
|
1802
1820
|
* `Err`. A **fixed tuple** keeps its positional types — `all([Ok(1), Ok("a")])`
|
|
1803
1821
|
* is `Result<[number, string], …>` — while a **dynamic array** `Result<T, E>[]`
|
|
1804
1822
|
* collapses to `Result<T[], E>` with no cast. For a **record** keyed by name,
|
|
1805
|
-
* use {@link allFromDict}.
|
|
1823
|
+
* use {@link allFromDict}. To report **every** `Err` instead of only the first,
|
|
1824
|
+
* use {@link validateAll}.
|
|
1806
1825
|
*
|
|
1807
1826
|
* @category Aggregate
|
|
1808
1827
|
*
|
|
@@ -1823,7 +1842,9 @@ declare function all<Rs extends readonly Result$1<unknown, unknown>[]>(results:
|
|
|
1823
1842
|
*
|
|
1824
1843
|
* @remarks
|
|
1825
1844
|
* Same folding rules as {@link all}: first `Err` short-circuits, any `Defect`
|
|
1826
|
-
* dominates. This is **not** error accumulation
|
|
1845
|
+
* dominates. This is **not** error accumulation — for that, reach for
|
|
1846
|
+
* {@link validateAllFromDict}, which accumulates every `Err` and folds them into
|
|
1847
|
+
* one modeled error.
|
|
1827
1848
|
*
|
|
1828
1849
|
* @category Aggregate
|
|
1829
1850
|
*
|
|
@@ -1844,7 +1865,8 @@ declare function allFromDict<R extends ResultRecord>(results: R): Result$1<{ [K
|
|
|
1844
1865
|
* The inputs are resolved **concurrently** (order preserved); the resolved
|
|
1845
1866
|
* `Result`s are then folded with the same rules as {@link all} — first `Err`
|
|
1846
1867
|
* short-circuits, any `Defect` dominates. As ever, the returned `AsyncResult`'s
|
|
1847
|
-
* internal promise never rejects. For a **record**, use {@link allFromDictAsync}
|
|
1868
|
+
* internal promise never rejects. For a **record**, use {@link allFromDictAsync};
|
|
1869
|
+
* to report **every** `Err`, use {@link validateAllAsync}.
|
|
1848
1870
|
*
|
|
1849
1871
|
* @category Aggregate
|
|
1850
1872
|
*
|
|
@@ -1866,7 +1888,8 @@ declare function allAsync<Rs extends readonly AsyncResult$1<unknown, unknown>[]>
|
|
|
1866
1888
|
*
|
|
1867
1889
|
* @remarks
|
|
1868
1890
|
* Resolved concurrently (order preserved), folded with the {@link all} rules,
|
|
1869
|
-
* and the internal promise never rejects.
|
|
1891
|
+
* and the internal promise never rejects. To report **every** `Err`, use
|
|
1892
|
+
* {@link validateAllFromDictAsync}.
|
|
1870
1893
|
*
|
|
1871
1894
|
* @category Aggregate
|
|
1872
1895
|
*
|
|
@@ -1882,6 +1905,153 @@ declare function allAsync<Rs extends readonly AsyncResult$1<unknown, unknown>[]>
|
|
|
1882
1905
|
* ```
|
|
1883
1906
|
*/
|
|
1884
1907
|
declare function allFromDictAsync<R extends AsyncResultRecord>(results: R): AsyncResult$1<{ [K in keyof R]: AsyncOkOf<R[K]>; }, AsyncErrOf<R[keyof R]>>;
|
|
1908
|
+
/**
|
|
1909
|
+
* Collect a tuple/array of {@link Result}s, **accumulating every** `Err` and
|
|
1910
|
+
* merging them into a single modeled error — the accumulating counterpart of
|
|
1911
|
+
* {@link all}.
|
|
1912
|
+
*
|
|
1913
|
+
* @remarks
|
|
1914
|
+
* Same success channel as {@link all}: a **fixed tuple** keeps its positional
|
|
1915
|
+
* types, a **dynamic array** collapses to `Result<T[], E2>`. The difference is
|
|
1916
|
+
* the error channel — instead of the first `Err` winning, every `Err` is
|
|
1917
|
+
* collected in input order and handed to `merge`, whose return becomes the
|
|
1918
|
+
* modeled error.
|
|
1919
|
+
*
|
|
1920
|
+
* `merge` receives a **non-empty** list, so it is total: it is called only when
|
|
1921
|
+
* at least one `Err` was collected. It is **not** called when every element is
|
|
1922
|
+
* `Ok`, nor when a `Defect` is present.
|
|
1923
|
+
*
|
|
1924
|
+
* Any `Defect` still **dominates** — it wins over the accumulated errors, which
|
|
1925
|
+
* are discarded and never reach `merge`. A defect means something in this batch
|
|
1926
|
+
* failed in a way nobody modeled, so the violations computed alongside it are
|
|
1927
|
+
* not trustworthy. An out-of-contract non-`Result` element becomes a
|
|
1928
|
+
* `TypeError`-caused `Defect` the same way, and a throw inside `merge` becomes
|
|
1929
|
+
* a `Defect` too.
|
|
1930
|
+
*
|
|
1931
|
+
* `merge` must be **synchronous** — an `async` one is a compile error
|
|
1932
|
+
* ({@link NotThenable}), since a `Promise` in `E` is an unqualified rejection.
|
|
1933
|
+
*
|
|
1934
|
+
* For **schema-shaped** input (a request body, a form), reach for
|
|
1935
|
+
* `@unthrown/standard-schema`'s `fromSchema` instead — a validator already
|
|
1936
|
+
* hands you every issue as the modeled error. `validateAll` is for independent
|
|
1937
|
+
* checks you wrote yourself. For a **record** keyed by name, use
|
|
1938
|
+
* {@link validateAllFromDict}.
|
|
1939
|
+
*
|
|
1940
|
+
* @typeParam Rs - the tuple/array of input `Result` types.
|
|
1941
|
+
* @typeParam E2 - the merged error type.
|
|
1942
|
+
* @param results - the results to collect.
|
|
1943
|
+
* @param merge - folds the collected errors into one modeled error.
|
|
1944
|
+
*
|
|
1945
|
+
* @category Aggregate
|
|
1946
|
+
*
|
|
1947
|
+
* @example
|
|
1948
|
+
* ```ts
|
|
1949
|
+
* import { validateAll, Ok, Err } from "unthrown";
|
|
1950
|
+
*
|
|
1951
|
+
* // every Err is collected, not just the first
|
|
1952
|
+
* validateAll([Ok(1), Err("stock"), Err("credit")], (errors) => errors.join(" and "));
|
|
1953
|
+
* // => Err("stock and credit")
|
|
1954
|
+
*
|
|
1955
|
+
* // all-Ok keeps the positional tuple; `merge` never runs
|
|
1956
|
+
* validateAll([Ok(1), Ok("a")], (errors) => errors.join());
|
|
1957
|
+
* // => Ok([1, "a"]) typed Result<[number, string], string>
|
|
1958
|
+
* ```
|
|
1959
|
+
*/
|
|
1960
|
+
declare function validateAll<Rs extends readonly Result$1<unknown, unknown>[], E2>(results: readonly [...Rs], merge: (errors: NonEmpty<ErrOf<Rs[number]>>) => E2 & NotThenable<E2>): Result$1<AllOk<Rs, { [K in keyof Rs]: OkOf<Rs[K]>; }>, E2>;
|
|
1961
|
+
/**
|
|
1962
|
+
* Collect a **record** of {@link Result}s, accumulating every `Err` — the
|
|
1963
|
+
* accumulating counterpart of {@link allFromDict}, and the named counterpart of
|
|
1964
|
+
* {@link validateAll}.
|
|
1965
|
+
*
|
|
1966
|
+
* @remarks
|
|
1967
|
+
* `merge` receives a non-empty list of **`[key, error]` entries**, correlated
|
|
1968
|
+
* per key: `{ a: Result<A, E1>; b: Result<B, E2> }` yields
|
|
1969
|
+
* `["a", E1] | ["b", E2]`, so a `switch` on the key narrows the error and an
|
|
1970
|
+
* impossible pairing does not typecheck. That is what keeps two checks sharing
|
|
1971
|
+
* one error type distinguishable. Entries come in `Object.keys` order.
|
|
1972
|
+
*
|
|
1973
|
+
* Every other rule matches {@link validateAll}: any `Defect` dominates and
|
|
1974
|
+
* discards the accumulated errors, a throw in `merge` becomes a `Defect`, and
|
|
1975
|
+
* `merge` must be synchronous.
|
|
1976
|
+
*
|
|
1977
|
+
* @typeParam R - the record of input `Result` types.
|
|
1978
|
+
* @typeParam E2 - the merged error type.
|
|
1979
|
+
* @param results - the results to collect, keyed by name.
|
|
1980
|
+
* @param merge - folds the collected `[key, error]` entries into one error.
|
|
1981
|
+
*
|
|
1982
|
+
* @category Aggregate
|
|
1983
|
+
*
|
|
1984
|
+
* @example
|
|
1985
|
+
* ```ts
|
|
1986
|
+
* import { validateAllFromDict, Ok, Err } from "unthrown";
|
|
1987
|
+
*
|
|
1988
|
+
* validateAllFromDict(
|
|
1989
|
+
* { vatRate: Err("out of range"), currency: Ok("EUR"), dueDate: Err("past") },
|
|
1990
|
+
* (entries) => entries.map(([key, error]) => `${key}: ${error}`).join("; "),
|
|
1991
|
+
* );
|
|
1992
|
+
* // => Err("vatRate: out of range; dueDate: past")
|
|
1993
|
+
* ```
|
|
1994
|
+
*/
|
|
1995
|
+
declare function validateAllFromDict<R extends ResultRecord, E2>(results: R, merge: (entries: NonEmpty<DictErrEntry<R>>) => E2 & NotThenable<E2>): Result$1<{ [K in keyof R]: OkOf<R[K]>; }, E2>;
|
|
1996
|
+
/**
|
|
1997
|
+
* The asynchronous counterpart of {@link validateAll}: collect a tuple/array of
|
|
1998
|
+
* {@link AsyncResult}s, accumulating every `Err` into one merged error.
|
|
1999
|
+
*
|
|
2000
|
+
* @remarks
|
|
2001
|
+
* Every {@link validateAll} rule holds, with the inputs resolved
|
|
2002
|
+
* **concurrently** (order preserved) — as with {@link allAsync}, no work is
|
|
2003
|
+
* short-circuited either way; the fail-fast/accumulating split is purely which
|
|
2004
|
+
* errors get reported. The internal promise never rejects: an out-of-contract
|
|
2005
|
+
* rejecting thenable becomes a dominating `Defect`. `merge` stays synchronous
|
|
2006
|
+
* here too — this is exactly where its rejection would land unqualified in `E`.
|
|
2007
|
+
* For a **record**, use {@link validateAllFromDictAsync}.
|
|
2008
|
+
*
|
|
2009
|
+
* @typeParam Rs - the tuple/array of input `AsyncResult` types.
|
|
2010
|
+
* @typeParam E2 - the merged error type.
|
|
2011
|
+
* @param results - the async results to collect.
|
|
2012
|
+
* @param merge - folds the collected errors into one modeled error.
|
|
2013
|
+
*
|
|
2014
|
+
* @category Aggregate
|
|
2015
|
+
*
|
|
2016
|
+
* @example
|
|
2017
|
+
* ```ts
|
|
2018
|
+
* import { validateAllAsync, OkAsync, ErrAsync } from "unthrown";
|
|
2019
|
+
*
|
|
2020
|
+
* const checked = validateAllAsync(
|
|
2021
|
+
* [OkAsync(1), ErrAsync("stock"), ErrAsync("credit")],
|
|
2022
|
+
* (errors) => errors.join(" and "),
|
|
2023
|
+
* );
|
|
2024
|
+
* // (await checked) => Err("stock and credit")
|
|
2025
|
+
* ```
|
|
2026
|
+
*/
|
|
2027
|
+
declare function validateAllAsync<Rs extends readonly AsyncResult$1<unknown, unknown>[], E2>(results: readonly [...Rs], merge: (errors: NonEmpty<AsyncErrOf<Rs[number]>>) => E2 & NotThenable<E2>): AsyncResult$1<AllOk<Rs, { [K in keyof Rs]: AsyncOkOf<Rs[K]>; }>, E2>;
|
|
2028
|
+
/**
|
|
2029
|
+
* The asynchronous counterpart of {@link validateAllFromDict}: collect a record
|
|
2030
|
+
* of {@link AsyncResult}s, accumulating every `Err` into one merged error.
|
|
2031
|
+
*
|
|
2032
|
+
* @remarks
|
|
2033
|
+
* The {@link validateAllFromDict} rules, over inputs resolved concurrently as
|
|
2034
|
+
* in {@link validateAllAsync}.
|
|
2035
|
+
*
|
|
2036
|
+
* @typeParam R - the record of input `AsyncResult` types.
|
|
2037
|
+
* @typeParam E2 - the merged error type.
|
|
2038
|
+
* @param results - the async results to collect, keyed by name.
|
|
2039
|
+
* @param merge - folds the collected `[key, error]` entries into one error.
|
|
2040
|
+
*
|
|
2041
|
+
* @category Aggregate
|
|
2042
|
+
*
|
|
2043
|
+
* @example
|
|
2044
|
+
* ```ts
|
|
2045
|
+
* import { validateAllFromDictAsync, OkAsync, ErrAsync } from "unthrown";
|
|
2046
|
+
*
|
|
2047
|
+
* const checked = validateAllFromDictAsync(
|
|
2048
|
+
* { stock: ErrAsync("none left"), credit: OkAsync(500) },
|
|
2049
|
+
* (entries) => entries.map(([key, error]) => `${key}: ${error}`).join("; "),
|
|
2050
|
+
* );
|
|
2051
|
+
* // (await checked) => Err("stock: none left")
|
|
2052
|
+
* ```
|
|
2053
|
+
*/
|
|
2054
|
+
declare function validateAllFromDictAsync<R extends AsyncResultRecord, E2>(results: R, merge: (entries: NonEmpty<AsyncDictErrEntry<R>>) => E2 & NotThenable<E2>): AsyncResult$1<{ [K in keyof R]: AsyncOkOf<R[K]>; }, E2>;
|
|
1885
2055
|
//#endregion
|
|
1886
2056
|
//#region src/facade.d.ts
|
|
1887
2057
|
/**
|
|
@@ -1889,7 +2059,8 @@ declare function allFromDictAsync<R extends AsyncResultRecord>(results: R): Asyn
|
|
|
1889
2059
|
* single, discoverable namespace: {@link Result.Ok}, {@link Result.Err},
|
|
1890
2060
|
* {@link Result.Do}, {@link Result.fromNullable}, {@link Result.fromThrowable},
|
|
1891
2061
|
* {@link Result.fromSafeThrowable}, {@link Result.all},
|
|
1892
|
-
* {@link Result.allFromDict}, {@link Result.
|
|
2062
|
+
* {@link Result.allFromDict}, {@link Result.validateAll},
|
|
2063
|
+
* {@link Result.validateAllFromDict}, {@link Result.isOk}, {@link Result.isErr},
|
|
1893
2064
|
* {@link Result.isDefect}, {@link Result.isResult}.
|
|
1894
2065
|
*
|
|
1895
2066
|
* @remarks
|
|
@@ -1919,6 +2090,8 @@ declare const Result: {
|
|
|
1919
2090
|
readonly fromSafeThrowable: typeof fromSafeThrowable;
|
|
1920
2091
|
readonly all: typeof all;
|
|
1921
2092
|
readonly allFromDict: typeof allFromDict;
|
|
2093
|
+
readonly validateAll: typeof validateAll;
|
|
2094
|
+
readonly validateAllFromDict: typeof validateAllFromDict;
|
|
1922
2095
|
readonly isOk: typeof isOk;
|
|
1923
2096
|
readonly isErr: typeof isErr;
|
|
1924
2097
|
readonly isDefect: typeof isDefect;
|
|
@@ -1944,7 +2117,8 @@ type Result<T, E> = Result$1<T, E>;
|
|
|
1944
2117
|
* the matching namespace: {@link AsyncResult.Ok}, {@link AsyncResult.Err},
|
|
1945
2118
|
* {@link AsyncResult.Do}, {@link AsyncResult.fromExecutor},
|
|
1946
2119
|
* {@link AsyncResult.fromPromise}, {@link AsyncResult.fromSafePromise},
|
|
1947
|
-
* {@link AsyncResult.all}, {@link AsyncResult.allFromDict}
|
|
2120
|
+
* {@link AsyncResult.all}, {@link AsyncResult.allFromDict},
|
|
2121
|
+
* {@link AsyncResult.validateAll}, {@link AsyncResult.validateAllFromDict}.
|
|
1948
2122
|
*
|
|
1949
2123
|
* @remarks
|
|
1950
2124
|
* The async sibling of {@link Result}. Statics are grouped by what they
|
|
@@ -1955,7 +2129,8 @@ type Result<T, E> = Result$1<T, E>;
|
|
|
1955
2129
|
* functions carry (`AsyncResult.Ok` is `OkAsync`; `AsyncResult.Err` is
|
|
1956
2130
|
* `ErrAsync`; `AsyncResult.Do` is `DoAsync`; `AsyncResult.all` is `allAsync`;
|
|
1957
2131
|
* `AsyncResult.allFromDict` is
|
|
1958
|
-
* `allFromDictAsync`). Like
|
|
2132
|
+
* `allFromDictAsync`; `AsyncResult.validateAll` is `validateAllAsync`). Like
|
|
2133
|
+
* {@link Result}, the free functions remain the
|
|
1959
2134
|
* primary, tree-shakeable API; the value `AsyncResult` and the type
|
|
1960
2135
|
* {@link AsyncResult} share one name.
|
|
1961
2136
|
*
|
|
@@ -1980,6 +2155,8 @@ declare const AsyncResult: {
|
|
|
1980
2155
|
readonly fromSafePromise: typeof fromSafePromise;
|
|
1981
2156
|
readonly all: typeof allAsync;
|
|
1982
2157
|
readonly allFromDict: typeof allFromDictAsync;
|
|
2158
|
+
readonly validateAll: typeof validateAllAsync;
|
|
2159
|
+
readonly validateAllFromDict: typeof validateAllFromDictAsync;
|
|
1983
2160
|
};
|
|
1984
2161
|
/**
|
|
1985
2162
|
* `AsyncResult<T, E>` — the async counterpart of {@link Result}. Shares its name
|
|
@@ -2104,4 +2281,4 @@ declare function TaggedError<Tag extends string>(tag: Tag, options?: {
|
|
|
2104
2281
|
readonly name?: string;
|
|
2105
2282
|
}): TaggedErrorConstructor<Tag>;
|
|
2106
2283
|
//#endregion
|
|
2107
|
-
export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type AsyncResultMethods, type Awaitable, type DefectView, Do, DoAsync, Err, ErrAsync, type ErrMatcher, type ErrOf, type ErrView, type FailureView, GetError, type Matcher, NonExhaustiveError, type NotThenable, Ok, OkAsync, type OkOf, type OkView, P, type PatternMatcher, Result, type ResultMethods, type Settle, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, type UniversalPattern, all, allAsync, allFromDict, allFromDictAsync, fromExecutor, fromNullable, fromPromise, fromSafePromise, fromSafeThrowable, fromThrowable, isDefect, isErr, isOk, isResult, match };
|
|
2284
|
+
export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type AsyncResultMethods, type Awaitable, type DefectView, Do, DoAsync, Err, ErrAsync, type ErrMatcher, type ErrOf, type ErrView, type FailureView, GetError, type Matcher, NonExhaustiveError, type NotThenable, Ok, OkAsync, type OkOf, type OkView, P, type PatternMatcher, Result, type ResultMethods, type Settle, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, type UniversalPattern, all, allAsync, allFromDict, allFromDictAsync, fromExecutor, fromNullable, fromPromise, fromSafePromise, fromSafeThrowable, fromThrowable, isDefect, isErr, isOk, isResult, match, validateAll, validateAllAsync, validateAllFromDict, validateAllFromDictAsync };
|
package/dist/index.d.mts
CHANGED
|
@@ -1788,6 +1788,24 @@ declare function fromExecutor<T = never, E = never>(executor: (settle: Settle<T,
|
|
|
1788
1788
|
* @internal
|
|
1789
1789
|
*/
|
|
1790
1790
|
type AllOk<Rs extends readonly unknown[], Ts extends readonly unknown[]> = number extends Rs["length"] ? Ts[number][] : Ts;
|
|
1791
|
+
/**
|
|
1792
|
+
* A `[key, error]` pair from a record aggregate, correlated per key.
|
|
1793
|
+
*
|
|
1794
|
+
* @remarks
|
|
1795
|
+
* `-?` because the mapped type is homomorphic: an optional input key would
|
|
1796
|
+
* otherwise carry its optionality through and put `undefined` in the entry
|
|
1797
|
+
* union, breaking the documented `([key, error]) => …` destructure. An entry
|
|
1798
|
+
* whose error channel is `never` (an infallible input — every `@unthrown/drizzle`
|
|
1799
|
+
* read) is dropped rather than emitted as an uninhabited `[K, never]` arm, which
|
|
1800
|
+
* a `switch` over the key would still have to write a dead case for.
|
|
1801
|
+
*
|
|
1802
|
+
* @internal
|
|
1803
|
+
*/
|
|
1804
|
+
type DictErrEntry<R> = { [K in keyof R]-?: [ErrOf<R[K]>] extends [never] ? never : readonly [K, ErrOf<R[K]>]; }[keyof R];
|
|
1805
|
+
/** The {@link AsyncResult} counterpart of {@link DictErrEntry}. @internal */
|
|
1806
|
+
type AsyncDictErrEntry<R> = { [K in keyof R]-?: [AsyncErrOf<R[K]>] extends [never] ? never : readonly [K, AsyncErrOf<R[K]>]; }[keyof R];
|
|
1807
|
+
/** A non-empty readonly list — `merge` runs only when an `Err` was collected. @internal */
|
|
1808
|
+
type NonEmpty<T> = readonly [T, ...T[]];
|
|
1791
1809
|
/** A record of `Result`s — the input to {@link allFromDict}. */
|
|
1792
1810
|
type ResultRecord = Record<string, Result$1<unknown, unknown>>;
|
|
1793
1811
|
/** A record of `AsyncResult`s — the input to {@link allFromDictAsync}. */
|
|
@@ -1802,7 +1820,8 @@ type AsyncResultRecord = Record<string, AsyncResult$1<unknown, unknown>>;
|
|
|
1802
1820
|
* `Err`. A **fixed tuple** keeps its positional types — `all([Ok(1), Ok("a")])`
|
|
1803
1821
|
* is `Result<[number, string], …>` — while a **dynamic array** `Result<T, E>[]`
|
|
1804
1822
|
* collapses to `Result<T[], E>` with no cast. For a **record** keyed by name,
|
|
1805
|
-
* use {@link allFromDict}.
|
|
1823
|
+
* use {@link allFromDict}. To report **every** `Err` instead of only the first,
|
|
1824
|
+
* use {@link validateAll}.
|
|
1806
1825
|
*
|
|
1807
1826
|
* @category Aggregate
|
|
1808
1827
|
*
|
|
@@ -1823,7 +1842,9 @@ declare function all<Rs extends readonly Result$1<unknown, unknown>[]>(results:
|
|
|
1823
1842
|
*
|
|
1824
1843
|
* @remarks
|
|
1825
1844
|
* Same folding rules as {@link all}: first `Err` short-circuits, any `Defect`
|
|
1826
|
-
* dominates. This is **not** error accumulation
|
|
1845
|
+
* dominates. This is **not** error accumulation — for that, reach for
|
|
1846
|
+
* {@link validateAllFromDict}, which accumulates every `Err` and folds them into
|
|
1847
|
+
* one modeled error.
|
|
1827
1848
|
*
|
|
1828
1849
|
* @category Aggregate
|
|
1829
1850
|
*
|
|
@@ -1844,7 +1865,8 @@ declare function allFromDict<R extends ResultRecord>(results: R): Result$1<{ [K
|
|
|
1844
1865
|
* The inputs are resolved **concurrently** (order preserved); the resolved
|
|
1845
1866
|
* `Result`s are then folded with the same rules as {@link all} — first `Err`
|
|
1846
1867
|
* short-circuits, any `Defect` dominates. As ever, the returned `AsyncResult`'s
|
|
1847
|
-
* internal promise never rejects. For a **record**, use {@link allFromDictAsync}
|
|
1868
|
+
* internal promise never rejects. For a **record**, use {@link allFromDictAsync};
|
|
1869
|
+
* to report **every** `Err`, use {@link validateAllAsync}.
|
|
1848
1870
|
*
|
|
1849
1871
|
* @category Aggregate
|
|
1850
1872
|
*
|
|
@@ -1866,7 +1888,8 @@ declare function allAsync<Rs extends readonly AsyncResult$1<unknown, unknown>[]>
|
|
|
1866
1888
|
*
|
|
1867
1889
|
* @remarks
|
|
1868
1890
|
* Resolved concurrently (order preserved), folded with the {@link all} rules,
|
|
1869
|
-
* and the internal promise never rejects.
|
|
1891
|
+
* and the internal promise never rejects. To report **every** `Err`, use
|
|
1892
|
+
* {@link validateAllFromDictAsync}.
|
|
1870
1893
|
*
|
|
1871
1894
|
* @category Aggregate
|
|
1872
1895
|
*
|
|
@@ -1882,6 +1905,153 @@ declare function allAsync<Rs extends readonly AsyncResult$1<unknown, unknown>[]>
|
|
|
1882
1905
|
* ```
|
|
1883
1906
|
*/
|
|
1884
1907
|
declare function allFromDictAsync<R extends AsyncResultRecord>(results: R): AsyncResult$1<{ [K in keyof R]: AsyncOkOf<R[K]>; }, AsyncErrOf<R[keyof R]>>;
|
|
1908
|
+
/**
|
|
1909
|
+
* Collect a tuple/array of {@link Result}s, **accumulating every** `Err` and
|
|
1910
|
+
* merging them into a single modeled error — the accumulating counterpart of
|
|
1911
|
+
* {@link all}.
|
|
1912
|
+
*
|
|
1913
|
+
* @remarks
|
|
1914
|
+
* Same success channel as {@link all}: a **fixed tuple** keeps its positional
|
|
1915
|
+
* types, a **dynamic array** collapses to `Result<T[], E2>`. The difference is
|
|
1916
|
+
* the error channel — instead of the first `Err` winning, every `Err` is
|
|
1917
|
+
* collected in input order and handed to `merge`, whose return becomes the
|
|
1918
|
+
* modeled error.
|
|
1919
|
+
*
|
|
1920
|
+
* `merge` receives a **non-empty** list, so it is total: it is called only when
|
|
1921
|
+
* at least one `Err` was collected. It is **not** called when every element is
|
|
1922
|
+
* `Ok`, nor when a `Defect` is present.
|
|
1923
|
+
*
|
|
1924
|
+
* Any `Defect` still **dominates** — it wins over the accumulated errors, which
|
|
1925
|
+
* are discarded and never reach `merge`. A defect means something in this batch
|
|
1926
|
+
* failed in a way nobody modeled, so the violations computed alongside it are
|
|
1927
|
+
* not trustworthy. An out-of-contract non-`Result` element becomes a
|
|
1928
|
+
* `TypeError`-caused `Defect` the same way, and a throw inside `merge` becomes
|
|
1929
|
+
* a `Defect` too.
|
|
1930
|
+
*
|
|
1931
|
+
* `merge` must be **synchronous** — an `async` one is a compile error
|
|
1932
|
+
* ({@link NotThenable}), since a `Promise` in `E` is an unqualified rejection.
|
|
1933
|
+
*
|
|
1934
|
+
* For **schema-shaped** input (a request body, a form), reach for
|
|
1935
|
+
* `@unthrown/standard-schema`'s `fromSchema` instead — a validator already
|
|
1936
|
+
* hands you every issue as the modeled error. `validateAll` is for independent
|
|
1937
|
+
* checks you wrote yourself. For a **record** keyed by name, use
|
|
1938
|
+
* {@link validateAllFromDict}.
|
|
1939
|
+
*
|
|
1940
|
+
* @typeParam Rs - the tuple/array of input `Result` types.
|
|
1941
|
+
* @typeParam E2 - the merged error type.
|
|
1942
|
+
* @param results - the results to collect.
|
|
1943
|
+
* @param merge - folds the collected errors into one modeled error.
|
|
1944
|
+
*
|
|
1945
|
+
* @category Aggregate
|
|
1946
|
+
*
|
|
1947
|
+
* @example
|
|
1948
|
+
* ```ts
|
|
1949
|
+
* import { validateAll, Ok, Err } from "unthrown";
|
|
1950
|
+
*
|
|
1951
|
+
* // every Err is collected, not just the first
|
|
1952
|
+
* validateAll([Ok(1), Err("stock"), Err("credit")], (errors) => errors.join(" and "));
|
|
1953
|
+
* // => Err("stock and credit")
|
|
1954
|
+
*
|
|
1955
|
+
* // all-Ok keeps the positional tuple; `merge` never runs
|
|
1956
|
+
* validateAll([Ok(1), Ok("a")], (errors) => errors.join());
|
|
1957
|
+
* // => Ok([1, "a"]) typed Result<[number, string], string>
|
|
1958
|
+
* ```
|
|
1959
|
+
*/
|
|
1960
|
+
declare function validateAll<Rs extends readonly Result$1<unknown, unknown>[], E2>(results: readonly [...Rs], merge: (errors: NonEmpty<ErrOf<Rs[number]>>) => E2 & NotThenable<E2>): Result$1<AllOk<Rs, { [K in keyof Rs]: OkOf<Rs[K]>; }>, E2>;
|
|
1961
|
+
/**
|
|
1962
|
+
* Collect a **record** of {@link Result}s, accumulating every `Err` — the
|
|
1963
|
+
* accumulating counterpart of {@link allFromDict}, and the named counterpart of
|
|
1964
|
+
* {@link validateAll}.
|
|
1965
|
+
*
|
|
1966
|
+
* @remarks
|
|
1967
|
+
* `merge` receives a non-empty list of **`[key, error]` entries**, correlated
|
|
1968
|
+
* per key: `{ a: Result<A, E1>; b: Result<B, E2> }` yields
|
|
1969
|
+
* `["a", E1] | ["b", E2]`, so a `switch` on the key narrows the error and an
|
|
1970
|
+
* impossible pairing does not typecheck. That is what keeps two checks sharing
|
|
1971
|
+
* one error type distinguishable. Entries come in `Object.keys` order.
|
|
1972
|
+
*
|
|
1973
|
+
* Every other rule matches {@link validateAll}: any `Defect` dominates and
|
|
1974
|
+
* discards the accumulated errors, a throw in `merge` becomes a `Defect`, and
|
|
1975
|
+
* `merge` must be synchronous.
|
|
1976
|
+
*
|
|
1977
|
+
* @typeParam R - the record of input `Result` types.
|
|
1978
|
+
* @typeParam E2 - the merged error type.
|
|
1979
|
+
* @param results - the results to collect, keyed by name.
|
|
1980
|
+
* @param merge - folds the collected `[key, error]` entries into one error.
|
|
1981
|
+
*
|
|
1982
|
+
* @category Aggregate
|
|
1983
|
+
*
|
|
1984
|
+
* @example
|
|
1985
|
+
* ```ts
|
|
1986
|
+
* import { validateAllFromDict, Ok, Err } from "unthrown";
|
|
1987
|
+
*
|
|
1988
|
+
* validateAllFromDict(
|
|
1989
|
+
* { vatRate: Err("out of range"), currency: Ok("EUR"), dueDate: Err("past") },
|
|
1990
|
+
* (entries) => entries.map(([key, error]) => `${key}: ${error}`).join("; "),
|
|
1991
|
+
* );
|
|
1992
|
+
* // => Err("vatRate: out of range; dueDate: past")
|
|
1993
|
+
* ```
|
|
1994
|
+
*/
|
|
1995
|
+
declare function validateAllFromDict<R extends ResultRecord, E2>(results: R, merge: (entries: NonEmpty<DictErrEntry<R>>) => E2 & NotThenable<E2>): Result$1<{ [K in keyof R]: OkOf<R[K]>; }, E2>;
|
|
1996
|
+
/**
|
|
1997
|
+
* The asynchronous counterpart of {@link validateAll}: collect a tuple/array of
|
|
1998
|
+
* {@link AsyncResult}s, accumulating every `Err` into one merged error.
|
|
1999
|
+
*
|
|
2000
|
+
* @remarks
|
|
2001
|
+
* Every {@link validateAll} rule holds, with the inputs resolved
|
|
2002
|
+
* **concurrently** (order preserved) — as with {@link allAsync}, no work is
|
|
2003
|
+
* short-circuited either way; the fail-fast/accumulating split is purely which
|
|
2004
|
+
* errors get reported. The internal promise never rejects: an out-of-contract
|
|
2005
|
+
* rejecting thenable becomes a dominating `Defect`. `merge` stays synchronous
|
|
2006
|
+
* here too — this is exactly where its rejection would land unqualified in `E`.
|
|
2007
|
+
* For a **record**, use {@link validateAllFromDictAsync}.
|
|
2008
|
+
*
|
|
2009
|
+
* @typeParam Rs - the tuple/array of input `AsyncResult` types.
|
|
2010
|
+
* @typeParam E2 - the merged error type.
|
|
2011
|
+
* @param results - the async results to collect.
|
|
2012
|
+
* @param merge - folds the collected errors into one modeled error.
|
|
2013
|
+
*
|
|
2014
|
+
* @category Aggregate
|
|
2015
|
+
*
|
|
2016
|
+
* @example
|
|
2017
|
+
* ```ts
|
|
2018
|
+
* import { validateAllAsync, OkAsync, ErrAsync } from "unthrown";
|
|
2019
|
+
*
|
|
2020
|
+
* const checked = validateAllAsync(
|
|
2021
|
+
* [OkAsync(1), ErrAsync("stock"), ErrAsync("credit")],
|
|
2022
|
+
* (errors) => errors.join(" and "),
|
|
2023
|
+
* );
|
|
2024
|
+
* // (await checked) => Err("stock and credit")
|
|
2025
|
+
* ```
|
|
2026
|
+
*/
|
|
2027
|
+
declare function validateAllAsync<Rs extends readonly AsyncResult$1<unknown, unknown>[], E2>(results: readonly [...Rs], merge: (errors: NonEmpty<AsyncErrOf<Rs[number]>>) => E2 & NotThenable<E2>): AsyncResult$1<AllOk<Rs, { [K in keyof Rs]: AsyncOkOf<Rs[K]>; }>, E2>;
|
|
2028
|
+
/**
|
|
2029
|
+
* The asynchronous counterpart of {@link validateAllFromDict}: collect a record
|
|
2030
|
+
* of {@link AsyncResult}s, accumulating every `Err` into one merged error.
|
|
2031
|
+
*
|
|
2032
|
+
* @remarks
|
|
2033
|
+
* The {@link validateAllFromDict} rules, over inputs resolved concurrently as
|
|
2034
|
+
* in {@link validateAllAsync}.
|
|
2035
|
+
*
|
|
2036
|
+
* @typeParam R - the record of input `AsyncResult` types.
|
|
2037
|
+
* @typeParam E2 - the merged error type.
|
|
2038
|
+
* @param results - the async results to collect, keyed by name.
|
|
2039
|
+
* @param merge - folds the collected `[key, error]` entries into one error.
|
|
2040
|
+
*
|
|
2041
|
+
* @category Aggregate
|
|
2042
|
+
*
|
|
2043
|
+
* @example
|
|
2044
|
+
* ```ts
|
|
2045
|
+
* import { validateAllFromDictAsync, OkAsync, ErrAsync } from "unthrown";
|
|
2046
|
+
*
|
|
2047
|
+
* const checked = validateAllFromDictAsync(
|
|
2048
|
+
* { stock: ErrAsync("none left"), credit: OkAsync(500) },
|
|
2049
|
+
* (entries) => entries.map(([key, error]) => `${key}: ${error}`).join("; "),
|
|
2050
|
+
* );
|
|
2051
|
+
* // (await checked) => Err("stock: none left")
|
|
2052
|
+
* ```
|
|
2053
|
+
*/
|
|
2054
|
+
declare function validateAllFromDictAsync<R extends AsyncResultRecord, E2>(results: R, merge: (entries: NonEmpty<AsyncDictErrEntry<R>>) => E2 & NotThenable<E2>): AsyncResult$1<{ [K in keyof R]: AsyncOkOf<R[K]>; }, E2>;
|
|
1885
2055
|
//#endregion
|
|
1886
2056
|
//#region src/facade.d.ts
|
|
1887
2057
|
/**
|
|
@@ -1889,7 +2059,8 @@ declare function allFromDictAsync<R extends AsyncResultRecord>(results: R): Asyn
|
|
|
1889
2059
|
* single, discoverable namespace: {@link Result.Ok}, {@link Result.Err},
|
|
1890
2060
|
* {@link Result.Do}, {@link Result.fromNullable}, {@link Result.fromThrowable},
|
|
1891
2061
|
* {@link Result.fromSafeThrowable}, {@link Result.all},
|
|
1892
|
-
* {@link Result.allFromDict}, {@link Result.
|
|
2062
|
+
* {@link Result.allFromDict}, {@link Result.validateAll},
|
|
2063
|
+
* {@link Result.validateAllFromDict}, {@link Result.isOk}, {@link Result.isErr},
|
|
1893
2064
|
* {@link Result.isDefect}, {@link Result.isResult}.
|
|
1894
2065
|
*
|
|
1895
2066
|
* @remarks
|
|
@@ -1919,6 +2090,8 @@ declare const Result: {
|
|
|
1919
2090
|
readonly fromSafeThrowable: typeof fromSafeThrowable;
|
|
1920
2091
|
readonly all: typeof all;
|
|
1921
2092
|
readonly allFromDict: typeof allFromDict;
|
|
2093
|
+
readonly validateAll: typeof validateAll;
|
|
2094
|
+
readonly validateAllFromDict: typeof validateAllFromDict;
|
|
1922
2095
|
readonly isOk: typeof isOk;
|
|
1923
2096
|
readonly isErr: typeof isErr;
|
|
1924
2097
|
readonly isDefect: typeof isDefect;
|
|
@@ -1944,7 +2117,8 @@ type Result<T, E> = Result$1<T, E>;
|
|
|
1944
2117
|
* the matching namespace: {@link AsyncResult.Ok}, {@link AsyncResult.Err},
|
|
1945
2118
|
* {@link AsyncResult.Do}, {@link AsyncResult.fromExecutor},
|
|
1946
2119
|
* {@link AsyncResult.fromPromise}, {@link AsyncResult.fromSafePromise},
|
|
1947
|
-
* {@link AsyncResult.all}, {@link AsyncResult.allFromDict}
|
|
2120
|
+
* {@link AsyncResult.all}, {@link AsyncResult.allFromDict},
|
|
2121
|
+
* {@link AsyncResult.validateAll}, {@link AsyncResult.validateAllFromDict}.
|
|
1948
2122
|
*
|
|
1949
2123
|
* @remarks
|
|
1950
2124
|
* The async sibling of {@link Result}. Statics are grouped by what they
|
|
@@ -1955,7 +2129,8 @@ type Result<T, E> = Result$1<T, E>;
|
|
|
1955
2129
|
* functions carry (`AsyncResult.Ok` is `OkAsync`; `AsyncResult.Err` is
|
|
1956
2130
|
* `ErrAsync`; `AsyncResult.Do` is `DoAsync`; `AsyncResult.all` is `allAsync`;
|
|
1957
2131
|
* `AsyncResult.allFromDict` is
|
|
1958
|
-
* `allFromDictAsync`). Like
|
|
2132
|
+
* `allFromDictAsync`; `AsyncResult.validateAll` is `validateAllAsync`). Like
|
|
2133
|
+
* {@link Result}, the free functions remain the
|
|
1959
2134
|
* primary, tree-shakeable API; the value `AsyncResult` and the type
|
|
1960
2135
|
* {@link AsyncResult} share one name.
|
|
1961
2136
|
*
|
|
@@ -1980,6 +2155,8 @@ declare const AsyncResult: {
|
|
|
1980
2155
|
readonly fromSafePromise: typeof fromSafePromise;
|
|
1981
2156
|
readonly all: typeof allAsync;
|
|
1982
2157
|
readonly allFromDict: typeof allFromDictAsync;
|
|
2158
|
+
readonly validateAll: typeof validateAllAsync;
|
|
2159
|
+
readonly validateAllFromDict: typeof validateAllFromDictAsync;
|
|
1983
2160
|
};
|
|
1984
2161
|
/**
|
|
1985
2162
|
* `AsyncResult<T, E>` — the async counterpart of {@link Result}. Shares its name
|
|
@@ -2104,4 +2281,4 @@ declare function TaggedError<Tag extends string>(tag: Tag, options?: {
|
|
|
2104
2281
|
readonly name?: string;
|
|
2105
2282
|
}): TaggedErrorConstructor<Tag>;
|
|
2106
2283
|
//#endregion
|
|
2107
|
-
export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type AsyncResultMethods, type Awaitable, type DefectView, Do, DoAsync, Err, ErrAsync, type ErrMatcher, type ErrOf, type ErrView, type FailureView, GetError, type Matcher, NonExhaustiveError, type NotThenable, Ok, OkAsync, type OkOf, type OkView, P, type PatternMatcher, Result, type ResultMethods, type Settle, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, type UniversalPattern, all, allAsync, allFromDict, allFromDictAsync, fromExecutor, fromNullable, fromPromise, fromSafePromise, fromSafeThrowable, fromThrowable, isDefect, isErr, isOk, isResult, match };
|
|
2284
|
+
export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type AsyncResultMethods, type Awaitable, type DefectView, Do, DoAsync, Err, ErrAsync, type ErrMatcher, type ErrOf, type ErrView, type FailureView, GetError, type Matcher, NonExhaustiveError, type NotThenable, Ok, OkAsync, type OkOf, type OkView, P, type PatternMatcher, Result, type ResultMethods, type Settle, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, type UniversalPattern, all, allAsync, allFromDict, allFromDictAsync, fromExecutor, fromNullable, fromPromise, fromSafePromise, fromSafeThrowable, fromThrowable, isDefect, isErr, isOk, isResult, match, validateAll, validateAllAsync, validateAllFromDict, validateAllFromDictAsync };
|