@clipboard-health/contract-core 2.3.47 → 3.1.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/README.md +29 -14
- package/package.json +1 -1
- package/src/lib/schemas/enum.d.ts +13 -6
- package/src/lib/schemas/enum.js +23 -9
- package/src/lib/schemas/enum.js.map +1 -1
package/README.md
CHANGED
|
@@ -29,14 +29,29 @@ This package provides four enum validation helpers to cover different use cases:
|
|
|
29
29
|
|
|
30
30
|
**Fallback validation (with coalescing):**
|
|
31
31
|
|
|
32
|
-
- `requiredEnumWithFallback(values
|
|
33
|
-
- `optionalEnumWithFallback(values
|
|
32
|
+
- `requiredEnumWithFallback(values)` - Invalid values are coerced to `ENUM_FALLBACK` (`"UNRECOGNIZED_"`), a business-context-neutral sentinel automatically appended to the enum type. `undefined` fails validation.
|
|
33
|
+
- `optionalEnumWithFallback(values)` - Invalid values are coerced to `ENUM_FALLBACK` (`"UNRECOGNIZED_"`). `undefined` passes through as `undefined`.
|
|
34
34
|
|
|
35
35
|
**Strict validation (no fallback):**
|
|
36
36
|
|
|
37
37
|
- `requiredEnum(values)` - Wraps `z.enum()` for required strict validation. Invalid values fail validation.
|
|
38
38
|
- `optionalEnum(values)` - Wraps `z.enum()` for optional strict validation. Invalid values fail validation, but `undefined` is allowed.
|
|
39
39
|
|
|
40
|
+
**Type narrowing:** All helpers reject widened `string[]` arrays at compile time. When passing a pre-declared variable, use `as const` to preserve literal types:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// Inline arrays work as-is
|
|
44
|
+
requiredEnum(["a", "b"]);
|
|
45
|
+
|
|
46
|
+
// Pre-declared variables require `as const`
|
|
47
|
+
const VALUES = ["a", "b"] as const;
|
|
48
|
+
requiredEnum(VALUES);
|
|
49
|
+
|
|
50
|
+
// Without `as const`, the type widens to string[] and is rejected
|
|
51
|
+
const widened = ["a", "b"];
|
|
52
|
+
requiredEnum(widened); // TS error
|
|
53
|
+
```
|
|
54
|
+
|
|
40
55
|
<embedex source="packages/contract-core/examples/schemas.ts">
|
|
41
56
|
|
|
42
57
|
```ts
|
|
@@ -44,6 +59,7 @@ import {
|
|
|
44
59
|
apiErrors,
|
|
45
60
|
booleanString,
|
|
46
61
|
dateTimeSchema,
|
|
62
|
+
ENUM_FALLBACK,
|
|
47
63
|
nonEmptyString,
|
|
48
64
|
optionalEnum,
|
|
49
65
|
optionalEnumWithFallback,
|
|
@@ -134,12 +150,13 @@ const someDate = schema.parse("2026-03-15T10:30:00.000Z");
|
|
|
134
150
|
console.log(someDate);
|
|
135
151
|
|
|
136
152
|
// Enum with fallback examples
|
|
153
|
+
// ENUM_FALLBACK is a neutral sentinel ("UNRECOGNIZED_") automatically appended
|
|
154
|
+
// to the enum type. Consumers cannot choose their own fallback value, preventing
|
|
155
|
+
// misuse where a business-meaningful value is treated as a default.
|
|
156
|
+
|
|
137
157
|
/* -- required -- */
|
|
138
|
-
const requiredStatusEnumSchema = requiredEnumWithFallback(
|
|
139
|
-
|
|
140
|
-
"unspecified",
|
|
141
|
-
);
|
|
142
|
-
// type RequiredStatusEnum = "unspecified" | "pending" | "completed" | "failed"
|
|
158
|
+
const requiredStatusEnumSchema = requiredEnumWithFallback(["pending", "completed", "failed"]);
|
|
159
|
+
// type RequiredStatusEnum = "pending" | "completed" | "failed" | "UNRECOGNIZED_"
|
|
143
160
|
type RequiredStatusEnum = z.infer<typeof requiredStatusEnumSchema>;
|
|
144
161
|
|
|
145
162
|
const completedStatus: RequiredStatusEnum = requiredStatusEnumSchema.parse("completed");
|
|
@@ -147,8 +164,9 @@ const completedStatus: RequiredStatusEnum = requiredStatusEnumSchema.parse("comp
|
|
|
147
164
|
console.log(completedStatus);
|
|
148
165
|
|
|
149
166
|
const additionalStatus = requiredStatusEnumSchema.parse("additional");
|
|
150
|
-
// => "
|
|
167
|
+
// => "UNRECOGNIZED_" (ENUM_FALLBACK)
|
|
151
168
|
console.log(additionalStatus);
|
|
169
|
+
console.log(additionalStatus === ENUM_FALLBACK); // true
|
|
152
170
|
|
|
153
171
|
try {
|
|
154
172
|
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
@@ -159,11 +177,8 @@ try {
|
|
|
159
177
|
}
|
|
160
178
|
|
|
161
179
|
/* -- optional -- */
|
|
162
|
-
const optionalStatusEnumSchema = optionalEnumWithFallback(
|
|
163
|
-
|
|
164
|
-
"unspecified",
|
|
165
|
-
);
|
|
166
|
-
// type OptionalStatusEnum = "unspecified" | "pending" | "completed" | "failed" | undefined
|
|
180
|
+
const optionalStatusEnumSchema = optionalEnumWithFallback(["pending", "completed", "failed"]);
|
|
181
|
+
// type OptionalStatusEnum = "pending" | "completed" | "failed" | "UNRECOGNIZED_" | undefined
|
|
167
182
|
type OptionalStatusEnum = z.infer<typeof optionalStatusEnumSchema>;
|
|
168
183
|
|
|
169
184
|
const failedStatus: OptionalStatusEnum = optionalStatusEnumSchema.parse("failed");
|
|
@@ -171,7 +186,7 @@ const failedStatus: OptionalStatusEnum = optionalStatusEnumSchema.parse("failed"
|
|
|
171
186
|
console.log(failedStatus);
|
|
172
187
|
|
|
173
188
|
const extraStatus = optionalStatusEnumSchema.parse("extra");
|
|
174
|
-
// => "
|
|
189
|
+
// => "UNRECOGNIZED_" (ENUM_FALLBACK)
|
|
175
190
|
console.log(extraStatus);
|
|
176
191
|
|
|
177
192
|
// eslint-disable-next-line unicorn/no-useless-undefined
|
package/package.json
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
type EnumValues = readonly [string, ...string[]];
|
|
3
|
-
|
|
3
|
+
type NarrowEnum<V extends EnumValues> = string extends V[number] ? never : V;
|
|
4
|
+
/**
|
|
5
|
+
* A business-context-neutral sentinel returned when an enum field
|
|
6
|
+
* receives a value the consumer does not recognize.
|
|
7
|
+
*/
|
|
8
|
+
export declare const ENUM_FALLBACK: "UNRECOGNIZED_";
|
|
9
|
+
type EnumFallback = typeof ENUM_FALLBACK;
|
|
10
|
+
export declare function enumWithFallback<const V extends EnumValues>(values: NarrowEnum<V>, options: {
|
|
4
11
|
optional: true;
|
|
5
|
-
}): z.ZodEffects<z.ZodOptional<z.ZodEnum<[...V]>>, V[number] | undefined, unknown>;
|
|
6
|
-
export declare
|
|
7
|
-
export declare
|
|
8
|
-
export declare function requiredEnum<const V extends EnumValues>(values: V): z.ZodEnum<[...V]>;
|
|
9
|
-
export declare function optionalEnum<const V extends EnumValues>(values: V): z.ZodOptional<z.ZodEnum<[...V]>>;
|
|
12
|
+
}): z.ZodEffects<z.ZodOptional<z.ZodEnum<[...V, EnumFallback]>>, V[number] | EnumFallback | undefined, unknown>;
|
|
13
|
+
export declare function requiredEnumWithFallback<const V extends EnumValues>(values: NarrowEnum<V>): z.ZodEffects<z.ZodEnum<[...V, "UNRECOGNIZED_"]>, "UNRECOGNIZED_" | V[number], unknown>;
|
|
14
|
+
export declare function optionalEnumWithFallback<const V extends EnumValues>(values: NarrowEnum<V>): z.ZodEffects<z.ZodOptional<z.ZodEnum<[...V, "UNRECOGNIZED_"]>>, "UNRECOGNIZED_" | V[number] | undefined, unknown>;
|
|
15
|
+
export declare function requiredEnum<const V extends EnumValues>(values: NarrowEnum<V>): z.ZodEnum<[...V]>;
|
|
16
|
+
export declare function optionalEnum<const V extends EnumValues>(values: NarrowEnum<V>): z.ZodOptional<z.ZodEnum<[...V]>>;
|
|
10
17
|
export {};
|
package/src/lib/schemas/enum.js
CHANGED
|
@@ -1,25 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.ENUM_FALLBACK = void 0;
|
|
4
4
|
exports.enumWithFallback = enumWithFallback;
|
|
5
|
+
exports.requiredEnumWithFallback = requiredEnumWithFallback;
|
|
6
|
+
exports.optionalEnumWithFallback = optionalEnumWithFallback;
|
|
5
7
|
exports.requiredEnum = requiredEnum;
|
|
6
8
|
exports.optionalEnum = optionalEnum;
|
|
7
9
|
const zod_1 = require("zod");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
/**
|
|
11
|
+
* A business-context-neutral sentinel returned when an enum field
|
|
12
|
+
* receives a value the consumer does not recognize.
|
|
13
|
+
*/
|
|
14
|
+
exports.ENUM_FALLBACK = "UNRECOGNIZED_";
|
|
15
|
+
function enumWithFallback(values, options = {}) {
|
|
16
|
+
if (values.includes(exports.ENUM_FALLBACK)) {
|
|
17
|
+
throw new Error(`Enum values must not include "${exports.ENUM_FALLBACK}". It is appended automatically.`);
|
|
18
|
+
}
|
|
19
|
+
const OriginalEnum = zod_1.z.enum([...values]);
|
|
20
|
+
const ExpandedEnum = zod_1.z.enum([...values, exports.ENUM_FALLBACK]);
|
|
10
21
|
const optional = options.optional ?? false;
|
|
11
|
-
const schema = optional ?
|
|
22
|
+
const schema = optional ? ExpandedEnum.optional() : ExpandedEnum;
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
12
24
|
return zod_1.z.preprocess((value) => {
|
|
13
25
|
if (value === undefined) {
|
|
14
26
|
return optional ? undefined : value;
|
|
15
27
|
}
|
|
16
|
-
return
|
|
28
|
+
return OriginalEnum.safeParse(value).success ? value : exports.ENUM_FALLBACK;
|
|
17
29
|
}, schema);
|
|
18
30
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
function requiredEnumWithFallback(values) {
|
|
32
|
+
return enumWithFallback(values, { optional: false });
|
|
33
|
+
}
|
|
34
|
+
function optionalEnumWithFallback(values) {
|
|
35
|
+
return enumWithFallback(values, { optional: true });
|
|
36
|
+
}
|
|
23
37
|
function requiredEnum(values) {
|
|
24
38
|
return zod_1.z.enum([...values]);
|
|
25
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enum.js","sourceRoot":"","sources":["../../../../../../packages/contract-core/src/lib/schemas/enum.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"enum.js","sourceRoot":"","sources":["../../../../../../packages/contract-core/src/lib/schemas/enum.ts"],"names":[],"mappings":";;;AAkCA,4CAuBC;AAED,4DAEC;AAED,4DAEC;AAED,oCAEC;AAED,oCAIC;AA3ED,6BAAwB;AAKxB;;;GAGG;AACU,QAAA,aAAa,GAAG,eAAwB,CAAC;AAyBtD,SAAgB,gBAAgB,CAC9B,MAAS,EACT,UAAkC,EAAE;IAEpC,IAAK,MAA4B,CAAC,QAAQ,CAAC,qBAAa,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CACb,iCAAiC,qBAAa,kCAAkC,CACjF,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,OAAC,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACzC,MAAM,YAAY,GAAG,OAAC,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,EAAE,qBAAa,CAAC,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC;IAC3C,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;IAEjE,+DAA+D;IAC/D,OAAO,OAAC,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE;QAC5B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;QACtC,CAAC;QAED,OAAO,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAa,CAAC;IACvE,CAAC,EAAE,MAAM,CAAC,CAAC;AACb,CAAC;AAED,SAAgB,wBAAwB,CAA6B,MAAqB;IACxF,OAAO,gBAAgB,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,SAAgB,wBAAwB,CAA6B,MAAqB;IACxF,OAAO,gBAAgB,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,SAAgB,YAAY,CAA6B,MAAqB;IAC5E,OAAO,OAAC,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,SAAgB,YAAY,CAC1B,MAAqB;IAErB,OAAO,OAAC,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AACxC,CAAC"}
|