Skip to content

Commit

Permalink
Handle enums
Browse files Browse the repository at this point in the history
  • Loading branch information
drwpow committed Mar 19, 2019
1 parent e250a3f commit 58bf03f
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 148 deletions.
95 changes: 18 additions & 77 deletions example/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,9 @@ namespace OpenAPI2 {
provisioning?: string;
base_url?: string;
sso_url?: string;
version?: UpdateProductBodyIntegrationVersion;
version?: 'v1';
features?: ProductIntegrationFeatures;
}
export enum UpdateProductBodyIntegrationVersion {
V1 = 'v1'
}
export interface UpdateProduct {
id: string;
body: UpdateProductBody;
Expand Down Expand Up @@ -79,16 +76,10 @@ namespace OpenAPI2 {
}
export interface Region {
id: string;
type: RegionType;
version: RegionVersion;
type: 'region';
version: 1;
body: RegionBody;
}
export enum RegionVersion {
Version1 = 1
}
export enum RegionType {
Region = 'region'
}
export interface ProviderBody {
team_id: string;
label: string;
Expand All @@ -99,16 +90,10 @@ namespace OpenAPI2 {
}
export interface Provider {
id: string;
version: ProviderVersion;
type: ProviderType;
version: 1;
type: 'provider';
body: ProviderBody;
}
export enum ProviderType {
Provider = 'provider'
}
export enum ProviderVersion {
Version1 = 1
}
export interface ProductTags {}
export interface ProductListing {
// When true, everyone can see the product when requested. When false it will
Expand Down Expand Up @@ -153,11 +138,7 @@ namespace OpenAPI2 {
// Describes how the region for a resource is specified, if
// unspecified, then regions have no impact on this
// resource.
region?: ProductIntegrationFeaturesRegion;
}
export enum ProductIntegrationFeaturesRegion {
UserSpecified = 'user-specified',
Unspecified = 'unspecified'
region?: 'user-specified' | 'unspecified';
}
export interface ProductBody {
provider_id: string;
Expand Down Expand Up @@ -186,40 +167,23 @@ namespace OpenAPI2 {
provisioning: string;
base_url: string;
sso_url?: string;
version: ProductBodyIntegrationVersion;
version: 'v1';
features: ProductIntegrationFeatures;
}
export enum ProductBodyIntegrationVersion {
V1 = 'v1'
}
export interface ProductBodyBilling {
type: ProductBodyBillingType;
currency: ProductBodyBillingCurrency;
}
export enum ProductBodyBillingCurrency {
Usd = 'usd'
}
export enum ProductBodyBillingType {
MonthlyProrated = 'monthly-prorated',
MonthlyAnniversary = 'monthly-anniversary',
AnnualAnniversary = 'annual-anniversary'
type: 'monthly-prorated' | 'monthly-anniversary' | 'annual-anniversary';
currency: 'usd';
}
export interface ProductBodyTerms {
url?: string;
provided: boolean;
}
export interface Product {
id: string;
version: ProductVersion;
type: ProductType;
version: 1;
type: 'product';
body: ProductBody;
}
export enum ProductType {
Product = 'product'
}
export enum ProductVersion {
Version1 = 1
}
export interface PlanResizeList {}
export interface PlanBody {
provider_id: string;
Expand All @@ -241,16 +205,10 @@ namespace OpenAPI2 {
}
export interface Plan {
id: string;
version: PlanVersion;
type: PlanType;
version: 1;
type: 'plan';
body: PlanBody;
}
export enum PlanType {
Plan = 'plan'
}
export enum PlanVersion {
Version1 = 1
}
export interface FeatureValuesList {}
export interface FeatureValueDetails {
label: string;
Expand Down Expand Up @@ -285,7 +243,7 @@ namespace OpenAPI2 {
export interface FeatureType {
label: string;
name: string;
type: FeatureTypeType;
type: 'boolean' | 'string' | 'number';
// This sets whether or not the feature can be customized by a consumer.
customizable?: boolean;
// This sets whether or not the feature can be upgraded by the consumer after the
Expand All @@ -301,11 +259,6 @@ namespace OpenAPI2 {
measurable?: boolean;
values?: FeatureValueDetails[];
}
export enum FeatureTypeType {
Boolean = 'boolean',
String = 'string',
Number = 'number'
}
export interface FeatureNumericRange {
// Defines the end of the range ( inclusive ), from the previous, or 0;
// where the cost_multiple starts taking effect. If set to -1 this defines the
Expand Down Expand Up @@ -337,18 +290,12 @@ namespace OpenAPI2 {
}
export interface ExpandedProduct {
id: string;
version: ExpandedProductVersion;
type: ExpandedProductType;
version: 1;
type: 'product';
body: ProductBody;
plans?: ExpandedPlan[];
provider: Provider;
}
export enum ExpandedProductType {
Product = 'product'
}
export enum ExpandedProductVersion {
Version1 = 1
}
export interface ExpandedPlanBody extends PlanBody {
// An array of feature definitions for the plan, as defined on the Product.
expanded_features?: ExpandedFeature[];
Expand All @@ -361,16 +308,10 @@ namespace OpenAPI2 {
}
export interface ExpandedPlan {
id: string;
version: ExpandedPlanVersion;
type: ExpandedPlanType;
version: 1;
type: 'plan';
body: ExpandedPlanBody;
}
export enum ExpandedPlanType {
Plan = 'plan'
}
export enum ExpandedPlanVersion {
Version1 = 1
}
export interface ExpandedFeature extends FeatureType {
// The string value set for the feature on the plan, this should only be used if the value property is null.
value_string?: string;
Expand Down
27 changes: 2 additions & 25 deletions src/swagger-2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ function parse(spec: Swagger2, options: Swagger2Options = {}) {
const shouldCamelCase = options.camelcase || false;

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

const { definitions } = spec;
Expand Down Expand Up @@ -103,21 +102,6 @@ function parse(spec: Swagger2, options: Swagger2Options = {}) {
return DEFAULT_TYPE;
}

function buildNextEnum([ID, enumOptions]: [string, (string | number)[]]) {
output.push(`export enum ${ID} {`);
enumOptions.forEach(option => {
if (typeof option === 'number') {
const lastWord = ID.search(/[A-Z](?=[^A-Z]*$)/);
const name = ID.substr(lastWord, ID.length);
output.push(`${name}${option} = ${option},`);
} else {
const name = capitalize(camelCase(option)); // Enums are always camel-cased
output.push(`${name} = ${JSON.stringify(option)},`);
}
});
output.push('}');
}

function buildNextInterface() {
const nextObject = queue.pop();
if (!nextObject) return; // Geez TypeScript it’s going to be OK
Expand Down Expand Up @@ -166,10 +150,9 @@ function parse(spec: Swagger2, options: Swagger2Options = {}) {
output.push(`// ${value.description.replace(/\n$/, '').replace(/\n/g, '\n// ')}`);
}

// Save enums for later
// Handle enums in the same definition
if (Array.isArray(value.enum)) {
enumQueue.push([newID, value.enum]);
output.push(`${name}: ${newID};`);
output.push(`${name}: ${value.enum.map(option => JSON.stringify(option)).join(' | ')};`);
return;
}

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

// Close interface
output.push('}');

// Clean up enumQueue
while (enumQueue.length > 0) {
const nextEnum = enumQueue.pop();
if (nextEnum) buildNextEnum(nextEnum);
}
}

// Begin parsing top-level entries
Expand Down
112 changes: 66 additions & 46 deletions tests/swagger-2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,52 +94,6 @@ describe('Swagger 2 spec', () => {
});
});

describe('property names', () => {
it('preserves snake_case keys by default', () => {
const swagger: Swagger2 = {
definitions: {
User: {
properties: {
profile_image: { type: 'string' },
address_line_1: { type: 'string' },
},
type: 'object',
},
},
};

const ts = format(`
export interface User {
profile_image?: string;
address_line_1?: string;
}`);

expect(swaggerToTS(swagger)).toBe(ts);
});

it('converts snake_case to camelCase if specified', () => {
const swagger: Swagger2 = {
definitions: {
User: {
properties: {
profile_image: { type: 'string' },
address_line_1: { type: 'string' },
},
type: 'object',
},
},
};

const ts = format(`
export interface User {
profileImage?: string;
addressLine1?: string;
}`);

expect(swaggerToTS(swagger, { camelcase: true })).toBe(ts);
});
});

describe('complex structures', () => {
it('handles arrays of primitive structures', () => {
const swagger: Swagger2 = {
Expand Down Expand Up @@ -247,6 +201,72 @@ describe('Swagger 2 spec', () => {

expect(swaggerToTS(swagger)).toBe(ts);
});

it('handles enum', () => {
const swagger: Swagger2 = {
definitions: {
User: {
properties: {
role: { type: 'string', enum: ['user', 'admin'] },
},
type: 'object',
},
},
};

const ts = format(`
export interface User {
role?: 'user' | 'admin';
}`);

expect(swaggerToTS(swagger)).toBe(ts);
});
});

describe('property names', () => {
it('preserves snake_case keys by default', () => {
const swagger: Swagger2 = {
definitions: {
User: {
properties: {
profile_image: { type: 'string' },
address_line_1: { type: 'string' },
},
type: 'object',
},
},
};

const ts = format(`
export interface User {
profile_image?: string;
address_line_1?: string;
}`);

expect(swaggerToTS(swagger)).toBe(ts);
});

it('converts snake_case to camelCase if specified', () => {
const swagger: Swagger2 = {
definitions: {
User: {
properties: {
profile_image: { type: 'string' },
address_line_1: { type: 'string' },
},
type: 'object',
},
},
};

const ts = format(`
export interface User {
profileImage?: string;
addressLine1?: string;
}`);

expect(swaggerToTS(swagger, { camelcase: true })).toBe(ts);
});
});

describe('TS features', () => {
Expand Down

0 comments on commit 58bf03f

Please sign in to comment.