fork of hey-api/openapi-ts because I need some additional things
1import type { AnalysisContext } from '@hey-api/codegen-core';
2
3import { py } from '../../py-compiler';
4import type { MaybePyDsl } from '../base';
5import { PyDsl } from '../base';
6import type { DoExpr } from '../mixins/do';
7import { BlockPyDsl } from './block';
8
9const Mixed = PyDsl<py.WithStatement>;
10
11export type WithItemInput =
12 | MaybePyDsl<py.Expression>
13 | { alias?: MaybePyDsl<py.Expression>; context: MaybePyDsl<py.Expression> };
14
15export class WithPyDsl extends Mixed {
16 readonly '~dsl' = 'WithPyDsl';
17
18 protected _body?: Array<DoExpr>;
19 protected _items: Array<WithItemInput> = [];
20 protected _modifier?: MaybePyDsl<py.Expression>;
21
22 constructor(...items: Array<WithItemInput>) {
23 super();
24 this._items = items;
25 }
26
27 override analyze(ctx: AnalysisContext): void {
28 super.analyze(ctx);
29
30 for (const item of this._items) {
31 if (typeof item === 'object' && 'context' in item) {
32 ctx.analyze(item.context);
33 ctx.analyze(item.alias);
34 } else {
35 ctx.analyze(item);
36 }
37 }
38 if (this._modifier) ctx.analyze(this._modifier);
39
40 if (this._body) {
41 ctx.pushScope();
42 try {
43 for (const stmt of this._body) ctx.analyze(stmt);
44 } finally {
45 ctx.popScope();
46 }
47 }
48 }
49
50 /** Returns true when all required builder calls are present. */
51 get isValid(): boolean {
52 return !this.missingRequiredCalls().length;
53 }
54
55 body(...items: Array<DoExpr>): this {
56 this._body = items;
57 return this;
58 }
59
60 item(item: WithItemInput): this {
61 this._items.push(item);
62 return this;
63 }
64
65 modifier(expr: MaybePyDsl<py.Expression>): this {
66 this._modifier = expr;
67 return this;
68 }
69
70 async(): this {
71 this._modifier = py.factory.createIdentifier('async');
72 return this;
73 }
74
75 override toAst() {
76 this.$validate();
77
78 const astItems = this._items.map((item) => {
79 if (typeof item === 'object' && 'context' in item) {
80 return py.factory.createWithItem(this.$node(item.context), this.$node(item.alias));
81 }
82 return py.factory.createWithItem(this.$node(item), undefined);
83 });
84
85 const body = new BlockPyDsl(...this._body!).$do();
86
87 return py.factory.createWithStatement(
88 astItems,
89 [...body],
90 this._modifier ? [this.$node(this._modifier)] : undefined,
91 );
92 }
93
94 $validate(): asserts this is this & {
95 _body: Array<DoExpr>;
96 } {
97 const missing = this.missingRequiredCalls();
98 if (!missing.length) return;
99 throw new Error(`With statement missing ${missing.join(' and ')}`);
100 }
101
102 private missingRequiredCalls(): ReadonlyArray<string> {
103 const missing: Array<string> = [];
104 if (!this._items.length) missing.push('items');
105 if (!this._body || !this._body.length) missing.push('.body()');
106 return missing;
107 }
108}