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: remove router options

Lubos 61561825 36636493

+5 -344
+1 -1
dev/typescript/presets.ts
··· 34 34 /** RPC-style SDK with Zod validation */ 35 35 { 36 36 contracts: { 37 - // containerName: 'contract', 37 + containerName: 'contracted', 38 38 strategy: 'single', 39 39 }, 40 40 name: '@orpc/contract',
+2 -60
packages/openapi-ts/src/plugins/@orpc/contract/config.ts
··· 1 1 import { log } from '@hey-api/codegen-core'; 2 - import type { OperationsStrategy, PluginContext } from '@hey-api/shared'; 3 - import { definePluginConfig, resolveNaming } from '@hey-api/shared'; 2 + import { definePluginConfig } from '@hey-api/shared'; 4 3 5 4 import { resolveContracts } from './contracts/config'; 6 5 import { handler } from './plugin'; 7 - import type { OrpcContractPlugin, RouterConfig, UserRouterConfig } from './types'; 6 + import type { OrpcContractPlugin } from './types'; 8 7 9 8 const validatorInferWarn = 10 9 'You set `validator: true` but no validator plugin was found in your plugins. Add a validator plugin like `zod` to enable this feature. The validator option has been disabled.'; 11 10 12 - function resolveRouter( 13 - input: OperationsStrategy | UserRouterConfig | undefined, 14 - context: PluginContext, 15 - ): RouterConfig { 16 - if (!input || typeof input === 'string' || typeof input === 'function') { 17 - input = { strategy: input }; 18 - } 19 - 20 - const strategy = input.strategy ?? 'flat'; 21 - 22 - return context.valueToObject({ 23 - defaultValue: { 24 - nesting: 'operationId', 25 - nestingDelimiters: /[./]/, 26 - strategy, 27 - strategyDefaultTag: 'default', 28 - }, 29 - mappers: { 30 - object(value) { 31 - value.methodName = context.valueToObject({ 32 - defaultValue: { casing: 'camelCase' }, 33 - mappers: { 34 - function: (name) => ({ name }), 35 - string: (name) => ({ name }), 36 - }, 37 - value: value.methodName, 38 - }); 39 - value.segmentName = context.valueToObject({ 40 - defaultValue: { casing: 'camelCase' }, 41 - mappers: { 42 - function: (name) => ({ name }), 43 - string: (name) => ({ name }), 44 - }, 45 - value: value.segmentName, 46 - }); 47 - return value; 48 - }, 49 - }, 50 - value: input, 51 - }) as RouterConfig; 52 - } 53 - 54 11 export const defaultConfig: OrpcContractPlugin['Config'] = { 55 12 config: { 56 13 includeInEntry: false, 57 - router: { 58 - methodName: { casing: 'camelCase' }, 59 - nesting: 'operationId', 60 - nestingDelimiters: /[./]/, 61 - segmentName: { casing: 'camelCase' }, 62 - strategy: 'flat', 63 - strategyDefaultTag: 'default', 64 - }, 65 - routerName: { name: 'router' }, 66 14 }, 67 15 handler, 68 16 name: '@orpc/contract', 69 17 resolveConfig: (plugin, context) => { 70 - plugin.config.router = resolveRouter(plugin.config.router, context); 71 - plugin.config.routerName = resolveNaming(plugin.config.routerName); 72 - if (!plugin.config.routerName.name) { 73 - plugin.config.routerName.name = 'router'; 74 - } 75 - 76 18 if (typeof plugin.config.validator !== 'object') { 77 19 plugin.config.validator = { 78 20 input: plugin.config.validator,
-39
packages/openapi-ts/src/plugins/@orpc/contract/shared/operation.ts
··· 1 1 import type { IR } from '@hey-api/shared'; 2 - import { OperationPath, OperationStrategy } from '@hey-api/shared'; 3 - 4 - import type { RouterConfig } from '../types'; 5 2 6 3 export function hasInput(operation: IR.OperationObject): boolean { 7 4 const hasPathParams = Boolean( ··· 39 36 export function getTags(operation: IR.OperationObject, defaultTag: string): ReadonlyArray<string> { 40 37 return operation.tags && operation.tags.length > 0 ? [...operation.tags] : [defaultTag]; 41 38 } 42 - 43 - export function getOperationPaths( 44 - operation: IR.OperationObject, 45 - routerConfig: RouterConfig, 46 - ): ReadonlyArray<ReadonlyArray<string>> { 47 - const { nesting, nestingDelimiters, strategy, strategyDefaultTag } = routerConfig; 48 - 49 - // Get path derivation function 50 - let pathFn = OperationPath.id(); 51 - if (typeof nesting === 'function') { 52 - pathFn = nesting; 53 - } else if (nesting === 'operationId') { 54 - pathFn = OperationPath.fromOperationId({ delimiters: nestingDelimiters }); 55 - } 56 - 57 - // Get structure strategy function 58 - let strategyFn; 59 - if (typeof strategy === 'function') { 60 - strategyFn = strategy; 61 - } else if (strategy === 'byTags') { 62 - strategyFn = OperationStrategy.byTags({ 63 - fallback: strategyDefaultTag, 64 - path: pathFn, 65 - }); 66 - } else if (strategy === 'single') { 67 - strategyFn = OperationStrategy.single({ 68 - path: pathFn, 69 - root: strategyDefaultTag, 70 - }); 71 - } else { 72 - // flat 73 - strategyFn = OperationStrategy.flat({ path: pathFn }); 74 - } 75 - 76 - return strategyFn(operation); 77 - }
+1 -151
packages/openapi-ts/src/plugins/@orpc/contract/types.d.ts
··· 1 - import type { 2 - // Casing, 3 - DefinePlugin, 4 - // FeatureToggle, 5 - // IR, 6 - // NameTransformer, 7 - // NamingOptions, 8 - NamingConfig, 9 - NamingRule, 10 - OperationPathStrategy, 11 - OperationsStrategy, 12 - Plugin, 13 - } from '@hey-api/shared'; 1 + import type { DefinePlugin, OperationsStrategy, Plugin } from '@hey-api/shared'; 14 2 15 3 import type { PluginValidatorNames } from '../../types'; 16 4 import type { ContractsConfig, UserContractsConfig } from './contracts/types'; 17 5 18 - export interface UserRouterConfig { 19 - /** 20 - * Customize method/key names for operations in the router. 21 - * 22 - * Applied to the final segment of the path. 23 - */ 24 - methodName?: NamingRule; 25 - /** 26 - * How to derive nesting structure from operations. 27 - * 28 - * - `'operationId'` - Split operationId by delimiters (e.g., `users.list` → `{ users: { list } }`) 29 - * - `'id'` - Use operation id as-is, no nesting 30 - * - Custom function for full control 31 - * 32 - * @default 'operationId' 33 - */ 34 - nesting?: 'id' | 'operationId' | OperationPathStrategy; 35 - /** 36 - * Delimiters for splitting operationId. 37 - * 38 - * Only applies when `nesting` is `'operationId'`. 39 - * 40 - * @default /[./]/ 41 - */ 42 - nestingDelimiters?: RegExp; 43 - /** 44 - * Customize segment names for nested groups. 45 - * 46 - * Applied to intermediate path segments (not the key name). 47 - */ 48 - segmentName?: NamingRule; 49 - /** 50 - * Grouping strategy. 51 - * 52 - * - `'flat'` - No grouping, all contracts at root level 53 - * - `'byTags'` - One group per operation tag 54 - * - `'single'` - All operations in one group 55 - * - Custom function for full control 56 - * 57 - * @default 'flat' 58 - */ 59 - strategy?: OperationsStrategy; 60 - /** 61 - * Default group name for operations without tags. 62 - * 63 - * Only applies when `strategy` is `'byTags'`. 64 - * 65 - * @default 'default' 66 - */ 67 - strategyDefaultTag?: string; 68 - } 69 - 70 - export interface RouterConfig { 71 - /** 72 - * Customize method/key names for operations in the router. 73 - * 74 - * Applied to the final segment of the path. 75 - */ 76 - methodName: NamingConfig; 77 - /** 78 - * How to derive nesting structure from operations. 79 - * 80 - * - `'operationId'` - Split operationId by delimiters (e.g., `users.list` → `{ users: { list } }`) 81 - * - `'id'` - Use operation id as-is, no nesting 82 - * - Custom function for full control 83 - */ 84 - nesting: 'id' | 'operationId' | OperationPathStrategy; 85 - /** 86 - * Delimiters for splitting operationId. 87 - * 88 - * Only applies when `nesting` is `'operationId'`. 89 - */ 90 - nestingDelimiters: RegExp; 91 - /** 92 - * Customize segment names for nested groups. 93 - * 94 - * Applied to intermediate path segments (not the key name). 95 - */ 96 - segmentName: NamingConfig; 97 - /** 98 - * Grouping strategy. 99 - * 100 - * - `'flat'` - No grouping, all contracts at root level 101 - * - `'byTags'` - One group per operation tag 102 - * - `'single'` - All operations in one group 103 - * - Custom function for full control 104 - */ 105 - strategy: OperationsStrategy; 106 - /** 107 - * Default group name for operations without tags. 108 - * 109 - * Only applies when `strategy` is `'byTags'`. 110 - */ 111 - strategyDefaultTag: string; 112 - } 113 - 114 6 export type UserConfig = Plugin.Name<'@orpc/contract'> & 115 7 Plugin.Hooks & 116 8 Plugin.UserExports & { ··· 129 21 */ 130 22 contracts?: OperationsStrategy | UserContractsConfig; 131 23 /** 132 - * Router configuration for grouping and nesting operations. 133 - * 134 - * Can be a strategy string for simple cases, or an object for full control. 135 - * 136 - * @default { strategy: 'flat' } 137 - * 138 - * @example 139 - * // Simple: just set strategy 140 - * router: 'byTags' 141 - * 142 - * @example 143 - * // Full control 144 - * router: { 145 - * strategy: 'byTags', 146 - * nesting: 'operationId', 147 - * segmentName: { casing: 'camelCase' }, 148 - * methodName: { casing: 'camelCase' }, 149 - * } 150 - */ 151 - router?: OperationsStrategy | UserRouterConfig; 152 - /** 153 - * Naming rule for the router export. 154 - * The type export will be the PascalCase version (e.g., 'router' → 'Router'). 155 - * 156 - * @default 'router' 157 - * 158 - * @example 159 - * // Simple string 160 - * routerName: 'contract' 161 - * 162 - * @example 163 - * // Template string 164 - * routerName: '{{name}}Contract' 165 - * 166 - * @example 167 - * // With casing 168 - * routerName: { name: '{{name}}Contract', casing: 'camelCase' } 169 - */ 170 - routerName?: NamingRule; 171 - /** 172 24 * Validate input/output schemas. 173 25 * 174 26 * @default true ··· 203 55 Plugin.Exports & { 204 56 /** Define the structure of generated oRPC contracts. */ 205 57 contracts: ContractsConfig; 206 - router: RouterConfig; 207 - routerName: NamingConfig; 208 58 /** Validate input/output schemas. */ 209 59 validator: { 210 60 /** The validator plugin to use for input schemas. */
+1 -93
packages/openapi-ts/src/plugins/@orpc/contract/v1/plugin.ts
··· 1 - import type { NodeName, Symbol } from '@hey-api/codegen-core'; 2 1 import { StructureModel } from '@hey-api/codegen-core'; 3 - import { applyNaming, toCase } from '@hey-api/shared'; 4 2 5 3 import { $ } from '../../../../ts-dsl'; 6 4 import type { ContractItem } from '../contracts'; 7 5 import { createShell, resolveStrategy, source, toNode } from '../contracts'; 8 - import { getOperationPaths } from '../shared/operation'; 9 6 import type { OrpcContractPlugin } from '../types'; 10 7 11 - type NestedLeaf = { type: 'leaf'; value: NodeName }; 12 - type NestedNode = { children: Map<string, NestedValue>; type: 'node' }; 13 - type NestedValue = NestedLeaf | NestedNode; 14 - 15 - function buildNestedObject(node: NestedNode): ReturnType<typeof $.object> { 16 - const obj = $.object(); 17 - for (const [key, child] of node.children) { 18 - if (child.type === 'leaf') { 19 - obj.prop(key, $(child.value)); 20 - } else { 21 - obj.prop(key, buildNestedObject(child)); 22 - } 23 - } 24 - return obj; 25 - } 26 - 27 8 export const handlerV1: OrpcContractPlugin['Handler'] = ({ plugin }) => { 28 9 const oc = plugin.symbol('oc', { 29 10 external: '@orpc/contract', ··· 43 24 const contractsShell = createShell(plugin); 44 25 const contractsStrategy = resolveStrategy(plugin); 45 26 46 - // Track contract symbols for router generation (keyed by operation ID) 47 - const contractSymbols = new Map<string, Symbol>(); 48 - // Router nested structure (to be refactored later) 49 - const routerRoot: NestedNode = { children: new Map(), type: 'node' }; 50 - // Track router leaf nodes by operation ID for later symbol assignment 51 - const routerLeaves = new Map<string, NestedLeaf>(); 52 - 53 27 plugin.forEach( 54 28 'operation', 55 29 (event) => { ··· 65 39 locations: contractPaths.map((path) => ({ path, shell: contractsShell })), 66 40 source, 67 41 }); 68 - 69 - const routerPaths = getOperationPaths(operation, plugin.config.router); 70 - for (const path of routerPaths) { 71 - let current: NestedNode = routerRoot; 72 - for (let i = 0; i < path.length; i++) { 73 - const isLast = i === path.length - 1; 74 - const segment = isLast 75 - ? applyNaming(path[i]!, plugin.config.router.methodName) 76 - : applyNaming(path[i]!, plugin.config.router.segmentName); 77 - 78 - if (isLast) { 79 - const leaf: NestedLeaf = { 80 - type: 'leaf', 81 - value: undefined as unknown as NodeName, // placeholder, updated after contracts are generated 82 - }; 83 - current.children.set(segment, leaf); 84 - routerLeaves.set(operation.id, leaf); 85 - } else { 86 - if (!current.children.has(segment)) { 87 - current.children.set(segment, { 88 - children: new Map(), 89 - type: 'node', 90 - }); 91 - } 92 - const next = current.children.get(segment)!; 93 - if (next.type === 'node') { 94 - current = next; 95 - } 96 - } 97 - } 98 - } 99 42 }, 100 43 { order: 'declarations' }, 101 44 ); 102 45 103 46 for (const node of contractsStructure.walk()) { 104 - const { nodes, symbols } = toNode(node, plugin, baseSymbol); 105 - 106 - if (symbols) { 107 - for (const [operationId, sym] of symbols) { 108 - contractSymbols.set(operationId, sym); 109 - } 110 - } 47 + const { nodes } = toNode(node, plugin, baseSymbol); 111 48 112 49 for (const node of nodes) { 113 50 plugin.node(node); 114 51 } 115 52 } 116 - 117 - for (const [operationId, leaf] of routerLeaves) { 118 - const sym = contractSymbols.get(operationId); 119 - if (sym) { 120 - leaf.value = sym; 121 - } 122 - } 123 - 124 - const routerExportName = applyNaming('router', plugin.config.routerName); 125 - const routerSymbol = plugin.symbol(routerExportName, { 126 - meta: { 127 - category: 'contract', 128 - resource: 'router', 129 - tool: plugin.name, 130 - }, 131 - }); 132 - const routerNode = $.const(routerSymbol).export().assign(buildNestedObject(routerRoot).pretty()); 133 - plugin.node(routerNode); 134 - 135 - const routerTypeName = toCase(routerExportName, 'PascalCase'); 136 - const routerTypeSymbol = plugin.symbol(routerTypeName, { 137 - meta: { 138 - category: 'type', 139 - resource: 'router', 140 - tool: plugin.name, 141 - }, 142 - }); 143 - const routerTypeNode = $.type.alias(routerTypeSymbol).export().type($.type.query(routerSymbol)); 144 - plugin.node(routerTypeNode); 145 53 };