Skip to content

Commit 6293a44

Browse files
committed
chore: add resolved config types for Zod
1 parent eb4fb3b commit 6293a44

File tree

9 files changed

+345
-37
lines changed

9 files changed

+345
-37
lines changed

docs/openapi-ts/plugins/custom.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ import type { Plugin } from '@hey-api/openapi-ts';
110110

111111
import type { Config } from './types';
112112

113-
export const handler: Plugin.Handler<Config> = ({ context, plugin }) => {
113+
export const handler: Plugin.Handler<Config> = ({ plugin }) => {
114114
// create an output file. it will not be
115115
// generated until it contains nodes
116-
const file = context.createFile({
116+
const file = plugin.createFile({
117117
id: plugin.name,
118118
path: plugin.output,
119119
});

packages/openapi-ts-tests/test/openapi-ts.config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,15 @@ export default defineConfig(() => {
163163
},
164164
{
165165
// comments: false,
166+
definitions: 'z{{name}}Definition',
166167
// exportFromIndex: true,
167168
// metadata: true,
168169
name: 'zod',
170+
requests: {
171+
case: 'PascalCase',
172+
enabled: false,
173+
},
174+
responses: false,
169175
},
170176
],
171177
// useOptions: false,

packages/openapi-ts/src/initConfigs.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,42 @@ const getPluginsConfig = ({
158158
`missing plugin - no plugin with tag "${tag}" found`,
159159
);
160160
},
161+
valueToObject: ({ defaultValue, mappers, value }) => {
162+
let result = { ...defaultValue };
163+
switch (typeof value) {
164+
case 'boolean':
165+
if ('boolean' in mappers) {
166+
const mapper = mappers.boolean as (
167+
value: boolean,
168+
) => Record<string, any>;
169+
result = { ...result, ...mapper(value) };
170+
}
171+
break;
172+
case 'number':
173+
if ('number' in mappers) {
174+
const mapper = mappers.number as (
175+
value: number,
176+
) => Record<string, any>;
177+
result = { ...result, ...mapper(value) };
178+
}
179+
break;
180+
case 'string':
181+
if ('string' in mappers) {
182+
const mapper = mappers.string as (
183+
value: string,
184+
) => Record<string, any>;
185+
result = { ...result, ...mapper(value) };
186+
}
187+
break;
188+
case 'object':
189+
if (value !== null) {
190+
result = { ...result, ...value };
191+
}
192+
break;
193+
}
194+
return result;
195+
},
161196
};
162-
// @ts-expect-error
163197
plugin.resolveConfig(plugin, context);
164198
}
165199

packages/openapi-ts/src/plugins/index.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,7 @@ export type ClientPlugins =
128128
| Plugin.Config<Zod>;
129129

130130
export const defaultPluginConfigs: {
131-
[K in PluginNames]: Plugin.Config<{
132-
exportFromIndex?: any;
133-
name: any;
134-
output?: any;
135-
}>;
131+
[K in PluginNames]: any;
136132
} = {
137133
'@hey-api/client-axios': heyApiClientAxios,
138134
'@hey-api/client-fetch': heyApiClientFetch,

packages/openapi-ts/src/plugins/shared/utils/config.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import type { BaseConfig, Plugin } from '../../types';
22

33
export const definePluginConfig =
4-
<Config extends BaseConfig>(defaultConfig: Plugin.Config<Config>) =>
4+
<Config extends BaseConfig, ResolvedConfig extends BaseConfig = Config>(
5+
defaultConfig: Plugin.Config<Config, ResolvedConfig>,
6+
) =>
57
(
68
userConfig?: Omit<Plugin.UserConfig<Config>, 'name'>,
7-
): Omit<Plugin.Config<Config>, 'name'> & {
9+
): Omit<Plugin.Config<Config, ResolvedConfig>, 'name'> & {
810
/**
911
* Cast name to `any` so it doesn't throw type error in `plugins` array.
1012
* We could allow any `string` as plugin `name` in the object syntax, but

packages/openapi-ts/src/plugins/types.d.ts

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ export type AnyPluginName = PluginNames | (string & {});
3434

3535
type PluginTag = 'client' | 'transformer' | 'validator';
3636

37+
type ObjectType<T> =
38+
Extract<T, Record<string, any>> extends never
39+
? Record<string, any>
40+
: Extract<T, Record<string, any>>;
41+
3742
export interface PluginContext {
3843
pluginByTag: <T extends AnyPluginName | boolean = AnyPluginName>(
3944
tag: PluginTag,
@@ -42,6 +47,25 @@ export interface PluginContext {
4247
errorMessage?: string;
4348
},
4449
) => Exclude<T, boolean> | undefined;
50+
valueToObject: <
51+
T extends undefined | string | boolean | number | Record<string, any>,
52+
>(args: {
53+
defaultValue: ObjectType<T>;
54+
mappers: {
55+
boolean: T extends boolean
56+
? (value: boolean) => Partial<ObjectType<T>>
57+
: never;
58+
number: T extends number
59+
? (value: number) => Partial<ObjectType<T>>
60+
: never;
61+
string: T extends string
62+
? (value: string) => Partial<ObjectType<T>>
63+
: never;
64+
} extends infer U
65+
? { [K in keyof U as U[K] extends never ? never : K]: U[K] }
66+
: never;
67+
value: T;
68+
}) => ObjectType<T>;
4569
}
4670

4771
export interface BaseConfig {
@@ -54,7 +78,10 @@ export interface BaseConfig {
5478
output?: string;
5579
}
5680

57-
interface Meta<Config extends BaseConfig> {
81+
interface Meta<
82+
Config extends BaseConfig,
83+
ResolvedConfig extends BaseConfig = Config,
84+
> {
5885
/**
5986
* Dependency plugins will be always processed, regardless of whether user
6087
* explicitly defines them in their `plugins` config.
@@ -66,7 +93,7 @@ interface Meta<Config extends BaseConfig> {
6693
* should be used for validation.
6794
*/
6895
resolveConfig?: (
69-
config: Omit<Plugin.Config<Config>, 'dependencies'> & {
96+
plugin: Omit<Plugin.Config<Config, ResolvedConfig>, 'dependencies'> & {
7097
dependencies: Set<AnyPluginName>;
7198
},
7299
context: PluginContext,
@@ -82,28 +109,32 @@ interface Meta<Config extends BaseConfig> {
82109
* Public Plugin API.
83110
*/
84111
export namespace Plugin {
85-
export type Config<Config extends BaseConfig> = Pick<
86-
Config,
87-
'name' | 'output'
88-
> &
89-
Meta<Config> & {
112+
export type Config<
113+
Config extends BaseConfig,
114+
ResolvedConfig extends BaseConfig = Config,
115+
> = Pick<Config, 'name' | 'output'> &
116+
Meta<Config, ResolvedConfig> & {
90117
config: Omit<Config, 'name' | 'output'>;
91118
handler: Plugin.Handler<
92-
Omit<Config, 'name'> & {
119+
Omit<ResolvedConfig, 'name'> & {
93120
name: any;
94121
}
95122
>;
96123
handlerLegacy: Plugin.LegacyHandler<
97-
Omit<Config, 'name'> & {
124+
Omit<ResolvedConfig, 'name'> & {
98125
name: any;
99126
}
100127
>;
101128
};
102129

103130
/** @deprecated - use `definePluginConfig()` instead */
104-
export type DefineConfig<Config extends BaseConfig> = (
105-
config?: Plugin.UserConfig<Omit<Config, 'name'>>,
106-
) => Omit<Plugin.Config<Config>, 'name'> & {
131+
export type DefineConfig<
132+
Config extends BaseConfig,
133+
ResolvedConfig extends BaseConfig = Config,
134+
> = (config?: Plugin.UserConfig<Omit<Config, 'name'>>) => Omit<
135+
Plugin.Config<Config, ResolvedConfig>,
136+
'name'
137+
> & {
107138
/**
108139
* Cast name to `any` so it doesn't throw type error in `plugins` array.
109140
* We could allow any `string` as plugin `name` in the object syntax, but

packages/openapi-ts/src/plugins/zod/config.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { definePluginConfig } from '../shared/utils/config';
22
import type { Plugin } from '../types';
33
import { handler } from './plugin';
4-
import type { Config } from './types';
4+
import type { Config, ResolvedConfig } from './types';
55

6-
export const defaultConfig: Plugin.Config<Config> = {
6+
export const defaultConfig: Plugin.Config<Config, ResolvedConfig> = {
77
config: {
88
comments: true,
99
exportFromIndex: false,
@@ -13,6 +13,46 @@ export const defaultConfig: Plugin.Config<Config> = {
1313
handlerLegacy: () => {},
1414
name: 'zod',
1515
output: 'zod',
16+
resolveConfig: (plugin, context) => {
17+
plugin.config.definitions = context.valueToObject({
18+
defaultValue: {
19+
case: 'camelCase',
20+
enabled: true,
21+
name: 'z{{name}}',
22+
},
23+
mappers: {
24+
boolean: (enabled) => ({ enabled }),
25+
string: (name) => ({ enabled: true, name }),
26+
},
27+
value: plugin.config.definitions,
28+
});
29+
30+
plugin.config.requests = context.valueToObject({
31+
defaultValue: {
32+
case: 'camelCase',
33+
enabled: true,
34+
name: 'z{{name}}Data',
35+
},
36+
mappers: {
37+
boolean: (enabled) => ({ enabled }),
38+
string: (name) => ({ enabled: true, name }),
39+
},
40+
value: plugin.config.requests,
41+
});
42+
43+
plugin.config.responses = context.valueToObject({
44+
defaultValue: {
45+
case: 'camelCase',
46+
enabled: true,
47+
name: 'z{{name}}Response',
48+
},
49+
mappers: {
50+
boolean: (enabled) => ({ enabled }),
51+
string: (name) => ({ enabled: true, name }),
52+
},
53+
value: plugin.config.responses,
54+
});
55+
},
1656
tags: ['validator'],
1757
};
1858

packages/openapi-ts/src/plugins/zod/plugin.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { numberRegExp } from '../../utils/regexp';
88
import { operationIrRef } from '../shared/utils/ref';
99
import { createSchemaComment } from '../shared/utils/schema';
1010
import type { Plugin } from '../types';
11-
import type { Config } from './types';
11+
import type { ResolvedConfig } from './types';
1212

1313
interface SchemaWithType<T extends Required<IR.SchemaObject>['type']>
1414
extends Omit<IR.SchemaObject, 'type'> {
@@ -50,7 +50,7 @@ const arrayTypeToZodSchema = ({
5050
schema,
5151
}: {
5252
context: IR.Context;
53-
plugin: Plugin.Instance<Config>;
53+
plugin: Plugin.Instance<ResolvedConfig>;
5454
result: Result;
5555
schema: SchemaWithType<'array'>;
5656
}): ts.CallExpression => {
@@ -389,7 +389,7 @@ const objectTypeToZodSchema = ({
389389
schema,
390390
}: {
391391
context: IR.Context;
392-
plugin: Plugin.Instance<Config>;
392+
plugin: Plugin.Instance<ResolvedConfig>;
393393
result: Result;
394394
schema: SchemaWithType<'object'>;
395395
}): {
@@ -614,7 +614,7 @@ const tupleTypeToZodSchema = ({
614614
schema,
615615
}: {
616616
context: IR.Context;
617-
plugin: Plugin.Instance<Config>;
617+
plugin: Plugin.Instance<ResolvedConfig>;
618618
result: Result;
619619
schema: SchemaWithType<'tuple'>;
620620
}) => {
@@ -724,7 +724,7 @@ const schemaTypeToZodSchema = ({
724724
schema,
725725
}: {
726726
context: IR.Context;
727-
plugin: Plugin.Instance<Config>;
727+
plugin: Plugin.Instance<ResolvedConfig>;
728728
result: Result;
729729
schema: IR.SchemaObject;
730730
}): {
@@ -832,7 +832,7 @@ const operationToZodSchema = ({
832832
}: {
833833
context: IR.Context;
834834
operation: IR.OperationObject;
835-
plugin: Plugin.Instance<Config>;
835+
plugin: Plugin.Instance<ResolvedConfig>;
836836
result: Result;
837837
}) => {
838838
if (operation.body) {
@@ -911,7 +911,7 @@ const schemaToZodSchema = ({
911911
* `.default()` which is handled in this function.
912912
*/
913913
optional?: boolean;
914-
plugin: Plugin.Instance<Config>;
914+
plugin: Plugin.Instance<ResolvedConfig>;
915915
result: Result;
916916
schema: IR.SchemaObject;
917917
}): ts.Expression => {
@@ -1145,7 +1145,7 @@ const schemaToZodSchema = ({
11451145
return expression!;
11461146
};
11471147

1148-
export const handler: Plugin.Handler<Config> = ({ plugin }) => {
1148+
export const handler: Plugin.Handler<ResolvedConfig> = ({ plugin }) => {
11491149
const file = plugin.createFile({
11501150
id: zodId,
11511151
identifierCase: 'camelCase',

0 commit comments

Comments
 (0)