Skip to content

Commit 770098d

Browse files
committed
added handling of null data type during reverse-engineering of JSON/JSON Schema, and converting to string with nullable = true
1 parent 34ca63a commit 770098d

File tree

23 files changed

+1860
-23
lines changed

23 files changed

+1860
-23
lines changed

forward_engineering/helpers/componentsHelpers/index.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,32 @@ const { getExamples } = require('./examplesHelper');
88
const { getLinks } = require('./linksHelper');
99
const { getCallbacks } = require('../pathHelper');
1010
const getExtensions = require('../extensionsHelper');
11+
const { prepareName } = require('../../utils/utils');
12+
13+
const renameComponents = (components) => {
14+
if (!components) {
15+
return components;
16+
}
17+
18+
return Object.keys(components).reduce((result, componentName) => {
19+
return Object.assign({}, result, {
20+
[prepareName(componentName)]: components[componentName]
21+
});
22+
}, {});
23+
};
1124

1225
function getComponents(data) {
1326
const componentsData = get(JSON.parse(data.modelDefinitions), 'properties', {});
1427

15-
const schemas = getSchemas(componentsData.schemas);
16-
const responses = getResponses(componentsData.responses);
17-
const parameters = getParameters(componentsData.parameters);
18-
const examples = getExamples(componentsData.examples);
19-
const requestBodies = getRequestBodies(componentsData.requestBodies);
20-
const headers = getHeaders(componentsData.headers);
21-
const securitySchemes = getSecuritySchemes(componentsData.securitySchemes);
22-
const links = getLinks(componentsData.links);
23-
const callbacks = getCallbacks(componentsData.callbacks, data.containers);
28+
const schemas = renameComponents(getSchemas(componentsData.schemas));
29+
const responses = renameComponents(getResponses(componentsData.responses));
30+
const parameters = renameComponents(getParameters(componentsData.parameters));
31+
const examples = renameComponents(getExamples(componentsData.examples));
32+
const requestBodies = renameComponents(getRequestBodies(componentsData.requestBodies));
33+
const headers = renameComponents(getHeaders(componentsData.headers));
34+
const securitySchemes = renameComponents(getSecuritySchemes(componentsData.securitySchemes));
35+
const links = renameComponents(getLinks(componentsData.links));
36+
const callbacks = renameComponents(getCallbacks(componentsData.callbacks, data.containers));
2437

2538
const extensions = getExtensions(get(componentsData, `['Specification Extensions'].scopesExtensions`));
2639

forward_engineering/helpers/typeHelper.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const get = require('lodash.get');
22
const getExtensions = require('./extensionsHelper');
3+
const { prepareReferenceName } = require('../utils/utils');
34

45
function getType(data, key) {
56
if (!data) {
@@ -29,6 +30,7 @@ function getTypeProps(data, key) {
2930
minItems: data.minItems,
3031
maxItems: data.maxItems,
3132
uniqueItems: data.uniqueItems || undefined,
33+
nullable: data.nullable,
3234
discriminator: data.discriminator,
3335
readOnly: data.readOnly,
3436
xml: getXml(data.xml)
@@ -46,6 +48,7 @@ function getTypeProps(data, key) {
4648
minProperties: data.minProperties,
4749
maxProperties: data.maxProperties,
4850
additionalProperties: getAdditionalProperties(data),
51+
nullable: data.nullable,
4952
discriminator: data.discriminator,
5053
readOnly: data.readOnly,
5154
example: parseExample(data.sample),
@@ -67,9 +70,10 @@ function getTypeProps(data, key) {
6770

6871
function getRef({ $ref: ref }) {
6972
if (ref.startsWith('#')) {
70-
return { $ref: ref.replace('#model/definitions', '#/components') };
73+
ref = ref.replace('#model/definitions', '#/components');
7174
}
72-
return { $ref: ref };
75+
76+
return { $ref: prepareReferenceName(ref) };
7377
}
7478

7579
function hasRef(data = {}) {
@@ -108,7 +112,7 @@ function getXml(data) {
108112
}
109113

110114
function getPrimitiveTypeProps(data) {
111-
return {
115+
const properties = {
112116
type: data.type,
113117
format: data.format || data.mode,
114118
description: data.description,
@@ -125,6 +129,8 @@ function getPrimitiveTypeProps(data) {
125129
xml: getXml(data.xml),
126130
example: data.sample
127131
};
132+
133+
return addIfTrue(properties, 'nullable', data.nullable);
128134
}
129135

130136
function getAdditionalProperties(data) {
@@ -197,6 +203,16 @@ function parseExample(data) {
197203
}
198204
}
199205

206+
function addIfTrue(data, propertyName, value) {
207+
if (!value) {
208+
return data;
209+
}
210+
211+
return Object.assign({}, data, {
212+
[propertyName]: value
213+
});
214+
}
215+
200216
module.exports = {
201217
getType,
202218
getRef,

forward_engineering/utils/utils.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ function removeEmptyObjectFields(inputObj) {
2424
);
2525
}
2626

27+
const prepareName = (name) => {
28+
return (name || '').replace(/\ /ig, '_');
29+
};
30+
31+
const prepareReferenceName = (ref) => {
32+
const refParts = ref.split('/');
33+
const name = refParts.pop();
34+
const preparedName = prepareName(name);
35+
36+
refParts.push(preparedName);
37+
38+
return refParts.join('/');
39+
};
40+
2741
module.exports = {
28-
removeEmptyObjectFields
42+
removeEmptyObjectFields,
43+
prepareName,
44+
prepareReferenceName
2945
};

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "OpenAPI",
3-
"version": "0.1.2",
4-
"versionDate": "2019-06-26",
3+
"version": "0.1.3",
4+
"versionDate": "2019-08-30",
55
"author": "hackolade",
66
"engines": {
77
"hackolade": "3.3.0",

properties_pane/field_level/fieldLevelConfig.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,13 @@ making sure that you maintain a proper JSON format.
303303
"propertyType": "text",
304304
"shouldValidate": true
305305
},
306+
{
307+
"propertyName": "nullable",
308+
"propertyKeyword": "nullable",
309+
"shouldValidate": false,
310+
"propertyType": "checkbox",
311+
"enableForReference": true
312+
},
306313
{
307314
"propertyName": "discriminator",
308315
"propertyKeyword": "discriminator",
@@ -488,6 +495,13 @@ making sure that you maintain a proper JSON format.
488495
"propertyType": "text",
489496
"shouldValidate": true
490497
},
498+
{
499+
"propertyName": "nullable",
500+
"propertyKeyword": "nullable",
501+
"shouldValidate": false,
502+
"propertyType": "checkbox",
503+
"enableForReference": true
504+
},
491505
{
492506
"propertyName": "discriminator",
493507
"propertyKeyword": "discriminator",
@@ -673,6 +687,13 @@ making sure that you maintain a proper JSON format.
673687
"propertyType": "text",
674688
"shouldValidate": true
675689
},
690+
{
691+
"propertyName": "nullable",
692+
"propertyKeyword": "nullable",
693+
"shouldValidate": false,
694+
"propertyType": "checkbox",
695+
"enableForReference": true
696+
},
676697
{
677698
"propertyName": "discriminator",
678699
"propertyKeyword": "discriminator",
@@ -878,6 +899,17 @@ making sure that you maintain a proper JSON format.
878899
"maxItems",
879900
"uniqueItems",
880901
"additionalItems",
902+
{
903+
"propertyName": "nullable",
904+
"propertyKeyword": "nullable",
905+
"shouldValidate": false,
906+
"propertyType": "checkbox",
907+
"enableForReference": true,
908+
"dependency": {
909+
"key": "subtype",
910+
"value": "schema"
911+
}
912+
},
881913
{
882914
"propertyName": "discriminator",
883915
"propertyKeyword": "discriminator",
@@ -1182,6 +1214,17 @@ making sure that you maintain a proper JSON format.
11821214
]
11831215
}
11841216
},
1217+
{
1218+
"propertyName": "nullable",
1219+
"propertyKeyword": "nullable",
1220+
"shouldValidate": false,
1221+
"propertyType": "checkbox",
1222+
"enableForReference": true,
1223+
"dependency": {
1224+
"key": "subtype",
1225+
"value": "schema"
1226+
}
1227+
},
11851228
{
11861229
"propertyName": "discriminator",
11871230
"propertyKeyword": "discriminator",

reverse_engineering/api.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const commonHelper = require('./helpers/commonHelper');
44
const dataHelper = require('./helpers/dataHelper');
55
const errorHelper = require('./helpers/errorHelper');
6+
const adaptJsonSchema = require('./helpers/adaptJsonSchema/adaptJsonSchema');
67

78
module.exports = {
89
reFromFile(data, logger, callback) {
@@ -20,7 +21,24 @@ module.exports = {
2021
logger.log('error', handledError, title);
2122
callback(handledError);
2223
});
23-
}
24+
},
25+
26+
adaptJsonSchema(data, logger, callback) {
27+
logger.log('info', 'Adaptation of JSON Schema started...', 'Adapt JSON Schema');
28+
try {
29+
const jsonSchema = JSON.parse(data.jsonSchema);
30+
31+
const adaptedJsonSchema = adaptJsonSchema(jsonSchema);
32+
33+
logger.log('info', 'Adaptation of JSON Schema finished.', 'Adapt JSON Schema');
34+
35+
callback(null, {
36+
jsonSchema: JSON.stringify(adaptedJsonSchema)
37+
});
38+
} catch(e) {
39+
callback(commonHelper.handleErrorObject(e, 'Adapt JSON Schema'), data);
40+
}
41+
}
2442
};
2543

2644
const convertOpenAPISchemaToHackolade = (openAPISchema, fieldOrder) => {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const mapJsonSchema = require('./mapJsonSchema');
2+
3+
const convertToString = (jsonSchema) => {
4+
return Object.assign({}, jsonSchema, {
5+
type: 'string',
6+
nullable: true
7+
});
8+
};
9+
10+
const adaptJsonSchema = (jsonSchema) => {
11+
return mapJsonSchema(jsonSchema, (jsonSchemaItem) => {
12+
if (jsonSchemaItem.type !== 'null') {
13+
return jsonSchemaItem;
14+
}
15+
16+
return convertToString(jsonSchemaItem);
17+
});
18+
};
19+
20+
module.exports = adaptJsonSchema;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const isPlainObject = require('lodash.isplainobject');
2+
const partial = require('lodash.partial');
3+
4+
const add = (obj, properties) => Object.assign({}, obj, properties);
5+
6+
const mapJsonSchema = (jsonSchema, callback) => {
7+
const mapProperties = (properties, mapper) => Object.keys(properties).reduce((newProperties, propertyName) => {
8+
return add(newProperties, {
9+
[propertyName]: mapper(properties[propertyName])
10+
});
11+
}, {});
12+
const mapItems = (items, mapper) => {
13+
if (Array.isArray(items)) {
14+
return items.map(jsonSchema => mapper(jsonSchema));
15+
} else if (isPlainObject(items)) {
16+
return mapper(items);
17+
} else {
18+
return items;
19+
}
20+
};
21+
const applyTo = (properties, jsonSchema, mapper) => {
22+
return properties.reduce((jsonSchema, propertyName) => {
23+
if (!jsonSchema[propertyName]) {
24+
return jsonSchema;
25+
}
26+
27+
return Object.assign({}, jsonSchema, {
28+
[propertyName]: mapper(jsonSchema[propertyName])
29+
});
30+
}, jsonSchema);
31+
};
32+
if (!isPlainObject(jsonSchema)) {
33+
return jsonSchema;
34+
}
35+
const mapper = partial(mapJsonSchema, partial.placeholder, callback);
36+
const propertiesLike = [ 'properties', 'definitions', 'patternProperties' ];
37+
const itemsLike = [ 'items', 'oneOf', 'allOf', 'anyOf', 'not' ];
38+
39+
const copyJsonSchema = Object.assign({}, jsonSchema);
40+
const jsonSchemaWithNewProperties = applyTo(propertiesLike, copyJsonSchema, partial(mapProperties, partial.placeholder, mapper));
41+
const newJsonSchema = applyTo(itemsLike, jsonSchemaWithNewProperties, partial(mapItems, partial.placeholder, mapper));
42+
43+
return callback(newJsonSchema);
44+
};
45+
46+
module.exports = mapJsonSchema;

reverse_engineering/node_modules/lodash.isplainobject/LICENSE

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

reverse_engineering/node_modules/lodash.isplainobject/README.md

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)