Skip to content

Commit 2aa16dc

Browse files
authored
Merge pull request #5 from mtseluiko/feature/json-and-model-external-references-fe
Feature/json and model external references fe
2 parents 717b86b + d61f11b commit 2aa16dc

File tree

4 files changed

+153
-51
lines changed

4 files changed

+153
-51
lines changed

forward_engineering/api.js

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const getComponents = require('./helpers/componentsHelpers');
77
const commonHelper = require('./helpers/commonHelper');
88
const { getServers } = require('./helpers/serversHelper');
99
const getExtensions = require('./helpers/extensionsHelper');
10+
const handleReferencePath = require('./helpers/handleReferencePath');
11+
const mapJsonSchema = require('../reverse_engineering/helpers/adaptJsonSchema/mapJsonSchema');
1012

1113
module.exports = {
1214
generateModelScript(data, logger, cb) {
@@ -23,8 +25,12 @@ module.exports = {
2325

2426
const info = getInfo(data.modelData[0]);
2527
const servers = getServers(modelServers);
26-
const paths = getPaths(data.containers, containersIdsFromCallbacks);
27-
const components = getComponents(data);
28+
const externalDefinitions = JSON.parse(data.externalDefinitions || '{}').properties || {};
29+
const containers = handleRefInContainers(data.containers, externalDefinitions);
30+
const paths = getPaths(containers, containersIdsFromCallbacks);
31+
const definitions = JSON.parse(data.modelDefinitions) || {};
32+
const definitionsWithHandledReferences = mapJsonSchema(definitions, handleRef(externalDefinitions));
33+
const components = getComponents(definitionsWithHandledReferences, data.containers);
2834
const security = commonHelper.mapSecurity(modelSecurity);
2935
const tags = commonHelper.mapTags(modelTags);
3036
const externalDocs = commonHelper.mapExternalDocs(modelExternalDocs);
@@ -143,3 +149,43 @@ const removeCommentLines = (scriptString) => {
143149
.join('\n')
144150
.replace(/(.*?),\s*(\}|])/g, '$1$2');
145151
}
152+
153+
const handleRefInContainers = (containers, externalDefinitions) => {
154+
return containers.map(container => {
155+
try {
156+
const updatedSchemas = Object.keys(container.jsonSchema).reduce((schemas, id) => {
157+
const json = container.jsonSchema[id];
158+
try {
159+
const updatedSchema = mapJsonSchema(JSON.parse(json), handleRef(externalDefinitions));
160+
161+
return {
162+
...schemas,
163+
[id]: JSON.stringify(updatedSchema)
164+
};
165+
} catch (err) {
166+
return { ...schemas, [id]: json }
167+
}
168+
}, {});
169+
170+
return {
171+
...container,
172+
jsonSchema: updatedSchemas
173+
};
174+
} catch (err) {
175+
return container;
176+
}
177+
});
178+
};
179+
180+
181+
const handleRef = externalDefinitions => field => {
182+
if (!field.$ref) {
183+
return field;
184+
}
185+
const ref = handleReferencePath(externalDefinitions, field);
186+
if (!ref.$ref) {
187+
return ref;
188+
}
189+
190+
return { ...field, ...ref };
191+
};

forward_engineering/helpers/componentsHelpers/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ const renameComponents = (components) => {
2222
}, {});
2323
};
2424

25-
function getComponents(data) {
26-
const componentsData = get(JSON.parse(data.modelDefinitions), 'properties', {});
25+
function getComponents(definitions, containers) {
26+
const componentsData = get(definitions, 'properties', {});
2727

2828
const schemas = renameComponents(getSchemas(componentsData.schemas));
2929
const responses = renameComponents(getResponses(componentsData.responses));
@@ -33,7 +33,7 @@ function getComponents(data) {
3333
const headers = renameComponents(getHeaders(componentsData.headers));
3434
const securitySchemes = renameComponents(getSecuritySchemes(componentsData.securitySchemes));
3535
const links = renameComponents(getLinks(componentsData.links));
36-
const callbacks = renameComponents(getCallbacks(componentsData.callbacks, data.containers));
36+
const callbacks = renameComponents(getCallbacks(componentsData.callbacks, containers));
3737

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

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
const COMPONENTS_SCHEMAS_OBJECT_INDEX = 2;
2+
const REQUEST_BODY_OBJECT_INDEX = 2;
3+
const RESPONSE_NAME_INDEX = 2;
4+
const RESPONSE_OBJECT_INDEX = 3;
5+
const PATH_START_INDEX = 4;
6+
7+
const { prepareReferenceName } = require('../utils/utils');
8+
9+
const handleReferencePath = (externalDefinitions, { $ref: ref }) => {
10+
if (ref.startsWith('#')) {
11+
ref = ref.replace('#model/definitions', '#/components');
12+
13+
return { $ref: prepareReferenceName(ref) };
14+
}
15+
16+
const [ pathToFile, relativePath] = ref.split('#/');
17+
if (!relativePath) {
18+
return { $ref: prepareReferenceName(ref) };
19+
}
20+
21+
const externalDefinition = findExternalDefinition(externalDefinitions, pathToFile, relativePath);
22+
if (!externalDefinition) {
23+
return { $ref: prepareReferenceName(ref) };
24+
}
25+
26+
if (externalDefinition.fileType === 'targetSchema') {
27+
return { $ref: updateOpenApiPath(pathToFile, relativePath) };
28+
} else if (externalDefinition.fileType === 'hackoladeSchema') {
29+
return externalDefinition;
30+
} else if (externalDefinition.fileType === 'jsonSchema') {
31+
return { $ref: fixJsonSchemaPath(pathToFile, relativePath) };;
32+
}
33+
34+
return { $ref: prepareReferenceName(ref) };
35+
};
36+
37+
const fixJsonSchemaPath = (pathToFile, relativePath) => {
38+
const namePath = relativePath.split('/');
39+
if (['properties', 'items'].includes(namePath[0])) {
40+
return `${pathToFile}#/${relativePath}`;
41+
}
42+
43+
return `${pathToFile}#/${namePath.slice(1).join('/')}`;
44+
};
45+
46+
const findExternalDefinition = (externalDefinitions, pathToFile, relativePath) => {
47+
pathToFile = pathToFile.replace('file://', '');
48+
49+
const definitionName = Object.keys(externalDefinitions).find(name => {
50+
const definition = externalDefinitions[name];
51+
return (
52+
definition.fieldRelativePath === '#/' + relativePath &&
53+
definition.link === pathToFile
54+
);
55+
});
56+
57+
return externalDefinitions[definitionName];
58+
};
59+
60+
const updateOpenApiPath = (pathToFile, relativePath) => {
61+
let path = relativePath.split('/');
62+
if (path[0] === 'definitions') {
63+
if (path[COMPONENTS_SCHEMAS_OBJECT_INDEX] === 'schemas') {
64+
return `${pathToFile}#/components/schemas/${path.slice(PATH_START_INDEX).join('/')}`;
65+
}
66+
67+
path = ['', ...path];
68+
}
69+
70+
const schemaIndex = path.indexOf('schema');
71+
const hasSchema = schemaIndex !== -1;
72+
const isComponents = (path[1] === 'definitions');
73+
const schemaPath = !hasSchema ? [] : path.slice(schemaIndex);
74+
const pathWithoutProperties = (hasSchema ? path.slice(0, schemaIndex) : path).filter(item => item !== 'properties');
75+
const bucketWithRequest = isComponents ? ['components'] : pathWithoutProperties.slice(0,2);
76+
const parentElementName = isComponents ? 'components' : 'paths';
77+
const isResponse = pathWithoutProperties[RESPONSE_OBJECT_INDEX] === 'response';
78+
const isRequestBody = pathWithoutProperties[REQUEST_BODY_OBJECT_INDEX] === 'requestBody'
79+
80+
if (!isResponse) {
81+
if (!isRequestBody) {
82+
if (isComponents) {
83+
return `${pathToFile}#/${parentElementName}/${[ ...pathWithoutProperties.slice(2), ...schemaPath].join('/')}`;
84+
}
85+
86+
return `${pathToFile}#/${parentElementName}/${[ ...pathWithoutProperties , ...schemaPath].join('/')}`;
87+
}
88+
89+
return `${pathToFile}#/${parentElementName}/${[ ...bucketWithRequest, 'requestBody', 'content', ...pathWithoutProperties.slice(3), ...schemaPath].join('/')}`;
90+
}
91+
92+
const response = pathWithoutProperties[RESPONSE_NAME_INDEX];
93+
const pathToItem = pathWithoutProperties.slice(PATH_START_INDEX)
94+
95+
const pathWithResponses = [ ...bucketWithRequest, 'responses', response, ...pathToItem, ...schemaPath ];
96+
97+
return `${pathToFile}#/paths/${pathWithResponses.join('/')}`;
98+
};
99+
100+
module.exports = handleReferencePath;

forward_engineering/helpers/typeHelper.js

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -71,52 +71,8 @@ function getTypeProps(data, key, isParentActivated) {
7171
}
7272
}
7373

74-
function getRef({ $ref: ref }) {
75-
if (ref.startsWith('#')) {
76-
ref = ref.replace('#model/definitions', '#/components');
77-
78-
return { $ref: prepareReferenceName(ref) };
79-
}
80-
81-
const [ pathToFile, relativePath] = ref.split('#/');
82-
if (!relativePath) {
83-
return { $ref: prepareReferenceName(ref) };
84-
}
85-
86-
let path = relativePath.split('/');
87-
if (path[0] === 'definitions') {
88-
if (path[2] === 'schemas') {
89-
return { $ref: `${pathToFile}#/components/schemas/${path.slice(4).join('/')}` };
90-
}
91-
92-
path = ['', ...path];
93-
}
94-
95-
const schemaIndex = path.indexOf('schema');
96-
const hasSchema = schemaIndex !== -1;
97-
const isComponents = (path[1] === 'definitions');
98-
const schemaPath = !hasSchema ? [] : path.slice(schemaIndex);
99-
const pathWithoutProperties = (hasSchema ? path.slice(0, schemaIndex) : path).filter(item => item !== 'properties');
100-
const bucketWithRequest = isComponents ? ['components'] : pathWithoutProperties.slice(0,2);
101-
const parentElementName = isComponents ? 'components' : 'paths';
102-
if (pathWithoutProperties[3] !== 'response') {
103-
if (pathWithoutProperties[2] !== 'requestBody') {
104-
if (isComponents) {
105-
return { $ref: `${pathToFile}#/${parentElementName}/${[ ...pathWithoutProperties.slice(2), ...schemaPath].join('/')}` };
106-
}
107-
108-
return { $ref: `${pathToFile}#/${parentElementName}/${[ ...pathWithoutProperties , ...schemaPath].join('/')}` };
109-
}
110-
111-
return { $ref: `${pathToFile}#/${parentElementName}/${[ ...bucketWithRequest, 'requestBody', 'content', ...pathWithoutProperties.slice(3), ...schemaPath].join('/')}` };
112-
}
113-
114-
const response = pathWithoutProperties[2];
115-
const pathToItem = pathWithoutProperties.slice(4)
116-
117-
const pathWithResponses = [ ...bucketWithRequest, 'responses', response, ...pathToItem, ...schemaPath ];
118-
119-
return { $ref: `${pathToFile}#/paths/${pathWithResponses.join('/')}` };
74+
function getRef({ $ref }) {
75+
return { $ref };
12076
};
12177

12278
function hasRef(data = {}) {

0 commit comments

Comments
 (0)