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

chore: update Angular plugin

Lubos 601ef707 b2987ed4

+2605 -2039
+17 -9
dev/openapi-ts.config.ts
··· 39 39 path: path.resolve( 40 40 getSpecsPath(), 41 41 // '2.0.x', 42 - '3.0.x', 43 - // '3.1.x', 42 + // '3.0.x', 43 + '3.1.x', 44 44 // 'circular.yaml', 45 45 // 'dutchie.json', 46 46 // 'enum-names-values.yaml', ··· 49 49 // 'invalid', 50 50 // 'object-property-names.yaml', 51 51 // 'openai.yaml', 52 - // 'opencode.yaml', 52 + 'opencode.yaml', 53 53 // 'pagination-ref.yaml', 54 54 // 'schema-const.yaml', 55 55 // 'sdk-instance.yaml', 56 - 'sdk-method-class-conflict.yaml', 56 + // 'sdk-method-class-conflict.yaml', 57 57 // 'sdk-nested-classes.yaml', 58 58 // 'sdk-nested-conflict.yaml', 59 59 // 'string-with-format.yaml', ··· 241 241 { 242 242 // baseUrl: false, 243 243 // exportFromIndex: true, 244 - // name: '@hey-api/client-nuxt', 244 + // name: '@hey-api/client-angular', 245 245 // runtimeConfigPath: path.resolve(__dirname, 'hey-api.ts'), 246 246 // runtimeConfigPath: './src/hey-api.ts', 247 247 // strictBaseUrl: true, ··· 275 275 // }, 276 276 }, 277 277 { 278 - // asClass: true, 278 + asClass: true, 279 279 // auth: false, 280 280 // classNameBuilder: '{{name}}Service', 281 281 // classStructure: 'off', ··· 285 285 // fields.unwrap('path') 286 286 // }, 287 287 // include... 288 - // instance: 'OpencodeClient', 288 + instance: 'OpencodeClient', 289 289 // methodNameBuilder: '{{name}}', 290 290 name: '@hey-api/sdk', 291 291 // operationId: false, ··· 294 294 // signature: 'auto', 295 295 // signature: 'client', 296 296 // signature: 'object', 297 + structure: { 298 + operations: { 299 + containerName: 'OpencodeClient', 300 + strategy: 'single', 301 + }, 302 + }, 297 303 // transformer: '@hey-api/transformers', 298 304 // transformer: true, 299 305 // validator: 'valibot', ··· 601 607 exportFromIndex: true, 602 608 httpRequests: { 603 609 asClass: true, 610 + // enabled: false, 604 611 }, 605 612 httpResources: { 606 - asClass: true, 613 + // asClass: true, 614 + enabled: false, 607 615 }, 608 616 // name: '@angular/common', 609 617 }, 610 618 { 611 619 exportFromIndex: true, 612 620 // mutationOptions: '{{name}}Mutationssss', 613 - name: '@pinia/colada', 621 + // name: '@pinia/colada', 614 622 // queryOptions: { 615 623 // name: '{{name}}Queryyyyy', 616 624 // },
+2
dev/package.json
··· 10 10 "dev": "ts-node ./playground.ts" 11 11 }, 12 12 "devDependencies": { 13 + "@angular/common": "19.2.17", 14 + "@angular/core": "19.2.17", 13 15 "@hey-api/codegen-core": "workspace:*", 14 16 "@hey-api/openapi-ts": "workspace:*", 15 17 "@opencode-ai/sdk": "1.0.170",
+7
packages/codegen-core/src/__tests__/exports.test.ts
··· 53 53 index.Refs<any>, 54 54 index.RenderContext, 55 55 index.Renderer, 56 + index.StructureInsert, 57 + index.StructureItem, 58 + index.StructureLocation, 59 + index.StructureModel, 60 + index.StructureNode, 61 + index.StructureShell, 62 + index.StructureShellResult, 56 63 index.Symbol, 57 64 index.SymbolIdentifier, 58 65 index.SymbolIn,
+9
packages/codegen-core/src/index.ts
··· 41 41 export { fromRef, fromRefs, isRef, ref, refs } from './refs/refs'; 42 42 export type { FromRef, FromRefs, Ref, Refs } from './refs/types'; 43 43 export type { RenderContext, Renderer } from './renderer'; 44 + export { StructureModel } from './structure/model'; 45 + export { StructureNode } from './structure/node'; 46 + export type { 47 + StructureInsert, 48 + StructureItem, 49 + StructureLocation, 50 + StructureShell, 51 + StructureShellResult, 52 + } from './structure/types'; 44 53 export { Symbol } from './symbols/symbol'; 45 54 export type { 46 55 BindingKind,
+90
packages/codegen-core/src/structure/model.ts
··· 1 + import { StructureNode } from './node'; 2 + import type { StructureInsert } from './types'; 3 + 4 + export class StructureModel { 5 + /** Root nodes mapped by their names. */ 6 + private _roots: Map<string, StructureNode> = new Map(); 7 + /** Node for data without a specific root. */ 8 + private _virtualRoot?: StructureNode; 9 + 10 + /** 11 + * Get all root nodes. 12 + */ 13 + get roots(): ReadonlyArray<StructureNode> { 14 + const roots = Array.from(this._roots.values()); 15 + if (this._virtualRoot) roots.unshift(this._virtualRoot); 16 + return roots; 17 + } 18 + 19 + /** 20 + * Insert data into the structure. 21 + */ 22 + insert(args: StructureInsert): void { 23 + const { data, locations, source } = args; 24 + for (const location of locations) { 25 + const { path, shell } = location; 26 + const fullPath = path.filter((s): s is string => Boolean(s)); 27 + const segments = fullPath.slice(0, -1); 28 + const name = fullPath[fullPath.length - 1]; 29 + 30 + if (!name) { 31 + throw new Error('Cannot insert data without path.'); 32 + } 33 + 34 + let cursor: StructureNode | null = null; 35 + 36 + for (const segment of segments) { 37 + if (!cursor) { 38 + cursor = this.root(segment); 39 + } else { 40 + cursor = cursor.child(segment); 41 + } 42 + 43 + if (shell && !cursor.shell) { 44 + cursor.shell = shell; 45 + cursor.shellSource = source; 46 + } 47 + } 48 + 49 + if (!cursor) { 50 + cursor = this.root(null); 51 + } 52 + 53 + cursor.items.push({ data, location: fullPath, source }); 54 + } 55 + } 56 + 57 + /** 58 + * Gets or creates a root by name. 59 + * 60 + * If the root doesn't exist, it's created automatically. 61 + * 62 + * @param name - The name of the root 63 + * @returns The root instance 64 + */ 65 + root(name: string | null): StructureNode { 66 + if (!name) { 67 + return (this._virtualRoot ??= new StructureNode('', undefined, { 68 + virtual: true, 69 + })); 70 + } 71 + if (!this._roots.has(name)) { 72 + this._roots.set(name, new StructureNode(name)); 73 + } 74 + return this._roots.get(name)!; 75 + } 76 + 77 + /** 78 + * Walk all nodes in the structure (depth-first, post-order). 79 + * 80 + * @returns Generator of all structure nodes 81 + */ 82 + *walk(): Generator<StructureNode> { 83 + if (this._virtualRoot) { 84 + yield* this._virtualRoot.walk(); 85 + } 86 + for (const root of this._roots.values()) { 87 + yield* root.walk(); 88 + } 89 + } 90 + }
+93
packages/codegen-core/src/structure/node.ts
··· 1 + import type { StructureItem, StructureShell } from './types'; 2 + 3 + export class StructureNode { 4 + /** Nested nodes within this node. */ 5 + children: Map<string, StructureNode> = new Map(); 6 + /** Items contained in this node. */ 7 + items: Array<StructureItem> = []; 8 + /** The name of this node (e.g., "Users", "Accounts"). */ 9 + name: string; 10 + /** Parent node in the hierarchy. Undefined if this is the root node. */ 11 + parent?: StructureNode; 12 + /** Shell claimed for this node. */ 13 + shell?: StructureShell; 14 + /** Source of the claimed shell. */ 15 + shellSource?: symbol; 16 + /** True if this is a virtual root. */ 17 + virtual: boolean; 18 + 19 + constructor( 20 + name: string, 21 + parent?: StructureNode, 22 + options?: { 23 + virtual?: boolean; 24 + }, 25 + ) { 26 + this.name = name; 27 + this.parent = parent; 28 + this.virtual = options?.virtual ?? false; 29 + } 30 + 31 + get isRoot(): boolean { 32 + return !this.parent; 33 + } 34 + 35 + /** 36 + * Gets or creates a child node. 37 + * 38 + * If the child doesn't exist, it's created automatically. 39 + * 40 + * @param name - The name of the child node 41 + * @returns The child node instance 42 + */ 43 + child(name: string): StructureNode { 44 + if (!this.children.has(name)) { 45 + this.children.set(name, new StructureNode(name, this)); 46 + } 47 + return this.children.get(name)!; 48 + } 49 + 50 + /** 51 + * Gets the full path of this node in the hierarchy. 52 + * 53 + * @returns An array of node names from the root to this node 54 + */ 55 + getPath(): ReadonlyArray<string> { 56 + const path: Array<string> = []; 57 + // eslint-disable-next-line @typescript-eslint/no-this-alias 58 + let cursor: StructureNode | undefined = this; 59 + while (cursor) { 60 + path.unshift(cursor.name); 61 + cursor = cursor.parent; 62 + } 63 + return path; 64 + } 65 + 66 + /** 67 + * Yields items from a specific source with typed data. 68 + * 69 + * @param source - The source symbol to filter by 70 + * @returns Generator of items from that source 71 + */ 72 + *itemsFrom<T = unknown>( 73 + source: symbol, 74 + ): Generator<StructureItem & { data: T }> { 75 + for (const item of this.items) { 76 + if (item.source === source) { 77 + yield item as StructureItem & { data: T }; 78 + } 79 + } 80 + } 81 + 82 + /** 83 + * Walk all nodes in the structure (depth-first, post-order). 84 + * 85 + * @returns Generator of all structure nodes 86 + */ 87 + *walk(): Generator<StructureNode> { 88 + for (const node of this.children.values()) { 89 + yield* node.walk(); 90 + } 91 + yield this; 92 + } 93 + }
+33
packages/codegen-core/src/structure/types.d.ts
··· 1 + import type { INode } from '../nodes/node'; 2 + import type { StructureNode } from './node'; 3 + 4 + export interface StructureInsert { 5 + /** Inserted data. */ 6 + data: unknown; 7 + /** Locations where the data should be inserted. */ 8 + locations: ReadonlyArray<StructureLocation>; 9 + /** Source of the inserted data. */ 10 + source: symbol; 11 + } 12 + 13 + export interface StructureItem 14 + extends Pick<StructureInsert, 'data' | 'source'> { 15 + /** Location of this item within the structure. */ 16 + location: ReadonlyArray<string>; 17 + } 18 + 19 + export interface StructureLocation { 20 + /** Path within the structure where the data should be inserted. */ 21 + path: ReadonlyArray<string>; 22 + /** Shell to apply at this location. */ 23 + shell?: StructureShell; 24 + } 25 + 26 + export interface StructureShell { 27 + define: (node: StructureNode) => StructureShellResult; 28 + } 29 + 30 + export interface StructureShellResult { 31 + dependencies?: Array<INode>; 32 + node: INode; 33 + }
+2 -5
packages/openapi-ts/src/ir/context.ts
··· 3 3 import type { Package } from '~/config/utils/package'; 4 4 import { packageFactory } from '~/config/utils/package'; 5 5 import type { Graph } from '~/graph'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import type { PluginConfigMap } from '~/plugins/config'; 8 7 import { PluginInstance } from '~/plugins/shared/utils/instance'; 9 8 import type { PluginNames } from '~/plugins/types'; 10 9 import { TypeScriptRenderer } from '~/ts-dsl'; 11 10 import type { Config } from '~/types/config'; 12 11 import type { Logger } from '~/utils/logger'; 12 + import { applyNaming } from '~/utils/naming'; 13 13 import { resolveRef } from '~/utils/ref'; 14 14 15 15 import type { IR } from './types'; ··· 72 72 this.gen = new Project({ 73 73 defaultFileName: 'index', 74 74 fileName: (base) => { 75 - const name = buildName({ 76 - config: config.output.fileName, 77 - name: base, 78 - }); 75 + const name = applyNaming(base, config.output.fileName); 79 76 const { suffix } = config.output.fileName; 80 77 if (!suffix) { 81 78 return name;
+5
packages/openapi-ts/src/openApi/shared/locations/index.ts
··· 1 + export type { 2 + OperationLocationStrategy, 3 + OperationPathStrategy, 4 + } from './operation'; 5 + export { OperationLocations, OperationPath } from './operation';
+174
packages/openapi-ts/src/openApi/shared/locations/operation.ts
··· 1 + import type { StructureLocation, StructureShell } from '@hey-api/codegen-core'; 2 + 3 + import type { IR } from '~/ir/types'; 4 + 5 + /** 6 + * A function that determines where an operation appears in the structure. 7 + * 8 + * Returns one or more locations, each with a full path and optional shell. 9 + */ 10 + export type OperationLocationStrategy = ( 11 + operation: IR.OperationObject, 12 + ) => ReadonlyArray<StructureLocation>; 13 + 14 + /** 15 + * A function that derives path segments from an operation. 16 + * 17 + * Used by location strategies to build paths within containers. 18 + */ 19 + export type OperationPathStrategy = ( 20 + operation: IR.OperationObject, 21 + ) => ReadonlyArray<string>; 22 + 23 + /** 24 + * Built-in location strategies for operations. 25 + */ 26 + export const OperationLocations = { 27 + /** 28 + * Creates one root container per operation tag. 29 + * 30 + * Operations with multiple tags appear in multiple root containers. 31 + * Operations without tags use the fallback root container. 32 + * 33 + * @example 34 + * // Operation with tags: ['users', 'admin'] 35 + * // Path function returns: ['list'] 36 + * // Result: [{ path: ['users', 'list'], shell }, { path: ['admin', 'list'], shell }] 37 + */ 38 + byTags: 39 + (config: { 40 + /** 41 + * Root name for operations without tags. 42 + * 43 + * @default 'default' 44 + */ 45 + fallback?: string; 46 + /** 47 + * Derives path segments from the operation. 48 + * 49 + * @default OperationPath.fromOperationId() 50 + */ 51 + path?: OperationPathStrategy; 52 + /** 53 + * Shell to apply to all created nodes. 54 + */ 55 + shell: StructureShell; 56 + }): OperationLocationStrategy => 57 + (operation) => { 58 + const tags = 59 + operation.tags && operation.tags.length > 0 60 + ? operation.tags 61 + : [config.fallback ?? 'default']; 62 + const pathSegments = (config.path ?? OperationPath.fromOperationId())( 63 + operation, 64 + ); 65 + return tags.map((tag) => ({ 66 + path: [tag, ...pathSegments], 67 + shell: config.shell, 68 + })); 69 + }, 70 + 71 + /** 72 + * Creates flat functions without any container. 73 + * 74 + * Each operation becomes a standalone function at the root level. 75 + * No shell is applied. 76 + * 77 + * @example 78 + * // Operation id: 'getUsers' 79 + * // Result: [{ path: ['getUsers'] }] 80 + */ 81 + flat: 82 + (config?: { 83 + /** 84 + * Derives the function name from the operation. 85 + * 86 + * @default operation.id 87 + */ 88 + name?: (operation: IR.OperationObject) => string; 89 + }): OperationLocationStrategy => 90 + (operation) => [ 91 + { 92 + path: [(config?.name ?? ((operation) => operation.id))(operation)], 93 + }, 94 + ], 95 + 96 + /** 97 + * Places all operations under a single root container. 98 + * 99 + * @example 100 + * // Root: 'Sdk', path function returns: ['users', 'list'] 101 + * // Result: [{ path: ['Sdk', 'users', 'list'], shell }] 102 + */ 103 + single: 104 + (config: { 105 + /** 106 + * Derives path segments within the root from the operation. 107 + * 108 + * @default OperationPath.fromOperationId() 109 + */ 110 + path?: OperationPathStrategy; 111 + /** 112 + * Name of the container. 113 + */ 114 + root: string; 115 + /** 116 + * Shell to apply to all created nodes. 117 + */ 118 + shell: StructureShell; 119 + }): OperationLocationStrategy => 120 + (operation) => [ 121 + { 122 + path: [ 123 + config.root, 124 + ...(config.path ?? OperationPath.fromOperationId())(operation), 125 + ], 126 + shell: config.shell, 127 + }, 128 + ], 129 + }; 130 + 131 + /** 132 + * Built-in path derivation helpers for operations. 133 + */ 134 + export const OperationPath = { 135 + /** 136 + * Splits operationId by delimiters to create nested paths. 137 + * 138 + * The last segment is converted to camelCase. 139 + * Falls back to operation.id if operationId is missing. 140 + * 141 + * @example 142 + * // operationId: 'users.accounts.list' 143 + * // Result: ['users', 'accounts', 'list'] 144 + * 145 + * @example 146 + * // operationId: 'users/accounts/getAll' 147 + * // Result: ['users', 'accounts', 'getAll'] 148 + */ 149 + fromOperationId: 150 + (config?: { 151 + /** 152 + * Pattern to split operationId. 153 + * 154 + * @default /[./]/ 155 + */ 156 + delimiters: RegExp; 157 + }): OperationPathStrategy => 158 + (operation) => { 159 + if (!operation.operationId) return [operation.id]; 160 + const segments = operation.operationId 161 + .split(config?.delimiters ?? /[./]/) 162 + .filter(Boolean); 163 + return segments.length > 0 ? segments : [operation.id]; 164 + }, 165 + 166 + /** 167 + * Uses operation.id as a single path segment. 168 + * 169 + * @example 170 + * // operation.id: 'getUserById' 171 + * // Result: ['getUserById'] 172 + */ 173 + id: (): OperationPathStrategy => (operation) => [operation.id], 174 + };
+7 -8
packages/openapi-ts/src/openApi/shared/transforms/enums.ts
··· 1 + import { applyNaming } from '~/utils/naming'; 1 2 import { jsonPointerToPath } from '~/utils/ref'; 2 3 3 4 import type { Config } from '../../../types/config'; 4 - import { buildName } from '../utils/name'; 5 5 import { deepClone } from '../utils/schema'; 6 6 import { childSchemaRelationships } from '../utils/schemaChildRelationships'; 7 7 import { getSchemasObject } from '../utils/transforms'; ··· 215 215 } 216 216 217 217 // Generate a unique name for the new root enum using config 218 - const base = buildName({ 219 - config, 220 - name: 221 - typeof node === 'object' && 218 + const base = applyNaming( 219 + typeof node === 'object' && 222 220 node && 223 221 'title' in node && 224 222 typeof node.title === 'string' 225 - ? node.title 226 - : String(key), 227 - }); 223 + ? node.title 224 + : String(key), 225 + config, 226 + ); 228 227 const name = getUniqueComponentName({ 229 228 base, 230 229 components: schemasObj,
+3 -9
packages/openapi-ts/src/openApi/shared/transforms/readWrite.ts
··· 1 1 import type { Graph } from '~/graph'; 2 2 import type { Logger } from '~/utils/logger'; 3 + import { applyNaming } from '~/utils/naming'; 3 4 import { jsonPointerToPath } from '~/utils/ref'; 4 5 5 6 import type { Config } from '../../../types/config'; 6 7 import deepEqual from '../utils/deepEqual'; 7 8 import { buildGraph, type Scope } from '../utils/graph'; 8 - import { buildName } from '../utils/name'; 9 9 import { deepClone } from '../utils/schema'; 10 10 import { childSchemaRelationships } from '../utils/schemaChildRelationships'; 11 11 import { ··· 404 404 // read variant 405 405 const readSchema = deepClone<unknown>(nodeInfo.node); 406 406 pruneSchemaByScope(graph, readSchema, 'writeOnly'); 407 - const readBase = buildName({ 408 - config: config.responses, 409 - name, 410 - }); 407 + const readBase = applyNaming(name, config.responses); 411 408 const readName = 412 409 readBase === name 413 410 ? readBase ··· 448 445 ) { 449 446 continue; 450 447 } 451 - const writeBase = buildName({ 452 - config: config.requests, 453 - name, 454 - }); 448 + const writeBase = applyNaming(name, config.requests); 455 449 const writeName = 456 450 writeBase === name && writeBase !== readName 457 451 ? writeBase
-22
packages/openapi-ts/src/openApi/shared/utils/name.ts
··· 1 - import type { StringCase, StringName } from '~/types/case'; 2 - import { toCase } from '~/utils/to-case'; 3 - 4 - export const buildName = ({ 5 - config, 6 - name, 7 - }: { 8 - config: { 9 - case: StringCase; 10 - name?: StringName; 11 - }; 12 - name: string; 13 - }): string => { 14 - if (typeof config.name === 'function') { 15 - name = config.name(name); 16 - } else if (config.name) { 17 - const separator = config.case === 'preserve' ? '' : '-'; 18 - name = config.name.replace('{{name}}', `${separator}${name}${separator}`); 19 - } 20 - 21 - return toCase(name, config.case); 22 - };
+1 -1
packages/openapi-ts/src/openApi/shared/utils/operation.ts
··· 1 1 import type { Context } from '~/ir/context'; 2 2 import { createOperationKey } from '~/ir/operation'; 3 3 import { sanitizeNamespaceIdentifier } from '~/openApi/common/parser/sanitize'; 4 - import { toCase } from '~/utils/to-case'; 4 + import { toCase } from '~/utils/naming'; 5 5 6 6 import type { State } from '../types/state'; 7 7
+2 -2
packages/openapi-ts/src/plugins/@angular/common/config.ts
··· 26 26 if (!plugin.config.httpRequests.methodNameBuilder) { 27 27 const { asClass } = plugin.config.httpRequests; 28 28 plugin.config.httpRequests.methodNameBuilder = (operation) => 29 - asClass ? String(operation.id) : `${String(operation.id)}Request`; 29 + asClass ? `${operation.id}` : `${operation.id}Request`; 30 30 } 31 31 32 32 plugin.config.httpResources = context.valueToObject({ ··· 44 44 if (!plugin.config.httpResources.methodNameBuilder) { 45 45 const { asClass } = plugin.config.httpResources; 46 46 plugin.config.httpResources.methodNameBuilder = (operation) => 47 - asClass ? String(operation.id) : `${String(operation.id)}Resource`; 47 + asClass ? `${operation.id}` : `${operation.id}Resource`; 48 48 } 49 49 }, 50 50 };
+114 -158
packages/openapi-ts/src/plugins/@angular/common/httpRequests.ts
··· 1 - import type { Symbol } from '@hey-api/codegen-core'; 2 - 3 1 import type { IR } from '~/ir/types'; 4 - import { buildName } from '~/openApi/shared/utils/name'; 5 2 import { operationClasses } from '~/plugins/@hey-api/sdk/shared/operation'; 6 3 import { 7 4 createOperationComment, 8 5 isOperationOptionsRequired, 9 6 } from '~/plugins/shared/utils/operation'; 10 7 import { $ } from '~/ts-dsl'; 11 - import { toCase } from '~/utils/to-case'; 8 + import { applyNaming, toCase } from '~/utils/naming'; 12 9 13 10 import type { AngularCommonPlugin } from './types'; 14 11 ··· 20 17 root: boolean; 21 18 } 22 19 23 - const generateAngularClassRequests = ({ 20 + const generateClassRequests = ({ 24 21 plugin, 25 22 }: { 26 23 plugin: AngularCommonPlugin['Instance']; ··· 28 25 const requestClasses = new Map<string, AngularRequestClassEntry>(); 29 26 const generatedClasses = new Set<string>(); 30 27 28 + const symbolHttpRequest = plugin.referenceSymbol({ 29 + category: 'external', 30 + resource: '@angular/common/http.HttpRequest', 31 + }); 32 + const symbolOptions = plugin.referenceSymbol({ 33 + category: 'type', 34 + resource: 'client-options', 35 + tool: 'sdk', 36 + }); 37 + const symbolInjectable = plugin.referenceSymbol({ 38 + category: 'external', 39 + resource: '@angular/core.Injectable', 40 + }); 41 + 31 42 const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk'); 32 43 33 44 plugin.forEach( ··· 73 84 return; 74 85 } 75 86 76 - const methodNode = generateAngularRequestMethod({ 77 - isRequiredOptions, 78 - methodName: requestMethodName, 79 - operation, 80 - plugin, 87 + const symbolDataType = plugin.querySymbol({ 88 + category: 'type', 89 + resource: 'operation', 90 + resourceId: operation.id, 91 + role: 'data', 92 + tool: 'typescript', 81 93 }); 82 94 95 + const methodNode = $.method(requestMethodName) 96 + .public() 97 + .$if(createOperationComment(operation), (c, v) => c.doc(v)) 98 + .param('options', (p) => 99 + p.required(isRequiredOptions).type( 100 + $.type(symbolOptions) 101 + .generic(symbolDataType ?? 'unknown') 102 + .generic('ThrowOnError'), 103 + ), 104 + ) 105 + .generic('ThrowOnError', (g) => g.extends('boolean').default(false)) 106 + .returns($.type(symbolHttpRequest).generic('unknown')) 107 + .do( 108 + $.return( 109 + generateRequestCallExpression({ 110 + operation, 111 + plugin, 112 + }), 113 + ), 114 + ); 115 + 83 116 if (!currentClass.nodes.length) { 84 117 currentClass.nodes.push(methodNode); 85 118 } else { ··· 109 142 currentClass.nodes.push( 110 143 $.field(toCase(childClass.className, 'camelCase')).assign( 111 144 $.new( 112 - buildName({ 113 - config: { 114 - case: 'preserve', 115 - name: plugin.config.httpRequests.classNameBuilder, 116 - }, 117 - name: childClass.className, 145 + applyNaming(childClass.className, { 146 + case: 'preserve', 147 + name: plugin.config.httpRequests.classNameBuilder, 118 148 }), 119 149 ), 120 150 ), ··· 122 152 } 123 153 } 124 154 125 - const symbolInjectable = plugin.referenceSymbol({ 126 - category: 'external', 127 - resource: '@angular/core.Injectable', 128 - }); 129 - const symbolClass = plugin.registerSymbol({ 130 - meta: { 131 - category: 'utility', 132 - resource: 'class', 133 - resourceId: currentClass.className, 134 - tool: 'angular', 135 - }, 136 - name: buildName({ 137 - config: { 138 - case: 'preserve', 139 - name: plugin.config.httpRequests.classNameBuilder, 140 - }, 141 - name: currentClass.className, 155 + const symbolClass = plugin.symbol( 156 + applyNaming(currentClass.className, { 157 + case: 'preserve', 158 + name: plugin.config.httpRequests.classNameBuilder, 142 159 }), 143 - }); 160 + { 161 + meta: { 162 + category: 'utility', 163 + resource: 'class', 164 + resourceId: currentClass.className, 165 + tool: 'angular', 166 + }, 167 + }, 168 + ); 144 169 const node = $.class(symbolClass) 145 170 .export() 146 171 .$if(currentClass.root, (c) => ··· 160 185 } 161 186 }; 162 187 163 - const generateAngularFunctionRequests = ({ 188 + const generateFunctionRequests = ({ 164 189 plugin, 165 190 }: { 166 191 plugin: AngularCommonPlugin['Instance']; 167 192 }) => { 193 + const symbolHttpRequest = plugin.referenceSymbol({ 194 + category: 'external', 195 + resource: '@angular/common/http.HttpRequest', 196 + }); 197 + const symbolOptions = plugin.referenceSymbol({ 198 + category: 'type', 199 + resource: 'client-options', 200 + tool: 'sdk', 201 + }); 202 + 168 203 plugin.forEach( 169 204 'operation', 170 205 ({ operation }) => { ··· 173 208 operation, 174 209 }); 175 210 176 - const symbol = plugin.registerSymbol({ 177 - meta: { 178 - category: 'utility', 179 - resource: 'operation', 180 - resourceId: operation.id, 181 - role: 'data', 182 - tool: 'angular', 211 + const symbol = plugin.symbol( 212 + plugin.config.httpRequests.methodNameBuilder(operation), 213 + { 214 + meta: { 215 + category: 'utility', 216 + resource: 'operation', 217 + resourceId: operation.id, 218 + role: 'data', 219 + tool: 'angular', 220 + }, 183 221 }, 184 - name: plugin.config.httpRequests.methodNameBuilder(operation), 185 - }); 186 - const node = generateAngularRequestFunction({ 187 - isRequiredOptions, 188 - operation, 189 - plugin, 190 - symbol, 222 + ); 223 + 224 + const symbolDataType = plugin.querySymbol({ 225 + category: 'type', 226 + resource: 'operation', 227 + resourceId: operation.id, 228 + role: 'data', 229 + tool: 'typescript', 191 230 }); 231 + 232 + const node = $.const(symbol) 233 + .export() 234 + .$if(createOperationComment(operation), (c, v) => c.doc(v)) 235 + .assign( 236 + $.func() 237 + .param('options', (p) => 238 + p.required(isRequiredOptions).type( 239 + $.type(symbolOptions) 240 + .generic(symbolDataType ?? 'unknown') 241 + .generic('ThrowOnError'), 242 + ), 243 + ) 244 + .generic('ThrowOnError', (g) => g.extends('boolean').default(false)) 245 + .returns($.type(symbolHttpRequest).generic('unknown')) 246 + .do( 247 + $.return( 248 + generateRequestCallExpression({ 249 + operation, 250 + plugin, 251 + }), 252 + ), 253 + ), 254 + ); 192 255 plugin.node(node); 193 256 }, 194 257 { ··· 224 287 ); 225 288 }; 226 289 227 - const generateAngularRequestMethod = ({ 228 - isRequiredOptions, 229 - methodName, 230 - operation, 231 - plugin, 232 - }: { 233 - isRequiredOptions: boolean; 234 - methodName: string; 235 - operation: IR.OperationObject; 236 - plugin: AngularCommonPlugin['Instance']; 237 - }) => { 238 - const symbolHttpRequest = plugin.referenceSymbol({ 239 - category: 'external', 240 - resource: '@angular/common/http.HttpRequest', 241 - }); 242 - 243 - const symbolOptions = plugin.referenceSymbol({ 244 - category: 'type', 245 - resource: 'client-options', 246 - tool: 'sdk', 247 - }); 248 - 249 - const symbolDataType = plugin.querySymbol({ 250 - category: 'type', 251 - resource: 'operation', 252 - resourceId: operation.id, 253 - role: 'data', 254 - tool: 'typescript', 255 - }); 256 - 257 - return $.method(methodName) 258 - .public() 259 - .$if(createOperationComment(operation), (c, v) => c.doc(v)) 260 - .param('options', (p) => 261 - p.required(isRequiredOptions).type( 262 - $.type(symbolOptions) 263 - .generic(symbolDataType ?? 'unknown') 264 - .generic('ThrowOnError'), 265 - ), 266 - ) 267 - .generic('ThrowOnError', (g) => g.extends('boolean').default(false)) 268 - .returns($.type(symbolHttpRequest).generic('unknown')) 269 - .do( 270 - $.return( 271 - generateRequestCallExpression({ 272 - operation, 273 - plugin, 274 - }), 275 - ), 276 - ); 277 - }; 278 - 279 - const generateAngularRequestFunction = ({ 280 - isRequiredOptions, 281 - operation, 282 - plugin, 283 - symbol, 284 - }: { 285 - isRequiredOptions: boolean; 286 - operation: IR.OperationObject; 287 - plugin: AngularCommonPlugin['Instance']; 288 - symbol: Symbol; 289 - }) => { 290 - const symbolHttpRequest = plugin.referenceSymbol({ 291 - category: 'external', 292 - resource: '@angular/common/http.HttpRequest', 293 - }); 294 - 295 - const symbolOptions = plugin.referenceSymbol({ 296 - category: 'type', 297 - resource: 'client-options', 298 - tool: 'sdk', 299 - }); 300 - 301 - const symbolDataType = plugin.querySymbol({ 302 - category: 'type', 303 - resource: 'operation', 304 - resourceId: operation.id, 305 - role: 'data', 306 - tool: 'typescript', 307 - }); 308 - 309 - return $.const(symbol) 310 - .export() 311 - .$if(createOperationComment(operation), (c, v) => c.doc(v)) 312 - .assign( 313 - $.func() 314 - .param('options', (p) => 315 - p.required(isRequiredOptions).type( 316 - $.type(symbolOptions) 317 - .generic(symbolDataType ?? 'unknown') 318 - .generic('ThrowOnError'), 319 - ), 320 - ) 321 - .generic('ThrowOnError', (g) => g.extends('boolean').default(false)) 322 - .returns($.type(symbolHttpRequest).generic('unknown')) 323 - .do( 324 - $.return( 325 - generateRequestCallExpression({ 326 - operation, 327 - plugin, 328 - }), 329 - ), 330 - ), 331 - ); 332 - }; 333 - 334 290 export const createHttpRequests: AngularCommonPlugin['Handler'] = ({ 335 291 plugin, 336 292 }) => { 337 293 if (plugin.config.httpRequests.asClass) { 338 - generateAngularClassRequests({ plugin }); 294 + generateClassRequests({ plugin }); 339 295 } else { 340 - generateAngularFunctionRequests({ plugin }); 296 + generateFunctionRequests({ plugin }); 341 297 } 342 298 };
+102 -148
packages/openapi-ts/src/plugins/@angular/common/httpResources.ts
··· 1 - import type { Symbol } from '@hey-api/codegen-core'; 2 - 3 1 import type { IR } from '~/ir/types'; 4 - import { buildName } from '~/openApi/shared/utils/name'; 5 2 import { operationClasses } from '~/plugins/@hey-api/sdk/shared/operation'; 6 3 import { 7 4 createOperationComment, 8 5 isOperationOptionsRequired, 9 6 } from '~/plugins/shared/utils/operation'; 10 7 import { $ } from '~/ts-dsl'; 11 - import { toCase } from '~/utils/to-case'; 8 + import { applyNaming, toCase } from '~/utils/naming'; 12 9 13 10 import type { AngularCommonPlugin } from './types'; 14 11 ··· 20 17 root: boolean; 21 18 } 22 19 23 - const generateAngularClassServices = ({ 20 + const generateClassServices = ({ 24 21 plugin, 25 22 }: { 26 23 plugin: AngularCommonPlugin['Instance']; ··· 28 25 const serviceClasses = new Map<string, AngularServiceClassEntry>(); 29 26 const generatedClasses = new Set<string>(); 30 27 28 + const symbolInjectable = plugin.referenceSymbol({ 29 + category: 'external', 30 + resource: '@angular/core.Injectable', 31 + }); 32 + const symbolOptions = plugin.referenceSymbol({ 33 + category: 'type', 34 + resource: 'client-options', 35 + tool: 'sdk', 36 + }); 37 + 31 38 const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk'); 32 39 33 40 plugin.forEach( ··· 73 80 return; 74 81 } 75 82 76 - const methodNode = generateAngularResourceMethod({ 77 - isRequiredOptions, 78 - methodName: resourceMethodName, 79 - operation, 80 - plugin, 83 + const symbolDataType = plugin.querySymbol({ 84 + category: 'type', 85 + resource: 'operation', 86 + resourceId: operation.id, 87 + role: 'data', 88 + tool: 'typescript', 81 89 }); 82 90 91 + const methodNode = $.method(resourceMethodName) 92 + .public() 93 + .$if(createOperationComment(operation), (c, v) => c.doc(v)) 94 + .param('options', (p) => 95 + p.required(isRequiredOptions).type( 96 + $.type.func().returns( 97 + $.type.or( 98 + $.type(symbolOptions) 99 + .generic(symbolDataType ?? 'unknown') 100 + .generic('ThrowOnError'), 101 + $.type('undefined'), 102 + ), 103 + ), 104 + ), 105 + ) 106 + .generic('ThrowOnError', (g) => g.extends('boolean').default(false)) 107 + .do( 108 + $.return( 109 + generateResourceCallExpression({ 110 + operation, 111 + plugin, 112 + }), 113 + ), 114 + ); 115 + 83 116 if (!currentClass.nodes.length) { 84 117 currentClass.nodes.push(methodNode); 85 118 } else { ··· 109 142 currentClass.nodes.push( 110 143 $.field(toCase(childClass.className, 'camelCase')).assign( 111 144 $.new( 112 - buildName({ 113 - config: { 114 - case: 'preserve', 115 - name: plugin.config.httpResources.classNameBuilder, 116 - }, 117 - name: childClass.className, 145 + applyNaming(childClass.className, { 146 + case: 'preserve', 147 + name: plugin.config.httpResources.classNameBuilder, 118 148 }), 119 149 ), 120 150 ), ··· 122 152 } 123 153 } 124 154 125 - const symbolInjectable = plugin.referenceSymbol({ 126 - category: 'external', 127 - resource: '@angular/core.Injectable', 128 - }); 129 - const symbolClass = plugin.registerSymbol({ 130 - name: buildName({ 131 - config: { 132 - case: 'preserve', 133 - name: plugin.config.httpResources.classNameBuilder, 134 - }, 135 - name: currentClass.className, 155 + const symbolClass = plugin.symbol( 156 + applyNaming(currentClass.className, { 157 + case: 'preserve', 158 + name: plugin.config.httpResources.classNameBuilder, 136 159 }), 137 - }); 160 + ); 138 161 const node = $.class(symbolClass) 139 162 .export() 140 163 .$if(currentClass.root, (c) => ··· 154 177 } 155 178 }; 156 179 157 - const generateAngularFunctionServices = ({ 180 + const generateFunctionServices = ({ 158 181 plugin, 159 182 }: { 160 183 plugin: AngularCommonPlugin['Instance']; 161 184 }) => { 185 + const symbolOptions = plugin.referenceSymbol({ 186 + category: 'type', 187 + resource: 'client-options', 188 + tool: 'sdk', 189 + }); 190 + 162 191 plugin.forEach( 163 192 'operation', 164 193 ({ operation }) => { ··· 167 196 operation, 168 197 }); 169 198 170 - const symbol = plugin.registerSymbol({ 171 - name: plugin.config.httpResources.methodNameBuilder(operation), 172 - }); 173 - const node = generateAngularResourceFunction({ 174 - isRequiredOptions, 175 - operation, 176 - plugin, 177 - symbol, 199 + const symbol = plugin.symbol( 200 + plugin.config.httpResources.methodNameBuilder(operation), 201 + ); 202 + 203 + const symbolDataType = plugin.querySymbol({ 204 + category: 'type', 205 + resource: 'operation', 206 + resourceId: operation.id, 207 + role: 'data', 208 + tool: 'typescript', 178 209 }); 210 + 211 + const node = $.const(symbol) 212 + .export() 213 + .$if(createOperationComment(operation), (c, v) => c.doc(v)) 214 + .assign( 215 + $.func() 216 + .param('options', (p) => 217 + p.required(isRequiredOptions).type( 218 + $.type.func().returns( 219 + $.type.or( 220 + $.type(symbolOptions) 221 + .generic(symbolDataType ?? 'unknown') 222 + .generic('ThrowOnError'), 223 + $.type('undefined'), 224 + ), 225 + ), 226 + ), 227 + ) 228 + .generic('ThrowOnError', (g) => g.extends('boolean').default(false)) 229 + .do( 230 + $.return( 231 + generateResourceCallExpression({ 232 + operation, 233 + plugin, 234 + }), 235 + ), 236 + ), 237 + ); 179 238 plugin.node(node); 180 239 }, 181 240 { ··· 197 256 category: 'external', 198 257 resource: '@angular/common/http.httpResource', 199 258 }); 259 + const symbolInject = plugin.referenceSymbol({ 260 + category: 'external', 261 + resource: '@angular/core.inject', 262 + }); 200 263 201 264 const symbolResponseType = plugin.querySymbol({ 202 265 category: 'type', ··· 221 284 }); 222 285 223 286 // Build the method access path using inject 224 - const symbolInject = plugin.referenceSymbol({ 225 - category: 'external', 226 - resource: '@angular/core.inject', 227 - }); 228 287 let methodAccess: ReturnType<typeof $.attr | typeof $.call> = 229 288 $(symbolInject).call(symbolClass); 230 289 ··· 292 351 ); 293 352 }; 294 353 295 - const generateAngularResourceMethod = ({ 296 - isRequiredOptions, 297 - methodName, 298 - operation, 299 - plugin, 300 - }: { 301 - isRequiredOptions: boolean; 302 - methodName: string; 303 - operation: IR.OperationObject; 304 - plugin: AngularCommonPlugin['Instance']; 305 - }) => { 306 - const symbolOptions = plugin.referenceSymbol({ 307 - category: 'type', 308 - resource: 'client-options', 309 - tool: 'sdk', 310 - }); 311 - 312 - const symbolDataType = plugin.querySymbol({ 313 - category: 'type', 314 - resource: 'operation', 315 - resourceId: operation.id, 316 - role: 'data', 317 - tool: 'typescript', 318 - }); 319 - 320 - return $.method(methodName) 321 - .public() 322 - .$if(createOperationComment(operation), (c, v) => c.doc(v)) 323 - .param('options', (p) => 324 - p.required(isRequiredOptions).type( 325 - $.type.func().returns( 326 - $.type.or( 327 - $.type(symbolOptions) 328 - .generic(symbolDataType ?? 'unknown') 329 - .generic('ThrowOnError'), 330 - $.type('undefined'), 331 - ), 332 - ), 333 - ), 334 - ) 335 - .generic('ThrowOnError', (g) => g.extends('boolean').default(false)) 336 - .do( 337 - $.return( 338 - generateResourceCallExpression({ 339 - operation, 340 - plugin, 341 - }), 342 - ), 343 - ); 344 - }; 345 - 346 - const generateAngularResourceFunction = ({ 347 - isRequiredOptions, 348 - operation, 349 - plugin, 350 - symbol, 351 - }: { 352 - isRequiredOptions: boolean; 353 - operation: IR.OperationObject; 354 - plugin: AngularCommonPlugin['Instance']; 355 - symbol: Symbol; 356 - }) => { 357 - const symbolOptions = plugin.referenceSymbol({ 358 - category: 'type', 359 - resource: 'client-options', 360 - tool: 'sdk', 361 - }); 362 - 363 - const symbolDataType = plugin.querySymbol({ 364 - category: 'type', 365 - resource: 'operation', 366 - resourceId: operation.id, 367 - role: 'data', 368 - tool: 'typescript', 369 - }); 370 - 371 - return $.const(symbol) 372 - .export() 373 - .$if(createOperationComment(operation), (c, v) => c.doc(v)) 374 - .assign( 375 - $.func() 376 - .param('options', (p) => 377 - p.required(isRequiredOptions).type( 378 - $.type.func().returns( 379 - $.type.or( 380 - $.type(symbolOptions) 381 - .generic(symbolDataType ?? 'unknown') 382 - .generic('ThrowOnError'), 383 - $.type('undefined'), 384 - ), 385 - ), 386 - ), 387 - ) 388 - .generic('ThrowOnError', (g) => g.extends('boolean').default(false)) 389 - .do( 390 - $.return( 391 - generateResourceCallExpression({ 392 - operation, 393 - plugin, 394 - }), 395 - ), 396 - ), 397 - ); 398 - }; 399 - 400 354 export const createHttpResources: AngularCommonPlugin['Handler'] = ({ 401 355 plugin, 402 356 }) => { 403 357 if (plugin.config.httpResources.asClass) { 404 - generateAngularClassServices({ plugin }); 358 + generateClassServices({ plugin }); 405 359 } else { 406 - generateAngularFunctionServices({ plugin }); 360 + generateFunctionServices({ plugin }); 407 361 } 408 362 };
+4 -8
packages/openapi-ts/src/plugins/@angular/common/plugin.ts
··· 3 3 import type { AngularCommonPlugin } from './types'; 4 4 5 5 export const handler: AngularCommonPlugin['Handler'] = ({ plugin }) => { 6 - plugin.registerSymbol({ 6 + plugin.symbol('HttpRequest', { 7 7 external: '@angular/common/http', 8 8 kind: 'type', 9 9 meta: { 10 10 category: 'external', 11 11 resource: '@angular/common/http.HttpRequest', 12 12 }, 13 - name: 'HttpRequest', 14 13 }); 15 - plugin.registerSymbol({ 14 + plugin.symbol('inject', { 16 15 external: '@angular/core', 17 16 meta: { 18 17 category: 'external', 19 18 resource: '@angular/core.inject', 20 19 }, 21 - name: 'inject', 22 20 }); 23 - plugin.registerSymbol({ 21 + plugin.symbol('Injectable', { 24 22 external: '@angular/core', 25 23 meta: { 26 24 category: 'external', 27 25 resource: '@angular/core.Injectable', 28 26 }, 29 - name: 'Injectable', 30 27 }); 31 - plugin.registerSymbol({ 28 + plugin.symbol('httpResource', { 32 29 external: '@angular/common/http', 33 30 meta: { 34 31 category: 'external', 35 32 resource: '@angular/common/http.httpResource', 36 33 }, 37 - name: 'httpResource', 38 34 }); 39 35 40 36 if (plugin.config.httpRequests.enabled) {
+5 -5
packages/openapi-ts/src/plugins/@angular/common/types.d.ts
··· 1 1 import type { DefinePlugin, Plugin } from '~/plugins'; 2 - import type { StringName } from '~/types/case'; 2 + import type { NameTransformer } from '~/utils/naming'; 3 3 4 4 export type UserConfig = Plugin.Name<'@angular/common'> & 5 5 Plugin.Hooks & { ··· 28 28 * Builds the class name for the generated resource. 29 29 * By default, the class name is suffixed with "Resources". 30 30 */ 31 - classNameBuilder?: StringName; 31 + classNameBuilder?: NameTransformer; 32 32 /** 33 33 * Whether or not to create HTTP Request instances. 34 34 * ··· 59 59 * Builds the class name for the generated resource. 60 60 * By default, the class name is suffixed with "Resources". 61 61 */ 62 - classNameBuilder?: StringName; 62 + classNameBuilder?: NameTransformer; 63 63 /** 64 64 * Whether or not to create HTTP resource APIs. 65 65 * ··· 98 98 * Builds the class name for the generated resource. 99 99 * By default, the class name is suffixed with "Resources". 100 100 */ 101 - classNameBuilder: StringName; 101 + classNameBuilder: NameTransformer; 102 102 /** 103 103 * Whether or not to create HTTP Request instances. 104 104 * ··· 125 125 * Builds the class name for the generated resource. 126 126 * By default, the class name is suffixed with "Resources". 127 127 */ 128 - classNameBuilder: StringName; 128 + classNameBuilder: NameTransformer; 129 129 /** 130 130 * Whether or not to create HTTP resource APIs. 131 131 *
+4 -8
packages/openapi-ts/src/plugins/@hey-api/client-core/client.ts
··· 29 29 30 30 export const createClient: PluginHandler = ({ plugin }) => { 31 31 const clientModule = clientFolderAbsolutePath(plugin.context.config); 32 - const symbolCreateClient = plugin.registerSymbol({ 32 + const symbolCreateClient = plugin.symbol('createClient', { 33 33 external: clientModule, 34 - name: 'createClient', 35 34 }); 36 - const symbolCreateConfig = plugin.registerSymbol({ 35 + const symbolCreateConfig = plugin.symbol('createConfig', { 37 36 external: clientModule, 38 - name: 'createConfig', 39 37 }); 40 38 const symbolClientOptions = plugin.referenceSymbol({ 41 39 category: 'type', ··· 45 43 46 44 const { runtimeConfigPath } = plugin.config; 47 45 const symbolCreateClientConfig = runtimeConfigPath 48 - ? plugin.registerSymbol({ 46 + ? plugin.symbol('createClientConfig', { 49 47 external: runtimeConfigPath, 50 - name: 'createClientConfig', 51 48 }) 52 49 : undefined; 53 50 ··· 84 81 .generic(symbolClientOptions), 85 82 ]; 86 83 87 - const symbolClient = plugin.registerSymbol({ 84 + const symbolClient = plugin.symbol('client', { 88 85 meta: { 89 86 category: 'client', 90 87 }, 91 - name: 'client', 92 88 }); 93 89 const statement = $.const(symbolClient) 94 90 .export()
+3 -7
packages/openapi-ts/src/plugins/@hey-api/client-core/createClientConfig.ts
··· 12 12 resource: 'client', 13 13 role: 'options', 14 14 }); 15 - const symbolConfig = plugin.registerSymbol({ 15 + const symbolConfig = plugin.symbol('Config', { 16 16 external: clientModule, 17 17 kind: 'type', 18 - name: 'Config', 19 18 }); 20 - const symbolDefaultClientOptions = plugin.registerSymbol({ 19 + const symbolDefaultClientOptions = plugin.symbol('ClientOptions', { 21 20 external: clientModule, 22 21 kind: 'type', 23 - name: 'ClientOptions', 24 22 }); 25 - const symbolCreateClientConfig = plugin.registerSymbol({ 26 - name: 'CreateClientConfig', 27 - }); 23 + const symbolCreateClientConfig = plugin.symbol('CreateClientConfig'); 28 24 29 25 const typeCreateClientConfig = $.type 30 26 .alias(symbolCreateClientConfig)
+3 -6
packages/openapi-ts/src/plugins/@hey-api/schemas/plugin.ts
··· 367 367 368 368 for (const name in context.spec.definitions) { 369 369 const schema = context.spec.definitions[name]!; 370 - const symbol = plugin.registerSymbol({ 370 + const symbol = plugin.symbol(schemaName({ name, plugin, schema }), { 371 371 meta: { 372 372 category: 'schema', 373 373 resource: 'definition', 374 374 resourceId: name, 375 375 tool: 'json-schema', 376 376 }, 377 - name: schemaName({ name, plugin, schema }), 378 377 }); 379 378 const obj = schemaToJsonSchemaDraft_04({ 380 379 context, ··· 407 406 408 407 for (const name in context.spec.components.schemas) { 409 408 const schema = context.spec.components.schemas[name]!; 410 - const symbol = plugin.registerSymbol({ 409 + const symbol = plugin.symbol(schemaName({ name, plugin, schema }), { 411 410 meta: { 412 411 category: 'schema', 413 412 resource: 'definition', 414 413 resourceId: name, 415 414 tool: 'json-schema', 416 415 }, 417 - name: schemaName({ name, plugin, schema }), 418 416 }); 419 417 const obj = schemaToJsonSchemaDraft_05({ 420 418 context, ··· 447 445 448 446 for (const name in context.spec.components.schemas) { 449 447 const schema = context.spec.components.schemas[name]!; 450 - const symbol = plugin.registerSymbol({ 448 + const symbol = plugin.symbol(schemaName({ name, plugin, schema }), { 451 449 meta: { 452 450 category: 'schema', 453 451 resource: 'definition', 454 452 resourceId: name, 455 453 tool: 'json-schema', 456 454 }, 457 - name: schemaName({ name, plugin, schema }), 458 455 }); 459 456 const obj = schemaToJsonSchema2020_12({ 460 457 context,
+12 -23
packages/openapi-ts/src/plugins/@hey-api/sdk/config.ts
··· 1 1 import { definePluginConfig } from '~/plugins/shared/utils/config'; 2 2 3 3 import { handler } from './plugin'; 4 + import { resolveStructure } from './structure'; 4 5 import type { HeyApiSdkPlugin } from './types'; 5 6 6 7 export const defaultConfig: HeyApiSdkPlugin['Config'] = { 7 8 config: { 8 - asClass: false, 9 9 auth: true, 10 - classNameBuilder: '{{name}}', 11 - classStructure: 'auto', 12 10 client: true, 13 11 exportFromIndex: true, 14 - instance: '', 15 - methodNameBuilder: '{{name}}', 16 - operationId: true, 17 12 paramsStructure: 'grouped', 18 - response: 'body', 19 13 responseStyle: 'fields', 20 14 transformer: false, 21 15 validator: false, 16 + 17 + // Deprecated - kept for backward compatibility 18 + // eslint-disable-next-line sort-keys-fix/sort-keys-fix 19 + asClass: false, 20 + classNameBuilder: '{{name}}', 21 + classStructure: 'auto', 22 + instance: '', 23 + methodNameBuilder: '{{name}}', 24 + operationId: true, 25 + response: 'body', 22 26 }, 23 27 dependencies: ['@hey-api/typescript'], 24 28 handler, ··· 73 77 plugin.config.validator.response = false; 74 78 } 75 79 76 - if (plugin.config.instance) { 77 - if (typeof plugin.config.instance !== 'string') { 78 - plugin.config.instance = 'Sdk'; 79 - } 80 - 81 - plugin.config.asClass = true; 82 - } else { 83 - plugin.config.instance = ''; 84 - } 85 - 86 - // Set default classNameBuilder based on client type 87 - if (plugin.config.classNameBuilder === '{{name}}') { 88 - if (plugin.config.client === '@hey-api/client-angular') { 89 - plugin.config.classNameBuilder = '{{name}}Service'; 90 - } 91 - } 80 + plugin.config.structure = resolveStructure(plugin.config, context); 92 81 }, 93 82 }; 94 83
-452
packages/openapi-ts/src/plugins/@hey-api/sdk/model/resource.ts
··· 1 - import type { Symbol } from '@hey-api/codegen-core'; 2 - 3 - import type { IR } from '~/ir/types'; 4 - import { getClientPlugin } from '~/plugins/@hey-api/client-core/utils'; 5 - import { 6 - createOperationComment, 7 - isOperationOptionsRequired, 8 - } from '~/plugins/shared/utils/operation'; 9 - import { $ } from '~/ts-dsl'; 10 - import { toCase } from '~/utils/to-case'; 11 - 12 - import { createClientClass, createRegistryClass } from '../shared/class'; 13 - import { nuxtTypeComposable, nuxtTypeDefault } from '../shared/constants'; 14 - import { 15 - operationClassName, 16 - operationMethodName, 17 - operationParameters, 18 - operationStatements, 19 - } from '../shared/operation'; 20 - import type { HeyApiSdkPlugin } from '../types'; 21 - 22 - export type Event = { 23 - operation: IR.OperationObject; 24 - path: ReadonlyArray<string | number>; 25 - tags: ReadonlyArray<string> | undefined; 26 - }; 27 - 28 - /** 29 - * Represents a resource layer in the SDK hierarchy. 30 - * 31 - * Resources can be nested (via children) and contain operations (methods). 32 - */ 33 - export class SdkResourceModel { 34 - /** Nested resources within this resource. */ 35 - children: Map<string, SdkResourceModel> = new Map(); 36 - /** The name of this resource (e.g., "Users", "Accounts"). */ 37 - name: string; 38 - /** Operations that will become methods in this resource. */ 39 - operations: Array<Event> = []; 40 - /** Parent resource in the hierarchy. Undefined if this is the root resource. */ 41 - parent?: SdkResourceModel; 42 - 43 - constructor(name: string, parent?: SdkResourceModel) { 44 - this.name = name; 45 - this.parent = parent; 46 - } 47 - 48 - get isRoot(): boolean { 49 - return !this.parent; 50 - } 51 - 52 - /** 53 - * Gets or creates a child resource. 54 - * 55 - * If the child doesn't exist, it's created automatically. 56 - * 57 - * @param name - The name of the child resource 58 - * @returns The child resource instance 59 - */ 60 - child(name: string): SdkResourceModel { 61 - if (!this.children.has(name)) { 62 - this.children.set(name, new SdkResourceModel(name, this)); 63 - } 64 - return this.children.get(name)!; 65 - } 66 - 67 - /** 68 - * Gets the full path of this resource in the hierarchy. 69 - * 70 - * @returns An array of resource names from the root to this resource 71 - */ 72 - getPath(): ReadonlyArray<string> { 73 - const path: Array<string> = []; 74 - // eslint-disable-next-line @typescript-eslint/no-this-alias 75 - let cursor: SdkResourceModel | undefined = this; 76 - while (cursor) { 77 - path.unshift(cursor.name); 78 - cursor = cursor.parent; 79 - } 80 - return path; 81 - } 82 - 83 - /** 84 - * Inserts an operation event into the resource tree. 85 - * 86 - * Parses the operation ID and creates the resource hierarchy. 87 - */ 88 - insert(event: Event, plugin: HeyApiSdkPlugin['Instance']): void { 89 - const { operation } = event; 90 - const classSegments = 91 - this.name && 92 - plugin.config.classStructure === 'auto' && 93 - operation.operationId 94 - ? this.splitOperationId(operation.operationId).slice(0, -1) 95 - : []; 96 - 97 - // eslint-disable-next-line @typescript-eslint/no-this-alias 98 - let cursor: SdkResourceModel = this; 99 - for (const segment of classSegments) { 100 - cursor = cursor.child(segment); 101 - } 102 - 103 - cursor.operations.push(event); 104 - } 105 - 106 - /** 107 - * Converts this class group to a class node. 108 - */ 109 - toNode(plugin: HeyApiSdkPlugin['Instance']): { 110 - dependencies: Array<ReturnType<typeof $.class>>; 111 - nodes: ReadonlyArray<ReturnType<typeof $.class | typeof $.var>>; 112 - } { 113 - const dependencies: Array<ReturnType<typeof $.class>> = []; 114 - const nodes: Array<ReturnType<typeof $.class | typeof $.var>> = []; 115 - 116 - const client = getClientPlugin(plugin.context.config); 117 - const isAngularClient = client.name === '@hey-api/client-angular'; 118 - 119 - if (this.name) { 120 - const { node, symbol: symbolClass } = this.classToNode(plugin); 121 - 122 - if (this.isRoot && plugin.config.instance) { 123 - this.enrichRootClass({ 124 - dependencies, 125 - node, 126 - plugin, 127 - symbol: symbolClass, 128 - }); 129 - } 130 - 131 - this.operations.forEach((event, index) => { 132 - const { operation } = event; 133 - if (index > 0 || node.hasBody) node.newline(); 134 - node.do( 135 - this.implementFn({ 136 - node: $.method(this.createFnSymbol(plugin, event), (m) => 137 - this.attachComment({ 138 - node: m, 139 - operation, 140 - }) 141 - .public() 142 - .static(!isAngularClient && !plugin.config.instance), 143 - ), 144 - operation, 145 - plugin, 146 - }), 147 - ); 148 - }); 149 - 150 - for (const child of this.children.values()) { 151 - if (node.hasBody) node.newline(); 152 - node.do(...this.childToNode(child, plugin)); 153 - } 154 - 155 - nodes.push(node); 156 - } else { 157 - this.operations.forEach((event) => { 158 - const { operation } = event; 159 - let node = $.const(this.createFnSymbol(plugin, event)) 160 - .export() 161 - .assign( 162 - this.implementFn({ 163 - node: $.func(), 164 - operation, 165 - plugin, 166 - }), 167 - ); 168 - node = this.attachComment({ node, operation }); 169 - nodes.push(node); 170 - }); 171 - } 172 - 173 - return { dependencies, nodes }; 174 - } 175 - 176 - /** 177 - * Recursively walks the tree depth-first. 178 - * 179 - * Yields this node, then all descendants. 180 - */ 181 - *walk(): Generator<SdkResourceModel> { 182 - for (const child of this.children.values()) { 183 - yield* child.walk(); 184 - } 185 - yield this; 186 - } 187 - 188 - private attachComment< 189 - T extends ReturnType<typeof $.var | typeof $.method>, 190 - >(args: { node: T; operation: IR.OperationObject }): T { 191 - const { node, operation } = args; 192 - return node.$if(createOperationComment(operation), (m, v) => m.doc(v)) as T; 193 - } 194 - 195 - private createFnSymbol( 196 - plugin: HeyApiSdkPlugin['Instance'], 197 - event: Event, 198 - ): Symbol { 199 - const { operation, path, tags } = event; 200 - const extractFromOperationId = 201 - this.name && plugin.config.classStructure === 'auto'; 202 - return plugin.symbol( 203 - operationMethodName({ 204 - operation, 205 - plugin, 206 - value: 207 - extractFromOperationId && operation.operationId 208 - ? toCase( 209 - this.splitOperationId(operation.operationId).pop()!, 210 - 'camelCase', 211 - ) 212 - : operation.id, 213 - }), 214 - { 215 - meta: { 216 - category: 'sdk', 217 - path, 218 - resource: 'operation', 219 - resourceId: operation.id, 220 - tags, 221 - tool: 'sdk', 222 - }, 223 - }, 224 - ); 225 - } 226 - 227 - private childToNode( 228 - resource: SdkResourceModel, 229 - plugin: HeyApiSdkPlugin['Instance'], 230 - ): ReadonlyArray<ReturnType<typeof $.field | typeof $.getter>> { 231 - const refChild = plugin.referenceSymbol({ 232 - category: 'utility', 233 - resource: 'class', 234 - resourceId: resource.getPath().join('.'), 235 - tool: 'sdk', 236 - }); 237 - const memberNameStr = toCase(refChild.name, 'camelCase'); 238 - const memberName = plugin.symbol(memberNameStr); 239 - if (plugin.config.instance) { 240 - const privateName = plugin.symbol(`_${memberNameStr}`); 241 - return [ 242 - $.field(privateName, (f) => f.private().optional().type(refChild)), 243 - $.getter(memberName, (g) => 244 - g.returns(refChild).do( 245 - $('this') 246 - .attr(privateName) 247 - .nullishAssign( 248 - $.new(refChild).args( 249 - $.object().prop('client', $('this').attr('client')), 250 - ), 251 - ) 252 - .return(), 253 - ), 254 - ), 255 - ]; 256 - } 257 - if (plugin.isSymbolRegistered(refChild.id)) { 258 - return [$.field(memberName, (f) => f.static().assign($(refChild)))]; 259 - } 260 - return [ 261 - $.getter(memberName, (g) => g.public().static().do($.return(refChild))), 262 - ]; 263 - } 264 - 265 - private classToNode(plugin: HeyApiSdkPlugin['Instance']): { 266 - node: ReturnType<typeof $.class>; 267 - symbol: Symbol; 268 - } { 269 - const client = getClientPlugin(plugin.context.config); 270 - const isAngularClient = client.name === '@hey-api/client-angular'; 271 - const symbol = plugin.symbol( 272 - operationClassName({ plugin, value: this.name }), 273 - { 274 - meta: { 275 - category: 'utility', 276 - resource: 'class', 277 - resourceId: this.getPath().join('.'), 278 - tool: 'sdk', 279 - }, 280 - }, 281 - ); 282 - const node = $.class(symbol) 283 - .export() 284 - .$if(plugin.config.instance, (c) => 285 - c.extends( 286 - plugin.referenceSymbol({ 287 - category: 'utility', 288 - resource: 'class', 289 - resourceId: 'HeyApiClient', 290 - tool: 'sdk', 291 - }), 292 - ), 293 - ) 294 - .$if(isAngularClient && this.isRoot, (c) => 295 - c.decorator( 296 - plugin.referenceSymbol({ 297 - category: 'external', 298 - resource: '@angular/core.Injectable', 299 - }), 300 - $.object().prop('providedIn', $.literal('root')), 301 - ), 302 - ); 303 - return { node, symbol }; 304 - } 305 - 306 - private enrichRootClass(args: { 307 - dependencies: Array<ReturnType<typeof $.class>>; 308 - node: ReturnType<typeof $.class>; 309 - plugin: HeyApiSdkPlugin['Instance']; 310 - symbol: Symbol; 311 - }): void { 312 - const { dependencies, node, plugin, symbol } = args; 313 - const symbolClient = plugin.symbol('HeyApiClient', { 314 - meta: { 315 - category: 'utility', 316 - resource: 'class', 317 - resourceId: 'HeyApiClient', 318 - tool: 'sdk', 319 - }, 320 - }); 321 - dependencies.push(createClientClass({ plugin, symbol: symbolClient })); 322 - const symbolRegistry = plugin.symbol('HeyApiRegistry', { 323 - meta: { 324 - category: 'utility', 325 - resource: 'class', 326 - resourceId: 'HeyApiRegistry', 327 - tool: 'sdk', 328 - }, 329 - }); 330 - dependencies.push( 331 - createRegistryClass({ 332 - plugin, 333 - sdkSymbol: symbol, 334 - symbol: symbolRegistry, 335 - }), 336 - ); 337 - const isClientRequired = 338 - !plugin.config.client || !plugin.getSymbol({ category: 'client' }); 339 - const registry = plugin.symbol('__registry'); 340 - node.toAccessNode = (node, options) => { 341 - if (options.context) return; 342 - return $(node.name).attr(registry).attr('get').call(); 343 - }; 344 - node.do( 345 - $.field(registry, (f) => 346 - f 347 - .public() 348 - .static() 349 - .readonly() 350 - .assign($.new(symbolRegistry).generic(symbol)), 351 - ), 352 - $.newline(), 353 - $.init((i) => 354 - i 355 - .param('args', (p) => 356 - p.required(isClientRequired).type( 357 - $.type 358 - .object() 359 - .prop('client', (p) => 360 - p.required(isClientRequired).type( 361 - plugin.referenceSymbol({ 362 - category: 'external', 363 - resource: 'client.Client', 364 - }), 365 - ), 366 - ) 367 - .prop('key', (p) => p.optional().type('string')), 368 - ), 369 - ) 370 - .do( 371 - $('super').call('args'), 372 - $(symbol) 373 - .attr(registry) 374 - .attr('set') 375 - .call('this', $('args').attr('key').required(isClientRequired)), 376 - ), 377 - ), 378 - ); 379 - } 380 - 381 - private implementFn< 382 - T extends ReturnType<typeof $.func | typeof $.method>, 383 - >(args: { 384 - node: T; 385 - operation: IR.OperationObject; 386 - plugin: HeyApiSdkPlugin['Instance']; 387 - }): T { 388 - const { node, operation, plugin } = args; 389 - const client = getClientPlugin(plugin.context.config); 390 - const isNuxtClient = client.name === '@hey-api/client-nuxt'; 391 - const isRequiredOptions = isOperationOptionsRequired({ 392 - context: plugin.context, 393 - operation, 394 - }); 395 - const opParameters = operationParameters({ 396 - isRequiredOptions, 397 - operation, 398 - plugin, 399 - }); 400 - const statements = operationStatements({ 401 - isRequiredOptions, 402 - opParameters, 403 - operation, 404 - plugin, 405 - }); 406 - return node 407 - .$if( 408 - isNuxtClient, 409 - (m) => 410 - m 411 - .generic(nuxtTypeComposable, (t) => 412 - t 413 - .extends( 414 - plugin.referenceSymbol({ 415 - category: 'external', 416 - resource: 'client.Composable', 417 - }), 418 - ) 419 - .default($.type.literal('$fetch')), 420 - ) 421 - .generic(nuxtTypeDefault, (t) => 422 - t.$if( 423 - plugin.querySymbol({ 424 - category: 'type', 425 - resource: 'operation', 426 - resourceId: operation.id, 427 - role: 'response', 428 - }), 429 - (t, s) => t.extends(s).default(s), 430 - (t) => t.default('undefined'), 431 - ), 432 - ), 433 - (m) => 434 - m.generic('ThrowOnError', (t) => 435 - t 436 - .extends('boolean') 437 - .default( 438 - ('throwOnError' in client.config 439 - ? client.config.throwOnError 440 - : false) ?? false, 441 - ), 442 - ), 443 - ) 444 - .params(...opParameters.parameters) 445 - .do(...statements) as T; 446 - } 447 - 448 - private splitOperationId(operationId: string): Array<string> { 449 - // TODO: expose this logic 450 - return operationId.split(/[./]/).filter(Boolean); 451 - } 452 - }
-70
packages/openapi-ts/src/plugins/@hey-api/sdk/model/structure.ts
··· 1 - import type { HeyApiSdkPlugin } from '../types'; 2 - import type { Event } from './resource'; 3 - import { SdkResourceModel } from './resource'; 4 - 5 - export class SdkStructureModel { 6 - /** If true, generates a flat SDK without resource hierarchy. */ 7 - private _flat: boolean; 8 - /** Name of the SDK. If empty, we fallback to operation tags. */ 9 - private _name: string; 10 - /** Root resources mapped by their names. */ 11 - private _roots: Map<string, SdkResourceModel> = new Map(); 12 - 13 - constructor( 14 - name: string, 15 - options?: { 16 - /** If true, generates a flat SDK without resource hierarchy. */ 17 - flat?: boolean; 18 - }, 19 - ) { 20 - this._flat = options?.flat ?? false; 21 - this._name = name; 22 - } 23 - 24 - /** 25 - * Inserts an operation event into the structure. 26 - * 27 - * Parses the operation ID and organizes it into classes based on tags. 28 - */ 29 - insert(event: Event, plugin: HeyApiSdkPlugin['Instance']): void { 30 - const { operation } = event; 31 - const roots = this._name 32 - ? [this._name] 33 - : this._flat 34 - ? [''] 35 - : operation.tags && operation.tags.length > 0 36 - ? operation.tags 37 - : ['default']; 38 - 39 - for (const name of roots) { 40 - const resource = this.root(name); 41 - resource.insert(event, plugin); 42 - } 43 - } 44 - 45 - /** 46 - * Gets or creates a root resource by name. 47 - * 48 - * If the root doesn't exist, it's created automatically. 49 - * 50 - * @param name - The name of the root resource 51 - * @returns The root resource instance 52 - */ 53 - root(name: string): SdkResourceModel { 54 - if (!this._roots.has(name)) { 55 - this._roots.set(name, new SdkResourceModel(name)); 56 - } 57 - return this._roots.get(name)!; 58 - } 59 - 60 - /** 61 - * Recursively walks the structure. 62 - * 63 - * Yields all resources in the structure. 64 - */ 65 - *walk(): Generator<SdkResourceModel> { 66 - for (const resource of this._roots.values()) { 67 - yield* resource.walk(); 68 - } 69 - } 70 - }
+9 -2
packages/openapi-ts/src/plugins/@hey-api/sdk/shared/operation.ts
··· 6 6 import { sanitizeNamespaceIdentifier } from '~/openApi/common/parser/sanitize'; 7 7 import { getClientPlugin } from '~/plugins/@hey-api/client-core/utils'; 8 8 import { $ } from '~/ts-dsl'; 9 - import { toCase } from '~/utils/to-case'; 9 + import { toCase } from '~/utils/naming'; 10 10 11 11 import type { Field, Fields } from '../../client-core/bundle/params'; 12 12 import type { HeyApiSdkPlugin } from '../types'; ··· 30 30 path: ReadonlyArray<string>; 31 31 } 32 32 33 + /** 34 + * @deprecated 35 + */ 33 36 export const operationClassName = ({ 34 37 plugin, 35 38 value, ··· 46 49 ); 47 50 }; 48 51 52 + /** 53 + * @deprecated 54 + */ 49 55 export const operationMethodName = ({ 50 56 operation, 51 57 plugin, ··· 60 66 return ( 61 67 (typeof plugin.config.methodNameBuilder === 'string' 62 68 ? plugin.config.methodNameBuilder.replace('{{name}}', name) 63 - : plugin.config.methodNameBuilder?.(name, operation)) || name 69 + : // @ts-expect-error TODO: remove 70 + plugin.config.methodNameBuilder?.(name, operation)) || name 64 71 ); 65 72 }; 66 73
+1 -1
packages/openapi-ts/src/plugins/@hey-api/sdk/shared/signature.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 2 import type { PluginInstance } from '~/plugins/shared/utils/instance'; 3 + import { toCase } from '~/utils/naming'; 3 4 import { refToName } from '~/utils/ref'; 4 - import { toCase } from '~/utils/to-case'; 5 5 6 6 import type { Field } from '../../client-core/bundle/params'; 7 7
+4 -8
packages/openapi-ts/src/plugins/@hey-api/sdk/shared/typeOptions.ts
··· 14 14 const client = getClientPlugin(plugin.context.config); 15 15 const isNuxtClient = client.name === '@hey-api/client-nuxt'; 16 16 17 - const symbolTDataShape = plugin.registerSymbol({ 17 + const symbolTDataShape = plugin.symbol('TDataShape', { 18 18 external: clientModule, 19 19 kind: 'type', 20 - name: 'TDataShape', 21 20 }); 22 - const symbolClient = plugin.registerSymbol({ 21 + const symbolClient = plugin.symbol('Client', { 23 22 external: clientModule, 24 23 kind: 'type', 25 24 meta: { ··· 27 26 resource: 'client.Client', 28 27 tool: client.name, 29 28 }, 30 - name: 'Client', 31 29 }); 32 - const symbolClientOptions = plugin.registerSymbol({ 30 + const symbolClientOptions = plugin.symbol('Options', { 33 31 external: clientModule, 34 32 kind: 'type', 35 - name: 'Options', 36 33 }); 37 - const symbolOptions = plugin.registerSymbol({ 34 + const symbolOptions = plugin.symbol('Options', { 38 35 meta: { 39 36 category: 'type', 40 37 resource: 'client-options', 41 38 tool: 'sdk', 42 39 }, 43 - name: 'Options', 44 40 }); 45 41 46 42 const typeOptions = $.type
+202
packages/openapi-ts/src/plugins/@hey-api/sdk/structure/config.ts
··· 1 + import type { PluginContext } from '~/plugins/types'; 2 + import type { NamingConfig, NamingRule } from '~/utils/naming'; 3 + import { resolveNaming } from '~/utils/naming'; 4 + 5 + import type { UserConfig } from '../types'; 6 + import type { 7 + StructureConfig, 8 + StructureStrategy, 9 + UserStructureConfig, 10 + } from './types'; 11 + 12 + type Config = Omit<UserConfig, 'name'>; 13 + 14 + // container: 'class', 15 + // containerName: {}, 16 + // defaultTag: 'default', 17 + // delimiters: /[./]/, 18 + // methodName: {}, 19 + // methods: 'instance', 20 + // nesting: 'operationId', 21 + // segmentName: {}, 22 + // strategy: 'flat', 23 + 24 + export function resolveStructure( 25 + config: Config, 26 + // eslint-disable-next-line @typescript-eslint/no-unused-vars 27 + _context: PluginContext, 28 + ): StructureConfig { 29 + // if (plugin.config.instance) { 30 + // if (typeof plugin.config.instance !== 'string') { 31 + // plugin.config.instance = 'Sdk'; 32 + // } 33 + 34 + // plugin.config.asClass = true; 35 + // } else { 36 + // plugin.config.instance = ''; 37 + // } 38 + 39 + // // Set default classNameBuilder based on client type 40 + // if (plugin.config.classNameBuilder === '{{name}}') { 41 + // if (plugin.config.client === '@hey-api/client-angular') { 42 + // plugin.config.classNameBuilder = '{{name}}Service'; 43 + // } 44 + // } 45 + 46 + // Check for deprecated options and warn 47 + if (config.asClass !== undefined) { 48 + console.warn( 49 + '`asClass` is deprecated. Use `grouping: "byTags"` or `grouping: "single"` instead.', 50 + ); 51 + } 52 + 53 + if (config.instance !== undefined) { 54 + console.warn( 55 + '`instance` is deprecated. Use `grouping: { strategy: "single", containerName: "Name", methods: "instance" }` instead.', 56 + ); 57 + } 58 + 59 + if (config.classStructure !== undefined) { 60 + console.warn( 61 + '`classStructure` is deprecated. Use `grouping: { nesting: "operationId" }` or `grouping: { nesting: "id" }` instead.', 62 + ); 63 + } 64 + 65 + if (config.classNameBuilder !== undefined) { 66 + console.warn( 67 + '`classNameBuilder` is deprecated. Use `grouping.containerName` instead.', 68 + ); 69 + } 70 + 71 + if (config.methodNameBuilder !== undefined) { 72 + console.warn( 73 + '`methodNameBuilder` is deprecated. Use `grouping.methodName` instead.', 74 + ); 75 + } 76 + 77 + if (config.operationId !== undefined) { 78 + console.warn( 79 + '`operationId` is deprecated. Use `grouping: { nesting: "operationId" }` or `grouping: { nesting: "id" }` instead.', 80 + ); 81 + } 82 + 83 + // If new grouping config is provided, use it 84 + if (config.structure !== undefined) { 85 + return normalizeStructureConfig(config.structure); 86 + } 87 + 88 + // Otherwise, map legacy config to new grouping config 89 + return mapLegacyToGrouping(config); 90 + } 91 + 92 + function normalizeStructureConfig( 93 + input: StructureStrategy | UserStructureConfig, 94 + ): StructureConfig { 95 + // String shorthand 96 + if (typeof input === 'string') { 97 + return { 98 + container: 'class', 99 + containerName: input === 'single' ? { name: 'Sdk' } : {}, 100 + defaultTag: 'default', 101 + delimiters: /[./]/, 102 + methodName: {}, 103 + methods: 'instance', 104 + nesting: 'operationId', 105 + segmentName: {}, 106 + strategy: input, 107 + }; 108 + } 109 + 110 + // Custom function 111 + if (typeof input === 'function') { 112 + return { 113 + container: 'class', 114 + containerName: {}, 115 + defaultTag: 'default', 116 + delimiters: /[./]/, 117 + methodName: {}, 118 + methods: 'instance', 119 + nesting: 'operationId', 120 + segmentName: {}, 121 + strategy: input, 122 + }; 123 + } 124 + 125 + // Full config object 126 + const strategy = input.strategy ?? 'flat'; 127 + 128 + return { 129 + container: input.container ?? 'class', 130 + containerName: resolveContainerName(input.containerName, strategy), 131 + defaultTag: input.defaultTag ?? 'default', 132 + delimiters: input.delimiters ?? /[./]/, 133 + methodName: resolveNaming(input.methodName), 134 + methods: input.methods ?? 'instance', 135 + nesting: input.nesting ?? 'operationId', 136 + segmentName: resolveNaming(input.segmentName), 137 + strategy, 138 + }; 139 + } 140 + 141 + function resolveContainerName( 142 + input: NamingRule | undefined, 143 + strategy: StructureStrategy, 144 + ): NamingConfig { 145 + const resolved = resolveNaming(input); 146 + 147 + // Default name for 'single' strategy 148 + if (strategy === 'single' && !resolved.name) { 149 + resolved.name = 'Sdk'; 150 + } 151 + 152 + return resolved; 153 + } 154 + 155 + function mapLegacyToGrouping(config: Config): StructureConfig { 156 + // Determine strategy from legacy options 157 + let strategy: StructureStrategy = 'flat'; 158 + 159 + if (config.asClass) { 160 + strategy = config.instance ? 'single' : 'byTags'; 161 + } 162 + 163 + // Determine container name 164 + let containerName: NamingConfig = {}; 165 + 166 + if (config.instance && typeof config.instance === 'string') { 167 + containerName = { name: config.instance }; 168 + } else if (config.classNameBuilder) { 169 + containerName = resolveNaming(config.classNameBuilder); 170 + } 171 + 172 + if (strategy === 'single' && !containerName.name) { 173 + containerName.name = 'Sdk'; 174 + } 175 + 176 + // Determine method name 177 + const methodName: NamingConfig = config.methodNameBuilder 178 + ? resolveNaming(config.methodNameBuilder) 179 + : {}; 180 + 181 + // Determine nesting 182 + let nesting: 'operationId' | 'id' = 'operationId'; 183 + 184 + if (config.classStructure === 'off' || config.operationId === false) { 185 + nesting = 'id'; 186 + } 187 + 188 + // Determine methods style 189 + const methods = config.instance ? 'instance' : 'static'; 190 + 191 + return { 192 + container: 'class', 193 + containerName, 194 + defaultTag: 'default', 195 + delimiters: /[./]/, 196 + methodName, 197 + methods, 198 + nesting, 199 + segmentName: {}, 200 + strategy, 201 + }; 202 + }
+6
packages/openapi-ts/src/plugins/@hey-api/sdk/structure/index.ts
··· 1 + export { resolveStructure } from './config'; 2 + export type { 3 + StructureConfig, 4 + StructureStrategy, 5 + UserStructureConfig, 6 + } from './types';
+195
packages/openapi-ts/src/plugins/@hey-api/sdk/structure/types.d.ts
··· 1 + import type { IR } from '~/ir/types'; 2 + import type { OperationPathStrategy } from '~/openApi/shared/locations'; 3 + import type { NamingConfig, NamingRule } from '~/utils/naming'; 4 + 5 + type CustomStructureStrategy = ( 6 + operation: IR.OperationObject, 7 + ) => ReadonlyArray<ReadonlyArray<string>>; 8 + 9 + export type StructureStrategy = 10 + | 'byTags' 11 + | 'flat' 12 + | 'single' 13 + | CustomStructureStrategy; 14 + 15 + export interface UserStructureConfig { 16 + /** 17 + * Type of container for grouped operations. 18 + * 19 + * Ignored when `strategy` is `'flat'`. 20 + * 21 + * - `'class'` - Class with methods 22 + * - `'object'` - Plain object literal 23 + * 24 + * @default 'class' 25 + */ 26 + container?: 'class' | 'object'; 27 + /** 28 + * Customize container names (class or object variable names). 29 + * 30 + * For `'single'` strategy, this sets the root container name. 31 + * For `'byTags'` strategy, this transforms tag names. 32 + * 33 + * @default 'Sdk' for `'single'` strategy 34 + * 35 + * @example 36 + * // Set root name for single strategy 37 + * containerName: 'MyApi' 38 + * 39 + * @example 40 + * // Transform tag names with suffix 41 + * containerName: '{{name}}Service' 42 + * 43 + * @example 44 + * // With casing 45 + * containerName: { name: '{{name}}Service', case: 'PascalCase' } 46 + */ 47 + containerName?: NamingRule; 48 + /** 49 + * Default container name for operations without tags. 50 + * 51 + * Only applies when `strategy` is `'byTags'`. 52 + * 53 + * @default 'default' 54 + */ 55 + defaultTag?: string; 56 + /** 57 + * Delimiters for splitting operationId. 58 + * 59 + * Only applies when `nesting` is `'operationId'`. 60 + * 61 + * @default /[./]/ 62 + */ 63 + delimiters?: RegExp; 64 + /** 65 + * Customize method/function names. 66 + * 67 + * Applied to the final segment of the path (the method name). 68 + */ 69 + methodName?: NamingRule; 70 + /** 71 + * How methods are attached to class containers. 72 + * 73 + * Only applies when `container` is `'class'`. 74 + * 75 + * - `'static'` - Static methods, no instantiation required 76 + * - `'instance'` - Instance methods, requires `new ClassName(config)` 77 + * 78 + * @default 'instance' 79 + */ 80 + methods?: 'instance' | 'static'; 81 + /** 82 + * How to derive nesting structure from operations. 83 + * 84 + * Ignored when `strategy` is `'flat'`. 85 + * 86 + * - `'operationId'` - Split operationId by delimiters (e.g., `users.list` → `Users.list()`) 87 + * - `'id'` - Use operation id as-is, no nesting 88 + * - Custom function for full control 89 + * 90 + * @default 'operationId' 91 + */ 92 + nesting?: 'operationId' | 'id' | OperationPathStrategy; 93 + /** 94 + * Customize nesting segment names. 95 + * 96 + * Applied to intermediate path segments (not the method name). 97 + */ 98 + segmentName?: NamingRule; 99 + /** 100 + * Grouping strategy. 101 + * 102 + * - `'flat'` - Standalone functions, no grouping 103 + * - `'byTags'` - One container per operation tag 104 + * - `'single'` - All operations in one container 105 + * - Custom function for full control 106 + * 107 + * @default 'flat' 108 + */ 109 + strategy?: StructureStrategy; 110 + } 111 + 112 + export interface StructureConfig { 113 + /** 114 + * Type of container for grouped operations. 115 + * 116 + * Ignored when `strategy` is `'flat'`. 117 + * 118 + * - `'class'` - Class with methods 119 + * - `'object'` - Plain object literal 120 + */ 121 + container: 'class' | 'object'; 122 + /** 123 + * Customize container names (class or object variable names). 124 + * 125 + * For `'single'` strategy, this sets the root container name. 126 + * For `'byTags'` strategy, this transforms tag names. 127 + * 128 + * @default 'Sdk' for `'single'` strategy 129 + * 130 + * @example 131 + * // Set root name for single strategy 132 + * containerName: 'MyApi' 133 + * 134 + * @example 135 + * // Transform tag names with suffix 136 + * containerName: '{{name}}Service' 137 + * 138 + * @example 139 + * // With casing 140 + * containerName: { name: '{{name}}Service', case: 'PascalCase' } 141 + */ 142 + containerName: NamingConfig; 143 + /** 144 + * Default container name for operations without tags. 145 + * 146 + * Only applies when `strategy` is `'byTags'`. 147 + */ 148 + defaultTag: string; 149 + /** 150 + * Delimiters for splitting operationId. 151 + * 152 + * Only applies when `nesting` is `'operationId'`. 153 + */ 154 + delimiters: RegExp; 155 + /** 156 + * Customize method/function names. 157 + * 158 + * Applied to the final segment of the path (the method name). 159 + */ 160 + methodName: NamingConfig; 161 + /** 162 + * How methods are attached to class containers. 163 + * 164 + * Only applies when `container` is `'class'`. 165 + * 166 + * - `'static'` - Static methods, no instantiation required 167 + * - `'instance'` - Instance methods, requires `new ClassName(config)` 168 + */ 169 + methods: 'instance' | 'static'; 170 + /** 171 + * How to derive nesting structure from operations. 172 + * 173 + * Ignored when `strategy` is `'flat'`. 174 + * 175 + * - `'operationId'` - Split operationId by delimiters (e.g., `users.list` → `Users.list()`) 176 + * - `'id'` - Use operation id as-is, no nesting 177 + * - Custom function for full control 178 + */ 179 + nesting: 'operationId' | 'id' | OperationPathStrategy; 180 + /** 181 + * Customize nesting segment names. 182 + * 183 + * Applied to intermediate path segments (not the method name). 184 + */ 185 + segmentName: NamingConfig; 186 + /** 187 + * Grouping strategy. 188 + * 189 + * - `'flat'` - Standalone functions, no grouping 190 + * - `'byTags'` - One container per operation tag 191 + * - `'single'` - All operations in one container 192 + * - Custom function for full control 193 + */ 194 + strategy: StructureStrategy; 195 + }
+134 -126
packages/openapi-ts/src/plugins/@hey-api/sdk/types.d.ts
··· 1 - import type { IR } from '~/ir/types'; 2 1 import type { DefinePlugin, Plugin } from '~/plugins'; 3 2 import type { PluginClientNames, PluginValidatorNames } from '~/plugins/types'; 4 - import type { StringName } from '~/types/case'; 3 + import type { NameTransformer } from '~/utils/naming'; 4 + 5 + import type { 6 + StructureConfig, 7 + StructureStrategy, 8 + UserStructureConfig, 9 + } from './structure'; 5 10 6 11 export type UserConfig = Plugin.Name<'@hey-api/sdk'> & 7 12 Plugin.Hooks & { 8 13 /** 9 - * Group operation methods into classes? When enabled, you can select which 10 - * classes to export with `sdk.include` and/or transform their names with 11 - * `sdk.classNameBuilder`. 12 - * 13 - * Note that by enabling this option, your SDKs will **NOT** 14 - * support {@link https://developer.mozilla.org/docs/Glossary/Tree_shaking tree-shaking}. 15 - * For this reason, it is disabled by default. 16 - * 17 - * @default false 18 - */ 19 - asClass?: boolean; 20 - /** 21 14 * Should the generated functions contain auth mechanisms? You may want to 22 15 * disable this option if you're handling auth yourself or defining it 23 16 * globally on the client and want to reduce the size of generated code. ··· 26 19 */ 27 20 auth?: boolean; 28 21 /** 29 - * Customize the generated class names. The name variable is obtained from 30 - * your OpenAPI specification tags or `instance` value. 31 - * 32 - * This option has no effect if `sdk.asClass` is `false`. 33 - */ 34 - classNameBuilder?: StringName; 35 - /** 36 - * How should we structure your SDK? By default, we try to infer the ideal 37 - * structure using `operationId` keywords. If you prefer a flatter structure, 38 - * you can set `classStructure` to `off` to disable this behavior. 39 - * 40 - * @default 'auto' 41 - */ 42 - classStructure?: 'auto' | 'off'; 43 - /** 44 22 * Use an internal client instance to send HTTP requests? This is useful if 45 23 * you don't want to manually pass the client to each SDK function. 46 24 * ··· 60 38 */ 61 39 exportFromIndex?: boolean; 62 40 /** 63 - * Include only service classes with names matching regular expression 64 - * 65 - * This option has no effect if `sdk.asClass` is `false`. 66 - */ 67 - include?: string; 68 - /** 69 - * Set `instance` to create an instantiable SDK. Using `true` will use the 70 - * default instance name; in practice, you want to define your own by passing 71 - * a string value. 72 - * 73 - * @default false 74 - */ 75 - instance?: string | boolean; 76 - /** 77 - * Customise the name of methods within the service. By default, 78 - * `operation.id` is used. 79 - */ 80 - methodNameBuilder?: 81 - | string 82 - | ((name: string, operation: IR.OperationObject) => string); 83 - // TODO: parser - rename operationId option to something like inferId?: boolean 84 - /** 85 - * Use operation ID to generate operation names? 86 - * 87 - * @default true 88 - */ 89 - operationId?: boolean; 90 - /** 91 41 * Define how request parameters are structured in generated SDK methods. 92 42 * 93 43 * - `'flat'` merges parameters into a single object. ··· 107 57 */ 108 58 responseStyle?: 'data' | 'fields'; 109 59 /** 60 + * Define how generated outputs are structurally organized. 61 + */ 62 + structure?: { 63 + /** 64 + * Define the structure of generated SDK operations. 65 + * 66 + * String shorthand: 67 + * - `'flat'` – standalone functions, no container 68 + * - `'byTags'` – one container per operation tag 69 + * - `'single'` – all operations in a single container 70 + * - custom function for full control 71 + * 72 + * Use the object form for advanced configuration. 73 + * 74 + * @default 'flat' 75 + */ 76 + operations?: StructureStrategy | UserStructureConfig; 77 + }; 78 + /** 110 79 * Transform response data before returning. This is useful if you want to 111 80 * convert for example ISO strings into Date objects. However, transformation 112 81 * adds runtime overhead, so it's not recommended to use unless necessary. ··· 163 132 // DEPRECATED OPTIONS BELOW 164 133 165 134 /** 166 - * **This feature works only with the legacy parser** 167 - * 168 - * Filter endpoints to be included in the generated SDK. The provided 169 - * string should be a regular expression where matched results will be 170 - * included in the output. The input pattern this string will be tested 171 - * against is `{method} {path}`. For example, you can match 172 - * `POST /api/v1/foo` with `^POST /api/v1/foo$`. 173 - * 174 - * @deprecated 175 - */ 176 - // eslint-disable-next-line typescript-sort-keys/interface 177 - filter?: string; 178 - /** 179 - * Define shape of returned value from service calls 180 - * 181 - * @deprecated 182 - * @default 'body' 183 - */ 184 - response?: 'body' | 'response'; 185 - }; 186 - 187 - export type Config = Plugin.Name<'@hey-api/sdk'> & 188 - Plugin.Hooks & { 189 - /** 190 135 * Group operation methods into classes? When enabled, you can select which 191 136 * classes to export with `sdk.include` and/or transform their names with 192 137 * `sdk.classNameBuilder`. ··· 195 140 * support {@link https://developer.mozilla.org/docs/Glossary/Tree_shaking tree-shaking}. 196 141 * For this reason, it is disabled by default. 197 142 * 143 + * @deprecated Use `grouping: 'byTags'` or `grouping: 'single'` instead. 198 144 * @default false 199 145 */ 200 - asClass: boolean; 201 - /** 202 - * Should the generated functions contain auth mechanisms? You may want to 203 - * disable this option if you're handling auth yourself or defining it 204 - * globally on the client and want to reduce the size of generated code. 205 - * 206 - * @default true 207 - */ 208 - auth: boolean; 146 + // eslint-disable-next-line typescript-sort-keys/interface 147 + asClass?: boolean; 209 148 /** 210 149 * Customize the generated class names. The name variable is obtained from 211 150 * your OpenAPI specification tags or `instance` value. 212 151 * 213 152 * This option has no effect if `sdk.asClass` is `false`. 153 + * 154 + * @deprecated Use `grouping.containerName` instead. 214 155 */ 215 - classNameBuilder: StringName; 156 + classNameBuilder?: NameTransformer; 216 157 /** 217 158 * How should we structure your SDK? By default, we try to infer the ideal 218 159 * structure using `operationId` keywords. If you prefer a flatter structure, 219 160 * you can set `classStructure` to `off` to disable this behavior. 220 161 * 162 + * @deprecated Use `grouping: { nesting: 'operationId' }` or `grouping: { nesting: 'id' }` instead. 221 163 * @default 'auto' 222 164 */ 223 - classStructure: 'auto' | 'off'; 165 + classStructure?: 'auto' | 'off'; 224 166 /** 225 - * Use an internal client instance to send HTTP requests? This is useful if 226 - * you don't want to manually pass the client to each SDK function. 167 + * Set `instance` to create an instantiable SDK. Using `true` will use the 168 + * default instance name; in practice, you want to define your own by passing 169 + * a string value. 227 170 * 228 - * You can customize the selected client output through its plugin. You can 229 - * also set `client` to `true` to automatically choose the client from your 230 - * defined plugins. If we can't detect a client plugin when using `true`, we 231 - * will default to `@hey-api/client-fetch`. 171 + * @deprecated Use `grouping: { strategy: 'single', as: 'Name', methods: 'instance' }` instead. 172 + * @default false 173 + */ 174 + instance?: string | boolean; 175 + /** 176 + * Customise the name of methods within the service. By default, 177 + * `operation.id` is used. 232 178 * 233 - * @default true 179 + * @deprecated Use `grouping.methodName` instead. 234 180 */ 235 - client: PluginClientNames | false; 181 + methodNameBuilder?: NameTransformer; 236 182 /** 237 - * Should the exports from the generated files be re-exported in the index 238 - * barrel file? 183 + * Use operation ID to generate operation names? 239 184 * 185 + * @deprecated Use `grouping.nesting: 'operationId'` or `grouping.nesting: 'id'` instead. 240 186 * @default true 241 187 */ 242 - exportFromIndex: boolean; 188 + operationId?: boolean; 243 189 /** 244 - * Include only service classes with names matching regular expression 190 + * Define shape of returned value from service calls 245 191 * 246 - * This option has no effect if `sdk.asClass` is `false`. 192 + * @deprecated 193 + * @default 'body' 247 194 */ 248 - include: string | undefined; 195 + response?: 'body' | 'response'; 196 + }; 197 + 198 + export type Config = Plugin.Name<'@hey-api/sdk'> & 199 + Plugin.Hooks & { 249 200 /** 250 - * Set `instance` to create an instantiable SDK. Using `true` will use the 251 - * default instance name; in practice, you want to define your own by passing 252 - * a string value. 201 + * Should the generated functions contain auth mechanisms? You may want to 202 + * disable this option if you're handling auth yourself or defining it 203 + * globally on the client and want to reduce the size of generated code. 204 + * 205 + * @default true 253 206 */ 254 - instance: string; 207 + auth: boolean; 255 208 /** 256 - * Customise the name of methods within the service. By default, 257 - * `operation.id` is used. 209 + * Use an internal client instance to send HTTP requests? This is useful if 210 + * you don't want to manually pass the client to each SDK function. 211 + * 212 + * You can customize the selected client output through its plugin. You can 213 + * also set `client` to `true` to automatically choose the client from your 214 + * defined plugins. If we can't detect a client plugin when using `true`, we 215 + * will default to `@hey-api/client-fetch`. 216 + * 217 + * @default true 258 218 */ 259 - methodNameBuilder: 260 - | string 261 - | ((name: string, operation: IR.OperationObject) => string); 262 - // TODO: parser - rename operationId option to something like inferId?: boolean 219 + client: PluginClientNames | false; 263 220 /** 264 - * Use operation ID to generate operation names? 221 + * Should the exports from the generated files be re-exported in the index 222 + * barrel file? 265 223 * 266 224 * @default true 267 225 */ 268 - operationId: boolean; 226 + exportFromIndex: boolean; 269 227 /** 270 228 * Define how request parameters are structured in generated SDK methods. 271 229 * ··· 286 244 */ 287 245 responseStyle: 'data' | 'fields'; 288 246 /** 247 + * Define how generated outputs are structurally organized. 248 + */ 249 + structure: { 250 + /** 251 + * Define the structure of generated SDK operations. 252 + */ 253 + operations: StructureConfig; 254 + }; 255 + /** 289 256 * Transform response data before returning. This is useful if you want to 290 257 * convert for example ISO strings into Date objects. However, transformation 291 258 * adds runtime overhead, so it's not recommended to use unless necessary. ··· 321 288 // DEPRECATED OPTIONS BELOW 322 289 323 290 /** 324 - * **This feature works only with the legacy parser** 291 + * Group operation methods into classes? When enabled, you can select which 292 + * classes to export with `sdk.include` and/or transform their names with 293 + * `sdk.classNameBuilder`. 325 294 * 326 - * Filter endpoints to be included in the generated SDK. The provided 327 - * string should be a regular expression where matched results will be 328 - * included in the output. The input pattern this string will be tested 329 - * against is `{method} {path}`. For example, you can match 330 - * `POST /api/v1/foo` with `^POST /api/v1/foo$`. 295 + * Note that by enabling this option, your SDKs will **NOT** 296 + * support {@link https://developer.mozilla.org/docs/Glossary/Tree_shaking tree-shaking}. 297 + * For this reason, it is disabled by default. 331 298 * 332 - * @deprecated 299 + * @deprecated Use `grouping: 'byTags'` or `grouping: 'single'` instead. 300 + * @default false 333 301 */ 334 302 // eslint-disable-next-line typescript-sort-keys/interface 335 - filter?: string; 303 + asClass: boolean; 304 + /** 305 + * Customize the generated class names. The name variable is obtained from 306 + * your OpenAPI specification tags or `instance` value. 307 + * 308 + * This option has no effect if `sdk.asClass` is `false`. 309 + * 310 + * @deprecated Use `grouping.containerName` instead. 311 + */ 312 + classNameBuilder: NameTransformer; 313 + /** 314 + * How should we structure your SDK? By default, we try to infer the ideal 315 + * structure using `operationId` keywords. If you prefer a flatter structure, 316 + * you can set `classStructure` to `off` to disable this behavior. 317 + * 318 + * @deprecated Use `grouping: { nesting: 'operationId' }` or `grouping: { nesting: 'id' }` instead. 319 + * @default 'auto' 320 + */ 321 + classStructure: 'auto' | 'off'; 322 + /** 323 + * Set `instance` to create an instantiable SDK. Using `true` will use the 324 + * default instance name; in practice, you want to define your own by passing 325 + * a string value. 326 + * 327 + * @deprecated Use `grouping: { strategy: 'single', as: 'Name', methods: 'instance' }` instead. 328 + */ 329 + instance: string; 330 + /** 331 + * Customise the name of methods within the service. By default, 332 + * `operation.id` is used. 333 + * 334 + * @deprecated Use `grouping.methodName` instead. 335 + */ 336 + methodNameBuilder: NameTransformer; 337 + /** 338 + * Use operation ID to generate operation names? 339 + * 340 + * @deprecated Use `grouping.nesting: 'operationId'` or `grouping.nesting: 'id'` instead. 341 + * @default true 342 + */ 343 + operationId: boolean; 336 344 /** 337 345 * Define shape of returned value from service calls 338 346 *
+417 -13
packages/openapi-ts/src/plugins/@hey-api/sdk/v1/plugin.ts
··· 1 + import type { 2 + StructureItem, 3 + StructureNode, 4 + StructureShell, 5 + Symbol, 6 + } from '@hey-api/codegen-core'; 7 + import { StructureModel } from '@hey-api/codegen-core'; 8 + 1 9 import { clientFolderAbsolutePath } from '~/generate/client'; 10 + import type { IR } from '~/ir/types'; 11 + import { 12 + OperationLocations, 13 + type OperationLocationStrategy, 14 + OperationPath, 15 + } from '~/openApi/shared/locations'; 2 16 import { getClientPlugin } from '~/plugins/@hey-api/client-core/utils'; 3 - import type { $ } from '~/ts-dsl'; 17 + import { 18 + createOperationComment, 19 + isOperationOptionsRequired, 20 + } from '~/plugins/shared/utils/operation'; 21 + import { $ } from '~/ts-dsl'; 22 + import { toCase } from '~/utils/naming'; 4 23 5 - import { SdkStructureModel } from '../model/structure'; 24 + import { createClientClass, createRegistryClass } from '../shared/class'; 25 + import { nuxtTypeComposable, nuxtTypeDefault } from '../shared/constants'; 26 + import { 27 + operationClassName, 28 + operationMethodName, 29 + operationParameters, 30 + operationStatements, 31 + } from '../shared/operation'; 6 32 import { createTypeOptions } from '../shared/typeOptions'; 7 33 import type { HeyApiSdkPlugin } from '../types'; 8 34 35 + interface OperationItem { 36 + operation: IR.OperationObject; 37 + path: ReadonlyArray<string | number>; 38 + tags: ReadonlyArray<string> | undefined; 39 + } 40 + 41 + const source = globalThis.Symbol('@hey-api/sdk'); 42 + 43 + function attachComment< 44 + T extends ReturnType<typeof $.var | typeof $.method>, 45 + >(args: { node: T; operation: IR.OperationObject }): T { 46 + const { node, operation } = args; 47 + return node.$if(createOperationComment(operation), (m, v) => m.doc(v)) as T; 48 + } 49 + 50 + function createFnSymbol( 51 + plugin: HeyApiSdkPlugin['Instance'], 52 + item: StructureItem & { data: OperationItem }, 53 + ): Symbol { 54 + const { operation, path, tags } = item.data; 55 + const name = item.location[item.location.length - 1]; 56 + return plugin.symbol( 57 + operationMethodName({ 58 + operation, 59 + plugin, 60 + value: name, 61 + }), 62 + { 63 + meta: { 64 + category: 'sdk', 65 + path, 66 + resource: 'operation', 67 + resourceId: operation.id, 68 + tags, 69 + tool: 'sdk', 70 + }, 71 + }, 72 + ); 73 + } 74 + 75 + function childToNode( 76 + resource: StructureNode, 77 + plugin: HeyApiSdkPlugin['Instance'], 78 + ): ReadonlyArray<ReturnType<typeof $.field | typeof $.getter>> { 79 + const refChild = plugin.referenceSymbol({ 80 + category: 'utility', 81 + resource: 'class', 82 + resourceId: resource.getPath().join('.'), 83 + tool: 'sdk', 84 + }); 85 + const memberNameStr = toCase(refChild.name, 'camelCase'); 86 + const memberName = plugin.symbol(memberNameStr); 87 + if (plugin.config.instance) { 88 + const privateName = plugin.symbol(`_${memberNameStr}`); 89 + return [ 90 + $.field(privateName, (f) => f.private().optional().type(refChild)), 91 + $.getter(memberName, (g) => 92 + g.returns(refChild).do( 93 + $('this') 94 + .attr(privateName) 95 + .nullishAssign( 96 + $.new(refChild).args( 97 + $.object().prop('client', $('this').attr('client')), 98 + ), 99 + ) 100 + .return(), 101 + ), 102 + ), 103 + ]; 104 + } 105 + if (plugin.isSymbolRegistered(refChild.id)) { 106 + return [$.field(memberName, (f) => f.static().assign($(refChild)))]; 107 + } 108 + return [ 109 + $.getter(memberName, (g) => g.public().static().do($.return(refChild))), 110 + ]; 111 + } 112 + 113 + function enrichRootClass(args: { 114 + dependencies: Array<ReturnType<typeof $.class>>; 115 + node: ReturnType<typeof $.class>; 116 + plugin: HeyApiSdkPlugin['Instance']; 117 + symbol: Symbol; 118 + }): void { 119 + const { dependencies, node, plugin, symbol } = args; 120 + const symbolClient = plugin.symbol('HeyApiClient', { 121 + meta: { 122 + category: 'utility', 123 + resource: 'class', 124 + resourceId: 'HeyApiClient', 125 + tool: 'sdk', 126 + }, 127 + }); 128 + dependencies.push(createClientClass({ plugin, symbol: symbolClient })); 129 + const symbolRegistry = plugin.symbol('HeyApiRegistry', { 130 + meta: { 131 + category: 'utility', 132 + resource: 'class', 133 + resourceId: 'HeyApiRegistry', 134 + tool: 'sdk', 135 + }, 136 + }); 137 + dependencies.push( 138 + createRegistryClass({ 139 + plugin, 140 + sdkSymbol: symbol, 141 + symbol: symbolRegistry, 142 + }), 143 + ); 144 + const isClientRequired = 145 + !plugin.config.client || !plugin.getSymbol({ category: 'client' }); 146 + const registry = plugin.symbol('__registry'); 147 + node.toAccessNode = (node, options) => { 148 + if (options.context) return; 149 + return $(node.name).attr(registry).attr('get').call(); 150 + }; 151 + node.do( 152 + $.field(registry, (f) => 153 + f 154 + .public() 155 + .static() 156 + .readonly() 157 + .assign($.new(symbolRegistry).generic(symbol)), 158 + ), 159 + $.newline(), 160 + $.init((i) => 161 + i 162 + .param('args', (p) => 163 + p.required(isClientRequired).type( 164 + $.type 165 + .object() 166 + .prop('client', (p) => 167 + p.required(isClientRequired).type( 168 + plugin.referenceSymbol({ 169 + category: 'external', 170 + resource: 'client.Client', 171 + }), 172 + ), 173 + ) 174 + .prop('key', (p) => p.optional().type('string')), 175 + ), 176 + ) 177 + .do( 178 + $('super').call('args'), 179 + $(symbol) 180 + .attr(registry) 181 + .attr('set') 182 + .call('this', $('args').attr('key').required(isClientRequired)), 183 + ), 184 + ), 185 + ); 186 + } 187 + 188 + function implementFn< 189 + T extends ReturnType<typeof $.func | typeof $.method>, 190 + >(args: { 191 + node: T; 192 + operation: IR.OperationObject; 193 + plugin: HeyApiSdkPlugin['Instance']; 194 + }): T { 195 + const { node, operation, plugin } = args; 196 + const client = getClientPlugin(plugin.context.config); 197 + const isNuxtClient = client.name === '@hey-api/client-nuxt'; 198 + const isRequiredOptions = isOperationOptionsRequired({ 199 + context: plugin.context, 200 + operation, 201 + }); 202 + const opParameters = operationParameters({ 203 + isRequiredOptions, 204 + operation, 205 + plugin, 206 + }); 207 + const statements = operationStatements({ 208 + isRequiredOptions, 209 + opParameters, 210 + operation, 211 + plugin, 212 + }); 213 + return node 214 + .$if( 215 + isNuxtClient, 216 + (m) => 217 + m 218 + .generic(nuxtTypeComposable, (t) => 219 + t 220 + .extends( 221 + plugin.referenceSymbol({ 222 + category: 'external', 223 + resource: 'client.Composable', 224 + }), 225 + ) 226 + .default($.type.literal('$fetch')), 227 + ) 228 + .generic(nuxtTypeDefault, (t) => 229 + t.$if( 230 + plugin.querySymbol({ 231 + category: 'type', 232 + resource: 'operation', 233 + resourceId: operation.id, 234 + role: 'response', 235 + }), 236 + (t, s) => t.extends(s).default(s), 237 + (t) => t.default('undefined'), 238 + ), 239 + ), 240 + (m) => 241 + m.generic('ThrowOnError', (t) => 242 + t 243 + .extends('boolean') 244 + .default( 245 + ('throwOnError' in client.config 246 + ? client.config.throwOnError 247 + : false) ?? false, 248 + ), 249 + ), 250 + ) 251 + .params(...opParameters.parameters) 252 + .do(...statements) as T; 253 + } 254 + 255 + /** 256 + * Converts this class group to a class node. 257 + */ 258 + function toNode( 259 + model: StructureNode, 260 + plugin: HeyApiSdkPlugin['Instance'], 261 + ): { 262 + dependencies?: Array<ReturnType<typeof $.class>>; 263 + nodes: ReadonlyArray<ReturnType<typeof $.class | typeof $.var>>; 264 + } { 265 + if (model.virtual) { 266 + const nodes: Array<ReturnType<typeof $.var>> = []; 267 + for (const item of model.itemsFrom<OperationItem>(source)) { 268 + const { operation } = item.data; 269 + let node = $.const(createFnSymbol(plugin, item)) 270 + .export() 271 + .assign( 272 + implementFn({ 273 + node: $.func(), 274 + operation, 275 + plugin, 276 + }), 277 + ); 278 + node = attachComment({ node, operation }); 279 + nodes.push(node); 280 + } 281 + return { nodes }; 282 + } 283 + 284 + if (!model.shell) { 285 + return { nodes: [] }; 286 + } 287 + 288 + const nodes: Array<ReturnType<typeof $.class>> = []; 289 + 290 + const client = getClientPlugin(plugin.context.config); 291 + const isAngularClient = client.name === '@hey-api/client-angular'; 292 + 293 + const shell = model.shell.define(model); 294 + const node = shell.node as ReturnType<typeof $.class>; 295 + 296 + let index = 0; 297 + for (const item of model.itemsFrom<OperationItem>(source)) { 298 + const { operation } = item.data; 299 + if (index > 0 || node.hasBody) node.newline(); 300 + node.do( 301 + implementFn({ 302 + node: $.method(createFnSymbol(plugin, item), (m) => 303 + attachComment({ 304 + node: m, 305 + operation, 306 + }) 307 + .public() 308 + .static(!isAngularClient && !plugin.config.instance), 309 + ), 310 + operation, 311 + plugin, 312 + }), 313 + ); 314 + index += 1; 315 + } 316 + 317 + for (const child of model.children.values()) { 318 + if (node.hasBody) node.newline(); 319 + node.do(...childToNode(child, plugin)); 320 + } 321 + 322 + nodes.push(node); 323 + 324 + return { 325 + dependencies: shell.dependencies as Array<ReturnType<typeof $.class>>, 326 + nodes, 327 + }; 328 + } 329 + 330 + function createShell(plugin: HeyApiSdkPlugin['Instance']): StructureShell { 331 + const client = getClientPlugin(plugin.context.config); 332 + const isAngularClient = client.name === '@hey-api/client-angular'; 333 + return { 334 + define: (node) => { 335 + const symbol = plugin.symbol( 336 + operationClassName({ plugin, value: node.name }), 337 + { 338 + meta: { 339 + category: 'utility', 340 + resource: 'class', 341 + resourceId: node.getPath().join('.'), 342 + tool: 'sdk', 343 + }, 344 + }, 345 + ); 346 + const c = $.class(symbol) 347 + .export() 348 + .$if(plugin.config.instance, (c) => 349 + c.extends( 350 + plugin.referenceSymbol({ 351 + category: 'utility', 352 + resource: 'class', 353 + resourceId: 'HeyApiClient', 354 + tool: 'sdk', 355 + }), 356 + ), 357 + ) 358 + .$if(isAngularClient && node.isRoot, (c) => 359 + c.decorator( 360 + plugin.referenceSymbol({ 361 + category: 'external', 362 + resource: '@angular/core.Injectable', 363 + }), 364 + $.object().prop('providedIn', $.literal('root')), 365 + ), 366 + ); 367 + 368 + const dependencies: Array<ReturnType<typeof $.class>> = []; 369 + 370 + if (node.isRoot && plugin.config.instance) { 371 + enrichRootClass({ 372 + dependencies, 373 + node: c, 374 + plugin, 375 + symbol, 376 + }); 377 + } 378 + 379 + return { dependencies, node: c }; 380 + }, 381 + }; 382 + } 383 + 384 + function resolveLocationStrategy( 385 + plugin: HeyApiSdkPlugin['Instance'], 386 + ): OperationLocationStrategy { 387 + const shell = createShell(plugin); 388 + const path = 389 + plugin.config.classStructure === 'auto' 390 + ? OperationPath.fromOperationId() 391 + : OperationPath.id(); 392 + 393 + if (!plugin.config.asClass) { 394 + return OperationLocations.flat(); 395 + } 396 + 397 + if (plugin.config.instance) { 398 + return OperationLocations.single({ 399 + path, 400 + root: plugin.config.instance, 401 + shell, 402 + }); 403 + } 404 + 405 + return OperationLocations.byTags({ 406 + fallback: 'default', 407 + path, 408 + shell, 409 + }); 410 + } 411 + 9 412 export const handlerV1: HeyApiSdkPlugin['Handler'] = ({ plugin }) => { 10 413 const clientModule = clientFolderAbsolutePath(plugin.context.config); 11 414 const client = getClientPlugin(plugin.context.config); ··· 59 462 60 463 createTypeOptions({ plugin }); 61 464 62 - const structure = plugin.config.asClass 63 - ? new SdkStructureModel(plugin.config.instance) 64 - : new SdkStructureModel('', { flat: true }); 465 + const structure = new StructureModel(); 466 + const locationStrategy = resolveLocationStrategy(plugin); 65 467 66 468 plugin.forEach( 67 469 'operation', 68 470 (event) => { 69 - structure.insert( 70 - { 471 + structure.insert({ 472 + data: { 71 473 operation: event.operation, 72 474 path: event._path, 73 475 tags: event.tags, 74 - }, 75 - plugin, 76 - ); 476 + } satisfies OperationItem, 477 + // TODO: expose this logic 478 + locations: locationStrategy(event.operation), 479 + source, 480 + }); 77 481 }, 78 482 { order: 'declarations' }, 79 483 ); ··· 81 485 const allDependencies: Array<ReturnType<typeof $.class>> = []; 82 486 const allNodes: Array<ReturnType<typeof $.class | typeof $.var>> = []; 83 487 84 - for (const model of structure.walk()) { 85 - const { dependencies, nodes } = model.toNode(plugin); 86 - allDependencies.push(...dependencies); 488 + for (const node of structure.walk()) { 489 + const { dependencies, nodes } = toNode(node, plugin); 490 + allDependencies.push(...(dependencies ?? [])); 87 491 allNodes.push(...nodes); 88 492 } 89 493
+17 -21
packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts
··· 3 3 4 4 import { createOperationKey, operationResponsesMap } from '~/ir/operation'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import { $ } from '~/ts-dsl'; 7 + import { applyNaming } from '~/utils/naming'; 8 8 import { refToName } from '~/utils/ref'; 9 9 10 10 import type { HeyApiTransformersPlugin } from './types'; ··· 62 62 const symbol = 63 63 plugin.getSymbol(query) ?? 64 64 plugin.symbol( 65 - buildName({ 66 - config: { 67 - case: 'camelCase', 68 - name: '{{name}}SchemaResponseTransformer', 69 - }, 70 - name: refToName(schema.$ref), 65 + applyNaming(refToName(schema.$ref), { 66 + case: 'camelCase', 67 + name: '{{name}}SchemaResponseTransformer', 71 68 }), 72 69 { 73 70 meta: query, ··· 311 308 schema: response, 312 309 }); 313 310 if (!nodes.length) return; 314 - const symbol = plugin.registerSymbol({ 315 - meta: { 316 - category: 'transform', 317 - resource: 'operation', 318 - resourceId: operation.id, 319 - role: 'response', 311 + const symbol = plugin.symbol( 312 + applyNaming(operation.id, { 313 + case: 'camelCase', 314 + name: '{{name}}ResponseTransformer', 315 + }), 316 + { 317 + meta: { 318 + category: 'transform', 319 + resource: 'operation', 320 + resourceId: operation.id, 321 + role: 'response', 322 + }, 320 323 }, 321 - name: buildName({ 322 - config: { 323 - case: 'camelCase', 324 - name: '{{name}}ResponseTransformer', 325 - }, 326 - name: operation.id, 327 - }), 328 - }); 324 + ); 329 325 const value = $.const(symbol) 330 326 .export() 331 327 .assign(
+3 -6
packages/openapi-ts/src/plugins/@hey-api/typescript/shared/clientOptions.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 - import { buildName } from '~/openApi/shared/utils/name'; 3 2 import { 4 3 getClientBaseUrlKey, 5 4 getClientPlugin, 6 5 } from '~/plugins/@hey-api/client-core/utils'; 7 6 import type { TypeTsDsl } from '~/ts-dsl'; 8 7 import { $ } from '~/ts-dsl'; 8 + import { applyNaming } from '~/utils/naming'; 9 9 import { parseUrl } from '~/utils/url'; 10 10 11 11 import type { HeyApiTypeScriptPlugin } from '../types'; ··· 50 50 } 51 51 52 52 const symbol = plugin.symbol( 53 - buildName({ 54 - config: { 55 - case: plugin.config.case, 56 - }, 57 - name: 'ClientOptions', 53 + applyNaming('ClientOptions', { 54 + case: plugin.config.case, 58 55 }), 59 56 { 60 57 meta: {
+49 -54
packages/openapi-ts/src/plugins/@hey-api/typescript/shared/export.ts
··· 1 1 import { fromRef } from '@hey-api/codegen-core'; 2 2 3 3 import type { IR } from '~/ir/types'; 4 - import { buildName } from '~/openApi/shared/utils/name'; 5 4 import { createSchemaComment } from '~/plugins/shared/utils/schema'; 6 5 import type { MaybeTsDsl, TypeTsDsl } from '~/ts-dsl'; 7 6 import { $, regexp } from '~/ts-dsl'; 7 + import { applyNaming, toCase } from '~/utils/naming'; 8 8 import { pathToJsonPointer, refToName } from '~/utils/ref'; 9 - import { toCase } from '~/utils/to-case'; 10 9 11 10 import type { HeyApiTypeScriptPlugin } from '../types'; 12 11 import type { IrSchemaToAstOptions } from './types'; ··· 106 105 ); 107 106 } 108 107 109 - const symbolObject = plugin.registerSymbol({ 110 - meta: { 111 - category: 'utility', 112 - path: fromRef(state.path), 113 - resource: 'definition', 114 - resourceId: $ref, 115 - tags: fromRef(state.tags), 116 - tool: 'typescript', 108 + const symbolObject = plugin.symbol( 109 + applyNaming(refToName($ref), plugin.config.definitions), 110 + { 111 + meta: { 112 + category: 'utility', 113 + path: fromRef(state.path), 114 + resource: 'definition', 115 + resourceId: $ref, 116 + tags: fromRef(state.tags), 117 + tool: 'typescript', 118 + }, 117 119 }, 118 - name: buildName({ 119 - config: plugin.config.definitions, 120 - name: refToName($ref), 121 - }), 122 - }); 120 + ); 123 121 const objectNode = $.const(symbolObject) 124 122 .export() 125 123 .$if(createSchemaComment(schema), (c, v) => c.doc(v)) ··· 134 132 ); 135 133 plugin.node(objectNode); 136 134 137 - const symbol = plugin.registerSymbol({ 138 - meta: { 139 - category: 'type', 140 - path: fromRef(state.path), 141 - resource: 'definition', 142 - resourceId: $ref, 143 - tags: fromRef(state.tags), 144 - tool: 'typescript', 135 + const symbol = plugin.symbol( 136 + applyNaming(refToName($ref), plugin.config.definitions), 137 + { 138 + meta: { 139 + category: 'type', 140 + path: fromRef(state.path), 141 + resource: 'definition', 142 + resourceId: $ref, 143 + tags: fromRef(state.tags), 144 + tool: 'typescript', 145 + }, 145 146 }, 146 - name: buildName({ 147 - config: plugin.config.definitions, 148 - name: refToName($ref), 149 - }), 150 - }); 147 + ); 151 148 const node = $.type 152 149 .alias(symbol) 153 150 .export() ··· 166 163 (type) => type !== 'number' && type !== 'string', 167 164 ); 168 165 if (shouldCreateTypeScriptEnum) { 169 - const symbol = plugin.registerSymbol({ 170 - meta: { 171 - category: 'type', 172 - path: fromRef(state.path), 173 - resource: 'definition', 174 - resourceId: $ref, 175 - tags: fromRef(state.tags), 176 - tool: 'typescript', 166 + const symbol = plugin.symbol( 167 + applyNaming(refToName($ref), plugin.config.definitions), 168 + { 169 + meta: { 170 + category: 'type', 171 + path: fromRef(state.path), 172 + resource: 'definition', 173 + resourceId: $ref, 174 + tags: fromRef(state.tags), 175 + tool: 'typescript', 176 + }, 177 177 }, 178 - name: buildName({ 179 - config: plugin.config.definitions, 180 - name: refToName($ref), 181 - }), 182 - }); 178 + ); 183 179 const enumNode = $.enum(symbol) 184 180 .export() 185 181 .$if(createSchemaComment(schema), (e, v) => e.doc(v)) ··· 197 193 } 198 194 } 199 195 200 - const symbol = plugin.registerSymbol({ 201 - meta: { 202 - category: 'type', 203 - path: fromRef(state.path), 204 - resource: 'definition', 205 - resourceId: $ref, 206 - tags: fromRef(state.tags), 207 - tool: 'typescript', 196 + const symbol = plugin.symbol( 197 + applyNaming(refToName($ref), plugin.config.definitions), 198 + { 199 + meta: { 200 + category: 'type', 201 + path: fromRef(state.path), 202 + resource: 'definition', 203 + resourceId: $ref, 204 + tags: fromRef(state.tags), 205 + tool: 'typescript', 206 + }, 208 207 }, 209 - name: buildName({ 210 - config: plugin.config.definitions, 211 - name: refToName($ref), 212 - }), 213 - }); 208 + ); 214 209 const node = $.type 215 210 .alias(symbol) 216 211 .export()
+72 -77
packages/openapi-ts/src/plugins/@hey-api/typescript/shared/operation.ts
··· 3 3 import { operationResponsesMap } from '~/ir/operation'; 4 4 import { deduplicateSchema } from '~/ir/schema'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import { $ } from '~/ts-dsl'; 7 + import { applyNaming } from '~/utils/naming'; 8 8 9 9 import { irSchemaToAst } from '../v1/plugin'; 10 10 import type { IrSchemaToAstOptions } from './types'; ··· 122 122 123 123 data.required = dataRequired; 124 124 125 - const symbol = plugin.registerSymbol({ 126 - meta: { 127 - category: 'type', 128 - path: fromRef(state.path), 129 - resource: 'operation', 130 - resourceId: operation.id, 131 - role: 'data', 132 - tags: fromRef(state.tags), 133 - tool: 'typescript', 125 + const symbol = plugin.symbol( 126 + applyNaming(operation.id, plugin.config.requests), 127 + { 128 + meta: { 129 + category: 'type', 130 + path: fromRef(state.path), 131 + resource: 'operation', 132 + resourceId: operation.id, 133 + role: 'data', 134 + tags: fromRef(state.tags), 135 + tool: 'typescript', 136 + }, 134 137 }, 135 - name: buildName({ 136 - config: plugin.config.requests, 137 - name: operation.id, 138 - }), 139 - }); 138 + ); 140 139 const node = $.type 141 140 .alias(symbol) 142 141 .export() ··· 163 162 operationResponsesMap(operation); 164 163 165 164 if (errors) { 166 - const symbolErrors = plugin.registerSymbol({ 167 - meta: { 168 - category: 'type', 169 - path: fromRef(state.path), 170 - resource: 'operation', 171 - resourceId: operation.id, 172 - role: 'errors', 173 - tags: fromRef(state.tags), 174 - tool: 'typescript', 165 + const symbolErrors = plugin.symbol( 166 + applyNaming(operation.id, plugin.config.errors), 167 + { 168 + meta: { 169 + category: 'type', 170 + path: fromRef(state.path), 171 + resource: 'operation', 172 + resourceId: operation.id, 173 + role: 'errors', 174 + tags: fromRef(state.tags), 175 + tool: 'typescript', 176 + }, 175 177 }, 176 - name: buildName({ 177 - config: plugin.config.errors, 178 - name: operation.id, 179 - }), 180 - }); 178 + ); 181 179 const node = $.type 182 180 .alias(symbolErrors) 183 181 .export() ··· 191 189 plugin.node(node); 192 190 193 191 if (error) { 194 - const symbol = plugin.registerSymbol({ 195 - meta: { 196 - category: 'type', 197 - path: fromRef(state.path), 198 - resource: 'operation', 199 - resourceId: operation.id, 200 - role: 'error', 201 - tags: fromRef(state.tags), 202 - tool: 'typescript', 192 + const symbol = plugin.symbol( 193 + applyNaming(operation.id, { 194 + case: plugin.config.errors.case, 195 + name: plugin.config.errors.error, 196 + }), 197 + { 198 + meta: { 199 + category: 'type', 200 + path: fromRef(state.path), 201 + resource: 'operation', 202 + resourceId: operation.id, 203 + role: 'error', 204 + tags: fromRef(state.tags), 205 + tool: 'typescript', 206 + }, 203 207 }, 204 - name: buildName({ 205 - config: { 206 - case: plugin.config.errors.case, 207 - name: plugin.config.errors.error, 208 - }, 209 - name: operation.id, 210 - }), 211 - }); 208 + ); 212 209 const node = $.type 213 210 .alias(symbol) 214 211 .export() ··· 218 215 } 219 216 220 217 if (responses) { 221 - const symbolResponses = plugin.registerSymbol({ 222 - meta: { 223 - category: 'type', 224 - path: fromRef(state.path), 225 - resource: 'operation', 226 - resourceId: operation.id, 227 - role: 'responses', 228 - tags: fromRef(state.tags), 229 - tool: 'typescript', 218 + const symbolResponses = plugin.symbol( 219 + applyNaming(operation.id, plugin.config.responses), 220 + { 221 + meta: { 222 + category: 'type', 223 + path: fromRef(state.path), 224 + resource: 'operation', 225 + resourceId: operation.id, 226 + role: 'responses', 227 + tags: fromRef(state.tags), 228 + tool: 'typescript', 229 + }, 230 230 }, 231 - name: buildName({ 232 - config: plugin.config.responses, 233 - name: operation.id, 234 - }), 235 - }); 231 + ); 236 232 const node = $.type 237 233 .alias(symbolResponses) 238 234 .export() ··· 246 242 plugin.node(node); 247 243 248 244 if (response) { 249 - const symbol = plugin.registerSymbol({ 250 - meta: { 251 - category: 'type', 252 - path: fromRef(state.path), 253 - resource: 'operation', 254 - resourceId: operation.id, 255 - role: 'response', 256 - tags: fromRef(state.tags), 257 - tool: 'typescript', 245 + const symbol = plugin.symbol( 246 + applyNaming(operation.id, { 247 + case: plugin.config.responses.case, 248 + name: plugin.config.responses.response, 249 + }), 250 + { 251 + meta: { 252 + category: 'type', 253 + path: fromRef(state.path), 254 + resource: 'operation', 255 + resourceId: operation.id, 256 + role: 'response', 257 + tags: fromRef(state.tags), 258 + tool: 'typescript', 259 + }, 258 260 }, 259 - name: buildName({ 260 - config: { 261 - case: plugin.config.responses.case, 262 - name: plugin.config.responses.response, 263 - }, 264 - name: operation.id, 265 - }), 266 - }); 261 + ); 267 262 const node = $.type 268 263 .alias(symbol) 269 264 .export()
+30 -32
packages/openapi-ts/src/plugins/@hey-api/typescript/shared/webhook.ts
··· 2 2 import { fromRef } from '@hey-api/codegen-core'; 3 3 4 4 import type { IR } from '~/ir/types'; 5 - import { buildName } from '~/openApi/shared/utils/name'; 6 5 import { createSchemaComment } from '~/plugins/shared/utils/schema'; 7 6 import { $ } from '~/ts-dsl'; 7 + import { applyNaming } from '~/utils/naming'; 8 8 9 9 import { irSchemaToAst } from '../v1/plugin'; 10 10 import type { IrSchemaToAstOptions } from './types'; ··· 26 26 } 27 27 28 28 if (operation.body) { 29 - const symbolWebhookPayload = plugin.registerSymbol({ 30 - meta: { 31 - category: 'type', 32 - path: fromRef(state.path), 33 - resource: 'webhook', 34 - resourceId: operation.id, 35 - role: 'data', 36 - tags: fromRef(state.tags), 37 - tool: 'typescript', 38 - }, 39 - name: buildName({ 40 - config: { 41 - case: plugin.config.webhooks.case, 42 - name: plugin.config.webhooks.payload, 43 - }, 44 - name: operation.id, 29 + const symbolWebhookPayload = plugin.symbol( 30 + applyNaming(operation.id, { 31 + case: plugin.config.webhooks.case, 32 + name: plugin.config.webhooks.payload, 45 33 }), 46 - }); 34 + { 35 + meta: { 36 + category: 'type', 37 + path: fromRef(state.path), 38 + resource: 'webhook', 39 + resourceId: operation.id, 40 + role: 'data', 41 + tags: fromRef(state.tags), 42 + tool: 'typescript', 43 + }, 44 + }, 45 + ); 47 46 const node = $.type 48 47 .alias(symbolWebhookPayload) 49 48 .export() ··· 74 73 75 74 data.required = dataRequired; 76 75 77 - const symbolWebhookRequest = plugin.registerSymbol({ 78 - meta: { 79 - category: 'type', 80 - path: fromRef(state.path), 81 - resource: 'webhook', 82 - resourceId: operation.id, 83 - role: 'data', 84 - tags: fromRef(state.tags), 85 - tool: 'typescript', 76 + const symbolWebhookRequest = plugin.symbol( 77 + applyNaming(operation.id, plugin.config.webhooks), 78 + { 79 + meta: { 80 + category: 'type', 81 + path: fromRef(state.path), 82 + resource: 'webhook', 83 + resourceId: operation.id, 84 + role: 'data', 85 + tags: fromRef(state.tags), 86 + tool: 'typescript', 87 + }, 86 88 }, 87 - name: buildName({ 88 - config: plugin.config.webhooks, 89 - name: operation.id, 90 - }), 91 - }); 89 + ); 92 90 const node = $.type 93 91 .alias(symbolWebhookRequest) 94 92 .export()
+36 -36
packages/openapi-ts/src/plugins/@hey-api/typescript/types.d.ts
··· 1 1 import type { DefinePlugin, Plugin } from '~/plugins'; 2 - import type { StringCase, StringName } from '~/types/case'; 2 + import type { Casing, NameTransformer } from '~/utils/naming'; 3 3 4 4 import type { IApi } from './api'; 5 5 ··· 12 12 * 13 13 * @default 'PascalCase' 14 14 */ 15 - case?: Exclude<StringCase, 'SCREAMING_SNAKE_CASE'>; 15 + case?: Exclude<Casing, 'SCREAMING_SNAKE_CASE'>; 16 16 /** 17 17 * Configuration for reusable schema definitions. 18 18 * ··· 26 26 * @default '{{name}}' 27 27 */ 28 28 definitions?: 29 - | StringName 29 + | NameTransformer 30 30 | { 31 31 /** 32 32 * The casing convention to use for generated definition names. 33 33 * 34 34 * @default 'PascalCase' 35 35 */ 36 - case?: StringCase; 36 + case?: Casing; 37 37 /** 38 38 * Custom naming pattern for generated definition names. The name variable 39 39 * is obtained from the schema name. 40 40 * 41 41 * @default '{{name}}' 42 42 */ 43 - name?: StringName; 43 + name?: NameTransformer; 44 44 }; 45 45 /** 46 46 * By default, enums are emitted as types to preserve runtime-free output. ··· 60 60 * 61 61 * @default 'SCREAMING_SNAKE_CASE' 62 62 */ 63 - case?: StringCase; 63 + case?: Casing; 64 64 /** 65 65 * When generating enums as JavaScript objects, they'll contain a null 66 66 * value if they're nullable. This might be undesirable if you want to do ··· 101 101 * @default '{{name}}Errors' 102 102 */ 103 103 errors?: 104 - | StringName 104 + | NameTransformer 105 105 | { 106 106 /** 107 107 * The casing convention to use for generated error type names. 108 108 * 109 109 * @default 'PascalCase' 110 110 */ 111 - case?: StringCase; 111 + case?: Casing; 112 112 /** 113 113 * Custom naming pattern for generated error type names. The name 114 114 * variable is obtained from the operation name. 115 115 * 116 116 * @default '{{name}}Error' 117 117 */ 118 - error?: StringName; 118 + error?: NameTransformer; 119 119 /** 120 120 * Custom naming pattern for generated error type names. The name 121 121 * variable is obtained from the operation name. 122 122 * 123 123 * @default '{{name}}Errors' 124 124 */ 125 - name?: StringName; 125 + name?: NameTransformer; 126 126 }; 127 127 /** 128 128 * Should the exports from the generated files be re-exported in the index ··· 144 144 * @default '{{name}}Data' 145 145 */ 146 146 requests?: 147 - | StringName 147 + | NameTransformer 148 148 | { 149 149 /** 150 150 * The casing convention to use for generated request type names. 151 151 * 152 152 * @default 'PascalCase' 153 153 */ 154 - case?: StringCase; 154 + case?: Casing; 155 155 /** 156 156 * Custom naming pattern for generated request type names. The name 157 157 * variable is obtained from the operation name. 158 158 * 159 159 * @default '{{name}}Data' 160 160 */ 161 - name?: StringName; 161 + name?: NameTransformer; 162 162 }; 163 163 /** 164 164 * Configuration for response-specific types. ··· 172 172 * @default '{{name}}Responses' 173 173 */ 174 174 responses?: 175 - | StringName 175 + | NameTransformer 176 176 | { 177 177 /** 178 178 * The casing convention to use for generated response type names. 179 179 * 180 180 * @default 'PascalCase' 181 181 */ 182 - case?: StringCase; 182 + case?: Casing; 183 183 /** 184 184 * Custom naming pattern for generated response type names. The name 185 185 * variable is obtained from the operation name. 186 186 * 187 187 * @default '{{name}}Responses' 188 188 */ 189 - name?: StringName; 189 + name?: NameTransformer; 190 190 /** 191 191 * Custom naming pattern for generated response type names. The name 192 192 * variable is obtained from the operation name. 193 193 * 194 194 * @default '{{name}}Response' 195 195 */ 196 - response?: StringName; 196 + response?: NameTransformer; 197 197 }; 198 198 /** 199 199 * The top type to use for untyped or unspecified schema values. ··· 217 217 * @default '{{name}}WebhookRequest' 218 218 */ 219 219 webhooks?: 220 - | StringName 220 + | NameTransformer 221 221 | { 222 222 /** 223 223 * The casing convention to use for generated webhook type names. 224 224 * 225 225 * @default 'PascalCase' 226 226 */ 227 - case?: StringCase; 227 + case?: Casing; 228 228 /** 229 229 * Custom naming pattern for generated webhook type names. The name 230 230 * variable is obtained from the webhook key. 231 231 * 232 232 * @default '{{name}}WebhookRequest' 233 233 */ 234 - name?: StringName; 234 + name?: NameTransformer; 235 235 /** 236 236 * Custom naming pattern for generated webhook type names. The name 237 237 * variable is obtained from the webhook key. 238 238 * 239 239 * @default '{{name}}WebhookPayload' 240 240 */ 241 - payload?: StringName; 241 + payload?: NameTransformer; 242 242 }; 243 243 }; 244 244 ··· 249 249 * 250 250 * @default 'PascalCase' 251 251 */ 252 - case: Exclude<StringCase, 'SCREAMING_SNAKE_CASE'>; 252 + case: Exclude<Casing, 'SCREAMING_SNAKE_CASE'>; 253 253 /** 254 254 * Configuration for reusable schema definitions. 255 255 * ··· 262 262 * 263 263 * @default 'PascalCase' 264 264 */ 265 - case: StringCase; 265 + case: Casing; 266 266 /** 267 267 * Custom naming pattern for generated definition names. The name variable 268 268 * is obtained from the schema name. 269 269 * 270 270 * @default '{{name}}' 271 271 */ 272 - name: StringName; 272 + name: NameTransformer; 273 273 }; 274 274 /** 275 275 * By default, enums are emitted as types to preserve runtime-free output. ··· 284 284 * 285 285 * @default 'SCREAMING_SNAKE_CASE' 286 286 */ 287 - case: StringCase; 287 + case: Casing; 288 288 /** 289 289 * When generating enums as JavaScript objects, they'll contain a null 290 290 * value if they're nullable. This might be undesirable if you want to do ··· 328 328 * 329 329 * @default 'PascalCase' 330 330 */ 331 - case: StringCase; 331 + case: Casing; 332 332 /** 333 333 * Custom naming pattern for generated error type names. The name 334 334 * variable is obtained from the operation name. 335 335 * 336 336 * @default '{{name}}Error' 337 337 */ 338 - error: StringName; 338 + error: NameTransformer; 339 339 /** 340 340 * Custom naming pattern for generated error type names. The name 341 341 * variable is obtained from the operation name. 342 342 * 343 343 * @default '{{name}}Errors' 344 344 */ 345 - name: StringName; 345 + name: NameTransformer; 346 346 }; 347 347 /** 348 348 * Should the exports from the generated files be re-exported in the index ··· 363 363 * 364 364 * @default 'PascalCase' 365 365 */ 366 - case: StringCase; 366 + case: Casing; 367 367 /** 368 368 * Custom naming pattern for generated request type names. The name 369 369 * variable is obtained from the operation name. 370 370 * 371 371 * @default '{{name}}Data' 372 372 */ 373 - name: StringName; 373 + name: NameTransformer; 374 374 }; 375 375 /** 376 376 * Configuration for response-specific types. ··· 383 383 * 384 384 * @default 'PascalCase' 385 385 */ 386 - case: StringCase; 386 + case: Casing; 387 387 /** 388 388 * Custom naming pattern for generated response type names. The name 389 389 * variable is obtained from the operation name. 390 390 * 391 391 * @default '{{name}}Responses' 392 392 */ 393 - name: StringName; 393 + name: NameTransformer; 394 394 /** 395 395 * Custom naming pattern for generated response type names. The name 396 396 * variable is obtained from the operation name. 397 397 * 398 398 * @default '{{name}}Response' 399 399 */ 400 - response: StringName; 400 + response: NameTransformer; 401 401 }; 402 402 /** 403 403 * The top type to use for untyped or unspecified schema values. ··· 416 416 * 417 417 * @default 'PascalCase' 418 418 */ 419 - case: StringCase; 419 + case: Casing; 420 420 /** 421 421 * Custom naming pattern for generated webhook type names. The name 422 422 * variable is obtained from the webhook key. 423 423 * 424 424 * @default '{{name}}WebhookRequest' 425 425 */ 426 - name: StringName; 426 + name: NameTransformer; 427 427 /** 428 428 * Custom naming pattern for generated webhook type names. The name 429 429 * variable is obtained from the webhook key. 430 430 * 431 431 * @default '{{name}}WebhookPayload' 432 432 */ 433 - payload: StringName; 433 + payload: NameTransformer; 434 434 }; 435 435 }; 436 436
+3 -6
packages/openapi-ts/src/plugins/@hey-api/typescript/v1/plugin.ts
··· 3 3 4 4 import { deduplicateSchema } from '~/ir/schema'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import type { SchemaWithType } from '~/plugins'; 8 7 import type { MaybeTsDsl, TypeTsDsl } from '~/ts-dsl'; 9 8 import { $ } from '~/ts-dsl'; 9 + import { applyNaming } from '~/utils/naming'; 10 10 11 11 import { createClientOptions } from '../shared/clientOptions'; 12 12 import { exportType } from '../shared/export'; ··· 175 175 176 176 if (webhooks.length > 0) { 177 177 const symbol = plugin.symbol( 178 - buildName({ 179 - config: { 180 - case: plugin.config.case, 181 - }, 182 - name: 'Webhooks', 178 + applyNaming('Webhooks', { 179 + case: plugin.config.case, 183 180 }), 184 181 { 185 182 meta: {
+8 -7
packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/string.ts
··· 3 3 import type { SchemaWithType } from '~/plugins'; 4 4 import type { TypeTsDsl } from '~/ts-dsl'; 5 5 import { $ } from '~/ts-dsl'; 6 - import { toCase } from '~/utils/to-case'; 6 + import { toCase } from '~/utils/naming'; 7 7 8 8 import type { IrSchemaToAstOptions } from '../../shared/types'; 9 9 ··· 49 49 }; 50 50 51 51 if (!plugin.getSymbol(queryTypeId)) { 52 - const symbolTypeId = plugin.registerSymbol({ 52 + const symbolTypeId = plugin.symbol('TypeID', { 53 53 meta: queryTypeId, 54 - name: 'TypeID', 55 54 }); 56 55 const nodeTypeId = $.type 57 56 .alias(symbolTypeId) ··· 64 63 } 65 64 66 65 const symbolTypeId = plugin.referenceSymbol(queryTypeId); 67 - const symbolTypeName = plugin.registerSymbol({ 68 - meta: query, 69 - name: toCase(`${type}_id`, plugin.config.case), 70 - }); 66 + const symbolTypeName = plugin.symbol( 67 + toCase(`${type}_id`, plugin.config.case), 68 + { 69 + meta: query, 70 + }, 71 + ); 71 72 const node = $.type 72 73 .alias(symbolTypeName) 73 74 .export()
+4 -7
packages/openapi-ts/src/plugins/@pinia/colada/mutationOptions.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 - import { buildName } from '~/openApi/shared/utils/name'; 3 2 import { getClientPlugin } from '~/plugins/@hey-api/client-core/utils'; 4 3 import { createOperationComment } from '~/plugins/shared/utils/operation'; 5 4 import { $ } from '~/ts-dsl'; 5 + import { applyNaming } from '~/utils/naming'; 6 6 7 7 import { handleMeta } from './meta'; 8 8 import type { PiniaColadaPlugin } from './types'; ··· 75 75 .$if(handleMeta(plugin, operation, 'mutationOptions'), (o, v) => 76 76 o.prop('meta', v), 77 77 ); 78 - const symbolMutationOptions = plugin.registerSymbol({ 79 - name: buildName({ 80 - config: plugin.config.mutationOptions, 81 - name: operation.id, 82 - }), 83 - }); 78 + const symbolMutationOptions = plugin.symbol( 79 + applyNaming(operation.id, plugin.config.mutationOptions), 80 + ); 84 81 const statement = $.const(symbolMutationOptions) 85 82 .export() 86 83 .$if(plugin.config.comments && createOperationComment(operation), (c, v) =>
+14 -17
packages/openapi-ts/src/plugins/@pinia/colada/queryKey.ts
··· 3 3 import { clientFolderAbsolutePath } from '~/generate/client'; 4 4 import { hasOperationDataRequired } from '~/ir/operation'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import { 8 7 getClientBaseUrlKey, 9 8 getClientPlugin, 10 9 } from '~/plugins/@hey-api/client-core/utils'; 11 10 import { $ } from '~/ts-dsl'; 11 + import { applyNaming } from '~/utils/naming'; 12 12 13 13 import type { PiniaColadaPlugin } from './types'; 14 14 import { getPublicTypeData } from './utils'; ··· 20 20 }: { 21 21 plugin: PiniaColadaPlugin['Instance']; 22 22 }) => { 23 - const symbolCreateQueryKey = plugin.registerSymbol({ 24 - meta: { 25 - category: 'utility', 26 - resource: 'createQueryKey', 27 - tool: plugin.name, 28 - }, 29 - name: buildName({ 30 - config: { 31 - case: plugin.config.case, 32 - }, 33 - name: 'createQueryKey', 23 + const symbolCreateQueryKey = plugin.symbol( 24 + applyNaming('createQueryKey', { 25 + case: plugin.config.case, 34 26 }), 35 - }); 27 + { 28 + meta: { 29 + category: 'utility', 30 + resource: 'createQueryKey', 31 + tool: plugin.name, 32 + }, 33 + }, 34 + ); 36 35 const symbolQueryKeyType = plugin.referenceSymbol({ 37 36 category: 'type', 38 37 resource: 'QueryKey', ··· 57 56 }); 58 57 59 58 const clientModule = clientFolderAbsolutePath(plugin.context.config); 60 - const symbolSerializeQueryValue = plugin.registerSymbol({ 59 + const symbolSerializeQueryValue = plugin.symbol('serializeQueryKeyValue', { 61 60 external: clientModule, 62 61 meta: { 63 62 category: 'external', 64 63 resource: `${clientModule}.serializeQueryKeyValue`, 65 64 }, 66 - name: 'serializeQueryKeyValue', 67 65 }); 68 66 69 67 const fn = $.const(symbolCreateQueryKey).assign( ··· 169 167 resource: 'client-options', 170 168 tool: 'sdk', 171 169 }); 172 - const symbolQueryKeyType = plugin.registerSymbol({ 170 + const symbolQueryKeyType = plugin.symbol('QueryKey', { 173 171 meta: { 174 172 category: 'type', 175 173 resource: 'QueryKey', 176 174 tool: plugin.name, 177 175 }, 178 - name: 'QueryKey', 179 176 }); 180 177 const queryKeyType = $.type 181 178 .alias(symbolQueryKeyType)
+15 -19
packages/openapi-ts/src/plugins/@pinia/colada/queryOptions.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 - import { buildName } from '~/openApi/shared/utils/name'; 3 2 import { getClientPlugin } from '~/plugins/@hey-api/client-core/utils'; 4 3 import { 5 4 createOperationComment, ··· 7 6 isOperationOptionsRequired, 8 7 } from '~/plugins/shared/utils/operation'; 9 8 import { $ } from '~/ts-dsl'; 9 + import { applyNaming } from '~/utils/naming'; 10 10 11 11 import { handleMeta } from './meta'; 12 12 import { ··· 48 48 49 49 let keyExpression: ReturnType<typeof $.call>; 50 50 if (plugin.config.queryKeys.enabled) { 51 - const symbolQueryKey = plugin.registerSymbol({ 52 - name: buildName({ 53 - config: plugin.config.queryKeys, 54 - name: operation.id, 55 - }), 56 - }); 51 + const symbolQueryKey = plugin.symbol( 52 + applyNaming(operation.id, plugin.config.queryKeys), 53 + ); 57 54 const node = queryKeyStatement({ 58 55 operation, 59 56 plugin, ··· 128 125 o.prop('meta', v), 129 126 ); 130 127 131 - const symbolQueryOptionsFn = plugin.registerSymbol({ 132 - meta: { 133 - category: 'hook', 134 - resource: 'operation', 135 - resourceId: operation.id, 136 - role: 'queryOptions', 137 - tool: plugin.name, 128 + const symbolQueryOptionsFn = plugin.symbol( 129 + applyNaming(operation.id, plugin.config.queryOptions), 130 + { 131 + meta: { 132 + category: 'hook', 133 + resource: 'operation', 134 + resourceId: operation.id, 135 + role: 'queryOptions', 136 + tool: plugin.name, 137 + }, 138 138 }, 139 - name: buildName({ 140 - config: plugin.config.queryOptions, 141 - name: operation.id, 142 - }), 143 - }); 139 + ); 144 140 const symbolDefineQueryOptions = plugin.referenceSymbol({ 145 141 category: 'external', 146 142 resource: `${plugin.name}.defineQueryOptions`,
+18 -18
packages/openapi-ts/src/plugins/@pinia/colada/types.d.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 2 import type { DefinePlugin, Plugin } from '~/plugins'; 3 - import type { StringCase, StringName } from '~/types/case'; 3 + import type { Casing, NameTransformer } from '~/utils/naming'; 4 4 5 5 export type UserConfig = Plugin.Name<'@pinia/colada'> & 6 6 Plugin.Hooks & { ··· 9 9 * 10 10 * @default 'camelCase' 11 11 */ 12 - case?: StringCase; 12 + case?: Casing; 13 13 /** 14 14 * Add comments from SDK functions to the generated Pinia Colada code? 15 15 * ··· 42 42 */ 43 43 mutationOptions?: 44 44 | boolean 45 - | StringName 45 + | NameTransformer 46 46 | { 47 47 /** 48 48 * The casing convention to use for generated names. 49 49 * 50 50 * @default 'camelCase' 51 51 */ 52 - case?: StringCase; 52 + case?: Casing; 53 53 /** 54 54 * Whether to generate mutation options helpers. 55 55 * ··· 85 85 * 86 86 * @default '{{name}}Mutation' 87 87 */ 88 - name?: StringName; 88 + name?: NameTransformer; 89 89 }; 90 90 /** 91 91 * Configuration for generated query keys. ··· 101 101 */ 102 102 queryKeys?: 103 103 | boolean 104 - | StringName 104 + | NameTransformer 105 105 | { 106 106 /** 107 107 * The casing convention to use for generated names. 108 108 * 109 109 * @default 'camelCase' 110 110 */ 111 - case?: StringCase; 111 + case?: Casing; 112 112 /** 113 113 * Whether to generate query keys. 114 114 * ··· 121 121 * 122 122 * @default '{{name}}QueryKey' 123 123 */ 124 - name?: StringName; 124 + name?: NameTransformer; 125 125 /** 126 126 * Whether to include operation tags in query keys. 127 127 * This will make query keys larger but provides better cache invalidation capabilities. ··· 144 144 */ 145 145 queryOptions?: 146 146 | boolean 147 - | StringName 147 + | NameTransformer 148 148 | { 149 149 /** 150 150 * The casing convention to use for generated names. 151 151 * 152 152 * @default 'camelCase' 153 153 */ 154 - case?: StringCase; 154 + case?: Casing; 155 155 /** 156 156 * Whether to generate query options helpers. 157 157 * ··· 187 187 * 188 188 * @default '{{name}}Query' 189 189 */ 190 - name?: StringName; 190 + name?: NameTransformer; 191 191 }; 192 192 }; 193 193 ··· 198 198 * 199 199 * @default 'camelCase' 200 200 */ 201 - case: StringCase; 201 + case: Casing; 202 202 /** 203 203 * Add comments from SDK functions to the generated Pinia Colada code? 204 204 * ··· 220 220 * 221 221 * @default 'camelCase' 222 222 */ 223 - case: StringCase; 223 + case: Casing; 224 224 /** 225 225 * Whether to generate mutation options helpers. 226 226 * ··· 258 258 * 259 259 * @default '{{name}}Mutation' 260 260 */ 261 - name: StringName; 261 + name: NameTransformer; 262 262 }; 263 263 /** 264 264 * Resolved configuration for generated query keys. ··· 271 271 * 272 272 * @default 'camelCase' 273 273 */ 274 - case: StringCase; 274 + case: Casing; 275 275 /** 276 276 * Whether to generate query keys. 277 277 * ··· 284 284 * 285 285 * @default '{{name}}QueryKey' 286 286 */ 287 - name: StringName; 287 + name: NameTransformer; 288 288 /** 289 289 * Whether to include operation tags in query keys. 290 290 * This will make query keys larger but provides better cache invalidation capabilities. ··· 304 304 * 305 305 * @default 'camelCase' 306 306 */ 307 - case: StringCase; 307 + case: Casing; 308 308 /** 309 309 * Whether to generate query options helpers. 310 310 * ··· 342 342 * 343 343 * @default '{{name}}Query' 344 344 */ 345 - name: StringName; 345 + name: NameTransformer; 346 346 }; 347 347 }; 348 348
+28 -28
packages/openapi-ts/src/plugins/@tanstack/angular-query-experimental/types.d.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 2 import type { DefinePlugin, Plugin } from '~/plugins'; 3 - import type { StringCase, StringName } from '~/types/case'; 3 + import type { Casing, NameTransformer } from '~/utils/naming'; 4 4 5 5 export type UserConfig = Plugin.Name<'@tanstack/angular-query-experimental'> & 6 6 Plugin.Hooks & { ··· 9 9 * 10 10 * @default 'camelCase' 11 11 */ 12 - case?: StringCase; 12 + case?: Casing; 13 13 /** 14 14 * Add comments from SDK functions to the generated TanStack Query code? 15 15 * ··· 41 41 */ 42 42 infiniteQueryKeys?: 43 43 | boolean 44 - | StringName 44 + | NameTransformer 45 45 | { 46 46 /** 47 47 * The casing convention to use for generated names. 48 48 * 49 49 * @default 'camelCase' 50 50 */ 51 - case?: StringCase; 51 + case?: Casing; 52 52 /** 53 53 * Whether to generate infinite query key helpers. 54 54 * ··· 62 62 * @default '{{name}}InfiniteQueryKey' 63 63 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/infiniteQueryOptions 64 64 */ 65 - name?: StringName; 65 + name?: NameTransformer; 66 66 /** 67 67 * Whether to include operation tags in infinite query keys. 68 68 * This will make query keys larger but provides better cache invalidation capabilities. ··· 85 85 */ 86 86 infiniteQueryOptions?: 87 87 | boolean 88 - | StringName 88 + | NameTransformer 89 89 | { 90 90 /** 91 91 * The casing convention to use for generated names. 92 92 * 93 93 * @default 'camelCase' 94 94 */ 95 - case?: StringCase; 95 + case?: Casing; 96 96 /** 97 97 * Whether to generate infinite query options helpers. 98 98 * ··· 128 128 * @default '{{name}}InfiniteOptions' 129 129 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/infiniteQueryOptions 130 130 */ 131 - name?: StringName; 131 + name?: NameTransformer; 132 132 }; 133 133 /** 134 134 * Configuration for generated mutation options helpers. ··· 144 144 */ 145 145 mutationOptions?: 146 146 | boolean 147 - | StringName 147 + | NameTransformer 148 148 | { 149 149 /** 150 150 * The casing convention to use for generated names. 151 151 * 152 152 * @default 'camelCase' 153 153 */ 154 - case?: StringCase; 154 + case?: Casing; 155 155 /** 156 156 * Whether to generate mutation options helpers. 157 157 * ··· 187 187 * @default '{{name}}Mutation' 188 188 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/useMutation 189 189 */ 190 - name?: StringName; 190 + name?: NameTransformer; 191 191 }; 192 192 /** 193 193 * Configuration for generated query keys. ··· 203 203 */ 204 204 queryKeys?: 205 205 | boolean 206 - | StringName 206 + | NameTransformer 207 207 | { 208 208 /** 209 209 * The casing convention to use for generated names. 210 210 * 211 211 * @default 'camelCase' 212 212 */ 213 - case?: StringCase; 213 + case?: Casing; 214 214 /** 215 215 * Whether to generate query keys. 216 216 * ··· 224 224 * @default '{{name}}QueryKey' 225 225 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/queryKey 226 226 */ 227 - name?: StringName; 227 + name?: NameTransformer; 228 228 /** 229 229 * Whether to include operation tags in query keys. 230 230 * This will make query keys larger but provides better cache invalidation capabilities. ··· 247 247 */ 248 248 queryOptions?: 249 249 | boolean 250 - | StringName 250 + | NameTransformer 251 251 | { 252 252 /** 253 253 * The casing convention to use for generated names. 254 254 * 255 255 * @default 'camelCase' 256 256 */ 257 - case?: StringCase; 257 + case?: Casing; 258 258 /** 259 259 * Whether to generate query options helpers. 260 260 * ··· 296 296 * @default '{{name}}Options' 297 297 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/queryOptions 298 298 */ 299 - name?: StringName; 299 + name?: NameTransformer; 300 300 }; 301 301 }; 302 302 ··· 307 307 * 308 308 * @default 'camelCase' 309 309 */ 310 - case: StringCase; 310 + case: Casing; 311 311 /** 312 312 * Add comments from SDK functions to the generated TanStack Query code? 313 313 * ··· 331 331 * 332 332 * @default 'camelCase' 333 333 */ 334 - case: StringCase; 334 + case: Casing; 335 335 /** 336 336 * Whether to generate infinite query key helpers. 337 337 * ··· 345 345 * @default '{{name}}InfiniteQueryKey' 346 346 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/infiniteQueryOptions 347 347 */ 348 - name: StringName; 348 + name: NameTransformer; 349 349 /** 350 350 * Whether to include operation tags in infinite query keys. 351 351 * This will make query keys larger but provides better cache invalidation capabilities. ··· 365 365 * 366 366 * @default 'camelCase' 367 367 */ 368 - case: StringCase; 368 + case: Casing; 369 369 /** 370 370 * Whether to generate infinite query options helpers. 371 371 * ··· 401 401 * @default '{{name}}InfiniteOptions' 402 402 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/infiniteQueryOptions 403 403 */ 404 - name: StringName; 404 + name: NameTransformer; 405 405 }; 406 406 /** 407 407 * Resolved configuration for generated mutation options helpers. ··· 414 414 * 415 415 * @default 'camelCase' 416 416 */ 417 - case: StringCase; 417 + case: Casing; 418 418 /** 419 419 * Whether to generate mutation options helpers. 420 420 * ··· 450 450 * @default '{{name}}Mutation' 451 451 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/useMutation 452 452 */ 453 - name: StringName; 453 + name: NameTransformer; 454 454 }; 455 455 /** 456 456 * Resolved configuration for generated query keys. ··· 463 463 * 464 464 * @default 'camelCase' 465 465 */ 466 - case: StringCase; 466 + case: Casing; 467 467 /** 468 468 * Whether to generate query keys. 469 469 * ··· 477 477 * @default '{{name}}QueryKey' 478 478 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/queryKey 479 479 */ 480 - name: StringName; 480 + name: NameTransformer; 481 481 /** 482 482 * Whether to include operation tags in query keys. 483 483 * This will make query keys larger but provides better cache invalidation capabilities. ··· 497 497 * 498 498 * @default 'camelCase' 499 499 */ 500 - case: StringCase; 500 + case: Casing; 501 501 /** 502 502 * Whether to generate query options helpers. 503 503 * ··· 539 539 * @default '{{name}}Options' 540 540 * @see https://tanstack.com/query/v5/docs/framework/angular/reference/queryOptions 541 541 */ 542 - name: StringName; 542 + name: NameTransformer; 543 543 }; 544 544 }; 545 545
+13 -15
packages/openapi-ts/src/plugins/@tanstack/query-core/queryKey.ts
··· 3 3 4 4 import { hasOperationDataRequired } from '~/ir/operation'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import { getClientBaseUrlKey } from '~/plugins/@hey-api/client-core/utils'; 8 7 import type { TsDsl } from '~/ts-dsl'; 9 8 import { $ } from '~/ts-dsl'; 9 + import { applyNaming } from '~/utils/naming'; 10 10 11 11 import { useTypeData } from './shared/useType'; 12 12 import type { PluginInstance } from './types'; ··· 18 18 }: { 19 19 plugin: PluginInstance; 20 20 }) => { 21 - const symbolCreateQueryKey = plugin.registerSymbol({ 22 - meta: { 23 - category: 'utility', 24 - resource: 'createQueryKey', 25 - tool: plugin.name, 21 + const symbolCreateQueryKey = plugin.symbol( 22 + applyNaming('createQueryKey', { 23 + case: plugin.config.case, 24 + }), 25 + { 26 + meta: { 27 + category: 'utility', 28 + resource: 'createQueryKey', 29 + tool: plugin.name, 30 + }, 26 31 }, 27 - name: buildName({ 28 - config: { 29 - case: plugin.config.case, 30 - }, 31 - name: 'createQueryKey', 32 - }), 33 - }); 32 + ); 34 33 const symbolQueryKeyType = plugin.referenceSymbol({ 35 34 category: 'type', 36 35 resource: 'QueryKey', ··· 140 139 resource: 'client-options', 141 140 tool: 'sdk', 142 141 }); 143 - const symbolQueryKeyType = plugin.registerSymbol({ 142 + const symbolQueryKeyType = plugin.symbol('QueryKey', { 144 143 meta: { 145 144 category: 'type', 146 145 resource: 'QueryKey', 147 146 tool: plugin.name, 148 147 }, 149 - name: 'QueryKey', 150 148 }); 151 149 const queryKeyType = $.type 152 150 .alias(symbolQueryKeyType)
+18 -25
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/infiniteQueryOptions.ts
··· 2 2 3 3 import { operationPagination } from '~/ir/operation'; 4 4 import type { IR } from '~/ir/types'; 5 - import { buildName } from '~/openApi/shared/utils/name'; 6 5 import { 7 6 createOperationComment, 8 7 isOperationOptionsRequired, 9 8 } from '~/plugins/shared/utils/operation'; 10 9 import type { TsDsl } from '~/ts-dsl'; 11 10 import { $ } from '~/ts-dsl'; 11 + import { applyNaming } from '~/utils/naming'; 12 12 13 13 import { 14 14 createQueryKeyFunction, ··· 24 24 }: { 25 25 plugin: PluginInstance; 26 26 }) => { 27 - const symbolCreateInfiniteParams = plugin.registerSymbol({ 28 - meta: { 29 - category: 'utility', 30 - resource: 'createInfiniteParams', 31 - tool: plugin.name, 27 + const symbolCreateInfiniteParams = plugin.symbol( 28 + applyNaming('createInfiniteParams', { 29 + case: plugin.config.case, 30 + }), 31 + { 32 + meta: { 33 + category: 'utility', 34 + resource: 'createInfiniteParams', 35 + tool: plugin.name, 36 + }, 32 37 }, 33 - name: buildName({ 34 - config: { 35 - case: plugin.config.case, 36 - }, 37 - name: 'createInfiniteParams', 38 - }), 39 - }); 38 + ); 40 39 41 40 const fn = $.const(symbolCreateInfiniteParams).assign( 42 41 $.func() ··· 181 180 }, 182 181 }); 183 182 184 - const symbolInfiniteQueryKey = plugin.registerSymbol({ 185 - name: buildName({ 186 - config: plugin.config.infiniteQueryKeys, 187 - name: operation.id, 188 - }), 189 - }); 183 + const symbolInfiniteQueryKey = plugin.symbol( 184 + applyNaming(operation.id, plugin.config.infiniteQueryKeys), 185 + ); 190 186 const node = queryKeyStatement({ 191 187 isInfinite: true, 192 188 operation, ··· 251 247 ); 252 248 } 253 249 254 - const symbolInfiniteQueryOptionsFn = plugin.registerSymbol({ 255 - name: buildName({ 256 - config: plugin.config.infiniteQueryOptions, 257 - name: operation.id, 258 - }), 259 - }); 250 + const symbolInfiniteQueryOptionsFn = plugin.symbol( 251 + applyNaming(operation.id, plugin.config.infiniteQueryOptions), 252 + ); 260 253 const statement = $.const(symbolInfiniteQueryOptionsFn) 261 254 .export() 262 255 .$if(plugin.config.comments && createOperationComment(operation), (c, v) =>
+2 -5
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/mutationOptions.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 - import { buildName } from '~/openApi/shared/utils/name'; 3 2 import { createOperationComment } from '~/plugins/shared/utils/operation'; 4 3 import type { TsDsl } from '~/ts-dsl'; 5 4 import { $ } from '~/ts-dsl'; 5 + import { applyNaming } from '~/utils/naming'; 6 6 7 7 import { handleMeta } from '../shared/meta'; 8 8 import { useTypeData, useTypeError, useTypeResponse } from '../shared/useType'; ··· 58 58 59 59 const mutationOptionsFn = 'mutationOptions'; 60 60 const symbolMutationOptions = plugin.symbol( 61 - buildName({ 62 - config: plugin.config.mutationOptions, 63 - name: operation.id, 64 - }), 61 + applyNaming(operation.id, plugin.config.mutationOptions), 65 62 ); 66 63 const statement = $.const(symbolMutationOptions) 67 64 .export()
+15 -19
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 - import { buildName } from '~/openApi/shared/utils/name'; 3 2 import { 4 3 createOperationComment, 5 4 hasOperationSse, ··· 7 6 } from '~/plugins/shared/utils/operation'; 8 7 import type { TsDsl } from '~/ts-dsl'; 9 8 import { $ } from '~/ts-dsl'; 9 + import { applyNaming } from '~/utils/naming'; 10 10 11 11 import { 12 12 createQueryKeyFunction, ··· 51 51 resource: `${plugin.name}.queryOptions`, 52 52 }); 53 53 54 - const symbolQueryKey = plugin.registerSymbol({ 55 - name: buildName({ 56 - config: plugin.config.queryKeys, 57 - name: operation.id, 58 - }), 59 - }); 54 + const symbolQueryKey = plugin.symbol( 55 + applyNaming(operation.id, plugin.config.queryKeys), 56 + ); 60 57 const node = queryKeyStatement({ 61 58 isInfinite: false, 62 59 operation, ··· 110 107 o.prop('meta', v), 111 108 ); 112 109 113 - const symbolQueryOptionsFn = plugin.registerSymbol({ 114 - meta: { 115 - category: 'hook', 116 - resource: 'operation', 117 - resourceId: operation.id, 118 - role: 'queryOptions', 119 - tool: plugin.name, 110 + const symbolQueryOptionsFn = plugin.symbol( 111 + applyNaming(operation.id, plugin.config.queryOptions), 112 + { 113 + meta: { 114 + category: 'hook', 115 + resource: 'operation', 116 + resourceId: operation.id, 117 + role: 'queryOptions', 118 + tool: plugin.name, 119 + }, 120 120 }, 121 - name: buildName({ 122 - config: plugin.config.queryOptions, 123 - name: operation.id, 124 - }), 125 - }); 121 + ); 126 122 // TODO: add type error 127 123 // TODO: AxiosError<PutSubmissionMetaError> 128 124 const statement = $.const(symbolQueryOptionsFn)
+4 -7
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/useQuery.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 - import { buildName } from '~/openApi/shared/utils/name'; 3 2 import { 4 3 createOperationComment, 5 4 hasOperationSse, 6 5 isOperationOptionsRequired, 7 6 } from '~/plugins/shared/utils/operation'; 8 7 import { $ } from '~/ts-dsl'; 8 + import { applyNaming } from '~/utils/naming'; 9 9 10 10 import { useTypeData } from '../shared/useType'; 11 11 import type { PluginInstance } from '../types'; ··· 27 27 return; 28 28 } 29 29 30 - const symbolUseQueryFn = plugin.registerSymbol({ 31 - name: buildName({ 32 - config: plugin.config.useQuery, 33 - name: operation.id, 34 - }), 35 - }); 30 + const symbolUseQueryFn = plugin.symbol( 31 + applyNaming(operation.id, plugin.config.useQuery), 32 + ); 36 33 37 34 const symbolUseQuery = plugin.referenceSymbol({ 38 35 category: 'external',
+33 -33
packages/openapi-ts/src/plugins/@tanstack/react-query/types.d.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 2 import type { DefinePlugin, Plugin } from '~/plugins'; 3 - import type { StringCase, StringName } from '~/types/case'; 3 + import type { Casing, NameTransformer } from '~/utils/naming'; 4 4 5 5 export type UserConfig = Plugin.Name<'@tanstack/react-query'> & 6 6 Plugin.Hooks & { ··· 9 9 * 10 10 * @default 'camelCase' 11 11 */ 12 - case?: StringCase; 12 + case?: Casing; 13 13 /** 14 14 * Add comments from SDK functions to the generated TanStack Query code? 15 15 * ··· 42 42 */ 43 43 infiniteQueryKeys?: 44 44 | boolean 45 - | StringName 45 + | NameTransformer 46 46 | { 47 47 /** 48 48 * The casing convention to use for generated names. 49 49 * 50 50 * @default 'camelCase' 51 51 */ 52 - case?: StringCase; 52 + case?: Casing; 53 53 /** 54 54 * Whether to generate infinite query key helpers. 55 55 * ··· 64 64 * 65 65 * @default '{{name}}InfiniteQueryKey' 66 66 */ 67 - name?: StringName; 67 + name?: NameTransformer; 68 68 /** 69 69 * Whether to include operation tags in infinite query keys. 70 70 * This will make query keys larger but provides better cache invalidation capabilities. ··· 87 87 */ 88 88 infiniteQueryOptions?: 89 89 | boolean 90 - | StringName 90 + | NameTransformer 91 91 | { 92 92 /** 93 93 * The casing convention to use for generated names. 94 94 * 95 95 * @default 'camelCase' 96 96 */ 97 - case?: StringCase; 97 + case?: Casing; 98 98 /** 99 99 * Whether to generate infinite query options helpers. 100 100 * ··· 132 132 * 133 133 * @default '{{name}}InfiniteOptions' 134 134 */ 135 - name?: StringName; 135 + name?: NameTransformer; 136 136 }; 137 137 /** 138 138 * Configuration for generated mutation options helpers. ··· 148 148 */ 149 149 mutationOptions?: 150 150 | boolean 151 - | StringName 151 + | NameTransformer 152 152 | { 153 153 /** 154 154 * The casing convention to use for generated names. 155 155 * 156 156 * @default 'camelCase' 157 157 */ 158 - case?: StringCase; 158 + case?: Casing; 159 159 /** 160 160 * Whether to generate mutation options helpers. 161 161 * ··· 193 193 * 194 194 * @default '{{name}}Mutation' 195 195 */ 196 - name?: StringName; 196 + name?: NameTransformer; 197 197 }; 198 198 /** 199 199 * Configuration for generated query keys. ··· 209 209 */ 210 210 queryKeys?: 211 211 | boolean 212 - | StringName 212 + | NameTransformer 213 213 | { 214 214 /** 215 215 * The casing convention to use for generated names. 216 216 * 217 217 * @default 'camelCase' 218 218 */ 219 - case?: StringCase; 219 + case?: Casing; 220 220 /** 221 221 * Whether to generate query keys. 222 222 * ··· 231 231 * 232 232 * @default '{{name}}QueryKey' 233 233 */ 234 - name?: StringName; 234 + name?: NameTransformer; 235 235 /** 236 236 * Whether to include operation tags in query keys. 237 237 * This will make query keys larger but provides better cache invalidation capabilities. ··· 254 254 */ 255 255 queryOptions?: 256 256 | boolean 257 - | StringName 257 + | NameTransformer 258 258 | { 259 259 /** 260 260 * The casing convention to use for generated names. 261 261 * 262 262 * @default 'camelCase' 263 263 */ 264 - case?: StringCase; 264 + case?: Casing; 265 265 /** 266 266 * Whether to generate query options helpers. 267 267 * ··· 305 305 * 306 306 * @default '{{name}}Options' 307 307 */ 308 - name?: StringName; 308 + name?: NameTransformer; 309 309 }; 310 310 /** 311 311 * Configuration for generated `useQuery()` function helpers. ··· 321 321 */ 322 322 useQuery?: 323 323 | boolean 324 - | StringName 324 + | NameTransformer 325 325 | { 326 326 /** 327 327 * The casing convention to use for generated names. 328 328 * 329 329 * @default 'camelCase' 330 330 */ 331 - case?: StringCase; 331 + case?: Casing; 332 332 /** 333 333 * Whether to generate `useQuery()` function helpers. 334 334 * ··· 343 343 * 344 344 * @default 'use{{name}}Query' 345 345 */ 346 - name?: StringName; 346 + name?: NameTransformer; 347 347 }; 348 348 }; 349 349 ··· 354 354 * 355 355 * @default 'camelCase' 356 356 */ 357 - case: StringCase; 357 + case: Casing; 358 358 /** 359 359 * Add comments from SDK functions to the generated TanStack Query code? 360 360 * ··· 378 378 * 379 379 * @default 'camelCase' 380 380 */ 381 - case: StringCase; 381 + case: Casing; 382 382 /** 383 383 * Whether to generate infinite query key helpers. 384 384 * ··· 392 392 * 393 393 * @default '{{name}}InfiniteQueryKey' 394 394 */ 395 - name: StringName; 395 + name: NameTransformer; 396 396 /** 397 397 * Whether to include operation tags in infinite query keys. 398 398 * This will make query keys larger but provides better cache invalidation capabilities. ··· 412 412 * 413 413 * @default 'camelCase' 414 414 */ 415 - case: StringCase; 415 + case: Casing; 416 416 /** 417 417 * Whether to generate infinite query options helpers. 418 418 * ··· 449 449 * 450 450 * @default '{{name}}InfiniteOptions' 451 451 */ 452 - name: StringName; 452 + name: NameTransformer; 453 453 }; 454 454 /** 455 455 * Resolved configuration for generated mutation options helpers. ··· 462 462 * 463 463 * @default 'camelCase' 464 464 */ 465 - case: StringCase; 465 + case: Casing; 466 466 /** 467 467 * Whether to generate mutation options helpers. 468 468 * ··· 499 499 * 500 500 * @default '{{name}}Mutation' 501 501 */ 502 - name: StringName; 502 + name: NameTransformer; 503 503 }; 504 504 /** 505 505 * Resolved configuration for generated query keys. ··· 512 512 * 513 513 * @default 'camelCase' 514 514 */ 515 - case: StringCase; 515 + case: Casing; 516 516 /** 517 517 * Whether to generate query keys. 518 518 * ··· 526 526 * 527 527 * @default '{{name}}QueryKey' 528 528 */ 529 - name: StringName; 529 + name: NameTransformer; 530 530 /** 531 531 * Whether to include operation tags in query keys. 532 532 * This will make query keys larger but provides better cache invalidation capabilities. ··· 546 546 * 547 547 * @default 'camelCase' 548 548 */ 549 - case: StringCase; 549 + case: Casing; 550 550 /** 551 551 * Whether to generate query options helpers. 552 552 * ··· 589 589 * 590 590 * @default '{{name}}Options' 591 591 */ 592 - name: StringName; 592 + name: NameTransformer; 593 593 }; 594 594 /** 595 595 * Configuration for generated `useQuery()` function helpers. ··· 602 602 * 603 603 * @default 'camelCase' 604 604 */ 605 - case: StringCase; 605 + case: Casing; 606 606 /** 607 607 * Whether to generate `useQuery()` function helpers. 608 608 * ··· 617 617 * 618 618 * @default 'use{{name}}Query' 619 619 */ 620 - name: StringName; 620 + name: NameTransformer; 621 621 }; 622 622 }; 623 623
+28 -28
packages/openapi-ts/src/plugins/@tanstack/solid-query/types.d.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 2 import type { DefinePlugin, Plugin } from '~/plugins'; 3 - import type { StringCase, StringName } from '~/types/case'; 3 + import type { Casing, NameTransformer } from '~/utils/naming'; 4 4 5 5 export type UserConfig = Plugin.Name<'@tanstack/solid-query'> & 6 6 Plugin.Hooks & { ··· 9 9 * 10 10 * @default 'camelCase' 11 11 */ 12 - case?: StringCase; 12 + case?: Casing; 13 13 /** 14 14 * Add comments from SDK functions to the generated TanStack Query code? 15 15 * ··· 41 41 */ 42 42 infiniteQueryKeys?: 43 43 | boolean 44 - | StringName 44 + | NameTransformer 45 45 | { 46 46 /** 47 47 * The casing convention to use for generated names. 48 48 * 49 49 * @default 'camelCase' 50 50 */ 51 - case?: StringCase; 51 + case?: Casing; 52 52 /** 53 53 * Whether to generate infinite query key helpers. 54 54 * ··· 62 62 * @default '{{name}}InfiniteQueryKey' 63 63 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/createInfiniteQuery 64 64 */ 65 - name?: StringName; 65 + name?: NameTransformer; 66 66 /** 67 67 * Whether to include operation tags in infinite query keys. 68 68 * This will make query keys larger but provides better cache invalidation capabilities. ··· 85 85 */ 86 86 infiniteQueryOptions?: 87 87 | boolean 88 - | StringName 88 + | NameTransformer 89 89 | { 90 90 /** 91 91 * The casing convention to use for generated names. 92 92 * 93 93 * @default 'camelCase' 94 94 */ 95 - case?: StringCase; 95 + case?: Casing; 96 96 /** 97 97 * Whether to generate infinite query options helpers. 98 98 * ··· 129 129 * @default '{{name}}InfiniteOptions' 130 130 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/createInfiniteQuery 131 131 */ 132 - name?: StringName; 132 + name?: NameTransformer; 133 133 }; 134 134 /** 135 135 * Configuration for generated mutation options helpers. ··· 145 145 */ 146 146 mutationOptions?: 147 147 | boolean 148 - | StringName 148 + | NameTransformer 149 149 | { 150 150 /** 151 151 * The casing convention to use for generated names. 152 152 * 153 153 * @default 'camelCase' 154 154 */ 155 - case?: StringCase; 155 + case?: Casing; 156 156 /** 157 157 * Whether to generate mutation options helpers. 158 158 * ··· 188 188 * @default '{{name}}Mutation' 189 189 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/createMutation 190 190 */ 191 - name?: StringName; 191 + name?: NameTransformer; 192 192 }; 193 193 /** 194 194 * Configuration for generated query keys. ··· 204 204 */ 205 205 queryKeys?: 206 206 | boolean 207 - | StringName 207 + | NameTransformer 208 208 | { 209 209 /** 210 210 * The casing convention to use for generated names. 211 211 * 212 212 * @default 'camelCase' 213 213 */ 214 - case?: StringCase; 214 + case?: Casing; 215 215 /** 216 216 * Whether to generate query keys. 217 217 * ··· 225 225 * @default '{{name}}QueryKey' 226 226 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/queryKey 227 227 */ 228 - name?: StringName; 228 + name?: NameTransformer; 229 229 /** 230 230 * Whether to include operation tags in query keys. 231 231 * This will make query keys larger but provides better cache invalidation capabilities. ··· 248 248 */ 249 249 queryOptions?: 250 250 | boolean 251 - | StringName 251 + | NameTransformer 252 252 | { 253 253 /** 254 254 * The casing convention to use for generated names. 255 255 * 256 256 * @default 'camelCase' 257 257 */ 258 - case?: StringCase; 258 + case?: Casing; 259 259 /** 260 260 * Whether to generate query options helpers. 261 261 * ··· 297 297 * @default '{{name}}Options' 298 298 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/createQuery 299 299 */ 300 - name?: StringName; 300 + name?: NameTransformer; 301 301 }; 302 302 }; 303 303 ··· 308 308 * 309 309 * @default 'camelCase' 310 310 */ 311 - case: StringCase; 311 + case: Casing; 312 312 /** 313 313 * Add comments from SDK functions to the generated TanStack Query code? 314 314 * ··· 332 332 * 333 333 * @default 'camelCase' 334 334 */ 335 - case: StringCase; 335 + case: Casing; 336 336 /** 337 337 * Whether to generate infinite query key helpers. 338 338 * ··· 346 346 * @default '{{name}}InfiniteQueryKey' 347 347 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/createInfiniteQuery 348 348 */ 349 - name: StringName; 349 + name: NameTransformer; 350 350 /** 351 351 * Whether to include operation tags in infinite query keys. 352 352 * This will make query keys larger but provides better cache invalidation capabilities. ··· 366 366 * 367 367 * @default 'camelCase' 368 368 */ 369 - case: StringCase; 369 + case: Casing; 370 370 /** 371 371 * Whether to generate infinite query options helpers. 372 372 * ··· 402 402 * @default '{{name}}InfiniteOptions' 403 403 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/createInfiniteQuery 404 404 */ 405 - name: StringName; 405 + name: NameTransformer; 406 406 }; 407 407 /** 408 408 * Resolved configuration for generated mutation options helpers. ··· 415 415 * 416 416 * @default 'camelCase' 417 417 */ 418 - case: StringCase; 418 + case: Casing; 419 419 /** 420 420 * Whether to generate mutation options helpers. 421 421 * ··· 451 451 * @default '{{name}}Mutation' 452 452 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/createMutation 453 453 */ 454 - name: StringName; 454 + name: NameTransformer; 455 455 }; 456 456 /** 457 457 * Resolved configuration for generated query keys. ··· 464 464 * 465 465 * @default 'camelCase' 466 466 */ 467 - case: StringCase; 467 + case: Casing; 468 468 /** 469 469 * Whether to generate query keys. 470 470 * ··· 478 478 * @default '{{name}}QueryKey' 479 479 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/queryKey 480 480 */ 481 - name: StringName; 481 + name: NameTransformer; 482 482 /** 483 483 * Whether to include operation tags in query keys. 484 484 * This will make query keys larger but provides better cache invalidation capabilities. ··· 498 498 * 499 499 * @default 'camelCase' 500 500 */ 501 - case: StringCase; 501 + case: Casing; 502 502 /** 503 503 * Whether to generate query options helpers. 504 504 * ··· 540 540 * @default '{{name}}Options' 541 541 * @see https://tanstack.com/query/v5/docs/framework/solid/reference/createQuery 542 542 */ 543 - name: StringName; 543 + name: NameTransformer; 544 544 }; 545 545 }; 546 546
+28 -28
packages/openapi-ts/src/plugins/@tanstack/svelte-query/types.d.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 2 import type { DefinePlugin, Plugin } from '~/plugins'; 3 - import type { StringCase, StringName } from '~/types/case'; 3 + import type { Casing, NameTransformer } from '~/utils/naming'; 4 4 5 5 export type UserConfig = Plugin.Name<'@tanstack/svelte-query'> & 6 6 Plugin.Hooks & { ··· 9 9 * 10 10 * @default 'camelCase' 11 11 */ 12 - case?: StringCase; 12 + case?: Casing; 13 13 /** 14 14 * Add comments from SDK functions to the generated TanStack Query code? 15 15 * ··· 41 41 */ 42 42 infiniteQueryKeys?: 43 43 | boolean 44 - | StringName 44 + | NameTransformer 45 45 | { 46 46 /** 47 47 * The casing convention to use for generated names. 48 48 * 49 49 * @default 'camelCase' 50 50 */ 51 - case?: StringCase; 51 + case?: Casing; 52 52 /** 53 53 * Whether to generate infinite query key helpers. 54 54 * ··· 62 62 * @default '{{name}}InfiniteQueryKey' 63 63 * @see https://tanstack.com/query/v5/docs/framework/svelte/reference/functions/createinfinitequery 64 64 */ 65 - name?: StringName; 65 + name?: NameTransformer; 66 66 /** 67 67 * Whether to include operation tags in infinite query keys. 68 68 * This will make query keys larger but provides better cache invalidation capabilities. ··· 85 85 */ 86 86 infiniteQueryOptions?: 87 87 | boolean 88 - | StringName 88 + | NameTransformer 89 89 | { 90 90 /** 91 91 * The casing convention to use for generated names. 92 92 * 93 93 * @default 'camelCase' 94 94 */ 95 - case?: StringCase; 95 + case?: Casing; 96 96 /** 97 97 * Whether to generate infinite query options helpers. 98 98 * ··· 128 128 * @default '{{name}}InfiniteOptions' 129 129 * @see https://tanstack.com/query/v5/docs/framework/svelte/reference/functions/createinfinitequery 130 130 */ 131 - name?: StringName; 131 + name?: NameTransformer; 132 132 }; 133 133 /** 134 134 * Configuration for generated mutation options helpers. ··· 144 144 */ 145 145 mutationOptions?: 146 146 | boolean 147 - | StringName 147 + | NameTransformer 148 148 | { 149 149 /** 150 150 * The casing convention to use for generated names. 151 151 * 152 152 * @default 'camelCase' 153 153 */ 154 - case?: StringCase; 154 + case?: Casing; 155 155 /** 156 156 * Whether to generate mutation options helpers. 157 157 * ··· 187 187 * @default '{{name}}Mutation' 188 188 * @see https://tanstack.com/query/v5/docs/framework/svelte/reference/functions/createmutation 189 189 */ 190 - name?: StringName; 190 + name?: NameTransformer; 191 191 }; 192 192 /** 193 193 * Configuration for generated query keys. ··· 203 203 */ 204 204 queryKeys?: 205 205 | boolean 206 - | StringName 206 + | NameTransformer 207 207 | { 208 208 /** 209 209 * The casing convention to use for generated names. 210 210 * 211 211 * @default 'camelCase' 212 212 */ 213 - case?: StringCase; 213 + case?: Casing; 214 214 /** 215 215 * Whether to generate query keys. 216 216 * ··· 224 224 * @default '{{name}}QueryKey' 225 225 * @see https://tanstack.com/query/v5/docs/framework/react/guides/query-keys 226 226 */ 227 - name?: StringName; 227 + name?: NameTransformer; 228 228 /** 229 229 * Whether to include operation tags in query keys. 230 230 * This will make query keys larger but provides better cache invalidation capabilities. ··· 247 247 */ 248 248 queryOptions?: 249 249 | boolean 250 - | StringName 250 + | NameTransformer 251 251 | { 252 252 /** 253 253 * The casing convention to use for generated names. 254 254 * 255 255 * @default 'camelCase' 256 256 */ 257 - case?: StringCase; 257 + case?: Casing; 258 258 /** 259 259 * Whether to generate query options helpers. 260 260 * ··· 296 296 * @default '{{name}}Options' 297 297 * @see https://tanstack.com/query/v5/docs/framework/svelte/reference/functions/createquery 298 298 */ 299 - name?: StringName; 299 + name?: NameTransformer; 300 300 }; 301 301 }; 302 302 ··· 307 307 * 308 308 * @default 'camelCase' 309 309 */ 310 - case: StringCase; 310 + case: Casing; 311 311 /** 312 312 * Add comments from SDK functions to the generated TanStack Query code? 313 313 * ··· 331 331 * 332 332 * @default 'camelCase' 333 333 */ 334 - case: StringCase; 334 + case: Casing; 335 335 /** 336 336 * Whether to generate infinite query key helpers. 337 337 * ··· 345 345 * @default '{{name}}InfiniteQueryKey' 346 346 * @see https://tanstack.com/query/v5/docs/framework/svelte/reference/functions/createinfinitequery 347 347 */ 348 - name: StringName; 348 + name: NameTransformer; 349 349 /** 350 350 * Whether to include operation tags in infinite query keys. 351 351 * This will make query keys larger but provides better cache invalidation capabilities. ··· 365 365 * 366 366 * @default 'camelCase' 367 367 */ 368 - case: StringCase; 368 + case: Casing; 369 369 /** 370 370 * Whether to generate infinite query options helpers. 371 371 * ··· 401 401 * @default '{{name}}InfiniteOptions' 402 402 * @see https://tanstack.com/query/v5/docs/framework/svelte/reference/functions/createinfinitequery 403 403 */ 404 - name: StringName; 404 + name: NameTransformer; 405 405 }; 406 406 /** 407 407 * Resolved configuration for generated mutation options helpers. ··· 414 414 * 415 415 * @default 'camelCase' 416 416 */ 417 - case: StringCase; 417 + case: Casing; 418 418 /** 419 419 * Whether to generate mutation options helpers. 420 420 * ··· 450 450 * @default '{{name}}Mutation' 451 451 * @see https://tanstack.com/query/v5/docs/framework/svelte/reference/functions/createmutation 452 452 */ 453 - name: StringName; 453 + name: NameTransformer; 454 454 }; 455 455 /** 456 456 * Resolved configuration for generated query keys. ··· 463 463 * 464 464 * @default 'camelCase' 465 465 */ 466 - case: StringCase; 466 + case: Casing; 467 467 /** 468 468 * Whether to generate query keys. 469 469 * ··· 477 477 * @default '{{name}}QueryKey' 478 478 * @see https://tanstack.com/query/v5/docs/framework/react/guides/query-keys 479 479 */ 480 - name: StringName; 480 + name: NameTransformer; 481 481 /** 482 482 * Whether to include operation tags in query keys. 483 483 * This will make query keys larger but provides better cache invalidation capabilities. ··· 497 497 * 498 498 * @default 'camelCase' 499 499 */ 500 - case: StringCase; 500 + case: Casing; 501 501 /** 502 502 * Whether to generate query options helpers. 503 503 * ··· 539 539 * @default '{{name}}Options' 540 540 * @see https://tanstack.com/query/v5/docs/framework/svelte/reference/functions/createquery 541 541 */ 542 - name: StringName; 542 + name: NameTransformer; 543 543 }; 544 544 }; 545 545
+28 -28
packages/openapi-ts/src/plugins/@tanstack/vue-query/types.d.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 2 import type { DefinePlugin, Plugin } from '~/plugins'; 3 - import type { StringCase, StringName } from '~/types/case'; 3 + import type { Casing, NameTransformer } from '~/utils/naming'; 4 4 5 5 export type UserConfig = Plugin.Name<'@tanstack/vue-query'> & 6 6 Plugin.Hooks & { ··· 9 9 * 10 10 * @default 'camelCase' 11 11 */ 12 - case?: StringCase; 12 + case?: Casing; 13 13 /** 14 14 * Add comments from SDK functions to the generated TanStack Query code? 15 15 * ··· 41 41 */ 42 42 infiniteQueryKeys?: 43 43 | boolean 44 - | StringName 44 + | NameTransformer 45 45 | { 46 46 /** 47 47 * The casing convention to use for generated names. 48 48 * 49 49 * @default 'camelCase' 50 50 */ 51 - case?: StringCase; 51 + case?: Casing; 52 52 /** 53 53 * Whether to generate infinite query key helpers. 54 54 * ··· 62 62 * @default '{{name}}InfiniteQueryKey' 63 63 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/infiniteQueryOptions 64 64 */ 65 - name?: StringName; 65 + name?: NameTransformer; 66 66 /** 67 67 * Whether to include operation tags in infinite query keys. 68 68 * This will make query keys larger but provides better cache invalidation capabilities. ··· 85 85 */ 86 86 infiniteQueryOptions?: 87 87 | boolean 88 - | StringName 88 + | NameTransformer 89 89 | { 90 90 /** 91 91 * The casing convention to use for generated names. 92 92 * 93 93 * @default 'camelCase' 94 94 */ 95 - case?: StringCase; 95 + case?: Casing; 96 96 /** 97 97 * Whether to generate infinite query options helpers. 98 98 * ··· 129 129 * @default '{{name}}InfiniteOptions' 130 130 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/infiniteQueryOptions 131 131 */ 132 - name?: StringName; 132 + name?: NameTransformer; 133 133 }; 134 134 /** 135 135 * Configuration for generated mutation options helpers. ··· 145 145 */ 146 146 mutationOptions?: 147 147 | boolean 148 - | StringName 148 + | NameTransformer 149 149 | { 150 150 /** 151 151 * The casing convention to use for generated names. 152 152 * 153 153 * @default 'camelCase' 154 154 */ 155 - case?: StringCase; 155 + case?: Casing; 156 156 /** 157 157 * Whether to generate mutation options helpers. 158 158 * ··· 189 189 * @default '{{name}}Mutation' 190 190 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/useMutation 191 191 */ 192 - name?: StringName; 192 + name?: NameTransformer; 193 193 }; 194 194 /** 195 195 * Configuration for generated query keys. ··· 205 205 */ 206 206 queryKeys?: 207 207 | boolean 208 - | StringName 208 + | NameTransformer 209 209 | { 210 210 /** 211 211 * The casing convention to use for generated names. 212 212 * 213 213 * @default 'camelCase' 214 214 */ 215 - case?: StringCase; 215 + case?: Casing; 216 216 /** 217 217 * Whether to generate query keys. 218 218 * ··· 226 226 * @default '{{name}}QueryKey' 227 227 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/queryKey 228 228 */ 229 - name?: StringName; 229 + name?: NameTransformer; 230 230 /** 231 231 * Whether to include operation tags in query keys. 232 232 * This will make query keys larger but provides better cache invalidation capabilities. ··· 249 249 */ 250 250 queryOptions?: 251 251 | boolean 252 - | StringName 252 + | NameTransformer 253 253 | { 254 254 /** 255 255 * The casing convention to use for generated names. 256 256 * 257 257 * @default 'camelCase' 258 258 */ 259 - case?: StringCase; 259 + case?: Casing; 260 260 /** 261 261 * Whether to generate query options helpers. 262 262 * ··· 299 299 * @default '{{name}}Options' 300 300 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/queryOptions 301 301 */ 302 - name?: StringName; 302 + name?: NameTransformer; 303 303 }; 304 304 }; 305 305 ··· 310 310 * 311 311 * @default 'camelCase' 312 312 */ 313 - case: StringCase; 313 + case: Casing; 314 314 /** 315 315 * Add comments from SDK functions to the generated TanStack Query code? 316 316 * ··· 334 334 * 335 335 * @default 'camelCase' 336 336 */ 337 - case: StringCase; 337 + case: Casing; 338 338 /** 339 339 * Whether to generate infinite query key helpers. 340 340 * ··· 348 348 * @default '{{name}}InfiniteQueryKey' 349 349 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/infiniteQueryOptions 350 350 */ 351 - name: StringName; 351 + name: NameTransformer; 352 352 /** 353 353 * Whether to include operation tags in infinite query keys. 354 354 * This will make query keys larger but provides better cache invalidation capabilities. ··· 368 368 * 369 369 * @default 'camelCase' 370 370 */ 371 - case: StringCase; 371 + case: Casing; 372 372 /** 373 373 * Whether to generate infinite query options helpers. 374 374 * ··· 405 405 * @default '{{name}}InfiniteOptions' 406 406 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/infiniteQueryOptions 407 407 */ 408 - name: StringName; 408 + name: NameTransformer; 409 409 }; 410 410 /** 411 411 * Resolved configuration for generated mutation options helpers. ··· 418 418 * 419 419 * @default 'camelCase' 420 420 */ 421 - case: StringCase; 421 + case: Casing; 422 422 /** 423 423 * Whether to generate mutation options helpers. 424 424 * ··· 455 455 * @default '{{name}}Mutation' 456 456 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/useMutation 457 457 */ 458 - name: StringName; 458 + name: NameTransformer; 459 459 }; 460 460 /** 461 461 * Resolved configuration for generated query keys. ··· 468 468 * 469 469 * @default 'camelCase' 470 470 */ 471 - case: StringCase; 471 + case: Casing; 472 472 /** 473 473 * Whether to generate query keys. 474 474 * ··· 482 482 * @default '{{name}}QueryKey' 483 483 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/queryKey 484 484 */ 485 - name: StringName; 485 + name: NameTransformer; 486 486 /** 487 487 * Whether to include operation tags in query keys. 488 488 * This will make query keys larger but provides better cache invalidation capabilities. ··· 502 502 * 503 503 * @default 'camelCase' 504 504 */ 505 - case: StringCase; 505 + case: Casing; 506 506 /** 507 507 * Whether to generate query options helpers. 508 508 * ··· 545 545 * @default '{{name}}Options' 546 546 * @see https://tanstack.com/query/v5/docs/framework/vue/reference/queryOptions 547 547 */ 548 - name: StringName; 548 + name: NameTransformer; 549 549 }; 550 550 }; 551 551
+46 -46
packages/openapi-ts/src/plugins/arktype/types.d.ts
··· 1 1 import type { DefinePlugin, Plugin } from '~/plugins'; 2 - import type { StringCase, StringName } from '~/types/case'; 2 + import type { Casing, NameTransformer } from '~/utils/naming'; 3 3 4 4 import type { IApi } from './api'; 5 5 ··· 10 10 * 11 11 * @default 'PascalCase' 12 12 */ 13 - case?: StringCase; 13 + case?: Casing; 14 14 /** 15 15 * Add comments from input to the generated Arktype schemas? 16 16 * ··· 30 30 */ 31 31 definitions?: 32 32 | boolean 33 - | StringName 33 + | NameTransformer 34 34 | { 35 35 /** 36 36 * The casing convention to use for generated names. 37 37 * 38 38 * @default 'PascalCase' 39 39 */ 40 - case?: StringCase; 40 + case?: Casing; 41 41 /** 42 42 * Whether to generate Arktype schemas for reusable definitions. 43 43 * ··· 50 50 * 51 51 * @default '{{name}}' 52 52 */ 53 - name?: StringName; 53 + name?: NameTransformer; 54 54 /** 55 55 * Configuration for TypeScript type generation from Arktype schemas. 56 56 * ··· 69 69 */ 70 70 infer?: 71 71 | boolean 72 - | StringName 72 + | NameTransformer 73 73 | { 74 74 /** 75 75 * The casing convention to use for generated type names. 76 76 * 77 77 * @default 'PascalCase' 78 78 */ 79 - case?: StringCase; 79 + case?: Casing; 80 80 /** 81 81 * Whether to generate TypeScript types from Arktype schemas. 82 82 * ··· 89 89 * 90 90 * @default '{{name}}' 91 91 */ 92 - name?: StringName; 92 + name?: NameTransformer; 93 93 }; 94 94 }; 95 95 }; ··· 123 123 */ 124 124 requests?: 125 125 | boolean 126 - | StringName 126 + | NameTransformer 127 127 | { 128 128 /** 129 129 * The casing convention to use for generated names. 130 130 * 131 131 * @default 'PascalCase' 132 132 */ 133 - case?: StringCase; 133 + case?: Casing; 134 134 /** 135 135 * Whether to generate Arktype schemas for request definitions. 136 136 * ··· 143 143 * 144 144 * @default '{{name}}Data' 145 145 */ 146 - name?: StringName; 146 + name?: NameTransformer; 147 147 /** 148 148 * Configuration for TypeScript type generation from Arktype schemas. 149 149 * ··· 162 162 */ 163 163 infer?: 164 164 | boolean 165 - | StringName 165 + | NameTransformer 166 166 | { 167 167 /** 168 168 * The casing convention to use for generated type names. 169 169 * 170 170 * @default 'PascalCase' 171 171 */ 172 - case?: StringCase; 172 + case?: Casing; 173 173 /** 174 174 * Whether to generate TypeScript types from Arktype schemas. 175 175 * ··· 182 182 * 183 183 * @default '{{name}}Data' 184 184 */ 185 - name?: StringName; 185 + name?: NameTransformer; 186 186 }; 187 187 }; 188 188 }; ··· 201 201 */ 202 202 responses?: 203 203 | boolean 204 - | StringName 204 + | NameTransformer 205 205 | { 206 206 /** 207 207 * The casing convention to use for generated names. 208 208 * 209 209 * @default 'PascalCase' 210 210 */ 211 - case?: StringCase; 211 + case?: Casing; 212 212 /** 213 213 * Whether to generate Arktype schemas for response definitions. 214 214 * ··· 221 221 * 222 222 * @default '{{name}}Response' 223 223 */ 224 - name?: StringName; 224 + name?: NameTransformer; 225 225 /** 226 226 * Configuration for TypeScript type generation from Arktype schemas. 227 227 * ··· 240 240 */ 241 241 infer?: 242 242 | boolean 243 - | StringName 243 + | NameTransformer 244 244 | { 245 245 /** 246 246 * The casing convention to use for generated type names. 247 247 * 248 248 * @default 'PascalCase' 249 249 */ 250 - case?: StringCase; 250 + case?: Casing; 251 251 /** 252 252 * Whether to generate TypeScript types from Arktype schemas. 253 253 * ··· 260 260 * 261 261 * @default '{{name}}Response' 262 262 */ 263 - name?: StringName; 263 + name?: NameTransformer; 264 264 }; 265 265 }; 266 266 }; ··· 282 282 */ 283 283 infer?: 284 284 | boolean 285 - | StringName 285 + | NameTransformer 286 286 | { 287 287 /** 288 288 * The casing convention to use for generated type names. 289 289 * 290 290 * @default 'PascalCase' 291 291 */ 292 - case?: StringCase; 292 + case?: Casing; 293 293 /** 294 294 * Whether to generate TypeScript types from Arktype schemas. 295 295 * ··· 312 312 */ 313 313 webhooks?: 314 314 | boolean 315 - | StringName 315 + | NameTransformer 316 316 | { 317 317 /** 318 318 * The casing convention to use for generated names. 319 319 * 320 320 * @default 'PascalCase' 321 321 */ 322 - case?: StringCase; 322 + case?: Casing; 323 323 /** 324 324 * Whether to generate Arktype schemas for webhook definitions. 325 325 * ··· 332 332 * 333 333 * @default '{{name}}WebhookRequest' 334 334 */ 335 - name?: StringName; 335 + name?: NameTransformer; 336 336 /** 337 337 * Configuration for TypeScript type generation from Arktype schemas. 338 338 * ··· 351 351 */ 352 352 infer?: 353 353 | boolean 354 - | StringName 354 + | NameTransformer 355 355 | { 356 356 /** 357 357 * The casing convention to use for generated type names. 358 358 * 359 359 * @default 'PascalCase' 360 360 */ 361 - case?: StringCase; 361 + case?: Casing; 362 362 /** 363 363 * Whether to generate TypeScript types from Arktype schemas. 364 364 * ··· 371 371 * 372 372 * @default '{{name}}WebhookRequest' 373 373 */ 374 - name?: StringName; 374 + name?: NameTransformer; 375 375 }; 376 376 }; 377 377 }; ··· 384 384 * 385 385 * @default 'PascalCase' 386 386 */ 387 - case: StringCase; 387 + case: Casing; 388 388 /** 389 389 * Add comments from input to the generated Arktype schemas? 390 390 * ··· 403 403 * 404 404 * @default 'PascalCase' 405 405 */ 406 - case: StringCase; 406 + case: Casing; 407 407 /** 408 408 * Whether to generate Arktype schemas for reusable definitions. 409 409 * ··· 416 416 * 417 417 * @default '{{name}}' 418 418 */ 419 - name: StringName; 419 + name: NameTransformer; 420 420 /** 421 421 * Configuration for TypeScript type generation from Arktype schemas. 422 422 * ··· 432 432 * 433 433 * @default 'PascalCase' 434 434 */ 435 - case: StringCase; 435 + case: Casing; 436 436 /** 437 437 * Whether to generate TypeScript types from Arktype schemas. 438 438 * ··· 445 445 * 446 446 * @default '{{name}}' 447 447 */ 448 - name: StringName; 448 + name: NameTransformer; 449 449 }; 450 450 }; 451 451 }; ··· 476 476 * 477 477 * @default 'PascalCase' 478 478 */ 479 - case: StringCase; 479 + case: Casing; 480 480 /** 481 481 * Whether to generate Arktype schemas for request definitions. 482 482 * ··· 489 489 * 490 490 * @default '{{name}}Data' 491 491 */ 492 - name: StringName; 492 + name: NameTransformer; 493 493 /** 494 494 * Configuration for TypeScript type generation from Arktype schemas. 495 495 * ··· 505 505 * 506 506 * @default 'PascalCase' 507 507 */ 508 - case: StringCase; 508 + case: Casing; 509 509 /** 510 510 * Whether to generate TypeScript types from Arktype schemas. 511 511 * ··· 518 518 * 519 519 * @default '{{name}}Data' 520 520 */ 521 - name: StringName; 521 + name: NameTransformer; 522 522 }; 523 523 }; 524 524 }; ··· 534 534 * 535 535 * @default 'PascalCase' 536 536 */ 537 - case: StringCase; 537 + case: Casing; 538 538 /** 539 539 * Whether to generate Arktype schemas for response definitions. 540 540 * ··· 547 547 * 548 548 * @default '{{name}}Response' 549 549 */ 550 - name: StringName; 550 + name: NameTransformer; 551 551 /** 552 552 * Configuration for TypeScript type generation from Arktype schemas. 553 553 * ··· 563 563 * 564 564 * @default 'PascalCase' 565 565 */ 566 - case: StringCase; 566 + case: Casing; 567 567 /** 568 568 * Whether to generate TypeScript types from Arktype schemas. 569 569 * ··· 576 576 * 577 577 * @default '{{name}}Response' 578 578 */ 579 - name: StringName; 579 + name: NameTransformer; 580 580 }; 581 581 }; 582 582 }; ··· 595 595 * 596 596 * @default 'PascalCase' 597 597 */ 598 - case: StringCase; 598 + case: Casing; 599 599 /** 600 600 * Whether to generate TypeScript types from Arktype schemas. 601 601 * ··· 615 615 * 616 616 * @default 'PascalCase' 617 617 */ 618 - case: StringCase; 618 + case: Casing; 619 619 /** 620 620 * Whether to generate Arktype schemas for webhook definitions. 621 621 * ··· 628 628 * 629 629 * @default '{{name}}WebhookRequest' 630 630 */ 631 - name: StringName; 631 + name: NameTransformer; 632 632 /** 633 633 * Configuration for TypeScript type generation from Arktype schemas. 634 634 * ··· 644 644 * 645 645 * @default 'PascalCase' 646 646 */ 647 - case: StringCase; 647 + case: Casing; 648 648 /** 649 649 * Whether to generate TypeScript types from Arktype schemas. 650 650 * ··· 657 657 * 658 658 * @default '{{name}}WebhookRequest' 659 659 */ 660 - name: StringName; 660 + name: NameTransformer; 661 661 }; 662 662 }; 663 663 };
+26 -29
packages/openapi-ts/src/plugins/arktype/v2/plugin.ts
··· 3 3 4 4 import { deduplicateSchema } from '~/ir/schema'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import type { SchemaWithType } from '~/plugins/shared/types/schema'; 8 7 import { $ } from '~/ts-dsl'; 8 + import { applyNaming } from '~/utils/naming'; 9 9 import { pathToJsonPointer, refToName } from '~/utils/ref'; 10 10 11 11 import { exportAst } from '../shared/export'; ··· 242 242 const $ref = pathToJsonPointer(fromRef(state.path)); 243 243 const ast = irSchemaToAst({ plugin, schema, state }); 244 244 const baseName = refToName($ref); 245 - const symbol = plugin.registerSymbol({ 246 - meta: { 247 - category: 'schema', 248 - path: fromRef(state.path), 249 - resource: 'definition', 250 - resourceId: $ref, 251 - tags: fromRef(state.tags), 252 - tool: 'arktype', 245 + const symbol = plugin.symbol( 246 + applyNaming(baseName, plugin.config.definitions), 247 + { 248 + meta: { 249 + category: 'schema', 250 + path: fromRef(state.path), 251 + resource: 'definition', 252 + resourceId: $ref, 253 + tags: fromRef(state.tags), 254 + tool: 'arktype', 255 + }, 253 256 }, 254 - name: buildName({ 255 - config: plugin.config.definitions, 256 - name: baseName, 257 - }), 258 - }); 257 + ); 259 258 const typeInferSymbol = plugin.config.definitions.types.infer.enabled 260 - ? plugin.registerSymbol({ 261 - meta: { 262 - category: 'type', 263 - path: fromRef(state.path), 264 - resource: 'definition', 265 - resourceId: $ref, 266 - tool: 'arktype', 267 - variant: 'infer', 259 + ? plugin.symbol( 260 + applyNaming(baseName, plugin.config.definitions.types.infer), 261 + { 262 + meta: { 263 + category: 'type', 264 + path: fromRef(state.path), 265 + resource: 'definition', 266 + resourceId: $ref, 267 + tool: 'arktype', 268 + variant: 'infer', 269 + }, 268 270 }, 269 - name: buildName({ 270 - config: plugin.config.definitions.types.infer, 271 - name: baseName, 272 - }), 273 - }) 271 + ) 274 272 : undefined; 275 273 exportAst({ 276 274 ast, ··· 282 280 }; 283 281 284 282 export const handlerV2: ArktypePlugin['Handler'] = ({ plugin }) => { 285 - plugin.registerSymbol({ 283 + plugin.symbol('type', { 286 284 external: 'arktype', 287 285 meta: { 288 286 category: 'external', 289 287 resource: 'arktype.type', 290 288 }, 291 - name: 'type', 292 289 }); 293 290 294 291 plugin.forEach(
+2 -5
packages/openapi-ts/src/plugins/fastify/plugin.ts
··· 130 130 }; 131 131 132 132 export const handler: FastifyPlugin['Handler'] = ({ plugin }) => { 133 - plugin.registerSymbol({ 133 + plugin.symbol('RouteHandler', { 134 134 external: 'fastify', 135 135 kind: 'type', 136 136 meta: { ··· 138 138 resource: 'route-handler', 139 139 tool: 'fastify', 140 140 }, 141 - name: 'RouteHandler', 142 141 }); 143 142 144 - const symbolRouteHandlers = plugin.registerSymbol({ 145 - name: 'RouteHandlers', 146 - }); 143 + const symbolRouteHandlers = plugin.symbol('RouteHandlers'); 147 144 148 145 const type = $.type.object(); 149 146
+33 -33
packages/openapi-ts/src/plugins/swr/types.d.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 2 import type { DefinePlugin, Plugin } from '~/plugins'; 3 - import type { StringCase, StringName } from '~/types/case'; 3 + import type { Casing, NameTransformer } from '~/utils/naming'; 4 4 5 5 export type UserConfig = Plugin.Name<'swr'> & 6 6 Plugin.Hooks & { ··· 9 9 * 10 10 * @default 'camelCase' 11 11 */ 12 - case?: StringCase; 12 + case?: Casing; 13 13 /** 14 14 * Add comments from SDK functions to the generated SWR code? 15 15 * ··· 42 42 */ 43 43 infiniteQueryKeys?: 44 44 | boolean 45 - | StringName 45 + | NameTransformer 46 46 | { 47 47 /** 48 48 * The casing convention to use for generated names. 49 49 * 50 50 * @default 'camelCase' 51 51 */ 52 - case?: StringCase; 52 + case?: Casing; 53 53 /** 54 54 * Whether to generate infinite query key helpers. 55 55 * ··· 64 64 * 65 65 * @default '{{name}}InfiniteQueryKey' 66 66 */ 67 - name?: StringName; 67 + name?: NameTransformer; 68 68 /** 69 69 * Whether to include operation tags in infinite query keys. 70 70 * This will make query keys larger but provides better cache invalidation capabilities. ··· 87 87 */ 88 88 infiniteQueryOptions?: 89 89 | boolean 90 - | StringName 90 + | NameTransformer 91 91 | { 92 92 /** 93 93 * The casing convention to use for generated names. 94 94 * 95 95 * @default 'camelCase' 96 96 */ 97 - case?: StringCase; 97 + case?: Casing; 98 98 /** 99 99 * Whether to generate infinite query options helpers. 100 100 * ··· 132 132 * 133 133 * @default '{{name}}InfiniteOptions' 134 134 */ 135 - name?: StringName; 135 + name?: NameTransformer; 136 136 }; 137 137 /** 138 138 * Configuration for generated mutation options helpers. ··· 148 148 */ 149 149 mutationOptions?: 150 150 | boolean 151 - | StringName 151 + | NameTransformer 152 152 | { 153 153 /** 154 154 * The casing convention to use for generated names. 155 155 * 156 156 * @default 'camelCase' 157 157 */ 158 - case?: StringCase; 158 + case?: Casing; 159 159 /** 160 160 * Whether to generate mutation options helpers. 161 161 * ··· 193 193 * 194 194 * @default '{{name}}Mutation' 195 195 */ 196 - name?: StringName; 196 + name?: NameTransformer; 197 197 }; 198 198 /** 199 199 * Configuration for generated query keys. ··· 209 209 */ 210 210 queryKeys?: 211 211 | boolean 212 - | StringName 212 + | NameTransformer 213 213 | { 214 214 /** 215 215 * The casing convention to use for generated names. 216 216 * 217 217 * @default 'camelCase' 218 218 */ 219 - case?: StringCase; 219 + case?: Casing; 220 220 /** 221 221 * Whether to generate query keys. 222 222 * ··· 231 231 * 232 232 * @default '{{name}}QueryKey' 233 233 */ 234 - name?: StringName; 234 + name?: NameTransformer; 235 235 /** 236 236 * Whether to include operation tags in query keys. 237 237 * This will make query keys larger but provides better cache invalidation capabilities. ··· 254 254 */ 255 255 queryOptions?: 256 256 | boolean 257 - | StringName 257 + | NameTransformer 258 258 | { 259 259 /** 260 260 * The casing convention to use for generated names. 261 261 * 262 262 * @default 'camelCase' 263 263 */ 264 - case?: StringCase; 264 + case?: Casing; 265 265 /** 266 266 * Whether to generate query options helpers. 267 267 * ··· 305 305 * 306 306 * @default '{{name}}Options' 307 307 */ 308 - name?: StringName; 308 + name?: NameTransformer; 309 309 }; 310 310 /** 311 311 * Configuration for generated `useSwr()` function helpers. ··· 321 321 */ 322 322 useSwr?: 323 323 | boolean 324 - | StringName 324 + | NameTransformer 325 325 | { 326 326 /** 327 327 * The casing convention to use for generated names. 328 328 * 329 329 * @default 'camelCase' 330 330 */ 331 - case?: StringCase; 331 + case?: Casing; 332 332 /** 333 333 * Whether to generate `useSwr()` function helpers. 334 334 * ··· 343 343 * 344 344 * @default 'use{{name}}' 345 345 */ 346 - name?: StringName; 346 + name?: NameTransformer; 347 347 }; 348 348 }; 349 349 ··· 354 354 * 355 355 * @default 'camelCase' 356 356 */ 357 - case: StringCase; 357 + case: Casing; 358 358 /** 359 359 * Add comments from SDK functions to the generated SWR code? 360 360 * ··· 378 378 * 379 379 * @default 'camelCase' 380 380 */ 381 - case: StringCase; 381 + case: Casing; 382 382 /** 383 383 * Whether to generate infinite query key helpers. 384 384 * ··· 392 392 * 393 393 * @default '{{name}}InfiniteQueryKey' 394 394 */ 395 - name: StringName; 395 + name: NameTransformer; 396 396 /** 397 397 * Whether to include operation tags in infinite query keys. 398 398 * This will make query keys larger but provides better cache invalidation capabilities. ··· 412 412 * 413 413 * @default 'camelCase' 414 414 */ 415 - case: StringCase; 415 + case: Casing; 416 416 /** 417 417 * Whether to generate infinite query options helpers. 418 418 * ··· 449 449 * 450 450 * @default '{{name}}InfiniteOptions' 451 451 */ 452 - name: StringName; 452 + name: NameTransformer; 453 453 }; 454 454 /** 455 455 * Resolved configuration for generated mutation options helpers. ··· 462 462 * 463 463 * @default 'camelCase' 464 464 */ 465 - case: StringCase; 465 + case: Casing; 466 466 /** 467 467 * Whether to generate mutation options helpers. 468 468 * ··· 499 499 * 500 500 * @default '{{name}}Mutation' 501 501 */ 502 - name: StringName; 502 + name: NameTransformer; 503 503 }; 504 504 /** 505 505 * Resolved configuration for generated query keys. ··· 512 512 * 513 513 * @default 'camelCase' 514 514 */ 515 - case: StringCase; 515 + case: Casing; 516 516 /** 517 517 * Whether to generate query keys. 518 518 * ··· 526 526 * 527 527 * @default '{{name}}QueryKey' 528 528 */ 529 - name: StringName; 529 + name: NameTransformer; 530 530 /** 531 531 * Whether to include operation tags in query keys. 532 532 * This will make query keys larger but provides better cache invalidation capabilities. ··· 546 546 * 547 547 * @default 'camelCase' 548 548 */ 549 - case: StringCase; 549 + case: Casing; 550 550 /** 551 551 * Whether to generate query options helpers. 552 552 * ··· 589 589 * 590 590 * @default '{{name}}Options' 591 591 */ 592 - name: StringName; 592 + name: NameTransformer; 593 593 }; 594 594 /** 595 595 * Configuration for generated `useSwr()` function helpers. ··· 602 602 * 603 603 * @default 'camelCase' 604 604 */ 605 - case: StringCase; 605 + case: Casing; 606 606 /** 607 607 * Whether to generate `useSwr()` function helpers. 608 608 * ··· 617 617 * 618 618 * @default 'use{{name}}' 619 619 */ 620 - name: StringName; 620 + name: NameTransformer; 621 621 }; 622 622 }; 623 623
+1 -2
packages/openapi-ts/src/plugins/swr/v2/plugin.ts
··· 2 2 import { createUseSwr } from './useSwr'; 3 3 4 4 export const handlerV2: SwrPlugin['Handler'] = ({ plugin }) => { 5 - plugin.registerSymbol({ 5 + plugin.symbol('useSWR', { 6 6 external: 'swr', 7 7 importKind: 'default', 8 8 kind: 'function', ··· 10 10 category: 'external', 11 11 resource: 'swr', 12 12 }, 13 - name: 'useSWR', 14 13 }); 15 14 16 15 plugin.forEach(
+4 -7
packages/openapi-ts/src/plugins/swr/v2/useSwr.ts
··· 1 1 import type { IR } from '~/ir/types'; 2 - import { buildName } from '~/openApi/shared/utils/name'; 3 2 import { 4 3 createOperationComment, 5 4 hasOperationSse, 6 5 } from '~/plugins/shared/utils/operation'; 7 6 import type { TsDsl } from '~/ts-dsl'; 8 7 import { $ } from '~/ts-dsl'; 8 + import { applyNaming } from '~/utils/naming'; 9 9 10 10 import type { SwrPlugin } from '../types'; 11 11 ··· 24 24 category: 'external', 25 25 resource: 'swr', 26 26 }); 27 - const symbolUseQueryFn = plugin.registerSymbol({ 28 - name: buildName({ 29 - config: plugin.config.useSwr, 30 - name: operation.id, 31 - }), 32 - }); 27 + const symbolUseQueryFn = plugin.symbol( 28 + applyNaming(operation.id, plugin.config.useSwr), 29 + ); 33 30 34 31 const awaitSdkFn = $.lazy((ctx) => 35 32 ctx
+27 -29
packages/openapi-ts/src/plugins/valibot/shared/operation.ts
··· 2 2 3 3 import { operationResponsesMap } from '~/ir/operation'; 4 4 import type { IR } from '~/ir/types'; 5 - import { buildName } from '~/openApi/shared/utils/name'; 5 + import { applyNaming } from '~/utils/naming'; 6 6 7 7 import { exportAst } from './export'; 8 8 import type { Ast, IrSchemaToAstOptions } from './types'; ··· 118 118 schemaData.required = [...requiredProperties]; 119 119 120 120 const ast = getAst(schemaData, fromRef(state.path)); 121 - const symbol = plugin.registerSymbol({ 122 - meta: { 123 - category: 'schema', 124 - path: fromRef(state.path), 125 - resource: 'operation', 126 - resourceId: operation.id, 127 - role: 'data', 128 - tags: fromRef(state.tags), 129 - tool: 'valibot', 121 + const symbol = plugin.symbol( 122 + applyNaming(operation.id, plugin.config.requests), 123 + { 124 + meta: { 125 + category: 'schema', 126 + path: fromRef(state.path), 127 + resource: 'operation', 128 + resourceId: operation.id, 129 + role: 'data', 130 + tags: fromRef(state.tags), 131 + tool: 'valibot', 132 + }, 130 133 }, 131 - name: buildName({ 132 - config: plugin.config.requests, 133 - name: operation.id, 134 - }), 135 - }); 134 + ); 136 135 exportAst({ 137 136 ast, 138 137 plugin, ··· 149 148 if (response) { 150 149 const path = [...fromRef(state.path), 'responses']; 151 150 const ast = getAst(response, path); 152 - const symbol = plugin.registerSymbol({ 153 - meta: { 154 - category: 'schema', 155 - path, 156 - resource: 'operation', 157 - resourceId: operation.id, 158 - role: 'responses', 159 - tags: fromRef(state.tags), 160 - tool: 'valibot', 151 + const symbol = plugin.symbol( 152 + applyNaming(operation.id, plugin.config.responses), 153 + { 154 + meta: { 155 + category: 'schema', 156 + path, 157 + resource: 'operation', 158 + resourceId: operation.id, 159 + role: 'responses', 160 + tags: fromRef(state.tags), 161 + tool: 'valibot', 162 + }, 161 163 }, 162 - name: buildName({ 163 - config: plugin.config.responses, 164 - name: operation.id, 165 - }), 166 - }); 164 + ); 167 165 exportAst({ 168 166 ast, 169 167 plugin,
+14 -15
packages/openapi-ts/src/plugins/valibot/shared/webhook.ts
··· 1 1 import { fromRef } from '@hey-api/codegen-core'; 2 2 3 3 import type { IR } from '~/ir/types'; 4 - import { buildName } from '~/openApi/shared/utils/name'; 4 + import { applyNaming } from '~/utils/naming'; 5 5 6 6 import { exportAst } from './export'; 7 7 import type { Ast, IrSchemaToAstOptions } from './types'; ··· 117 117 schemaData.required = [...requiredProperties]; 118 118 119 119 const ast = getAst(schemaData, fromRef(state.path)); 120 - const symbol = plugin.registerSymbol({ 121 - meta: { 122 - category: 'schema', 123 - path: fromRef(state.path), 124 - resource: 'webhook', 125 - resourceId: operation.id, 126 - role: 'data', 127 - tags: fromRef(state.tags), 128 - tool: 'valibot', 120 + const symbol = plugin.symbol( 121 + applyNaming(operation.id, plugin.config.webhooks), 122 + { 123 + meta: { 124 + category: 'schema', 125 + path: fromRef(state.path), 126 + resource: 'webhook', 127 + resourceId: operation.id, 128 + role: 'data', 129 + tags: fromRef(state.tags), 130 + tool: 'valibot', 131 + }, 129 132 }, 130 - name: buildName({ 131 - config: plugin.config.webhooks, 132 - name: operation.id, 133 - }), 134 - }); 133 + ); 135 134 exportAst({ 136 135 ast, 137 136 plugin,
+23 -23
packages/openapi-ts/src/plugins/valibot/types.d.ts
··· 8 8 } from '~/plugins/shared/utils/coerce'; 9 9 import type { GetIntegerLimit } from '~/plugins/shared/utils/formats'; 10 10 import type { $, DollarTsDsl } from '~/ts-dsl'; 11 - import type { StringCase, StringName } from '~/types/case'; 11 + import type { Casing, NameTransformer } from '~/utils/naming'; 12 12 13 13 import type { IApi } from './api'; 14 14 import type { Pipe, PipeResult, PipesUtils } from './shared/pipes'; ··· 22 22 * 23 23 * @default 'camelCase' 24 24 */ 25 - case?: StringCase; 25 + case?: Casing; 26 26 /** 27 27 * Add comments from input to the generated Valibot schemas? 28 28 * ··· 42 42 */ 43 43 definitions?: 44 44 | boolean 45 - | StringName 45 + | NameTransformer 46 46 | { 47 47 /** 48 48 * The casing convention to use for generated names. 49 49 * 50 50 * @default 'camelCase' 51 51 */ 52 - case?: StringCase; 52 + case?: Casing; 53 53 /** 54 54 * Whether to generate Valibot schemas for reusable definitions. 55 55 * ··· 62 62 * 63 63 * @default 'v{{name}}' 64 64 */ 65 - name?: StringName; 65 + name?: NameTransformer; 66 66 }; 67 67 /** 68 68 * Should the exports from the generated files be re-exported in the index ··· 92 92 */ 93 93 requests?: 94 94 | boolean 95 - | StringName 95 + | NameTransformer 96 96 | { 97 97 /** 98 98 * The casing convention to use for generated names. 99 99 * 100 100 * @default 'camelCase' 101 101 */ 102 - case?: StringCase; 102 + case?: Casing; 103 103 /** 104 104 * Whether to generate Valibot schemas for request definitions. 105 105 * ··· 112 112 * 113 113 * @default 'v{{name}}Data' 114 114 */ 115 - name?: StringName; 115 + name?: NameTransformer; 116 116 }; 117 117 /** 118 118 * Configuration for response-specific Valibot schemas. ··· 127 127 */ 128 128 responses?: 129 129 | boolean 130 - | StringName 130 + | NameTransformer 131 131 | { 132 132 /** 133 133 * The casing convention to use for generated names. 134 134 * 135 135 * @default 'camelCase' 136 136 */ 137 - case?: StringCase; 137 + case?: Casing; 138 138 /** 139 139 * Whether to generate Valibot schemas for response definitions. 140 140 * ··· 147 147 * 148 148 * @default 'v{{name}}Response' 149 149 */ 150 - name?: StringName; 150 + name?: NameTransformer; 151 151 }; 152 152 /** 153 153 * Configuration for webhook-specific Valibot schemas. ··· 163 163 */ 164 164 webhooks?: 165 165 | boolean 166 - | StringName 166 + | NameTransformer 167 167 | { 168 168 /** 169 169 * The casing convention to use for generated names. 170 170 * 171 171 * @default 'camelCase' 172 172 */ 173 - case?: StringCase; 173 + case?: Casing; 174 174 /** 175 175 * Whether to generate Valibot schemas for webhook definitions. 176 176 * ··· 183 183 * 184 184 * @default 'v{{name}}WebhookRequest' 185 185 */ 186 - name?: StringName; 186 + name?: NameTransformer; 187 187 }; 188 188 }; 189 189 ··· 195 195 * 196 196 * @default 'camelCase' 197 197 */ 198 - case: StringCase; 198 + case: Casing; 199 199 /** 200 200 * Add comments from input to the generated Valibot schemas? 201 201 * ··· 214 214 * 215 215 * @default 'camelCase' 216 216 */ 217 - case: StringCase; 217 + case: Casing; 218 218 /** 219 219 * Whether to generate Valibot schemas for reusable definitions. 220 220 * ··· 227 227 * 228 228 * @default 'v{{name}}' 229 229 */ 230 - name: StringName; 230 + name: NameTransformer; 231 231 }; 232 232 /** 233 233 * Should the exports from the generated files be re-exported in the index ··· 256 256 * 257 257 * @default 'camelCase' 258 258 */ 259 - case: StringCase; 259 + case: Casing; 260 260 /** 261 261 * Whether to generate Valibot schemas for request definitions. 262 262 * ··· 269 269 * 270 270 * @default 'v{{name}}Data' 271 271 */ 272 - name: StringName; 272 + name: NameTransformer; 273 273 }; 274 274 /** 275 275 * Configuration for response-specific Valibot schemas. ··· 283 283 * 284 284 * @default 'camelCase' 285 285 */ 286 - case: StringCase; 286 + case: Casing; 287 287 /** 288 288 * Whether to generate Valibot schemas for response definitions. 289 289 * ··· 296 296 * 297 297 * @default 'v{{name}}Response' 298 298 */ 299 - name: StringName; 299 + name: NameTransformer; 300 300 }; 301 301 /** 302 302 * Configuration for webhook-specific Valibot schemas. ··· 309 309 * 310 310 * @default 'camelCase' 311 311 */ 312 - case: StringCase; 312 + case: Casing; 313 313 /** 314 314 * Whether to generate Valibot schemas for webhook definitions. 315 315 * ··· 322 322 * 323 323 * @default 'v{{name}}WebhookRequest' 324 324 */ 325 - name: StringName; 325 + name: NameTransformer; 326 326 }; 327 327 }; 328 328
+14 -16
packages/openapi-ts/src/plugins/valibot/v1/plugin.ts
··· 3 3 4 4 import { deduplicateSchema } from '~/ir/schema'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import type { SchemaWithType } from '~/plugins'; 8 7 import { maybeBigInt } from '~/plugins/shared/utils/coerce'; 9 8 import { $ } from '~/ts-dsl'; 9 + import { applyNaming } from '~/utils/naming'; 10 10 import { pathToJsonPointer, refToName } from '~/utils/ref'; 11 11 12 12 import { exportAst } from '../shared/export'; ··· 157 157 const $ref = pathToJsonPointer(fromRef(state.path)); 158 158 const ast = irSchemaToAst({ plugin, schema, state }); 159 159 const baseName = refToName($ref); 160 - const symbol = plugin.registerSymbol({ 161 - meta: { 162 - category: 'schema', 163 - path: fromRef(state.path), 164 - resource: 'definition', 165 - resourceId: $ref, 166 - tags: fromRef(state.tags), 167 - tool: 'valibot', 160 + const symbol = plugin.symbol( 161 + applyNaming(baseName, plugin.config.definitions), 162 + { 163 + meta: { 164 + category: 'schema', 165 + path: fromRef(state.path), 166 + resource: 'definition', 167 + resourceId: $ref, 168 + tags: fromRef(state.tags), 169 + tool: 'valibot', 170 + }, 168 171 }, 169 - name: buildName({ 170 - config: plugin.config.definitions, 171 - name: baseName, 172 - }), 173 - }); 172 + ); 174 173 exportAst({ 175 174 ast, 176 175 plugin, ··· 181 180 }; 182 181 183 182 export const handlerV1: ValibotPlugin['Handler'] = ({ plugin }) => { 184 - plugin.registerSymbol({ 183 + plugin.symbol('v', { 185 184 external: 'valibot', 186 185 importKind: 'namespace', 187 186 meta: { 188 187 category: 'external', 189 188 resource: 'valibot.v', 190 189 }, 191 - name: 'v', 192 190 }); 193 191 194 192 plugin.forEach(
+27 -30
packages/openapi-ts/src/plugins/zod/mini/plugin.ts
··· 3 3 4 4 import { deduplicateSchema } from '~/ir/schema'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import type { SchemaWithType } from '~/plugins'; 8 7 import { maybeBigInt } from '~/plugins/shared/utils/coerce'; 9 8 import { $ } from '~/ts-dsl'; 9 + import { applyNaming } from '~/utils/naming'; 10 10 import { pathToJsonPointer, refToName } from '~/utils/ref'; 11 11 12 12 import { identifiers } from '../constants'; ··· 176 176 const $ref = pathToJsonPointer(fromRef(state.path)); 177 177 const ast = irSchemaToAst({ plugin, schema, state }); 178 178 const baseName = refToName($ref); 179 - const symbol = plugin.registerSymbol({ 180 - meta: { 181 - category: 'schema', 182 - path: fromRef(state.path), 183 - resource: 'definition', 184 - resourceId: $ref, 185 - tags: fromRef(state.tags), 186 - tool: 'zod', 179 + const symbol = plugin.symbol( 180 + applyNaming(baseName, plugin.config.definitions), 181 + { 182 + meta: { 183 + category: 'schema', 184 + path: fromRef(state.path), 185 + resource: 'definition', 186 + resourceId: $ref, 187 + tags: fromRef(state.tags), 188 + tool: 'zod', 189 + }, 187 190 }, 188 - name: buildName({ 189 - config: plugin.config.definitions, 190 - name: baseName, 191 - }), 192 - }); 191 + ); 193 192 const typeInferSymbol = plugin.config.definitions.types.infer.enabled 194 - ? plugin.registerSymbol({ 195 - meta: { 196 - category: 'type', 197 - path: fromRef(state.path), 198 - resource: 'definition', 199 - resourceId: $ref, 200 - tags: fromRef(state.tags), 201 - tool: 'zod', 202 - variant: 'infer', 193 + ? plugin.symbol( 194 + applyNaming(baseName, plugin.config.definitions.types.infer), 195 + { 196 + meta: { 197 + category: 'type', 198 + path: fromRef(state.path), 199 + resource: 'definition', 200 + resourceId: $ref, 201 + tags: fromRef(state.tags), 202 + tool: 'zod', 203 + variant: 'infer', 204 + }, 203 205 }, 204 - name: buildName({ 205 - config: plugin.config.definitions.types.infer, 206 - name: baseName, 207 - }), 208 - }) 206 + ) 209 207 : undefined; 210 208 exportAst({ 211 209 ast, ··· 217 215 }; 218 216 219 217 export const handlerMini: ZodPlugin['Handler'] = ({ plugin }) => { 220 - plugin.registerSymbol({ 218 + plugin.symbol('z', { 221 219 external: getZodModule({ plugin }), 222 220 importKind: 'namespace', 223 221 meta: { 224 222 category: 'external', 225 223 resource: 'zod.z', 226 224 }, 227 - name: 'z', 228 225 }); 229 226 230 227 plugin.forEach(
+5 -17
packages/openapi-ts/src/plugins/zod/shared/operation.ts
··· 2 2 3 3 import { operationResponsesMap } from '~/ir/operation'; 4 4 import type { IR } from '~/ir/types'; 5 - import { buildName } from '~/openApi/shared/utils/name'; 5 + import { applyNaming } from '~/utils/naming'; 6 6 7 7 import { exportAst } from './export'; 8 8 import type { Ast, IrSchemaToAstOptions } from './types'; ··· 119 119 120 120 const ast = getAst(schemaData, fromRef(state.path)); 121 121 const symbol = plugin.symbol( 122 - buildName({ 123 - config: plugin.config.requests, 124 - name: operation.id, 125 - }), 122 + applyNaming(operation.id, plugin.config.requests), 126 123 { 127 124 meta: { 128 125 category: 'schema', ··· 137 134 ); 138 135 const typeInferSymbol = plugin.config.requests.types.infer.enabled 139 136 ? plugin.symbol( 140 - buildName({ 141 - config: plugin.config.requests.types.infer, 142 - name: operation.id, 143 - }), 137 + applyNaming(operation.id, plugin.config.requests.types.infer), 144 138 { 145 139 meta: { 146 140 category: 'type', ··· 172 166 const path = [...fromRef(state.path), 'responses']; 173 167 const ast = getAst(response, path); 174 168 const symbol = plugin.symbol( 175 - buildName({ 176 - config: plugin.config.responses, 177 - name: operation.id, 178 - }), 169 + applyNaming(operation.id, plugin.config.responses), 179 170 { 180 171 meta: { 181 172 category: 'schema', ··· 190 181 ); 191 182 const typeInferSymbol = plugin.config.responses.types.infer.enabled 192 183 ? plugin.symbol( 193 - buildName({ 194 - config: plugin.config.responses.types.infer, 195 - name: operation.id, 196 - }), 184 + applyNaming(operation.id, plugin.config.responses.types.infer), 197 185 { 198 186 meta: { 199 187 category: 'type',
+28 -30
packages/openapi-ts/src/plugins/zod/shared/webhook.ts
··· 1 1 import { fromRef } from '@hey-api/codegen-core'; 2 2 3 3 import type { IR } from '~/ir/types'; 4 - import { buildName } from '~/openApi/shared/utils/name'; 4 + import { applyNaming } from '~/utils/naming'; 5 5 6 6 import { exportAst } from './export'; 7 7 import type { Ast, IrSchemaToAstOptions } from './types'; ··· 117 117 schemaData.required = [...requiredProperties]; 118 118 119 119 const ast = getAst(schemaData, fromRef(state.path)); 120 - const symbol = plugin.registerSymbol({ 121 - meta: { 122 - category: 'schema', 123 - path: fromRef(state.path), 124 - resource: 'webhook', 125 - resourceId: operation.id, 126 - role: 'data', 127 - tags: fromRef(state.tags), 128 - tool: 'zod', 120 + const symbol = plugin.symbol( 121 + applyNaming(operation.id, plugin.config.webhooks), 122 + { 123 + meta: { 124 + category: 'schema', 125 + path: fromRef(state.path), 126 + resource: 'webhook', 127 + resourceId: operation.id, 128 + role: 'data', 129 + tags: fromRef(state.tags), 130 + tool: 'zod', 131 + }, 129 132 }, 130 - name: buildName({ 131 - config: plugin.config.webhooks, 132 - name: operation.id, 133 - }), 134 - }); 133 + ); 135 134 const typeInferSymbol = plugin.config.webhooks.types.infer.enabled 136 - ? plugin.registerSymbol({ 137 - meta: { 138 - category: 'type', 139 - path: fromRef(state.path), 140 - resource: 'webhook', 141 - resourceId: operation.id, 142 - role: 'data', 143 - tags: fromRef(state.tags), 144 - tool: 'zod', 145 - variant: 'infer', 135 + ? plugin.symbol( 136 + applyNaming(operation.id, plugin.config.webhooks.types.infer), 137 + { 138 + meta: { 139 + category: 'type', 140 + path: fromRef(state.path), 141 + resource: 'webhook', 142 + resourceId: operation.id, 143 + role: 'data', 144 + tags: fromRef(state.tags), 145 + tool: 'zod', 146 + variant: 'infer', 147 + }, 146 148 }, 147 - name: buildName({ 148 - config: plugin.config.webhooks.types.infer, 149 - name: operation.id, 150 - }), 151 - }) 149 + ) 152 150 : undefined; 153 151 exportAst({ 154 152 ast,
+46 -46
packages/openapi-ts/src/plugins/zod/types.d.ts
··· 9 9 } from '~/plugins/shared/utils/coerce'; 10 10 import type { GetIntegerLimit } from '~/plugins/shared/utils/formats'; 11 11 import type { $, DollarTsDsl, TsDsl } from '~/ts-dsl'; 12 - import type { StringCase, StringName } from '~/types/case'; 13 12 import type { MaybeArray } from '~/types/utils'; 13 + import type { Casing, NameTransformer } from '~/utils/naming'; 14 14 15 15 import type { IApi } from './api'; 16 16 import type { Chain } from './shared/chain'; ··· 24 24 * 25 25 * @default 'camelCase' 26 26 */ 27 - case?: StringCase; 27 + case?: Casing; 28 28 /** 29 29 * Add comments from input to the generated Zod schemas? 30 30 * ··· 83 83 */ 84 84 definitions?: 85 85 | boolean 86 - | StringName 86 + | NameTransformer 87 87 | { 88 88 /** 89 89 * The casing convention to use for generated names. 90 90 * 91 91 * @default 'camelCase' 92 92 */ 93 - case?: StringCase; 93 + case?: Casing; 94 94 /** 95 95 * Whether to generate Zod schemas for reusable definitions. 96 96 * ··· 103 103 * 104 104 * @default 'z{{name}}' 105 105 */ 106 - name?: StringName; 106 + name?: NameTransformer; 107 107 /** 108 108 * Configuration for TypeScript type generation from Zod schemas. 109 109 * ··· 122 122 */ 123 123 infer?: 124 124 | boolean 125 - | StringName 125 + | NameTransformer 126 126 | { 127 127 /** 128 128 * The casing convention to use for generated type names. 129 129 * 130 130 * @default 'PascalCase' 131 131 */ 132 - case?: StringCase; 132 + case?: Casing; 133 133 /** 134 134 * Whether to generate TypeScript types from Zod schemas. 135 135 * ··· 142 142 * 143 143 * @default '{{name}}ZodType' 144 144 */ 145 - name?: StringName; 145 + name?: NameTransformer; 146 146 }; 147 147 }; 148 148 }; ··· 176 176 */ 177 177 requests?: 178 178 | boolean 179 - | StringName 179 + | NameTransformer 180 180 | { 181 181 /** 182 182 * The casing convention to use for generated names. 183 183 * 184 184 * @default 'camelCase' 185 185 */ 186 - case?: StringCase; 186 + case?: Casing; 187 187 /** 188 188 * Whether to generate Zod schemas for request definitions. 189 189 * ··· 196 196 * 197 197 * @default 'z{{name}}Data' 198 198 */ 199 - name?: StringName; 199 + name?: NameTransformer; 200 200 /** 201 201 * Configuration for TypeScript type generation from Zod schemas. 202 202 * ··· 215 215 */ 216 216 infer?: 217 217 | boolean 218 - | StringName 218 + | NameTransformer 219 219 | { 220 220 /** 221 221 * The casing convention to use for generated type names. 222 222 * 223 223 * @default 'PascalCase' 224 224 */ 225 - case?: StringCase; 225 + case?: Casing; 226 226 /** 227 227 * Whether to generate TypeScript types from Zod schemas. 228 228 * ··· 235 235 * 236 236 * @default '{{name}}DataZodType' 237 237 */ 238 - name?: StringName; 238 + name?: NameTransformer; 239 239 }; 240 240 }; 241 241 }; ··· 254 254 */ 255 255 responses?: 256 256 | boolean 257 - | StringName 257 + | NameTransformer 258 258 | { 259 259 /** 260 260 * The casing convention to use for generated names. 261 261 * 262 262 * @default 'camelCase' 263 263 */ 264 - case?: StringCase; 264 + case?: Casing; 265 265 /** 266 266 * Whether to generate Zod schemas for response definitions. 267 267 * ··· 274 274 * 275 275 * @default 'z{{name}}Response' 276 276 */ 277 - name?: StringName; 277 + name?: NameTransformer; 278 278 /** 279 279 * Configuration for TypeScript type generation from Zod schemas. 280 280 * ··· 293 293 */ 294 294 infer?: 295 295 | boolean 296 - | StringName 296 + | NameTransformer 297 297 | { 298 298 /** 299 299 * The casing convention to use for generated type names. 300 300 * 301 301 * @default 'PascalCase' 302 302 */ 303 - case?: StringCase; 303 + case?: Casing; 304 304 /** 305 305 * Whether to generate TypeScript types from Zod schemas. 306 306 * ··· 313 313 * 314 314 * @default '{{name}}ResponseZodType' 315 315 */ 316 - name?: StringName; 316 + name?: NameTransformer; 317 317 }; 318 318 }; 319 319 }; ··· 335 335 */ 336 336 infer?: 337 337 | boolean 338 - | StringName 338 + | NameTransformer 339 339 | { 340 340 /** 341 341 * The casing convention to use for generated type names. 342 342 * 343 343 * @default 'PascalCase' 344 344 */ 345 - case?: StringCase; 345 + case?: Casing; 346 346 /** 347 347 * Whether to generate TypeScript types from Zod schemas. 348 348 * ··· 365 365 */ 366 366 webhooks?: 367 367 | boolean 368 - | StringName 368 + | NameTransformer 369 369 | { 370 370 /** 371 371 * The casing convention to use for generated names. 372 372 * 373 373 * @default 'camelCase' 374 374 */ 375 - case?: StringCase; 375 + case?: Casing; 376 376 /** 377 377 * Whether to generate Zod schemas for webhook definitions. 378 378 * ··· 385 385 * 386 386 * @default 'z{{name}}WebhookRequest' 387 387 */ 388 - name?: StringName; 388 + name?: NameTransformer; 389 389 /** 390 390 * Configuration for TypeScript type generation from Zod schemas. 391 391 * ··· 404 404 */ 405 405 infer?: 406 406 | boolean 407 - | StringName 407 + | NameTransformer 408 408 | { 409 409 /** 410 410 * The casing convention to use for generated type names. 411 411 * 412 412 * @default 'PascalCase' 413 413 */ 414 - case?: StringCase; 414 + case?: Casing; 415 415 /** 416 416 * Whether to generate TypeScript types from Zod schemas. 417 417 * ··· 424 424 * 425 425 * @default '{{name}}WebhookRequestZodType' 426 426 */ 427 - name?: StringName; 427 + name?: NameTransformer; 428 428 }; 429 429 }; 430 430 }; ··· 438 438 * 439 439 * @default 'camelCase' 440 440 */ 441 - case: StringCase; 441 + case: Casing; 442 442 /** 443 443 * Add comments from input to the generated Zod schemas? 444 444 * ··· 494 494 * 495 495 * @default 'camelCase' 496 496 */ 497 - case: StringCase; 497 + case: Casing; 498 498 /** 499 499 * Whether to generate Zod schemas for reusable definitions. 500 500 * ··· 507 507 * 508 508 * @default 'z{{name}}' 509 509 */ 510 - name: StringName; 510 + name: NameTransformer; 511 511 /** 512 512 * Configuration for TypeScript type generation from Zod schemas. 513 513 * ··· 523 523 * 524 524 * @default 'PascalCase' 525 525 */ 526 - case: StringCase; 526 + case: Casing; 527 527 /** 528 528 * Whether to generate TypeScript types from Zod schemas. 529 529 * ··· 536 536 * 537 537 * @default '{{name}}ZodType' 538 538 */ 539 - name: StringName; 539 + name: NameTransformer; 540 540 }; 541 541 }; 542 542 }; ··· 567 567 * 568 568 * @default 'camelCase' 569 569 */ 570 - case: StringCase; 570 + case: Casing; 571 571 /** 572 572 * Whether to generate Zod schemas for request definitions. 573 573 * ··· 580 580 * 581 581 * @default 'z{{name}}Data' 582 582 */ 583 - name: StringName; 583 + name: NameTransformer; 584 584 /** 585 585 * Configuration for TypeScript type generation from Zod schemas. 586 586 * ··· 596 596 * 597 597 * @default 'PascalCase' 598 598 */ 599 - case: StringCase; 599 + case: Casing; 600 600 /** 601 601 * Whether to generate TypeScript types from Zod schemas. 602 602 * ··· 609 609 * 610 610 * @default '{{name}}DataZodType' 611 611 */ 612 - name: StringName; 612 + name: NameTransformer; 613 613 }; 614 614 }; 615 615 }; ··· 625 625 * 626 626 * @default 'camelCase' 627 627 */ 628 - case: StringCase; 628 + case: Casing; 629 629 /** 630 630 * Whether to generate Zod schemas for response definitions. 631 631 * ··· 638 638 * 639 639 * @default 'z{{name}}Response' 640 640 */ 641 - name: StringName; 641 + name: NameTransformer; 642 642 /** 643 643 * Configuration for TypeScript type generation from Zod schemas. 644 644 * ··· 654 654 * 655 655 * @default 'PascalCase' 656 656 */ 657 - case: StringCase; 657 + case: Casing; 658 658 /** 659 659 * Whether to generate TypeScript types from Zod schemas. 660 660 * ··· 667 667 * 668 668 * @default '{{name}}ResponseZodType' 669 669 */ 670 - name: StringName; 670 + name: NameTransformer; 671 671 }; 672 672 }; 673 673 }; ··· 686 686 * 687 687 * @default 'PascalCase' 688 688 */ 689 - case: StringCase; 689 + case: Casing; 690 690 /** 691 691 * Whether to generate TypeScript types from Zod schemas. 692 692 * ··· 706 706 * 707 707 * @default 'camelCase' 708 708 */ 709 - case: StringCase; 709 + case: Casing; 710 710 /** 711 711 * Whether to generate Zod schemas for webhook definitions. 712 712 * ··· 719 719 * 720 720 * @default 'z{{name}}WebhookRequest' 721 721 */ 722 - name: StringName; 722 + name: NameTransformer; 723 723 /** 724 724 * Configuration for TypeScript type generation from Zod schemas. 725 725 * ··· 735 735 * 736 736 * @default 'PascalCase' 737 737 */ 738 - case: StringCase; 738 + case: Casing; 739 739 /** 740 740 * Whether to generate TypeScript types from Zod schemas. 741 741 * ··· 748 748 * 749 749 * @default '{{name}}WebhookRequestZodType' 750 750 */ 751 - name: StringName; 751 + name: NameTransformer; 752 752 }; 753 753 }; 754 754 };
+27 -30
packages/openapi-ts/src/plugins/zod/v3/plugin.ts
··· 3 3 4 4 import { deduplicateSchema } from '~/ir/schema'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import type { SchemaWithType } from '~/plugins'; 8 7 import { maybeBigInt } from '~/plugins/shared/utils/coerce'; 9 8 import { $ } from '~/ts-dsl'; 9 + import { applyNaming } from '~/utils/naming'; 10 10 import { pathToJsonPointer, refToName } from '~/utils/ref'; 11 11 12 12 import { identifiers } from '../constants'; ··· 170 170 const $ref = pathToJsonPointer(fromRef(state.path)); 171 171 const ast = irSchemaToAst({ plugin, schema, state }); 172 172 const baseName = refToName($ref); 173 - const symbol = plugin.registerSymbol({ 174 - meta: { 175 - category: 'schema', 176 - path: fromRef(state.path), 177 - resource: 'definition', 178 - resourceId: $ref, 179 - tags: fromRef(state.tags), 180 - tool: 'zod', 173 + const symbol = plugin.symbol( 174 + applyNaming(baseName, plugin.config.definitions), 175 + { 176 + meta: { 177 + category: 'schema', 178 + path: fromRef(state.path), 179 + resource: 'definition', 180 + resourceId: $ref, 181 + tags: fromRef(state.tags), 182 + tool: 'zod', 183 + }, 181 184 }, 182 - name: buildName({ 183 - config: plugin.config.definitions, 184 - name: baseName, 185 - }), 186 - }); 185 + ); 187 186 const typeInferSymbol = plugin.config.definitions.types.infer.enabled 188 - ? plugin.registerSymbol({ 189 - meta: { 190 - category: 'type', 191 - path: fromRef(state.path), 192 - resource: 'definition', 193 - resourceId: $ref, 194 - tags: fromRef(state.tags), 195 - tool: 'zod', 196 - variant: 'infer', 187 + ? plugin.symbol( 188 + applyNaming(baseName, plugin.config.definitions.types.infer), 189 + { 190 + meta: { 191 + category: 'type', 192 + path: fromRef(state.path), 193 + resource: 'definition', 194 + resourceId: $ref, 195 + tags: fromRef(state.tags), 196 + tool: 'zod', 197 + variant: 'infer', 198 + }, 197 199 }, 198 - name: buildName({ 199 - config: plugin.config.definitions.types.infer, 200 - name: baseName, 201 - }), 202 - }) 200 + ) 203 201 : undefined; 204 202 exportAst({ 205 203 ast, ··· 211 209 }; 212 210 213 211 export const handlerV3: ZodPlugin['Handler'] = ({ plugin }) => { 214 - plugin.registerSymbol({ 212 + plugin.symbol('z', { 215 213 external: getZodModule({ plugin }), 216 214 meta: { 217 215 category: 'external', 218 216 resource: 'zod.z', 219 217 }, 220 - name: 'z', 221 218 }); 222 219 223 220 plugin.forEach(
+27 -30
packages/openapi-ts/src/plugins/zod/v4/plugin.ts
··· 3 3 4 4 import { deduplicateSchema } from '~/ir/schema'; 5 5 import type { IR } from '~/ir/types'; 6 - import { buildName } from '~/openApi/shared/utils/name'; 7 6 import type { SchemaWithType } from '~/plugins'; 8 7 import { maybeBigInt } from '~/plugins/shared/utils/coerce'; 9 8 import { $ } from '~/ts-dsl'; 9 + import { applyNaming } from '~/utils/naming'; 10 10 import { pathToJsonPointer, refToName } from '~/utils/ref'; 11 11 12 12 import { identifiers } from '../constants'; ··· 178 178 const $ref = pathToJsonPointer(fromRef(state.path)); 179 179 const ast = irSchemaToAst({ plugin, schema, state }); 180 180 const baseName = refToName($ref); 181 - const symbol = plugin.registerSymbol({ 182 - meta: { 183 - category: 'schema', 184 - path: fromRef(state.path), 185 - resource: 'definition', 186 - resourceId: $ref, 187 - tags: fromRef(state.tags), 188 - tool: 'zod', 181 + const symbol = plugin.symbol( 182 + applyNaming(baseName, plugin.config.definitions), 183 + { 184 + meta: { 185 + category: 'schema', 186 + path: fromRef(state.path), 187 + resource: 'definition', 188 + resourceId: $ref, 189 + tags: fromRef(state.tags), 190 + tool: 'zod', 191 + }, 189 192 }, 190 - name: buildName({ 191 - config: plugin.config.definitions, 192 - name: baseName, 193 - }), 194 - }); 193 + ); 195 194 const typeInferSymbol = plugin.config.definitions.types.infer.enabled 196 - ? plugin.registerSymbol({ 197 - meta: { 198 - category: 'type', 199 - path: fromRef(state.path), 200 - resource: 'definition', 201 - resourceId: $ref, 202 - tags: fromRef(state.tags), 203 - tool: 'zod', 204 - variant: 'infer', 195 + ? plugin.symbol( 196 + applyNaming(baseName, plugin.config.definitions.types.infer), 197 + { 198 + meta: { 199 + category: 'type', 200 + path: fromRef(state.path), 201 + resource: 'definition', 202 + resourceId: $ref, 203 + tags: fromRef(state.tags), 204 + tool: 'zod', 205 + variant: 'infer', 206 + }, 205 207 }, 206 - name: buildName({ 207 - config: plugin.config.definitions.types.infer, 208 - name: baseName, 209 - }), 210 - }) 208 + ) 211 209 : undefined; 212 210 exportAst({ 213 211 ast, ··· 219 217 }; 220 218 221 219 export const handlerV4: ZodPlugin['Handler'] = ({ plugin }) => { 222 - plugin.registerSymbol({ 220 + plugin.symbol('z', { 223 221 external: getZodModule({ plugin }), 224 222 meta: { 225 223 category: 'external', 226 224 resource: 'zod.z', 227 225 }, 228 - name: 'z', 229 226 }); 230 227 231 228 plugin.forEach(
-8
packages/openapi-ts/src/types/case.d.ts
··· 1 - export type StringCase = 2 - | 'camelCase' 3 - | 'PascalCase' 4 - | 'preserve' 5 - | 'snake_case' 6 - | 'SCREAMING_SNAKE_CASE'; 7 - 8 - export type StringName = string | ((name: string) => string);
+8 -8
packages/openapi-ts/src/types/output.d.ts
··· 1 1 import type { NameConflictResolver } from '@hey-api/codegen-core'; 2 2 import type ts from 'typescript'; 3 3 4 - import type { StringCase, StringName } from './case'; 4 + import type { Casing, NameTransformer } from '~/utils/naming'; 5 5 6 6 export type Formatters = 'biome' | 'prettier'; 7 7 ··· 16 16 * 17 17 * @default undefined 18 18 */ 19 - case?: StringCase; 19 + case?: Casing; 20 20 /** 21 21 * Clean the `output` folder on every run? If disabled, this folder may 22 22 * be used to store additional files. The default option is `true` to ··· 34 34 * @default '{{name}}' 35 35 */ 36 36 fileName?: 37 - | StringName 37 + | NameTransformer 38 38 | { 39 39 /** 40 40 * The casing convention to use for generated file names. 41 41 * 42 42 * @default 'preserve' 43 43 */ 44 - case?: StringCase; 44 + case?: Casing; 45 45 /** 46 46 * Custom naming pattern for generated file names. 47 47 * 48 48 * @default '{{name}}' 49 49 */ 50 - name?: StringName; 50 + name?: NameTransformer; 51 51 /** 52 52 * Suffix to append to file names (before the extension). For example, 53 53 * with a suffix of `.gen`, `example.ts` becomes `example.gen.ts`. ··· 128 128 * Defines casing of the output fields. By default, we preserve `input` 129 129 * values as data transforms incur a performance penalty at runtime. 130 130 */ 131 - case: StringCase | undefined; 131 + case: Casing | undefined; 132 132 /** 133 133 * Clean the `output` folder on every run? If disabled, this folder may 134 134 * be used to store additional files. The default option is `true` to ··· 146 146 /** 147 147 * The casing convention to use for generated file names. 148 148 */ 149 - case: StringCase; 149 + case: Casing; 150 150 /** 151 151 * Custom naming pattern for generated file names. 152 152 */ 153 - name: StringName; 153 + name: NameTransformer; 154 154 /** 155 155 * Suffix to append to file names (before the extension). For example, 156 156 * with a suffix of `.gen`, `example.ts` becomes `example.gen.ts`.
+15 -16
packages/openapi-ts/src/types/parser.d.ts
··· 7 7 OpenApiSchemaObject, 8 8 } from '~/openApi/types'; 9 9 import type { Hooks } from '~/parser/types/hooks'; 10 - 11 - import type { StringCase, StringName } from './case'; 10 + import type { Casing, NameTransformer } from '~/utils/naming'; 12 11 13 12 type EnumsMode = 'inline' | 'root'; 14 13 ··· 73 72 * 74 73 * @default 'PascalCase' 75 74 */ 76 - case?: StringCase; 75 + case?: Casing; 77 76 /** 78 77 * Whether to transform all enums. 79 78 * ··· 92 91 * 93 92 * @default '{{name}}Enum' 94 93 */ 95 - name?: StringName; 94 + name?: NameTransformer; 96 95 }; 97 96 /** 98 97 * By default, any object schema with a missing `required` keyword is ··· 137 136 * @default '{{name}}Writable' 138 137 */ 139 138 requests?: 140 - | StringName 139 + | NameTransformer 141 140 | { 142 141 /** 143 142 * The casing convention to use for generated names. 144 143 * 145 144 * @default 'preserve' 146 145 */ 147 - case?: StringCase; 146 + case?: Casing; 148 147 /** 149 148 * Customize the generated name of schemas used in requests or 150 149 * containing write-only fields. 151 150 * 152 151 * @default '{{name}}Writable' 153 152 */ 154 - name?: StringName; 153 + name?: NameTransformer; 155 154 }; 156 155 /** 157 156 * Configuration for generated response-specific schemas. ··· 163 162 * @default '{{name}}' 164 163 */ 165 164 responses?: 166 - | StringName 165 + | NameTransformer 167 166 | { 168 167 /** 169 168 * The casing convention to use for generated names. 170 169 * 171 170 * @default 'preserve' 172 171 */ 173 - case?: StringCase; 172 + case?: Casing; 174 173 /** 175 174 * Customize the generated name of schemas used in responses or 176 175 * containing read-only fields. We default to the original name ··· 178 177 * 179 178 * @default '{{name}}' 180 179 */ 181 - name?: StringName; 180 + name?: NameTransformer; 182 181 }; 183 182 }; 184 183 }; ··· 250 249 * 251 250 * @default 'PascalCase' 252 251 */ 253 - case: StringCase; 252 + case: Casing; 254 253 /** 255 254 * Whether to transform all enums. 256 255 * ··· 269 268 * 270 269 * @default '{{name}}Enum' 271 270 */ 272 - name: StringName; 271 + name: NameTransformer; 273 272 }; 274 273 /** 275 274 * By default, any object schema with a missing `required` keyword is ··· 309 308 * 310 309 * @default 'preserve' 311 310 */ 312 - case: StringCase; 311 + case: Casing; 313 312 /** 314 313 * Customize the generated name of schemas used in requests or 315 314 * containing write-only fields. 316 315 * 317 316 * @default '{{name}}Writable' 318 317 */ 319 - name: StringName; 318 + name: NameTransformer; 320 319 }; 321 320 /** 322 321 * Configuration for generated response-specific schemas. ··· 327 326 * 328 327 * @default 'preserve' 329 328 */ 330 - case: StringCase; 329 + case: Casing; 331 330 /** 332 331 * Customize the generated name of schemas used in responses or 333 332 * containing read-only fields. We default to the original name ··· 335 334 * 336 335 * @default '{{name}}' 337 336 */ 338 - name: StringName; 337 + name: NameTransformer; 339 338 }; 340 339 }; 341 340 };
+3 -4
packages/openapi-ts/src/utils/__tests__/to-case.test.ts packages/openapi-ts/src/utils/naming/__tests__/naming.test.ts
··· 1 1 import { describe, expect, it } from 'vitest'; 2 2 3 - import type { StringCase } from '~/types/case'; 3 + import { toCase } from '../naming'; 4 + import type { Casing } from '../types'; 4 5 5 - import { toCase } from '../to-case'; 6 - 7 - const cases: ReadonlyArray<StringCase> = [ 6 + const cases: ReadonlyArray<Casing> = [ 8 7 'camelCase', 9 8 'PascalCase', 10 9 'SCREAMING_SNAKE_CASE',
+3 -4
packages/openapi-ts/src/utils/exports.ts
··· 1 - import type { StringCase } from '~/types/case'; 2 - 3 - import { toCase } from './to-case'; 1 + import type { Casing } from './naming'; 2 + import { toCase } from './naming'; 4 3 5 4 /** 6 5 * Utilities shared across the package. ··· 14 13 stripLeadingSeparators, 15 14 value, 16 15 }: { 17 - readonly case: StringCase | undefined; 16 + readonly case: Casing | undefined; 18 17 /** 19 18 * If leading separators have a semantic meaning, we might not want to 20 19 * remove them.
+7
packages/openapi-ts/src/utils/naming/index.ts
··· 1 + export { applyNaming, resolveNaming, toCase } from './naming'; 2 + export type { 3 + Casing, 4 + NameTransformer, 5 + NamingConfig, 6 + NamingRule, 7 + } from './types';
+43
packages/openapi-ts/src/utils/naming/types.d.ts
··· 1 + /** 2 + * Available casing strategies. 3 + */ 4 + export type Casing = 5 + | 'camelCase' 6 + | 'PascalCase' 7 + | 'preserve' 8 + | 'snake_case' 9 + | 'SCREAMING_SNAKE_CASE'; 10 + 11 + /** 12 + * Name transformer: template string or function. 13 + * 14 + * Template supports `{{name}}` variable. 15 + */ 16 + export type NameTransformer = string | ((name: string) => string); 17 + 18 + /** 19 + * Full naming configuration. 20 + */ 21 + export interface NamingConfig { 22 + /** 23 + * Casing strategy applied after transformation. 24 + * 25 + * @deprecated Use `casing` instead. 26 + */ 27 + case?: Casing; 28 + /** 29 + * Casing strategy applied after transformation. 30 + */ 31 + casing?: Casing; 32 + /** 33 + * Name template or transformer function. 34 + * 35 + * Applied before `casing` transformation. 36 + */ 37 + name?: NameTransformer; 38 + } 39 + 40 + /** 41 + * Name customization: shorthand or full configuration. 42 + */ 43 + export type NamingRule = NameTransformer | NamingConfig;
+44 -4
packages/openapi-ts/src/utils/to-case.ts packages/openapi-ts/src/utils/naming/naming.ts
··· 1 - import type { StringCase } from '~/types/case'; 1 + import type { Casing, NamingConfig, NamingRule } from './types'; 2 2 3 3 const uppercaseRegExp = /[\p{Lu}]/u; 4 4 const lowercaseRegExp = /[\p{Ll}]/u; ··· 15 15 'gu', 16 16 ); 17 17 18 - const preserveCase = (value: string, casing: StringCase) => { 18 + const preserveCase = (value: string, casing: Casing) => { 19 19 let isLastCharLower = false; 20 20 let isLastCharUpper = false; 21 21 let isLastLastCharUpper = false; ··· 84 84 }; 85 85 86 86 /** 87 - * Converts the given string to the specified casing. 87 + * Convert a string to the specified casing. 88 88 * 89 89 * @param value - The string to convert 90 90 * @param casing - The target casing ··· 93 93 */ 94 94 export const toCase = ( 95 95 value: string, 96 - casing: StringCase | undefined, 96 + casing: Casing | undefined, 97 97 options: { 98 98 /** 99 99 * If leading separators have a semantic meaning, we might not want to ··· 188 188 189 189 return result; 190 190 }; 191 + 192 + /** 193 + * Normalize a NamingRule to NamingConfig. 194 + */ 195 + export function resolveNaming(rule: NamingRule | undefined): NamingConfig { 196 + if (!rule) { 197 + return {}; 198 + } 199 + if (typeof rule === 'string' || typeof rule === 'function') { 200 + return { name: rule }; 201 + } 202 + return rule; 203 + } 204 + 205 + /** 206 + * Apply naming configuration to a value. 207 + * 208 + * Casing is applied first, then transformation. 209 + */ 210 + export function applyNaming(value: string, config: NamingConfig): string { 211 + let result = value; 212 + 213 + const casing = config.casing ?? config.case; 214 + 215 + if (config.name) { 216 + if (typeof config.name === 'function') { 217 + result = config.name(result); 218 + } else { 219 + // TODO: refactor so there's no need for separators? 220 + const separator = casing === 'preserve' ? '' : '-'; 221 + result = config.name.replace( 222 + '{{name}}', 223 + `${separator}${result}${separator}`, 224 + ); 225 + } 226 + } 227 + 228 + // TODO: apply case before name? 229 + return toCase(result, casing); 230 + }
+6
pnpm-lock.yaml
··· 112 112 113 113 dev: 114 114 devDependencies: 115 + '@angular/common': 116 + specifier: 19.2.17 117 + version: 19.2.17(@angular/core@19.2.17(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2) 118 + '@angular/core': 119 + specifier: 19.2.17 120 + version: 19.2.17(rxjs@7.8.2)(zone.js@0.16.0) 115 121 '@hey-api/codegen-core': 116 122 specifier: workspace:* 117 123 version: link:../packages/codegen-core