Skip to content

Commit d0d09f2

Browse files
authored
Merge pull request #130 from manifoldco/dangodev/fix-hashmaps
Fix HashMaps
2 parents 446f974 + 2712819 commit d0d09f2

File tree

9 files changed

+140
-58
lines changed

9 files changed

+140
-58
lines changed

README.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,13 @@ For anything more complicated, or for generating specs dynamically, you can also
9999

100100
#### CLI Options
101101

102-
| Option | Alias | Default | Description |
103-
| :-------------------- | :---- | :--------------------------: | :---------------------------------------------------------------------------- |
104-
| `--wrapper` | `-w` | `declare namespace OpenAPI2` | How should this export the types? |
105-
| `--output [location]` | `-o` | (stdout) | Where should the output file be saved? |
106-
| `--swagger [version]` | `-s` | `2` | Manually specify Swagger version (by default it will use `version` in schema) |
107-
| `--camelcase` | `-c` | `false` | Convert `snake_case` properties to `camelCase` |
108-
| `--nowarning` | | `false` | Disables “autogenerated file” warning at the top of generated files |
109-
| `--nowrapper` | `-nw` | `false` | Disables rendering a wrapper |
102+
| Option | Alias | Default | Description |
103+
| :-------------------- | :---- | :--------------------------: | :------------------------------------------------------------------ |
104+
| `--wrapper` | `-w` | `declare namespace OpenAPI2` | How should this export the types? |
105+
| `--output [location]` | `-o` | (stdout) | Where should the output file be saved? |
106+
| `--camelcase` | `-c` | `false` | Convert `snake_case` properties to `camelCase` |
107+
| `--nowarning` | | `false` | Disables “autogenerated file” warning at the top of generated files |
108+
| `--nowrapper` | `-nw` | `false` | Disables rendering a wrapper |
110109

111110
### Node
112111

@@ -131,20 +130,19 @@ If your specs are in YAML, you’ll have to convert them to JS objects using a l
131130

132131
#### Node Options
133132

134-
| Name | Type | Default | Description |
135-
| :--------------- | :---------------: | :--------------------------: | :--------------------------------------------------------------------------- |
136-
| `wrapper` | `string \| false` | `declare namespace OpenAPI2` | How should this export the types? Pass false to disable rendering a wrapper |
137-
| `swagger` | `number` | `2` | Manully specify Swagger version (by default it will use `version` in schema) |
138-
| `camelcase` | `boolean` | `false` | Convert `snake_case` properties to `camelCase` |
139-
| `propertyMapper` | `function` | `undefined` | Allows you to further manipulate how properties are parsed. See below. |
133+
| Name | Type | Default | Description |
134+
| :--------------- | :---------------: | :--------------------------: | :-------------------------------------------------------------------------- |
135+
| `wrapper` | `string \| false` | `declare namespace OpenAPI2` | How should this export the types? Pass false to disable rendering a wrapper |
136+
| `camelcase` | `boolean` | `false` | Convert `snake_case` properties to `camelCase` |
137+
| `propertyMapper` | `function` | `undefined` | Allows you to further manipulate how properties are parsed. See below. |
140138

141139
#### PropertyMapper
142140

143141
In order to allow more control over how properties are parsed, and to specifically handle
144142
`x-something`-properties, the `propertyMapper` option may be specified.
145143

146144
This is a function that, if specified, is called for each property and allows you to change how
147-
swagger-to-ts handles parsing of swagger files.
145+
swagger-to-ts handles parsing of Swagger files.
148146

149147
An example on how to use the `x-nullable` property to control if a property is optional:
150148

bin/cli.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ Options
1818
--wrapper, -w specify wrapper (default: "declare namespace OpenAPI2")
1919
--output, -o specify output file
2020
--camelcase, -c convert snake_case properties to camelCase (default: off)
21-
--swagger, -s specify Swagger version (default: 2)
2221
--nowrapper -nw disables rendering the wrapper
2322
--no-warning hides the warning at the top of the generated file (default: off)
2423
`,
@@ -38,10 +37,6 @@ Options
3837
type: 'string',
3938
alias: 'o',
4039
},
41-
swagger: {
42-
type: 'number',
43-
alias: 's',
44-
},
4540
namespace: {
4641
type: 'string',
4742
alias: 'n',

example/basic.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ declare namespace OpenAPI2 {
376376
cost_ranges?: FeatureNumericRange[];
377377
}
378378
export interface FeatureMap {
379-
[name: string]: any;
379+
[key: string]: any;
380380
}
381381
export interface ExpandedProduct {
382382
id: string;
@@ -428,7 +428,7 @@ declare namespace OpenAPI2 {
428428
message: string[];
429429
}
430430
export interface Credentials {
431-
[name: string]: string;
431+
[key: string]: string;
432432
}
433433
export interface CreateRegion {
434434
body: RegionBody;

example/no-warning.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ declare namespace OpenAPI2 {
371371
cost_ranges?: FeatureNumericRange[];
372372
}
373373
export interface FeatureMap {
374-
[name: string]: any;
374+
[key: string]: any;
375375
}
376376
export interface ExpandedProduct {
377377
id: string;
@@ -423,7 +423,7 @@ declare namespace OpenAPI2 {
423423
message: string[];
424424
}
425425
export interface Credentials {
426-
[name: string]: string;
426+
[key: string]: string;
427427
}
428428
export interface CreateRegion {
429429
body: RegionBody;

example/no-wrapper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ export interface FeatureNumericDetails {
375375
cost_ranges?: FeatureNumericRange[];
376376
}
377377
export interface FeatureMap {
378-
[name: string]: any;
378+
[key: string]: any;
379379
}
380380
export interface ExpandedProduct {
381381
id: string;
@@ -427,7 +427,7 @@ export interface Error {
427427
message: string[];
428428
}
429429
export interface Credentials {
430-
[name: string]: string;
430+
[key: string]: string;
431431
}
432432
export interface CreateRegion {
433433
body: RegionBody;

src/index.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,35 @@ import swagger2, { Swagger2, Swagger2Options } from './swagger-2';
22
//re-export these from top-level as users may need thrm to create a propert5ymapper
33
export { Swagger2Definition, Property } from './swagger-2';
44

5-
export interface Options extends Swagger2Options {
6-
swagger?: number;
7-
}
5+
export type Options = Swagger2Options;
6+
7+
export default function(spec: Swagger2, options?: Swagger2Options): string {
8+
let version: number | undefined;
89

9-
export default function(spec: Swagger2, options?: Options): string {
10-
const swagger = (options && options.swagger) || 2;
10+
if (spec.swagger && parseInt(spec.swagger, 10) === 2) {
11+
version = 2; // identify v3
12+
} else if (spec.openapi && parseInt(spec.openapi, 10) === 3) {
13+
version = 3; // identify v3
14+
}
1115

12-
if (swagger !== 2) {
13-
throw new Error(`Swagger version ${swagger} is not supported`);
16+
switch (version) {
17+
case undefined: {
18+
console.warn(`Could not determine Swagger version. Assuming 2.0.`);
19+
break;
20+
}
21+
case 2: {
22+
// continue
23+
break;
24+
}
25+
case 3: {
26+
console.warn(
27+
`Swagger version 3 is in beta. Please report any bugs you find to github.com/manifoldco/swagger-to-ts 🙏!`
28+
);
29+
break;
30+
}
31+
default: {
32+
throw new Error(`Swagger version ${version} is not supported`);
33+
}
1434
}
1535

1636
return swagger2(spec, options);

src/swagger-2.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export interface Property {
2626
}
2727

2828
export interface Swagger2 {
29+
swagger?: string;
30+
openapi?: string;
2931
definitions: {
3032
[index: string]: Swagger2Definition;
3133
};
@@ -142,6 +144,17 @@ function parse(spec: Swagger2, options: Swagger2Options = {}): string {
142144
return DEFAULT_TYPE;
143145
}
144146

147+
function handleAdditionalProperties(additionalProperties: boolean | Swagger2Definition): string {
148+
if ((additionalProperties as Swagger2Definition).type) {
149+
const interfaceType = getType(additionalProperties as Swagger2Definition, '', {
150+
camelcase: shouldCamelCase,
151+
});
152+
return `[key: string]: ${interfaceType}`;
153+
}
154+
155+
return '[key: string]: any;';
156+
}
157+
145158
function buildNextInterface(): void {
146159
const nextObject = queue.pop();
147160
if (!nextObject) return; // Geez TypeScript it’s going to be OK
@@ -203,20 +216,15 @@ function parse(spec: Swagger2, options: Swagger2Options = {}): string {
203216
output.push(`/**\n* ${property.description.replace(/\n$/, '').replace(/\n/g, '\n* ')}\n*/`);
204217
}
205218

206-
output.push(`${name}: ${interfaceType};`);
219+
if (value.additionalProperties) {
220+
output.push(`${name}: { ${handleAdditionalProperties(value.additionalProperties)} }`);
221+
} else {
222+
output.push(`${name}: ${interfaceType};`);
223+
}
207224
});
208225

209226
if (additionalProperties) {
210-
if ((additionalProperties as boolean) === true) {
211-
output.push('[name: string]: any');
212-
}
213-
214-
if ((additionalProperties as Swagger2Definition).type) {
215-
const interfaceType = getType(additionalProperties as Swagger2Definition, '', {
216-
camelcase: shouldCamelCase,
217-
});
218-
output.push(`[name: string]: ${interfaceType}`);
219-
}
227+
output.push(handleAdditionalProperties(additionalProperties));
220228
}
221229

222230
// Close interface

tests/index.test.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@ import swaggerToTS, { Options } from '../src';
22

33
describe('swaggerToTS', () => {
44
it('is able to parse a Swagger 2 spec', () => {
5-
const spec = { definitions: {} };
6-
const options: Options = { swagger: 2, warning: false };
7-
5+
const spec = { swagger: '2.0', definitions: {} };
6+
const options: Options = { warning: false };
87
expect(swaggerToTS(spec, options)).toBe('declare namespace OpenAPI2 {}\n');
98
});
109

11-
it('errs on other options', () => {
10+
it('assumes Swagger 2 if version missing', () => {
1211
const spec = { definitions: {} };
13-
const options: Options = { swagger: 1, warning: false };
14-
expect(() => swaggerToTS(spec, options)).toThrowError();
12+
const options: Options = { warning: false };
13+
expect(swaggerToTS(spec, options)).toBe('declare namespace OpenAPI2 {}\n');
1514
});
1615

1716
it('should not render a wrapper when passing false', () => {
18-
const spec = { definitions: {} };
19-
const options: Options = { swagger: 2, wrapper: false, warning: false };
17+
const spec = { swagger: '2.0', definitions: {} };
18+
const options: Options = { wrapper: false, warning: false };
2019
expect(swaggerToTS(spec, options)).toBe('');
2120
});
2221
});

0 commit comments

Comments
 (0)