Skip to content

Commit d7f08be

Browse files
committed
feat(plugin): add api field
1 parent c123f05 commit d7f08be

File tree

10 files changed

+220
-142
lines changed

10 files changed

+220
-142
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ export default defineConfig(() => {
128128
// transformer: '@hey-api/transformers',
129129
transformer: true,
130130
validator: {
131-
request: 'valibot',
132-
response: 'zod',
131+
request: 'zod',
132+
response: 'valibot',
133133
},
134134
},
135135
{

packages/openapi-ts/src/plugins/@hey-api/sdk/validator.ts

Lines changed: 4 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,132 +1,8 @@
1-
import { compiler } from '../../../compiler';
21
import type { IR } from '../../../ir/types';
32
import type { Plugin } from '../../types';
4-
import { valibotId } from '../../valibot/constants';
5-
import { zodId } from '../../zod/plugin';
63
import { sdkId } from './constants';
74
import type { HeyApiSdkPlugin } from './types';
85

9-
const identifiers = {
10-
data: compiler.identifier({ text: 'data' }),
11-
parseAsync: compiler.identifier({ text: 'parseAsync' }),
12-
v: compiler.identifier({ text: 'v' }),
13-
};
14-
15-
const valibotResponseValidator = ({
16-
operation,
17-
plugin,
18-
}: {
19-
operation: IR.OperationObject;
20-
plugin: Plugin.Instance<HeyApiSdkPlugin>;
21-
}) => {
22-
const file = plugin.context.file({ id: sdkId })!;
23-
24-
const responses = plugin.getPlugin('valibot')?.config.responses;
25-
const identifierSchema = plugin.context.file({ id: valibotId })!.identifier({
26-
// TODO: refactor for better cross-plugin compatibility
27-
$ref: `#/valibot-response/${operation.id}`,
28-
// TODO: refactor to not have to define nameTransformer
29-
nameTransformer: typeof responses === 'object' ? responses.name : undefined,
30-
namespace: 'value',
31-
});
32-
33-
if (!identifierSchema.name) {
34-
return;
35-
}
36-
37-
file.import({
38-
module: file.relativePathToFile({
39-
context: plugin.context,
40-
id: valibotId,
41-
}),
42-
name: identifierSchema.name,
43-
});
44-
45-
file.import({
46-
alias: identifiers.v.text,
47-
module: 'valibot',
48-
name: '*',
49-
});
50-
51-
return compiler.arrowFunction({
52-
async: true,
53-
parameters: [
54-
{
55-
name: 'data',
56-
},
57-
],
58-
statements: [
59-
compiler.returnStatement({
60-
expression: compiler.awaitExpression({
61-
expression: compiler.callExpression({
62-
functionName: compiler.propertyAccessExpression({
63-
expression: identifiers.v,
64-
name: identifiers.parseAsync,
65-
}),
66-
parameters: [
67-
compiler.identifier({ text: identifierSchema.name }),
68-
identifiers.data,
69-
],
70-
}),
71-
}),
72-
}),
73-
],
74-
});
75-
};
76-
77-
const zodResponseValidator = ({
78-
operation,
79-
plugin,
80-
}: {
81-
operation: IR.OperationObject;
82-
plugin: Plugin.Instance<HeyApiSdkPlugin>;
83-
}) => {
84-
const file = plugin.context.file({ id: sdkId })!;
85-
86-
const responses = plugin.getPlugin('zod')?.config.responses;
87-
const identifierSchema = plugin.context.file({ id: zodId })!.identifier({
88-
// TODO: refactor for better cross-plugin compatibility
89-
$ref: `#/zod-response/${operation.id}`,
90-
// TODO: refactor to not have to define nameTransformer
91-
nameTransformer: typeof responses === 'object' ? responses.name : undefined,
92-
namespace: 'value',
93-
});
94-
95-
if (!identifierSchema.name) {
96-
return;
97-
}
98-
99-
file.import({
100-
module: file.relativePathToFile({
101-
context: plugin.context,
102-
id: zodId,
103-
}),
104-
name: identifierSchema.name,
105-
});
106-
107-
return compiler.arrowFunction({
108-
async: true,
109-
parameters: [
110-
{
111-
name: 'data',
112-
},
113-
],
114-
statements: [
115-
compiler.returnStatement({
116-
expression: compiler.awaitExpression({
117-
expression: compiler.callExpression({
118-
functionName: compiler.propertyAccessExpression({
119-
expression: compiler.identifier({ text: identifierSchema.name }),
120-
name: identifiers.parseAsync,
121-
}),
122-
parameters: [identifiers.data],
123-
}),
124-
}),
125-
}),
126-
],
127-
});
128-
};
129-
1306
export const createResponseValidator = ({
1317
operation,
1328
plugin,
@@ -143,15 +19,13 @@ export const createResponseValidator = ({
14319
return;
14420
}
14521

146-
if (pluginValidator.name === 'zod') {
147-
console.log(pluginValidator.api?.foo());
148-
}
22+
const file = plugin.context.file({ id: sdkId })!;
14923

150-
switch (plugin.config.validator.response) {
24+
switch (pluginValidator.name) {
15125
case 'valibot':
152-
return valibotResponseValidator({ operation, plugin });
26+
return pluginValidator.api.createResponseValidator({ file, operation, plugin: pluginValidator });
15327
case 'zod':
154-
return zodResponseValidator({ operation, plugin });
28+
return pluginValidator.api.createResponseValidator({ file, operation, plugin: pluginValidator });
15529
default:
15630
return;
15731
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import type ts from "typescript";
2+
3+
import { compiler } from "../../compiler";
4+
import type { TypeScriptFile } from "../../generate/files";
5+
import type { IR } from "../../ir/types";
6+
import type { PluginInstance } from "../shared/utils/instance";
7+
import { identifiers, valibotId } from "./constants";
8+
import type { ValibotPlugin } from "./types";
9+
10+
const createResponseValidator = ({
11+
file,
12+
operation,
13+
plugin,
14+
}: {
15+
file: TypeScriptFile;
16+
operation: IR.OperationObject;
17+
plugin: PluginInstance<ValibotPlugin>;
18+
}): ts.ArrowFunction | undefined => {
19+
const responses = plugin.getPlugin('valibot')?.config.responses;
20+
const identifierSchema = plugin.context.file({ id: valibotId })!.identifier({
21+
// TODO: refactor for better cross-plugin compatibility
22+
$ref: `#/valibot-response/${operation.id}`,
23+
// TODO: refactor to not have to define nameTransformer
24+
nameTransformer: typeof responses === 'object' ? responses.name : undefined,
25+
namespace: 'value',
26+
});
27+
28+
if (!identifierSchema.name) {
29+
return;
30+
}
31+
32+
file.import({
33+
module: file.relativePathToFile({
34+
context: plugin.context,
35+
id: valibotId,
36+
}),
37+
name: identifierSchema.name,
38+
});
39+
40+
file.import({
41+
alias: identifiers.v.text,
42+
module: 'valibot',
43+
name: '*',
44+
});
45+
46+
const dataParameterName = 'data';
47+
48+
return compiler.arrowFunction({
49+
async: true,
50+
parameters: [
51+
{
52+
name: dataParameterName,
53+
},
54+
],
55+
statements: [
56+
compiler.returnStatement({
57+
expression: compiler.awaitExpression({
58+
expression: compiler.callExpression({
59+
functionName: compiler.propertyAccessExpression({
60+
expression: identifiers.v,
61+
name: identifiers.async.parseAsync,
62+
}),
63+
parameters: [
64+
compiler.identifier({ text: identifierSchema.name }),
65+
compiler.identifier({ text: dataParameterName }),
66+
],
67+
}),
68+
}),
69+
}),
70+
],
71+
});
72+
}
73+
74+
export type Api = {
75+
createResponseValidator: (args: {
76+
file: TypeScriptFile;
77+
operation: IR.OperationObject;
78+
plugin: PluginInstance<ValibotPlugin>;
79+
}) => ts.ArrowFunction | undefined;
80+
};
81+
82+
export const api: Api = {
83+
createResponseValidator,
84+
};

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { definePluginConfig } from '../shared/utils/config';
22
import type { Plugin } from '../types';
3+
import { api } from './api';
34
import { handler } from './plugin';
45
import type { ValibotPlugin } from './types';
56

67
export const defaultConfig: Plugin.Config<ValibotPlugin> = {
8+
api,
79
config: {
810
case: 'camelCase',
911
comments: true,

packages/openapi-ts/src/plugins/valibot/constants.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,51 @@ export const identifiers = {
116116
* {@link https://valibot.dev/api/#async Async}
117117
*/
118118
async: {
119-
// TODO: implement if necessary
119+
argsAsync: compiler.identifier({ text: 'argsAsync' }),
120+
arrayAsync: compiler.identifier({ text: 'arrayAsync' }),
121+
awaitAsync: compiler.identifier({ text: 'awaitAsync' }),
122+
checkAsync: compiler.identifier({ text: 'checkAsync' }),
123+
checkItemsAsync: compiler.identifier({ text: 'checkItemsAsync' }),
124+
customAsync: compiler.identifier({ text: 'customAsync' }),
125+
exactOptionalAsync: compiler.identifier({ text: 'exactOptionalAsync' }),
126+
fallbackAsync: compiler.identifier({ text: 'fallbackAsync' }),
127+
forwardAsync: compiler.identifier({ text: 'forwardAsync' }),
128+
getDefaultsAsync: compiler.identifier({ text: 'getDefaultsAsync' }),
129+
getFallbacksAsync: compiler.identifier({ text: 'getFallbacksAsync' }),
130+
intersectAsync: compiler.identifier({ text: 'intersectAsync' }),
131+
lazyAsync: compiler.identifier({ text: 'lazyAsync' }),
132+
looseObjectAsync: compiler.identifier({ text: 'looseObjectAsync' }),
133+
looseTupleAsync: compiler.identifier({ text: 'looseTupleAsync' }),
134+
mapAsync: compiler.identifier({ text: 'mapAsync' }),
135+
nonNullableAsync: compiler.identifier({ text: 'nonNullableAsync' }),
136+
nonNullishAsync: compiler.identifier({ text: 'nonNullishAsync' }),
137+
nonOptionalAsync: compiler.identifier({ text: 'nonOptionalAsync' }),
138+
nullableAsync: compiler.identifier({ text: 'nullableAsync' }),
139+
nullishAsync: compiler.identifier({ text: 'nullishAsync' }),
140+
objectAsync: compiler.identifier({ text: 'objectAsync' }),
141+
objectWithRestAsync: compiler.identifier({ text: 'objectWithRestAsync' }),
142+
optionalAsync: compiler.identifier({ text: 'optionalAsync' }),
143+
parseAsync: compiler.identifier({ text: 'parseAsync' }),
144+
parserAsync: compiler.identifier({ text: 'parserAsync' }),
145+
partialAsync: compiler.identifier({ text: 'partialAsync' }),
146+
partialCheckAsync: compiler.identifier({ text: 'partialCheckAsync' }),
147+
pipeAsync: compiler.identifier({ text: 'pipeAsync' }),
148+
rawCheckAsync: compiler.identifier({ text: 'rawCheckAsync' }),
149+
rawTransformAsync: compiler.identifier({ text: 'rawTransformAsync' }),
150+
recordAsync: compiler.identifier({ text: 'recordAsync' }),
151+
requiredAsync: compiler.identifier({ text: 'requiredAsync' }),
152+
returnsAsync: compiler.identifier({ text: 'returnsAsync' }),
153+
safeParseAsync: compiler.identifier({ text: 'safeParseAsync' }),
154+
safeParserAsync: compiler.identifier({ text: 'safeParserAsync' }),
155+
setAsync: compiler.identifier({ text: 'setAsync' }),
156+
strictObjectAsync: compiler.identifier({ text: 'strictObjectAsync' }),
157+
strictTupleAsync: compiler.identifier({ text: 'strictTupleAsync' }),
158+
transformAsync: compiler.identifier({ text: 'transformAsync' }),
159+
tupleAsync: compiler.identifier({ text: 'tupleAsync' }),
160+
tupleWithRestAsync: compiler.identifier({ text: 'tupleWithRestAsync' }),
161+
undefinedableAsync: compiler.identifier({ text: 'undefinedableAsync' }),
162+
unionAsync: compiler.identifier({ text: 'unionAsync' }),
163+
variantAsync: compiler.identifier({ text: 'variantAsync' }),
120164
},
121165
/**
122166
* {@link https://valibot.dev/api/#methods Methods}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { StringCase } from '../../types/case';
22
import type { Plugin } from '../types';
3+
import type { Api } from './api';
34

45
export type Config = Plugin.Name<'valibot'> & {
56
/**
@@ -253,4 +254,4 @@ export type ResolvedConfig = Plugin.Name<'valibot'> & {
253254
};
254255
};
255256

256-
export type ValibotPlugin = Plugin.Types<Config, ResolvedConfig>;
257+
export type ValibotPlugin = Plugin.Types<Config, ResolvedConfig, Api>;

0 commit comments

Comments
 (0)