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

Merge pull request #3101 from hey-api/refactor/sdk-class-name

refactor: clean up class name logic

authored by

Lubos and committed by
GitHub
dfad1ca2 72d36102

+29 -92
+4 -4
dev/openapi-ts.config.ts
··· 38 38 // }, 39 39 path: path.resolve( 40 40 getSpecsPath(), 41 - // '3.0.x', 42 - '3.1.x', 41 + '3.0.x', 42 + // '3.1.x', 43 43 // 'circular.yaml', 44 44 // 'dutchie.json', 45 45 // 'enum-names-values.yaml', ··· 52 52 // 'pagination-ref.yaml', 53 53 // 'schema-const.yaml', 54 54 // 'sdk-instance.yaml', 55 - // 'sdk-method-class-conflict.yaml', 55 + 'sdk-method-class-conflict.yaml', 56 56 // 'sdk-nested-classes.yaml', 57 - 'sdk-nested-conflict.yaml', 57 + // 'sdk-nested-conflict.yaml', 58 58 // 'string-with-format.yaml', 59 59 // 'transformers.json', 60 60 // 'transformers-recursive.json',
+1 -5
packages/openapi-ts/src/plugins/@angular/common/httpRequests.ts
··· 38 38 operation, 39 39 }); 40 40 41 - const classes = operationClasses({ 42 - context: plugin.context, 43 - operation, 44 - plugin: sdkPlugin, 45 - }); 41 + const classes = operationClasses({ operation, plugin: sdkPlugin }); 46 42 47 43 for (const entry of classes.values()) { 48 44 entry.path.forEach((currentClassName, index) => {
+2 -10
packages/openapi-ts/src/plugins/@angular/common/httpResources.ts
··· 38 38 operation, 39 39 }); 40 40 41 - const classes = operationClasses({ 42 - context: plugin.context, 43 - operation, 44 - plugin: sdkPlugin, 45 - }); 41 + const classes = operationClasses({ operation, plugin: sdkPlugin }); 46 42 47 43 for (const entry of classes.values()) { 48 44 entry.path.forEach((currentClassName, index) => { ··· 216 212 217 213 if (plugin.config.httpRequests.asClass) { 218 214 // For class-based request methods, use inject and class hierarchy 219 - const classes = operationClasses({ 220 - context: plugin.context, 221 - operation, 222 - plugin: sdkPlugin, 223 - }); 215 + const classes = operationClasses({ operation, plugin: sdkPlugin }); 224 216 225 217 const firstEntry = Array.from(classes.values())[0]; 226 218 if (firstEntry) {
+1 -5
packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts
··· 181 181 }) 182 182 : undefined; 183 183 184 - const classes = operationClasses({ 185 - context: plugin.context, 186 - operation, 187 - plugin, 188 - }); 184 + const classes = operationClasses({ operation, plugin }); 189 185 190 186 for (const entry of classes.values()) { 191 187 entry.path.forEach((currentClassName, index) => {
+16 -27
packages/openapi-ts/src/plugins/@hey-api/sdk/shared/operation.ts
··· 1 1 import type { SymbolMeta } from '@hey-api/codegen-core'; 2 2 import { refs } from '@hey-api/codegen-core'; 3 3 4 - import type { Context } from '~/ir/context'; 5 4 import { statusCodeToGroup } from '~/ir/operation'; 6 5 import type { IR } from '~/ir/types'; 7 6 import { sanitizeNamespaceIdentifier } from '~/openApi/common/parser/sanitize'; 8 7 import { getClientPlugin } from '~/plugins/@hey-api/client-core/utils'; 9 8 import { $ } from '~/ts-dsl'; 10 9 import { stringCase } from '~/utils/stringCase'; 11 - import { transformClassName } from '~/utils/transform'; 12 10 13 11 import type { Field, Fields } from '../../client-core/bundle/params'; 14 12 import type { HeyApiSdkPlugin } from '../types'; ··· 18 16 import { getSignatureParameters } from './signature'; 19 17 import { createRequestValidator, createResponseValidator } from './validator'; 20 18 19 + type Plugin = { 20 + config: Pick< 21 + HeyApiSdkPlugin['Instance']['config'], 22 + 'asClass' | 'classNameBuilder' | 'classStructure' | 'instance' 23 + >; 24 + }; 25 + 21 26 interface ClassNameEntry { 22 27 /** 23 28 * Name of the class where this function appears. ··· 34 39 } 35 40 36 41 const operationClassName = ({ 37 - context, 42 + plugin, 38 43 value, 39 44 }: { 40 - context: Context; 45 + plugin: Plugin; 41 46 value: string; 42 47 }) => { 43 - const name = stringCase({ 44 - case: 'PascalCase', 45 - value: sanitizeNamespaceIdentifier(value), 46 - }); 47 - return transformClassName({ 48 - config: context.config, 49 - name, 50 - }); 48 + const name = stringCase({ case: 'PascalCase', value }); 49 + return typeof plugin.config.classNameBuilder === 'string' 50 + ? plugin.config.classNameBuilder.replace('{{name}}', name) 51 + : plugin.config.classNameBuilder(name); 51 52 }; 52 53 53 54 const getOperationMethodName = ({ ··· 78 79 * Returns a list of classes where this operation appears in the generated SDK. 79 80 */ 80 81 export const operationClasses = ({ 81 - context, 82 82 operation, 83 83 plugin, 84 84 }: { 85 - context: Context; 86 85 operation: IR.OperationObject; 87 - plugin: { 88 - config: Pick< 89 - HeyApiSdkPlugin['Instance']['config'], 90 - 'asClass' | 'classStructure' | 'instance' 91 - >; 92 - }; 86 + plugin: Plugin; 93 87 }): Map<string, ClassNameEntry> => { 94 88 const classNames = new Map<string, ClassNameEntry>(); 95 89 ··· 115 109 116 110 for (const rootClass of rootClasses) { 117 111 const finalClassName = operationClassName({ 118 - context, 112 + plugin, 119 113 value: className || rootClass, 120 114 }); 121 115 ··· 134 128 classNames.set(rootClass, { 135 129 className: finalClassName, 136 130 methodName: methodName || getOperationMethodName({ operation, plugin }), 137 - path: path.map((value) => 138 - operationClassName({ 139 - context, 140 - value, 141 - }), 142 - ), 131 + path: path.map((value) => operationClassName({ plugin, value })), 143 132 }); 144 133 } 145 134
+1 -5
packages/openapi-ts/src/plugins/@pinia/colada/v0/plugin.ts
··· 59 59 'operation', 60 60 ({ operation }) => { 61 61 const classes = sdkPlugin.config.asClass 62 - ? operationClasses({ 63 - context: plugin.context, 64 - operation, 65 - plugin: sdkPlugin, 66 - }) 62 + ? operationClasses({ operation, plugin: sdkPlugin }) 67 63 : undefined; 68 64 const entry = classes ? classes.values().next().value : undefined; 69 65 // TODO: this should use class graph to determine correct path string
+1 -5
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/plugin.ts
··· 83 83 'operation', 84 84 ({ operation }) => { 85 85 const classes = sdkPlugin.config.asClass 86 - ? operationClasses({ 87 - context: plugin.context, 88 - operation, 89 - plugin: sdkPlugin, 90 - }) 86 + ? operationClasses({ operation, plugin: sdkPlugin }) 91 87 : undefined; 92 88 const entry = classes ? classes.values().next().value : undefined; 93 89 // TODO: this should use class graph to determine correct path string
+1 -5
packages/openapi-ts/src/plugins/swr/v2/plugin.ts
··· 24 24 'operation', 25 25 ({ operation }) => { 26 26 const classes = sdkPlugin.config.asClass 27 - ? operationClasses({ 28 - context: plugin.context, 29 - operation, 30 - plugin: sdkPlugin, 31 - }) 27 + ? operationClasses({ operation, plugin: sdkPlugin }) 32 28 : undefined; 33 29 const entry = classes ? classes.values().next().value : undefined; 34 30 // TODO: this should use class graph to determine correct path string
+1 -1
packages/openapi-ts/src/utils/__tests__/stringCase.test.ts
··· 136 136 SCREAMING_SNAKE_CASE: 'IO_K8S_APIMACHINERY_PKG_APIS_META_V1_DELETE_OPTIONS', 137 137 camelCase: 'ioK8sApimachineryPkgApisMetaV1DeleteOptions', 138 138 snake_case: 'io_k8s_apimachinery_pkg_apis_meta_v1_delete_options', 139 - value: 'io.k8sApimachinery.pkg.apis.meta.v1.DeleteOptions', 139 + value: 'io.k8sApimachinery.pkg.apis.meta:v1.DeleteOptions', 140 140 }, 141 141 { 142 142 PascalCase: 'GenericSchemaDuplicateIssue1SystemBoolean',
+1 -1
packages/openapi-ts/src/utils/stringCase.ts
··· 3 3 const uppercaseRegExp = /[\p{Lu}]/u; 4 4 const lowercaseRegExp = /[\p{Ll}]/u; 5 5 const identifierRegExp = /([\p{Alpha}\p{N}_]|$)/u; 6 - const separatorsRegExp = /[_.\- `\\[\]{}\\/]+/; 6 + const separatorsRegExp = /[_.:\- `\\[\]{}\\/]+/; 7 7 8 8 const leadingSeparatorsRegExp = new RegExp(`^${separatorsRegExp.source}`); 9 9 const separatorsAndIdentifierRegExp = new RegExp(
-24
packages/openapi-ts/src/utils/transform.ts
··· 1 - import type { Config } from '~/types/config'; 2 - 3 - export const transformClassName = ({ 4 - config, 5 - name, 6 - }: { 7 - config: Config; 8 - name: string; 9 - }) => { 10 - const plugin = config.plugins['@hey-api/sdk']; 11 - if (plugin?.config.classNameBuilder) { 12 - let customName = ''; 13 - 14 - if (typeof plugin.config.classNameBuilder === 'function') { 15 - customName = plugin.config.classNameBuilder(name); 16 - } else { 17 - customName = plugin.config.classNameBuilder.replace('{{name}}', name); 18 - } 19 - 20 - return customName; 21 - } 22 - 23 - return name; 24 - };