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: add contracts type

Lubos ee6835d2 014e038e

+287 -163
+3
dev/typescript/presets.ts
··· 33 33 rpc: () => [ 34 34 /** RPC-style SDK with Zod validation */ 35 35 { 36 + contracts: { 37 + containerName: 'contract', 38 + }, 36 39 name: '@orpc/contract', 37 40 }, 38 41 'zod',
+16 -16
packages/openapi-ts-tests/@orpc/contract/v1/__snapshots__/3.0.x/custom-router-name/@orpc/contract.gen.ts
··· 9 9 /** 10 10 * Get all users 11 11 */ 12 - export const getUsersContract = base.route({ 12 + export const getUsers = base.route({ 13 13 method: 'GET', 14 14 operationId: 'getUsers', 15 15 path: '/users', ··· 20 20 /** 21 21 * Create a new user 22 22 */ 23 - export const createUserContract = base.route({ 23 + export const createUser = base.route({ 24 24 method: 'POST', 25 25 operationId: 'createUser', 26 26 path: '/users', ··· 32 32 /** 33 33 * Delete a user 34 34 */ 35 - export const deleteUserContract = base.route({ 35 + export const deleteUser = base.route({ 36 36 method: 'DELETE', 37 37 operationId: 'deleteUser', 38 38 path: '/users/{userId}', ··· 43 43 /** 44 44 * Get a user by ID 45 45 */ 46 - export const getUserByIdContract = base.route({ 46 + export const getUserById = base.route({ 47 47 method: 'GET', 48 48 operationId: 'getUserById', 49 49 path: '/users/{userId}', ··· 54 54 /** 55 55 * Update a user 56 56 */ 57 - export const updateUserContract = base.route({ 57 + export const updateUser = base.route({ 58 58 method: 'PUT', 59 59 operationId: 'updateUser', 60 60 path: '/users/{userId}', ··· 65 65 /** 66 66 * Get all posts 67 67 */ 68 - export const getPostsContract = base.route({ 68 + export const getPosts = base.route({ 69 69 method: 'GET', 70 70 operationId: 'getPosts', 71 71 path: '/posts', ··· 76 76 /** 77 77 * Create a new post 78 78 */ 79 - export const createPostContract = base.route({ 79 + export const createPost = base.route({ 80 80 method: 'POST', 81 81 operationId: 'createPost', 82 82 path: '/posts', ··· 88 88 /** 89 89 * Get a post by ID 90 90 */ 91 - export const getPostByIdContract = base.route({ 91 + export const getPostById = base.route({ 92 92 method: 'GET', 93 93 operationId: 'getPostById', 94 94 path: '/posts/{postId}', ··· 97 97 }).input(zGetPostByIdData).output(zGetPostByIdResponse); 98 98 99 99 export const contract = { 100 - getUsers: getUsersContract, 101 - createUser: createUserContract, 102 - deleteUser: deleteUserContract, 103 - getUserById: getUserByIdContract, 104 - updateUser: updateUserContract, 105 - getPosts: getPostsContract, 106 - createPost: createPostContract, 107 - getPostById: getPostByIdContract 100 + getUsers, 101 + createUser, 102 + deleteUser, 103 + getUserById, 104 + updateUser, 105 + getPosts, 106 + createPost, 107 + getPostById 108 108 }; 109 109 110 110 export type Contract = typeof contract;
+16 -16
packages/openapi-ts-tests/@orpc/contract/v1/__snapshots__/3.0.x/default/@orpc/contract.gen.ts
··· 9 9 /** 10 10 * Get all users 11 11 */ 12 - export const getUsersContract = base.route({ 12 + export const getUsers = base.route({ 13 13 method: 'GET', 14 14 operationId: 'getUsers', 15 15 path: '/users', ··· 20 20 /** 21 21 * Create a new user 22 22 */ 23 - export const createUserContract = base.route({ 23 + export const createUser = base.route({ 24 24 method: 'POST', 25 25 operationId: 'createUser', 26 26 path: '/users', ··· 32 32 /** 33 33 * Delete a user 34 34 */ 35 - export const deleteUserContract = base.route({ 35 + export const deleteUser = base.route({ 36 36 method: 'DELETE', 37 37 operationId: 'deleteUser', 38 38 path: '/users/{userId}', ··· 43 43 /** 44 44 * Get a user by ID 45 45 */ 46 - export const getUserByIdContract = base.route({ 46 + export const getUserById = base.route({ 47 47 method: 'GET', 48 48 operationId: 'getUserById', 49 49 path: '/users/{userId}', ··· 54 54 /** 55 55 * Update a user 56 56 */ 57 - export const updateUserContract = base.route({ 57 + export const updateUser = base.route({ 58 58 method: 'PUT', 59 59 operationId: 'updateUser', 60 60 path: '/users/{userId}', ··· 65 65 /** 66 66 * Get all posts 67 67 */ 68 - export const getPostsContract = base.route({ 68 + export const getPosts = base.route({ 69 69 method: 'GET', 70 70 operationId: 'getPosts', 71 71 path: '/posts', ··· 76 76 /** 77 77 * Create a new post 78 78 */ 79 - export const createPostContract = base.route({ 79 + export const createPost = base.route({ 80 80 method: 'POST', 81 81 operationId: 'createPost', 82 82 path: '/posts', ··· 88 88 /** 89 89 * Get a post by ID 90 90 */ 91 - export const getPostByIdContract = base.route({ 91 + export const getPostById = base.route({ 92 92 method: 'GET', 93 93 operationId: 'getPostById', 94 94 path: '/posts/{postId}', ··· 97 97 }).input(zGetPostByIdData).output(zGetPostByIdResponse); 98 98 99 99 export const router = { 100 - getUsers: getUsersContract, 101 - createUser: createUserContract, 102 - deleteUser: deleteUserContract, 103 - getUserById: getUserByIdContract, 104 - updateUser: updateUserContract, 105 - getPosts: getPostsContract, 106 - createPost: createPostContract, 107 - getPostById: getPostByIdContract 100 + getUsers, 101 + createUser, 102 + deleteUser, 103 + getUserById, 104 + updateUser, 105 + getPosts, 106 + createPost, 107 + getPostById 108 108 }; 109 109 110 110 export type Router = typeof router;
+16 -16
packages/openapi-ts-tests/@orpc/contract/v1/__snapshots__/3.1.x/custom-router-name/@orpc/contract.gen.ts
··· 9 9 /** 10 10 * Get all users 11 11 */ 12 - export const getUsersContract = base.route({ 12 + export const getUsers = base.route({ 13 13 method: 'GET', 14 14 operationId: 'getUsers', 15 15 path: '/users', ··· 20 20 /** 21 21 * Create a new user 22 22 */ 23 - export const createUserContract = base.route({ 23 + export const createUser = base.route({ 24 24 method: 'POST', 25 25 operationId: 'createUser', 26 26 path: '/users', ··· 32 32 /** 33 33 * Delete a user 34 34 */ 35 - export const deleteUserContract = base.route({ 35 + export const deleteUser = base.route({ 36 36 method: 'DELETE', 37 37 operationId: 'deleteUser', 38 38 path: '/users/{userId}', ··· 43 43 /** 44 44 * Get a user by ID 45 45 */ 46 - export const getUserByIdContract = base.route({ 46 + export const getUserById = base.route({ 47 47 method: 'GET', 48 48 operationId: 'getUserById', 49 49 path: '/users/{userId}', ··· 54 54 /** 55 55 * Update a user 56 56 */ 57 - export const updateUserContract = base.route({ 57 + export const updateUser = base.route({ 58 58 method: 'PUT', 59 59 operationId: 'updateUser', 60 60 path: '/users/{userId}', ··· 65 65 /** 66 66 * Get all posts 67 67 */ 68 - export const getPostsContract = base.route({ 68 + export const getPosts = base.route({ 69 69 method: 'GET', 70 70 operationId: 'getPosts', 71 71 path: '/posts', ··· 76 76 /** 77 77 * Create a new post 78 78 */ 79 - export const createPostContract = base.route({ 79 + export const createPost = base.route({ 80 80 method: 'POST', 81 81 operationId: 'createPost', 82 82 path: '/posts', ··· 88 88 /** 89 89 * Get a post by ID 90 90 */ 91 - export const getPostByIdContract = base.route({ 91 + export const getPostById = base.route({ 92 92 method: 'GET', 93 93 operationId: 'getPostById', 94 94 path: '/posts/{postId}', ··· 97 97 }).input(zGetPostByIdData).output(zGetPostByIdResponse); 98 98 99 99 export const contract = { 100 - getUsers: getUsersContract, 101 - createUser: createUserContract, 102 - deleteUser: deleteUserContract, 103 - getUserById: getUserByIdContract, 104 - updateUser: updateUserContract, 105 - getPosts: getPostsContract, 106 - createPost: createPostContract, 107 - getPostById: getPostByIdContract 100 + getUsers, 101 + createUser, 102 + deleteUser, 103 + getUserById, 104 + updateUser, 105 + getPosts, 106 + createPost, 107 + getPostById 108 108 }; 109 109 110 110 export type Contract = typeof contract;
+16 -16
packages/openapi-ts-tests/@orpc/contract/v1/__snapshots__/3.1.x/default/@orpc/contract.gen.ts
··· 9 9 /** 10 10 * Get all users 11 11 */ 12 - export const getUsersContract = base.route({ 12 + export const getUsers = base.route({ 13 13 method: 'GET', 14 14 operationId: 'getUsers', 15 15 path: '/users', ··· 20 20 /** 21 21 * Create a new user 22 22 */ 23 - export const createUserContract = base.route({ 23 + export const createUser = base.route({ 24 24 method: 'POST', 25 25 operationId: 'createUser', 26 26 path: '/users', ··· 32 32 /** 33 33 * Delete a user 34 34 */ 35 - export const deleteUserContract = base.route({ 35 + export const deleteUser = base.route({ 36 36 method: 'DELETE', 37 37 operationId: 'deleteUser', 38 38 path: '/users/{userId}', ··· 43 43 /** 44 44 * Get a user by ID 45 45 */ 46 - export const getUserByIdContract = base.route({ 46 + export const getUserById = base.route({ 47 47 method: 'GET', 48 48 operationId: 'getUserById', 49 49 path: '/users/{userId}', ··· 54 54 /** 55 55 * Update a user 56 56 */ 57 - export const updateUserContract = base.route({ 57 + export const updateUser = base.route({ 58 58 method: 'PUT', 59 59 operationId: 'updateUser', 60 60 path: '/users/{userId}', ··· 65 65 /** 66 66 * Get all posts 67 67 */ 68 - export const getPostsContract = base.route({ 68 + export const getPosts = base.route({ 69 69 method: 'GET', 70 70 operationId: 'getPosts', 71 71 path: '/posts', ··· 76 76 /** 77 77 * Create a new post 78 78 */ 79 - export const createPostContract = base.route({ 79 + export const createPost = base.route({ 80 80 method: 'POST', 81 81 operationId: 'createPost', 82 82 path: '/posts', ··· 88 88 /** 89 89 * Get a post by ID 90 90 */ 91 - export const getPostByIdContract = base.route({ 91 + export const getPostById = base.route({ 92 92 method: 'GET', 93 93 operationId: 'getPostById', 94 94 path: '/posts/{postId}', ··· 97 97 }).input(zGetPostByIdData).output(zGetPostByIdResponse); 98 98 99 99 export const router = { 100 - getUsers: getUsersContract, 101 - createUser: createUserContract, 102 - deleteUser: deleteUserContract, 103 - getUserById: getUserByIdContract, 104 - updateUser: updateUserContract, 105 - getPosts: getPostsContract, 106 - createPost: createPostContract, 107 - getPostById: getPostByIdContract 100 + getUsers, 101 + createUser, 102 + deleteUser, 103 + getUserById, 104 + updateUser, 105 + getPosts, 106 + createPost, 107 + getPostById 108 108 }; 109 109 110 110 export type Router = typeof router;
+3 -1
packages/openapi-ts-tests/@orpc/contract/v1/test/3.0.x.test.ts
··· 30 30 plugins: [ 31 31 'zod', 32 32 { 33 - contractNameBuilder: (id: string) => `${id}Rpc`, 33 + contracts: { 34 + contractName: '{{name}}Rpc', 35 + }, 34 36 name: '@orpc/contract', 35 37 }, 36 38 ],
+3 -1
packages/openapi-ts-tests/@orpc/contract/v1/test/3.1.x.test.ts
··· 30 30 plugins: [ 31 31 'zod', 32 32 { 33 - contractNameBuilder: (id: string) => `${id}Rpc`, 33 + contracts: { 34 + contractName: '{{name}}Rpc', 35 + }, 34 36 name: '@orpc/contract', 35 37 }, 36 38 ],
+2 -2
packages/openapi-ts/src/plugins/@hey-api/sdk/operations/config.ts
··· 1 1 import { log } from '@hey-api/codegen-core'; 2 - import type { OperationsStrategy, PluginContext } from '@hey-api/shared'; 2 + import type { PluginContext } from '@hey-api/shared'; 3 3 4 4 import type { UserConfig } from '../types'; 5 5 import type { OperationsConfig, UserOperationsConfig } from './types'; ··· 60 60 } 61 61 62 62 function normalizeConfig( 63 - input: OperationsStrategy | UserOperationsConfig | undefined, 63 + input: Config['operations'], 64 64 legacy: Partial<OperationsConfig>, 65 65 context: PluginContext, 66 66 ): OperationsConfig {
+11 -72
packages/openapi-ts/src/plugins/@hey-api/sdk/operations/types.ts
··· 16 16 * @default 'class' 17 17 */ 18 18 container?: 'class'; 19 - // * - `'object'` - Plain object literal 19 + // * - `'object'` - Object with properties 20 20 // container?: 'class' | 'object'; 21 21 /** 22 22 * Customize container names. ··· 102 102 } 103 103 104 104 export interface OperationsConfig { 105 - /** 106 - * Type of container for grouped operations. 107 - * 108 - * Ignored when `strategy` is `'flat'`. 109 - * 110 - * - `'class'` - Class with methods 111 - */ 105 + /** Type of container for grouped operations. */ 112 106 container: 'class'; 113 - // * - `'object'` - Plain object literal 107 + // * - `'object'` - Object with properties 114 108 // container: 'class' | 'object'; 115 - /** 116 - * Customize container names. 117 - * 118 - * For `'single'` strategy, this sets the root container name. 119 - * For `'byTags'` strategy, this transforms tag names. 120 - * 121 - * @default 'Sdk' for `'single'` strategy 122 - * 123 - * @example 124 - * // Set root name for single strategy 125 - * containerName: 'MyApi' 126 - * 127 - * @example 128 - * // Transform tag names with suffix 129 - * containerName: '{{name}}Service' 130 - * 131 - * @example 132 - * // With casing 133 - * containerName: { name: '{{name}}Service', case: 'PascalCase' } 134 - */ 109 + /** Customize container names. */ 135 110 containerName: NamingConfig; 136 - /** 137 - * Customize method/function names. 138 - * 139 - * Applied to the final segment of the path (the method name). 140 - */ 111 + /** Customize method/function names. */ 141 112 methodName: NamingConfig; 142 - /** 143 - * How methods are attached to class containers. 144 - * 145 - * Only applies when `container` is `'class'`. 146 - * 147 - * - `'static'` - Static methods, no instantiation required 148 - * - `'instance'` - Instance methods, requires `new ClassName(config)` 149 - */ 113 + /** How methods are attached to class containers. */ 150 114 methods: 'instance' | 'static'; 151 - /** 152 - * How to derive nesting structure from operations. 153 - * 154 - * - `'operationId'` - Split operationId by delimiters (e.g., `users.list` → `Users.list()`) 155 - * - `'id'` - Use operation id as-is, no nesting 156 - * - Custom function for full control 157 - */ 115 + /** How to derive nesting structure from operations. */ 158 116 nesting: 'operationId' | 'id' | OperationPathStrategy; 159 - /** 160 - * Delimiters for splitting operationId. 161 - * 162 - * Only applies when `nesting` is `'operationId'`. 163 - */ 117 + /** Delimiters for splitting operationId. */ 164 118 nestingDelimiters: RegExp; 165 - /** 166 - * Customize nesting segment names. 167 - * 168 - * Applied to intermediate path segments (not the method name). 169 - */ 119 + /** Customize nesting segment names. */ 170 120 segmentName: NamingConfig; 171 - /** 172 - * Grouping strategy. 173 - * 174 - * - `'flat'` - Standalone functions, no grouping 175 - * - `'byTags'` - One container per operation tag 176 - * - `'single'` - All operations in one container 177 - * - Custom function for full control 178 - */ 121 + /** Grouping strategy. */ 179 122 strategy: OperationsStrategy; 180 - /** 181 - * Default container name for operations without tags. 182 - * 183 - * Only applies when `strategy` is `'byTags'`. 184 - */ 123 + /** Default container name for operations without tags. */ 185 124 strategyDefaultTag: string; 186 125 }
+2 -6
packages/openapi-ts/src/plugins/@hey-api/sdk/types.ts
··· 215 215 * @default true 216 216 */ 217 217 client: PluginClientNames | false; 218 - /** 219 - * Configuration for generating SDK code examples. 220 - */ 218 + /** Configuration for generating SDK code examples. */ 221 219 examples: ExamplesConfig; 222 - /** 223 - * Define the structure of generated SDK operations. 224 - */ 220 + /** Define the structure of generated SDK operations. */ 225 221 operations: OperationsConfig; 226 222 /** 227 223 * Define how request parameters are structured in generated SDK methods.
+3 -2
packages/openapi-ts/src/plugins/@orpc/contract/config.ts
··· 2 2 import type { OperationsStrategy, PluginContext } from '@hey-api/shared'; 3 3 import { definePluginConfig, resolveNaming } from '@hey-api/shared'; 4 4 5 + import { resolveContracts } from './contracts/config'; 5 6 import { handler } from './plugin'; 6 7 import type { OrpcContractPlugin, RouterConfig, UserRouterConfig } from './types'; 7 8 ··· 52 53 53 54 export const defaultConfig: OrpcContractPlugin['Config'] = { 54 55 config: { 55 - contractNameBuilder: (id: string) => `${id}Contract`, 56 56 includeInEntry: false, 57 57 router: { 58 58 methodName: { casing: 'camelCase' }, ··· 67 67 handler, 68 68 name: '@orpc/contract', 69 69 resolveConfig: (plugin, context) => { 70 - plugin.config.contractNameBuilder ??= (id: string) => `${id}Contract`; 71 70 plugin.config.router = resolveRouter(plugin.config.router, context); 72 71 plugin.config.routerName = resolveNaming(plugin.config.routerName); 73 72 if (!plugin.config.routerName.name) { ··· 124 123 } else { 125 124 plugin.config.validator.output = false; 126 125 } 126 + 127 + plugin.config.contracts = resolveContracts(plugin.config, context); 127 128 }, 128 129 }; 129 130
+61
packages/openapi-ts/src/plugins/@orpc/contract/contracts/config.ts
··· 1 + import type { PluginContext } from '@hey-api/shared'; 2 + 3 + import type { UserConfig } from '../types'; 4 + import type { ContractsConfig } from './types'; 5 + 6 + type Config = Omit<UserConfig, 'name'>; 7 + 8 + export function resolveContracts(config: Config, context: PluginContext): ContractsConfig { 9 + return normalizeConfig(config.contracts, context); 10 + } 11 + 12 + function normalizeConfig(input: Config['contracts'], context: PluginContext): ContractsConfig { 13 + if (!input || typeof input === 'string' || typeof input === 'function') { 14 + input = { strategy: input }; 15 + } 16 + 17 + const strategy = input.strategy ?? 'flat'; 18 + 19 + return context.valueToObject({ 20 + defaultValue: { 21 + container: 'object', 22 + nesting: 'operationId', 23 + nestingDelimiters: /[./]/, 24 + strategy, 25 + strategyDefaultTag: 'default', 26 + }, 27 + mappers: { 28 + object(value) { 29 + value.containerName = context.valueToObject({ 30 + defaultValue: 31 + strategy === 'single' 32 + ? { casing: 'camelCase', name: 'contract' } 33 + : { casing: 'camelCase' }, 34 + mappers: { 35 + function: (name) => ({ name }), 36 + string: (name) => ({ name }), 37 + }, 38 + value: value.containerName, 39 + }); 40 + value.contractName = context.valueToObject({ 41 + defaultValue: { casing: 'camelCase' }, 42 + mappers: { 43 + function: (name) => ({ name }), 44 + string: (name) => ({ name }), 45 + }, 46 + value: value.contractName, 47 + }); 48 + value.segmentName = context.valueToObject({ 49 + defaultValue: { casing: 'camelCase' }, 50 + mappers: { 51 + function: (name) => ({ name }), 52 + string: (name) => ({ name }), 53 + }, 54 + value: value.segmentName, 55 + }); 56 + return value; 57 + }, 58 + }, 59 + value: input, 60 + }) as ContractsConfig; 61 + }
+108
packages/openapi-ts/src/plugins/@orpc/contract/contracts/types.ts
··· 1 + import type { 2 + NamingConfig, 3 + NamingRule, 4 + OperationPathStrategy, 5 + OperationsStrategy, 6 + } from '@hey-api/shared'; 7 + 8 + export interface UserContractsConfig { 9 + /** 10 + * Type of container for grouped contracts. 11 + * 12 + * Ignored when `strategy` is `'flat'`. 13 + * 14 + * - `'object'` - Object with properties 15 + * 16 + * @default 'object' 17 + */ 18 + container?: 'object'; 19 + /** 20 + * Customize container names. 21 + * 22 + * For `'single'` strategy, this sets the root container name. 23 + * For `'byTags'` strategy, this transforms tag names. 24 + * 25 + * @default 'contract' for `'single'` strategy 26 + * 27 + * @example 28 + * // Set root name for single strategy 29 + * containerName: 'myContract' 30 + * 31 + * @example 32 + * // Transform tag names with suffix 33 + * containerName: '{{name}}Contract' 34 + * 35 + * @example 36 + * // With casing 37 + * containerName: { name: '{{name}}Contract', casing: 'camelCase' } 38 + */ 39 + containerName?: NamingRule; 40 + /** 41 + * Customize contract names. 42 + * 43 + * Applied to the final segment of the path (the contract name). 44 + */ 45 + contractName?: NamingRule; 46 + /** 47 + * How to derive nesting structure from operations. 48 + * 49 + * - `'operationId'` - Split operationId by delimiters (e.g., `users.list` → `Users.list()`) 50 + * - `'id'` - Use operation id as-is, no nesting 51 + * - Custom function for full control 52 + * 53 + * @default 'operationId' 54 + */ 55 + nesting?: 'operationId' | 'id' | OperationPathStrategy; 56 + /** 57 + * Delimiters for splitting operationId. 58 + * 59 + * Only applies when `nesting` is `'operationId'`. 60 + * 61 + * @default /[./]/ 62 + */ 63 + nestingDelimiters?: RegExp; 64 + /** 65 + * Customize nesting segment names. 66 + * 67 + * Applied to intermediate path segments (not the contract name). 68 + */ 69 + segmentName?: NamingRule; 70 + /** 71 + * Grouping strategy. 72 + * 73 + * - `'flat'` - Standalone contracts, no grouping 74 + * - `'byTags'` - One container per operation tag 75 + * - `'single'` - All contracts in one container 76 + * - Custom function for full control 77 + * 78 + * @default 'flat' 79 + */ 80 + strategy?: OperationsStrategy; 81 + /** 82 + * Default container name for operations without tags. 83 + * 84 + * Only applies when `strategy` is `'byTags'`. 85 + * 86 + * @default 'default' 87 + */ 88 + strategyDefaultTag?: string; 89 + } 90 + 91 + export interface ContractsConfig { 92 + /** Type of container for grouped operations. */ 93 + container: 'object'; 94 + /** Customize container names. */ 95 + containerName: NamingConfig; 96 + /** Customize contract names. */ 97 + contractName: NamingConfig; 98 + /** How to derive nesting structure from operations. */ 99 + nesting: 'operationId' | 'id' | OperationPathStrategy; 100 + /** Delimiters for splitting operationId. */ 101 + nestingDelimiters: RegExp; 102 + /** Customize nesting segment names. */ 103 + segmentName: NamingConfig; 104 + /** Grouping strategy. */ 105 + strategy: OperationsStrategy; 106 + /** Default container name for operations without tags. */ 107 + strategyDefaultTag: string; 108 + }
+14 -4
packages/openapi-ts/src/plugins/@orpc/contract/types.d.ts
··· 13 13 } from '@hey-api/shared'; 14 14 15 15 import type { PluginValidatorNames } from '../../types'; 16 + import type { ContractsConfig, UserContractsConfig } from './contracts/types'; 16 17 17 18 export interface UserRouterConfig { 18 19 /** ··· 114 115 Plugin.Hooks & 115 116 Plugin.UserExports & { 116 117 /** 117 - * Custom naming function for contract symbols. 118 + * Define the structure of generated oRPC contracts. 118 119 * 119 - * @default (id) => `${id}Contract` 120 + * String shorthand: 121 + * - `'byTags'` – one container per operation tag 122 + * - `'flat'` – standalone functions, no container 123 + * - `'single'` – all operations in a single container 124 + * - custom function for full control 125 + * 126 + * Use the object form for advanced configuration. 127 + * 128 + * @default 'flat' 120 129 */ 121 - contractNameBuilder?: (operationId: string) => string; 130 + contracts?: OperationsStrategy | UserContractsConfig; 122 131 /** 123 132 * Router configuration for grouping and nesting operations. 124 133 * ··· 192 201 export type Config = Plugin.Name<'@orpc/contract'> & 193 202 Plugin.Hooks & 194 203 Plugin.Exports & { 195 - contractNameBuilder: (operationId: string) => string; 204 + /** Define the structure of generated oRPC contracts. */ 205 + contracts: ContractsConfig; 196 206 router: RouterConfig; 197 207 routerName: NamingConfig; 198 208 /** Validate input/output schemas. */
+13 -11
packages/openapi-ts/src/plugins/@orpc/contract/v1/plugin.ts
··· 44 44 (event) => { 45 45 const { operation } = event; 46 46 47 - const contractName = plugin.config.contractNameBuilder(operation.id); 48 47 const tags = getTags(operation, plugin.config.router.strategyDefaultTag); 49 48 const successResponse = getSuccessResponse(operation); 50 49 51 - const contractSymbol = plugin.symbol(contractName, { 52 - meta: { 53 - category: 'contract', 54 - path: event._path, 55 - resource: 'operation', 56 - resourceId: operation.id, 57 - role: 'contract', 58 - tags, 59 - tool: plugin.name, 50 + const contractSymbol = plugin.symbol( 51 + applyNaming(operation.id, plugin.config.contracts.contractName), 52 + { 53 + meta: { 54 + category: 'contract', 55 + path: event._path, 56 + resource: 'operation', 57 + resourceId: operation.id, 58 + role: 'contract', 59 + tags, 60 + tool: plugin.name, 61 + }, 60 62 }, 61 - }); 63 + ); 62 64 63 65 let expression = $(baseSymbol) 64 66 .attr('route')