+28
-22
dev/openapi-ts.config.ts
+28
-22
dev/openapi-ts.config.ts
···
431
},
432
},
433
'~resolvers': {
434
-
number: {
435
-
// base({ $, pipes, v }) {
436
-
// return pipes.push($(v).attr('test').call());
437
-
// },
438
-
formats: {
439
-
// date: ({ $, pipes }) => pipes.push($('v').attr('isoDateTime').call()),
440
-
// 'date-time': ({ $, pipes }) => pipes.push($('v').attr('isoDateTime').call()),
441
-
},
442
-
},
443
-
object: {
444
-
// base({ $, additional, pipes, shape }) {
445
-
// if (additional === undefined) {
446
-
// return pipes.push($('v').attr('looseObject').call(shape));
447
-
// }
448
-
// return;
449
-
// },
450
-
},
451
-
string: {
452
-
formats: {
453
-
// date: ({ $, pipes }) => pipes.push($('v').attr('isoDateTime').call()),
454
-
// 'date-time': ({ $, pipes }) => pipes.push($('v').attr('isoDateTime').call()),
455
-
},
456
},
457
// validator({ $, plugin, schema, v }) {
458
// const vShadow = plugin.symbol('v');
459
// const test = plugin.symbol('test');
···
431
},
432
},
433
'~resolvers': {
434
+
number(ctx) {
435
+
const { $, plugin } = ctx;
436
+
const { v } = ctx.symbols;
437
+
const big = plugin.symbolOnce('Big', {
438
+
external: 'big.js',
439
+
importKind: 'default',
440
+
meta: {
441
+
category: 'external',
442
+
resource: 'big.js',
443
+
},
444
+
});
445
+
return $(v).attr('instance').call(big);
446
},
447
+
// object(ctx) {
448
+
// const { $ } = ctx;
449
+
// const additional = ctx.nodes.additionalProperties(ctx);
450
+
// const shape = ctx.nodes.shape(ctx);
451
+
// if (additional === undefined) {
452
+
// return $('v').attr('looseObject').call(shape);
453
+
// }
454
+
// return;
455
+
// },
456
+
// string(ctx) {
457
+
// const { $, schema } = ctx;
458
+
// if (schema.format === 'date' || schema.format === 'date-time') {
459
+
// ctx.nodes.format = () => $('v').attr('isoDateTime').call();
460
+
// }
461
+
// return;
462
+
// },
463
// validator({ $, plugin, schema, v }) {
464
// const vShadow = plugin.symbol('v');
465
// const test = plugin.symbol('test');
+92
-78
packages/openapi-ts/src/plugins/valibot/types.d.ts
+92
-78
packages/openapi-ts/src/plugins/valibot/types.d.ts
···
1
-
import type { Symbol } from '@hey-api/codegen-core';
2
import type ts from 'typescript';
3
4
import type { IR } from '~/ir/types';
5
-
import type { DefinePlugin, Plugin } from '~/plugins';
6
import type { $, DollarTsDsl, TsDsl } from '~/ts-dsl';
7
import type { StringCase, StringName } from '~/types/case';
8
import type { MaybeArray } from '~/types/utils';
9
10
import type { IApi } from './api';
11
12
export type UserConfig = Plugin.Name<'valibot'> &
13
Plugin.Hooks &
···
323
324
type SharedResolverArgs = DollarTsDsl & {
325
/**
326
* The current builder state being processed by this resolver.
327
*
328
* In Valibot, this represents the current list of call expressions ("pipes")
329
* being assembled to form a schema definition.
330
*
331
* Each pipe can be extended, modified, or replaced to customize how the
332
-
* resulting schema is constructed. Returning `undefined` from a resolver will
333
-
* use the default generation behavior.
334
*/
335
-
pipes: Array<ReturnType<typeof $.call>>;
336
-
plugin: ValibotPlugin['Instance'];
337
-
v: Symbol;
338
};
339
340
-
export type FormatResolverArgs = SharedResolverArgs & {
341
-
schema: IR.SchemaObject;
342
};
343
344
-
export type ObjectBaseResolverArgs = SharedResolverArgs & {
345
-
/** Null = never */
346
-
additional?: ReturnType<typeof $.call | typeof $.expr> | null;
347
-
schema: IR.SchemaObject;
348
-
shape: ReturnType<typeof $.object>;
349
};
350
351
-
type ResolverResult = boolean | number;
352
353
export type ValidatorResolverArgs = SharedResolverArgs & {
354
operation: IR.Operation;
···
361
362
type Resolvers = Plugin.Resolvers<{
363
/**
364
-
* Resolvers for number schemas.
365
*
366
-
* Allows customization of how number types are rendered, including
367
-
* per-format handling.
368
*/
369
-
number?: {
370
-
/**
371
-
* Controls the base segment for number schemas.
372
-
*
373
-
* Returning `undefined` will execute the default resolver logic.
374
-
*/
375
-
base?: (args: FormatResolverArgs) => ResolverResult | undefined;
376
-
/**
377
-
* Resolvers for number formats (e.g., `float`, `double`, `int32`).
378
-
*
379
-
* Each key represents a specific format name with a custom
380
-
* resolver function that controls how that format is rendered.
381
-
*
382
-
* Example path: `~resolvers.number.formats.float`
383
-
*
384
-
* Returning `undefined` from a resolver will apply the default
385
-
* generation behavior for that format.
386
-
*/
387
-
formats?: Record<
388
-
string,
389
-
(args: FormatResolverArgs) => ResolverResult | undefined
390
-
>;
391
-
};
392
/**
393
-
* Resolvers for object schemas.
394
*
395
* Allows customization of how object types are rendered.
396
*
397
-
* Example path: `~resolvers.object.base`
398
-
*
399
-
* Returning `undefined` from a resolver will apply the default
400
-
* generation behavior for the object schema.
401
*/
402
-
object?: {
403
-
/**
404
-
* Controls how object schemas are constructed.
405
-
*
406
-
* Called with the fully assembled shape (properties) and any additional
407
-
* property schema, allowing the resolver to choose the correct Valibot
408
-
* base constructor and modify the schema chain if needed.
409
-
*
410
-
* Returning `undefined` will execute the default resolver logic.
411
-
*/
412
-
base?: (args: ObjectBaseResolverArgs) => ResolverResult | undefined;
413
-
};
414
/**
415
-
* Resolvers for string schemas.
416
*
417
-
* Allows customization of how string types are rendered, including
418
-
* per-format handling.
419
*/
420
-
string?: {
421
-
/**
422
-
* Resolvers for string formats (e.g., `uuid`, `email`, `date-time`).
423
-
*
424
-
* Each key represents a specific format name with a custom
425
-
* resolver function that controls how that format is rendered.
426
-
*
427
-
* Example path: `~resolvers.string.formats.uuid`
428
-
*
429
-
* Returning `undefined` from a resolver will apply the default
430
-
* generation behavior for that format.
431
-
*/
432
-
formats?: Record<
433
-
string,
434
-
(args: FormatResolverArgs) => ResolverResult | undefined
435
-
>;
436
-
};
437
/**
438
* Resolvers for request and response validators.
439
*
···
1
+
import type { Refs, Symbol } from '@hey-api/codegen-core';
2
import type ts from 'typescript';
3
4
import type { IR } from '~/ir/types';
5
+
import type { DefinePlugin, Plugin, SchemaWithType } from '~/plugins';
6
+
import type {
7
+
MaybeBigInt,
8
+
ShouldCoerceToBigInt,
9
+
} from '~/plugins/shared/utils/coerce';
10
+
import type { GetIntegerLimit } from '~/plugins/shared/utils/formats';
11
import type { $, DollarTsDsl, TsDsl } from '~/ts-dsl';
12
import type { StringCase, StringName } from '~/types/case';
13
import type { MaybeArray } from '~/types/utils';
14
15
import type { IApi } from './api';
16
+
import type { Pipe, PipeResult, PipesUtils } from './shared/pipes';
17
+
import type { Ast, PluginState } from './shared/types';
18
19
export type UserConfig = Plugin.Name<'valibot'> &
20
Plugin.Hooks &
···
330
331
type SharedResolverArgs = DollarTsDsl & {
332
/**
333
+
* Functions for working with pipes.
334
+
*/
335
+
pipes: PipesUtils;
336
+
plugin: ValibotPlugin['Instance'];
337
+
/**
338
* The current builder state being processed by this resolver.
339
*
340
* In Valibot, this represents the current list of call expressions ("pipes")
341
* being assembled to form a schema definition.
342
*
343
* Each pipe can be extended, modified, or replaced to customize how the
344
+
* resulting schema is constructed.
345
*/
346
+
result: Pipes;
347
+
/**
348
+
* Provides access to commonly used symbols within the Valibot plugin.
349
+
*/
350
+
symbols: {
351
+
v: Symbol;
352
+
};
353
};
354
355
+
export type NumberResolverContext = SharedResolverArgs & {
356
+
/**
357
+
* Nodes used to build different parts of the number schema.
358
+
*/
359
+
nodes: {
360
+
base: (ctx: NumberResolverContext) => PipeResult;
361
+
const: (ctx: NumberResolverContext) => PipeResult | undefined;
362
+
max: (ctx: NumberResolverContext) => PipeResult | undefined;
363
+
min: (ctx: NumberResolverContext) => PipeResult | undefined;
364
+
};
365
+
schema: SchemaWithType<'integer' | 'number'>;
366
+
/**
367
+
* Utility functions for number schema processing.
368
+
*/
369
+
utils: {
370
+
getIntegerLimit: GetIntegerLimit;
371
+
maybeBigInt: MaybeBigInt;
372
+
shouldCoerceToBigInt: ShouldCoerceToBigInt;
373
+
};
374
};
375
376
+
export type ObjectResolverContext = SharedResolverArgs & {
377
+
/**
378
+
* Nodes used to build different parts of the object schema.
379
+
*/
380
+
nodes: {
381
+
/**
382
+
* If `additionalProperties` is `false` or `{ type: 'never' }`, returns `null`
383
+
* to indicate no additional properties are allowed.
384
+
*/
385
+
additionalProperties: (
386
+
ctx: ObjectResolverContext,
387
+
) => Pipe | null | undefined;
388
+
base: (ctx: ObjectResolverContext) => PipeResult;
389
+
shape: (ctx: ObjectResolverContext) => ReturnType<typeof $.object>;
390
+
};
391
+
schema: SchemaWithType<'object'>;
392
+
/**
393
+
* Utility functions for object schema processing.
394
+
*/
395
+
utils: {
396
+
ast: Partial<Omit<Ast, 'typeName'>>;
397
+
state: Refs<PluginState>;
398
+
};
399
};
400
401
+
export type StringResolverContext = SharedResolverArgs & {
402
+
/**
403
+
* Nodes used to build different parts of the string schema.
404
+
*/
405
+
nodes: {
406
+
base: (ctx: StringResolverContext) => PipeResult;
407
+
const: (ctx: StringResolverContext) => PipeResult | undefined;
408
+
format: (ctx: StringResolverContext) => PipeResult | undefined;
409
+
length: (ctx: StringResolverContext) => PipeResult | undefined;
410
+
maxLength: (ctx: StringResolverContext) => PipeResult | undefined;
411
+
minLength: (ctx: StringResolverContext) => PipeResult | undefined;
412
+
pattern: (ctx: StringResolverContext) => PipeResult | undefined;
413
+
};
414
+
schema: SchemaWithType<'string'>;
415
+
};
416
417
export type ValidatorResolverArgs = SharedResolverArgs & {
418
operation: IR.Operation;
···
425
426
type Resolvers = Plugin.Resolvers<{
427
/**
428
+
* Resolver for number schemas.
429
+
*
430
+
* Allows customization of how number types are rendered.
431
*
432
+
* Returning `undefined` will execute the default resolver logic.
433
*/
434
+
number?: (args: NumberResolverContext) => PipeResult | undefined;
435
/**
436
+
* Resolver for object schemas.
437
*
438
* Allows customization of how object types are rendered.
439
*
440
+
* Returning `undefined` will execute the default resolver logic.
441
*/
442
+
object?: (ctx: ObjectResolverContext) => PipeResult | undefined;
443
/**
444
+
* Resolver for string schemas.
445
+
*
446
+
* Allows customization of how string types are rendered.
447
*
448
+
* Returning `undefined` will execute the default resolver logic.
449
*/
450
+
string?: (ctx: StringResolverContext) => PipeResult | undefined;
451
/**
452
* Resolvers for request and response validators.
453
*
+24
-19
packages/openapi-ts/src/plugins/valibot/v1/api.ts
+24
-19
packages/openapi-ts/src/plugins/valibot/v1/api.ts
···
1
import { $ } from '~/ts-dsl';
2
3
import type { ValidatorArgs } from '../shared/types';
4
import type { ValidatorResolverArgs } from '../types';
5
import { identifiers } from './constants';
6
7
-
const defaultValidatorResolver = ({
8
-
schema,
9
-
v,
10
-
}: ValidatorResolverArgs): ReturnType<typeof $.return> =>
11
-
$(v).attr(identifiers.async.parseAsync).call(schema, 'data').await().return();
12
13
export const createRequestValidatorV1 = ({
14
operation,
···
23
});
24
if (!symbol) return;
25
26
-
const v = plugin.referenceSymbol({
27
-
category: 'external',
28
-
resource: 'valibot.v',
29
-
});
30
const args: ValidatorResolverArgs = {
31
$,
32
operation,
33
-
pipes: [],
34
plugin,
35
schema: symbol,
36
-
v,
37
};
38
const validator = plugin.config['~resolvers']?.validator;
39
const resolver =
40
typeof validator === 'function' ? validator : validator?.request;
41
-
const candidates = [resolver, defaultValidatorResolver];
42
for (const candidate of candidates) {
43
const statements = candidate?.(args);
44
if (statements === null) return;
···
65
});
66
if (!symbol) return;
67
68
-
const v = plugin.referenceSymbol({
69
-
category: 'external',
70
-
resource: 'valibot.v',
71
-
});
72
const args: ValidatorResolverArgs = {
73
$,
74
operation,
75
-
pipes: [],
76
plugin,
77
schema: symbol,
78
-
v,
79
};
80
const validator = plugin.config['~resolvers']?.validator;
81
const resolver =
82
typeof validator === 'function' ? validator : validator?.response;
83
-
const candidates = [resolver, defaultValidatorResolver];
84
for (const candidate of candidates) {
85
const statements = candidate?.(args);
86
if (statements === null) return;
···
1
import { $ } from '~/ts-dsl';
2
3
+
import { pipes } from '../shared/pipes';
4
import type { ValidatorArgs } from '../shared/types';
5
import type { ValidatorResolverArgs } from '../types';
6
import { identifiers } from './constants';
7
8
+
const validatorResolver = (
9
+
ctx: ValidatorResolverArgs,
10
+
): ReturnType<typeof $.return> => {
11
+
const { schema } = ctx;
12
+
const { v } = ctx.symbols;
13
+
return $(v)
14
+
.attr(identifiers.async.parseAsync)
15
+
.call(schema, 'data')
16
+
.await()
17
+
.return();
18
+
};
19
20
export const createRequestValidatorV1 = ({
21
operation,
···
30
});
31
if (!symbol) return;
32
33
const args: ValidatorResolverArgs = {
34
$,
35
operation,
36
+
pipes,
37
plugin,
38
+
result: [],
39
schema: symbol,
40
+
symbols: {
41
+
v: plugin.external('valibot.v'),
42
+
},
43
};
44
const validator = plugin.config['~resolvers']?.validator;
45
const resolver =
46
typeof validator === 'function' ? validator : validator?.request;
47
+
const candidates = [resolver, validatorResolver];
48
for (const candidate of candidates) {
49
const statements = candidate?.(args);
50
if (statements === null) return;
···
71
});
72
if (!symbol) return;
73
74
const args: ValidatorResolverArgs = {
75
$,
76
operation,
77
+
pipes,
78
plugin,
79
+
result: [],
80
schema: symbol,
81
+
symbols: {
82
+
v: plugin.external('valibot.v'),
83
+
},
84
};
85
const validator = plugin.config['~resolvers']?.validator;
86
const resolver =
87
typeof validator === 'function' ? validator : validator?.response;
88
+
const candidates = [resolver, validatorResolver];
89
for (const candidate of candidates) {
90
const statements = candidate?.(args);
91
if (statements === null) return;
+4
-4
packages/openapi-ts/src/plugins/valibot/v1/plugin.ts
+4
-4
packages/openapi-ts/src/plugins/valibot/v1/plugin.ts
···
11
12
import { exportAst } from '../shared/export';
13
import { irOperationToAst } from '../shared/operation';
14
-
import { pipesToAst } from '../shared/pipesToAst';
15
import type { Ast, IrSchemaToAstOptions, PluginState } from '../shared/types';
16
import { irWebhookToAst } from '../shared/webhook';
17
import type { ValibotPlugin } from '../types';
···
87
path: ref([...fromRef(state.path), 'items', index]),
88
},
89
});
90
-
return pipesToAst(itemAst.pipes, plugin);
91
});
92
93
if (schema.logicalOperator === 'and') {
···
129
$(v)
130
.attr(identifiers.schemas.optional)
131
.call(
132
-
pipesToAst(ast.pipes, plugin),
133
schema.type === 'integer' || schema.type === 'number'
134
? maybeBigInt(schema.default, schema.format)
135
: $.fromValue(schema.default),
···
139
ast.pipes = [
140
$(v)
141
.attr(identifiers.schemas.optional)
142
-
.call(pipesToAst(ast.pipes, plugin)),
143
];
144
}
145
}
···
11
12
import { exportAst } from '../shared/export';
13
import { irOperationToAst } from '../shared/operation';
14
+
import { pipesToNode } from '../shared/pipes';
15
import type { Ast, IrSchemaToAstOptions, PluginState } from '../shared/types';
16
import { irWebhookToAst } from '../shared/webhook';
17
import type { ValibotPlugin } from '../types';
···
87
path: ref([...fromRef(state.path), 'items', index]),
88
},
89
});
90
+
return pipesToNode(itemAst.pipes, plugin);
91
});
92
93
if (schema.logicalOperator === 'and') {
···
129
$(v)
130
.attr(identifiers.schemas.optional)
131
.call(
132
+
pipesToNode(ast.pipes, plugin),
133
schema.type === 'integer' || schema.type === 'number'
134
? maybeBigInt(schema.default, schema.format)
135
: $.fromValue(schema.default),
···
139
ast.pipes = [
140
$(v)
141
.attr(identifiers.schemas.optional)
142
+
.call(pipesToNode(ast.pipes, plugin)),
143
];
144
}
145
}
+2
-2
packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts
+2
-2
packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts
···
4
import type { SchemaWithType } from '~/plugins';
5
import { $ } from '~/ts-dsl';
6
7
-
import { pipesToAst } from '../../shared/pipesToAst';
8
import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
9
import { identifiers } from '../constants';
10
import { irSchemaToAst } from '../plugin';
···
54
if (itemAst.hasLazyExpression) {
55
result.hasLazyExpression = true;
56
}
57
-
return pipesToAst(itemAst.pipes, plugin);
58
});
59
60
if (itemExpressions.length === 1) {
···
4
import type { SchemaWithType } from '~/plugins';
5
import { $ } from '~/ts-dsl';
6
7
+
import { pipesToNode } from '../../shared/pipes';
8
import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
9
import { identifiers } from '../constants';
10
import { irSchemaToAst } from '../plugin';
···
54
if (itemAst.hasLazyExpression) {
55
result.hasLazyExpression = true;
56
}
57
+
return pipesToNode(itemAst.pipes, plugin);
58
});
59
60
if (itemExpressions.length === 1) {
+3
-3
packages/openapi-ts/src/plugins/valibot/v1/toAst/boolean.ts
+3
-3
packages/openapi-ts/src/plugins/valibot/v1/toAst/boolean.ts
···
1
import type { SchemaWithType } from '~/plugins';
2
import { $ } from '~/ts-dsl';
3
4
-
import { pipesToAst } from '../../shared/pipesToAst';
5
import type { IrSchemaToAstOptions } from '../../shared/types';
6
import { identifiers } from '../constants';
7
···
22
pipes.push(
23
$(v).attr(identifiers.schemas.literal).call($.literal(schema.const)),
24
);
25
-
return pipesToAst(pipes, plugin);
26
}
27
28
pipes.push($(v).attr(identifiers.schemas.boolean).call());
29
-
return pipesToAst(pipes, plugin);
30
};
···
1
import type { SchemaWithType } from '~/plugins';
2
import { $ } from '~/ts-dsl';
3
4
+
import { pipesToNode } from '../../shared/pipes';
5
import type { IrSchemaToAstOptions } from '../../shared/types';
6
import { identifiers } from '../constants';
7
···
22
pipes.push(
23
$(v).attr(identifiers.schemas.literal).call($.literal(schema.const)),
24
);
25
+
return pipesToNode(pipes, plugin);
26
}
27
28
pipes.push($(v).attr(identifiers.schemas.boolean).call());
29
+
return pipesToNode(pipes, plugin);
30
};
+9
-9
packages/openapi-ts/src/plugins/valibot/v1/toAst/index.ts
+9
-9
packages/openapi-ts/src/plugins/valibot/v1/toAst/index.ts
···
2
import { shouldCoerceToBigInt } from '~/plugins/shared/utils/coerce';
3
import type { $ } from '~/ts-dsl';
4
5
-
import { pipesToAst } from '../../shared/pipesToAst';
6
import type { IrSchemaToAstOptions } from '../../shared/types';
7
import { arrayToAst } from './array';
8
import { booleanToAst } from './boolean';
9
import { enumToAst } from './enum';
10
import { neverToAst } from './never';
11
import { nullToAst } from './null';
12
-
import { numberToAst } from './number';
13
import { objectToAst } from './object';
14
-
import { stringToAst } from './string';
15
import { tupleToAst } from './tuple';
16
import { undefinedToAst } from './undefined';
17
import { unknownToAst } from './unknown';
···
29
switch (schema.type) {
30
case 'array':
31
return {
32
-
expression: pipesToAst(
33
arrayToAst({
34
...args,
35
schema: schema as SchemaWithType<'array'>,
···
54
case 'integer':
55
case 'number':
56
return {
57
-
expression: numberToAst({
58
...args,
59
schema: schema as SchemaWithType<'integer' | 'number'>,
60
}),
···
75
};
76
case 'object':
77
return {
78
-
expression: pipesToAst(
79
objectToAst({
80
...args,
81
schema: schema as SchemaWithType<'object'>,
···
86
case 'string':
87
return {
88
expression: shouldCoerceToBigInt(schema.format)
89
-
? numberToAst({
90
...args,
91
schema: { ...schema, type: 'number' },
92
})
93
-
: stringToAst({
94
...args,
95
schema: schema as SchemaWithType<'string'>,
96
}),
97
};
98
case 'tuple':
99
return {
100
-
expression: pipesToAst(
101
tupleToAst({
102
...args,
103
schema: schema as SchemaWithType<'tuple'>,
···
2
import { shouldCoerceToBigInt } from '~/plugins/shared/utils/coerce';
3
import type { $ } from '~/ts-dsl';
4
5
+
import { pipesToNode } from '../../shared/pipes';
6
import type { IrSchemaToAstOptions } from '../../shared/types';
7
import { arrayToAst } from './array';
8
import { booleanToAst } from './boolean';
9
import { enumToAst } from './enum';
10
import { neverToAst } from './never';
11
import { nullToAst } from './null';
12
+
import { numberToNode } from './number';
13
import { objectToAst } from './object';
14
+
import { stringToNode } from './string';
15
import { tupleToAst } from './tuple';
16
import { undefinedToAst } from './undefined';
17
import { unknownToAst } from './unknown';
···
29
switch (schema.type) {
30
case 'array':
31
return {
32
+
expression: pipesToNode(
33
arrayToAst({
34
...args,
35
schema: schema as SchemaWithType<'array'>,
···
54
case 'integer':
55
case 'number':
56
return {
57
+
expression: numberToNode({
58
...args,
59
schema: schema as SchemaWithType<'integer' | 'number'>,
60
}),
···
75
};
76
case 'object':
77
return {
78
+
expression: pipesToNode(
79
objectToAst({
80
...args,
81
schema: schema as SchemaWithType<'object'>,
···
86
case 'string':
87
return {
88
expression: shouldCoerceToBigInt(schema.format)
89
+
? numberToNode({
90
...args,
91
schema: { ...schema, type: 'number' },
92
})
93
+
: stringToNode({
94
...args,
95
schema: schema as SchemaWithType<'string'>,
96
}),
97
};
98
case 'tuple':
99
return {
100
+
expression: pipesToNode(
101
tupleToAst({
102
...args,
103
schema: schema as SchemaWithType<'tuple'>,
+111
-94
packages/openapi-ts/src/plugins/valibot/v1/toAst/number.ts
+111
-94
packages/openapi-ts/src/plugins/valibot/v1/toAst/number.ts
···
6
import { getIntegerLimit } from '~/plugins/shared/utils/formats';
7
import { $ } from '~/ts-dsl';
8
9
-
import { pipesToAst } from '../../shared/pipesToAst';
10
import type { IrSchemaToAstOptions } from '../../shared/types';
11
-
import type { FormatResolverArgs } from '../../types';
12
import { identifiers } from '../constants';
13
14
-
const defaultBaseResolver = ({
15
-
pipes,
16
-
schema,
17
-
v,
18
-
}: FormatResolverArgs): boolean | number => {
19
-
if (shouldCoerceToBigInt(schema.format)) {
20
-
pipes.push(
21
$(v)
22
.attr(identifiers.schemas.union)
23
.call(
···
30
$(v)
31
.attr(identifiers.actions.transform)
32
.call($.func().param('x').do($('BigInt').call('x').return())),
33
-
);
34
-
} else {
35
-
pipes.push($(v).attr(identifiers.schemas.number).call());
36
-
if (schema.type === 'integer') {
37
-
pipes.push($(v).attr(identifiers.actions.integer).call());
38
-
}
39
}
40
41
-
return true;
42
-
};
43
44
-
export const numberToAst = ({
45
-
plugin,
46
-
schema,
47
-
}: IrSchemaToAstOptions & {
48
-
schema: SchemaWithType<'integer' | 'number'>;
49
-
}) => {
50
-
const v = plugin.referenceSymbol({
51
-
category: 'external',
52
-
resource: 'valibot.v',
53
-
});
54
55
-
if (schema.const !== undefined) {
56
return $(v)
57
-
.attr(identifiers.schemas.literal)
58
-
.call(maybeBigInt(schema.const, schema.format));
59
}
60
61
-
const pipes: Array<ReturnType<typeof $.call>> = [];
62
63
-
const args: FormatResolverArgs = { $, pipes, plugin, schema, v };
64
-
const resolver = plugin.config['~resolvers']?.number?.base;
65
-
if (!resolver?.(args)) defaultBaseResolver(args);
66
67
-
let hasLowerBound = false;
68
-
let hasUpperBound = false;
69
-
70
-
if (schema.exclusiveMinimum !== undefined) {
71
-
pipes.push(
72
-
$(v)
73
-
.attr(identifiers.actions.gtValue)
74
-
.call(maybeBigInt(schema.exclusiveMinimum, schema.format)),
75
-
);
76
-
hasLowerBound = true;
77
-
} else if (schema.minimum !== undefined) {
78
-
pipes.push(
79
-
$(v)
80
-
.attr(identifiers.actions.minValue)
81
-
.call(maybeBigInt(schema.minimum, schema.format)),
82
-
);
83
-
hasLowerBound = true;
84
-
}
85
86
-
if (schema.exclusiveMaximum !== undefined) {
87
-
pipes.push(
88
-
$(v)
89
-
.attr(identifiers.actions.ltValue)
90
-
.call(maybeBigInt(schema.exclusiveMaximum, schema.format)),
91
-
);
92
-
hasUpperBound = true;
93
-
} else if (schema.maximum !== undefined) {
94
-
pipes.push(
95
-
$(v)
96
-
.attr(identifiers.actions.maxValue)
97
-
.call(maybeBigInt(schema.maximum, schema.format)),
98
-
);
99
-
hasUpperBound = true;
100
-
}
101
-
102
-
const integerLimit = getIntegerLimit(schema.format);
103
-
if (integerLimit) {
104
-
if (!hasLowerBound) {
105
-
pipes.push(
106
-
$(v)
107
-
.attr(identifiers.actions.minValue)
108
-
.call(
109
-
maybeBigInt(integerLimit.minValue, schema.format),
110
-
$.literal(integerLimit.minError),
111
-
),
112
-
);
113
-
hasLowerBound = true;
114
-
}
115
116
-
if (!hasUpperBound) {
117
-
pipes.push(
118
-
$(v)
119
-
.attr(identifiers.actions.maxValue)
120
-
.call(
121
-
maybeBigInt(integerLimit.maxValue, schema.format),
122
-
$.literal(integerLimit.maxError),
123
-
),
124
-
);
125
-
hasUpperBound = true;
126
-
}
127
-
}
128
129
-
return pipesToAst(pipes, plugin);
130
};
···
6
import { getIntegerLimit } from '~/plugins/shared/utils/formats';
7
import { $ } from '~/ts-dsl';
8
9
+
import type { Pipe, PipeResult, Pipes } from '../../shared/pipes';
10
+
import { pipes } from '../../shared/pipes';
11
import type { IrSchemaToAstOptions } from '../../shared/types';
12
+
import type { NumberResolverContext } from '../../types';
13
import { identifiers } from '../constants';
14
15
+
function baseNode(ctx: NumberResolverContext): PipeResult {
16
+
const { schema } = ctx;
17
+
const { v } = ctx.symbols;
18
+
if (ctx.utils.shouldCoerceToBigInt(schema.format)) {
19
+
return [
20
$(v)
21
.attr(identifiers.schemas.union)
22
.call(
···
29
$(v)
30
.attr(identifiers.actions.transform)
31
.call($.func().param('x').do($('BigInt').call('x').return())),
32
+
];
33
}
34
+
const pipes: Pipes = [];
35
+
pipes.push($(v).attr(identifiers.schemas.number).call());
36
+
if (schema.type === 'integer') {
37
+
pipes.push($(v).attr(identifiers.actions.integer).call());
38
+
}
39
+
return pipes;
40
+
}
41
42
+
function constNode(ctx: NumberResolverContext): PipeResult | undefined {
43
+
const { schema } = ctx;
44
+
const { v } = ctx.symbols;
45
+
if (schema.const === undefined) return;
46
+
return $(v)
47
+
.attr(identifiers.schemas.literal)
48
+
.call(ctx.utils.maybeBigInt(schema.const, schema.format));
49
+
}
50
51
+
function maxNode(ctx: NumberResolverContext): PipeResult | undefined {
52
+
const { schema } = ctx;
53
+
const { v } = ctx.symbols;
54
+
if (schema.exclusiveMaximum !== undefined) {
55
+
return $(v)
56
+
.attr(identifiers.actions.ltValue)
57
+
.call(ctx.utils.maybeBigInt(schema.exclusiveMaximum, schema.format));
58
+
}
59
+
if (schema.maximum !== undefined) {
60
+
return $(v)
61
+
.attr(identifiers.actions.maxValue)
62
+
.call(ctx.utils.maybeBigInt(schema.maximum, schema.format));
63
+
}
64
+
const limit = ctx.utils.getIntegerLimit(schema.format);
65
+
if (limit) {
66
+
return $(v)
67
+
.attr(identifiers.actions.maxValue)
68
+
.call(
69
+
ctx.utils.maybeBigInt(limit.maxValue, schema.format),
70
+
$.literal(limit.maxError),
71
+
);
72
+
}
73
+
return;
74
+
}
75
76
+
function minNode(ctx: NumberResolverContext): PipeResult | undefined {
77
+
const { schema } = ctx;
78
+
const { v } = ctx.symbols;
79
+
if (schema.exclusiveMinimum !== undefined) {
80
+
return $(v)
81
+
.attr(identifiers.actions.gtValue)
82
+
.call(ctx.utils.maybeBigInt(schema.exclusiveMinimum, schema.format));
83
+
}
84
+
if (schema.minimum !== undefined) {
85
+
return $(v)
86
+
.attr(identifiers.actions.minValue)
87
+
.call(ctx.utils.maybeBigInt(schema.minimum, schema.format));
88
+
}
89
+
const limit = ctx.utils.getIntegerLimit(schema.format);
90
+
if (limit) {
91
return $(v)
92
+
.attr(identifiers.actions.minValue)
93
+
.call(
94
+
ctx.utils.maybeBigInt(limit.minValue, schema.format),
95
+
$.literal(limit.minError),
96
+
);
97
}
98
+
return;
99
+
}
100
101
+
function numberResolver(ctx: NumberResolverContext): Pipes {
102
+
const constNode = ctx.nodes.const(ctx);
103
+
if (constNode) return ctx.pipes.push(ctx.result, constNode);
104
105
+
const baseNode = ctx.nodes.base(ctx);
106
+
if (baseNode) ctx.pipes.push(ctx.result, baseNode);
107
108
+
const minNode = ctx.nodes.min(ctx);
109
+
if (minNode) ctx.pipes.push(ctx.result, minNode);
110
111
+
const maxNode = ctx.nodes.max(ctx);
112
+
if (maxNode) ctx.pipes.push(ctx.result, maxNode);
113
114
+
return ctx.result;
115
+
}
116
117
+
export const numberToNode = ({
118
+
plugin,
119
+
schema,
120
+
}: IrSchemaToAstOptions & {
121
+
schema: SchemaWithType<'integer' | 'number'>;
122
+
}): Pipe => {
123
+
const ctx: NumberResolverContext = {
124
+
$,
125
+
nodes: {
126
+
base: baseNode,
127
+
const: constNode,
128
+
max: maxNode,
129
+
min: minNode,
130
+
},
131
+
pipes,
132
+
plugin,
133
+
result: [],
134
+
schema,
135
+
symbols: {
136
+
v: plugin.external('valibot.v'),
137
+
},
138
+
utils: {
139
+
getIntegerLimit,
140
+
maybeBigInt,
141
+
shouldCoerceToBigInt,
142
+
},
143
+
};
144
+
const resolver = plugin.config['~resolvers']?.number;
145
+
const node = resolver?.(ctx) ?? numberResolver(ctx);
146
+
return ctx.pipes.toNode(node, plugin);
147
};
+74
-71
packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts
+74
-71
packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts
···
3
import type { SchemaWithType } from '~/plugins';
4
import { $ } from '~/ts-dsl';
5
6
-
import { pipesToAst } from '../../shared/pipesToAst';
7
import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
8
-
import type { ObjectBaseResolverArgs } from '../../types';
9
import { identifiers } from '../constants';
10
import { irSchemaToAst } from '../plugin';
11
12
-
function defaultBaseResolver({
13
-
additional,
14
-
pipes,
15
-
shape,
16
-
v,
17
-
}: ObjectBaseResolverArgs): number {
18
-
// Handle `additionalProperties: { type: 'never' }` → v.strictObject()
19
if (additional === null) {
20
-
return pipes.push($(v).attr(identifiers.schemas.strictObject).call(shape));
21
}
22
23
-
// Handle additionalProperties as schema → v.record() or v.objectWithRest()
24
if (additional) {
25
if (shape.isEmpty) {
26
-
return pipes.push(
27
-
$(v)
28
-
.attr(identifiers.schemas.record)
29
-
.call($(v).attr(identifiers.schemas.string).call(), additional),
30
-
);
31
}
32
33
-
// If there are named properties, use v.objectWithRest() to validate both
34
-
return pipes.push(
35
-
$(v).attr(identifiers.schemas.objectWithRest).call(shape, additional),
36
-
);
37
}
38
39
-
// Default case → v.object()
40
-
return pipes.push($(v).attr(identifiers.schemas.object).call(shape));
41
}
42
43
-
export const objectToAst = ({
44
-
plugin,
45
-
schema,
46
-
state,
47
-
}: IrSchemaToAstOptions & {
48
-
schema: SchemaWithType<'object'>;
49
-
}): Omit<Ast, 'typeName'> => {
50
-
const v = plugin.referenceSymbol({
51
-
category: 'external',
52
-
resource: 'valibot.v',
53
-
});
54
-
55
-
const result: Partial<Omit<Ast, 'typeName'>> = {};
56
-
const pipes: Array<ReturnType<typeof $.call>> = [];
57
-
58
// TODO: parser - handle constants
59
60
const shape = $.object().pretty();
61
-
const required = schema.required ?? [];
62
63
for (const name in schema.properties) {
64
const property = schema.properties[name]!;
65
-
const isRequired = required.includes(name);
66
67
const propertyAst = irSchemaToAst({
68
-
optional: !isRequired,
69
plugin,
70
schema: property,
71
state: {
72
-
...state,
73
-
path: ref([...fromRef(state.path), 'properties', name]),
74
},
75
});
76
-
if (propertyAst.hasLazyExpression) result.hasLazyExpression = true;
77
-
78
-
shape.prop(name, pipesToAst(propertyAst.pipes, plugin));
79
}
80
81
-
let additional: ReturnType<typeof $.call | typeof $.expr> | null | undefined;
82
-
if (schema.additionalProperties && schema.additionalProperties.type) {
83
-
if (schema.additionalProperties.type === 'never') {
84
-
additional = null;
85
-
} else {
86
-
const additionalAst = irSchemaToAst({
87
-
plugin,
88
-
schema: schema.additionalProperties,
89
-
state: {
90
-
...state,
91
-
path: ref([...fromRef(state.path), 'additionalProperties']),
92
-
},
93
-
});
94
-
if (additionalAst.hasLazyExpression) result.hasLazyExpression = true;
95
-
additional = pipesToAst(additionalAst.pipes, plugin);
96
-
}
97
-
}
98
99
-
const args: ObjectBaseResolverArgs = {
100
$,
101
-
additional,
102
pipes,
103
plugin,
104
schema,
105
-
shape,
106
-
v,
107
};
108
-
const resolver = plugin.config['~resolvers']?.object?.base;
109
-
if (!resolver?.(args)) defaultBaseResolver(args);
110
-
111
-
result.pipes = [pipesToAst(pipes, plugin)];
112
-
return result as Omit<Ast, 'typeName'>;
113
};
···
3
import type { SchemaWithType } from '~/plugins';
4
import { $ } from '~/ts-dsl';
5
6
+
import type { Pipe, PipeResult } from '../../shared/pipes';
7
+
import { pipes } from '../../shared/pipes';
8
import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
9
+
import type { ObjectResolverContext } from '../../types';
10
import { identifiers } from '../constants';
11
import { irSchemaToAst } from '../plugin';
12
13
+
function additionalPropertiesNode(
14
+
ctx: ObjectResolverContext,
15
+
): Pipe | null | undefined {
16
+
const { plugin, schema } = ctx;
17
+
18
+
if (!schema.additionalProperties || !schema.additionalProperties.type) return;
19
+
if (schema.additionalProperties.type === 'never') return null;
20
+
21
+
const additionalAst = irSchemaToAst({
22
+
plugin,
23
+
schema: schema.additionalProperties,
24
+
state: {
25
+
...ctx.utils.state,
26
+
path: ref([...fromRef(ctx.utils.state.path), 'additionalProperties']),
27
+
},
28
+
});
29
+
if (additionalAst.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true;
30
+
return pipes.toNode(additionalAst.pipes, plugin);
31
+
}
32
+
33
+
function baseNode(ctx: ObjectResolverContext): PipeResult {
34
+
const { v } = ctx.symbols;
35
+
36
+
const additional = ctx.nodes.additionalProperties(ctx);
37
+
const shape = ctx.nodes.shape(ctx);
38
+
39
if (additional === null) {
40
+
return $(v).attr(identifiers.schemas.strictObject).call(shape);
41
}
42
43
if (additional) {
44
if (shape.isEmpty) {
45
+
return $(v)
46
+
.attr(identifiers.schemas.record)
47
+
.call($(v).attr(identifiers.schemas.string).call(), additional);
48
}
49
50
+
return $(v)
51
+
.attr(identifiers.schemas.objectWithRest)
52
+
.call(shape, additional);
53
}
54
55
+
return $(v).attr(identifiers.schemas.object).call(shape);
56
}
57
58
+
function objectResolver(ctx: ObjectResolverContext): PipeResult {
59
// TODO: parser - handle constants
60
+
return ctx.nodes.base(ctx);
61
+
}
62
63
+
function shapeNode(ctx: ObjectResolverContext): ReturnType<typeof $.object> {
64
+
const { plugin, schema } = ctx;
65
const shape = $.object().pretty();
66
67
for (const name in schema.properties) {
68
const property = schema.properties[name]!;
69
70
const propertyAst = irSchemaToAst({
71
+
optional: !schema.required?.includes(name),
72
plugin,
73
schema: property,
74
state: {
75
+
...ctx.utils.state,
76
+
path: ref([...fromRef(ctx.utils.state.path), 'properties', name]),
77
},
78
});
79
+
if (propertyAst.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true;
80
+
shape.prop(name, pipes.toNode(propertyAst.pipes, plugin));
81
}
82
83
+
return shape;
84
+
}
85
86
+
export const objectToAst = ({
87
+
plugin,
88
+
schema,
89
+
state,
90
+
}: IrSchemaToAstOptions & {
91
+
schema: SchemaWithType<'object'>;
92
+
}): Omit<Ast, 'typeName'> => {
93
+
const ctx: ObjectResolverContext = {
94
$,
95
+
nodes: {
96
+
additionalProperties: additionalPropertiesNode,
97
+
base: baseNode,
98
+
shape: shapeNode,
99
+
},
100
pipes,
101
plugin,
102
+
result: [],
103
schema,
104
+
symbols: {
105
+
v: plugin.external('valibot.v'),
106
+
},
107
+
utils: {
108
+
ast: {},
109
+
state,
110
+
},
111
};
112
+
const resolver = plugin.config['~resolvers']?.object;
113
+
const node = resolver?.(ctx) ?? objectResolver(ctx);
114
+
ctx.utils.ast.pipes = [ctx.pipes.toNode(node, plugin)];
115
+
return ctx.utils.ast as Omit<Ast, 'typeName'>;
116
};
+108
-60
packages/openapi-ts/src/plugins/valibot/v1/toAst/string.ts
+108
-60
packages/openapi-ts/src/plugins/valibot/v1/toAst/string.ts
···
1
import type { SchemaWithType } from '~/plugins';
2
import { $ } from '~/ts-dsl';
3
4
-
import { pipesToAst } from '../../shared/pipesToAst';
5
import type { IrSchemaToAstOptions } from '../../shared/types';
6
-
import type { FormatResolverArgs } from '../../types';
7
import { identifiers } from '../constants';
8
9
-
const defaultFormatResolver = ({
10
-
pipes,
11
-
schema,
12
-
v,
13
-
}: FormatResolverArgs): boolean | number => {
14
switch (schema.format) {
15
case 'date':
16
-
return pipes.push($(v).attr(identifiers.actions.isoDate).call());
17
case 'date-time':
18
-
return pipes.push($(v).attr(identifiers.actions.isoTimestamp).call());
19
case 'email':
20
-
return pipes.push($(v).attr(identifiers.actions.email).call());
21
case 'ipv4':
22
case 'ipv6':
23
-
return pipes.push($(v).attr(identifiers.actions.ip).call());
24
case 'time':
25
-
return pipes.push($(v).attr(identifiers.actions.isoTimeSecond).call());
26
case 'uri':
27
-
return pipes.push($(v).attr(identifiers.actions.url).call());
28
case 'uuid':
29
-
return pipes.push($(v).attr(identifiers.actions.uuid).call());
30
}
31
32
-
return true;
33
-
};
34
35
-
export const stringToAst = ({
36
-
plugin,
37
-
schema,
38
-
}: IrSchemaToAstOptions & {
39
-
schema: SchemaWithType<'string'>;
40
-
}): ReturnType<typeof $.call | typeof $.expr> => {
41
-
const v = plugin.referenceSymbol({
42
-
category: 'external',
43
-
resource: 'valibot.v',
44
-
});
45
46
-
if (typeof schema.const === 'string') {
47
-
return $(v).attr(identifiers.schemas.literal).call($.literal(schema.const));
48
-
}
49
50
-
const pipes = [$(v).attr(identifiers.schemas.string).call()];
51
52
-
if (schema.format) {
53
-
const args: FormatResolverArgs = { $, pipes, plugin, schema, v };
54
-
const resolver =
55
-
plugin.config['~resolvers']?.string?.formats?.[schema.format];
56
-
if (!resolver?.(args)) defaultFormatResolver(args);
57
-
}
58
59
-
if (schema.minLength === schema.maxLength && schema.minLength !== undefined) {
60
-
pipes.push(
61
-
$(v).attr(identifiers.actions.length).call($.literal(schema.minLength)),
62
-
);
63
} else {
64
-
if (schema.minLength !== undefined) {
65
-
pipes.push(
66
-
$(v)
67
-
.attr(identifiers.actions.minLength)
68
-
.call($.literal(schema.minLength)),
69
-
);
70
-
}
71
72
-
if (schema.maxLength !== undefined) {
73
-
pipes.push(
74
-
$(v)
75
-
.attr(identifiers.actions.maxLength)
76
-
.call($.literal(schema.maxLength)),
77
-
);
78
-
}
79
}
80
81
-
if (schema.pattern) {
82
-
pipes.push(
83
-
$(v).attr(identifiers.actions.regex).call($.regexp(schema.pattern)),
84
-
);
85
-
}
86
87
-
return pipesToAst(pipes, plugin);
88
};
···
1
import type { SchemaWithType } from '~/plugins';
2
import { $ } from '~/ts-dsl';
3
4
+
import type { Pipe, PipeResult, Pipes } from '../../shared/pipes';
5
+
import { pipes } from '../../shared/pipes';
6
import type { IrSchemaToAstOptions } from '../../shared/types';
7
+
import type { StringResolverContext } from '../../types';
8
import { identifiers } from '../constants';
9
10
+
function baseNode(ctx: StringResolverContext): PipeResult {
11
+
const { v } = ctx.symbols;
12
+
return $(v).attr(identifiers.schemas.string).call();
13
+
}
14
+
15
+
function constNode(ctx: StringResolverContext): PipeResult | undefined {
16
+
const { schema } = ctx;
17
+
const { v } = ctx.symbols;
18
+
if (typeof schema.const !== 'string') return;
19
+
return $(v).attr(identifiers.schemas.literal).call($.literal(schema.const));
20
+
}
21
+
22
+
function formatNode(ctx: StringResolverContext): PipeResult | undefined {
23
+
const { schema } = ctx;
24
+
const { v } = ctx.symbols;
25
switch (schema.format) {
26
case 'date':
27
+
return $(v).attr(identifiers.actions.isoDate).call();
28
case 'date-time':
29
+
return $(v).attr(identifiers.actions.isoTimestamp).call();
30
case 'email':
31
+
return $(v).attr(identifiers.actions.email).call();
32
case 'ipv4':
33
case 'ipv6':
34
+
return $(v).attr(identifiers.actions.ip).call();
35
case 'time':
36
+
return $(v).attr(identifiers.actions.isoTimeSecond).call();
37
case 'uri':
38
+
return $(v).attr(identifiers.actions.url).call();
39
case 'uuid':
40
+
return $(v).attr(identifiers.actions.uuid).call();
41
}
42
43
+
return;
44
+
}
45
46
+
function lengthNode(ctx: StringResolverContext): PipeResult | undefined {
47
+
const { schema } = ctx;
48
+
const { v } = ctx.symbols;
49
+
if (schema.minLength === undefined || schema.minLength !== schema.maxLength)
50
+
return;
51
+
return $(v)
52
+
.attr(identifiers.actions.length)
53
+
.call($.literal(schema.minLength));
54
+
}
55
56
+
function maxLengthNode(ctx: StringResolverContext): PipeResult | undefined {
57
+
const { schema } = ctx;
58
+
const { v } = ctx.symbols;
59
+
if (schema.maxLength === undefined) return;
60
+
return $(v)
61
+
.attr(identifiers.actions.maxLength)
62
+
.call($.literal(schema.maxLength));
63
+
}
64
65
+
function minLengthNode(ctx: StringResolverContext): PipeResult | undefined {
66
+
const { schema } = ctx;
67
+
const { v } = ctx.symbols;
68
+
if (schema.minLength === undefined) return;
69
+
return $(v)
70
+
.attr(identifiers.actions.minLength)
71
+
.call($.literal(schema.minLength));
72
+
}
73
74
+
function patternNode(ctx: StringResolverContext): PipeResult | undefined {
75
+
const { schema } = ctx;
76
+
const { v } = ctx.symbols;
77
+
if (!schema.pattern) return;
78
+
return $(v).attr(identifiers.actions.regex).call($.regexp(schema.pattern));
79
+
}
80
+
81
+
function stringResolver(ctx: StringResolverContext): Pipes {
82
+
const constNode = ctx.nodes.const(ctx);
83
+
if (constNode) return ctx.pipes.push(ctx.result, constNode);
84
+
85
+
const baseNode = ctx.nodes.base(ctx);
86
+
if (baseNode) ctx.pipes.push(ctx.result, baseNode);
87
88
+
const formatNode = ctx.nodes.format(ctx);
89
+
if (formatNode) ctx.pipes.push(ctx.result, formatNode);
90
+
91
+
const lengthNode = ctx.nodes.length(ctx);
92
+
if (lengthNode) {
93
+
ctx.pipes.push(ctx.result, lengthNode);
94
} else {
95
+
const minLengthNode = ctx.nodes.minLength(ctx);
96
+
if (minLengthNode) ctx.pipes.push(ctx.result, minLengthNode);
97
98
+
const maxLengthNode = ctx.nodes.maxLength(ctx);
99
+
if (maxLengthNode) ctx.pipes.push(ctx.result, maxLengthNode);
100
}
101
102
+
const patternNode = ctx.nodes.pattern(ctx);
103
+
if (patternNode) ctx.pipes.push(ctx.result, patternNode);
104
+
105
+
return ctx.result;
106
+
}
107
108
+
export const stringToNode = ({
109
+
plugin,
110
+
schema,
111
+
}: IrSchemaToAstOptions & {
112
+
schema: SchemaWithType<'string'>;
113
+
}): Pipe => {
114
+
const ctx: StringResolverContext = {
115
+
$,
116
+
nodes: {
117
+
base: baseNode,
118
+
const: constNode,
119
+
format: formatNode,
120
+
length: lengthNode,
121
+
maxLength: maxLengthNode,
122
+
minLength: minLengthNode,
123
+
pattern: patternNode,
124
+
},
125
+
pipes,
126
+
plugin,
127
+
result: [],
128
+
schema,
129
+
symbols: {
130
+
v: plugin.external('valibot.v'),
131
+
},
132
+
};
133
+
const resolver = plugin.config['~resolvers']?.string;
134
+
const node = resolver?.(ctx) ?? stringResolver(ctx);
135
+
return ctx.pipes.toNode(node, plugin);
136
};
+2
-2
packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts
+2
-2
packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts
···
3
import type { SchemaWithType } from '~/plugins';
4
import { $ } from '~/ts-dsl';
5
6
-
import { pipesToAst } from '../../shared/pipesToAst';
7
import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
8
import { identifiers } from '../constants';
9
import { irSchemaToAst } from '../plugin';
···
48
if (schemaPipes.hasLazyExpression) {
49
result.hasLazyExpression = true;
50
}
51
-
return pipesToAst(schemaPipes.pipes, plugin);
52
});
53
result.pipes = [
54
$(v)
···
3
import type { SchemaWithType } from '~/plugins';
4
import { $ } from '~/ts-dsl';
5
6
+
import { pipesToNode } from '../../shared/pipes';
7
import type { Ast, IrSchemaToAstOptions } from '../../shared/types';
8
import { identifiers } from '../constants';
9
import { irSchemaToAst } from '../plugin';
···
48
if (schemaPipes.hasLazyExpression) {
49
result.hasLazyExpression = true;
50
}
51
+
return pipesToNode(schemaPipes.pipes, plugin);
52
});
53
result.pipes = [
54
$(v)
+3
-3
packages/openapi-ts/src/plugins/zod/mini/api.ts
+3
-3
packages/openapi-ts/src/plugins/zod/mini/api.ts
···
4
import type { ValidatorArgs } from '../shared/types';
5
import type { ValidatorResolverArgs } from '../types';
6
7
-
const defaultValidatorResolver = ({
8
schema,
9
}: ValidatorResolverArgs): ReturnType<typeof $.return> =>
10
$(schema).attr(identifiers.parseAsync).call('data').await().return();
···
37
const validator = plugin.config['~resolvers']?.validator;
38
const resolver =
39
typeof validator === 'function' ? validator : validator?.request;
40
-
const candidates = [resolver, defaultValidatorResolver];
41
for (const candidate of candidates) {
42
const statements = candidate?.(args);
43
if (statements === null) return;
···
79
const validator = plugin.config['~resolvers']?.validator;
80
const resolver =
81
typeof validator === 'function' ? validator : validator?.response;
82
-
const candidates = [resolver, defaultValidatorResolver];
83
for (const candidate of candidates) {
84
const statements = candidate?.(args);
85
if (statements === null) return;
···
4
import type { ValidatorArgs } from '../shared/types';
5
import type { ValidatorResolverArgs } from '../types';
6
7
+
const validatorResolver = ({
8
schema,
9
}: ValidatorResolverArgs): ReturnType<typeof $.return> =>
10
$(schema).attr(identifiers.parseAsync).call('data').await().return();
···
37
const validator = plugin.config['~resolvers']?.validator;
38
const resolver =
39
typeof validator === 'function' ? validator : validator?.request;
40
+
const candidates = [resolver, validatorResolver];
41
for (const candidate of candidates) {
42
const statements = candidate?.(args);
43
if (statements === null) return;
···
79
const validator = plugin.config['~resolvers']?.validator;
80
const resolver =
81
typeof validator === 'function' ? validator : validator?.response;
82
+
const candidates = [resolver, validatorResolver];
83
for (const candidate of candidates) {
84
const statements = candidate?.(args);
85
if (statements === null) return;
+3
-3
packages/openapi-ts/src/plugins/zod/v3/api.ts
+3
-3
packages/openapi-ts/src/plugins/zod/v3/api.ts
···
4
import type { ValidatorArgs } from '../shared/types';
5
import type { ValidatorResolverArgs } from '../types';
6
7
-
const defaultValidatorResolver = ({
8
schema,
9
}: ValidatorResolverArgs): ReturnType<typeof $.return> =>
10
$(schema).attr(identifiers.parseAsync).call('data').await().return();
···
37
const validator = plugin.config['~resolvers']?.validator;
38
const resolver =
39
typeof validator === 'function' ? validator : validator?.request;
40
-
const candidates = [resolver, defaultValidatorResolver];
41
for (const candidate of candidates) {
42
const statements = candidate?.(args);
43
if (statements === null) return;
···
79
const validator = plugin.config['~resolvers']?.validator;
80
const resolver =
81
typeof validator === 'function' ? validator : validator?.response;
82
-
const candidates = [resolver, defaultValidatorResolver];
83
for (const candidate of candidates) {
84
const statements = candidate?.(args);
85
if (statements === null) return;
···
4
import type { ValidatorArgs } from '../shared/types';
5
import type { ValidatorResolverArgs } from '../types';
6
7
+
const validatorResolver = ({
8
schema,
9
}: ValidatorResolverArgs): ReturnType<typeof $.return> =>
10
$(schema).attr(identifiers.parseAsync).call('data').await().return();
···
37
const validator = plugin.config['~resolvers']?.validator;
38
const resolver =
39
typeof validator === 'function' ? validator : validator?.request;
40
+
const candidates = [resolver, validatorResolver];
41
for (const candidate of candidates) {
42
const statements = candidate?.(args);
43
if (statements === null) return;
···
79
const validator = plugin.config['~resolvers']?.validator;
80
const resolver =
81
typeof validator === 'function' ? validator : validator?.response;
82
+
const candidates = [resolver, validatorResolver];
83
for (const candidate of candidates) {
84
const statements = candidate?.(args);
85
if (statements === null) return;
+3
-3
packages/openapi-ts/src/plugins/zod/v4/api.ts
+3
-3
packages/openapi-ts/src/plugins/zod/v4/api.ts
···
4
import type { ValidatorArgs } from '../shared/types';
5
import type { ValidatorResolverArgs } from '../types';
6
7
-
const defaultValidatorResolver = ({
8
schema,
9
}: ValidatorResolverArgs): ReturnType<typeof $.return> =>
10
$(schema).attr(identifiers.parseAsync).call('data').await().return();
···
37
const validator = plugin.config['~resolvers']?.validator;
38
const resolver =
39
typeof validator === 'function' ? validator : validator?.request;
40
-
const candidates = [resolver, defaultValidatorResolver];
41
for (const candidate of candidates) {
42
const statements = candidate?.(args);
43
if (statements === null) return;
···
79
const validator = plugin.config['~resolvers']?.validator;
80
const resolver =
81
typeof validator === 'function' ? validator : validator?.response;
82
-
const candidates = [resolver, defaultValidatorResolver];
83
for (const candidate of candidates) {
84
const statements = candidate?.(args);
85
if (statements === null) return;
···
4
import type { ValidatorArgs } from '../shared/types';
5
import type { ValidatorResolverArgs } from '../types';
6
7
+
const validatorResolver = ({
8
schema,
9
}: ValidatorResolverArgs): ReturnType<typeof $.return> =>
10
$(schema).attr(identifiers.parseAsync).call('data').await().return();
···
37
const validator = plugin.config['~resolvers']?.validator;
38
const resolver =
39
typeof validator === 'function' ? validator : validator?.request;
40
+
const candidates = [resolver, validatorResolver];
41
for (const candidate of candidates) {
42
const statements = candidate?.(args);
43
if (statements === null) return;
···
79
const validator = plugin.config['~resolvers']?.validator;
80
const resolver =
81
typeof validator === 'function' ? validator : validator?.response;
82
+
const candidates = [resolver, validatorResolver];
83
for (const candidate of candidates) {
84
const statements = candidate?.(args);
85
if (statements === null) return;