From aed4bb4c64ac2276ecfe26d4e899d8b23264a0a0 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sat, 8 Nov 2025 16:25:23 +0800 Subject: [PATCH] refactor: tighten up return and await methods --- .changeset/chilled-wolves-pump.md | 2 +- .../src/plugins/@hey-api/sdk/shared/class.ts | 12 ++-- .../@tanstack/query-core/v5/queryOptions.ts | 2 +- .../openapi-ts/src/plugins/arktype/v2/api.ts | 22 +++---- .../openapi-ts/src/plugins/swr/v2/useSwr.ts | 8 +-- .../openapi-ts/src/plugins/valibot/v1/api.ts | 22 +++---- .../openapi-ts/src/plugins/zod/mini/api.ts | 22 +++---- packages/openapi-ts/src/plugins/zod/v3/api.ts | 22 +++---- packages/openapi-ts/src/plugins/zod/v4/api.ts | 22 +++---- packages/openapi-ts/src/ts-dsl/attr.ts | 4 +- packages/openapi-ts/src/ts-dsl/await.ts | 15 +++-- packages/openapi-ts/src/ts-dsl/call.ts | 21 +++--- packages/openapi-ts/src/ts-dsl/expr.ts | 6 +- .../openapi-ts/src/ts-dsl/mixins/access.ts | 64 +++++++++++++++++-- .../openapi-ts/src/ts-dsl/mixins/value.ts | 3 +- packages/openapi-ts/src/ts-dsl/new.ts | 5 +- packages/openapi-ts/src/ts-dsl/not.ts | 7 +- packages/openapi-ts/src/ts-dsl/return.ts | 15 +++-- 18 files changed, 166 insertions(+), 108 deletions(-) diff --git a/.changeset/chilled-wolves-pump.md b/.changeset/chilled-wolves-pump.md index 1802a812c..278e18733 100644 --- a/.changeset/chilled-wolves-pump.md +++ b/.changeset/chilled-wolves-pump.md @@ -2,4 +2,4 @@ "@hey-api/openapi-ts": patch --- -parser: merge `default` keyword with `$ref` in OpenAPI 3.1 +**parser**: merge `default` keyword with `$ref` in OpenAPI 3.1 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 33c9ed7ab..5a01884cb 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 @@ -392,13 +392,13 @@ export const generateClassSdk = ({ g .$if(!plugin.config.instance, (g) => g.public().static()) .do( - plugin.config.instance - ? $.return( - $.new(refChildClass.placeholder).args( + $.return( + plugin.config.instance + ? $.new(refChildClass.placeholder).args( $.object().prop('client', $('this').attr('client')), - ), - ) - : $.return(refChildClass.placeholder), + ) + : refChildClass.placeholder, + ), ), ); diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts index e8cd04106..74d7acaad 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts @@ -131,7 +131,7 @@ export const createQueryOptions = ({ .param(optionsParamName, (p) => p.optional(!isRequiredOptions).type(typeData), ) - .do($.return($(symbolQueryOptions.placeholder).call(queryOptionsObj))), + .do($(symbolQueryOptions.placeholder).call(queryOptionsObj).return()), ); plugin.setSymbolValue(symbolQueryOptionsFn, statement); }; diff --git a/packages/openapi-ts/src/plugins/arktype/v2/api.ts b/packages/openapi-ts/src/plugins/arktype/v2/api.ts index 38a4688fc..ccc010f4d 100644 --- a/packages/openapi-ts/src/plugins/arktype/v2/api.ts +++ b/packages/openapi-ts/src/plugins/arktype/v2/api.ts @@ -35,12 +35,11 @@ export const createRequestValidatorV2 = ({ .async() .param(dataParameterName) .do( - $.return( - $(symbol.placeholder) - .attr('parseAsync') - .call($(dataParameterName)) - .await(), - ), + $(symbol.placeholder) + .attr('parseAsync') + .call(dataParameterName) + .await() + .return(), ); }; @@ -62,11 +61,10 @@ export const createResponseValidatorV2 = ({ .async() .param(dataParameterName) .do( - $.return( - $(symbol.placeholder) - .attr('parseAsync') - .call($(dataParameterName)) - .await(), - ), + $(symbol.placeholder) + .attr('parseAsync') + .call(dataParameterName) + .await() + .return(), ); }; diff --git a/packages/openapi-ts/src/plugins/swr/v2/useSwr.ts b/packages/openapi-ts/src/plugins/swr/v2/useSwr.ts index f4e2f8865..932d7506f 100644 --- a/packages/openapi-ts/src/plugins/swr/v2/useSwr.ts +++ b/packages/openapi-ts/src/plugins/swr/v2/useSwr.ts @@ -56,14 +56,14 @@ export const createUseSwr = ({ ) .assign( $.func().do( - $.return( - $(symbolUseSwr.placeholder).call( + $(symbolUseSwr.placeholder) + .call( $.literal(operation.path), $.func() .async() .do(...statements), - ), - ), + ) + .return(), ), ); plugin.setSymbolValue(symbolUseQueryFn, statement); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/api.ts b/packages/openapi-ts/src/plugins/valibot/v1/api.ts index 51f0056fd..7f31d0c79 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/api.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/api.ts @@ -25,12 +25,11 @@ export const createRequestValidatorV1 = ({ .async() .param(dataParameterName) .do( - $.return( - $(v.placeholder) - .attr(identifiers.async.parseAsync) - .call($(symbol.placeholder), $(dataParameterName)) - .await(), - ), + $(v.placeholder) + .attr(identifiers.async.parseAsync) + .call(symbol.placeholder, dataParameterName) + .await() + .return(), ); }; @@ -56,11 +55,10 @@ export const createResponseValidatorV1 = ({ .async() .param(dataParameterName) .do( - $.return( - $(v.placeholder) - .attr(identifiers.async.parseAsync) - .call($(symbol.placeholder), $(dataParameterName)) - .await(), - ), + $(v.placeholder) + .attr(identifiers.async.parseAsync) + .call(symbol.placeholder, dataParameterName) + .await() + .return(), ); }; diff --git a/packages/openapi-ts/src/plugins/zod/mini/api.ts b/packages/openapi-ts/src/plugins/zod/mini/api.ts index 191e13bc1..522c113dd 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/api.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/api.ts @@ -22,12 +22,11 @@ export const createRequestValidatorMini = ({ .async() .param(dataParameterName) .do( - $.return( - $(symbol.placeholder) - .attr(identifiers.parseAsync) - .call($(dataParameterName)) - .await(), - ), + $(symbol.placeholder) + .attr(identifiers.parseAsync) + .call(dataParameterName) + .await() + .return(), ); }; @@ -49,11 +48,10 @@ export const createResponseValidatorMini = ({ .async() .param(dataParameterName) .do( - $.return( - $(symbol.placeholder) - .attr(identifiers.parseAsync) - .call($(dataParameterName)) - .await(), - ), + $(symbol.placeholder) + .attr(identifiers.parseAsync) + .call(dataParameterName) + .await() + .return(), ); }; diff --git a/packages/openapi-ts/src/plugins/zod/v3/api.ts b/packages/openapi-ts/src/plugins/zod/v3/api.ts index 4f79c0261..6086f6def 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/api.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/api.ts @@ -22,12 +22,11 @@ export const createRequestValidatorV3 = ({ .async() .param(dataParameterName) .do( - $.return( - $(symbol.placeholder) - .attr(identifiers.parseAsync) - .call($(dataParameterName)) - .await(), - ), + $(symbol.placeholder) + .attr(identifiers.parseAsync) + .call(dataParameterName) + .await() + .return(), ); }; @@ -49,11 +48,10 @@ export const createResponseValidatorV3 = ({ .async() .param(dataParameterName) .do( - $.return( - $(symbol.placeholder) - .attr(identifiers.parseAsync) - .call($(dataParameterName)) - .await(), - ), + $(symbol.placeholder) + .attr(identifiers.parseAsync) + .call(dataParameterName) + .await() + .return(), ); }; diff --git a/packages/openapi-ts/src/plugins/zod/v4/api.ts b/packages/openapi-ts/src/plugins/zod/v4/api.ts index d22a2208b..c78592779 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/api.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/api.ts @@ -22,12 +22,11 @@ export const createRequestValidatorV4 = ({ .async() .param(dataParameterName) .do( - $.return( - $(symbol.placeholder) - .attr(identifiers.parseAsync) - .call(dataParameterName) - .await(), - ), + $(symbol.placeholder) + .attr(identifiers.parseAsync) + .call(dataParameterName) + .await() + .return(), ); }; @@ -49,11 +48,10 @@ export const createResponseValidatorV4 = ({ .async() .param(dataParameterName) .do( - $.return( - $(symbol.placeholder) - .attr(identifiers.parseAsync) - .call(dataParameterName) - .await(), - ), + $(symbol.placeholder) + .attr(identifiers.parseAsync) + .call(dataParameterName) + .await() + .return(), ); }; diff --git a/packages/openapi-ts/src/ts-dsl/attr.ts b/packages/openapi-ts/src/ts-dsl/attr.ts index 88b020ded..8f22c43ed 100644 --- a/packages/openapi-ts/src/ts-dsl/attr.ts +++ b/packages/openapi-ts/src/ts-dsl/attr.ts @@ -3,7 +3,7 @@ import ts from 'typescript'; import type { MaybeTsDsl, WithString } from './base'; import { TsDsl } from './base'; -import { AccessMixin } from './mixins/access'; +import { AccessMixin, registerLazyAccessAttrFactory } from './mixins/access'; import { mixin } from './mixins/apply'; import { AssignmentMixin } from './mixins/assignment'; import { OperatorMixin } from './mixins/operator'; @@ -59,3 +59,5 @@ export interface AttrTsDsl OperatorMixin, OptionalMixin {} mixin(AttrTsDsl, AccessMixin, AssignmentMixin, OperatorMixin, OptionalMixin); + +registerLazyAccessAttrFactory((expr, name) => new AttrTsDsl(expr, name)); diff --git a/packages/openapi-ts/src/ts-dsl/await.ts b/packages/openapi-ts/src/ts-dsl/await.ts index 5bece0efc..592535235 100644 --- a/packages/openapi-ts/src/ts-dsl/await.ts +++ b/packages/openapi-ts/src/ts-dsl/await.ts @@ -1,18 +1,25 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */ import ts from 'typescript'; import type { MaybeTsDsl, WithString } from './base'; import { TsDsl } from './base'; +import { AccessMixin, registerLazyAccessAwaitFactory } from './mixins/access'; +import { mixin } from './mixins/apply'; export class AwaitTsDsl extends TsDsl { - private exprNode: MaybeTsDsl; + private _awaitExpr: MaybeTsDsl; constructor(expr: MaybeTsDsl) { super(); - this.exprNode = expr; + this._awaitExpr = expr; } $render(): ts.AwaitExpression { - const expr = this.$node(this.exprNode); - return ts.factory.createAwaitExpression(expr); + return ts.factory.createAwaitExpression(this.$node(this._awaitExpr)); } } + +export interface AwaitTsDsl extends AccessMixin {} +mixin(AwaitTsDsl, AccessMixin); + +registerLazyAccessAwaitFactory((expr) => new AwaitTsDsl(expr)); diff --git a/packages/openapi-ts/src/ts-dsl/call.ts b/packages/openapi-ts/src/ts-dsl/call.ts index fb3cdb0d1..0cae679b0 100644 --- a/packages/openapi-ts/src/ts-dsl/call.ts +++ b/packages/openapi-ts/src/ts-dsl/call.ts @@ -1,37 +1,34 @@ -/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ import ts from 'typescript'; -import { AwaitTsDsl } from './await'; import type { MaybeTsDsl, WithString } from './base'; import { TsDsl } from './base'; +import { AccessMixin, registerLazyAccessCallFactory } from './mixins/access'; import { mixin } from './mixins/apply'; import { ArgsMixin } from './mixins/args'; export class CallTsDsl extends TsDsl { - private callee: MaybeTsDsl; + private _callee: MaybeTsDsl; constructor( callee: MaybeTsDsl, ...args: ReadonlyArray> ) { super(); - this.callee = callee; + this._callee = callee; this.args(...args); } - /** Await the result of the call expression. */ - await(): AwaitTsDsl { - return new AwaitTsDsl(this); - } - $render(): ts.CallExpression { return ts.factory.createCallExpression( - this.$node(this.callee), + this.$node(this._callee), undefined, this.$args(), ); } } -export interface CallTsDsl extends ArgsMixin {} -mixin(CallTsDsl, ArgsMixin); +export interface CallTsDsl extends AccessMixin, ArgsMixin {} +mixin(CallTsDsl, AccessMixin, ArgsMixin); + +registerLazyAccessCallFactory((expr, args) => new CallTsDsl(expr, ...args)); diff --git a/packages/openapi-ts/src/ts-dsl/expr.ts b/packages/openapi-ts/src/ts-dsl/expr.ts index 266c0a00e..9167bc82b 100644 --- a/packages/openapi-ts/src/ts-dsl/expr.ts +++ b/packages/openapi-ts/src/ts-dsl/expr.ts @@ -8,15 +8,15 @@ import { mixin } from './mixins/apply'; import { OperatorMixin } from './mixins/operator'; export class ExprTsDsl extends TsDsl { - private input: MaybeTsDsl; + private _exprInput: MaybeTsDsl; constructor(id: MaybeTsDsl) { super(); - this.input = id; + this._exprInput = id; } $render(): ts.Expression { - return this.$node(this.input); + return this.$node(this._exprInput); } } diff --git a/packages/openapi-ts/src/ts-dsl/mixins/access.ts b/packages/openapi-ts/src/ts-dsl/mixins/access.ts index 58334eb46..84dbdaf5c 100644 --- a/packages/openapi-ts/src/ts-dsl/mixins/access.ts +++ b/packages/openapi-ts/src/ts-dsl/mixins/access.ts @@ -1,8 +1,51 @@ import type ts from 'typescript'; -import { AttrTsDsl } from '../attr'; +import type { AttrTsDsl } from '../attr'; +import type { AwaitTsDsl } from '../await'; import type { MaybeTsDsl, WithString } from '../base'; -import { CallTsDsl } from '../call'; +import type { CallTsDsl } from '../call'; +import type { ReturnTsDsl } from '../return'; + +/** + * Access helpers depend on other DSL classes that are initialized later in the + * module graph. We store factory callbacks here and let each class lazily + * register its own implementation once it has finished evaluation. This keeps + * mixin application order predictable and avoids circular import crashes. + */ + +type AttrFactory = ( + expr: MaybeTsDsl, + name: WithString | number, +) => AttrTsDsl; +let attrFactory: AttrFactory | undefined; +/** Registers the Attr DSL factory after its module has finished evaluating. */ +export function registerLazyAccessAttrFactory(factory: AttrFactory): void { + attrFactory = factory; +} + +type AwaitFactory = (expr: MaybeTsDsl) => AwaitTsDsl; +let awaitFactory: AwaitFactory | undefined; +/** Registers the Await DSL factory after its module has finished evaluating. */ +export function registerLazyAccessAwaitFactory(factory: AwaitFactory): void { + awaitFactory = factory; +} + +type CallFactory = ( + expr: MaybeTsDsl, + args: ReadonlyArray>, +) => CallTsDsl; +let callFactory: CallFactory | undefined; +/** Registers the Call DSL factory after its module has finished evaluating. */ +export function registerLazyAccessCallFactory(factory: CallFactory): void { + callFactory = factory; +} + +type ReturnFactory = (expr: MaybeTsDsl) => ReturnTsDsl; +let returnFactory: ReturnFactory | undefined; +/** Registers the Return DSL factory after its module has finished evaluating. */ +export function registerLazyAccessReturnFactory(factory: ReturnFactory): void { + returnFactory = factory; +} export class AccessMixin { /** Accesses a property on the current expression (e.g. `this.foo`). */ @@ -10,13 +53,24 @@ export class AccessMixin { this: MaybeTsDsl, name: WithString | number, ): AttrTsDsl { - return new AttrTsDsl(this, name); + return attrFactory!(this, name); + } + + /** Awaits the current expression (e.g. `await expr`). */ + await(this: MaybeTsDsl): AwaitTsDsl { + return awaitFactory!(this); } - /** Calls the current expression as a function (e.g. `fn(arg1, arg2)`). */ + + /** Calls the current expression (e.g. `fn(arg1, arg2)`). */ call( this: MaybeTsDsl, ...args: ReadonlyArray> ): CallTsDsl { - return new CallTsDsl(this, ...args); + return callFactory!(this, args); + } + + /** Produces a `return` statement returning the current expression. */ + return(this: MaybeTsDsl): ReturnTsDsl { + return returnFactory!(this); } } diff --git a/packages/openapi-ts/src/ts-dsl/mixins/value.ts b/packages/openapi-ts/src/ts-dsl/mixins/value.ts index 6d51309c2..68dbb441b 100644 --- a/packages/openapi-ts/src/ts-dsl/mixins/value.ts +++ b/packages/openapi-ts/src/ts-dsl/mixins/value.ts @@ -1,6 +1,7 @@ import type ts from 'typescript'; -import { type MaybeTsDsl, TsDsl, type WithString } from '../base'; +import type { MaybeTsDsl, WithString } from '../base'; +import { TsDsl } from '../base'; export class ValueMixin extends TsDsl { private value?: MaybeTsDsl; diff --git a/packages/openapi-ts/src/ts-dsl/new.ts b/packages/openapi-ts/src/ts-dsl/new.ts index 82461c791..86c0eb885 100644 --- a/packages/openapi-ts/src/ts-dsl/new.ts +++ b/packages/openapi-ts/src/ts-dsl/new.ts @@ -3,6 +3,7 @@ import ts from 'typescript'; import type { MaybeTsDsl, WithString } from './base'; import { TsDsl } from './base'; +import { AccessMixin } from './mixins/access'; import { mixin } from './mixins/apply'; import { ArgsMixin } from './mixins/args'; import { GenericsMixin } from './mixins/generics'; @@ -31,5 +32,5 @@ export class NewTsDsl extends TsDsl { } } -export interface NewTsDsl extends ArgsMixin, GenericsMixin {} -mixin(NewTsDsl, ArgsMixin, GenericsMixin); +export interface NewTsDsl extends AccessMixin, ArgsMixin, GenericsMixin {} +mixin(NewTsDsl, AccessMixin, ArgsMixin, GenericsMixin); diff --git a/packages/openapi-ts/src/ts-dsl/not.ts b/packages/openapi-ts/src/ts-dsl/not.ts index a5926d3f5..0cb7ca83c 100644 --- a/packages/openapi-ts/src/ts-dsl/not.ts +++ b/packages/openapi-ts/src/ts-dsl/not.ts @@ -4,18 +4,17 @@ import type { MaybeTsDsl, WithString } from './base'; import { TsDsl } from './base'; export class NotTsDsl extends TsDsl { - private exprInput: MaybeTsDsl; + private _notExpr: MaybeTsDsl; constructor(expr: MaybeTsDsl) { super(); - this.exprInput = expr; + this._notExpr = expr; } $render(): ts.PrefixUnaryExpression { - const expression = this.$node(this.exprInput); return ts.factory.createPrefixUnaryExpression( ts.SyntaxKind.ExclamationToken, - expression, + this.$node(this._notExpr), ); } } diff --git a/packages/openapi-ts/src/ts-dsl/return.ts b/packages/openapi-ts/src/ts-dsl/return.ts index b74ba4780..4ea939615 100644 --- a/packages/openapi-ts/src/ts-dsl/return.ts +++ b/packages/openapi-ts/src/ts-dsl/return.ts @@ -1,18 +1,25 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */ import ts from 'typescript'; import type { MaybeTsDsl, WithString } from './base'; import { TsDsl } from './base'; +import { AccessMixin, registerLazyAccessReturnFactory } from './mixins/access'; +import { mixin } from './mixins/apply'; export class ReturnTsDsl extends TsDsl { - private expr?: MaybeTsDsl; + private _returnExpr?: MaybeTsDsl; constructor(expr?: MaybeTsDsl) { super(); - this.expr = expr; + this._returnExpr = expr; } $render(): ts.ReturnStatement { - const exprNode = this.$node(this.expr); - return ts.factory.createReturnStatement(exprNode); + return ts.factory.createReturnStatement(this.$node(this._returnExpr)); } } + +export interface ReturnTsDsl extends AccessMixin {} +mixin(ReturnTsDsl, AccessMixin); + +registerLazyAccessReturnFactory((expr) => new ReturnTsDsl(expr));