fork of hey-api/openapi-ts because I need some additional things

refactor: clean up valibot resolver interface

Lubos edf99ed8 497f219e

Changed files
+97 -82
dev
packages
openapi-ts
src
plugins
+15 -13
dev/openapi-ts.config.ts
··· 431 }, 432 }, 433 '~resolvers': { 434 - number(ctx) { 435 - const { $, plugin, symbols } = ctx; 436 - const { v } = symbols; 437 - // ctx.nodes.base = () => { 438 - // // implement custom base number resolver 439 - // } 440 - const big = plugin.symbolOnce('Big', { 441 - external: 'big.js', 442 - importKind: 'default', 443 - }); 444 - return $(v).attr('instance').call(big); 445 - }, 446 // object(ctx) { 447 // const { $ } = ctx; 448 // const additional = ctx.nodes.additionalProperties(ctx); ··· 458 // ctx.nodes.format = () => $('v').attr('isoDateTime').call(); 459 // } 460 // }, 461 - // validator({ $, plugin, schema, v }) { 462 // const vShadow = plugin.symbol('v'); 463 // const test = plugin.symbol('test'); 464 // const e = plugin.symbol('err');
··· 431 }, 432 }, 433 '~resolvers': { 434 + // number(ctx) { 435 + // const { $, plugin, symbols } = ctx; 436 + // const { v } = symbols; 437 + // // ctx.nodes.base = () => { 438 + // // // implement custom base number resolver 439 + // // } 440 + // const big = plugin.symbolOnce('Big', { 441 + // external: 'big.js', 442 + // importKind: 'default', 443 + // }); 444 + // return $(v).attr('instance').call(big); 445 + // }, 446 // object(ctx) { 447 // const { $ } = ctx; 448 // const additional = ctx.nodes.additionalProperties(ctx); ··· 458 // ctx.nodes.format = () => $('v').attr('isoDateTime').call(); 459 // } 460 // }, 461 + // validator(ctx) { 462 + // const { $, plugin, symbols } = ctx; 463 + // const { schema, v } = symbols; 464 // const vShadow = plugin.symbol('v'); 465 // const test = plugin.symbol('test'); 466 // const e = plugin.symbol('err');
+6 -6
packages/openapi-ts/src/plugins/valibot/shared/pipes.ts
··· 33 }; 34 35 export interface PipesUtils { 36 push: PushPipes; 37 toNode: PipesToNode; 38 } 39 ··· 41 * Functions for working with pipes. 42 */ 43 export const pipes: PipesUtils = { 44 - /** 45 - * Push pipes into target array. 46 - */ 47 push: pushPipes, 48 - /** 49 - * Convert pipes to a single node. 50 - */ 51 toNode: pipesToNode, 52 };
··· 33 }; 34 35 export interface PipesUtils { 36 + /** 37 + * Push pipes into target array. 38 + */ 39 push: PushPipes; 40 + /** 41 + * Convert pipes to a single node. 42 + */ 43 toNode: PipesToNode; 44 } 45 ··· 47 * Functions for working with pipes. 48 */ 49 export const pipes: PipesUtils = { 50 push: pushPipes, 51 toNode: pipesToNode, 52 };
+34 -30
packages/openapi-ts/src/plugins/valibot/types.d.ts
··· 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'; ··· 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'; ··· 328 }; 329 }; 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 */ ··· 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 */ ··· 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 */ ··· 412 pattern: (ctx: StringResolverContext) => PipeResult | undefined; 413 }; 414 schema: SchemaWithType<'string'>; 415 - }; 416 417 - export type ValidatorResolverArgs = SharedResolverArgs & { 418 operation: IR.Operation; 419 - schema: Symbol; 420 - }; 421 422 type ValidatorResolver = ( 423 - args: ValidatorResolverArgs, 424 - ) => MaybeArray<TsDsl<ts.Statement>> | null | undefined; 425 426 type Resolvers = Plugin.Resolvers<{ 427 /** ··· 455 * 456 * Example path: `~resolvers.validator.request` or `~resolvers.validator.response` 457 * 458 - * Returning `undefined` from a resolver will apply the default generation logic. 459 */ 460 validator?: 461 | ValidatorResolver ··· 463 /** 464 * Controls how the request validator function body is generated. 465 * 466 - * Returning `undefined` will fall back to the default `.await().return()` logic. 467 */ 468 request?: ValidatorResolver; 469 /** 470 * Controls how the response validator function body is generated. 471 * 472 - * Returning `undefined` will fall back to the default `.await().return()` logic. 473 */ 474 response?: ValidatorResolver; 475 };
··· 1 import type { Refs, Symbol } from '@hey-api/codegen-core'; 2 3 import type { IR } from '~/ir/types'; 4 import type { DefinePlugin, Plugin, SchemaWithType } from '~/plugins'; ··· 7 ShouldCoerceToBigInt, 8 } from '~/plugins/shared/utils/coerce'; 9 import type { GetIntegerLimit } from '~/plugins/shared/utils/formats'; 10 + import type { $, DollarTsDsl } from '~/ts-dsl'; 11 import type { StringCase, StringName } from '~/types/case'; 12 13 import type { IApi } from './api'; 14 import type { Pipe, PipeResult, PipesUtils } from './shared/pipes'; ··· 326 }; 327 }; 328 329 + interface BaseResolverContext extends DollarTsDsl { 330 /** 331 * Functions for working with pipes. 332 */ 333 + pipes: PipesUtils & { 334 + /** 335 + * The current builder state being processed by this resolver. 336 + * 337 + * In Valibot, this represents the current list of call expressions ("pipes") 338 + * being assembled to form a schema definition. 339 + * 340 + * Each pipe can be extended, modified, or replaced to customize how the 341 + * resulting schema is constructed. 342 + */ 343 + current: Pipes; 344 + }; 345 plugin: ValibotPlugin['Instance']; 346 /** 347 * Provides access to commonly used symbols within the Valibot plugin. 348 */ 349 symbols: { 350 v: Symbol; 351 }; 352 + } 353 354 + export interface NumberResolverContext extends BaseResolverContext { 355 /** 356 * Nodes used to build different parts of the number schema. 357 */ ··· 370 maybeBigInt: MaybeBigInt; 371 shouldCoerceToBigInt: ShouldCoerceToBigInt; 372 }; 373 + } 374 375 + export interface ObjectResolverContext extends BaseResolverContext { 376 /** 377 * Nodes used to build different parts of the object schema. 378 */ ··· 395 ast: Partial<Omit<Ast, 'typeName'>>; 396 state: Refs<PluginState>; 397 }; 398 + } 399 400 + export interface StringResolverContext extends BaseResolverContext { 401 /** 402 * Nodes used to build different parts of the string schema. 403 */ ··· 411 pattern: (ctx: StringResolverContext) => PipeResult | undefined; 412 }; 413 schema: SchemaWithType<'string'>; 414 + } 415 416 + export interface ValidatorResolverContext extends BaseResolverContext { 417 operation: IR.Operation; 418 + /** 419 + * Provides access to commonly used symbols within the Valibot plugin. 420 + */ 421 + symbols: BaseResolverContext['symbols'] & { 422 + schema: Symbol; 423 + }; 424 + } 425 426 type ValidatorResolver = ( 427 + args: ValidatorResolverContext, 428 + ) => PipeResult | null | undefined; 429 430 type Resolvers = Plugin.Resolvers<{ 431 /** ··· 459 * 460 * Example path: `~resolvers.validator.request` or `~resolvers.validator.response` 461 * 462 + * Returning `undefined` will execute the default resolver logic. 463 */ 464 validator?: 465 | ValidatorResolver ··· 467 /** 468 * Controls how the request validator function body is generated. 469 * 470 + * Returning `undefined` will execute the default resolver logic. 471 */ 472 request?: ValidatorResolver; 473 /** 474 * Controls how the response validator function body is generated. 475 * 476 + * Returning `undefined` will execute the default resolver logic. 477 */ 478 response?: ValidatorResolver; 479 };
+17 -14
packages/openapi-ts/src/plugins/valibot/v1/api.ts
··· 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, symbols } = ctx; 12 - const { v } = symbols; 13 return $(v) 14 .attr(identifiers.async.parseAsync) 15 .call(schema, 'data') ··· 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 }; ··· 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; 51 if (statements !== undefined) { 52 return $.func() ··· 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 }; ··· 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; 92 if (statements !== undefined) { 93 return $.func()
··· 2 3 import { pipes } from '../shared/pipes'; 4 import type { ValidatorArgs } from '../shared/types'; 5 + import type { ValidatorResolverContext } from '../types'; 6 import { identifiers } from './constants'; 7 8 const validatorResolver = ( 9 + ctx: ValidatorResolverContext, 10 ): ReturnType<typeof $.return> => { 11 + const { schema, v } = ctx.symbols; 12 return $(v) 13 .attr(identifiers.async.parseAsync) 14 .call(schema, 'data') ··· 29 }); 30 if (!symbol) return; 31 32 + const ctx: ValidatorResolverContext = { 33 $, 34 operation, 35 + pipes: { 36 + ...pipes, 37 + current: [], 38 + }, 39 plugin, 40 symbols: { 41 + schema: symbol, 42 v: plugin.external('valibot.v'), 43 }, 44 }; ··· 47 typeof validator === 'function' ? validator : validator?.request; 48 const candidates = [resolver, validatorResolver]; 49 for (const candidate of candidates) { 50 + const statements = candidate?.(ctx); 51 if (statements === null) return; 52 if (statements !== undefined) { 53 return $.func() ··· 72 }); 73 if (!symbol) return; 74 75 + const ctx: ValidatorResolverContext = { 76 $, 77 operation, 78 + pipes: { 79 + ...pipes, 80 + current: [], 81 + }, 82 plugin, 83 symbols: { 84 + schema: symbol, 85 v: plugin.external('valibot.v'), 86 }, 87 }; ··· 90 typeof validator === 'function' ? validator : validator?.response; 91 const candidates = [resolver, validatorResolver]; 92 for (const candidate of candidates) { 93 + const statements = candidate?.(ctx); 94 if (statements === null) return; 95 if (statements !== undefined) { 96 return $.func()
+9 -7
packages/openapi-ts/src/plugins/valibot/v1/toAst/number.ts
··· 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 = ({ ··· 128 max: maxNode, 129 min: minNode, 130 }, 131 - pipes, 132 plugin, 133 - result: [], 134 schema, 135 symbols: { 136 v: plugin.external('valibot.v'),
··· 100 101 function numberResolver(ctx: NumberResolverContext): Pipes { 102 const constNode = ctx.nodes.const(ctx); 103 + if (constNode) return ctx.pipes.push(ctx.pipes.current, constNode); 104 105 const baseNode = ctx.nodes.base(ctx); 106 + if (baseNode) ctx.pipes.push(ctx.pipes.current, baseNode); 107 108 const minNode = ctx.nodes.min(ctx); 109 + if (minNode) ctx.pipes.push(ctx.pipes.current, minNode); 110 111 const maxNode = ctx.nodes.max(ctx); 112 + if (maxNode) ctx.pipes.push(ctx.pipes.current, maxNode); 113 114 + return ctx.pipes.current; 115 } 116 117 export const numberToNode = ({ ··· 128 max: maxNode, 129 min: minNode, 130 }, 131 + pipes: { 132 + ...pipes, 133 + current: [], 134 + }, 135 plugin, 136 schema, 137 symbols: { 138 v: plugin.external('valibot.v'),
+4 -2
packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts
··· 98 base: baseNode, 99 shape: shapeNode, 100 }, 101 - pipes, 102 plugin, 103 - result: [], 104 schema, 105 symbols: { 106 v: plugin.external('valibot.v'),
··· 98 base: baseNode, 99 shape: shapeNode, 100 }, 101 + pipes: { 102 + ...pipes, 103 + current: [], 104 + }, 105 plugin, 106 schema, 107 symbols: { 108 v: plugin.external('valibot.v'),
+12 -10
packages/openapi-ts/src/plugins/valibot/v1/toAst/string.ts
··· 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 = ({ ··· 122 minLength: minLengthNode, 123 pattern: patternNode, 124 }, 125 - pipes, 126 plugin, 127 - result: [], 128 schema, 129 symbols: { 130 v: plugin.external('valibot.v'),
··· 80 81 function stringResolver(ctx: StringResolverContext): Pipes { 82 const constNode = ctx.nodes.const(ctx); 83 + if (constNode) return ctx.pipes.push(ctx.pipes.current, constNode); 84 85 const baseNode = ctx.nodes.base(ctx); 86 + if (baseNode) ctx.pipes.push(ctx.pipes.current, baseNode); 87 88 const formatNode = ctx.nodes.format(ctx); 89 + if (formatNode) ctx.pipes.push(ctx.pipes.current, formatNode); 90 91 const lengthNode = ctx.nodes.length(ctx); 92 if (lengthNode) { 93 + ctx.pipes.push(ctx.pipes.current, lengthNode); 94 } else { 95 const minLengthNode = ctx.nodes.minLength(ctx); 96 + if (minLengthNode) ctx.pipes.push(ctx.pipes.current, minLengthNode); 97 98 const maxLengthNode = ctx.nodes.maxLength(ctx); 99 + if (maxLengthNode) ctx.pipes.push(ctx.pipes.current, maxLengthNode); 100 } 101 102 const patternNode = ctx.nodes.pattern(ctx); 103 + if (patternNode) ctx.pipes.push(ctx.pipes.current, patternNode); 104 105 + return ctx.pipes.current; 106 } 107 108 export const stringToNode = ({ ··· 122 minLength: minLengthNode, 123 pattern: patternNode, 124 }, 125 + pipes: { 126 + ...pipes, 127 + current: [], 128 + }, 129 plugin, 130 schema, 131 symbols: { 132 v: plugin.external('valibot.v'),