paramour 0.9.0 → 0.10.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/codec.d.ts +19 -3
- package/dist/codec.js +22 -1
- package/package.json +1 -1
package/dist/codec.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export type Arity = "many" | "single";
|
|
|
30
30
|
* `Out` (which is an array type).
|
|
31
31
|
*/
|
|
32
32
|
export interface Codec<Out, P extends Presence = "required", C extends boolean = false, A extends Arity = "single", E extends boolean = boolean> {
|
|
33
|
-
readonly catch: C extends false ? (fallback: (() => Out) | Out) => Codec<Out, P, true, A, E> : never;
|
|
33
|
+
readonly catch: C extends false ? (fallback: (() => CatchFallback<Out, P>) | CatchFallback<Out, P>) => Codec<Out, P, true, A, E> : never;
|
|
34
34
|
/**
|
|
35
35
|
* Overloaded so the value/factory split is visible in type-state: the
|
|
36
36
|
* factory overload comes FIRST and must stay first. The runtime
|
|
@@ -48,8 +48,13 @@ export interface Codec<Out, P extends Presence = "required", C extends boolean =
|
|
|
48
48
|
} : never : never;
|
|
49
49
|
readonly optional: A extends "single" ? P extends "required" ? () => Codec<Out, "optional", C, A, E> : never : never;
|
|
50
50
|
readonly "~arity": A;
|
|
51
|
-
/**
|
|
52
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Stored as a thunk regardless of the form passed to `.catch()`. The thunk
|
|
53
|
+
* may return `undefined` only on an `.optional()` codec (see
|
|
54
|
+
* {@link CatchFallback}); typed uniformly so every codec stays assignable
|
|
55
|
+
* to {@link AnyCodec}.
|
|
56
|
+
*/
|
|
57
|
+
readonly "~catchValue": (() => Out | undefined) | undefined;
|
|
53
58
|
readonly "~caught": C;
|
|
54
59
|
/**
|
|
55
60
|
* True when `.default()` received a value (not a factory). Value defaults
|
|
@@ -104,6 +109,17 @@ export type ParamCodec = Codec<any, "required", boolean>;
|
|
|
104
109
|
*/
|
|
105
110
|
export type Presence = "defaulted" | "optional" | "required";
|
|
106
111
|
export type PresenceOf<C extends AnyCodec> = C["~presence"];
|
|
112
|
+
/**
|
|
113
|
+
* What `.catch()` may recover to. An `.optional()` codec already decodes to
|
|
114
|
+
* `Out | undefined`, so it may also recover a failed parse to *absent* —
|
|
115
|
+
* `undefined` — which is the honest fallback when no in-domain value means
|
|
116
|
+
* "nothing selected". This does not blur D2: the INPUT `.catch()` handles is
|
|
117
|
+
* still a present-but-malformed value, never absence. Every other presence
|
|
118
|
+
* keeps an `Out`-only fallback: a required or defaulted key must decode to a
|
|
119
|
+
* value. Non-distributive so the `Presence` union inside {@link AnyCodec}
|
|
120
|
+
* reads as `Out`, keeping concrete optional codecs assignable to it.
|
|
121
|
+
*/
|
|
122
|
+
type CatchFallback<Out, P extends Presence> = [P] extends ["optional"] ? Out | undefined : Out;
|
|
107
123
|
/**
|
|
108
124
|
* Rejects value-form `.default()` arguments whose static type includes any
|
|
109
125
|
* function member: runtime {@link isFactory} would treat them as factories,
|
package/dist/codec.js
CHANGED
|
@@ -22,7 +22,28 @@ function build(state) {
|
|
|
22
22
|
if (state.catchValue !== undefined) {
|
|
23
23
|
throw new ParamourError(".catch() may only be applied once");
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
if (state.presence === "optional") {
|
|
26
|
+
return build({ ...state, catchValue: toThunk(fallback, "catch") });
|
|
27
|
+
}
|
|
28
|
+
// Only an optional key may recover to absent (CatchFallback). The
|
|
29
|
+
// value form fails here, at definition time; a factory's result is
|
|
30
|
+
// only knowable per decode, so it is checked there.
|
|
31
|
+
if (fallback === undefined) {
|
|
32
|
+
throw new ParamourError(".catch(undefined) requires .optional() first: only an optional key can recover to absent");
|
|
33
|
+
}
|
|
34
|
+
const thunk = toThunk(fallback, "catch");
|
|
35
|
+
return build({
|
|
36
|
+
...state,
|
|
37
|
+
catchValue: isFactory(fallback)
|
|
38
|
+
? () => {
|
|
39
|
+
const value = thunk();
|
|
40
|
+
if (value === undefined) {
|
|
41
|
+
throw new ParamourError(".catch() factory returned undefined on a non-optional codec: only an optional key can recover to absent");
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
: thunk,
|
|
46
|
+
});
|
|
26
47
|
},
|
|
27
48
|
default(value) {
|
|
28
49
|
if (state.arity === "many") {
|