fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3520 from hey-api/chore/renderer-exports

chore: render exports

authored by

Lubos and committed by
GitHub
cf5ae58d 234c7f4c

+157 -103
+2 -3
packages/openapi-python/src/plugins/@hey-api/sdk/v1/node.ts
··· 100 100 101 101 const symbolClient = plugin.external('client.Client'); 102 102 103 - const c = $.class(symbol).extends(symbolClient); 103 + const c = $.class(symbol).export().extends(symbolClient); 104 104 105 105 const dependencies: Array<ReturnType<typeof $.class>> = []; 106 106 ··· 137 137 String(item.location[item.location.length - 1]), 138 138 plugin.config.operations.methodName, 139 139 ); 140 - const node = $.func(fnName); 141 - node.do($.return($.id('None'))); 140 + const node = $.func(fnName).export().do($('None').return()); 142 141 nodes.push(node); 143 142 } 144 143 return { nodes };
+2 -1
packages/openapi-python/src/py-dsl/decl/class.ts
··· 7 7 import { DecoratorMixin } from '../mixins/decorator'; 8 8 import { DocMixin } from '../mixins/doc'; 9 9 import { LayoutMixin } from '../mixins/layout'; 10 + import { ExportMixin } from '../mixins/modifiers'; 10 11 import { safeRuntimeName } from '../utils/name'; 11 12 12 13 type Body = Array<MaybePyDsl<py.Statement>>; 13 14 14 - const Mixed = DecoratorMixin(DocMixin(LayoutMixin(PyDsl<py.ClassDeclaration>))); 15 + const Mixed = DecoratorMixin(DocMixin(ExportMixin(LayoutMixin(PyDsl<py.ClassDeclaration>)))); 15 16 16 17 export class ClassPyDsl extends Mixed { 17 18 readonly '~dsl' = 'ClassPyDsl';
+3 -3
packages/openapi-python/src/py-dsl/decl/func.ts
··· 7 7 import { DoMixin } from '../mixins/do'; 8 8 import { DocMixin } from '../mixins/doc'; 9 9 import { LayoutMixin } from '../mixins/layout'; 10 - import { AsyncMixin, ModifiersMixin } from '../mixins/modifiers'; 10 + import { AsyncMixin, ExportMixin } from '../mixins/modifiers'; 11 11 import { safeRuntimeName } from '../utils/name'; 12 12 13 - const Mixed = DecoratorMixin( 14 - DocMixin(DoMixin(LayoutMixin(AsyncMixin(ModifiersMixin(PyDsl<py.FunctionDeclaration>))))), 13 + const Mixed = AsyncMixin( 14 + DecoratorMixin(DocMixin(DoMixin(ExportMixin(LayoutMixin(PyDsl<py.FunctionDeclaration>))))), 15 15 ); 16 16 17 17 export class FuncPyDsl extends Mixed {
+36 -1
packages/openapi-python/src/py-dsl/mixins/modifiers.ts
··· 34 34 } 35 35 } 36 36 37 - export function ModifiersMixin<T extends py.Node, TBase extends BaseCtor<T>>(Base: TBase) { 37 + function ModifiersMixin<T extends py.Node, TBase extends BaseCtor<T>>(Base: TBase) { 38 38 abstract class Modifiers extends Base { 39 39 protected modifiers: Array<py.Expression> = []; 40 40 ··· 84 84 85 85 return Async as unknown as MixinCtor<TBase, AsyncMethods>; 86 86 } 87 + 88 + export interface ExportMethods extends Modifiers { 89 + /** 90 + * Adds the `export` keyword modifier if the condition is true. 91 + * 92 + * @param condition - Whether to add the modifier (default: true). 93 + * @returns The target object for chaining. 94 + */ 95 + export(condition?: boolean): this; 96 + } 97 + 98 + /** 99 + * Mixin that adds an `export` modifier to a node. 100 + */ 101 + export function ExportMixin<T extends py.Node, TBase extends BaseCtor<T>>(Base: TBase) { 102 + const Mixed = ModifiersMixin(Base as BaseCtor<T>); 103 + 104 + abstract class Export extends Mixed { 105 + /** 106 + * Adds the `export` keyword modifier if the condition is true. 107 + * 108 + * @param condition - Whether to add the modifier (default: true). 109 + * @returns The target object for chaining. 110 + */ 111 + protected export(condition?: boolean): this { 112 + const cond = arguments.length === 0 ? true : Boolean(condition); 113 + this.exported = cond; 114 + // TODO: remove this side-effect once planner handles exported flag 115 + if (this.symbol) this.symbol.setExported(cond); 116 + return this; 117 + } 118 + } 119 + 120 + return Export as unknown as MixinCtor<TBase, ExportMethods>; 121 + }
+114 -95
packages/openapi-python/src/py-dsl/utils/render.ts
··· 11 11 preferExportAll?: boolean; 12 12 }; 13 13 type Header = MaybeArray<string> | null | undefined; 14 - type Imports = ReadonlyArray<ReadonlyArray<ModuleImport>>; 14 + type Imports = Array<ReadonlyArray<ModuleImport>>; 15 15 16 16 function headerToLines(header: Header): ReadonlyArray<string> { 17 17 if (!header) return []; ··· 69 69 render(ctx: RenderContext<PyDsl>): string { 70 70 const header = typeof this._header === 'function' ? this._header(ctx) : this._header; 71 71 return PythonRenderer.astToString({ 72 - // exports: this.getExports(ctx), 72 + exports: this.getExports(ctx), 73 73 exportsOptions: { 74 74 preferExportAll: this._preferExportAll, 75 75 }, ··· 101 101 text += `${header}\n`; 102 102 } 103 103 104 + const argsImports = args.imports ?? []; 105 + 106 + for (const group of args.exports ?? []) { 107 + for (const exp of group) { 108 + let found = false; 109 + for (const impGroup of argsImports) { 110 + if (found) break; 111 + for (const imp of impGroup) { 112 + if (imp.modulePath === exp.modulePath) { 113 + // TODO: merge imports and exports from the same module 114 + found = true; 115 + break; 116 + } 117 + } 118 + } 119 + if (!found) { 120 + argsImports.push([ 121 + { 122 + imports: exp.exports.map((exp) => ({ 123 + isTypeOnly: exp.isTypeOnly, 124 + localName: exp.exportedName, 125 + sourceName: exp.exportedName, 126 + })), 127 + isTypeOnly: false, 128 + kind: 'named', 129 + modulePath: exp.modulePath, 130 + }, 131 + ]); 132 + } 133 + } 134 + } 135 + 104 136 let imports = ''; 105 - for (const group of args.imports ?? []) { 137 + for (const group of argsImports) { 106 138 if (imports) imports += '\n'; 107 139 for (const imp of group) { 108 - imports += `${astToString(PythonRenderer.toImportAst(imp))}\n`; 140 + imports += `${astToString(PythonRenderer.toImportAst(imp))}`; 109 141 } 110 142 } 111 143 text = `${text}${text && imports ? '\n' : ''}${imports}`; 112 144 145 + let exports = ''; 146 + for (const group of args.exports ?? []) { 147 + if (exports) exports += '\n'; 148 + for (const exp of group) { 149 + exports += `${astToString(PythonRenderer.toExportAst(exp, args.exportsOptions))}`; 150 + } 151 + } 152 + text = `${text}${text && exports ? '\n' : ''}${exports}`; 153 + 113 154 let nodes = ''; 114 155 for (const node of args.nodes ?? []) { 115 - if (nodes) nodes += '\n'; 116 - nodes += `${astToString(node.toAst())}\n`; 156 + if (nodes) nodes += '\n\n'; 157 + nodes += `${astToString(node.toAst())}`; 117 158 } 118 - text = `${text}${text && nodes ? '\n' : ''}${nodes}`; 119 - 120 - const exports = ''; 121 - // let exports = ''; 122 - // for (const group of args.exports ?? []) { 123 - // if ((!exports && nodes) || exports) exports += '\n'; 124 - // for (const exp of group) { 125 - // exports += `${astToString(PythonRenderer.toExportAst(exp, args.exportsOptions))}\n`; 126 - // } 127 - // } 128 - text = `${text}${text && exports ? '\n' : ''}${exports}`; 159 + text = `${text}${text && nodes ? '\n\n' : ''}${nodes}`; 129 160 130 161 if (args.trailingNewline === false && text.endsWith('\n')) { 131 162 text = text.slice(0, -1); ··· 134 165 return text; 135 166 } 136 167 137 - // static toExportAst(group: ModuleExport, options?: ExportsOptions): ts.ExportDeclaration { 138 - // const specifiers = group.exports.map((exp) => { 139 - // const specifier = ts.factory.createExportSpecifier( 140 - // exp.isTypeOnly, 141 - // exp.sourceName !== exp.exportedName ? $.id(exp.sourceName).toAst() : undefined, 142 - // $.id(exp.exportedName).toAst(), 143 - // ); 144 - // return specifier; 145 - // }); 146 - // const exportClause = group.namespaceExport 147 - // ? ts.factory.createNamespaceExport($.id(group.namespaceExport).toAst()) 148 - // : (!group.canExportAll || !options?.preferExportAll) && specifiers.length 149 - // ? ts.factory.createNamedExports(specifiers) 150 - // : undefined; 151 - // return ts.factory.createExportDeclaration( 152 - // undefined, 153 - // group.isTypeOnly, 154 - // exportClause, 155 - // $.literal(group.modulePath).toAst(), 156 - // ); 157 - // } 168 + // eslint-disable-next-line @typescript-eslint/no-unused-vars 169 + static toExportAst(group: ModuleExport, options?: ExportsOptions): py.Assignment { 170 + const specifiers = group.exports.map((exp) => py.factory.createLiteral(exp.exportedName)); 171 + return py.factory.createAssignment( 172 + py.factory.createIdentifier('__all__'), 173 + undefined, 174 + py.factory.createListExpression(specifiers), 175 + ); 176 + } 158 177 159 178 static toImportAst(group: ModuleImport): py.ImportStatement { 160 179 const names: Array<{ ··· 167 186 return py.factory.createImportStatement(group.modulePath, names, group.imports.length > 0); 168 187 } 169 188 170 - // private getExports(ctx: RenderContext): Exports { 171 - // type ModuleEntry = { 172 - // group: ModuleExport; 173 - // sortKey: SortKey; 174 - // }; 189 + private getExports(ctx: RenderContext): Exports { 190 + type ModuleEntry = { 191 + group: ModuleExport; 192 + sortKey: SortKey; 193 + }; 175 194 176 - // const groups = new Map<SortGroup, Map<SortModule, ModuleEntry>>(); 195 + const groups = new Map<SortGroup, Map<SortModule, ModuleEntry>>(); 177 196 178 - // for (const exp of ctx.file.exports) { 179 - // const sortKey = moduleSortKey({ 180 - // file: ctx.file, 181 - // fromFile: exp.from, 182 - // preferFileExtension: this._preferFileExtension, 183 - // root: ctx.project.root, 184 - // }); 185 - // const modulePath = this._resolveModuleName?.(sortKey[2]) ?? sortKey[2]; 186 - // const [groupIndex] = sortKey; 197 + for (const exp of ctx.file.exports) { 198 + const sortKey = moduleSortKey({ 199 + file: ctx.file, 200 + fromFile: exp.from, 201 + preferFileExtension: this._preferFileExtension, 202 + root: ctx.project.root, 203 + }); 204 + const modulePath = this._resolveModuleName?.(sortKey[2]) ?? sortKey[2]; 205 + const [groupIndex] = sortKey; 187 206 188 - // if (!groups.has(groupIndex)) groups.set(groupIndex, new Map()); 189 - // const moduleMap = groups.get(groupIndex)!; 207 + if (!groups.has(groupIndex)) groups.set(groupIndex, new Map()); 208 + const moduleMap = groups.get(groupIndex)!; 190 209 191 - // if (!moduleMap.has(modulePath)) { 192 - // moduleMap.set(modulePath, { 193 - // group: { 194 - // canExportAll: exp.canExportAll, 195 - // exports: exp.exports, 196 - // isTypeOnly: exp.isTypeOnly, 197 - // modulePath, 198 - // namespaceExport: exp.namespaceExport, 199 - // }, 200 - // sortKey, 201 - // }); 202 - // } 203 - // } 210 + if (!moduleMap.has(modulePath)) { 211 + moduleMap.set(modulePath, { 212 + group: { 213 + canExportAll: exp.canExportAll, 214 + exports: exp.exports, 215 + isTypeOnly: exp.isTypeOnly, 216 + modulePath, 217 + namespaceExport: exp.namespaceExport, 218 + }, 219 + sortKey, 220 + }); 221 + } 222 + } 204 223 205 - // const exports: Array<Array<ModuleExport>> = Array.from(groups.entries()) 206 - // .sort((a, b) => a[0] - b[0]) 207 - // .map(([, moduleMap]) => { 208 - // const entries = Array.from(moduleMap.values()); 224 + const exports: Array<Array<ModuleExport>> = Array.from(groups.entries()) 225 + .sort((a, b) => a[0] - b[0]) 226 + .map(([, moduleMap]) => { 227 + const entries = Array.from(moduleMap.values()); 209 228 210 - // entries.sort((a, b) => { 211 - // const d = a.sortKey[1] - b.sortKey[1]; 212 - // return d !== 0 ? d : a.group.modulePath.localeCompare(b.group.modulePath); 213 - // }); 229 + entries.sort((a, b) => { 230 + const d = a.sortKey[1] - b.sortKey[1]; 231 + return d !== 0 ? d : a.group.modulePath.localeCompare(b.group.modulePath); 232 + }); 214 233 215 - // return entries.map((e) => { 216 - // const group = e.group; 217 - // if (group.namespaceExport) { 218 - // group.exports = []; 219 - // } else { 220 - // const isTypeOnly = !group.exports.find((exp) => !exp.isTypeOnly); 221 - // if (isTypeOnly) { 222 - // group.isTypeOnly = true; 223 - // for (const exp of group.exports) { 224 - // exp.isTypeOnly = false; 225 - // } 226 - // } 227 - // group.exports.sort((a, b) => a.exportedName.localeCompare(b.exportedName)); 228 - // } 229 - // return group; 230 - // }); 231 - // }); 234 + return entries.map((e) => { 235 + const group = e.group; 236 + if (group.namespaceExport) { 237 + group.exports = []; 238 + } else { 239 + const isTypeOnly = !group.exports.find((exp) => !exp.isTypeOnly); 240 + if (isTypeOnly) { 241 + group.isTypeOnly = true; 242 + for (const exp of group.exports) { 243 + exp.isTypeOnly = false; 244 + } 245 + } 246 + group.exports.sort((a, b) => a.exportedName.localeCompare(b.exportedName)); 247 + } 248 + return group; 249 + }); 250 + }); 232 251 233 - // return exports; 234 - // } 252 + return exports; 253 + } 235 254 236 255 private getImports(ctx: RenderContext): Imports { 237 256 type ModuleEntry = {