Skip to content

Commit 9715d53

Browse files
committed
refactor: valibot plugin internals
1 parent 3a46263 commit 9715d53

25 files changed

Lines changed: 642 additions & 678 deletions

File tree

packages/openapi-ts/src/plugins/valibot/resolvers/types.ts renamed to packages/openapi-ts/src/plugins/valibot/resolvers.ts

Lines changed: 51 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { Refs, Symbol } from '@hey-api/codegen-core';
1+
import type { Symbol } from '@hey-api/codegen-core';
22
import type { IR, Plugin, SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared';
33

4-
import type { MaybeBigInt, ShouldCoerceToBigInt } from '../../../plugins/shared/utils/coerce';
5-
import type { GetIntegerLimit } from '../../../plugins/shared/utils/formats';
6-
import type { $, DollarTsDsl } from '../../../ts-dsl';
7-
import type { Pipe, PipeResult, Pipes, PipesUtils } from '../shared/pipes';
8-
import type { Ast, IrSchemaToAstOptions, PluginState, ValibotSchemaResult } from '../shared/types';
9-
import type { ValibotPlugin } from '../types';
4+
import type { MaybeBigInt, ShouldCoerceToBigInt } from '../../plugins/shared/utils/coerce';
5+
import type { GetIntegerLimit } from '../../plugins/shared/utils/formats';
6+
import type { $, DollarTsDsl } from '../../ts-dsl';
7+
import type { Pipe, PipeResult, Pipes, PipesUtils } from './shared/pipes';
8+
import type { ValibotFinal, ValibotResult } from './shared/types';
9+
import type { ValibotPlugin } from './types';
1010

1111
export type Resolvers = Plugin.Resolvers<{
1212
/**
@@ -16,31 +16,31 @@ export type Resolvers = Plugin.Resolvers<{
1616
*
1717
* Returning `undefined` will execute the default resolver logic.
1818
*/
19-
enum?: (ctx: EnumResolverContext) => PipeResult | undefined;
19+
enum?: (ctx: EnumResolverContext) => PipeResult;
2020
/**
2121
* Resolver for number schemas.
2222
*
2323
* Allows customization of how number types are rendered.
2424
*
2525
* Returning `undefined` will execute the default resolver logic.
2626
*/
27-
number?: (ctx: NumberResolverContext) => PipeResult | undefined;
27+
number?: (ctx: NumberResolverContext) => PipeResult;
2828
/**
2929
* Resolver for object schemas.
3030
*
3131
* Allows customization of how object types are rendered.
3232
*
3333
* Returning `undefined` will execute the default resolver logic.
3434
*/
35-
object?: (ctx: ObjectResolverContext) => PipeResult | undefined;
35+
object?: (ctx: ObjectResolverContext) => PipeResult;
3636
/**
3737
* Resolver for string schemas.
3838
*
3939
* Allows customization of how string types are rendered.
4040
*
4141
* Returning `undefined` will execute the default resolver logic.
4242
*/
43-
string?: (ctx: StringResolverContext) => PipeResult | undefined;
43+
string?: (ctx: StringResolverContext) => PipeResult;
4444
/**
4545
* Resolvers for request and response validators.
4646
*
@@ -70,34 +70,35 @@ export type Resolvers = Plugin.Resolvers<{
7070

7171
type ValidatorResolver = (ctx: ValidatorResolverContext) => PipeResult | null | undefined;
7272

73-
type BaseContext = DollarTsDsl &
74-
Pick<IrSchemaToAstOptions, 'plugin'> & {
75-
/**
76-
* Functions for working with pipes.
77-
*/
78-
pipes: PipesUtils & {
79-
/**
80-
* The current pipe.
81-
*
82-
* In Valibot, this represents a list of call expressions ("pipes")
83-
* being assembled to form a schema definition.
84-
*
85-
* Each pipe can be extended, modified, or replaced to customize
86-
* the resulting schema.
87-
*/
88-
current: Pipes;
89-
};
73+
interface BaseContext extends DollarTsDsl {
74+
/**
75+
* Functions for working with pipes.
76+
*/
77+
pipes: PipesUtils & {
9078
/**
91-
* Provides access to commonly used symbols within the plugin.
79+
* The current pipe.
80+
*
81+
* In Valibot, this represents a list of call expressions ("pipes")
82+
* being assembled to form a schema definition.
83+
*
84+
* Each pipe can be extended, modified, or replaced to customize
85+
* the resulting schema.
9286
*/
93-
symbols: {
94-
v: Symbol;
95-
};
87+
current: Pipes;
9688
};
89+
/** The plugin instance. */
90+
plugin: ValibotPlugin['Instance'];
91+
/**
92+
* Provides access to commonly used symbols within the plugin.
93+
*/
94+
symbols: {
95+
v: Symbol;
96+
};
97+
}
9798

9899
export interface EnumResolverContext extends BaseContext {
99100
/**
100-
* Nodes used to build different parts of the enum schema.
101+
* Nodes used to build different parts of the schema.
101102
*/
102103
nodes: {
103104
/**
@@ -119,23 +120,17 @@ export interface EnumResolverContext extends BaseContext {
119120
};
120121
};
121122
schema: SchemaWithType<'enum'>;
122-
/**
123-
* Utility functions for enum schema processing.
124-
*/
125-
utils: {
126-
state: Refs<PluginState>;
127-
};
128123
}
129124

130125
export interface NumberResolverContext extends BaseContext {
131126
/**
132-
* Nodes used to build different parts of the number schema.
127+
* Nodes used to build different parts of the schema.
133128
*/
134129
nodes: {
135130
base: (ctx: NumberResolverContext) => PipeResult;
136-
const: (ctx: NumberResolverContext) => PipeResult | undefined;
137-
max: (ctx: NumberResolverContext) => PipeResult | undefined;
138-
min: (ctx: NumberResolverContext) => PipeResult | undefined;
131+
const: (ctx: NumberResolverContext) => PipeResult;
132+
max: (ctx: NumberResolverContext) => PipeResult;
133+
min: (ctx: NumberResolverContext) => PipeResult;
139134
};
140135
schema: SchemaWithType<'integer' | 'number'>;
141136
/**
@@ -149,43 +144,39 @@ export interface NumberResolverContext extends BaseContext {
149144
}
150145

151146
export interface ObjectResolverContext extends BaseContext {
152-
applyModifiers: (result: ValibotSchemaResult, opts: { optional?: boolean }) => Ast;
147+
_childResults: Array<ValibotResult>;
148+
applyModifiers: (result: ValibotResult, opts: { optional?: boolean }) => ValibotFinal;
153149
/**
154-
* Nodes used to build different parts of the object schema.
150+
* Nodes used to build different parts of the schema.
155151
*/
156152
nodes: {
157-
/**
158-
* If `additionalProperties` is `false` or `{ type: 'never' }`, returns `null`
159-
* to indicate no additional properties are allowed.
160-
*/
161153
additionalProperties: (ctx: ObjectResolverContext) => Pipe | null | undefined;
162-
base: (ctx: ObjectResolverContext) => PipeResult;
154+
base: (ctx: ObjectResolverContext) => Pipes | Pipe;
163155
shape: (ctx: ObjectResolverContext) => ReturnType<typeof $.object>;
164156
};
165157
schema: SchemaWithType<'object'>;
166158
/**
167159
* Utility functions for object schema processing.
168160
*/
169161
utils: {
170-
ast: Partial<Omit<Ast, 'typeName'>>;
171-
state: Refs<PluginState>;
162+
ast: Partial<{ hasLazy: boolean }>;
172163
};
173-
walk: Walker<ValibotSchemaResult, ValibotPlugin['Instance']>;
164+
walk: Walker<ValibotResult, ValibotPlugin['Instance']>;
174165
walkerCtx: SchemaVisitorContext<ValibotPlugin['Instance']>;
175166
}
176167

177168
export interface StringResolverContext extends BaseContext {
178169
/**
179-
* Nodes used to build different parts of the string schema.
170+
* Nodes used to build different parts of the schema.
180171
*/
181172
nodes: {
182173
base: (ctx: StringResolverContext) => PipeResult;
183-
const: (ctx: StringResolverContext) => PipeResult | undefined;
184-
format: (ctx: StringResolverContext) => PipeResult | undefined;
185-
length: (ctx: StringResolverContext) => PipeResult | undefined;
186-
maxLength: (ctx: StringResolverContext) => PipeResult | undefined;
187-
minLength: (ctx: StringResolverContext) => PipeResult | undefined;
188-
pattern: (ctx: StringResolverContext) => PipeResult | undefined;
174+
const: (ctx: StringResolverContext) => PipeResult;
175+
format: (ctx: StringResolverContext) => PipeResult;
176+
length: (ctx: StringResolverContext) => PipeResult;
177+
maxLength: (ctx: StringResolverContext) => PipeResult;
178+
minLength: (ctx: StringResolverContext) => PipeResult;
179+
pattern: (ctx: StringResolverContext) => PipeResult;
189180
};
190181
schema: SchemaWithType<'string'>;
191182
}

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

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/openapi-ts/src/plugins/valibot/shared/export.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,24 @@ import { applyNaming, pathToName } from '@hey-api/shared';
22

33
import { createSchemaComment } from '../../../plugins/shared/utils/schema';
44
import { $ } from '../../../ts-dsl';
5-
import { identifiers } from '../v1/constants';
5+
import type { ValibotPlugin } from '../types';
66
import { pipesToNode } from './pipes';
77
import type { ProcessorContext } from './processor';
8-
import type { Ast, IrSchemaToAstOptions } from './types';
8+
import type { ValibotFinal } from './types';
99

1010
export function exportAst({
11-
ast,
11+
final,
1212
meta,
1313
naming,
1414
namingAnchor,
1515
path,
1616
plugin,
1717
schema,
18-
state,
1918
tags,
20-
}: Pick<IrSchemaToAstOptions, 'state'> &
21-
ProcessorContext & {
22-
ast: Ast;
23-
}): void {
19+
}: ProcessorContext & {
20+
final: ValibotFinal;
21+
plugin: ValibotPlugin['Instance'];
22+
}): void {
2423
const v = plugin.external('valibot.v');
2524

2625
const name = pathToName(path, { anchor: namingAnchor });
@@ -37,9 +36,8 @@ export function exportAst({
3736
const statement = $.const(symbol)
3837
.export()
3938
.$if(plugin.config.comments && createSchemaComment(schema), (c, v) => c.doc(v))
40-
.$if(state.hasLazyExpression['~ref'], (c) =>
41-
c.type($.type(v).attr(ast.typeName || identifiers.types.GenericSchema)),
42-
)
43-
.assign(pipesToNode(ast.pipes, plugin));
39+
.$if(final.typeName, (c) => c.type($.type(v).attr(final.typeName!)))
40+
.assign(pipesToNode(final.pipes, plugin));
41+
4442
plugin.node(statement);
4543
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import type { IR } from '@hey-api/shared';
2+
3+
import type { ValibotMeta, ValibotResult } from './types';
4+
5+
/**
6+
* Creates default metadata from a schema.
7+
*/
8+
export function defaultMeta(schema: IR.SchemaObject): ValibotMeta {
9+
return {
10+
default: schema.default,
11+
format: schema.format,
12+
hasLazy: false,
13+
nullable: false,
14+
readonly: schema.accessScope === 'read',
15+
};
16+
}
17+
18+
/**
19+
* Composes metadata from child results.
20+
*
21+
* Automatically propagates hasLazy, nullable, readonly from children.
22+
*
23+
* @param children - Results from walking child schemas
24+
* @param overrides - Explicit overrides (e.g., from parent schema)
25+
*/
26+
export function composeMeta(
27+
children: ReadonlyArray<ValibotResult>,
28+
overrides?: Partial<ValibotMeta>,
29+
): ValibotMeta {
30+
const hasLazy = overrides?.hasLazy ?? children.some((c) => c.meta.hasLazy);
31+
const nullable = overrides?.nullable ?? children.some((c) => c.meta.nullable);
32+
const readonly = overrides?.readonly ?? children.some((c) => c.meta.readonly);
33+
34+
return {
35+
default: overrides?.default,
36+
format: overrides?.format,
37+
hasLazy,
38+
nullable,
39+
readonly,
40+
};
41+
}
42+
43+
/**
44+
* Merges parent schema metadata with composed child metadata.
45+
*
46+
* @param parent - The parent schema
47+
* @param children - Results from walking child schemas
48+
*/
49+
export function inheritMeta(
50+
parent: IR.SchemaObject,
51+
children: ReadonlyArray<ValibotResult>,
52+
): ValibotMeta {
53+
return composeMeta(children, {
54+
default: parent.default,
55+
format: parent.format,
56+
nullable: false,
57+
readonly: parent.accessScope === 'read',
58+
});
59+
}

packages/openapi-ts/src/plugins/valibot/shared/operation.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,17 @@ import { operationResponsesMap } from '@hey-api/shared';
33

44
import { buildOperationSchema } from './operation-schema';
55
import type { ProcessorContext, ProcessorResult } from './processor';
6-
import type { IrSchemaToAstOptions } from './types';
76

87
export function irOperationToAst({
98
operation,
109
path,
1110
plugin,
1211
processor,
1312
tags,
14-
}: Pick<IrSchemaToAstOptions, 'plugin'> &
15-
Pick<ProcessorContext, 'path' | 'tags'> & {
16-
operation: IR.OperationObject;
17-
processor: ProcessorResult;
18-
}): void {
13+
}: Pick<ProcessorContext, 'path' | 'plugin' | 'tags'> & {
14+
operation: IR.OperationObject;
15+
processor: ProcessorResult;
16+
}): void {
1917
if (plugin.config.requests.enabled) {
2018
const { schema } = buildOperationSchema(operation);
2119

0 commit comments

Comments
 (0)