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

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3547 from hey-api/feat/valibot-resolvers

feat: add more resolvers to valibot

authored by

Lubos and committed by
GitHub
7b3771fd 0f79f2bd

+736 -139
+5
.changeset/common-cougars-pump.md
··· 1 + --- 2 + "@hey-api/openapi-ts": patch 3 + --- 4 + 5 + **plugin(valibot)**: provide more resolvers
+198
packages/openapi-ts/src/plugins/valibot/resolvers.ts
··· 10 10 11 11 export type Resolvers = Plugin.Resolvers<{ 12 12 /** 13 + * Resolver for array schemas. 14 + * 15 + * Allows customization of how array types are rendered. 16 + * 17 + * Returning `undefined` will execute the default resolver logic. 18 + */ 19 + array?: (ctx: ArrayResolverContext) => PipeResult; 20 + /** 21 + * Resolver for boolean schemas. 22 + * 23 + * Allows customization of how boolean types are rendered. 24 + * 25 + * Returning `undefined` will execute the default resolver logic. 26 + */ 27 + boolean?: (ctx: BooleanResolverContext) => PipeResult; 28 + /** 13 29 * Resolver for enum schemas. 14 30 * 15 31 * Allows customization of how enum types are rendered. ··· 18 34 */ 19 35 enum?: (ctx: EnumResolverContext) => PipeResult; 20 36 /** 37 + * Resolver for intersection schemas. 38 + * 39 + * Allows customization of how intersection types are rendered. 40 + * 41 + * Returning `undefined` will execute the default resolver logic. 42 + */ 43 + intersection?: (ctx: IntersectionResolverContext) => PipeResult; 44 + /** 45 + * Resolver for never schemas. 46 + * 47 + * Allows customization of how never types are rendered. 48 + * 49 + * Returning `undefined` will execute the default resolver logic. 50 + */ 51 + never?: (ctx: NeverResolverContext) => PipeResult; 52 + /** 53 + * Resolver for null schemas. 54 + * 55 + * Allows customization of how null types are rendered. 56 + * 57 + * Returning `undefined` will execute the default resolver logic. 58 + */ 59 + null?: (ctx: NullResolverContext) => PipeResult; 60 + /** 21 61 * Resolver for number schemas. 22 62 * 23 63 * Allows customization of how number types are rendered. ··· 42 82 */ 43 83 string?: (ctx: StringResolverContext) => PipeResult; 44 84 /** 85 + * Resolver for tuple schemas. 86 + * 87 + * Allows customization of how tuple types are rendered. 88 + * 89 + * Returning `undefined` will execute the default resolver logic. 90 + */ 91 + tuple?: (ctx: TupleResolverContext) => PipeResult; 92 + /** 93 + * Resolver for undefined schemas. 94 + * 95 + * Allows customization of how undefined types are rendered. 96 + * 97 + * Returning `undefined` will execute the default resolver logic. 98 + */ 99 + undefined?: (ctx: UndefinedResolverContext) => PipeResult; 100 + /** 101 + * Resolver for union schemas. 102 + * 103 + * Allows customization of how union types are rendered. 104 + * 105 + * Returning `undefined` will execute the default resolver logic. 106 + */ 107 + union?: (ctx: UnionResolverContext) => PipeResult; 108 + /** 109 + * Resolver for unknown schemas. 110 + * 111 + * Allows customization of how unknown types are rendered. 112 + * 113 + * Returning `undefined` will execute the default resolver logic. 114 + */ 115 + unknown?: (ctx: UnknownResolverContext) => PipeResult; 116 + /** 45 117 * Resolvers for request and response validators. 46 118 * 47 119 * Allow customization of validator function bodies. ··· 66 138 */ 67 139 response?: ValidatorResolver; 68 140 }; 141 + /** 142 + * Resolver for void schemas. 143 + * 144 + * Allows customization of how void types are rendered. 145 + * 146 + * Returning `undefined` will execute the default resolver logic. 147 + */ 148 + void?: (ctx: VoidResolverContext) => PipeResult; 69 149 }>; 70 150 71 151 type ValidatorResolver = (ctx: ValidatorResolverContext) => PipeResult | null | undefined; ··· 96 176 }; 97 177 } 98 178 179 + export interface ArrayResolverContext extends BaseContext { 180 + applyModifiers: (result: ValibotResult, opts?: { optional?: boolean }) => ValibotFinal; 181 + /** 182 + * Nodes used to build different parts of the result. 183 + */ 184 + nodes: { 185 + base: (ctx: ArrayResolverContext) => PipeResult; 186 + length: (ctx: ArrayResolverContext) => PipeResult; 187 + maxLength: (ctx: ArrayResolverContext) => PipeResult; 188 + minLength: (ctx: ArrayResolverContext) => PipeResult; 189 + }; 190 + schema: SchemaWithType<'array'>; 191 + walk: Walker<ValibotResult, ValibotPlugin['Instance']>; 192 + walkerCtx: SchemaVisitorContext<ValibotPlugin['Instance']>; 193 + } 194 + 195 + export interface BooleanResolverContext extends BaseContext { 196 + /** 197 + * Nodes used to build different parts of the result. 198 + */ 199 + nodes: { 200 + base: (ctx: BooleanResolverContext) => PipeResult; 201 + const: (ctx: BooleanResolverContext) => PipeResult; 202 + }; 203 + schema: SchemaWithType<'boolean'>; 204 + } 205 + 99 206 export interface EnumResolverContext extends BaseContext { 100 207 /** 101 208 * Nodes used to build different parts of the result. ··· 122 229 schema: SchemaWithType<'enum'>; 123 230 } 124 231 232 + export interface IntersectionResolverContext extends BaseContext { 233 + applyModifiers: (result: ValibotResult, opts?: { optional?: boolean }) => ValibotFinal; 234 + childResults: Array<ValibotResult>; 235 + /** 236 + * Nodes used to build different parts of the result. 237 + */ 238 + nodes: { 239 + base: (ctx: IntersectionResolverContext) => PipeResult; 240 + }; 241 + parentSchema: IR.SchemaObject; 242 + schema: IR.SchemaObject; 243 + } 244 + 245 + export interface NeverResolverContext extends BaseContext { 246 + /** 247 + * Nodes used to build different parts of the result. 248 + */ 249 + nodes: { 250 + base: (ctx: NeverResolverContext) => PipeResult; 251 + }; 252 + schema: SchemaWithType<'never'>; 253 + } 254 + 255 + export interface NullResolverContext extends BaseContext { 256 + /** 257 + * Nodes used to build different parts of the result. 258 + */ 259 + nodes: { 260 + base: (ctx: NullResolverContext) => PipeResult; 261 + }; 262 + schema: SchemaWithType<'null'>; 263 + } 264 + 125 265 export interface NumberResolverContext extends BaseContext { 126 266 /** 127 267 * Nodes used to build different parts of the result. ··· 173 313 pattern: (ctx: StringResolverContext) => PipeResult; 174 314 }; 175 315 schema: SchemaWithType<'string'>; 316 + } 317 + 318 + export interface TupleResolverContext extends BaseContext { 319 + applyModifiers: (result: ValibotResult, opts?: { optional?: boolean }) => ValibotFinal; 320 + /** 321 + * Nodes used to build different parts of the result. 322 + */ 323 + nodes: { 324 + base: (ctx: TupleResolverContext) => PipeResult; 325 + const: (ctx: TupleResolverContext) => PipeResult; 326 + }; 327 + schema: SchemaWithType<'tuple'>; 328 + walk: Walker<ValibotResult, ValibotPlugin['Instance']>; 329 + walkerCtx: SchemaVisitorContext<ValibotPlugin['Instance']>; 330 + } 331 + 332 + export interface UndefinedResolverContext extends BaseContext { 333 + /** 334 + * Nodes used to build different parts of the result. 335 + */ 336 + nodes: { 337 + base: (ctx: UndefinedResolverContext) => PipeResult; 338 + }; 339 + schema: SchemaWithType<'undefined'>; 340 + } 341 + 342 + export interface UnionResolverContext extends BaseContext { 343 + applyModifiers: (result: ValibotResult, opts?: { optional?: boolean }) => ValibotFinal; 344 + childResults: Array<ValibotResult>; 345 + /** 346 + * Nodes used to build different parts of the result. 347 + */ 348 + nodes: { 349 + base: (ctx: UnionResolverContext) => PipeResult; 350 + }; 351 + parentSchema: IR.SchemaObject; 352 + schema: IR.SchemaObject; 353 + schemas: ReadonlyArray<IR.SchemaObject>; 354 + } 355 + 356 + export interface UnknownResolverContext extends BaseContext { 357 + /** 358 + * Nodes used to build different parts of the result. 359 + */ 360 + nodes: { 361 + base: (ctx: UnknownResolverContext) => PipeResult; 362 + }; 363 + schema: SchemaWithType<'unknown'>; 364 + } 365 + 366 + export interface VoidResolverContext extends BaseContext { 367 + /** 368 + * Nodes used to build different parts of the result. 369 + */ 370 + nodes: { 371 + base: (ctx: VoidResolverContext) => PipeResult; 372 + }; 373 + schema: SchemaWithType<'void'>; 176 374 } 177 375 178 376 export interface ValidatorResolverContext extends BaseContext {
+2 -2
packages/openapi-ts/src/plugins/valibot/shared/pipes.ts
··· 61 61 * 62 62 * Re-exported for backward compatibility. 63 63 */ 64 - export function pipesToNode(p: Pipes, plugin: ValibotPlugin['Instance']): Pipe { 65 - return toNode(p, plugin); 64 + export function pipesToNode(pipes: Pipes | Pipe, plugin: ValibotPlugin['Instance']): Pipe { 65 + return toNode(pipes, plugin); 66 66 }
+107 -30
packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts
··· 2 2 import { childContext, deduplicateSchema } from '@hey-api/shared'; 3 3 4 4 import { $ } from '../../../../ts-dsl'; 5 - import type { Pipes } from '../../shared/pipes'; 6 - import { pipesToNode } from '../../shared/pipes'; 5 + import type { ArrayResolverContext } from '../../resolvers'; 6 + import type { PipeResult, Pipes } from '../../shared/pipes'; 7 + import { pipes } from '../../shared/pipes'; 7 8 import type { CompositeHandlerResult, ValibotFinal, ValibotResult } from '../../shared/types'; 8 9 import type { ValibotPlugin } from '../../types'; 9 10 import { identifiers } from '../constants'; ··· 17 18 walkerCtx: SchemaVisitorContext<ValibotPlugin['Instance']>; 18 19 } 19 20 20 - export function arrayToPipes(ctx: ArrayToPipesContext): CompositeHandlerResult { 21 - const { plugin, walk, walkerCtx } = ctx; 22 - let { schema } = ctx; 21 + function baseNode(ctx: ArrayResolverContext): PipeResult { 22 + const { plugin, symbols } = ctx; 23 + const { v } = symbols; 23 24 24 - const v = plugin.external('valibot.v'); 25 25 const arrayFn = $(v).attr(identifiers.schemas.array); 26 + 27 + let { schema: normalizedSchema } = ctx; 28 + if (normalizedSchema.items) { 29 + normalizedSchema = deduplicateSchema({ schema: normalizedSchema }); 30 + } 31 + 32 + if (!normalizedSchema.items) { 33 + return arrayFn.call(unknownToPipes({ plugin })); 34 + } 35 + 26 36 const childResults: Array<ValibotResult> = []; 27 - const resultPipes: Pipes = []; 37 + const { applyModifiers, pipes, walk, walkerCtx } = ctx; 38 + 39 + for (let i = 0; i < normalizedSchema.items!.length; i++) { 40 + const item = normalizedSchema.items![i]!; 41 + const result = walk!(item, childContext(walkerCtx!, 'items', i)); 42 + childResults.push(result); 43 + } 44 + 45 + if (childResults.length === 1) { 46 + const itemNode = pipes.toNode(applyModifiers!(childResults[0]!).pipes, plugin); 47 + return arrayFn.call(itemNode); 48 + } 49 + 50 + return arrayFn.call(unknownToPipes({ plugin })); 51 + } 52 + 53 + function lengthNode(ctx: ArrayResolverContext): PipeResult { 54 + const { schema, symbols } = ctx; 55 + const { v } = symbols; 56 + if (schema.minItems === schema.maxItems && schema.minItems !== undefined) { 57 + return $(v).attr(identifiers.actions.length).call($.fromValue(schema.minItems)); 58 + } 59 + } 28 60 29 - if (!schema.items) { 30 - resultPipes.push(arrayFn.call(unknownToPipes({ plugin }))); 61 + function maxLengthNode(ctx: ArrayResolverContext): PipeResult { 62 + const { schema, symbols } = ctx; 63 + const { v } = symbols; 64 + if (schema.maxItems === undefined) return; 65 + return $(v).attr(identifiers.actions.maxLength).call($.fromValue(schema.maxItems)); 66 + } 67 + 68 + function minLengthNode(ctx: ArrayResolverContext): PipeResult { 69 + const { schema, symbols } = ctx; 70 + const { v } = symbols; 71 + if (schema.minItems === undefined) return; 72 + return $(v).attr(identifiers.actions.minLength).call($.fromValue(schema.minItems)); 73 + } 74 + 75 + function arrayResolver(ctx: ArrayResolverContext): Pipes { 76 + const baseResult = ctx.nodes.base(ctx); 77 + if (baseResult) { 78 + ctx.pipes.push(ctx.pipes.current, baseResult); 79 + } 80 + 81 + const lengthResult = ctx.nodes.length(ctx); 82 + if (lengthResult) { 83 + ctx.pipes.push(ctx.pipes.current, lengthResult); 31 84 } else { 32 - schema = deduplicateSchema({ schema }); 33 - 34 - for (let i = 0; i < schema.items!.length; i++) { 35 - const item = schema.items![i]!; 36 - const result = walk(item, childContext(walkerCtx, 'items', i)); 37 - childResults.push(result); 85 + const minLengthResult = ctx.nodes.minLength(ctx); 86 + if (minLengthResult) { 87 + ctx.pipes.push(ctx.pipes.current, minLengthResult); 38 88 } 39 89 40 - if (childResults.length === 1) { 41 - const itemNode = pipesToNode(ctx.applyModifiers(childResults[0]!).pipes, plugin); 42 - resultPipes.push(arrayFn.call(itemNode)); 43 - } else { 44 - // TODO: handle intersection/union properly 45 - resultPipes.push(arrayFn.call(unknownToPipes({ plugin }))); 90 + const maxLengthResult = ctx.nodes.maxLength(ctx); 91 + if (maxLengthResult) { 92 + ctx.pipes.push(ctx.pipes.current, maxLengthResult); 46 93 } 47 94 } 48 95 49 - if (schema.minItems === schema.maxItems && schema.minItems !== undefined) { 50 - resultPipes.push($(v).attr(identifiers.actions.length).call($.fromValue(schema.minItems))); 51 - } else { 52 - if (schema.minItems !== undefined) { 53 - resultPipes.push($(v).attr(identifiers.actions.minLength).call($.fromValue(schema.minItems))); 54 - } 55 - if (schema.maxItems !== undefined) { 56 - resultPipes.push($(v).attr(identifiers.actions.maxLength).call($.fromValue(schema.maxItems))); 96 + return ctx.pipes.current; 97 + } 98 + 99 + export function arrayToPipes(ctx: ArrayToPipesContext): CompositeHandlerResult { 100 + const { plugin, schema, walk, walkerCtx } = ctx; 101 + const childResults: Array<ValibotResult> = []; 102 + 103 + if (schema.items) { 104 + const normalizedSchema = deduplicateSchema({ schema }); 105 + for (let i = 0; i < normalizedSchema.items!.length; i++) { 106 + const item = normalizedSchema.items![i]!; 107 + const result = walk(item, childContext(walkerCtx, 'items', i)); 108 + childResults.push(result); 57 109 } 58 110 } 59 111 112 + const resolverCtx: ArrayResolverContext = { 113 + $, 114 + applyModifiers: ctx.applyModifiers, 115 + nodes: { 116 + base: baseNode, 117 + length: lengthNode, 118 + maxLength: maxLengthNode, 119 + minLength: minLengthNode, 120 + }, 121 + pipes: { 122 + ...pipes, 123 + current: [], 124 + }, 125 + plugin, 126 + schema, 127 + symbols: { 128 + v: plugin.external('valibot.v'), 129 + }, 130 + walk, 131 + walkerCtx, 132 + }; 133 + 134 + const resolver = plugin.config['~resolvers']?.array; 135 + const node = resolver?.(resolverCtx) ?? arrayResolver(resolverCtx); 136 + 60 137 return { 61 138 childResults, 62 - pipes: resultPipes, 139 + pipes: [resolverCtx.pipes.toNode(node, plugin)], 63 140 }; 64 141 }
+49 -7
packages/openapi-ts/src/plugins/valibot/v1/toAst/boolean.ts
··· 1 1 import type { SchemaWithType } from '@hey-api/shared'; 2 2 3 3 import { $ } from '../../../../ts-dsl'; 4 - import type { Pipe } from '../../shared/pipes'; 4 + import type { BooleanResolverContext } from '../../resolvers'; 5 + import type { Pipe, PipeResult, Pipes } from '../../shared/pipes'; 6 + import { pipes } from '../../shared/pipes'; 5 7 import type { ValibotPlugin } from '../../types'; 6 8 import { identifiers } from '../constants'; 7 9 10 + function baseNode(ctx: BooleanResolverContext): PipeResult { 11 + const { symbols } = ctx; 12 + const { v } = symbols; 13 + return $(v).attr(identifiers.schemas.boolean).call(); 14 + } 15 + 16 + function constNode(ctx: BooleanResolverContext): PipeResult { 17 + const { schema, symbols } = ctx; 18 + const { v } = symbols; 19 + if (typeof schema.const !== 'boolean') return; 20 + return $(v).attr(identifiers.schemas.literal).call($.literal(schema.const)); 21 + } 22 + 23 + function booleanResolver(ctx: BooleanResolverContext): Pipes { 24 + const constResult = ctx.nodes.const(ctx); 25 + if (constResult) { 26 + return ctx.pipes.push(ctx.pipes.current, constResult); 27 + } 28 + 29 + const baseResult = ctx.nodes.base(ctx); 30 + if (baseResult) { 31 + ctx.pipes.push(ctx.pipes.current, baseResult); 32 + } 33 + 34 + return ctx.pipes.current; 35 + } 36 + 8 37 export function booleanToPipes({ 9 38 plugin, 10 39 schema, ··· 12 41 plugin: ValibotPlugin['Instance']; 13 42 schema: SchemaWithType<'boolean'>; 14 43 }): Pipe { 15 - const v = plugin.external('valibot.v'); 16 - 17 - if (typeof schema.const === 'boolean') { 18 - return $(v).attr(identifiers.schemas.literal).call($.literal(schema.const)); 19 - } 44 + const ctx: BooleanResolverContext = { 45 + $, 46 + nodes: { 47 + base: baseNode, 48 + const: constNode, 49 + }, 50 + pipes: { 51 + ...pipes, 52 + current: [], 53 + }, 54 + plugin, 55 + schema, 56 + symbols: { 57 + v: plugin.external('valibot.v'), 58 + }, 59 + }; 20 60 21 - return $(v).attr(identifiers.schemas.boolean).call(); 61 + const resolver = plugin.config['~resolvers']?.boolean; 62 + const node = resolver?.(ctx) ?? booleanResolver(ctx); 63 + return ctx.pipes.toNode(node, plugin); 22 64 }
+57 -23
packages/openapi-ts/src/plugins/valibot/v1/toAst/intersection.ts
··· 1 1 import type { IR } from '@hey-api/shared'; 2 2 3 3 import { $ } from '../../../../ts-dsl'; 4 - import type { Pipes } from '../../shared/pipes'; 5 - import { pipesToNode } from '../../shared/pipes'; 4 + import type { IntersectionResolverContext } from '../../resolvers'; 5 + import type { PipeResult, Pipes } from '../../shared/pipes'; 6 + import { pipes, pipesToNode } from '../../shared/pipes'; 6 7 import type { CompositeHandlerResult, ValibotFinal, ValibotResult } from '../../shared/types'; 7 8 import type { ValibotPlugin } from '../../types'; 8 9 import { identifiers } from '../constants'; 9 10 10 - interface IntersectionToPipesContext { 11 + function baseNode(ctx: IntersectionResolverContext): PipeResult { 12 + const { applyModifiers, childResults, plugin, symbols } = ctx; 13 + const { v } = symbols; 14 + 15 + if (childResults.length === 0) { 16 + return $(v).attr(identifiers.schemas.any).call(); 17 + } 18 + 19 + if (childResults.length === 1) { 20 + const finalResult = applyModifiers!(childResults[0]!); 21 + return finalResult.pipes; 22 + } 23 + 24 + const itemNodes = childResults.map((item) => pipesToNode(item.pipes, plugin)); 25 + return $(v) 26 + .attr(identifiers.schemas.intersect) 27 + .call($.array(...itemNodes)); 28 + } 29 + 30 + function intersectionResolver(ctx: IntersectionResolverContext): Pipes { 31 + const base = ctx.nodes.base(ctx); 32 + if (base) { 33 + ctx.pipes.push(ctx.pipes.current, base); 34 + } 35 + return ctx.pipes.current; 36 + } 37 + 38 + export function intersectionToPipes(ctx: { 11 39 applyModifiers: (result: ValibotResult, options?: { optional?: boolean }) => ValibotFinal; 12 40 childResults: Array<ValibotResult>; 13 41 parentSchema: IR.SchemaObject; 14 42 plugin: ValibotPlugin['Instance']; 15 - } 16 - 17 - export function intersectionToPipes(ctx: IntersectionToPipesContext): CompositeHandlerResult { 18 - const { applyModifiers, childResults, plugin } = ctx; 43 + }): CompositeHandlerResult { 44 + const { applyModifiers, childResults, parentSchema, plugin } = ctx; 19 45 20 - const v = plugin.external('valibot.v'); 21 - let pipes: Pipes; 46 + const resolverCtx: IntersectionResolverContext = { 47 + $, 48 + applyModifiers, 49 + childResults, 50 + nodes: { 51 + base: baseNode, 52 + }, 53 + parentSchema, 54 + pipes: { 55 + ...pipes, 56 + current: [], 57 + }, 58 + plugin, 59 + schema: parentSchema, 60 + symbols: { 61 + v: plugin.external('valibot.v'), 62 + }, 63 + }; 22 64 23 - if (childResults.length === 0) { 24 - pipes = [$(v).attr(identifiers.schemas.any).call()]; 25 - } else if (childResults.length === 1) { 26 - const finalResult = applyModifiers(childResults[0]!); 27 - pipes = finalResult.pipes; 28 - } else { 29 - const itemNodes = childResults.map((item) => pipesToNode(item.pipes, plugin)); 30 - pipes = [ 31 - $(v) 32 - .attr(identifiers.schemas.intersect) 33 - .call($.array(...itemNodes)), 34 - ]; 35 - } 65 + const resolver = plugin.config['~resolvers']?.intersection; 66 + const node = resolver?.(resolverCtx) ?? intersectionResolver(resolverCtx); 36 67 37 - return { childResults, pipes }; 68 + return { 69 + childResults, 70 + pipes: [resolverCtx.pipes.toNode(node, plugin)], 71 + }; 38 72 }
+35 -3
packages/openapi-ts/src/plugins/valibot/v1/toAst/never.ts
··· 1 1 import type { SchemaWithType } from '@hey-api/shared'; 2 2 3 3 import { $ } from '../../../../ts-dsl'; 4 - import type { Pipe } from '../../shared/pipes'; 4 + import type { NeverResolverContext } from '../../resolvers'; 5 + import type { Pipe, PipeResult, Pipes } from '../../shared/pipes'; 6 + import { pipes } from '../../shared/pipes'; 5 7 import type { ValibotPlugin } from '../../types'; 6 8 import { identifiers } from '../constants'; 7 9 10 + function baseNode(ctx: NeverResolverContext): PipeResult { 11 + const { symbols } = ctx; 12 + const { v } = symbols; 13 + return $(v).attr(identifiers.schemas.never).call(); 14 + } 15 + 16 + function neverResolver(ctx: NeverResolverContext): Pipes { 17 + const base = ctx.nodes.base(ctx); 18 + ctx.pipes.push(ctx.pipes.current, base); 19 + return ctx.pipes.current; 20 + } 21 + 8 22 export function neverToPipes({ 9 23 plugin, 24 + schema, 10 25 }: { 11 26 plugin: ValibotPlugin['Instance']; 12 27 schema: SchemaWithType<'never'>; 13 28 }): Pipe { 14 - const v = plugin.external('valibot.v'); 15 - return $(v).attr(identifiers.schemas.never).call(); 29 + const ctx: NeverResolverContext = { 30 + $, 31 + nodes: { 32 + base: baseNode, 33 + }, 34 + pipes: { 35 + ...pipes, 36 + current: [], 37 + }, 38 + plugin, 39 + schema, 40 + symbols: { 41 + v: plugin.external('valibot.v'), 42 + }, 43 + }; 44 + 45 + const resolver = plugin.config['~resolvers']?.never; 46 + const node = resolver?.(ctx) ?? neverResolver(ctx); 47 + return ctx.pipes.toNode(node, plugin); 16 48 }
+35 -3
packages/openapi-ts/src/plugins/valibot/v1/toAst/null.ts
··· 1 1 import type { SchemaWithType } from '@hey-api/shared'; 2 2 3 3 import { $ } from '../../../../ts-dsl'; 4 - import type { Pipe } from '../../shared/pipes'; 4 + import type { NullResolverContext } from '../../resolvers'; 5 + import type { Pipe, PipeResult, Pipes } from '../../shared/pipes'; 6 + import { pipes } from '../../shared/pipes'; 5 7 import type { ValibotPlugin } from '../../types'; 6 8 import { identifiers } from '../constants'; 7 9 10 + function baseNode(ctx: NullResolverContext): PipeResult { 11 + const { symbols } = ctx; 12 + const { v } = symbols; 13 + return $(v).attr(identifiers.schemas.null).call(); 14 + } 15 + 16 + function nullResolver(ctx: NullResolverContext): Pipes { 17 + const base = ctx.nodes.base(ctx); 18 + ctx.pipes.push(ctx.pipes.current, base); 19 + return ctx.pipes.current; 20 + } 21 + 8 22 export function nullToPipes({ 9 23 plugin, 24 + schema, 10 25 }: { 11 26 plugin: ValibotPlugin['Instance']; 12 27 schema: SchemaWithType<'null'>; 13 28 }): Pipe { 14 - const v = plugin.external('valibot.v'); 15 - return $(v).attr(identifiers.schemas.null).call(); 29 + const ctx: NullResolverContext = { 30 + $, 31 + nodes: { 32 + base: baseNode, 33 + }, 34 + pipes: { 35 + ...pipes, 36 + current: [], 37 + }, 38 + plugin, 39 + schema, 40 + symbols: { 41 + v: plugin.external('valibot.v'), 42 + }, 43 + }; 44 + 45 + const resolver = plugin.config['~resolvers']?.null; 46 + const node = resolver?.(ctx) ?? nullResolver(ctx); 47 + return ctx.pipes.toNode(node, plugin); 16 48 }
+8 -8
packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts
··· 3 3 import { $ } from '../../../../ts-dsl'; 4 4 import type { ObjectResolverContext } from '../../resolvers'; 5 5 import type { Pipe, Pipes } from '../../shared/pipes'; 6 - import { pipes, pipesToNode } from '../../shared/pipes'; 6 + import { pipes } from '../../shared/pipes'; 7 7 import type { CompositeHandlerResult, ValibotResult } from '../../shared/types'; 8 8 import { identifiers } from '../constants'; 9 9 10 10 function additionalPropertiesNode(ctx: ObjectResolverContext): Pipe | null | undefined { 11 - const { schema } = ctx; 11 + const { pipes, schema } = ctx; 12 12 13 13 if (!schema.additionalProperties || !schema.additionalProperties.type) return; 14 14 if (schema.additionalProperties.type === 'never') return null; ··· 19 19 ); 20 20 ctx._childResults.push(additionalResult); 21 21 22 - return pipesToNode(additionalResult.pipes, ctx.plugin); 22 + return pipes.toNode(additionalResult.pipes, ctx.plugin); 23 23 } 24 24 25 25 function baseNode(ctx: ObjectResolverContext): Pipes | Pipe { ··· 51 51 } 52 52 53 53 function shapeNode(ctx: ObjectResolverContext): ReturnType<typeof $.object> { 54 - const { schema } = ctx; 54 + const { pipes, schema } = ctx; 55 55 const shape = $.object().pretty(); 56 56 57 57 for (const name in schema.properties) { ··· 62 62 ctx._childResults.push(propertyResult); 63 63 64 64 const finalExpr = ctx.applyModifiers(propertyResult, { optional: isOptional }); 65 - shape.prop(name, pipesToNode(finalExpr.pipes, ctx.plugin)); 65 + shape.prop(name, pipes.toNode(finalExpr.pipes, ctx.plugin)); 66 66 } 67 67 68 68 return shape; ··· 75 75 76 76 const childResults: Array<ValibotResult> = []; 77 77 78 - const extendedCtx: ObjectResolverContext = { 78 + const resolverCtx: ObjectResolverContext = { 79 79 $, 80 80 _childResults: childResults, 81 81 applyModifiers, ··· 98 98 }; 99 99 100 100 const resolver = plugin.config['~resolvers']?.object; 101 - const node = resolver?.(extendedCtx) ?? objectResolver(extendedCtx); 101 + const node = resolver?.(resolverCtx) ?? objectResolver(resolverCtx); 102 102 103 103 return { 104 104 childResults, 105 - pipes: [extendedCtx.pipes.toNode(node, plugin)], 105 + pipes: [resolverCtx.pipes.toNode(node, plugin)], 106 106 }; 107 107 }
+77 -28
packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts
··· 2 2 import { childContext } from '@hey-api/shared'; 3 3 4 4 import { $ } from '../../../../ts-dsl'; 5 - import { pipesToNode } from '../../shared/pipes'; 5 + import type { TupleResolverContext } from '../../resolvers'; 6 + import type { PipeResult, Pipes } from '../../shared/pipes'; 7 + import { pipes } from '../../shared/pipes'; 6 8 import type { CompositeHandlerResult, ValibotFinal, ValibotResult } from '../../shared/types'; 7 9 import type { ValibotPlugin } from '../../types'; 8 10 import { identifiers } from '../constants'; ··· 16 18 walkerCtx: SchemaVisitorContext<ValibotPlugin['Instance']>; 17 19 } 18 20 19 - export function tupleToPipes(ctx: TupleToPipesContext): CompositeHandlerResult { 20 - const { plugin, schema, walk, walkerCtx } = ctx; 21 + function baseNode(ctx: TupleResolverContext): PipeResult { 22 + const { applyModifiers, pipes, plugin, schema, symbols, walk, walkerCtx } = ctx; 21 23 22 - const v = plugin.external('valibot.v'); 24 + if (!schema.items) { 25 + return unknownToPipes({ plugin }); 26 + } 27 + 28 + const { v } = symbols; 23 29 const childResults: Array<ValibotResult> = []; 24 30 25 - if (schema.const && Array.isArray(schema.const)) { 26 - const tupleElements = schema.const.map((value) => 27 - $(v).attr(identifiers.schemas.literal).call($.fromValue(value)), 28 - ); 31 + for (let i = 0; i < schema.items.length; i++) { 32 + const item = schema.items[i]!; 33 + const result = walk!(item, childContext(walkerCtx!, 'items', i)); 34 + childResults.push(result); 35 + } 36 + 37 + const tupleElements = childResults.map((r) => pipes.toNode(applyModifiers!(r).pipes, plugin)); 38 + 39 + return $(v) 40 + .attr(identifiers.schemas.tuple) 41 + .call($.array(...tupleElements)); 42 + } 43 + 44 + function constNode(ctx: TupleResolverContext): PipeResult { 45 + const { schema, symbols } = ctx; 46 + const { v } = symbols; 47 + 48 + if (!schema.const || !Array.isArray(schema.const)) return; 49 + 50 + const tupleElements = schema.const.map((value) => 51 + $(v).attr(identifiers.schemas.literal).call($.fromValue(value)), 52 + ); 29 53 30 - return { 31 - childResults: [], 32 - pipes: [ 33 - $(v) 34 - .attr(identifiers.schemas.tuple) 35 - .call($.array(...tupleElements)), 36 - ], 37 - }; 54 + return $(v) 55 + .attr(identifiers.schemas.tuple) 56 + .call($.array(...tupleElements)); 57 + } 58 + 59 + function tupleResolver(ctx: TupleResolverContext): Pipes { 60 + const constResult = ctx.nodes.const(ctx); 61 + if (constResult) { 62 + return ctx.pipes.push(ctx.pipes.current, constResult); 63 + } 64 + 65 + const baseResult = ctx.nodes.base(ctx); 66 + if (baseResult) { 67 + ctx.pipes.push(ctx.pipes.current, baseResult); 38 68 } 39 69 70 + return ctx.pipes.current; 71 + } 72 + 73 + export function tupleToPipes(ctx: TupleToPipesContext): CompositeHandlerResult { 74 + const { plugin, schema, walk, walkerCtx } = ctx; 75 + const childResults: Array<ValibotResult> = []; 76 + 40 77 if (schema.items) { 41 78 for (let i = 0; i < schema.items.length; i++) { 42 79 const item = schema.items[i]!; 43 80 const result = walk(item, childContext(walkerCtx, 'items', i)); 44 81 childResults.push(result); 45 82 } 83 + } 46 84 47 - const tupleElements = childResults.map((r) => pipesToNode(ctx.applyModifiers(r).pipes, plugin)); 85 + const resolverCtx: TupleResolverContext = { 86 + $, 87 + applyModifiers: ctx.applyModifiers, 88 + nodes: { 89 + base: baseNode, 90 + const: constNode, 91 + }, 92 + pipes: { 93 + ...pipes, 94 + current: [], 95 + }, 96 + plugin, 97 + schema, 98 + symbols: { 99 + v: plugin.external('valibot.v'), 100 + }, 101 + walk, 102 + walkerCtx, 103 + }; 48 104 49 - return { 50 - childResults, 51 - pipes: [ 52 - $(v) 53 - .attr(identifiers.schemas.tuple) 54 - .call($.array(...tupleElements)), 55 - ], 56 - }; 57 - } 105 + const resolver = plugin.config['~resolvers']?.tuple; 106 + const node = resolver?.(resolverCtx) ?? tupleResolver(resolverCtx); 58 107 59 108 return { 60 - childResults: [], 61 - pipes: [unknownToPipes({ plugin })], 109 + childResults, 110 + pipes: [resolverCtx.pipes.toNode(node, plugin)], 62 111 }; 63 112 }
+35 -3
packages/openapi-ts/src/plugins/valibot/v1/toAst/undefined.ts
··· 1 1 import type { SchemaWithType } from '@hey-api/shared'; 2 2 3 3 import { $ } from '../../../../ts-dsl'; 4 - import type { Pipe } from '../../shared/pipes'; 4 + import type { UndefinedResolverContext } from '../../resolvers'; 5 + import type { Pipe, PipeResult, Pipes } from '../../shared/pipes'; 6 + import { pipes } from '../../shared/pipes'; 5 7 import type { ValibotPlugin } from '../../types'; 6 8 import { identifiers } from '../constants'; 7 9 10 + function baseNode(ctx: UndefinedResolverContext): PipeResult { 11 + const { symbols } = ctx; 12 + const { v } = symbols; 13 + return $(v).attr(identifiers.schemas.undefined).call(); 14 + } 15 + 16 + function undefinedResolver(ctx: UndefinedResolverContext): Pipes { 17 + const base = ctx.nodes.base(ctx); 18 + ctx.pipes.push(ctx.pipes.current, base); 19 + return ctx.pipes.current; 20 + } 21 + 8 22 export function undefinedToPipes({ 9 23 plugin, 24 + schema, 10 25 }: { 11 26 plugin: ValibotPlugin['Instance']; 12 27 schema: SchemaWithType<'undefined'>; 13 28 }): Pipe { 14 - const v = plugin.external('valibot.v'); 15 - return $(v).attr(identifiers.schemas.undefined).call(); 29 + const ctx: UndefinedResolverContext = { 30 + $, 31 + nodes: { 32 + base: baseNode, 33 + }, 34 + pipes: { 35 + ...pipes, 36 + current: [], 37 + }, 38 + plugin, 39 + schema, 40 + symbols: { 41 + v: plugin.external('valibot.v'), 42 + }, 43 + }; 44 + 45 + const resolver = plugin.config['~resolvers']?.undefined; 46 + const node = resolver?.(ctx) ?? undefinedResolver(ctx); 47 + return ctx.pipes.toNode(node, plugin); 16 48 }
+58 -26
packages/openapi-ts/src/plugins/valibot/v1/toAst/union.ts
··· 1 1 import type { IR } from '@hey-api/shared'; 2 2 3 3 import { $ } from '../../../../ts-dsl'; 4 - import type { Pipes } from '../../shared/pipes'; 5 - import { pipesToNode } from '../../shared/pipes'; 4 + import type { UnionResolverContext } from '../../resolvers'; 5 + import type { PipeResult, Pipes } from '../../shared/pipes'; 6 + import { pipes, pipesToNode } from '../../shared/pipes'; 6 7 import type { CompositeHandlerResult, ValibotFinal, ValibotResult } from '../../shared/types'; 7 8 import type { ValibotPlugin } from '../../types'; 8 9 import { identifiers } from '../constants'; 9 10 10 - interface UnionToPipesContext { 11 - applyModifiers: (result: ValibotResult, options?: { optional?: boolean }) => ValibotFinal; 12 - childResults: Array<ValibotResult>; 13 - parentSchema: IR.SchemaObject; 14 - plugin: ValibotPlugin['Instance']; 15 - schemas: ReadonlyArray<IR.SchemaObject>; 16 - } 17 - 18 - export function unionToPipes(ctx: UnionToPipesContext): CompositeHandlerResult { 19 - const { childResults, plugin, schemas } = ctx; 11 + function baseNode(ctx: UnionResolverContext): PipeResult { 12 + const { childResults, plugin, schemas, symbols } = ctx; 13 + const { v } = symbols; 20 14 21 15 const nonNullItems: Array<ValibotResult> = []; 22 16 childResults.forEach((item, index) => { ··· 25 19 nonNullItems.push(item); 26 20 } 27 21 }); 28 - 29 - const v = plugin.external('valibot.v'); 30 - let pipes: Pipes; 31 22 32 23 if (nonNullItems.length === 0) { 33 - pipes = [$(v).attr(identifiers.schemas.null).call()]; 34 - } else if (nonNullItems.length === 1) { 35 - pipes = nonNullItems[0]!.pipes; 36 - } else { 37 - const itemNodes = nonNullItems.map((i) => pipesToNode(i.pipes, plugin)); 38 - pipes = [ 39 - $(v) 40 - .attr(identifiers.schemas.union) 41 - .call($.array(...itemNodes)), 42 - ]; 24 + return $(v).attr(identifiers.schemas.null).call(); 25 + } 26 + 27 + if (nonNullItems.length === 1) { 28 + return nonNullItems[0]!.pipes; 43 29 } 44 30 31 + const itemNodes = nonNullItems.map((i) => pipesToNode(i.pipes, plugin)); 32 + return $(v) 33 + .attr(identifiers.schemas.union) 34 + .call($.array(...itemNodes)); 35 + } 36 + 37 + function unionResolver(ctx: UnionResolverContext): Pipes { 38 + const base = ctx.nodes.base(ctx); 39 + if (base) { 40 + ctx.pipes.push(ctx.pipes.current, base); 41 + } 42 + return ctx.pipes.current; 43 + } 44 + 45 + export function unionToPipes(ctx: { 46 + applyModifiers: (result: ValibotResult, options?: { optional?: boolean }) => ValibotFinal; 47 + childResults: Array<ValibotResult>; 48 + parentSchema: IR.SchemaObject; 49 + plugin: ValibotPlugin['Instance']; 50 + schemas: ReadonlyArray<IR.SchemaObject>; 51 + }): CompositeHandlerResult { 52 + const { childResults, parentSchema, plugin, schemas } = ctx; 53 + 54 + const resolverCtx: UnionResolverContext = { 55 + $, 56 + applyModifiers: ctx.applyModifiers, 57 + childResults, 58 + nodes: { 59 + base: baseNode, 60 + }, 61 + parentSchema, 62 + pipes: { 63 + ...pipes, 64 + current: [], 65 + }, 66 + plugin, 67 + schema: parentSchema, 68 + schemas, 69 + symbols: { 70 + v: plugin.external('valibot.v'), 71 + }, 72 + }; 73 + 74 + const resolver = plugin.config['~resolvers']?.union; 75 + const node = resolver?.(resolverCtx) ?? unionResolver(resolverCtx); 76 + 45 77 return { 46 78 childResults, 47 - pipes, 79 + pipes: [resolverCtx.pipes.toNode(node, plugin)], 48 80 }; 49 81 }
+35 -3
packages/openapi-ts/src/plugins/valibot/v1/toAst/unknown.ts
··· 1 1 import type { SchemaWithType } from '@hey-api/shared'; 2 2 3 3 import { $ } from '../../../../ts-dsl'; 4 - import type { Pipe } from '../../shared/pipes'; 4 + import type { UnknownResolverContext } from '../../resolvers'; 5 + import type { Pipe, PipeResult, Pipes } from '../../shared/pipes'; 6 + import { pipes } from '../../shared/pipes'; 5 7 import type { ValibotPlugin } from '../../types'; 6 8 import { identifiers } from '../constants'; 7 9 10 + function baseNode(ctx: UnknownResolverContext): PipeResult { 11 + const { symbols } = ctx; 12 + const { v } = symbols; 13 + return $(v).attr(identifiers.schemas.unknown).call(); 14 + } 15 + 16 + function unknownResolver(ctx: UnknownResolverContext): Pipes { 17 + const base = ctx.nodes.base(ctx); 18 + ctx.pipes.push(ctx.pipes.current, base); 19 + return ctx.pipes.current; 20 + } 21 + 8 22 export function unknownToPipes({ 9 23 plugin, 24 + schema, 10 25 }: { 11 26 plugin: ValibotPlugin['Instance']; 12 27 schema?: SchemaWithType<'unknown'>; 13 28 }): Pipe { 14 - const v = plugin.external('valibot.v'); 15 - return $(v).attr(identifiers.schemas.unknown).call(); 29 + const ctx: UnknownResolverContext = { 30 + $, 31 + nodes: { 32 + base: baseNode, 33 + }, 34 + pipes: { 35 + ...pipes, 36 + current: [], 37 + }, 38 + plugin, 39 + schema: schema ?? { type: 'unknown' }, 40 + symbols: { 41 + v: plugin.external('valibot.v'), 42 + }, 43 + }; 44 + 45 + const resolver = plugin.config['~resolvers']?.unknown; 46 + const node = resolver?.(ctx) ?? unknownResolver(ctx); 47 + return ctx.pipes.toNode(node, plugin); 16 48 }
+35 -3
packages/openapi-ts/src/plugins/valibot/v1/toAst/void.ts
··· 1 1 import type { SchemaWithType } from '@hey-api/shared'; 2 2 3 3 import { $ } from '../../../../ts-dsl'; 4 - import type { Pipe } from '../../shared/pipes'; 4 + import type { VoidResolverContext } from '../../resolvers'; 5 + import type { Pipe, PipeResult, Pipes } from '../../shared/pipes'; 6 + import { pipes } from '../../shared/pipes'; 5 7 import type { ValibotPlugin } from '../../types'; 6 8 import { identifiers } from '../constants'; 7 9 10 + function baseNode(ctx: VoidResolverContext): PipeResult { 11 + const { symbols } = ctx; 12 + const { v } = symbols; 13 + return $(v).attr(identifiers.schemas.void).call(); 14 + } 15 + 16 + function voidResolver(ctx: VoidResolverContext): Pipes { 17 + const base = ctx.nodes.base(ctx); 18 + ctx.pipes.push(ctx.pipes.current, base); 19 + return ctx.pipes.current; 20 + } 21 + 8 22 export function voidToPipes({ 9 23 plugin, 24 + schema, 10 25 }: { 11 26 plugin: ValibotPlugin['Instance']; 12 27 schema: SchemaWithType<'void'>; 13 28 }): Pipe { 14 - const v = plugin.external('valibot.v'); 15 - return $(v).attr(identifiers.schemas.void).call(); 29 + const ctx: VoidResolverContext = { 30 + $, 31 + nodes: { 32 + base: baseNode, 33 + }, 34 + pipes: { 35 + ...pipes, 36 + current: [], 37 + }, 38 + plugin, 39 + schema, 40 + symbols: { 41 + v: plugin.external('valibot.v'), 42 + }, 43 + }; 44 + 45 + const resolver = plugin.config['~resolvers']?.void; 46 + const node = resolver?.(ctx) ?? voidResolver(ctx); 47 + return ctx.pipes.toNode(node, plugin); 16 48 }