Skip to content

Commit 81724af

Browse files
authored
Drop optionalPropStyle from Integration (#2561)
In favor of using Zod 4 `z.interface`
1 parent 1a7b502 commit 81724af

8 files changed

Lines changed: 10 additions & 514 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
- The `numericRange` option removed from `Documentation` class constructor argument;
1717
- The `brandHandling` should consist of postprocessing functions altering the depiction made by Zod 4;
1818
- The `Depicter` type changed to `Overrider` having different signature;
19+
- The `optionalPropStyle` option removed from `Integration` class constructor:
20+
- Use the new `z.interface()` schema to describe key-optional objects: https://v4.zod.dev/v4#zinterface.
1921

2022
## Version 23
2123

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1269,7 +1269,6 @@ import { Integration } from "express-zod-api";
12691269
const client = new Integration({
12701270
routing,
12711271
variant: "client", // <— optional, see also "types" for a DIY solution
1272-
optionalPropStyle: { withQuestionMark: true, withUndefined: true }, // optional
12731272
});
12741273

12751274
const prettierFormattedTypescriptCode = await client.printFormatted(); // or just .print() for unformatted

express-zod-api/src/integration.ts

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,6 @@ interface IntegrationParams {
4141
* @default https://example.com
4242
* */
4343
serverUrl?: string;
44-
/**
45-
* @desc configures the style of object's optional properties
46-
* @default { withQuestionMark: true, withUndefined: true }
47-
*/
48-
optionalPropStyle?: {
49-
/**
50-
* @desc add question mark to the optional property definition
51-
* @example { someProp?: boolean }
52-
* */
53-
withQuestionMark?: boolean;
54-
/**
55-
* @desc add undefined to the property union type
56-
* @example { someProp: boolean | undefined }
57-
*/
58-
withUndefined?: boolean;
59-
};
6044
/**
6145
* @desc The schema to use for responses without body such as 204
6246
* @default z.undefined()
@@ -110,14 +94,10 @@ export class Integration extends IntegrationBase {
11094
clientClassName = "Client",
11195
subscriptionClassName = "Subscription",
11296
serverUrl = "https://example.com",
113-
optionalPropStyle = { withQuestionMark: true, withUndefined: true },
11497
noContent = z.undefined(),
11598
}: IntegrationParams) {
11699
super(serverUrl);
117-
const commons = {
118-
makeAlias: this.#makeAlias.bind(this),
119-
optionalPropStyle,
120-
};
100+
const commons = { makeAlias: this.#makeAlias.bind(this) };
121101
const ctxIn = { brandHandling, ctx: { ...commons, isResponse: false } };
122102
const ctxOut = { brandHandling, ctx: { ...commons, isResponse: true } };
123103
const onEndpoint: OnEndpoint = (endpoint, path, method) => {

express-zod-api/src/zts-helpers.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ export interface ZTSContext extends FlatObject {
99
schema: $ZodType | (() => $ZodType),
1010
produce: () => ts.TypeNode,
1111
) => ts.TypeNode;
12-
// @todo remove it in favor of z.interface
13-
optionalPropStyle: { withQuestionMark?: boolean; withUndefined?: boolean };
1412
}
1513

1614
export type Producer = SchemaHandler<ts.TypeNode, ZTSContext>;

express-zod-api/src/zts.ts

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,7 @@ const onInterface: Producer = (int: z.ZodInterface, { next, makeAlias }) =>
8585

8686
const onObject: Producer = (
8787
{ _zod: { def } }: z.ZodObject,
88-
{
89-
isResponse,
90-
next,
91-
optionalPropStyle: { withQuestionMark: hasQuestionMark },
92-
},
88+
{ isResponse, next },
9389
) => {
9490
const members = Object.entries(def.shape).map<ts.TypeElement>(
9591
([key, value]) => {
@@ -103,7 +99,7 @@ const onObject: Producer = (
10399
return makeInterfaceProp(key, next(value), {
104100
comment,
105101
isDeprecated,
106-
isOptional: isOptional && hasQuestionMark,
102+
isOptional,
107103
});
108104
},
109105
);
@@ -131,18 +127,11 @@ const onSomeUnion: Producer = (
131127
const makeSample = (produced: ts.TypeNode) =>
132128
samples?.[produced.kind as keyof typeof samples];
133129

134-
const onOptional: Producer = (
135-
{ _zod: { def } }: $ZodOptional,
136-
{ next, optionalPropStyle: { withUndefined: hasUndefined } },
137-
) => {
138-
const actualTypeNode = next(def.innerType);
139-
return hasUndefined
140-
? f.createUnionTypeNode([
141-
actualTypeNode,
142-
ensureTypeNode(ts.SyntaxKind.UndefinedKeyword),
143-
])
144-
: actualTypeNode;
145-
};
130+
const onOptional: Producer = ({ _zod: { def } }: $ZodOptional, { next }) =>
131+
f.createUnionTypeNode([
132+
next(def.innerType),
133+
ensureTypeNode(ts.SyntaxKind.UndefinedKeyword),
134+
]);
146135

147136
const onNullable: Producer = ({ _zod: { def } }: $ZodNullable, { next }) =>
148137
f.createUnionTypeNode([next(def.innerType), makeLiteralType(null)]);

0 commit comments

Comments
 (0)