Skip to content

Commit 6695576

Browse files
authored
Release 1.6.3 (#40)
* chore(ci/cd): slack notifications only when happens failure * fix: 'nullable' property shouldn't be used as required property * fix: problems of usage 'nullable' and 'required' properties; feat: parse type: 'null' schema components Co-authored-by: svolkov <[email protected]>
1 parent 2fdcf73 commit 6695576

File tree

10 files changed

+253
-72
lines changed

10 files changed

+253
-72
lines changed

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
language: node_js
32
node_js:
43
- "node"
@@ -26,5 +25,7 @@ jobs:
2625

2726
notifications:
2827
slack:
28+
on_success: never
29+
on_failure: always
2930
rooms:
30-
secure: vOYvagXgEbjgwSJaK70QU574OcUq1MyqJYJp08wqcLA2AUfxrN3HJj24s2qd3NAMIU2Zw6jfEwQBbH3vV10cwf2u5Yp9pAgbrLOJCV+1wixMJL6GxWLesbtUuizoOCEL+f5qogFPNpy4W2FDcG0DEYwuhLSdf5qToGXP5BSn3VPuvZYRhKRq9wJpeXNTLbu+XW8hEkuUpjbr2zzm+k8pCggONGVQ5SCSCI5DVHsCnsxzumwNcKbNitLiRMQKRJiFCOQ4YQwpZ7SCEu75YxMjb+UDIEYi5CtxgxCRaoBZfYj/uI4exxavmb0/vp5CJ1dTUNmI2R3pTQUIERoFXajl479FMnxhGsKycVG7O2hKqxNCDT8tPAzxdMaF31u7AtWajdZpmOLyAIc/RjUAJfuSlzT3hcSfZUQ23VOcf8Q/yJXVT6XqYPuEO8xhVXdCJN4PtDowjzeoMqZCTSmknrPcKGfvuY86rw5aIFngYy1TysR8fhDgpxqTmsrG2HOrVzmq4oLsEsm6jGqghvLM3x03HOxX6pdo/lDoaTl1lR0ZraC1tGvGQpb1M38GxNpWFmmqb0A7Q9aHK4OBddvEMEU1nivb2t41DQou3ga+czm8vo1o0cEXOczDQmCQhOrPn0/m5ud49rzMLfxhXQbT4fphuNAAbumn2dc2eKc3ZB3w4ng=
31+
secure: vOYvagXgEbjgwSJaK70QU574OcUq1MyqJYJp08wqcLA2AUfxrN3HJj24s2qd3NAMIU2Zw6jfEwQBbH3vV10cwf2u5Yp9pAgbrLOJCV+1wixMJL6GxWLesbtUuizoOCEL+f5qogFPNpy4W2FDcG0DEYwuhLSdf5qToGXP5BSn3VPuvZYRhKRq9wJpeXNTLbu+XW8hEkuUpjbr2zzm+k8pCggONGVQ5SCSCI5DVHsCnsxzumwNcKbNitLiRMQKRJiFCOQ4YQwpZ7SCEu75YxMjb+UDIEYi5CtxgxCRaoBZfYj/uI4exxavmb0/vp5CJ1dTUNmI2R3pTQUIERoFXajl479FMnxhGsKycVG7O2hKqxNCDT8tPAzxdMaF31u7AtWajdZpmOLyAIc/RjUAJfuSlzT3hcSfZUQ23VOcf8Q/yJXVT6XqYPuEO8xhVXdCJN4PtDowjzeoMqZCTSmknrPcKGfvuY86rw5aIFngYy1TysR8fhDgpxqTmsrG2HOrVzmq4oLsEsm6jGqghvLM3x03HOxX6pdo/lDoaTl1lR0ZraC1tGvGQpb1M38GxNpWFmmqb0A7Q9aHK4OBddvEMEU1nivb2t41DQou3ga+czm8vo1o0cEXOczDQmCQhOrPn0/m5ud49rzMLfxhXQbT4fphuNAAbumn2dc2eKc3ZB3w4ng=

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# next release
22

3+
# 1.6.3
4+
5+
Fixes:
6+
7+
- Handling of nullable for $ref in OpenAPI 3.0 ([issue](https://github.com/acacode/swagger-typescript-api/issues/39))
8+
Plus based on this issue was fixed most other problems with using `required` and `nullable` properties
9+
10+
311
# 1.6.2
412

513
Fixes:

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "swagger-typescript-api",
3-
"version": "1.6.2",
3+
"version": "1.6.3",
44
"description": "Create typescript api module from swagger schema",
55
"scripts": {
66
"cli": "node index.js -d -p ./swagger-test-cli.json -n swagger-test-cli.ts",

src/config.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
const config = {
32
/** CLI flag */
43
generateResponses: false,
@@ -8,14 +7,17 @@ const config = {
87
generateRouteTypes: false,
98
/** CLI flag */
109
generateClient: true,
11-
/** parsed swagger schema from getSwaggerObject() */
10+
/** parsed swagger schema from getSwaggerObject() */
11+
1212
swaggerSchema: null,
1313
/** { "#/components/schemas/Foo": @TypeInfo, ... } */
1414
componentsMap: {},
15-
}
15+
/** flag for catching convertion from swagger 2.0 */
16+
convertedFromSwagger2: false,
17+
};
1618

1719
/** needs to use data everywhere in project */
1820
module.exports = {
19-
addToConfig: configParts => Object.assign(config, configParts),
21+
addToConfig: (configParts) => Object.assign(config, configParts),
2022
config,
21-
}
23+
};

src/index.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ const { getModelType } = require("./modelTypes");
1616
const { getSwaggerObject } = require("./swagger");
1717
const { createComponentsMap, filterComponentsMap } = require("./components");
1818
const { getTemplate, createFile, pathIsExist } = require("./files");
19-
const { addToConfig, config: defaults } = require("./config");
19+
const { addToConfig, config } = require("./config");
2020

21-
mustache.escape = value => value;
21+
mustache.escape = (value) => value;
2222

2323
const prettierConfig = {
2424
printWidth: 120,
@@ -33,10 +33,10 @@ module.exports = {
3333
output,
3434
url,
3535
name,
36-
generateResponses = defaults.generateResponses,
37-
defaultResponseAsSuccess = defaults.defaultResponseAsSuccess,
38-
generateRouteTypes = defaults.generateRouteTypes,
39-
generateClient = defaults.generateClient,
36+
generateResponses = config.generateResponses,
37+
defaultResponseAsSuccess = config.defaultResponseAsSuccess,
38+
generateRouteTypes = config.generateRouteTypes,
39+
generateClient = config.generateClient,
4040
}) =>
4141
new Promise((resolve, reject) => {
4242
addToConfig({
@@ -46,7 +46,7 @@ module.exports = {
4646
generateResponses,
4747
});
4848
getSwaggerObject(input, url)
49-
.then(swaggerSchema => {
49+
.then((swaggerSchema) => {
5050
console.log("☄️ start generating your typescript api");
5151

5252
addToConfig({ swaggerSchema });
@@ -62,8 +62,8 @@ module.exports = {
6262

6363
const parsedSchemas = parseSchemas(components);
6464
const routes = parseRoutes(swaggerSchema, parsedSchemas, componentsMap, components);
65-
const hasSecurityRoutes = routes.some(route => route.security);
66-
const hasQueryRoutes = routes.some(route => route.hasQuery);
65+
const hasSecurityRoutes = routes.some((route) => route.security);
66+
const hasQueryRoutes = routes.some((route) => route.hasQuery);
6767
const apiConfig = createApiConfig({ info, servers }, hasSecurityRoutes);
6868

6969
const configuration = {
@@ -91,7 +91,7 @@ module.exports = {
9191

9292
resolve(sourceFile);
9393
})
94-
.catch(e => {
94+
.catch((e) => {
9595
reject(e);
9696
throw new Error("Swagger schema parse error!\r\n " + e);
9797
});

src/schema.js

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@ const findSchemaType = (schema) => {
1919
return "primitive";
2020
};
2121

22+
const nullableExtras = (schema, value) => {
23+
const { nullable, type } = schema || {};
24+
return nullable || type === "null" ? `${value} | null` : value;
25+
};
26+
2227
const getPrimitiveType = (property) => {
23-
const { type, nullable } = property || {};
28+
const { type } = property || {};
2429
const primitiveType = typeAliases[type] || type;
25-
return primitiveType
26-
? (nullable && `${primitiveType} | null`) || primitiveType
27-
: DEFAULT_PRIMITIVE_TYPE;
30+
return primitiveType ? nullableExtras(property, primitiveType) : DEFAULT_PRIMITIVE_TYPE;
2831
};
2932

3033
const specificObjectTypes = {
31-
array: ({ items }) => {
34+
array: ({ items, ...schemaPart }) => {
3235
const { content, type } = parseSchema(items, null, inlineExtraFormatters);
33-
return type === "primitive" ? `${content}[]` : `Array<${content}>`;
36+
return nullableExtras(schemaPart, type === "primitive" ? `${content}[]` : `Array<${content}>`);
3437
},
3538
};
3639

@@ -48,14 +51,17 @@ const getType = (property) => {
4851
if (!property) return DEFAULT_PRIMITIVE_TYPE;
4952

5053
const anotherTypeGetter = specificObjectTypes[property.type] || getPrimitiveType;
51-
return getRefTypeName(property) || anotherTypeGetter(property);
54+
const refType = getRefTypeName(property);
55+
return refType ? nullableExtras(property, refType) : anotherTypeGetter(property);
5256
};
5357

5458
const getObjectTypeContent = (properties) => {
5559
return _.map(properties, (property, name) => {
56-
// TODO: probably nullable should'n be use as required/no-required conditions
57-
const isRequired =
58-
typeof property.nullable === "undefined" ? property.required : !property.nullable;
60+
const isRequired = config.convertedFromSwagger2
61+
? typeof property.nullable === "undefined"
62+
? property.required
63+
: !property.nullable
64+
: !!property.required;
5965
return {
6066
description: property.description,
6167
isRequired,
@@ -72,16 +78,21 @@ const complexSchemaParsers = {
7278
oneOf: (schema) => {
7379
// T1 | T2
7480
const combined = _.map(schema.oneOf, complexTypeGetter);
75-
return combined.join(" | ");
81+
return nullableExtras(schema, combined.join(" | "));
7682
},
7783
allOf: (schema) => {
7884
// T1 & T2
79-
return _.map(schema.allOf, complexTypeGetter).join(" & ");
85+
return nullableExtras(schema, _.map(schema.allOf, complexTypeGetter).join(" & "));
8086
},
8187
anyOf: (schema) => {
8288
// T1 | T2 | (T1 & T2)
8389
const combined = _.map(schema.anyOf, complexTypeGetter);
84-
return `${combined.join(" | ")}` + (combined.length > 1 ? ` | (${combined.join(" & ")})` : "");
90+
const nonEmptyTypesCombined = combined.filter((type) => !jsEmptyTypes.includes(type));
91+
return nullableExtras(
92+
schema,
93+
`${combined.join(" | ")}` +
94+
(nonEmptyTypesCombined.length > 1 ? ` | (${nonEmptyTypesCombined.join(" & ")})` : ""),
95+
);
8596
},
8697
// TODO
8798
not: (schema) => {
@@ -170,7 +181,8 @@ const schemaParsers = {
170181
typeIdentifier: "type",
171182
name: typeName,
172183
description: formatDescription(description),
173-
content: contentType || getType(schema),
184+
// TODO: probably it should be refactored. `type === 'null'` is not flexible
185+
content: type === "null" ? type : contentType || getType(schema),
174186
};
175187
},
176188
};
@@ -191,12 +203,10 @@ const parseSchema = (rawSchema, typeName, formattersMap) => {
191203
let parsedSchema = null;
192204

193205
if (typeof rawSchema === "string") {
194-
console.log("WOW THERE IS STRING", rawSchema);
195206
return rawSchema;
196207
}
197208

198209
if (rawSchema.$parsedSchema) {
199-
console.log("IT IS ALREADY PARSED SCHEMA", rawSchema);
200210
schemaType = rawSchema.schemaType;
201211
parsedSchema = rawSchema;
202212
} else {

src/swagger.js

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
const _ = require('lodash');
2-
const yaml = require('js-yaml');
1+
const _ = require("lodash");
2+
const yaml = require("js-yaml");
33
const axios = require("axios");
4-
const converter = require('swagger2openapi');
4+
const converter = require("swagger2openapi");
5+
const { addToConfig } = require("./config");
56
const { pathIsExist, getFileContent } = require("./files");
67

78
const parseSwaggerFile = (file) => {
@@ -10,44 +11,54 @@ const parseSwaggerFile = (file) => {
1011
try {
1112
return JSON.parse(file);
1213
} catch (e) {
13-
return yaml.safeLoad(file)
14+
return yaml.safeLoad(file);
1415
}
15-
}
16+
};
1617

17-
const getSwaggerFile = (pathToSwagger, urlToSwagger) => new Promise((resolve) => {
18-
if (pathIsExist(pathToSwagger)){
19-
console.log(`✨ try to get swagger by path "${pathToSwagger}"`)
20-
resolve(getFileContent(pathToSwagger))
21-
} else {
22-
console.log(`✨ try to get swagger by url "${urlToSwagger}"`)
23-
axios.get(urlToSwagger).then(res => resolve(res.data))
24-
}
25-
})
18+
const getSwaggerFile = (pathToSwagger, urlToSwagger) =>
19+
new Promise((resolve) => {
20+
if (pathIsExist(pathToSwagger)) {
21+
console.log(`✨ try to get swagger by path "${pathToSwagger}"`);
22+
resolve(getFileContent(pathToSwagger));
23+
} else {
24+
console.log(`✨ try to get swagger by url "${urlToSwagger}"`);
25+
axios.get(urlToSwagger).then((res) => resolve(res.data));
26+
}
27+
});
2628

2729
const getSwaggerObject = (pathToSwagger, urlToSwagger) =>
28-
new Promise(resolve =>
29-
getSwaggerFile(pathToSwagger, urlToSwagger).then(file => {
30-
const swaggerSchema = parseSwaggerFile(file);
31-
if (!(swaggerSchema.openapi)) {
32-
converter.convertObj(swaggerSchema, {
33-
warnOnly: true,
34-
refSiblings: 'preserve',
35-
rbname: "requestBodyName",
36-
}, function(err, options){
37-
const swaggerSchema = _.get(err, 'options.openapi', _.get(options, 'openapi'))
38-
if (!swaggerSchema && err) {
39-
throw new Error(err)
40-
}
41-
resolve(swaggerSchema)
42-
});
43-
} else {
44-
resolve(swaggerSchema)
45-
}
46-
}).catch(e => {
47-
throw new Error(e)
48-
})
49-
)
30+
new Promise((resolve) =>
31+
getSwaggerFile(pathToSwagger, urlToSwagger)
32+
.then((file) => {
33+
const swaggerSchema = parseSwaggerFile(file);
34+
if (!swaggerSchema.openapi) {
35+
converter.convertObj(
36+
swaggerSchema,
37+
{
38+
warnOnly: true,
39+
refSiblings: "preserve",
40+
rbname: "requestBodyName",
41+
},
42+
function (err, options) {
43+
const swaggerSchema = _.get(err, "options.openapi", _.get(options, "openapi"));
44+
if (!swaggerSchema && err) {
45+
throw new Error(err);
46+
}
47+
addToConfig({
48+
convertedFromSwagger2: true,
49+
});
50+
resolve(swaggerSchema);
51+
},
52+
);
53+
} else {
54+
resolve(swaggerSchema);
55+
}
56+
})
57+
.catch((e) => {
58+
throw new Error(e);
59+
}),
60+
);
5061

5162
module.exports = {
5263
getSwaggerObject,
53-
}
64+
};

0 commit comments

Comments
 (0)