Skip to content

Commit

Permalink
Add Union type generation
Browse files Browse the repository at this point in the history
  • Loading branch information
drwpow committed Jan 31, 2019
1 parent a587fa2 commit ab5345a
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 34 deletions.
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@ Node client for generating crude GraphQL specs from Swagger OpenAPI.
| Enum ||
| ID ||
| Implements (`allOf`) ||
| Polymorphism\* (`oneOf`) | N/A |
| Polymorphism (`oneOf`) | |
| Non-nullable ||
| Primitives (string, boolean, number) ||
| Query | 🚫 |
| Mutation | 🚫 |

To compare actual generated output, see the [example](./example) folder.

_\* Polymorphism isn’t supported by GraphQL by design. If this encounters one
in Swagger, it’ll assign the first type it encounters and throw a warning._

## Usage

### CLI
Expand Down
24 changes: 17 additions & 7 deletions src/swagger-2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function snakeCase(name: string) {
function parse(spec: Swagger2) {
const queue: [string, Swagger2Definition][] = [];
const enumQueue: [string, (string | number)[]][] = [];
const unionQueue: [string, Swagger2Definition[]][] = [];
const output: string[] = [];

const { definitions } = spec;
Expand Down Expand Up @@ -87,13 +88,9 @@ function parse(spec: Swagger2) {
return `[${TYPES[items.type]}]`;
}

if (Array.isArray(value.oneOf)) {
if (value.oneOf.length > 1) {
console.warn(
`Multiple types given for ${nestedName}. Using ${JSON.stringify(value.oneOf[0])}.`
);
}
return getType(value.oneOf[0], '');
if (Array.isArray(value.oneOf) && value.oneOf.length > 0) {
unionQueue.push([nestedName, value.oneOf]);
return nestedName;
}

if (value.properties) {
Expand Down Expand Up @@ -123,6 +120,11 @@ function parse(spec: Swagger2) {
output.push('}');
}

function buildNextUnion([ID, types]: [string, Swagger2Definition[]]) {
const union = types.map(type => getType(type, '')).join(' | ');
output.push(`union ${ID} = ${union}`);
}

function buildNextObject() {
const nextObject = queue.pop();
if (!nextObject) {
Expand Down Expand Up @@ -191,6 +193,14 @@ function parse(spec: Swagger2) {
buildNextEnum(nextEnum);
}
}

// Clean up unionQueue
while (unionQueue.length > 0) {
const nextUnion = unionQueue.pop();
if (nextUnion) {
buildNextUnion(nextUnion);
}
}
}

// Begin parsing top-level entries
Expand Down
47 changes: 24 additions & 23 deletions tests/swagger-2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,30 @@ describe('Swagger 2 spec', () => {

expect(graphqlGen(swagger)).toBe(format(graphql));
});

it('converts oneOf to union types', () => {
const swagger: Swagger2 = {
definitions: {
Record: {
properties: {
rand: {
oneOf: [{ type: 'string' }, { type: 'integer' }],
type: 'array',
},
},
type: 'object',
},
},
};

const graphql = format(`
type Record {
rand: RecordRand
}
union RecordRand = String | Int`);

expect(graphqlGen(swagger)).toBe(format(graphql));
});
});

describe('complex structures', () => {
Expand Down Expand Up @@ -266,29 +290,6 @@ describe('Swagger 2 spec', () => {

expect(graphqlGen(swagger)).toBe(format(graphql));
});

it('handles oneOf (kinda)', () => {
const swagger: Swagger2 = {
definitions: {
Record: {
properties: {
rand: {
oneOf: [{ type: 'string' }, { type: 'number' }],
type: 'array',
},
},
type: 'object',
},
},
};

const graphql = format(`
type Record {
rand: String
}`);

expect(graphqlGen(swagger)).toBe(format(graphql));
});
});

describe('other output', () => {
Expand Down

0 comments on commit ab5345a

Please sign in to comment.