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.

chore: scaffold pydantic plugin

Lubos 902aecc7 403b72d7

+988 -414
+9
dev/python/plugins.ts
··· 10 10 ...options, 11 11 }; 12 12 } 13 + 14 + export function pydantic( 15 + options?: Partial<Omit<Extract<PluginConfig, { name: 'pydantic' }>, 'name'>>, 16 + ) { 17 + return { 18 + name: 'pydantic' as const, 19 + ...options, 20 + }; 21 + }
+6 -1
dev/python/presets.ts
··· 1 - import { sdk } from './plugins'; 1 + import { pydantic, sdk } from './plugins'; 2 2 3 3 export const presets = { 4 4 sdk: () => [ ··· 13 13 }, 14 14 }, 15 15 }), 16 + ], 17 + validated: () => [ 18 + /** SDK + Pydantic validation */ 19 + sdk(), 20 + pydantic(), 16 21 ], 17 22 } as const; 18 23
+10 -10
packages/openapi-python/src/index.ts
··· 41 41 * Tags associated with this symbol. 42 42 */ 43 43 tags?: ReadonlyArray<string>; 44 - tool?: 45 - | 'angular' 46 - | 'arktype' 47 - | 'fastify' 48 - | 'json-schema' 49 - | 'sdk' 50 - | 'typescript' 51 - | 'valibot' 52 - | 'zod' 53 - | AnyString; 44 + tool?: 'pydantic' | 'sdk' | AnyString; 54 45 variant?: 'container' | AnyString; 55 46 } 56 47 } ··· 59 50 interface PluginConfigMap { 60 51 '@hey-api/client-httpx': HeyApiClientHttpxPlugin['Types']; 61 52 '@hey-api/python-sdk': HeyApiSdkPlugin['Types']; 53 + pydantic: PydanticPlugin['Types']; 62 54 } 63 55 } 64 56 // END OVERRIDES ··· 71 63 import type { UserConfig } from './config/types'; 72 64 import type { HeyApiClientHttpxPlugin } from './plugins/@hey-api/client-httpx'; 73 65 import type { HeyApiSdkPlugin } from './plugins/@hey-api/sdk'; 66 + import type { PydanticPlugin } from './plugins/pydantic'; 74 67 75 68 colors.enabled = colorSupport().hasBasic; 76 69 ··· 111 104 OperationStrategy, 112 105 utils, 113 106 } from '@hey-api/shared'; 107 + 108 + // Pydantic plugin 109 + export type { PydanticPlugin } from './plugins/pydantic'; 110 + export { 111 + defaultConfig as defaultPydanticConfig, 112 + defineConfig as definePydanticConfig, 113 + } from './plugins/pydantic';
+2
packages/openapi-python/src/plugins/config.ts
··· 2 2 3 3 import { defaultConfig as heyApiClientHttpx } from '../plugins/@hey-api/client-httpx'; 4 4 import { defaultConfig as heyApiSdk } from '../plugins/@hey-api/sdk'; 5 + import { defaultConfig as pydantic } from '../plugins/pydantic'; 5 6 6 7 export const defaultPluginConfigs: { 7 8 [K in PluginNames]: Plugin.Config<PluginConfigMap[K]>; 8 9 } = { 9 10 '@hey-api/client-httpx': heyApiClientHttpx, 10 11 '@hey-api/python-sdk': heyApiSdk, 12 + pydantic, 11 13 };
+62
packages/openapi-python/src/plugins/pydantic/config.ts
··· 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 + 3 + import { handler } from './plugin'; 4 + import type { PydanticPlugin } from './types'; 5 + 6 + export const defaultConfig: PydanticPlugin['Config'] = { 7 + config: { 8 + case: 'PascalCase', 9 + comments: true, 10 + includeInEntry: false, 11 + strict: false, 12 + }, 13 + handler, 14 + name: 'pydantic', 15 + resolveConfig: (plugin, context) => { 16 + plugin.config.definitions = context.valueToObject({ 17 + defaultValue: { 18 + case: plugin.config.case ?? 'PascalCase', 19 + enabled: true, 20 + name: '{{name}}', 21 + }, 22 + mappers, 23 + value: plugin.config.definitions, 24 + }); 25 + 26 + plugin.config.requests = context.valueToObject({ 27 + defaultValue: { 28 + case: plugin.config.case ?? 'PascalCase', 29 + enabled: true, 30 + name: '{{name}}Request', 31 + }, 32 + mappers, 33 + value: plugin.config.requests, 34 + }); 35 + 36 + plugin.config.responses = context.valueToObject({ 37 + defaultValue: { 38 + case: plugin.config.case ?? 'PascalCase', 39 + enabled: true, 40 + name: '{{name}}Response', 41 + }, 42 + mappers, 43 + value: plugin.config.responses, 44 + }); 45 + 46 + plugin.config.webhooks = context.valueToObject({ 47 + defaultValue: { 48 + case: plugin.config.case ?? 'PascalCase', 49 + enabled: true, 50 + name: '{{name}}Webhook', 51 + }, 52 + mappers, 53 + value: plugin.config.webhooks, 54 + }); 55 + }, 56 + tags: ['validator'], 57 + }; 58 + 59 + /** 60 + * Type helper for Pydantic plugin, returns {@link Plugin.Config} object 61 + */ 62 + export const defineConfig = definePluginConfig(defaultConfig);
+2
packages/openapi-python/src/plugins/pydantic/index.ts
··· 1 + export { defaultConfig, defineConfig } from './config'; 2 + export type { PydanticPlugin } from './types';
+4
packages/openapi-python/src/plugins/pydantic/plugin.ts
··· 1 + import type { PydanticPlugin } from './types'; 2 + import { handlerV2 } from './v2/plugin'; 3 + 4 + export const handler: PydanticPlugin['Handler'] = (args) => handlerV2(args);
+71
packages/openapi-python/src/plugins/pydantic/shared/export.ts
··· 1 + import type { Symbol } from '@hey-api/codegen-core'; 2 + import type { IR } from '@hey-api/shared'; 3 + 4 + // import { createSchemaComment } from '../../../plugins/shared/utils/schema'; 5 + import { $ } from '../../../py-dsl'; 6 + // import { identifiers } from '../v2/constants'; 7 + // import { pipesToNode } from './pipes'; 8 + import type { Ast, IrSchemaToAstOptions } from './types'; 9 + 10 + export function exportAst({ 11 + // ast, 12 + plugin, 13 + // schema, 14 + // state, 15 + symbol, 16 + }: IrSchemaToAstOptions & { 17 + ast: Ast; 18 + schema: IR.SchemaObject; 19 + symbol: Symbol; 20 + }): void { 21 + // const v = plugin.external('valibot.v'); 22 + const classDef = $.class(symbol); 23 + // .export() 24 + // .$if(plugin.config.comments && createSchemaComment(schema), (c, v) => c.doc(v)) 25 + // .$if(state.hasLazyExpression['~ref'], (c) => 26 + // c.type($.type(v).attr(ast.typeName || identifiers.types.GenericSchema)), 27 + // ) 28 + // .assign(pipesToNode(ast.pipes, plugin)); 29 + plugin.node(classDef); 30 + // if (schema.type === 'object' && schema.properties) { 31 + // const baseModelSymbol = plugin.external('pydantic.BaseModel'); 32 + // const fieldSymbol = plugin.external('pydantic.Field'); 33 + // const classDef = $.class(symbol).extends(baseModelSymbol); 34 + 35 + // if (plugin.config.comments && schema.description) { 36 + // classDef.doc(schema.description); 37 + // } 38 + 39 + // for (const name in schema.properties) { 40 + // const property = schema.properties[name]!; 41 + // const isOptional = !schema.required?.includes(name); 42 + 43 + // const propertyAst = irSchemaToAst({ 44 + // optional: isOptional, 45 + // plugin, 46 + // schema: property, 47 + // state: { 48 + // ...state, 49 + // path: ref([...fromRef(state.path), 'properties', name]), 50 + // }, 51 + // }); 52 + 53 + // let typeAnnotation = propertyAst.typeAnnotation; 54 + 55 + // if (isOptional && !typeAnnotation.startsWith('Optional[')) { 56 + // typeAnnotation = `Optional[${typeAnnotation}]`; 57 + // } 58 + 59 + // if (propertyAst.fieldConstraints && Object.keys(propertyAst.fieldConstraints).length > 0) { 60 + // const constraints = Object.entries(propertyAst.fieldConstraints) 61 + // .map(([key, value]) => `${key}=${JSON.stringify(value)}`) 62 + // .join(', '); 63 + // classDef.do($.stmt($.expr(`${name}: ${typeAnnotation} = Field(${constraints})`))); 64 + // } else { 65 + // classDef.do($.stmt($.expr(`${name}: ${typeAnnotation}`))); 66 + // } 67 + // } 68 + 69 + // plugin.node(classDef); 70 + // } 71 + }
+1
packages/openapi-python/src/plugins/pydantic/shared/index.ts
··· 1 + export type { Ast, IrSchemaToAstOptions, Pipes, PluginState, ResolverContext } from './types';
+80
packages/openapi-python/src/plugins/pydantic/shared/types.ts
··· 1 + import type { Refs, SymbolMeta } from '@hey-api/codegen-core'; 2 + import type { IR } from '@hey-api/shared'; 3 + 4 + import type { PydanticPlugin } from '../types'; 5 + 6 + /** 7 + * Shared types for Pydantic plugin 8 + */ 9 + 10 + export type PluginState = Pick<Required<SymbolMeta>, 'path'> & 11 + Pick<Partial<SymbolMeta>, 'tags'> & { 12 + hasLazyExpression: boolean; 13 + }; 14 + 15 + /** 16 + * AST node representation for Pydantic models 17 + */ 18 + export interface Ast { 19 + /** 20 + * Expression node for the type 21 + */ 22 + expression: unknown; 23 + /** 24 + * Field constraints for pydantic.Field() 25 + */ 26 + fieldConstraints?: Record<string, unknown>; 27 + /** 28 + * Whether this AST node has a lazy expression (forward reference) 29 + */ 30 + hasLazyExpression?: boolean; 31 + /** 32 + * Pipes/chains for building the field definition (similar to Valibot pipes) 33 + */ 34 + pipes?: Pipes; 35 + /** 36 + * Type annotation for the field 37 + */ 38 + typeAnnotation: string; 39 + /** 40 + * Type name for the model class 41 + */ 42 + typeName?: string; 43 + } 44 + 45 + /** 46 + * Pipe system for building field constraints (similar to Valibot pattern) 47 + */ 48 + export type Pipes = Array<unknown>; 49 + 50 + /** 51 + * Options for converting IR schema to AST 52 + */ 53 + export interface IrSchemaToAstOptions { 54 + /** 55 + * The plugin instance 56 + */ 57 + plugin: PydanticPlugin['Instance']; 58 + /** 59 + * Current plugin state 60 + */ 61 + state: Refs<PluginState>; 62 + } 63 + 64 + /** 65 + * Context for type resolver functions 66 + */ 67 + export interface ResolverContext { 68 + /** 69 + * Field constraints being built 70 + */ 71 + constraints: Record<string, unknown>; 72 + /** 73 + * The plugin instance 74 + */ 75 + plugin: PydanticPlugin['Instance']; 76 + /** 77 + * IR schema being processed 78 + */ 79 + schema: IR.SchemaObject; 80 + }
+194
packages/openapi-python/src/plugins/pydantic/types.ts
··· 1 + import type { 2 + Casing, 3 + DefinePlugin, 4 + FeatureToggle, 5 + NameTransformer, 6 + NamingOptions, 7 + Plugin, 8 + } from '@hey-api/shared'; 9 + 10 + export type UserConfig = Plugin.Name<'pydantic'> & 11 + Plugin.Hooks & 12 + Plugin.UserComments & 13 + Plugin.UserExports & { 14 + /** 15 + * Casing convention for generated names. 16 + * 17 + * @default 'PascalCase' 18 + */ 19 + case?: Casing; 20 + /** 21 + * Configuration for reusable schema definitions. 22 + * 23 + * Controls generation of shared Pydantic models that can be referenced 24 + * across requests and responses. 25 + * 26 + * Can be: 27 + * - `boolean`: Shorthand for `{ enabled: boolean }` 28 + * - `string` or `function`: Shorthand for `{ name: string | function }` 29 + * - `object`: Full configuration object 30 + * 31 + * @default true 32 + */ 33 + definitions?: 34 + | boolean 35 + | NameTransformer 36 + | { 37 + /** 38 + * Casing convention for generated names. 39 + * 40 + * @default 'PascalCase' 41 + */ 42 + case?: Casing; 43 + /** 44 + * Whether this feature is enabled. 45 + * 46 + * @default true 47 + */ 48 + enabled?: boolean; 49 + /** 50 + * Naming pattern for generated names. 51 + * 52 + * @default '{{name}}' 53 + */ 54 + name?: NameTransformer; 55 + }; 56 + /** 57 + * Configuration for request-specific Pydantic models. 58 + * 59 + * Controls generation of Pydantic models for request bodies, 60 + * query parameters, path parameters, and headers. 61 + * 62 + * Can be: 63 + * - `boolean`: Shorthand for `{ enabled: boolean }` 64 + * - `string` or `function`: Shorthand for `{ name: string | function }` 65 + * - `object`: Full configuration object 66 + * 67 + * @default true 68 + */ 69 + requests?: 70 + | boolean 71 + | NameTransformer 72 + | { 73 + /** 74 + * Casing convention for generated names. 75 + * 76 + * @default 'PascalCase' 77 + */ 78 + case?: Casing; 79 + /** 80 + * Whether this feature is enabled. 81 + * 82 + * @default true 83 + */ 84 + enabled?: boolean; 85 + /** 86 + * Naming pattern for generated names. 87 + * 88 + * @default '{{name}}Request' 89 + */ 90 + name?: NameTransformer; 91 + }; 92 + /** 93 + * Configuration for response-specific Pydantic models. 94 + * 95 + * Controls generation of Pydantic models for response bodies, 96 + * error responses, and status codes. 97 + * 98 + * Can be: 99 + * - `boolean`: Shorthand for `{ enabled: boolean }` 100 + * - `string` or `function`: Shorthand for `{ name: string | function }` 101 + * - `object`: Full configuration object 102 + * 103 + * @default true 104 + */ 105 + responses?: 106 + | boolean 107 + | NameTransformer 108 + | { 109 + /** 110 + * Casing convention for generated names. 111 + * 112 + * @default 'PascalCase' 113 + */ 114 + case?: Casing; 115 + /** 116 + * Whether this feature is enabled. 117 + * 118 + * @default true 119 + */ 120 + enabled?: boolean; 121 + /** 122 + * Naming pattern for generated names. 123 + * 124 + * @default '{{name}}Response' 125 + */ 126 + name?: NameTransformer; 127 + }; 128 + /** 129 + * Enable strict mode for Pydantic models? 130 + * 131 + * When enabled, extra fields not defined in the schema will be rejected. 132 + * 133 + * This adds `model_config = ConfigDict(extra='forbid')` 134 + * to generated models. 135 + * 136 + * @default false 137 + */ 138 + strict?: boolean; 139 + /** 140 + * Configuration for webhook-specific Pydantic models. 141 + * 142 + * Controls generation of Pydantic models for webhook payloads. 143 + * 144 + * Can be: 145 + * - `boolean`: Shorthand for `{ enabled: boolean }` 146 + * - `string` or `function`: Shorthand for `{ name: string | function }` 147 + * - `object`: Full configuration object 148 + * 149 + * @default true 150 + */ 151 + webhooks?: 152 + | boolean 153 + | NameTransformer 154 + | { 155 + /** 156 + * Casing convention for generated names. 157 + * 158 + * @default 'PascalCase' 159 + */ 160 + case?: Casing; 161 + /** 162 + * Whether this feature is enabled. 163 + * 164 + * @default true 165 + */ 166 + enabled?: boolean; 167 + /** 168 + * Naming pattern for generated names. 169 + * 170 + * @default '{{name}}Webhook' 171 + */ 172 + name?: NameTransformer; 173 + }; 174 + }; 175 + 176 + export type Config = Plugin.Name<'pydantic'> & 177 + Plugin.Hooks & 178 + Plugin.Comments & 179 + Plugin.Exports & { 180 + /** Casing convention for generated names. */ 181 + case: Casing; 182 + /** Configuration for reusable schema definitions. */ 183 + definitions: NamingOptions & FeatureToggle; 184 + /** Configuration for request-specific Pydantic models. */ 185 + requests: NamingOptions & FeatureToggle; 186 + /** Configuration for response-specific Pydantic models. */ 187 + responses: NamingOptions & FeatureToggle; 188 + /** Enable strict mode for Pydantic models? */ 189 + strict: boolean; 190 + /** Configuration for webhook-specific Pydantic models. */ 191 + webhooks: NamingOptions & FeatureToggle; 192 + }; 193 + 194 + export type PydanticPlugin = DefinePlugin<UserConfig, Config>;
+44
packages/openapi-python/src/plugins/pydantic/v2/constants.ts
··· 1 + export const identifiers = { 2 + Annotated: 'Annotated', 3 + Any: 'Any', 4 + BaseModel: 'BaseModel', 5 + ConfigDict: 'ConfigDict', 6 + Dict: 'Dict', 7 + Field: 'Field', 8 + List: 'List', 9 + Literal: 'Literal', 10 + Optional: 'Optional', 11 + Union: 'Union', 12 + alias: 'alias', 13 + default: 'default', 14 + description: 'description', 15 + ge: 'ge', 16 + gt: 'gt', 17 + le: 'le', 18 + lt: 'lt', 19 + max_length: 'max_length', 20 + min_length: 'min_length', 21 + model_config: 'model_config', 22 + multiple_of: 'multiple_of', 23 + pattern: 'pattern', 24 + } as const; 25 + 26 + export const typeMappings: Record<string, string> = { 27 + array: 'list', 28 + boolean: 'bool', 29 + integer: 'int', 30 + null: 'None', 31 + number: 'float', 32 + object: 'dict', 33 + string: 'str', 34 + }; 35 + 36 + export const pydanticTypes = { 37 + array: 'list', 38 + boolean: 'bool', 39 + integer: 'int', 40 + null: 'None', 41 + number: 'float', 42 + object: 'dict', 43 + string: 'str', 44 + } as const;
+216
packages/openapi-python/src/plugins/pydantic/v2/plugin.ts
··· 1 + import type { SymbolMeta } from '@hey-api/codegen-core'; 2 + import { fromRef, ref, refs } from '@hey-api/codegen-core'; 3 + import type { IR, SchemaWithType } from '@hey-api/shared'; 4 + import { applyNaming, deduplicateSchema, pathToJsonPointer, refToName } from '@hey-api/shared'; 5 + 6 + import { $ } from '../../../py-dsl'; 7 + import { exportAst } from '../shared/export'; 8 + import type { Ast, IrSchemaToAstOptions, PluginState } from '../shared/types'; 9 + import type { PydanticPlugin } from '../types'; 10 + import { irSchemaWithTypeToAst } from './toAst'; 11 + 12 + export function irSchemaToAst({ 13 + optional, 14 + plugin, 15 + schema, 16 + state, 17 + }: IrSchemaToAstOptions & { 18 + optional?: boolean; 19 + schema: IR.SchemaObject; 20 + }): Ast { 21 + if (schema.$ref) { 22 + const query: SymbolMeta = { 23 + category: 'schema', 24 + resource: 'definition', 25 + resourceId: schema.$ref, 26 + tool: 'pydantic', 27 + }; 28 + const refSymbol = plugin.referenceSymbol(query); 29 + const refName = typeof refSymbol === 'string' ? refSymbol : refSymbol.name; 30 + 31 + return { 32 + expression: $.expr(refName), 33 + fieldConstraints: optional ? { default: null } : undefined, 34 + hasLazyExpression: !plugin.isSymbolRegistered(query), 35 + pipes: [], 36 + typeAnnotation: refName, 37 + }; 38 + } 39 + 40 + if (schema.type) { 41 + const typeAst = irSchemaWithTypeToAst({ 42 + plugin, 43 + schema: schema as SchemaWithType, 44 + state, 45 + }); 46 + 47 + const constraints: Record<string, unknown> = {}; 48 + if (optional) { 49 + constraints.default = null; 50 + } 51 + if (schema.default !== undefined) { 52 + constraints.default = schema.default; 53 + } 54 + if (schema.description) { 55 + constraints.description = schema.description; 56 + } 57 + 58 + return { 59 + ...typeAst, 60 + fieldConstraints: { ...typeAst.fieldConstraints, ...constraints }, 61 + pipes: [], 62 + }; 63 + } 64 + 65 + if (schema.items) { 66 + schema = deduplicateSchema({ schema }); 67 + 68 + if (schema.items) { 69 + const itemsAnnotations: string[] = []; 70 + const itemsConstraints: Record<string, unknown>[] = []; 71 + 72 + for (const item of schema.items) { 73 + const itemAst = irSchemaToAst({ 74 + plugin, 75 + schema: item, 76 + state: { 77 + ...state, 78 + path: ref([...fromRef(state.path), 'items']), 79 + }, 80 + }); 81 + itemsAnnotations.push(itemAst.typeAnnotation); 82 + if (itemAst.fieldConstraints) { 83 + itemsConstraints.push(itemAst.fieldConstraints); 84 + } 85 + } 86 + 87 + const unionType = itemsAnnotations.join(' | '); 88 + return { 89 + expression: $.expr(`list[${unionType}]`), 90 + fieldConstraints: itemsConstraints.length > 0 ? itemsConstraints[0] : undefined, 91 + hasLazyExpression: false, 92 + pipes: [], 93 + typeAnnotation: `list[${unionType}]`, 94 + }; 95 + } 96 + } 97 + 98 + return { 99 + expression: $.expr('Any'), 100 + hasLazyExpression: false, 101 + pipes: [], 102 + typeAnnotation: 'Any', 103 + }; 104 + } 105 + 106 + function handleComponent({ 107 + plugin, 108 + schema, 109 + state, 110 + }: IrSchemaToAstOptions & { 111 + schema: IR.SchemaObject; 112 + }): void { 113 + const $ref = pathToJsonPointer(fromRef(state.path)); 114 + const ast = irSchemaToAst({ plugin, schema, state }); 115 + const baseName = refToName($ref); 116 + const symbol = plugin.symbol(applyNaming(baseName, plugin.config.definitions), { 117 + meta: { 118 + category: 'schema', 119 + path: fromRef(state.path), 120 + resource: 'definition', 121 + resourceId: $ref, 122 + tags: fromRef(state.tags), 123 + tool: 'pydantic', 124 + }, 125 + }); 126 + exportAst({ 127 + ast, 128 + plugin, 129 + schema, 130 + state, 131 + symbol, 132 + }); 133 + } 134 + 135 + export const handlerV2: PydanticPlugin['Handler'] = ({ plugin }) => { 136 + plugin.symbol('Any', { 137 + external: 'typing', 138 + importKind: 'named', 139 + meta: { 140 + category: 'external', 141 + resource: 'typing.Any', 142 + }, 143 + }); 144 + plugin.symbol('BaseModel', { 145 + external: 'pydantic', 146 + importKind: 'named', 147 + meta: { 148 + category: 'external', 149 + resource: 'pydantic.BaseModel', 150 + }, 151 + }); 152 + plugin.symbol('ConfigDict', { 153 + external: 'pydantic', 154 + importKind: 'named', 155 + meta: { 156 + category: 'external', 157 + resource: 'pydantic.ConfigDict', 158 + }, 159 + }); 160 + plugin.symbol('Field', { 161 + external: 'pydantic', 162 + importKind: 'named', 163 + meta: { 164 + category: 'external', 165 + resource: 'pydantic.Field', 166 + }, 167 + }); 168 + plugin.symbol('Literal', { 169 + external: 'typing', 170 + importKind: 'named', 171 + meta: { 172 + category: 'external', 173 + resource: 'typing.Literal', 174 + }, 175 + }); 176 + plugin.symbol('Optional', { 177 + external: 'typing', 178 + importKind: 'named', 179 + meta: { 180 + category: 'external', 181 + resource: 'typing.Optional', 182 + }, 183 + }); 184 + 185 + plugin.forEach('operation', 'parameter', 'requestBody', 'schema', 'webhook', (event) => { 186 + const state = refs<PluginState>({ 187 + hasLazyExpression: false, 188 + path: event._path, 189 + tags: event.tags, 190 + }); 191 + 192 + switch (event.type) { 193 + case 'parameter': 194 + handleComponent({ 195 + plugin, 196 + schema: event.parameter.schema, 197 + state, 198 + }); 199 + break; 200 + case 'requestBody': 201 + handleComponent({ 202 + plugin, 203 + schema: event.requestBody.schema, 204 + state, 205 + }); 206 + break; 207 + case 'schema': 208 + handleComponent({ 209 + plugin, 210 + schema: event.schema, 211 + state, 212 + }); 213 + break; 214 + } 215 + }); 216 + };
+30
packages/openapi-python/src/plugins/pydantic/v2/toAst/index.ts
··· 1 + import type { SchemaWithType } from '@hey-api/shared'; 2 + 3 + import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; 4 + import { objectToAst } from './object'; 5 + import { stringToNode } from './string'; 6 + 7 + export function irSchemaWithTypeToAst({ 8 + schema, 9 + ...args 10 + }: IrSchemaToAstOptions & { 11 + schema: SchemaWithType; 12 + }): Ast { 13 + switch (schema.type) { 14 + case 'object': 15 + return objectToAst({ 16 + ...args, 17 + schema: schema as SchemaWithType<'object'>, 18 + }); 19 + case 'string': 20 + return stringToNode({ 21 + ...args, 22 + schema: schema as SchemaWithType<'string'>, 23 + }); 24 + default: 25 + return { 26 + expression: 'Any', 27 + typeAnnotation: 'Any', 28 + }; 29 + } 30 + }
+61
packages/openapi-python/src/plugins/pydantic/v2/toAst/object.ts
··· 1 + // import { fromRef, ref } from '@hey-api/codegen-core'; 2 + import type { SchemaWithType } from '@hey-api/shared'; 3 + 4 + import { $ } from '../../../../py-dsl'; 5 + import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; 6 + // import { irSchemaToAst } from '../plugin'; 7 + 8 + export const objectToAst = ({ 9 + plugin, 10 + // schema, 11 + // state, 12 + }: IrSchemaToAstOptions & { 13 + schema: SchemaWithType<'object'>; 14 + }): Ast => { 15 + const symbolBaseModel = plugin.external('pydantic.BaseModel'); 16 + // const fieldSymbol = plugin.external('pydantic.Field'); 17 + const symbolTemp = plugin.symbol('temp'); 18 + 19 + const classDef = $.class(symbolTemp).extends(symbolBaseModel); 20 + 21 + // if (schema.properties) { 22 + // for (const name in schema.properties) { 23 + // const property = schema.properties[name]!; 24 + // const isOptional = !schema.required?.includes(name); 25 + 26 + // const propertyAst = irSchemaToAst({ 27 + // optional: isOptional, 28 + // plugin, 29 + // schema: property, 30 + // state: { 31 + // ...state, 32 + // path: ref([...fromRef(state.path), 'properties', name]), 33 + // }, 34 + // }); 35 + 36 + // let typeAnnotation = propertyAst.typeAnnotation; 37 + 38 + // if (isOptional && !typeAnnotation.startsWith('Optional[')) { 39 + // typeAnnotation = `Optional[${typeAnnotation}]`; 40 + // } 41 + 42 + // if (propertyAst.fieldConstraints && Object.keys(propertyAst.fieldConstraints).length > 0) { 43 + // const constraints = Object.entries(propertyAst.fieldConstraints) 44 + // .map(([key, value]) => `${key}=${JSON.stringify(value)}`) 45 + // .join(', '); 46 + // classDef.do($.expr(`${name}: ${typeAnnotation} = Field(${constraints})`)); 47 + // } else { 48 + // classDef.do($.expr(`${name}: ${typeAnnotation}`)); 49 + // } 50 + // } 51 + // } 52 + 53 + return { 54 + expression: classDef, 55 + fieldConstraints: {}, 56 + hasLazyExpression: false, 57 + pipes: [], 58 + typeAnnotation: 'DynamicModel', 59 + typeName: 'DynamicModel', 60 + }; 61 + };
+46
packages/openapi-python/src/plugins/pydantic/v2/toAst/string.ts
··· 1 + import type { SchemaWithType } from '@hey-api/shared'; 2 + 3 + import { $ } from '../../../../py-dsl'; 4 + import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; 5 + 6 + export const stringToNode = ({ 7 + schema, 8 + }: IrSchemaToAstOptions & { 9 + schema: SchemaWithType<'string'>; 10 + }): Ast => { 11 + const constraints: Record<string, unknown> = {}; 12 + 13 + if (schema.minLength !== undefined) { 14 + constraints.min_length = schema.minLength; 15 + } 16 + 17 + if (schema.maxLength !== undefined) { 18 + constraints.max_length = schema.maxLength; 19 + } 20 + 21 + if (schema.pattern !== undefined) { 22 + constraints.pattern = schema.pattern; 23 + } 24 + 25 + if (schema.description !== undefined) { 26 + constraints.description = schema.description; 27 + } 28 + 29 + if (typeof schema.const === 'string') { 30 + return { 31 + expression: $.expr(`Literal["${schema.const}"]`), 32 + fieldConstraints: constraints, 33 + hasLazyExpression: false, 34 + pipes: [], 35 + typeAnnotation: `Literal["${schema.const}"]`, 36 + }; 37 + } 38 + 39 + return { 40 + expression: $.expr('str'), 41 + fieldConstraints: constraints, 42 + hasLazyExpression: false, 43 + pipes: [], 44 + typeAnnotation: 'str', 45 + }; 46 + };
+2 -6
packages/openapi-ts/src/plugins/@faker-js/faker/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { Api } from './api'; 4 4 // import { handler } from './plugin'; ··· 20 20 enabled: true, 21 21 name: 'v{{name}}', 22 22 }, 23 - mappers: { 24 - boolean: (enabled) => ({ enabled }), 25 - function: (name) => ({ name }), 26 - string: (name) => ({ name }), 27 - }, 23 + mappers, 28 24 value: plugin.config.definitions, 29 25 }); 30 26 },
+6 -6
packages/openapi-ts/src/plugins/@hey-api/typescript/v1/plugin.ts
··· 15 15 import type { HeyApiTypeScriptPlugin } from '../types'; 16 16 import { irSchemaWithTypeToAst } from './toAst'; 17 17 18 - export const irSchemaToAst = ({ 18 + export function irSchemaToAst({ 19 19 plugin, 20 20 schema, 21 21 state, 22 22 }: IrSchemaToAstOptions & { 23 23 schema: IR.SchemaObject; 24 - }): MaybeTsDsl<TypeTsDsl> => { 24 + }): MaybeTsDsl<TypeTsDsl> { 25 25 if (schema.symbolRef) { 26 26 const baseType = $.type(schema.symbolRef); 27 27 if (schema.omit && schema.omit.length > 0) { ··· 79 79 }, 80 80 state, 81 81 }); 82 - }; 82 + } 83 83 84 - const handleComponent = ({ 84 + function handleComponent({ 85 85 plugin, 86 86 schema, 87 87 state, 88 88 }: IrSchemaToAstOptions & { 89 89 schema: IR.SchemaObject; 90 - }) => { 90 + }) { 91 91 const type = irSchemaToAst({ plugin, schema, state }); 92 92 exportType({ 93 93 plugin, ··· 95 95 state, 96 96 type, 97 97 }); 98 - }; 98 + } 99 99 100 100 export const handlerV1: HeyApiTypeScriptPlugin['Handler'] = ({ plugin }) => { 101 101 // reserve node for ClientOptions
+3 -3
packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/index.ts
··· 15 15 import { unknownToAst } from './unknown'; 16 16 import { voidToAst } from './void'; 17 17 18 - export const irSchemaWithTypeToAst = ({ 18 + export function irSchemaWithTypeToAst({ 19 19 schema, 20 20 ...args 21 21 }: IrSchemaToAstOptions & { 22 22 schema: SchemaWithType; 23 - }): MaybeTsDsl<TypeTsDsl> => { 23 + }): MaybeTsDsl<TypeTsDsl> { 24 24 const transformersPlugin = args.plugin.getPlugin('@hey-api/transformers'); 25 25 if (transformersPlugin?.config.typeTransformers) { 26 26 for (const typeTransformer of transformersPlugin.config.typeTransformers) { ··· 94 94 schema: schema as SchemaWithType<'void'>, 95 95 }); 96 96 } 97 - }; 97 + }
+4 -16
packages/openapi-ts/src/plugins/@pinia/colada/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { handler } from './plugin'; 4 4 import type { PiniaColadaPlugin } from './types'; ··· 19 19 enabled: true, 20 20 name: '{{name}}Mutation', 21 21 }, 22 - mappers: { 23 - boolean: (enabled) => ({ enabled }), 24 - function: (name) => ({ name }), 25 - string: (name) => ({ name }), 26 - }, 22 + mappers, 27 23 value: plugin.config.mutationOptions, 28 24 }); 29 25 ··· 34 30 name: '{{name}}QueryKey', 35 31 tags: false, 36 32 }, 37 - mappers: { 38 - boolean: (enabled) => ({ enabled }), 39 - function: (name) => ({ name }), 40 - string: (name) => ({ name }), 41 - }, 33 + mappers, 42 34 value: plugin.config.queryKeys, 43 35 }); 44 36 ··· 48 40 enabled: true, 49 41 name: '{{name}}Query', 50 42 }, 51 - mappers: { 52 - boolean: (enabled) => ({ enabled }), 53 - function: (name) => ({ name }), 54 - string: (name) => ({ name }), 55 - }, 43 + mappers, 56 44 value: plugin.config.queryOptions, 57 45 }); 58 46 },
+6 -26
packages/openapi-ts/src/plugins/@tanstack/angular-query-experimental/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { handler } from '../../../plugins/@tanstack/query-core/plugin'; 4 4 import type { TanStackAngularQueryPlugin } from './types'; ··· 20 20 name: '{{name}}InfiniteQueryKey', 21 21 tags: false, 22 22 }, 23 - mappers: { 24 - boolean: (enabled) => ({ enabled }), 25 - function: (name) => ({ name }), 26 - string: (name) => ({ name }), 27 - }, 23 + mappers, 28 24 value: plugin.config.infiniteQueryKeys, 29 25 }); 30 26 ··· 34 30 enabled: true, 35 31 name: '{{name}}InfiniteOptions', 36 32 }, 37 - mappers: { 38 - boolean: (enabled) => ({ enabled }), 39 - function: (name) => ({ name }), 40 - string: (name) => ({ name }), 41 - }, 33 + mappers, 42 34 value: plugin.config.infiniteQueryOptions, 43 35 }); 44 36 ··· 48 40 enabled: true, 49 41 name: '{{name}}Mutation', 50 42 }, 51 - mappers: { 52 - boolean: (enabled) => ({ enabled }), 53 - function: (name) => ({ name }), 54 - string: (name) => ({ name }), 55 - }, 43 + mappers, 56 44 value: plugin.config.mutationOptions, 57 45 }); 58 46 ··· 63 51 name: '{{name}}QueryKey', 64 52 tags: false, 65 53 }, 66 - mappers: { 67 - boolean: (enabled) => ({ enabled }), 68 - function: (name) => ({ name }), 69 - string: (name) => ({ name }), 70 - }, 54 + mappers, 71 55 value: plugin.config.queryKeys, 72 56 }); 73 57 ··· 78 62 exported: true, 79 63 name: '{{name}}Options', 80 64 }, 81 - mappers: { 82 - boolean: (enabled) => ({ enabled }), 83 - function: (name) => ({ name }), 84 - string: (name) => ({ name }), 85 - }, 65 + mappers, 86 66 value: plugin.config.queryOptions, 87 67 }); 88 68 },
+6 -26
packages/openapi-ts/src/plugins/@tanstack/react-query/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { handler } from '../../../plugins/@tanstack/query-core/plugin'; 4 4 import type { TanStackReactQueryPlugin } from './types'; ··· 20 20 name: '{{name}}InfiniteQueryKey', 21 21 tags: false, 22 22 }, 23 - mappers: { 24 - boolean: (enabled) => ({ enabled }), 25 - function: (name) => ({ name }), 26 - string: (name) => ({ name }), 27 - }, 23 + mappers, 28 24 value: plugin.config.infiniteQueryKeys, 29 25 }); 30 26 ··· 34 30 enabled: true, 35 31 name: '{{name}}InfiniteOptions', 36 32 }, 37 - mappers: { 38 - boolean: (enabled) => ({ enabled }), 39 - function: (name) => ({ name }), 40 - string: (name) => ({ name }), 41 - }, 33 + mappers, 42 34 value: plugin.config.infiniteQueryOptions, 43 35 }); 44 36 ··· 48 40 enabled: true, 49 41 name: '{{name}}Mutation', 50 42 }, 51 - mappers: { 52 - boolean: (enabled) => ({ enabled }), 53 - function: (name) => ({ name }), 54 - string: (name) => ({ name }), 55 - }, 43 + mappers, 56 44 value: plugin.config.mutationOptions, 57 45 }); 58 46 ··· 63 51 name: '{{name}}QueryKey', 64 52 tags: false, 65 53 }, 66 - mappers: { 67 - boolean: (enabled) => ({ enabled }), 68 - function: (name) => ({ name }), 69 - string: (name) => ({ name }), 70 - }, 54 + mappers, 71 55 value: plugin.config.queryKeys, 72 56 }); 73 57 ··· 78 62 exported: true, 79 63 name: '{{name}}Options', 80 64 }, 81 - mappers: { 82 - boolean: (enabled) => ({ enabled }), 83 - function: (name) => ({ name }), 84 - string: (name) => ({ name }), 85 - }, 65 + mappers, 86 66 value: plugin.config.queryOptions, 87 67 }); 88 68
+6 -26
packages/openapi-ts/src/plugins/@tanstack/solid-query/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { handler } from '../../../plugins/@tanstack/query-core/plugin'; 4 4 import type { TanStackSolidQueryPlugin } from './types'; ··· 20 20 name: '{{name}}InfiniteQueryKey', 21 21 tags: false, 22 22 }, 23 - mappers: { 24 - boolean: (enabled) => ({ enabled }), 25 - function: (name) => ({ name }), 26 - string: (name) => ({ name }), 27 - }, 23 + mappers, 28 24 value: plugin.config.infiniteQueryKeys, 29 25 }); 30 26 ··· 34 30 enabled: true, 35 31 name: '{{name}}InfiniteOptions', 36 32 }, 37 - mappers: { 38 - boolean: (enabled) => ({ enabled }), 39 - function: (name) => ({ name }), 40 - string: (name) => ({ name }), 41 - }, 33 + mappers, 42 34 value: plugin.config.infiniteQueryOptions, 43 35 }); 44 36 ··· 48 40 enabled: true, 49 41 name: '{{name}}Mutation', 50 42 }, 51 - mappers: { 52 - boolean: (enabled) => ({ enabled }), 53 - function: (name) => ({ name }), 54 - string: (name) => ({ name }), 55 - }, 43 + mappers, 56 44 value: plugin.config.mutationOptions, 57 45 }); 58 46 ··· 63 51 name: '{{name}}QueryKey', 64 52 tags: false, 65 53 }, 66 - mappers: { 67 - boolean: (enabled) => ({ enabled }), 68 - function: (name) => ({ name }), 69 - string: (name) => ({ name }), 70 - }, 54 + mappers, 71 55 value: plugin.config.queryKeys, 72 56 }); 73 57 ··· 78 62 exported: true, 79 63 name: '{{name}}Options', 80 64 }, 81 - mappers: { 82 - boolean: (enabled) => ({ enabled }), 83 - function: (name) => ({ name }), 84 - string: (name) => ({ name }), 85 - }, 65 + mappers, 86 66 value: plugin.config.queryOptions, 87 67 }); 88 68 },
+6 -26
packages/openapi-ts/src/plugins/@tanstack/svelte-query/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { handler } from '../../../plugins/@tanstack/query-core/plugin'; 4 4 import type { TanStackSvelteQueryPlugin } from './types'; ··· 20 20 name: '{{name}}InfiniteQueryKey', 21 21 tags: false, 22 22 }, 23 - mappers: { 24 - boolean: (enabled) => ({ enabled }), 25 - function: (name) => ({ name }), 26 - string: (name) => ({ name }), 27 - }, 23 + mappers, 28 24 value: plugin.config.infiniteQueryKeys, 29 25 }); 30 26 ··· 34 30 enabled: true, 35 31 name: '{{name}}InfiniteOptions', 36 32 }, 37 - mappers: { 38 - boolean: (enabled) => ({ enabled }), 39 - function: (name) => ({ name }), 40 - string: (name) => ({ name }), 41 - }, 33 + mappers, 42 34 value: plugin.config.infiniteQueryOptions, 43 35 }); 44 36 ··· 48 40 enabled: true, 49 41 name: '{{name}}Mutation', 50 42 }, 51 - mappers: { 52 - boolean: (enabled) => ({ enabled }), 53 - function: (name) => ({ name }), 54 - string: (name) => ({ name }), 55 - }, 43 + mappers, 56 44 value: plugin.config.mutationOptions, 57 45 }); 58 46 ··· 63 51 name: '{{name}}QueryKey', 64 52 tags: false, 65 53 }, 66 - mappers: { 67 - boolean: (enabled) => ({ enabled }), 68 - function: (name) => ({ name }), 69 - string: (name) => ({ name }), 70 - }, 54 + mappers, 71 55 value: plugin.config.queryKeys, 72 56 }); 73 57 ··· 78 62 exported: true, 79 63 name: '{{name}}Options', 80 64 }, 81 - mappers: { 82 - boolean: (enabled) => ({ enabled }), 83 - function: (name) => ({ name }), 84 - string: (name) => ({ name }), 85 - }, 65 + mappers, 86 66 value: plugin.config.queryOptions, 87 67 }); 88 68 },
+6 -26
packages/openapi-ts/src/plugins/@tanstack/vue-query/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { handler } from '../../../plugins/@tanstack/query-core/plugin'; 4 4 import type { TanStackVueQueryPlugin } from './types'; ··· 20 20 name: '{{name}}InfiniteQueryKey', 21 21 tags: false, 22 22 }, 23 - mappers: { 24 - boolean: (enabled) => ({ enabled }), 25 - function: (name) => ({ name }), 26 - string: (name) => ({ name }), 27 - }, 23 + mappers, 28 24 value: plugin.config.infiniteQueryKeys, 29 25 }); 30 26 ··· 34 30 enabled: true, 35 31 name: '{{name}}InfiniteOptions', 36 32 }, 37 - mappers: { 38 - boolean: (enabled) => ({ enabled }), 39 - function: (name) => ({ name }), 40 - string: (name) => ({ name }), 41 - }, 33 + mappers, 42 34 value: plugin.config.infiniteQueryOptions, 43 35 }); 44 36 ··· 48 40 enabled: true, 49 41 name: '{{name}}Mutation', 50 42 }, 51 - mappers: { 52 - boolean: (enabled) => ({ enabled }), 53 - function: (name) => ({ name }), 54 - string: (name) => ({ name }), 55 - }, 43 + mappers, 56 44 value: plugin.config.mutationOptions, 57 45 }); 58 46 ··· 63 51 name: '{{name}}QueryKey', 64 52 tags: false, 65 53 }, 66 - mappers: { 67 - boolean: (enabled) => ({ enabled }), 68 - function: (name) => ({ name }), 69 - string: (name) => ({ name }), 70 - }, 54 + mappers, 71 55 value: plugin.config.queryKeys, 72 56 }); 73 57 ··· 78 62 exported: true, 79 63 name: '{{name}}Options', 80 64 }, 81 - mappers: { 82 - boolean: (enabled) => ({ enabled }), 83 - function: (name) => ({ name }), 84 - string: (name) => ({ name }), 85 - }, 65 + mappers, 86 66 value: plugin.config.queryOptions, 87 67 }); 88 68 },
+3 -3
packages/openapi-ts/src/plugins/arktype/shared/export.ts
··· 7 7 import type { ArktypePlugin } from '../types'; 8 8 import type { Ast } from './types'; 9 9 10 - export const exportAst = ({ 10 + export function exportAst({ 11 11 ast, 12 12 plugin, 13 13 schema, ··· 19 19 schema: IR.SchemaObject; 20 20 symbol: Symbol; 21 21 typeInferSymbol: Symbol | undefined; 22 - }): void => { 22 + }): void { 23 23 const type = plugin.external('arktype.type'); 24 24 25 25 const statement = $.const(symbol) ··· 43 43 .type($.type(symbol).attr(identifiers.type.infer).typeofType()); 44 44 plugin.node(inferType); 45 45 } 46 - }; 46 + }
+6 -6
packages/openapi-ts/src/plugins/arktype/v2/plugin.ts
··· 9 9 import type { ArktypePlugin } from '../types'; 10 10 import { irSchemaWithTypeToAst } from './toAst'; 11 11 12 - export const irSchemaToAst = ({ 12 + export function irSchemaToAst({ 13 13 // optional, 14 14 plugin, 15 15 schema, ··· 22 22 */ 23 23 optional?: boolean; 24 24 schema: IR.SchemaObject; 25 - }): Ast => { 25 + }): Ast { 26 26 let ast: Partial<Ast> = {}; 27 27 28 28 // const z = plugin.referenceSymbol({ ··· 226 226 // } 227 227 228 228 return ast as Ast; 229 - }; 229 + } 230 230 231 - const handleComponent = ({ 231 + function handleComponent({ 232 232 plugin, 233 233 schema, 234 234 state, 235 235 }: IrSchemaToAstOptions & { 236 236 schema: IR.SchemaObject; 237 - }): void => { 237 + }): void { 238 238 const $ref = pathToJsonPointer(fromRef(state.path)); 239 239 const ast = irSchemaToAst({ plugin, schema, state }); 240 240 const baseName = refToName($ref); ··· 267 267 symbol, 268 268 typeInferSymbol, 269 269 }); 270 - }; 270 + } 271 271 272 272 export const handlerV2: ArktypePlugin['Handler'] = ({ plugin }) => { 273 273 plugin.symbol('type', {
+3 -3
packages/openapi-ts/src/plugins/arktype/v2/toAst/index.ts
··· 15 15 // import { unknownToAst } from "./unknown"; 16 16 // import { voidToAst } from "./void"; 17 17 18 - export const irSchemaWithTypeToAst = ({ 18 + export function irSchemaWithTypeToAst({ 19 19 schema, 20 20 ...args 21 21 }: IrSchemaToAstOptions & { 22 22 schema: SchemaWithType; 23 - }): Omit<Ast, 'typeName'> => { 23 + }): Omit<Ast, 'typeName'> { 24 24 switch (schema.type) { 25 25 // case 'array': 26 26 // return arrayToAst({ ··· 99 99 expression, 100 100 hasLazyExpression: false, 101 101 }; 102 - }; 102 + }
+6 -26
packages/openapi-ts/src/plugins/swr/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { handler } from './plugin'; 4 4 import type { SwrPlugin } from './types'; ··· 20 20 name: '{{name}}InfiniteQueryKey', 21 21 tags: false, 22 22 }, 23 - mappers: { 24 - boolean: (enabled) => ({ enabled }), 25 - function: (name) => ({ name }), 26 - string: (name) => ({ name }), 27 - }, 23 + mappers, 28 24 value: plugin.config.infiniteQueryKeys, 29 25 }); 30 26 ··· 34 30 enabled: true, 35 31 name: '{{name}}InfiniteOptions', 36 32 }, 37 - mappers: { 38 - boolean: (enabled) => ({ enabled }), 39 - function: (name) => ({ name }), 40 - string: (name) => ({ name }), 41 - }, 33 + mappers, 42 34 value: plugin.config.infiniteQueryOptions, 43 35 }); 44 36 ··· 48 40 enabled: true, 49 41 name: '{{name}}Mutation', 50 42 }, 51 - mappers: { 52 - boolean: (enabled) => ({ enabled }), 53 - function: (name) => ({ name }), 54 - string: (name) => ({ name }), 55 - }, 43 + mappers, 56 44 value: plugin.config.mutationOptions, 57 45 }); 58 46 ··· 63 51 name: '{{name}}QueryKey', 64 52 tags: false, 65 53 }, 66 - mappers: { 67 - boolean: (enabled) => ({ enabled }), 68 - function: (name) => ({ name }), 69 - string: (name) => ({ name }), 70 - }, 54 + mappers, 71 55 value: plugin.config.queryKeys, 72 56 }); 73 57 ··· 78 62 exported: true, 79 63 name: '{{name}}Options', 80 64 }, 81 - mappers: { 82 - boolean: (enabled) => ({ enabled }), 83 - function: (name) => ({ name }), 84 - string: (name) => ({ name }), 85 - }, 65 + mappers, 86 66 value: plugin.config.queryOptions, 87 67 }); 88 68
+5 -21
packages/openapi-ts/src/plugins/valibot/config.ts
··· 1 - import { definePluginConfig } from '@hey-api/shared'; 1 + import { definePluginConfig, mappers } from '@hey-api/shared'; 2 2 3 3 import { Api } from './api'; 4 4 import { handler } from './plugin'; ··· 21 21 enabled: true, 22 22 name: 'v{{name}}', 23 23 }, 24 - mappers: { 25 - boolean: (enabled) => ({ enabled }), 26 - function: (name) => ({ name }), 27 - string: (name) => ({ name }), 28 - }, 24 + mappers, 29 25 value: plugin.config.definitions, 30 26 }); 31 27 ··· 35 31 enabled: true, 36 32 name: 'v{{name}}Data', 37 33 }, 38 - mappers: { 39 - boolean: (enabled) => ({ enabled }), 40 - function: (name) => ({ name }), 41 - string: (name) => ({ name }), 42 - }, 34 + mappers, 43 35 value: plugin.config.requests, 44 36 }); 45 37 ··· 49 41 enabled: true, 50 42 name: 'v{{name}}Response', 51 43 }, 52 - mappers: { 53 - boolean: (enabled) => ({ enabled }), 54 - function: (name) => ({ name }), 55 - string: (name) => ({ name }), 56 - }, 44 + mappers, 57 45 value: plugin.config.responses, 58 46 }); 59 47 ··· 63 51 enabled: true, 64 52 name: 'v{{name}}WebhookRequest', 65 53 }, 66 - mappers: { 67 - boolean: (enabled) => ({ enabled }), 68 - function: (name) => ({ name }), 69 - string: (name) => ({ name }), 70 - }, 54 + mappers, 71 55 value: plugin.config.webhooks, 72 56 }); 73 57 },
+3 -3
packages/openapi-ts/src/plugins/valibot/shared/export.ts
··· 7 7 import { pipesToNode } from './pipes'; 8 8 import type { Ast, IrSchemaToAstOptions } from './types'; 9 9 10 - export const exportAst = ({ 10 + export function exportAst({ 11 11 ast, 12 12 plugin, 13 13 schema, ··· 17 17 ast: Ast; 18 18 schema: IR.SchemaObject; 19 19 symbol: Symbol; 20 - }): void => { 20 + }): void { 21 21 const v = plugin.external('valibot.v'); 22 22 const statement = $.const(symbol) 23 23 .export() ··· 27 27 ) 28 28 .assign(pipesToNode(ast.pipes, plugin)); 29 29 plugin.node(statement); 30 - }; 30 + }
+12 -33
packages/openapi-ts/src/plugins/valibot/types.ts
··· 31 31 * - `boolean`: Shorthand for `{ enabled: boolean }` 32 32 * - `string` or `function`: Shorthand for `{ name: string | function }` 33 33 * - `object`: Full configuration object 34 + * 35 + * @default true 34 36 */ 35 37 definitions?: 36 38 | boolean ··· 73 75 * - `boolean`: Shorthand for `{ enabled: boolean }` 74 76 * - `string` or `function`: Shorthand for `{ name: string | function }` 75 77 * - `object`: Full configuration object 78 + * 79 + * @default true 76 80 */ 77 81 requests?: 78 82 | boolean ··· 107 111 * - `boolean`: Shorthand for `{ enabled: boolean }` 108 112 * - `string` or `function`: Shorthand for `{ name: string | function }` 109 113 * - `object`: Full configuration object 114 + * 115 + * @default true 110 116 */ 111 117 responses?: 112 118 | boolean ··· 173 179 Plugin.Comments & 174 180 Plugin.Exports & 175 181 Resolvers & { 176 - /** 177 - * Casing convention for generated names. 178 - */ 182 + /** Casing convention for generated names. */ 179 183 case: Casing; 180 - /** 181 - * Configuration for reusable schema definitions. 182 - * 183 - * Controls generation of shared Valibot schemas that can be referenced 184 - * across requests and responses. 185 - */ 184 + /** Configuration for reusable schema definitions. */ 186 185 definitions: NamingOptions & FeatureToggle; 187 - /** 188 - * Enable Valibot metadata support? It's often useful to associate a schema 189 - * with some additional metadata for documentation, code generation, AI 190 - * structured outputs, form validation, and other purposes. 191 - * 192 - * @default false 193 - */ 186 + /** Enable Valibot metadata support? */ 194 187 metadata: boolean; 195 - /** 196 - * Configuration for request-specific Valibot schemas. 197 - * 198 - * Controls generation of Valibot schemas for request bodies, query 199 - * parameters, path parameters, and headers. 200 - */ 188 + /** Configuration for request-specific Valibot schemas. */ 201 189 requests: NamingOptions & FeatureToggle; 202 - /** 203 - * Configuration for response-specific Valibot schemas. 204 - * 205 - * Controls generation of Valibot schemas for response bodies, error 206 - * responses, and status codes. 207 - */ 190 + /** Configuration for response-specific Valibot schemas. */ 208 191 responses: NamingOptions & FeatureToggle; 209 - /** 210 - * Configuration for webhook-specific Valibot schemas. 211 - * 212 - * Controls generation of Valibot schemas for webhook payloads. 213 - */ 192 + /** Configuration for webhook-specific Valibot schemas. */ 214 193 webhooks: NamingOptions & FeatureToggle; 215 194 }; 216 195
+6 -6
packages/openapi-ts/src/plugins/valibot/v1/plugin.ts
··· 14 14 import { identifiers } from './constants'; 15 15 import { irSchemaWithTypeToAst } from './toAst'; 16 16 17 - export const irSchemaToAst = ({ 17 + export function irSchemaToAst({ 18 18 optional, 19 19 plugin, 20 20 schema, ··· 27 27 */ 28 28 optional?: boolean; 29 29 schema: IR.SchemaObject; 30 - }): Ast => { 30 + }): Ast { 31 31 const ast: Ast = { 32 32 pipes: [], 33 33 }; ··· 134 134 } 135 135 136 136 return ast as Ast; 137 - }; 137 + } 138 138 139 - const handleComponent = ({ 139 + function handleComponent({ 140 140 plugin, 141 141 schema, 142 142 state, 143 143 }: IrSchemaToAstOptions & { 144 144 schema: IR.SchemaObject; 145 - }): void => { 145 + }): void { 146 146 const $ref = pathToJsonPointer(fromRef(state.path)); 147 147 const ast = irSchemaToAst({ plugin, schema, state }); 148 148 const baseName = refToName($ref); ··· 163 163 state, 164 164 symbol, 165 165 }); 166 - }; 166 + } 167 167 168 168 export const handlerV1: ValibotPlugin['Handler'] = ({ plugin }) => { 169 169 plugin.symbol('v', {
+3 -3
packages/openapi-ts/src/plugins/valibot/v1/toAst/index.ts
··· 17 17 import { unknownToAst } from './unknown'; 18 18 import { voidToAst } from './void'; 19 19 20 - export const irSchemaWithTypeToAst = ({ 20 + export function irSchemaWithTypeToAst({ 21 21 schema, 22 22 ...args 23 23 }: IrSchemaToAstOptions & { ··· 25 25 }): { 26 26 anyType?: string; 27 27 expression: ReturnType<typeof $.call | typeof $.expr>; 28 - } => { 28 + } { 29 29 switch (schema.type) { 30 30 case 'array': 31 31 return { ··· 127 127 }), 128 128 }; 129 129 } 130 - }; 130 + }
+6 -6
packages/openapi-ts/src/plugins/zod/mini/plugin.ts
··· 14 14 import type { ZodPlugin } from '../types'; 15 15 import { irSchemaWithTypeToAst } from './toAst'; 16 16 17 - export const irSchemaToAst = ({ 17 + export function irSchemaToAst({ 18 18 optional, 19 19 plugin, 20 20 schema, ··· 27 27 */ 28 28 optional?: boolean; 29 29 schema: IR.SchemaObject; 30 - }): Ast => { 30 + }): Ast { 31 31 let ast: Partial<Ast> = {}; 32 32 33 33 const z = plugin.external('zod.z'); ··· 153 153 } 154 154 155 155 return ast as Ast; 156 - }; 156 + } 157 157 158 - const handleComponent = ({ 158 + function handleComponent({ 159 159 plugin, 160 160 schema, 161 161 state, 162 162 }: IrSchemaToAstOptions & { 163 163 schema: IR.SchemaObject; 164 - }): void => { 164 + }): void { 165 165 const $ref = pathToJsonPointer(fromRef(state.path)); 166 166 const ast = irSchemaToAst({ plugin, schema, state }); 167 167 const baseName = refToName($ref); ··· 195 195 symbol, 196 196 typeInferSymbol, 197 197 }); 198 - }; 198 + } 199 199 200 200 export const handlerMini: ZodPlugin['Handler'] = ({ plugin }) => { 201 201 plugin.symbol('z', {
+3 -3
packages/openapi-ts/src/plugins/zod/mini/toAst/index.ts
··· 15 15 import { unknownToAst } from './unknown'; 16 16 import { voidToAst } from './void'; 17 17 18 - export const irSchemaWithTypeToAst = ({ 18 + export function irSchemaWithTypeToAst({ 19 19 schema, 20 20 ...args 21 21 }: IrSchemaToAstOptions & { 22 22 schema: SchemaWithType; 23 - }): Omit<Ast, 'typeName'> => { 23 + }): Omit<Ast, 'typeName'> { 24 24 switch (schema.type) { 25 25 case 'array': 26 26 return arrayToAst({ ··· 89 89 schema: schema as SchemaWithType<'void'>, 90 90 }); 91 91 } 92 - }; 92 + }
+3 -3
packages/openapi-ts/src/plugins/zod/shared/export.ts
··· 7 7 import type { ZodPlugin } from '../types'; 8 8 import type { Ast } from './types'; 9 9 10 - export const exportAst = ({ 10 + export function exportAst({ 11 11 ast, 12 12 plugin, 13 13 schema, ··· 19 19 schema: IR.SchemaObject; 20 20 symbol: Symbol; 21 21 typeInferSymbol: Symbol | undefined; 22 - }): void => { 22 + }): void { 23 23 const z = plugin.external('zod.z'); 24 24 25 25 const statement = $.const(symbol) ··· 36 36 .type($.type(z).attr(identifiers.infer).generic($(symbol).typeofType())); 37 37 plugin.node(inferType); 38 38 } 39 - }; 39 + }
+21 -108
packages/openapi-ts/src/plugins/zod/types.ts
··· 410 410 Plugin.Comments & 411 411 Plugin.Exports & 412 412 Resolvers & { 413 - /** 414 - * Casing convention for generated names. 415 - */ 413 + /** Casing convention for generated names. */ 416 414 case: Casing; 417 - /** 418 - * The compatibility version to target for generated output. 419 - * 420 - * Can be: 421 - * - `4`: [Zod 4](https://zod.dev/packages/zod) (default). 422 - * - `3`: [Zod 3](https://v3.zod.dev/). 423 - * - `'mini'`: [Zod Mini](https://zod.dev/packages/mini). 424 - * 425 - * @default 4 426 - */ 415 + /** The compatibility version to target for generated output. */ 427 416 compatibilityVersion: 3 | 4 | 'mini'; 428 - /** 429 - * Configuration for date handling in generated Zod schemas. 430 - * 431 - * Controls how date values are processed and validated using Zod's 432 - * date validation features. 433 - */ 417 + /** Configuration for date handling in generated Zod schemas. */ 434 418 dates: { 435 - /** 436 - * Whether to allow unqualified (timezone-less) datetimes: 437 - * 438 - * When enabled, Zod will accept datetime strings without timezone information. 439 - * When disabled, Zod will require timezone information in datetime strings. 440 - * 441 - * @default false 442 - */ 419 + /** Whether to allow unqualified (timezone-less) datetimes. */ 443 420 local: boolean; 444 - /** 445 - * Whether to include timezone offset information when handling dates. 446 - * 447 - * When enabled, date strings will preserve timezone information. 448 - * When disabled, dates will be treated as local time. 449 - * 450 - * @default false 451 - */ 421 + /** Whether to include timezone offset information when handling dates. */ 452 422 offset: boolean; 453 423 }; 454 - /** 455 - * Configuration for reusable schema definitions. 456 - * 457 - * Controls generation of shared Zod schemas that can be referenced across 458 - * requests and responses. 459 - */ 424 + /** Configuration for reusable schema definitions. */ 460 425 definitions: NamingOptions & 461 426 FeatureToggle & { 462 - /** 463 - * Configuration for TypeScript type generation from Zod schemas. 464 - * 465 - * Controls generation of TypeScript types based on the generated Zod schemas. 466 - */ 427 + /** Configuration for TypeScript type generation from Zod schemas. */ 467 428 types: { 468 - /** 469 - * Configuration for `infer` types. 470 - */ 429 + /** Configuration for `infer` types. */ 471 430 infer: NamingOptions & FeatureToggle; 472 431 }; 473 432 }; 474 - /** 475 - * Enable Zod metadata support? It's often useful to associate a schema with 476 - * some additional metadata for documentation, code generation, AI 477 - * structured outputs, form validation, and other purposes. 478 - * 479 - * @default false 480 - */ 433 + /** Enable Zod metadata support? */ 481 434 metadata: boolean; 482 - /** 483 - * Configuration for request-specific Zod schemas. 484 - * 485 - * Controls generation of Zod schemas for request bodies, query parameters, path 486 - * parameters, and headers. 487 - */ 435 + /** Configuration for request-specific Zod schemas. */ 488 436 requests: NamingOptions & 489 437 FeatureToggle & { 490 - /** 491 - * Configuration for TypeScript type generation from Zod schemas. 492 - * 493 - * Controls generation of TypeScript types based on the generated Zod schemas. 494 - */ 438 + /** Configuration for TypeScript type generation from Zod schemas. */ 495 439 types: { 496 - /** 497 - * Configuration for `infer` types. 498 - */ 440 + /** Configuration for `infer` types. */ 499 441 infer: NamingOptions & FeatureToggle; 500 442 }; 501 443 }; 502 - /** 503 - * Configuration for response-specific Zod schemas. 504 - * 505 - * Controls generation of Zod schemas for response bodies, error responses, 506 - * and status codes. 507 - */ 444 + /** Configuration for response-specific Zod schemas. */ 508 445 responses: NamingOptions & 509 446 FeatureToggle & { 510 - /** 511 - * Configuration for TypeScript type generation from Zod schemas. 512 - * 513 - * Controls generation of TypeScript types based on the generated Zod schemas. 514 - */ 447 + /** Configuration for TypeScript type generation from Zod schemas. */ 515 448 types: { 516 - /** 517 - * Configuration for `infer` types. 518 - */ 449 + /** Configuration for `infer` types. */ 519 450 infer: NamingOptions & FeatureToggle; 520 451 }; 521 452 }; 522 - /** 523 - * Configuration for TypeScript type generation from Zod schemas. 524 - * 525 - * Controls generation of TypeScript types based on the generated Zod schemas. 526 - */ 453 + /** Configuration for TypeScript type generation from Zod schemas. */ 527 454 types: { 528 - /** 529 - * Configuration for `infer` types. 530 - */ 455 + /** Configuration for `infer` types. */ 531 456 infer: FeatureToggle & { 532 - /** 533 - * Casing convention for generated names. 534 - */ 457 + /** Casing convention for generated names. */ 535 458 case: Casing; 536 459 }; 537 460 }; 538 - /** 539 - * Configuration for webhook-specific Zod schemas. 540 - * 541 - * Controls generation of Zod schemas for webhook payloads. 542 - */ 461 + /** Configuration for webhook-specific Zod schemas. */ 543 462 webhooks: NamingOptions & 544 463 FeatureToggle & { 545 - /** 546 - * Configuration for TypeScript type generation from Zod schemas. 547 - * 548 - * Controls generation of TypeScript types based on the generated Zod schemas. 549 - */ 464 + /** Configuration for TypeScript type generation from Zod schemas. */ 550 465 types: { 551 - /** 552 - * Configuration for `infer` types. 553 - */ 466 + /** Configuration for `infer` types. */ 554 467 infer: NamingOptions & FeatureToggle; 555 468 }; 556 469 };
+6 -6
packages/openapi-ts/src/plugins/zod/v3/plugin.ts
··· 14 14 import type { ZodPlugin } from '../types'; 15 15 import { irSchemaWithTypeToAst } from './toAst'; 16 16 17 - export const irSchemaToAst = ({ 17 + export function irSchemaToAst({ 18 18 optional, 19 19 plugin, 20 20 schema, ··· 27 27 */ 28 28 optional?: boolean; 29 29 schema: IR.SchemaObject; 30 - }): Ast => { 30 + }): Ast { 31 31 let ast: Partial<Ast> = {}; 32 32 33 33 const z = plugin.external('zod.z'); ··· 151 151 } 152 152 153 153 return ast as Ast; 154 - }; 154 + } 155 155 156 - const handleComponent = ({ 156 + function handleComponent({ 157 157 plugin, 158 158 schema, 159 159 state, 160 160 }: IrSchemaToAstOptions & { 161 161 schema: IR.SchemaObject; 162 - }): void => { 162 + }): void { 163 163 const $ref = pathToJsonPointer(fromRef(state.path)); 164 164 const ast = irSchemaToAst({ plugin, schema, state }); 165 165 const baseName = refToName($ref); ··· 193 193 symbol, 194 194 typeInferSymbol, 195 195 }); 196 - }; 196 + } 197 197 198 198 export const handlerV3: ZodPlugin['Handler'] = ({ plugin }) => { 199 199 plugin.symbol('z', {
+3 -3
packages/openapi-ts/src/plugins/zod/v3/toAst/index.ts
··· 15 15 import { unknownToAst } from './unknown'; 16 16 import { voidToAst } from './void'; 17 17 18 - export const irSchemaWithTypeToAst = ({ 18 + export function irSchemaWithTypeToAst({ 19 19 schema, 20 20 ...args 21 21 }: IrSchemaToAstOptions & { 22 22 schema: SchemaWithType; 23 23 }): Omit<Ast, 'typeName'> & { 24 24 anyType?: string; 25 - } => { 25 + } { 26 26 switch (schema.type) { 27 27 case 'array': 28 28 return arrayToAst({ ··· 109 109 }), 110 110 }; 111 111 } 112 - }; 112 + }
+6 -6
packages/openapi-ts/src/plugins/zod/v4/plugin.ts
··· 14 14 import type { ZodPlugin } from '../types'; 15 15 import { irSchemaWithTypeToAst } from './toAst'; 16 16 17 - export const irSchemaToAst = ({ 17 + export function irSchemaToAst({ 18 18 optional, 19 19 plugin, 20 20 schema, ··· 27 27 */ 28 28 optional?: boolean; 29 29 schema: IR.SchemaObject; 30 - }): Ast => { 30 + }): Ast { 31 31 let ast: Partial<Ast> = {}; 32 32 33 33 const z = plugin.external('zod.z'); ··· 155 155 } 156 156 157 157 return ast as Ast; 158 - }; 158 + } 159 159 160 - const handleComponent = ({ 160 + function handleComponent({ 161 161 plugin, 162 162 schema, 163 163 state, 164 164 }: IrSchemaToAstOptions & { 165 165 schema: IR.SchemaObject; 166 - }): void => { 166 + }): void { 167 167 const $ref = pathToJsonPointer(fromRef(state.path)); 168 168 const ast = irSchemaToAst({ plugin, schema, state }); 169 169 const baseName = refToName($ref); ··· 197 197 symbol, 198 198 typeInferSymbol, 199 199 }); 200 - }; 200 + } 201 201 202 202 export const handlerV4: ZodPlugin['Handler'] = ({ plugin }) => { 203 203 plugin.symbol('z', {
+3 -3
packages/openapi-ts/src/plugins/zod/v4/toAst/index.ts
··· 15 15 import { unknownToAst } from './unknown'; 16 16 import { voidToAst } from './void'; 17 17 18 - export const irSchemaWithTypeToAst = ({ 18 + export function irSchemaWithTypeToAst({ 19 19 schema, 20 20 ...args 21 21 }: IrSchemaToAstOptions & { 22 22 schema: SchemaWithType; 23 - }): Omit<Ast, 'typeName'> => { 23 + }): Omit<Ast, 'typeName'> { 24 24 switch (schema.type) { 25 25 case 'array': 26 26 return arrayToAst({ ··· 89 89 schema: schema as SchemaWithType<'void'>, 90 90 }); 91 91 } 92 - }; 92 + }
+7
renovate.json
··· 3 3 "dependencyDashboardTitle": "Dependencies 📦", 4 4 "extends": ["config:recommended"], 5 5 "minimumReleaseAge": "3 days", 6 + "packageRules": [ 7 + { 8 + "matchPackageNames": ["zod"], 9 + "matchRepositories": ["./packages/openapi-ts-tests/zod/v3"], 10 + "allowedVersions": "<4.0.0" 11 + } 12 + ], 6 13 "prConcurrentLimit": 4, 7 14 "schedule": ["before 3am on Monday"], 8 15 "updatePinnedDependencies": true