Skip to content

Commit 02628a0

Browse files
committed
Fix items.$ref generation
1 parent 7bb608d commit 02628a0

File tree

6 files changed

+42
-58
lines changed

6 files changed

+42
-58
lines changed

.prettierrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"printWidth": 100,
23
"singleQuote": true,
34
"trailingComma": "es5"
45
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@manifoldco/swagger-to-ts",
3-
"version": "1.0.0-alpha.0",
3+
"version": "1.0.0",
44
"description": "Generate TypeScript types from Swagger OpenAPI specs",
55
"main": "dist/cjs",
66
"engines": {

scripts/generate.js

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,31 @@
1-
const { existsSync, mkdirSync, readFileSync, writeFileSync } = require('fs');
21
const { resolve, sep } = require('path');
2+
const { exec } = require('child_process');
33
const glob = require('glob');
4-
const yaml = require('js-yaml');
5-
const swaggerToGQL = require('../dist'); // replace with: require('@manifoldco/swagger-to-graphql')
64

7-
// 1. Load all YAML files from a certain directory
8-
glob(
9-
'./spec/**/*.yaml',
10-
{ root: resolve(__dirname, '..') },
11-
(error, matches) => {
12-
if (error) {
13-
console.error('No files found');
14-
return;
15-
}
5+
const swaggerToTS = resolve(__dirname, '..', 'bin', 'cli.js');
166

17-
if (typeof matches === 'string') {
18-
generate(matches);
19-
return;
20-
}
7+
// Settings
8+
const INPUT_DIR = 'spec';
9+
const OUTPUT_DIR = 'types';
2110

22-
matches.forEach(file => generate(file));
23-
}
24-
);
11+
// Methods
12+
function rename(filename) {
13+
return filename
14+
.replace(`${sep}${INPUT_DIR}${sep}`, `${sep}${OUTPUT_DIR}${sep}`)
15+
.replace(/\.ya?ml$/i, '.ts');
16+
}
2517

26-
// 2. Convert to GraphQL types, write to `./types` folder.
27-
function generate(file) {
28-
const source = resolve(__dirname, '..', file);
29-
const segments = source.split(sep);
30-
const dirname = segments[segments.length - 2];
31-
const basename = segments[segments.length - 1].replace(/\.yaml$/i, '.ts');
18+
// Initialize
19+
glob('./spec/**/*.yaml', { root: resolve(__dirname, '..') }, (error, matches) => {
20+
if (error) {
21+
console.error('No files found');
22+
return;
23+
}
3224

33-
const output = resolve(__dirname, '..', 'types', dirname);
34-
if (!existsSync(output)) {
35-
mkdirSync(output);
25+
if (typeof matches === 'string') {
26+
exec(`node ${swaggerToTS} ${matches} -o ${rename(matches)}`);
27+
return;
3628
}
3729

38-
const schema = swaggerToGQL(
39-
yaml.safeLoad(readFileSync(source, 'UTF-8')),
40-
dirname
41-
);
42-
writeFileSync(resolve(output, basename), schema);
43-
}
30+
matches.forEach(file => exec(`node ${swaggerToTS} ${file} -o ${rename(file)}`));
31+
});

src/index.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import swagger2, { Swagger2 } from './swagger-2';
22

3-
export default (
4-
spec: Swagger2,
5-
namespace?: string,
6-
options?: { version?: number }
7-
) => {
3+
export default (spec: Swagger2, namespace?: string, options?: { version?: number }) => {
84
const version = (options && options.version) || 2;
95

106
if (version === 1 || version === 3) {

src/swagger-2.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ const TYPES: { [index: string]: string } = {
2727
const capitalize = (str: string) => `${str[0].toUpperCase()}${str.slice(1)}`;
2828

2929
const camelCase = (name: string) =>
30-
name.replace(/(-|_|\.|\s)+[a-z]/g, letter =>
31-
letter.toUpperCase().replace(/[^0-9a-z]/gi, '')
32-
);
30+
name.replace(/(-|_|\.|\s)+[a-z]/g, letter => letter.toUpperCase().replace(/[^0-9a-z]/gi, ''));
3331

3432
const buildTypes = (spec: Swagger2, namespace: string) => {
3533
const queue: [string, Swagger2Definition][] = [];
@@ -39,16 +37,21 @@ const buildTypes = (spec: Swagger2, namespace: string) => {
3937
const { definitions } = spec;
4038

4139
function getRef(lookup: string): [string, Swagger2Definition] {
42-
const ref = lookup.replace('#/definitions/', '');
43-
return [ref, definitions[ref]];
40+
const ID = lookup.replace('#/definitions/', '');
41+
const ref = definitions[ID];
42+
return [ID, ref];
4443
}
4544

4645
// Returns primitive type, or 'object' or 'any'
47-
function getType(definition: Swagger2Definition, nestedName: string) {
46+
function getType(definition: Swagger2Definition, nestedName: string): string {
4847
const { $ref, items, type, ...value } = definition;
4948

5049
if ($ref) {
5150
const [refName, refProperties] = getRef($ref);
51+
// If a shallow array interface, return that instead
52+
if (refProperties.items && refProperties.items.$ref) {
53+
return getType(refProperties, refName);
54+
}
5255
return TYPES[refProperties.type] || refName || 'any';
5356
}
5457

@@ -110,9 +113,7 @@ const buildTypes = (spec: Swagger2, namespace: string) => {
110113
return;
111114
}
112115
// Open interface
113-
const isExtending = includes.length
114-
? ` extends ${includes.join(', ')}`
115-
: '';
116+
const isExtending = includes.length ? ` extends ${includes.join(', ')}` : '';
116117

117118
output.push(`export interface ${camelCase(ID)}${isExtending} {`);
118119

@@ -125,9 +126,7 @@ const buildTypes = (spec: Swagger2, namespace: string) => {
125126

126127
if (typeof value.description === 'string') {
127128
// Print out descriptions as comments, but only if there’s something there (.*)
128-
output.push(
129-
`// ${value.description.replace(/\n$/, '').replace(/\n/g, '\n// ')}`
130-
);
129+
output.push(`// ${value.description.replace(/\n$/, '').replace(/\n/g, '\n// ')}`);
131130
}
132131

133132
// Save enums for later

types/catalog/v1.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace catalog {
1+
namespace OpenAPI2 {
22
export interface ValueProp {
33
// Heading of a value proposition.
44
header: string;
@@ -33,7 +33,7 @@ namespace catalog {
3333
termsUrl?: string;
3434
featureTypes?: FeatureType[];
3535
integration?: UpdateProductBodyIntegration;
36-
tags?: ProductTags;
36+
tags?: string[];
3737
}
3838
export interface UpdateProductBodyIntegration {
3939
provisioning?: string;
@@ -55,7 +55,7 @@ namespace catalog {
5555
state?: string;
5656
// Used in conjuction with resizable_to to set or unset the list
5757
hasResizeConstraints?: boolean;
58-
resizableTo?: PlanResizeList;
58+
resizableTo?: string[];
5959
// Array of Region IDs
6060
regions?: string[];
6161
// Array of Feature Values
@@ -179,7 +179,7 @@ namespace catalog {
179179
featureTypes: FeatureType[];
180180
billing: ProductBodyBilling;
181181
integration: ProductBodyIntegration;
182-
tags?: ProductTags;
182+
tags?: string[];
183183
}
184184
export interface ProductBodyIntegration {
185185
provisioning: string;
@@ -225,7 +225,7 @@ namespace catalog {
225225
name: string;
226226
label: string;
227227
state: string;
228-
resizableTo?: PlanResizeList;
228+
resizableTo?: string[];
229229
// Array of Region IDs
230230
regions: string[];
231231
// Array of Feature Values
@@ -296,7 +296,7 @@ namespace catalog {
296296
// Sets if this feature’s value is trackable from the provider,
297297
// this only really affects numeric constraints.
298298
measurable?: boolean;
299-
values?: FeatureValuesList;
299+
values?: FeatureValueDetails[];
300300
}
301301
export enum FeatureTypeType {
302302
Boolean = 'boolean',

0 commit comments

Comments
 (0)