Skip to content

Commit c34225f

Browse files
authored
Merge pull request #3548 from hey-api/feat/typescript-resolvers
feat: add more resolvers to typescript
2 parents 7b3771f + cea899b commit c34225f

File tree

12 files changed

+600
-50
lines changed

12 files changed

+600
-50
lines changed

packages/openapi-ts/src/plugins/@hey-api/typescript/resolvers.ts

Lines changed: 245 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
1-
import type { Plugin, SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared';
1+
import type { IR, Plugin, SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared';
22

33
import type { $, DollarTsDsl } from '../../../ts-dsl';
44
import type { Type, TypeScriptResult } from './shared/types';
55
import type { HeyApiTypeScriptPlugin } from './types';
66

77
export type Resolvers = Plugin.Resolvers<{
8+
/**
9+
* Resolver for array schemas.
10+
*
11+
* Allows customization of how array types are rendered.
12+
*
13+
* Returning `undefined` will execute the default resolver logic.
14+
*/
15+
array?: (ctx: ArrayResolverContext) => Type | undefined;
16+
/**
17+
* Resolver for boolean schemas.
18+
*
19+
* Allows customization of how boolean types are rendered.
20+
*
21+
* Returning `undefined` will execute the default resolver logic.
22+
*/
23+
boolean?: (ctx: BooleanResolverContext) => Type | undefined;
824
/**
925
* Resolver for enum schemas.
1026
*
@@ -13,6 +29,30 @@ export type Resolvers = Plugin.Resolvers<{
1329
* Returning `undefined` will execute the default resolver logic.
1430
*/
1531
enum?: (ctx: EnumResolverContext) => Type | undefined;
32+
/**
33+
* Resolver for intersection schemas.
34+
*
35+
* Allows customization of how intersection types are rendered.
36+
*
37+
* Returning `undefined` will execute the default resolver logic.
38+
*/
39+
intersection?: (ctx: IntersectionResolverContext) => Type | undefined;
40+
/**
41+
* Resolver for never schemas.
42+
*
43+
* Allows customization of how never types are rendered.
44+
*
45+
* Returning `undefined` will execute the default resolver logic.
46+
*/
47+
never?: (ctx: NeverResolverContext) => Type | undefined;
48+
/**
49+
* Resolver for null schemas.
50+
*
51+
* Allows customization of how null types are rendered.
52+
*
53+
* Returning `undefined` will execute the default resolver logic.
54+
*/
55+
null?: (ctx: NullResolverContext) => Type | undefined;
1656
/**
1757
* Resolver for number schemas.
1858
*
@@ -37,13 +77,85 @@ export type Resolvers = Plugin.Resolvers<{
3777
* Returning `undefined` will execute the default resolver logic.
3878
*/
3979
string?: (ctx: StringResolverContext) => Type | undefined;
80+
/**
81+
* Resolver for tuple schemas.
82+
*
83+
* Allows customization of how tuple types are rendered.
84+
*
85+
* Returning `undefined` will execute the default resolver logic.
86+
*/
87+
tuple?: (ctx: TupleResolverContext) => Type | undefined;
88+
/**
89+
* Resolver for undefined schemas.
90+
*
91+
* Allows customization of how undefined types are rendered.
92+
*
93+
* Returning `undefined` will execute the default resolver logic.
94+
*/
95+
undefined?: (ctx: UndefinedResolverContext) => Type | undefined;
96+
/**
97+
* Resolver for union schemas.
98+
*
99+
* Allows customization of how union types are rendered.
100+
*
101+
* Returning `undefined` will execute the default resolver logic.
102+
*/
103+
union?: (ctx: UnionResolverContext) => Type | undefined;
104+
/**
105+
* Resolver for unknown schemas.
106+
*
107+
* Allows customization of how unknown types are rendered.
108+
*
109+
* Returning `undefined` will execute the default resolver logic.
110+
*/
111+
unknown?: (ctx: UnknownResolverContext) => Type | undefined;
112+
/**
113+
* Resolver for void schemas.
114+
*
115+
* Allows customization of how void types are rendered.
116+
*
117+
* Returning `undefined` will execute the default resolver logic.
118+
*/
119+
void?: (ctx: VoidResolverContext) => Type | undefined;
40120
}>;
41121

42122
interface BaseContext extends DollarTsDsl {
43123
/** The plugin instance. */
44124
plugin: HeyApiTypeScriptPlugin['Instance'];
45125
}
46126

127+
export interface ArrayResolverContext extends BaseContext {
128+
/**
129+
* Nodes used to build different parts of the result.
130+
*/
131+
nodes: {
132+
/**
133+
* Returns the base array type expression.
134+
*/
135+
base: (ctx: ArrayResolverContext) => Type;
136+
};
137+
schema: SchemaWithType<'array'>;
138+
walk: Walker<TypeScriptResult, HeyApiTypeScriptPlugin['Instance']>;
139+
walkerCtx: SchemaVisitorContext<HeyApiTypeScriptPlugin['Instance']>;
140+
}
141+
142+
export interface BooleanResolverContext extends BaseContext {
143+
/**
144+
* Nodes used to build different parts of the result.
145+
*/
146+
nodes: {
147+
/**
148+
* Returns the base boolean type expression.
149+
*/
150+
base: (ctx: BooleanResolverContext) => Type;
151+
/**
152+
* Returns the literal type for const values.
153+
*/
154+
const: (ctx: BooleanResolverContext) => Type | undefined;
155+
};
156+
schema: SchemaWithType<'boolean'>;
157+
}
158+
47159
export interface EnumResolverContext extends BaseContext {
48160
/**
49161
* Nodes used to build different parts of the result.
@@ -70,6 +182,56 @@ export interface EnumResolverContext extends BaseContext {
70182
schema: SchemaWithType<'enum'>;
71183
}
72184

185+
export interface IntersectionResolverContext extends BaseContext {
186+
/**
187+
* The child results from walking intersection members.
188+
*/
189+
childResults: ReadonlyArray<TypeScriptResult>;
190+
/**
191+
* Nodes used to build different parts of the result.
192+
*/
193+
nodes: {
194+
/**
195+
* Returns the base intersection type expression.
196+
*/
197+
base: (ctx: IntersectionResolverContext) => Type;
198+
};
199+
/**
200+
* The parent schema containing the intersection.
201+
*/
202+
parentSchema: IR.SchemaObject;
203+
/**
204+
* The individual schemas being intersected.
205+
*/
206+
schemas: ReadonlyArray<IR.SchemaObject>;
207+
}
208+
209+
export interface NeverResolverContext extends BaseContext {
210+
/**
211+
* Nodes used to build different parts of the result.
212+
*/
213+
nodes: {
214+
/**
215+
* Returns the base never type expression.
216+
*/
217+
base: (ctx: NeverResolverContext) => Type;
218+
};
219+
schema: SchemaWithType<'never'>;
220+
}
221+
222+
export interface NullResolverContext extends BaseContext {
223+
/**
224+
* Nodes used to build different parts of the result.
225+
*/
226+
nodes: {
227+
/**
228+
* Returns the base null type expression.
229+
*/
230+
base: (ctx: NullResolverContext) => Type;
231+
};
232+
schema: SchemaWithType<'null'>;
233+
}
234+
73235
export interface NumberResolverContext extends BaseContext {
74236
/**
75237
* Nodes used to build different parts of the result.
@@ -126,3 +288,85 @@ export interface StringResolverContext extends BaseContext {
126288
};
127289
schema: SchemaWithType<'string'>;
128290
}
291+
292+
export interface TupleResolverContext extends BaseContext {
293+
/**
294+
* Nodes used to build different parts of the result.
295+
*/
296+
nodes: {
297+
/**
298+
* Returns the base tuple type expression.
299+
*/
300+
base: (ctx: TupleResolverContext) => Type;
301+
/**
302+
* Returns the literal type for const tuple values.
303+
*/
304+
const: (ctx: TupleResolverContext) => Type | undefined;
305+
};
306+
schema: SchemaWithType<'tuple'>;
307+
walk: Walker<TypeScriptResult, HeyApiTypeScriptPlugin['Instance']>;
308+
walkerCtx: SchemaVisitorContext<HeyApiTypeScriptPlugin['Instance']>;
309+
}
310+
311+
export interface UnionResolverContext extends BaseContext {
312+
/**
313+
* The child results from walking union members.
314+
*/
315+
childResults: ReadonlyArray<TypeScriptResult>;
316+
/**
317+
* Nodes used to build different parts of the result.
318+
*/
319+
nodes: {
320+
/**
321+
* Returns the base union type expression.
322+
*/
323+
base: (ctx: UnionResolverContext) => Type;
324+
};
325+
/**
326+
* The parent schema containing the union.
327+
*/
328+
parentSchema: IR.SchemaObject;
329+
/**
330+
* The individual schemas being unioned.
331+
*/
332+
schemas: ReadonlyArray<IR.SchemaObject>;
333+
}
334+
335+
export interface UndefinedResolverContext extends BaseContext {
336+
/**
337+
* Nodes used to build different parts of the result.
338+
*/
339+
nodes: {
340+
/**
341+
* Returns the base undefined type expression.
342+
*/
343+
base: (ctx: UndefinedResolverContext) => Type;
344+
};
345+
schema: SchemaWithType<'undefined'>;
346+
}
347+
348+
export interface UnknownResolverContext extends BaseContext {
349+
/**
350+
* Nodes used to build different parts of the result.
351+
*/
352+
nodes: {
353+
/**
354+
* Returns the base unknown type expression.
355+
*/
356+
base: (ctx: UnknownResolverContext) => Type;
357+
};
358+
schema: SchemaWithType<'unknown'>;
359+
}
360+
361+
export interface VoidResolverContext extends BaseContext {
362+
/**
363+
* Nodes used to build different parts of the result.
364+
*/
365+
nodes: {
366+
/**
367+
* Returns the base void type expression.
368+
*/
369+
base: (ctx: VoidResolverContext) => Type;
370+
};
371+
schema: SchemaWithType<'void'>;
372+
}

packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/array.ts

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
import { ref } from '@hey-api/codegen-core';
2-
import type { SchemaWithType } from '@hey-api/shared';
3-
import type { Walker } from '@hey-api/shared';
2+
import type { SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared';
43
import { deduplicateSchema } from '@hey-api/shared';
54

65
import { $ } from '../../../../../ts-dsl';
7-
import type { Type } from '../../shared/types';
8-
import type { TypeScriptResult } from '../../shared/types';
6+
import type { ArrayResolverContext } from '../../resolvers';
7+
import type { Type, TypeScriptResult } from '../../shared/types';
98
import type { HeyApiTypeScriptPlugin } from '../../types';
109

11-
export function arrayToAst({
12-
plugin,
13-
schema,
14-
walk,
15-
}: {
16-
plugin: HeyApiTypeScriptPlugin['Instance'];
17-
schema: SchemaWithType<'array'>;
18-
walk: Walker<TypeScriptResult, HeyApiTypeScriptPlugin['Instance']>;
19-
}): Type {
10+
function baseNode(ctx: ArrayResolverContext): Type {
11+
const { plugin, schema, walk } = ctx;
12+
2013
if (!schema.items) {
2114
return $.type('Array').generic($.type(plugin.config.topType));
2215
}
@@ -40,3 +33,34 @@ export function arrayToAst({
4033
? $.type('Array').generic($.type.and(...itemResults.map((r) => r.type)))
4134
: $.type('Array').generic($.type.or(...itemResults.map((r) => r.type)));
4235
}
36+
37+
function arrayResolver(ctx: ArrayResolverContext): Type {
38+
return ctx.nodes.base(ctx);
39+
}
40+
41+
export function arrayToAst({
42+
plugin,
43+
schema,
44+
walk,
45+
walkerCtx,
46+
}: {
47+
plugin: HeyApiTypeScriptPlugin['Instance'];
48+
schema: SchemaWithType<'array'>;
49+
walk: Walker<TypeScriptResult, HeyApiTypeScriptPlugin['Instance']>;
50+
walkerCtx: SchemaVisitorContext<HeyApiTypeScriptPlugin['Instance']>;
51+
}): Type {
52+
const ctx: ArrayResolverContext = {
53+
$,
54+
nodes: {
55+
base: baseNode,
56+
},
57+
plugin,
58+
schema,
59+
walk,
60+
walkerCtx,
61+
};
62+
63+
const resolver = plugin.config['~resolvers']?.array;
64+
const result = resolver?.(ctx);
65+
return result ?? arrayResolver(ctx);
66+
}

0 commit comments

Comments
 (0)