Skip to content

Commit 58bf03f

Browse files
committed
Handle enums
1 parent e250a3f commit 58bf03f

File tree

3 files changed

+86
-148
lines changed

3 files changed

+86
-148
lines changed

example/output.ts

+18-77
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,9 @@ namespace OpenAPI2 {
3939
provisioning?: string;
4040
base_url?: string;
4141
sso_url?: string;
42-
version?: UpdateProductBodyIntegrationVersion;
42+
version?: 'v1';
4343
features?: ProductIntegrationFeatures;
4444
}
45-
export enum UpdateProductBodyIntegrationVersion {
46-
V1 = 'v1'
47-
}
4845
export interface UpdateProduct {
4946
id: string;
5047
body: UpdateProductBody;
@@ -79,16 +76,10 @@ namespace OpenAPI2 {
7976
}
8077
export interface Region {
8178
id: string;
82-
type: RegionType;
83-
version: RegionVersion;
79+
type: 'region';
80+
version: 1;
8481
body: RegionBody;
8582
}
86-
export enum RegionVersion {
87-
Version1 = 1
88-
}
89-
export enum RegionType {
90-
Region = 'region'
91-
}
9283
export interface ProviderBody {
9384
team_id: string;
9485
label: string;
@@ -99,16 +90,10 @@ namespace OpenAPI2 {
9990
}
10091
export interface Provider {
10192
id: string;
102-
version: ProviderVersion;
103-
type: ProviderType;
93+
version: 1;
94+
type: 'provider';
10495
body: ProviderBody;
10596
}
106-
export enum ProviderType {
107-
Provider = 'provider'
108-
}
109-
export enum ProviderVersion {
110-
Version1 = 1
111-
}
11297
export interface ProductTags {}
11398
export interface ProductListing {
11499
// When true, everyone can see the product when requested. When false it will
@@ -153,11 +138,7 @@ namespace OpenAPI2 {
153138
// Describes how the region for a resource is specified, if
154139
// unspecified, then regions have no impact on this
155140
// resource.
156-
region?: ProductIntegrationFeaturesRegion;
157-
}
158-
export enum ProductIntegrationFeaturesRegion {
159-
UserSpecified = 'user-specified',
160-
Unspecified = 'unspecified'
141+
region?: 'user-specified' | 'unspecified';
161142
}
162143
export interface ProductBody {
163144
provider_id: string;
@@ -186,40 +167,23 @@ namespace OpenAPI2 {
186167
provisioning: string;
187168
base_url: string;
188169
sso_url?: string;
189-
version: ProductBodyIntegrationVersion;
170+
version: 'v1';
190171
features: ProductIntegrationFeatures;
191172
}
192-
export enum ProductBodyIntegrationVersion {
193-
V1 = 'v1'
194-
}
195173
export interface ProductBodyBilling {
196-
type: ProductBodyBillingType;
197-
currency: ProductBodyBillingCurrency;
198-
}
199-
export enum ProductBodyBillingCurrency {
200-
Usd = 'usd'
201-
}
202-
export enum ProductBodyBillingType {
203-
MonthlyProrated = 'monthly-prorated',
204-
MonthlyAnniversary = 'monthly-anniversary',
205-
AnnualAnniversary = 'annual-anniversary'
174+
type: 'monthly-prorated' | 'monthly-anniversary' | 'annual-anniversary';
175+
currency: 'usd';
206176
}
207177
export interface ProductBodyTerms {
208178
url?: string;
209179
provided: boolean;
210180
}
211181
export interface Product {
212182
id: string;
213-
version: ProductVersion;
214-
type: ProductType;
183+
version: 1;
184+
type: 'product';
215185
body: ProductBody;
216186
}
217-
export enum ProductType {
218-
Product = 'product'
219-
}
220-
export enum ProductVersion {
221-
Version1 = 1
222-
}
223187
export interface PlanResizeList {}
224188
export interface PlanBody {
225189
provider_id: string;
@@ -241,16 +205,10 @@ namespace OpenAPI2 {
241205
}
242206
export interface Plan {
243207
id: string;
244-
version: PlanVersion;
245-
type: PlanType;
208+
version: 1;
209+
type: 'plan';
246210
body: PlanBody;
247211
}
248-
export enum PlanType {
249-
Plan = 'plan'
250-
}
251-
export enum PlanVersion {
252-
Version1 = 1
253-
}
254212
export interface FeatureValuesList {}
255213
export interface FeatureValueDetails {
256214
label: string;
@@ -285,7 +243,7 @@ namespace OpenAPI2 {
285243
export interface FeatureType {
286244
label: string;
287245
name: string;
288-
type: FeatureTypeType;
246+
type: 'boolean' | 'string' | 'number';
289247
// This sets whether or not the feature can be customized by a consumer.
290248
customizable?: boolean;
291249
// This sets whether or not the feature can be upgraded by the consumer after the
@@ -301,11 +259,6 @@ namespace OpenAPI2 {
301259
measurable?: boolean;
302260
values?: FeatureValueDetails[];
303261
}
304-
export enum FeatureTypeType {
305-
Boolean = 'boolean',
306-
String = 'string',
307-
Number = 'number'
308-
}
309262
export interface FeatureNumericRange {
310263
// Defines the end of the range ( inclusive ), from the previous, or 0;
311264
// where the cost_multiple starts taking effect. If set to -1 this defines the
@@ -337,18 +290,12 @@ namespace OpenAPI2 {
337290
}
338291
export interface ExpandedProduct {
339292
id: string;
340-
version: ExpandedProductVersion;
341-
type: ExpandedProductType;
293+
version: 1;
294+
type: 'product';
342295
body: ProductBody;
343296
plans?: ExpandedPlan[];
344297
provider: Provider;
345298
}
346-
export enum ExpandedProductType {
347-
Product = 'product'
348-
}
349-
export enum ExpandedProductVersion {
350-
Version1 = 1
351-
}
352299
export interface ExpandedPlanBody extends PlanBody {
353300
// An array of feature definitions for the plan, as defined on the Product.
354301
expanded_features?: ExpandedFeature[];
@@ -361,16 +308,10 @@ namespace OpenAPI2 {
361308
}
362309
export interface ExpandedPlan {
363310
id: string;
364-
version: ExpandedPlanVersion;
365-
type: ExpandedPlanType;
311+
version: 1;
312+
type: 'plan';
366313
body: ExpandedPlanBody;
367314
}
368-
export enum ExpandedPlanType {
369-
Plan = 'plan'
370-
}
371-
export enum ExpandedPlanVersion {
372-
Version1 = 1
373-
}
374315
export interface ExpandedFeature extends FeatureType {
375316
// The string value set for the feature on the plan, this should only be used if the value property is null.
376317
value_string?: string;

src/swagger-2.ts

+2-25
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ function parse(spec: Swagger2, options: Swagger2Options = {}) {
4545
const shouldCamelCase = options.camelcase || false;
4646

4747
const queue: [string, Swagger2Definition][] = [];
48-
const enumQueue: [string, (string | number)[]][] = [];
4948
const output: string[] = [`namespace ${namespace} {`];
5049

5150
const { definitions } = spec;
@@ -103,21 +102,6 @@ function parse(spec: Swagger2, options: Swagger2Options = {}) {
103102
return DEFAULT_TYPE;
104103
}
105104

106-
function buildNextEnum([ID, enumOptions]: [string, (string | number)[]]) {
107-
output.push(`export enum ${ID} {`);
108-
enumOptions.forEach(option => {
109-
if (typeof option === 'number') {
110-
const lastWord = ID.search(/[A-Z](?=[^A-Z]*$)/);
111-
const name = ID.substr(lastWord, ID.length);
112-
output.push(`${name}${option} = ${option},`);
113-
} else {
114-
const name = capitalize(camelCase(option)); // Enums are always camel-cased
115-
output.push(`${name} = ${JSON.stringify(option)},`);
116-
}
117-
});
118-
output.push('}');
119-
}
120-
121105
function buildNextInterface() {
122106
const nextObject = queue.pop();
123107
if (!nextObject) return; // Geez TypeScript it’s going to be OK
@@ -166,10 +150,9 @@ function parse(spec: Swagger2, options: Swagger2Options = {}) {
166150
output.push(`// ${value.description.replace(/\n$/, '').replace(/\n/g, '\n// ')}`);
167151
}
168152

169-
// Save enums for later
153+
// Handle enums in the same definition
170154
if (Array.isArray(value.enum)) {
171-
enumQueue.push([newID, value.enum]);
172-
output.push(`${name}: ${newID};`);
155+
output.push(`${name}: ${value.enum.map(option => JSON.stringify(option)).join(' | ')};`);
173156
return;
174157
}
175158

@@ -189,12 +172,6 @@ function parse(spec: Swagger2, options: Swagger2Options = {}) {
189172

190173
// Close interface
191174
output.push('}');
192-
193-
// Clean up enumQueue
194-
while (enumQueue.length > 0) {
195-
const nextEnum = enumQueue.pop();
196-
if (nextEnum) buildNextEnum(nextEnum);
197-
}
198175
}
199176

200177
// Begin parsing top-level entries

tests/swagger-2.test.ts

+66-46
Original file line numberDiff line numberDiff line change
@@ -94,52 +94,6 @@ describe('Swagger 2 spec', () => {
9494
});
9595
});
9696

97-
describe('property names', () => {
98-
it('preserves snake_case keys by default', () => {
99-
const swagger: Swagger2 = {
100-
definitions: {
101-
User: {
102-
properties: {
103-
profile_image: { type: 'string' },
104-
address_line_1: { type: 'string' },
105-
},
106-
type: 'object',
107-
},
108-
},
109-
};
110-
111-
const ts = format(`
112-
export interface User {
113-
profile_image?: string;
114-
address_line_1?: string;
115-
}`);
116-
117-
expect(swaggerToTS(swagger)).toBe(ts);
118-
});
119-
120-
it('converts snake_case to camelCase if specified', () => {
121-
const swagger: Swagger2 = {
122-
definitions: {
123-
User: {
124-
properties: {
125-
profile_image: { type: 'string' },
126-
address_line_1: { type: 'string' },
127-
},
128-
type: 'object',
129-
},
130-
},
131-
};
132-
133-
const ts = format(`
134-
export interface User {
135-
profileImage?: string;
136-
addressLine1?: string;
137-
}`);
138-
139-
expect(swaggerToTS(swagger, { camelcase: true })).toBe(ts);
140-
});
141-
});
142-
14397
describe('complex structures', () => {
14498
it('handles arrays of primitive structures', () => {
14599
const swagger: Swagger2 = {
@@ -247,6 +201,72 @@ describe('Swagger 2 spec', () => {
247201

248202
expect(swaggerToTS(swagger)).toBe(ts);
249203
});
204+
205+
it('handles enum', () => {
206+
const swagger: Swagger2 = {
207+
definitions: {
208+
User: {
209+
properties: {
210+
role: { type: 'string', enum: ['user', 'admin'] },
211+
},
212+
type: 'object',
213+
},
214+
},
215+
};
216+
217+
const ts = format(`
218+
export interface User {
219+
role?: 'user' | 'admin';
220+
}`);
221+
222+
expect(swaggerToTS(swagger)).toBe(ts);
223+
});
224+
});
225+
226+
describe('property names', () => {
227+
it('preserves snake_case keys by default', () => {
228+
const swagger: Swagger2 = {
229+
definitions: {
230+
User: {
231+
properties: {
232+
profile_image: { type: 'string' },
233+
address_line_1: { type: 'string' },
234+
},
235+
type: 'object',
236+
},
237+
},
238+
};
239+
240+
const ts = format(`
241+
export interface User {
242+
profile_image?: string;
243+
address_line_1?: string;
244+
}`);
245+
246+
expect(swaggerToTS(swagger)).toBe(ts);
247+
});
248+
249+
it('converts snake_case to camelCase if specified', () => {
250+
const swagger: Swagger2 = {
251+
definitions: {
252+
User: {
253+
properties: {
254+
profile_image: { type: 'string' },
255+
address_line_1: { type: 'string' },
256+
},
257+
type: 'object',
258+
},
259+
},
260+
};
261+
262+
const ts = format(`
263+
export interface User {
264+
profileImage?: string;
265+
addressLine1?: string;
266+
}`);
267+
268+
expect(swaggerToTS(swagger, { camelcase: true })).toBe(ts);
269+
});
250270
});
251271

252272
describe('TS features', () => {

0 commit comments

Comments
 (0)