Skip to content

Commit 7ab277b

Browse files
committed
feat: add namespace supporting for enums
1 parent 810a4c2 commit 7ab277b

File tree

6 files changed

+100
-6
lines changed

6 files changed

+100
-6
lines changed

.changeset/bright-poets-confess.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@hey-api/openapi-ts': minor
3+
---
4+
5+
feat: add namespace supporting for enums

packages/openapi-ts/src/compiler/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ export const compiler = {
179179
array: types.createArrayType,
180180
enum: types.createEnumDeclaration,
181181
function: types.createFunction,
182+
namespace: types.createNamespaceDeclaration,
182183
object: types.createObjectType,
183184
},
184185
utils: {

packages/openapi-ts/src/compiler/types.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,25 @@ export const createEnumDeclaration = <T extends object>({
355355
}
356356
return declaration;
357357
};
358+
359+
/**
360+
* Create namespace declaration. Example `export namespace MyNamespace { ... }`
361+
* @param name - the name of the namespace.
362+
* @param nodes - the nodes in the namespace.
363+
* @returns
364+
*/
365+
export const createNamespaceDeclaration = <
366+
T extends Array<ts.EnumDeclaration>,
367+
>({
368+
name,
369+
statements,
370+
}: {
371+
name: string;
372+
statements: T;
373+
}) =>
374+
ts.factory.createModuleDeclaration(
375+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
376+
ts.factory.createIdentifier(name),
377+
ts.factory.createModuleBlock(statements),
378+
ts.NodeFlags.Namespace,
379+
);

packages/openapi-ts/src/generate/types.ts

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { EnumDeclaration } from 'typescript';
2+
13
import {
24
type Comments,
35
compiler,
@@ -121,10 +123,34 @@ export const generateType = ({
121123
};
122124

123125
const processComposition = (props: TypesProps) => {
124-
processType(props);
125-
props.model.enums.forEach((enumerator) =>
126-
processEnum({ ...props, model: enumerator }),
127-
);
126+
const config = getConfig();
127+
128+
if (config.types.enums !== 'typescript+namespace') {
129+
processType(props);
130+
props.model.enums.forEach((enumerator) =>
131+
processEnum({ ...props, model: enumerator }),
132+
);
133+
} else {
134+
const enumDeclarations = [] as EnumDeclaration[];
135+
props.model.enums.forEach((enumerator) =>
136+
processScopedEnum({
137+
...props,
138+
model: enumerator,
139+
onNode: (node) => {
140+
enumDeclarations.push(node as EnumDeclaration);
141+
},
142+
}),
143+
);
144+
processType(props);
145+
if (enumDeclarations.length > 0) {
146+
props.onNode(
147+
compiler.types.namespace({
148+
name: props.model.name,
149+
statements: enumDeclarations,
150+
}),
151+
);
152+
}
153+
}
128154
};
129155

130156
const processEnum = ({ client, model, onNode }: TypesProps) => {
@@ -146,7 +172,10 @@ const processEnum = ({ client, model, onNode }: TypesProps) => {
146172
model.deprecated && '@deprecated',
147173
];
148174

149-
if (config.types.enums === 'typescript') {
175+
if (
176+
config.types.enums === 'typescript' ||
177+
config.types.enums === 'typescript+namespace'
178+
) {
150179
generateEnum({
151180
client,
152181
comments,
@@ -185,6 +214,30 @@ const processEnum = ({ client, model, onNode }: TypesProps) => {
185214
});
186215
};
187216

217+
const processScopedEnum = ({ model, onNode }: TypesProps) => {
218+
const properties: Record<string | number, unknown> = {};
219+
const comments: Record<string | number, Comments> = {};
220+
model.enum.forEach((enumerator) => {
221+
const { key, value } = enumEntry(enumerator);
222+
properties[key] = value;
223+
const comment = enumerator.customDescription || enumerator.description;
224+
if (comment) {
225+
comments[key] = [escapeComment(comment)];
226+
}
227+
});
228+
onNode(
229+
compiler.types.enum({
230+
comments,
231+
leadingComment: [
232+
model.description && escapeComment(model.description),
233+
model.deprecated && '@deprecated',
234+
],
235+
name: model.meta?.name || model.name,
236+
obj: properties,
237+
}),
238+
);
239+
};
240+
188241
const processType = ({ client, model, onNode }: TypesProps) => {
189242
generateType({
190243
client,

packages/openapi-ts/src/types/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export interface ClientConfig {
198198
* Generate enum definitions?
199199
* @default false
200200
*/
201-
enums?: 'javascript' | 'typescript' | false;
201+
enums?: 'javascript' | 'typescript' | 'typescript+namespace' | false;
202202
/**
203203
* Generate types?
204204
* @default true

packages/openapi-ts/test/index.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,19 @@ describe('OpenAPI v3', () => {
234234
description: 'generate TypeScript enums',
235235
name: 'v3_enums_typescript',
236236
},
237+
{
238+
config: createConfig({
239+
schemas: false,
240+
services: {
241+
asClass: true,
242+
},
243+
types: {
244+
enums: 'typescript+namespace',
245+
},
246+
}),
247+
description: 'generate TypeScript enums',
248+
name: 'v3_enums_typescript_namespace',
249+
},
237250
{
238251
config: createConfig({
239252
exportCore: false,

0 commit comments

Comments
 (0)