From f481f5cb11f9a8a5e0b1a0baee367f07dd327730 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 14 Dec 2025 22:59:35 +0800 Subject: [PATCH] feat(sdk): lazily initialize sub-resources to improve performance --- .changeset/major-cats-divide.md | 5 + dev/openapi-ts.config.ts | 3 +- .../sdk-nested-classes-instance/sdk.gen.ts | 15 +- .../plugins/@hey-api/sdk/instance/sdk.gen.ts | 10 +- .../sdk-nested-classes-instance/sdk.gen.ts | 15 +- .../plugins/@hey-api/sdk/instance/sdk.gen.ts | 10 +- .../sdk-nested-classes-instance/sdk.gen.ts | 15 +- .../plugins/@hey-api/sdk/instance/sdk.gen.ts | 10 +- .../method-class-conflict/instance/sdk.gen.ts | 125 +++++++++++--- .../src/plugins/@hey-api/sdk/shared/class.ts | 160 ++++++++---------- packages/openapi-ts/src/ts-dsl/decl/field.ts | 16 +- packages/openapi-ts/src/ts-dsl/decl/func.ts | 24 ++- packages/openapi-ts/src/ts-dsl/decl/getter.ts | 9 +- packages/openapi-ts/src/ts-dsl/decl/method.ts | 20 +-- packages/openapi-ts/src/ts-dsl/expr/binary.ts | 7 + .../openapi-ts/src/ts-dsl/mixins/operator.ts | 6 + .../src/ts-dsl/mixins/type-returns.ts | 39 +++++ packages/openapi-ts/src/ts-dsl/type/and.ts | 5 +- packages/openapi-ts/src/ts-dsl/type/attr.ts | 4 +- packages/openapi-ts/src/ts-dsl/type/expr.ts | 4 +- packages/openapi-ts/src/ts-dsl/type/func.ts | 20 +-- .../openapi-ts/src/ts-dsl/type/idx-sig.ts | 4 +- packages/openapi-ts/src/ts-dsl/type/idx.ts | 4 +- .../openapi-ts/src/ts-dsl/type/literal.ts | 4 +- packages/openapi-ts/src/ts-dsl/type/mapped.ts | 4 +- packages/openapi-ts/src/ts-dsl/type/object.ts | 4 +- .../openapi-ts/src/ts-dsl/type/operator.ts | 4 +- packages/openapi-ts/src/ts-dsl/type/or.ts | 5 +- packages/openapi-ts/src/ts-dsl/type/param.ts | 6 +- packages/openapi-ts/src/ts-dsl/type/prop.ts | 4 +- packages/openapi-ts/src/ts-dsl/type/query.ts | 6 +- .../openapi-ts/src/ts-dsl/type/template.ts | 4 +- packages/openapi-ts/src/ts-dsl/type/tuple.ts | 5 +- specs/3.1.x/sdk-nested-conflict.yaml | 25 +++ 34 files changed, 391 insertions(+), 210 deletions(-) create mode 100644 .changeset/major-cats-divide.md create mode 100644 packages/openapi-ts/src/ts-dsl/mixins/type-returns.ts create mode 100644 specs/3.1.x/sdk-nested-conflict.yaml diff --git a/.changeset/major-cats-divide.md b/.changeset/major-cats-divide.md new file mode 100644 index 000000000..e9d91f206 --- /dev/null +++ b/.changeset/major-cats-divide.md @@ -0,0 +1,5 @@ +--- +'@hey-api/openapi-ts': patch +--- + +**@hey-api/sdk**: lazily initialize sub-resources to improve performance diff --git a/dev/openapi-ts.config.ts b/dev/openapi-ts.config.ts index f57191869..f51db7f4d 100644 --- a/dev/openapi-ts.config.ts +++ b/dev/openapi-ts.config.ts @@ -48,12 +48,13 @@ export default defineConfig(() => { // 'invalid', // 'object-property-names.yaml', // 'openai.yaml', - 'opencode.yaml', + // 'opencode.yaml', // 'pagination-ref.yaml', // 'schema-const.yaml', // 'sdk-instance.yaml', // 'sdk-method-class-conflict.yaml', // 'sdk-nested-classes.yaml', + 'sdk-nested-conflict.yaml', // 'string-with-format.yaml', // 'transformers.json', // 'transformers-recursive.json', diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts index 42a9481df..fafb8ed66 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts @@ -57,7 +57,10 @@ export class Domains extends HeyApiClient { } export class Providers extends HeyApiClient { - domains = new Domains({ client: this.client }); + private _domains?: Domains; + get domains(): Domains { + return this._domains ??= new Domains({ client: this.client }); + } } export class Business extends HeyApiClient { @@ -65,7 +68,10 @@ export class Business extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/locations/businesses', ...options }); } - providers = new Providers({ client: this.client }); + private _providers?: Providers; + get providers(): Providers { + return this._providers ??= new Providers({ client: this.client }); + } } export class NestedSdkWithInstance extends HeyApiClient { @@ -87,5 +93,8 @@ export class NestedSdkWithInstance extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/locations', ...options }); } - business = new Business({ client: this.client }); + private _business?: Business; + get business(): Business { + return this._business ??= new Business({ client: this.client }); + } } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts index 09d2b380f..af464f9b9 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts @@ -65,7 +65,10 @@ export class Foo extends HeyApiClient { return (options?.client ?? this.client).put({ url: '/foo', ...options }); } - bar = new Bar({ client: this.client }); + private _bar?: Bar; + get bar(): Bar { + return this._bar ??= new Bar({ client: this.client }); + } } export class Sdk extends HeyApiClient { @@ -87,5 +90,8 @@ export class Sdk extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/foo/bar', ...options }); } - foo = new Foo({ client: this.client }); + private _foo?: Foo; + get foo(): Foo { + return this._foo ??= new Foo({ client: this.client }); + } } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts index 42a9481df..fafb8ed66 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts @@ -57,7 +57,10 @@ export class Domains extends HeyApiClient { } export class Providers extends HeyApiClient { - domains = new Domains({ client: this.client }); + private _domains?: Domains; + get domains(): Domains { + return this._domains ??= new Domains({ client: this.client }); + } } export class Business extends HeyApiClient { @@ -65,7 +68,10 @@ export class Business extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/locations/businesses', ...options }); } - providers = new Providers({ client: this.client }); + private _providers?: Providers; + get providers(): Providers { + return this._providers ??= new Providers({ client: this.client }); + } } export class NestedSdkWithInstance extends HeyApiClient { @@ -87,5 +93,8 @@ export class NestedSdkWithInstance extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/locations', ...options }); } - business = new Business({ client: this.client }); + private _business?: Business; + get business(): Business { + return this._business ??= new Business({ client: this.client }); + } } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts index 09d2b380f..af464f9b9 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts @@ -65,7 +65,10 @@ export class Foo extends HeyApiClient { return (options?.client ?? this.client).put({ url: '/foo', ...options }); } - bar = new Bar({ client: this.client }); + private _bar?: Bar; + get bar(): Bar { + return this._bar ??= new Bar({ client: this.client }); + } } export class Sdk extends HeyApiClient { @@ -87,5 +90,8 @@ export class Sdk extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/foo/bar', ...options }); } - foo = new Foo({ client: this.client }); + private _foo?: Foo; + get foo(): Foo { + return this._foo ??= new Foo({ client: this.client }); + } } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts index 42a9481df..fafb8ed66 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts @@ -57,7 +57,10 @@ export class Domains extends HeyApiClient { } export class Providers extends HeyApiClient { - domains = new Domains({ client: this.client }); + private _domains?: Domains; + get domains(): Domains { + return this._domains ??= new Domains({ client: this.client }); + } } export class Business extends HeyApiClient { @@ -65,7 +68,10 @@ export class Business extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/locations/businesses', ...options }); } - providers = new Providers({ client: this.client }); + private _providers?: Providers; + get providers(): Providers { + return this._providers ??= new Providers({ client: this.client }); + } } export class NestedSdkWithInstance extends HeyApiClient { @@ -87,5 +93,8 @@ export class NestedSdkWithInstance extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/locations', ...options }); } - business = new Business({ client: this.client }); + private _business?: Business; + get business(): Business { + return this._business ??= new Business({ client: this.client }); + } } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/sdk/instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/sdk/instance/sdk.gen.ts index 09d2b380f..af464f9b9 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/sdk/instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/sdk/instance/sdk.gen.ts @@ -65,7 +65,10 @@ export class Foo extends HeyApiClient { return (options?.client ?? this.client).put({ url: '/foo', ...options }); } - bar = new Bar({ client: this.client }); + private _bar?: Bar; + get bar(): Bar { + return this._bar ??= new Bar({ client: this.client }); + } } export class Sdk extends HeyApiClient { @@ -87,5 +90,8 @@ export class Sdk extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/foo/bar', ...options }); } - foo = new Foo({ client: this.client }); + private _foo?: Foo; + get foo(): Foo { + return this._foo ??= new Foo({ client: this.client }); + } } diff --git a/packages/openapi-ts-tests/sdks/__snapshots__/method-class-conflict/instance/sdk.gen.ts b/packages/openapi-ts-tests/sdks/__snapshots__/method-class-conflict/instance/sdk.gen.ts index 2ba6a8fb3..86dcdf974 100644 --- a/packages/openapi-ts-tests/sdks/__snapshots__/method-class-conflict/instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/sdks/__snapshots__/method-class-conflict/instance/sdk.gen.ts @@ -259,43 +259,100 @@ export class Odata extends HeyApiClient { return (options?.client ?? this.client).get({ url: '/api/v1/odata/Tasks({key})', ...options }); } - accountingCompanies2 = new AccountingCompanies({ client: this.client }); + private _accountingCompanies2?: AccountingCompanies; + get accountingCompanies2(): AccountingCompanies { + return this._accountingCompanies2 ??= new AccountingCompanies({ client: this.client }); + } - accountingCompanyMemberships2 = new AccountingCompanyMemberships({ client: this.client }); + private _accountingCompanyMemberships2?: AccountingCompanyMemberships; + get accountingCompanyMemberships2(): AccountingCompanyMemberships { + return this._accountingCompanyMemberships2 ??= new AccountingCompanyMemberships({ client: this.client }); + } - bankAccounts2 = new BankAccounts({ client: this.client }); + private _bankAccounts2?: BankAccounts; + get bankAccounts2(): BankAccounts { + return this._bankAccounts2 ??= new BankAccounts({ client: this.client }); + } - businessAccountantAssignments2 = new BusinessAccountantAssignments({ client: this.client }); + private _businessAccountantAssignments2?: BusinessAccountantAssignments; + get businessAccountantAssignments2(): BusinessAccountantAssignments { + return this._businessAccountantAssignments2 ??= new BusinessAccountantAssignments({ client: this.client }); + } - businessDocumentActivities2 = new BusinessDocumentActivities({ client: this.client }); + private _businessDocumentActivities2?: BusinessDocumentActivities; + get businessDocumentActivities2(): BusinessDocumentActivities { + return this._businessDocumentActivities2 ??= new BusinessDocumentActivities({ client: this.client }); + } - businessDocuments2 = new BusinessDocuments({ client: this.client }); + private _businessDocuments2?: BusinessDocuments; + get businessDocuments2(): BusinessDocuments { + return this._businessDocuments2 ??= new BusinessDocuments({ client: this.client }); + } - businessDocumentsSummaries2 = new BusinessDocumentsSummaries({ client: this.client }); + private _businessDocumentsSummaries2?: BusinessDocumentsSummaries; + get businessDocumentsSummaries2(): BusinessDocumentsSummaries { + return this._businessDocumentsSummaries2 ??= new BusinessDocumentsSummaries({ client: this.client }); + } - businesses2 = new Businesses({ client: this.client }); + private _businesses2?: Businesses; + get businesses2(): Businesses { + return this._businesses2 ??= new Businesses({ client: this.client }); + } - businessSummaries2 = new BusinessSummaries({ client: this.client }); + private _businessSummaries2?: BusinessSummaries; + get businessSummaries2(): BusinessSummaries { + return this._businessSummaries2 ??= new BusinessSummaries({ client: this.client }); + } - counterparties2 = new Counterparties({ client: this.client }); + private _counterparties2?: Counterparties; + get counterparties2(): Counterparties { + return this._counterparties2 ??= new Counterparties({ client: this.client }); + } - dataBoxCredentials2 = new DataBoxCredentials({ client: this.client }); + private _dataBoxCredentials2?: DataBoxCredentials; + get dataBoxCredentials2(): DataBoxCredentials { + return this._dataBoxCredentials2 ??= new DataBoxCredentials({ client: this.client }); + } - documentTypes2 = new DocumentTypes({ client: this.client }); + private _documentTypes2?: DocumentTypes; + get documentTypes2(): DocumentTypes { + return this._documentTypes2 ??= new DocumentTypes({ client: this.client }); + } - invitations2 = new Invitations({ client: this.client }); + private _invitations2?: Invitations; + get invitations2(): Invitations { + return this._invitations2 ??= new Invitations({ client: this.client }); + } - invoices2 = new Invoices({ client: this.client }); + private _invoices2?: Invoices; + get invoices2(): Invoices { + return this._invoices2 ??= new Invoices({ client: this.client }); + } - invoiceSettings2 = new InvoiceSettings({ client: this.client }); + private _invoiceSettings2?: InvoiceSettings; + get invoiceSettings2(): InvoiceSettings { + return this._invoiceSettings2 ??= new InvoiceSettings({ client: this.client }); + } - licenses2 = new Licenses({ client: this.client }); + private _licenses2?: Licenses; + get licenses2(): Licenses { + return this._licenses2 ??= new Licenses({ client: this.client }); + } - personalDocuments2 = new PersonalDocuments({ client: this.client }); + private _personalDocuments2?: PersonalDocuments; + get personalDocuments2(): PersonalDocuments { + return this._personalDocuments2 ??= new PersonalDocuments({ client: this.client }); + } - recurringTasks2 = new RecurringTasks({ client: this.client }); + private _recurringTasks2?: RecurringTasks; + get recurringTasks2(): RecurringTasks { + return this._recurringTasks2 ??= new RecurringTasks({ client: this.client }); + } - tasks2 = new Tasks({ client: this.client }); + private _tasks2?: Tasks; + get tasks2(): Tasks { + return this._tasks2 ??= new Tasks({ client: this.client }); + } } export class User extends HeyApiClient { @@ -305,17 +362,29 @@ export class User extends HeyApiClient { } export class VVersionApiVersion extends HeyApiClient { - odata = new Odata({ client: this.client }); + private _odata?: Odata; + get odata(): Odata { + return this._odata ??= new Odata({ client: this.client }); + } - user = new User({ client: this.client }); + private _user?: User; + get user(): User { + return this._user ??= new User({ client: this.client }); + } } export class Api extends HeyApiClient { - vVersionApiVersion = new VVersionApiVersion({ client: this.client }); + private _vVersionApiVersion?: VVersionApiVersion; + get vVersionApiVersion(): VVersionApiVersion { + return this._vVersionApiVersion ??= new VVersionApiVersion({ client: this.client }); + } } export class MapIdentityApi extends HeyApiClient { - api = new Api({ client: this.client }); + private _api?: Api; + get api(): Api { + return this._api ??= new Api({ client: this.client }); + } } export class Sdk extends HeyApiClient { @@ -994,7 +1063,13 @@ export class Sdk extends HeyApiClient { }); } - api = new Api({ client: this.client }); + private _api?: Api; + get api(): Api { + return this._api ??= new Api({ client: this.client }); + } - mapIdentityApi = new MapIdentityApi({ client: this.client }); + private _mapIdentityApi?: MapIdentityApi; + get mapIdentityApi(): MapIdentityApi { + return this._mapIdentityApi ??= new MapIdentityApi({ client: this.client }); + } } diff --git a/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts b/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts index 5fc381bff..427639dbe 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts @@ -236,10 +236,9 @@ export const generateClassSdk = ({ symbolCurrentClass.meta!.resourceId!, )!; - // avoid duplicate methods - if (currentClass.methods.has(entry.methodName)) { - return; - } + const methodName = entry.methodName; + if (currentClass.methods.has(methodName)) return; + currentClass.methods.add(methodName); const opParameters = operationParameters({ isRequiredOptions, @@ -252,7 +251,7 @@ export const generateClassSdk = ({ operation, plugin, }); - const functionNode = $.method(entry.methodName, (m) => + const functionNode = $.method(methodName, (m) => m .$if(createOperationComment(operation), (m, v) => m.doc(v)) .public() @@ -295,8 +294,6 @@ export const generateClassSdk = ({ currentClass.nodes.push($.newline(), functionNode); } - currentClass.methods.add(entry.methodName); - sdkClasses.set(symbolCurrentClass.meta!.resourceId!, currentClass); }); } @@ -306,11 +303,9 @@ export const generateClassSdk = ({ }, ); - const heyApiClientIndex = plugin.config.instance - ? plugin.node(null) - : undefined; - const symbolHeyApiClient = - heyApiClientIndex !== undefined + const clientIndex = plugin.config.instance ? plugin.node(null) : undefined; + const symbolClient = + clientIndex !== undefined ? plugin.symbol('HeyApiClient', { meta: { category: 'utility', @@ -320,94 +315,81 @@ export const generateClassSdk = ({ }, }) : undefined; - const heyApiRegistryIndex = plugin.config.instance - ? plugin.node(null) - : undefined; + const registryIndex = plugin.config.instance ? plugin.node(null) : undefined; const generateClass = (currentClass: SdkClassEntry) => { - if (generatedClasses.has(currentClass.className)) { - return; - } - const resourceId = currentClass.className; + + if (generatedClasses.has(resourceId)) return; generatedClasses.add(resourceId); - if (currentClass.classes.size) { - for (const childClassName of currentClass.classes) { - const childClass = sdkClasses.get(childClassName)!; - generateClass(childClass); + if (clientIndex !== undefined && symbolClient && !symbolClient.node) { + const node = createClientClass({ plugin, symbol: symbolClient }); + plugin.node(node, clientIndex); + } - const refChildClass = plugin.referenceSymbol({ - category: 'utility', - resource: 'class', - resourceId: childClass.className, - tool: 'sdk', - }); + for (const childClassName of currentClass.classes) { + const childClass = sdkClasses.get(childClassName)!; + generateClass(childClass); - const originalMemberName = stringCase({ - case: 'camelCase', - value: refChildClass.meta!.resourceId!, - }); - // avoid collisions with existing method names - let memberName = originalMemberName; - if (currentClass.methods.has(memberName)) { - let index = 2; - let attempt = `${memberName}${index}`; - while (currentClass.methods.has(attempt)) { - attempt = `${memberName}${index++}`; - } - memberName = attempt; + const refChildClass = plugin.referenceSymbol({ + category: 'utility', + resource: 'class', + resourceId: childClass.className, + tool: 'sdk', + }); + + const originalMemberName = stringCase({ + case: 'camelCase', + value: refChildClass.meta!.resourceId!, + }); + // avoid collisions with existing method names + let memberName = originalMemberName; + if (currentClass.methods.has(memberName)) { + let index = 2; + let attempt = `${memberName}${index}`; + while (currentClass.methods.has(attempt)) { + attempt = `${memberName}${index++}`; } - currentClass.methods.add(memberName); + memberName = attempt; + } + currentClass.methods.add(memberName); + + if (currentClass.nodes.length > 0) { + currentClass.nodes.push($.newline()); + } + if (plugin.config.instance) { + const privateName = plugin.symbol(`_${memberName}`); + const privateNode = $.field(privateName, (f) => + f.private().optional().type(refChildClass), + ); + currentClass.nodes.push(privateNode); + const getterNode = $.getter(memberName, (g) => + g.returns(refChildClass).do( + $('this') + .attr(privateName) + .nullishAssign( + $.new(refChildClass).args( + $.object().prop('client', $('this').attr('client')), + ), + ) + .return(), + ), + ); + currentClass.nodes.push(getterNode); + } else { const subClassReferenceNode = plugin.isSymbolRegistered( refChildClass.id, ) - ? $.field(memberName, (f) => - f - .static(!plugin.config.instance) - .assign( - plugin.config.instance - ? $.new(refChildClass).args( - $.object().prop('client', $('this').attr('client')), - ) - : $(refChildClass), - ), - ) + ? $.field(memberName, (f) => f.static().assign($(refChildClass))) : $.getter(memberName, (g) => - g - .$if(!plugin.config.instance, (g) => g.public().static()) - .do( - $.return( - plugin.config.instance - ? $.new(refChildClass).args( - $.object().prop('client', $('this').attr('client')), - ) - : refChildClass, - ), - ), + g.public().static().do($.return(refChildClass)), ); - - if (!currentClass.nodes.length) { - currentClass.nodes.push(subClassReferenceNode); - } else { - currentClass.nodes.push($.newline(), subClassReferenceNode); - } + currentClass.nodes.push(subClassReferenceNode); } } - if ( - heyApiClientIndex !== undefined && - symbolHeyApiClient && - !symbolHeyApiClient.node - ) { - const node = createClientClass({ - plugin, - symbol: symbolHeyApiClient, - }); - plugin.node(node, heyApiClientIndex); - } - const symbol = plugin.symbol(resourceId, { meta: { category: 'utility', @@ -417,10 +399,8 @@ export const generateClassSdk = ({ }, }); - if (currentClass.root && heyApiRegistryIndex !== undefined) { - const symClient = plugin.getSymbol({ - category: 'client', - }); + if (currentClass.root && registryIndex !== undefined) { + const symClient = plugin.getSymbol({ category: 'client' }); const isClientRequired = !plugin.config.client || !symClient; const symbolClient = plugin.referenceSymbol({ category: 'external', @@ -466,7 +446,7 @@ export const generateClassSdk = ({ sdkSymbol: symbol, symbol: symbolRegistry, }); - plugin.node(node, heyApiRegistryIndex); + plugin.node(node, registryIndex); const registryNode = $.field(registryName, (f) => f .public() @@ -479,8 +459,8 @@ export const generateClassSdk = ({ const node = $.class(symbol) .export() - .extends(symbolHeyApiClient) - .$if(currentClass.root && isAngularClient, (c) => + .extends(symbolClient) + .$if(isAngularClient && currentClass.root, (c) => c.decorator( plugin.referenceSymbol({ category: 'external', diff --git a/packages/openapi-ts/src/ts-dsl/decl/field.ts b/packages/openapi-ts/src/ts-dsl/decl/field.ts index f8f009e7f..73f8d00d6 100644 --- a/packages/openapi-ts/src/ts-dsl/decl/field.ts +++ b/packages/openapi-ts/src/ts-dsl/decl/field.ts @@ -15,7 +15,9 @@ import { ReadonlyMixin, StaticMixin, } from '../mixins/modifiers'; +import { OptionalMixin } from '../mixins/optional'; import { ValueMixin } from '../mixins/value'; +import { TokenTsDsl } from '../token'; import type { TypeExprName } from '../type/expr'; import { TypeExprTsDsl } from '../type/expr'; @@ -24,10 +26,14 @@ export type FieldType = TypeExprName | TypeTsDsl; const Mixed = DecoratorMixin( DocMixin( - PrivateMixin( - ProtectedMixin( - PublicMixin( - ReadonlyMixin(StaticMixin(ValueMixin(TsDsl))), + OptionalMixin( + PrivateMixin( + ProtectedMixin( + PublicMixin( + ReadonlyMixin( + StaticMixin(ValueMixin(TsDsl)), + ), + ), ), ), ), @@ -61,7 +67,7 @@ export class FieldTsDsl extends Mixed { const node = ts.factory.createPropertyDeclaration( [...this.$decorators(ctx), ...this.modifiers], this.$node(ctx, this.name) as ts.PropertyName, - undefined, + this._optional ? this.$node(ctx, new TokenTsDsl().optional()) : undefined, this.$type(ctx, this._type), this.$value(ctx), ); diff --git a/packages/openapi-ts/src/ts-dsl/decl/func.ts b/packages/openapi-ts/src/ts-dsl/decl/func.ts index d0f8f90b1..c8eac07b2 100644 --- a/packages/openapi-ts/src/ts-dsl/decl/func.ts +++ b/packages/openapi-ts/src/ts-dsl/decl/func.ts @@ -7,7 +7,7 @@ import type { import { isSymbol, ref } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TsDsl, TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { AsMixin } from '../mixins/as'; import { DecoratorMixin } from '../mixins/decorator'; import { DoMixin } from '../mixins/do'; @@ -22,8 +22,8 @@ import { } from '../mixins/modifiers'; import { ParamMixin } from '../mixins/param'; import { TypeParamsMixin } from '../mixins/type-params'; +import { TypeReturnsMixin } from '../mixins/type-returns'; import { BlockTsDsl } from '../stmt/block'; -import { TypeExprTsDsl } from '../type/expr'; import { safeRuntimeName } from '../utils/name'; export type FuncMode = 'arrow' | 'decl' | 'expr'; @@ -39,7 +39,11 @@ const Mixed = AbstractMixin( PrivateMixin( ProtectedMixin( PublicMixin( - StaticMixin(TypeParamsMixin(TsDsl)), + StaticMixin( + TypeParamsMixin( + TypeReturnsMixin(TsDsl), + ), + ), ), ), ), @@ -56,7 +60,6 @@ class ImplFuncTsDsl extends Mixed { protected mode?: FuncMode; protected name?: Ref; - protected _returns?: TypeTsDsl; constructor(); constructor(fn: (f: ImplFuncTsDsl<'arrow'>) => void); @@ -87,7 +90,6 @@ class ImplFuncTsDsl extends Mixed { try { super.analyze(ctx); ctx.analyze(this.name); - ctx.analyze(this._returns); } finally { ctx.popScope(); } @@ -111,12 +113,6 @@ class ImplFuncTsDsl extends Mixed { return this as unknown as FuncTsDsl<'expr'>; } - /** Sets the return type. */ - returns(type: string | TypeTsDsl): this { - this._returns = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type); - return this; - } - // @ts-expect-error --- need to fix types --- override toAst( ctx: AstContext, @@ -135,7 +131,7 @@ class ImplFuncTsDsl extends Mixed { this.$node(ctx, this.name) as ts.Identifier, this.$generics(ctx), this.$params(ctx), - this.$type(ctx, this._returns), + this.$returns(ctx), body, ) as any; return this.$docs(ctx, node); @@ -148,7 +144,7 @@ class ImplFuncTsDsl extends Mixed { this.$node(ctx, this.name) as ts.Identifier, this.$generics(ctx), this.$params(ctx), - this.$type(ctx, this._returns), + this.$returns(ctx), body, ) as any; return this.$docs(ctx, node); @@ -158,7 +154,7 @@ class ImplFuncTsDsl extends Mixed { this.modifiers, this.$generics(ctx), this.$params(ctx), - this.$type(ctx, this._returns), + this.$returns(ctx), undefined, body.statements.length === 1 && ts.isReturnStatement(body.statements[0]!) && diff --git a/packages/openapi-ts/src/ts-dsl/decl/getter.ts b/packages/openapi-ts/src/ts-dsl/decl/getter.ts index 08ec71f9a..6ec55d14b 100644 --- a/packages/openapi-ts/src/ts-dsl/decl/getter.ts +++ b/packages/openapi-ts/src/ts-dsl/decl/getter.ts @@ -14,6 +14,7 @@ import { StaticMixin, } from '../mixins/modifiers'; import { ParamMixin } from '../mixins/param'; +import { TypeReturnsMixin } from '../mixins/type-returns'; import { BlockTsDsl } from '../stmt/block'; export type GetterName = string | ts.PropertyName; @@ -26,7 +27,11 @@ const Mixed = AbstractMixin( ParamMixin( PrivateMixin( ProtectedMixin( - PublicMixin(StaticMixin(TsDsl)), + PublicMixin( + StaticMixin( + TypeReturnsMixin(TsDsl), + ), + ), ), ), ), @@ -61,7 +66,7 @@ export class GetterTsDsl extends Mixed { [...this.$decorators(ctx), ...this.modifiers], this.name, this.$params(ctx), - undefined, + this.$returns(ctx), this.$node(ctx, new BlockTsDsl(...this._do).pretty()), ); return this.$docs(ctx, node); diff --git a/packages/openapi-ts/src/ts-dsl/decl/method.ts b/packages/openapi-ts/src/ts-dsl/decl/method.ts index ea45a0530..e21d1ca97 100644 --- a/packages/openapi-ts/src/ts-dsl/decl/method.ts +++ b/packages/openapi-ts/src/ts-dsl/decl/method.ts @@ -1,7 +1,7 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TsDsl, TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { DecoratorMixin } from '../mixins/decorator'; import { DoMixin } from '../mixins/do'; import { DocMixin } from '../mixins/doc'; @@ -16,9 +16,9 @@ import { import { OptionalMixin } from '../mixins/optional'; import { ParamMixin } from '../mixins/param'; import { TypeParamsMixin } from '../mixins/type-params'; +import { TypeReturnsMixin } from '../mixins/type-returns'; import { BlockTsDsl } from '../stmt/block'; import { TokenTsDsl } from '../token'; -import { TypeExprTsDsl } from '../type/expr'; const Mixed = AbstractMixin( AsyncMixin( @@ -30,7 +30,11 @@ const Mixed = AbstractMixin( PrivateMixin( ProtectedMixin( PublicMixin( - StaticMixin(TypeParamsMixin(TsDsl)), + StaticMixin( + TypeParamsMixin( + TypeReturnsMixin(TsDsl), + ), + ), ), ), ), @@ -46,7 +50,6 @@ export class MethodTsDsl extends Mixed { readonly '~dsl' = 'MethodTsDsl'; protected name: string; - protected _returns?: TypeTsDsl; constructor(name: string, fn?: (m: MethodTsDsl) => void) { super(); @@ -58,18 +61,11 @@ export class MethodTsDsl extends Mixed { ctx.pushScope(); try { super.analyze(ctx); - ctx.analyze(this._returns); } finally { ctx.popScope(); } } - /** Sets the return type. */ - returns(type: string | TypeTsDsl): this { - this._returns = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type); - return this; - } - override toAst(ctx: AstContext) { const node = ts.factory.createMethodDeclaration( [...this.$decorators(ctx), ...this.modifiers], @@ -78,7 +74,7 @@ export class MethodTsDsl extends Mixed { this._optional ? this.$node(ctx, new TokenTsDsl().optional()) : undefined, this.$generics(ctx), this.$params(ctx), - this.$type(ctx, this._returns), + this.$returns(ctx), this.$node(ctx, new BlockTsDsl(...this._do).pretty()), ); return this.$docs(ctx, node); diff --git a/packages/openapi-ts/src/ts-dsl/expr/binary.ts b/packages/openapi-ts/src/ts-dsl/expr/binary.ts index e7fa67efe..42d45ee9c 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/binary.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/binary.ts @@ -30,6 +30,7 @@ type Operator = | '>' | '>=' | '??' + | '??=' | '||'; const Mixed = AsMixin(ExprMixin(TsDsl)); @@ -119,6 +120,11 @@ export class BinaryTsDsl extends Mixed { return this.opAndExpr('!==', expr); } + /** Nullish assignment — `this ??= expr` */ + nullishAssign(expr: Expr): this { + return this.opAndExpr('??=', expr); + } + /** Logical OR — `this || expr` */ or(expr: Expr): this { return this.opAndExpr('||', expr); @@ -172,6 +178,7 @@ export class BinaryTsDsl extends Mixed { '>': ts.SyntaxKind.GreaterThanToken, '>=': ts.SyntaxKind.GreaterThanEqualsToken, '??': ts.SyntaxKind.QuestionQuestionToken, + '??=': ts.SyntaxKind.QuestionQuestionEqualsToken, '||': ts.SyntaxKind.BarBarToken, }; const token = tokenMap[op]; diff --git a/packages/openapi-ts/src/ts-dsl/mixins/operator.ts b/packages/openapi-ts/src/ts-dsl/mixins/operator.ts index 2bc7de200..288579ade 100644 --- a/packages/openapi-ts/src/ts-dsl/mixins/operator.ts +++ b/packages/openapi-ts/src/ts-dsl/mixins/operator.ts @@ -34,6 +34,8 @@ export interface OperatorMethods extends Node { minus(expr: Expr): BinaryTsDsl; /** Strict inequality — `this !== expr` */ neq(expr: Expr): BinaryTsDsl; + /** Nullish assignment — `this ??= expr` */ + nullishAssign(expr: Expr): BinaryTsDsl; /** Logical OR — `this || expr` */ or(expr: Expr): BinaryTsDsl; /** Addition — `this + expr` */ @@ -103,6 +105,10 @@ export function OperatorMixin< return new BinaryTsDsl(this).neq(expr); } + protected nullishAssign(expr: Expr): BinaryTsDsl { + return new BinaryTsDsl(this).nullishAssign(expr); + } + protected or(expr: Expr): BinaryTsDsl { return new BinaryTsDsl(this).or(expr); } diff --git a/packages/openapi-ts/src/ts-dsl/mixins/type-returns.ts b/packages/openapi-ts/src/ts-dsl/mixins/type-returns.ts new file mode 100644 index 000000000..0454aa1de --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/type-returns.ts @@ -0,0 +1,39 @@ +import type { AnalysisContext, AstContext, Node } from '@hey-api/codegen-core'; +import type ts from 'typescript'; + +import { TypeTsDsl } from '../base'; +import type { TypeExprName } from '../type/expr'; +import { TypeExprTsDsl } from '../type/expr'; +import type { BaseCtor, MixinCtor } from './types'; + +export interface TypeReturnsMethods extends Node { + /** Returns the return type node. */ + $returns(ctx: AstContext): ts.TypeNode | undefined; + /** Sets the return type. */ + returns(type: TypeExprName | TypeTsDsl): this; +} + +export function TypeReturnsMixin>( + Base: TBase, +) { + abstract class TypeReturns extends Base { + protected _returns?: TypeTsDsl; + + override analyze(ctx: AnalysisContext): void { + super.analyze(ctx); + ctx.analyze(this._returns); + } + + protected returns(type: TypeExprName | TypeTsDsl): this { + this._returns = + type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type); + return this; + } + + protected $returns(ctx: AstContext): ts.TypeNode | undefined { + return this.$type(ctx, this._returns); + } + } + + return TypeReturns as unknown as MixinCtor; +} diff --git a/packages/openapi-ts/src/ts-dsl/type/and.ts b/packages/openapi-ts/src/ts-dsl/type/and.ts index 72dee8cd0..085602eb9 100644 --- a/packages/openapi-ts/src/ts-dsl/type/and.ts +++ b/packages/openapi-ts/src/ts-dsl/type/and.ts @@ -7,11 +7,12 @@ import type { import { ref } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TypeTsDsl } from '../base'; +import type { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; type Type = Symbol | string | ts.TypeNode | TypeTsDsl; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; export class TypeAndTsDsl extends Mixed { readonly '~dsl' = 'TypeAndTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/attr.ts b/packages/openapi-ts/src/ts-dsl/type/attr.ts index 534ededf6..59434b0ef 100644 --- a/packages/openapi-ts/src/ts-dsl/type/attr.ts +++ b/packages/openapi-ts/src/ts-dsl/type/attr.ts @@ -8,13 +8,13 @@ import { isRef, ref } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { TypeExprMixin } from '../mixins/type-expr'; type Base = Symbol | string | MaybeTsDsl; type Right = Symbol | string | ts.Identifier; -const Mixed = TypeExprMixin(TypeTsDsl); +const Mixed = TypeExprMixin(TsDsl); export class TypeAttrTsDsl extends Mixed { readonly '~dsl' = 'TypeAttrTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/expr.ts b/packages/openapi-ts/src/ts-dsl/type/expr.ts index 72c765dcd..4712aabff 100644 --- a/packages/openapi-ts/src/ts-dsl/type/expr.ts +++ b/packages/openapi-ts/src/ts-dsl/type/expr.ts @@ -7,7 +7,7 @@ import type { import { isNode, ref } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { TypeArgsMixin } from '../mixins/type-args'; import { TypeExprMixin } from '../mixins/type-expr'; import { f } from '../utils/factories'; @@ -21,7 +21,7 @@ export type TypeExprCtor = ( fn?: TypeExprFn, ) => TypeExprTsDsl; -const Mixed = TypeArgsMixin(TypeExprMixin(TypeTsDsl)); +const Mixed = TypeArgsMixin(TypeExprMixin(TsDsl)); export class TypeExprTsDsl extends Mixed { readonly '~dsl' = 'TypeExprTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/func.ts b/packages/openapi-ts/src/ts-dsl/type/func.ts index 1813425e5..871485b28 100644 --- a/packages/openapi-ts/src/ts-dsl/type/func.ts +++ b/packages/openapi-ts/src/ts-dsl/type/func.ts @@ -1,40 +1,32 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { DocMixin } from '../mixins/doc'; import { ParamMixin } from '../mixins/param'; import { TypeParamsMixin } from '../mixins/type-params'; -import { TypeExprTsDsl } from './expr'; +import { TypeReturnsMixin } from '../mixins/type-returns'; const Mixed = DocMixin( - ParamMixin(TypeParamsMixin(TypeTsDsl)), + ParamMixin(TypeParamsMixin(TypeReturnsMixin(TsDsl))), ); export class TypeFuncTsDsl extends Mixed { readonly '~dsl' = 'TypeFuncTsDsl'; - protected _returns?: TypeTsDsl; - override analyze(ctx: AnalysisContext): void { super.analyze(ctx); - ctx.analyze(this._returns); - } - - /** Sets the return type. */ - returns(type: string | TypeTsDsl): this { - this._returns = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type); - return this; } override toAst(ctx: AstContext) { - if (this._returns === undefined) { + const returns = this.$returns(ctx); + if (returns === undefined) { throw new Error('Missing return type in function type DSL'); } const node = ts.factory.createFunctionTypeNode( this.$generics(ctx), this.$params(ctx), - this.$type(ctx, this._returns), + returns, ); return this.$docs(ctx, node); } diff --git a/packages/openapi-ts/src/ts-dsl/type/idx-sig.ts b/packages/openapi-ts/src/ts-dsl/type/idx-sig.ts index d81afbf12..092c479e1 100644 --- a/packages/openapi-ts/src/ts-dsl/type/idx-sig.ts +++ b/packages/openapi-ts/src/ts-dsl/type/idx-sig.ts @@ -2,14 +2,14 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { DocMixin } from '../mixins/doc'; import { ReadonlyMixin } from '../mixins/modifiers'; export type TypeIdxSigName = string; export type TypeIdxSigType = string | MaybeTsDsl; -const Mixed = DocMixin(ReadonlyMixin(TypeTsDsl)); +const Mixed = DocMixin(ReadonlyMixin(TsDsl)); export class TypeIdxSigTsDsl extends Mixed { readonly '~dsl' = 'TypeIdxSigTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/idx.ts b/packages/openapi-ts/src/ts-dsl/type/idx.ts index 70934b7d3..a6260a048 100644 --- a/packages/openapi-ts/src/ts-dsl/type/idx.ts +++ b/packages/openapi-ts/src/ts-dsl/type/idx.ts @@ -2,7 +2,7 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { TypeExprMixin } from '../mixins/type-expr'; import { f } from '../utils/factories'; @@ -10,7 +10,7 @@ type Base = string | MaybeTsDsl; type Index = string | number | MaybeTsDsl; export type TypeIdxCtor = (base: Base, index: Index) => TypeIdxTsDsl; -const Mixed = TypeExprMixin(TypeTsDsl); +const Mixed = TypeExprMixin(TsDsl); export class TypeIdxTsDsl extends Mixed { readonly '~dsl' = 'TypeIdxTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/literal.ts b/packages/openapi-ts/src/ts-dsl/type/literal.ts index 298208005..e14101989 100644 --- a/packages/openapi-ts/src/ts-dsl/type/literal.ts +++ b/packages/openapi-ts/src/ts-dsl/type/literal.ts @@ -1,10 +1,10 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { LiteralTsDsl } from '../expr/literal'; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; export class TypeLiteralTsDsl extends Mixed { readonly '~dsl' = 'TypeLiteralTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/mapped.ts b/packages/openapi-ts/src/ts-dsl/type/mapped.ts index 05a7c5bd5..12d915822 100644 --- a/packages/openapi-ts/src/ts-dsl/type/mapped.ts +++ b/packages/openapi-ts/src/ts-dsl/type/mapped.ts @@ -2,10 +2,10 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { TokenTsDsl } from '../token'; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; export class TypeMappedTsDsl extends Mixed { readonly '~dsl' = 'TypeMappedTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/object.ts b/packages/openapi-ts/src/ts-dsl/type/object.ts index 30c696ee7..b839624a2 100644 --- a/packages/openapi-ts/src/ts-dsl/type/object.ts +++ b/packages/openapi-ts/src/ts-dsl/type/object.ts @@ -1,11 +1,11 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { TypeIdxSigTsDsl } from './idx-sig'; import { TypePropTsDsl } from './prop'; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; export class TypeObjectTsDsl extends Mixed { readonly '~dsl' = 'TypeObjectTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/operator.ts b/packages/openapi-ts/src/ts-dsl/type/operator.ts index 0c0600461..86dedd8ff 100644 --- a/packages/openapi-ts/src/ts-dsl/type/operator.ts +++ b/packages/openapi-ts/src/ts-dsl/type/operator.ts @@ -2,7 +2,7 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { f } from '../utils/factories'; type Op = @@ -12,7 +12,7 @@ type Op = type Type = string | MaybeTsDsl; export type TypeOperatorCtor = () => TypeOperatorTsDsl; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; /** * Builds a TypeScript `TypeOperatorNode`, such as: diff --git a/packages/openapi-ts/src/ts-dsl/type/or.ts b/packages/openapi-ts/src/ts-dsl/type/or.ts index 60937cd90..f317cba4f 100644 --- a/packages/openapi-ts/src/ts-dsl/type/or.ts +++ b/packages/openapi-ts/src/ts-dsl/type/or.ts @@ -7,11 +7,12 @@ import type { import { ref } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TypeTsDsl } from '../base'; +import type { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; type Type = Symbol | string | ts.TypeNode | TypeTsDsl; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; export class TypeOrTsDsl extends Mixed { readonly '~dsl' = 'TypeOrTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/param.ts b/packages/openapi-ts/src/ts-dsl/type/param.ts index fcbcf3668..2088f0229 100644 --- a/packages/openapi-ts/src/ts-dsl/type/param.ts +++ b/packages/openapi-ts/src/ts-dsl/type/param.ts @@ -7,13 +7,13 @@ import type { import { ref } from '@hey-api/codegen-core'; import ts from 'typescript'; -import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import type { MaybeTsDsl, TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; export type TypeParamName = Symbol | string; export type TypeParamExpr = Symbol | string | boolean | MaybeTsDsl; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; export class TypeParamTsDsl extends Mixed { readonly '~dsl' = 'TypeParamTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/prop.ts b/packages/openapi-ts/src/ts-dsl/type/prop.ts index 508f73207..c46739b4c 100644 --- a/packages/openapi-ts/src/ts-dsl/type/prop.ts +++ b/packages/openapi-ts/src/ts-dsl/type/prop.ts @@ -8,7 +8,7 @@ import { ref } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { DocMixin } from '../mixins/doc'; import { ReadonlyMixin } from '../mixins/modifiers'; import { OptionalMixin } from '../mixins/optional'; @@ -18,7 +18,7 @@ import { safePropName } from '../utils/name'; export type TypePropName = string; export type TypePropType = Symbol | string | MaybeTsDsl; -const Mixed = DocMixin(OptionalMixin(ReadonlyMixin(TypeTsDsl))); +const Mixed = DocMixin(OptionalMixin(ReadonlyMixin(TsDsl))); export class TypePropTsDsl extends Mixed { readonly '~dsl' = 'TypePropTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/query.ts b/packages/openapi-ts/src/ts-dsl/type/query.ts index 60b1ea21a..860661721 100644 --- a/packages/openapi-ts/src/ts-dsl/type/query.ts +++ b/packages/openapi-ts/src/ts-dsl/type/query.ts @@ -1,15 +1,15 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; -import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import type { MaybeTsDsl, TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; import { TypeExprMixin } from '../mixins/type-expr'; import { f } from '../utils/factories'; export type TypeQueryExpr = string | MaybeTsDsl; export type TypeQueryCtor = (expr: TypeQueryExpr) => TypeQueryTsDsl; -const Mixed = TypeExprMixin(TypeTsDsl); +const Mixed = TypeExprMixin(TsDsl); export class TypeQueryTsDsl extends Mixed { readonly '~dsl' = 'TypeQueryTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/template.ts b/packages/openapi-ts/src/ts-dsl/type/template.ts index fc23360ef..4d12c9202 100644 --- a/packages/openapi-ts/src/ts-dsl/type/template.ts +++ b/packages/openapi-ts/src/ts-dsl/type/template.ts @@ -2,9 +2,9 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; -import { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; export class TypeTemplateTsDsl extends Mixed { readonly '~dsl' = 'TypeTemplateTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/type/tuple.ts b/packages/openapi-ts/src/ts-dsl/type/tuple.ts index 82e9dbb2b..ae3170830 100644 --- a/packages/openapi-ts/src/ts-dsl/type/tuple.ts +++ b/packages/openapi-ts/src/ts-dsl/type/tuple.ts @@ -1,9 +1,10 @@ import type { AnalysisContext, AstContext } from '@hey-api/codegen-core'; import ts from 'typescript'; -import { TypeTsDsl } from '../base'; +import type { TypeTsDsl } from '../base'; +import { TsDsl } from '../base'; -const Mixed = TypeTsDsl; +const Mixed = TsDsl; export class TypeTupleTsDsl extends Mixed { readonly '~dsl' = 'TypeTupleTsDsl'; diff --git a/specs/3.1.x/sdk-nested-conflict.yaml b/specs/3.1.x/sdk-nested-conflict.yaml new file mode 100644 index 000000000..035ec259c --- /dev/null +++ b/specs/3.1.x/sdk-nested-conflict.yaml @@ -0,0 +1,25 @@ +openapi: 3.1.1 +info: + title: OpenAPI 3.1.1 sdk nested conflict example + version: 1 +paths: + /v1/providers: + get: + operationId: providers.list + summary: List Providers + tags: + - providers + /v1/tenants/{tenantId}/providers: + get: + operationId: tenants.providers.list + summary: List Tenant Providers + tags: + - tenants + - tenantProviders + parameters: + - name: tenantId + in: path + required: true + schema: + type: string + description: Tenant ID -- 2.51.2