fork of hey-api/openapi-ts because I need some additional things
at feat/skip-token 111 lines 3.0 kB view raw
1import type { AnalysisContext } from '@hey-api/codegen-core'; 2 3import { py } from '../../ts-python'; 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 === 0; 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(): py.WithStatement { 76 this.$validate(); 77 78 const astItems = this._items.map((item) => { 79 if (typeof item === 'object' && 'context' in item) { 80 return py.factory.createWithItem( 81 this.$node(item.context) as py.Expression, 82 item.alias ? (this.$node(item.alias) as py.Expression) : undefined, 83 ); 84 } 85 return py.factory.createWithItem(this.$node(item) as py.Expression, undefined); 86 }); 87 88 const body = new BlockPyDsl(...this._body!).$do(); 89 90 return py.factory.createWithStatement( 91 astItems, 92 [...body], 93 this._modifier ? [this.$node(this._modifier) as py.Expression] : undefined, 94 ); 95 } 96 97 $validate(): asserts this is this & { 98 _body: Array<DoExpr>; 99 } { 100 const missing = this.missingRequiredCalls(); 101 if (missing.length === 0) return; 102 throw new Error(`With statement missing ${missing.join(' and ')}`); 103 } 104 105 private missingRequiredCalls(): ReadonlyArray<string> { 106 const missing: Array<string> = []; 107 if (!this._items.length) missing.push('items'); 108 if (!this._body || this._body.length === 0) missing.push('.body()'); 109 return missing; 110 } 111}