···88import type { ReturnTsDsl } from '../return';
991010/**
1111- * Access helpers depend on other DSL classes that are initialized later in the
1212- * module graph. We store factory callbacks here and let each class lazily
1313- * register its own implementation once it has finished evaluation. This keeps
1414- * mixin application order predictable and avoids circular import crashes.
1111+ * Lazily register factory callbacks to avoid circular imports and
1212+ * ensure predictable mixin application order.
1513 */
16141715type AsFactory = (
···1917 type: string | TypeTsDsl,
2018) => AsTsDsl;
2119let asFactory: AsFactory | undefined;
2222-/** Registers the Attr DSL factory after its module has finished evaluating. */
2020+/** Registers the As DSL factory after its module has finished evaluating. */
2321export function registerLazyAccessAsFactory(factory: AsFactory): void {
2422 asFactory = factory;
2523}
···2020 return this;
2121 }
22222323- /**
2424- * Returns the type arguments as an array of ts.TypeNode nodes.
2525- */
2323+ /** Returns the type arguments as an array of ts.TypeNode nodes. */
2624 protected $generics(): ReadonlyArray<ts.TypeNode> | undefined {
2725 return this.$type(this._generics);
2826 }
···2222 return this;
2323 }
24242525- /**
2626- * Returns the type parameters as an array of ts.TypeParameterDeclaration nodes.
2727- */
2525+ /** Returns the type parameters as an array of ts.TypeParameterDeclaration nodes. */
2826 protected $generics():
2927 | ReadonlyArray<ts.TypeParameterDeclaration>
3028 | undefined {
+15-1
packages/openapi-ts/src/ts-dsl/object.ts
···1515export class ObjectTsDsl extends TsDsl<ts.ObjectLiteralExpression> {
1616 private props: Array<
1717 | {
1818+ expr: string | MaybeTsDsl<ts.Expression>;
1919+ kind: 'computed';
2020+ name: string;
2121+ }
2222+ | {
1823 expr: string | MaybeTsDsl<ts.Statement>;
1924 kind: 'getter';
2025 name: string;
···2732 }
2833 | { expr: string | MaybeTsDsl<ts.Expression>; kind: 'spread' }
2934 > = [];
3535+3636+ /** Adds a computed property (e.g. `{ [expr]: value }`). */
3737+ computed(name: string, expr: string | MaybeTsDsl<ts.Expression>): this {
3838+ this.props.push({ expr, kind: 'computed', name });
3939+ return this;
4040+ }
30413142 /** Adds a getter property (e.g. `{ get foo() { ... } }`). */
3243 getter(name: string, expr: string | MaybeTsDsl<ts.Statement>): this {
···94105 'Invalid property: object property value must be an expression, not a statement.',
95106 );
96107 }
108108+ const name = this.safePropertyName(p.name);
97109 return ts.factory.createPropertyAssignment(
9898- this.safePropertyName(p.name),
110110+ p.kind === 'computed'
111111+ ? ts.factory.createComputedPropertyName(this.$node(name as string))
112112+ : name,
99113 node,
100114 );
101115 });
+1-1
packages/openapi-ts/src/ts-dsl/return.ts
···2222export interface ReturnTsDsl extends ExprMixin {}
2323mixin(ReturnTsDsl, ExprMixin);
24242525-registerLazyAccessReturnFactory((expr) => new ReturnTsDsl(expr));
2525+registerLazyAccessReturnFactory((...args) => new ReturnTsDsl(...args));
+6
packages/openapi-ts/src/ts-dsl/type/attr.ts
···11+/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
12import ts from 'typescript';
2334import type { MaybeTsDsl } from '../base';
45import { TsDsl } from '../base';
66+import { mixin } from '../mixins/apply';
77+import { TypeExprMixin } from '../mixins/type-expr';
5869export class TypeAttrTsDsl extends TsDsl<ts.QualifiedName> {
710 private _base?: string | MaybeTsDsl<ts.EntityName>;
···4346 return ts.factory.createQualifiedName(left, right);
4447 }
4548}
4949+5050+export interface TypeAttrTsDsl extends TypeExprMixin {}
5151+mixin(TypeAttrTsDsl, TypeExprMixin);
+12-3
packages/openapi-ts/src/ts-dsl/type/expr.ts
···11-/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */
11+/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
22import ts from 'typescript';
3344import { TypeTsDsl } from '../base';
55import { mixin } from '../mixins/apply';
66import { TypeArgsMixin } from '../mixins/type-args';
77+import {
88+ registerLazyAccessTypeExprFactory,
99+ TypeExprMixin,
1010+} from '../mixins/type-expr';
711import { TypeAttrTsDsl } from './attr';
812import { TypeIdxTsDsl } from './idx';
913···5256 }
5357}
54585555-export interface TypeExprTsDsl extends TypeArgsMixin {}
5656-mixin(TypeExprTsDsl, TypeArgsMixin);
5959+export interface TypeExprTsDsl extends TypeArgsMixin, TypeExprMixin {}
6060+mixin(TypeExprTsDsl, TypeArgsMixin, TypeExprMixin);
6161+6262+registerLazyAccessTypeExprFactory(
6363+ (...args) =>
6464+ new TypeExprTsDsl(...(args as ConstructorParameters<typeof TypeExprTsDsl>)),
6565+);
+8-10
packages/openapi-ts/src/ts-dsl/type/query.ts
···2233import type { MaybeTsDsl } from '../base';
44import { TypeTsDsl } from '../base';
55+import { registerLazyAccessTypeQueryFactory } from '../mixins/type-expr';
5667export class TypeQueryTsDsl extends TypeTsDsl<ts.TypeQueryNode> {
77- private expr: string | MaybeTsDsl<ts.Expression>;
88+ private _expr: string | MaybeTsDsl<TypeTsDsl | ts.Expression>;
8999- constructor(expr: string | MaybeTsDsl<ts.Expression>) {
1010+ constructor(expr: string | MaybeTsDsl<TypeTsDsl | ts.Expression>) {
1011 super();
1111- this.expr = expr;
1212+ this._expr = expr;
1213 }
13141415 $render(): ts.TypeQueryNode {
1515- const exprName = this.$node(this.expr);
1616- if (!ts.isEntityName(exprName)) {
1717- throw new Error(
1818- 'TypeQueryTsDsl: expression must resolve to an EntityName',
1919- );
2020- }
2121- return ts.factory.createTypeQueryNode(exprName);
1616+ const expr = this.$node(this._expr);
1717+ return ts.factory.createTypeQueryNode(expr as unknown as ts.EntityName);
2218 }
2319}
2020+2121+registerLazyAccessTypeQueryFactory((...args) => new TypeQueryTsDsl(...args));
+3
packages/openapi-ts/src/ts-dsl/typeof.ts
···55import { TsDsl } from './base';
66import { mixin } from './mixins/apply';
77import { OperatorMixin } from './mixins/operator';
88+import { registerLazyAccessTypeOfExprFactory } from './mixins/type-expr';
89910export class TypeOfExprTsDsl extends TsDsl<ts.TypeOfExpression> {
1011 private _expr: string | MaybeTsDsl<ts.Expression>;
···21222223export interface TypeOfExprTsDsl extends OperatorMixin {}
2324mixin(TypeOfExprTsDsl, OperatorMixin);
2525+2626+registerLazyAccessTypeOfExprFactory((...args) => new TypeOfExprTsDsl(...args));