Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure the name modification function #1762

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Optional;

/**
* This contains the OAS modification tests.
Expand All @@ -39,8 +41,9 @@ public void testForRecordName() throws IOException, BallerinaOpenApiException {
Path definitionPath = RES_DIR.resolve("record.yaml");
Path expectedPath = RES_DIR.resolve("modified_record.yaml");
OpenAPI openAPI = GeneratorUtils.getOpenAPIFromOpenAPIV3Parser(definitionPath);
OASModifier oasModifier = new OASModifier(openAPI);
OpenAPI modifiedOAS = oasModifier.modifyWithBallerinaConventions();
OASModifier oasModifier = new OASModifier();
Optional<Map<String, String>> proposedNameList = oasModifier.getProposedNameList(openAPI);
OpenAPI modifiedOAS = oasModifier.modifyWithBallerinaConventions(openAPI, proposedNameList.get());
// file comparison
OpenAPI expectedFileContent = GeneratorUtils.getOpenAPIFromOpenAPIV3Parser(expectedPath);
Assert.assertEquals(modifiedOAS, expectedFileContent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -767,8 +768,12 @@ public static OpenAPI normalizeOpenAPI(OpenAPI openAPI, boolean validateOpIds, b
}
validateRequestBody(openAPIPaths.entrySet());
if (isSanitized) {
OASModifier oasSanitizer = new OASModifier(openAPI);
return oasSanitizer.modifyWithBallerinaConventions();
OASModifier oasSanitizer = new OASModifier();
Optional<Map<String, String>> proposedNameList = oasSanitizer.getProposedNameList(openAPI);
if (proposedNameList.isEmpty()) {
return openAPI;
}
return oasSanitizer.modifyWithBallerinaConventions(openAPI, proposedNameList.get());
TharmiganK marked this conversation as resolved.
Show resolved Hide resolved
}
return openAPI;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
Expand All @@ -53,134 +54,187 @@
* @since 2.1.0
*/
public class OASModifier {
OpenAPI openapi;
List<Diagnostic> diagnostics = new ArrayList<>();

public OASModifier(OpenAPI openapi) {
this.openapi = openapi;
}

public List<Diagnostic> getDiagnostics() {
return diagnostics;
}

//modifyWithBallerinaConventions
public OpenAPI modifyWithBallerinaConventions() {
Paths paths = openapi.getPaths();
public Optional<Map<String, String>> getProposedNameList(OpenAPI openapi) {
lnash94 marked this conversation as resolved.
Show resolved Hide resolved
Map<String, String> nameMap = new HashMap<>();
if (openapi.getComponents() == null) {
return Optional.empty();
}
Components components = openapi.getComponents();
List<String> modifiedSchemaNames = new ArrayList<>();
Map<String, Schema> modifiedSchemas = new HashMap<>();
Map<String, RequestBody> modifiedRequestBodies = new HashMap<>();
Map<String, ApiResponse> modifiedResponses = new HashMap<>();
Map<String, Parameter> modifiedReusableParameters = new HashMap<>();
Map<String, Schema> schemas = components.getSchemas();
if (schemas == null) {
return Optional.empty();
}

if (components != null) {
Map<String, Schema> schemas = components.getSchemas();
if (schemas != null) {
for (Map.Entry<String, Schema> schema : schemas.entrySet()) {
String schemaName = schema.getKey();
String modifiedName = getValidNameForType(schemaName);

if (!schemaName.equals(modifiedName) && (schema.getKey().contains(modifiedName) ||
modifiedSchemaNames.contains(modifiedName))) {
// todo: check the duplication, till providing the name this will give same name as it is.
continue;
}
modifiedSchemaNames.add(modifiedName);

// replace only for reference
// 1.Update the reference at the component sections
for (Map.Entry<String, Schema> componentSchema : schemas.entrySet()) {
Schema value = componentSchema.getValue();
updateSchemaWithReference(schemaName, modifiedName, value);
modifiedSchemas.put(modifiedName, value);
}

if (components.getSchemas() != null) {
components.setSchemas(modifiedSchemas);
}

if (paths == null || paths.isEmpty()) {
openapi.setComponents(components);
return openapi;
}
for (Map.Entry<String, Schema> schemaEntry: schemas.entrySet()) {
String modifiedName = getValidNameForType(schemaEntry.getKey());
nameMap.put(schemaEntry.getKey(), modifiedName);
}
return Optional.of(getResolvedNameMap(nameMap));
}

// 2. Update OAS reusable requestBody with reference details
if (components.getRequestBodies() != null) {
for (Map.Entry<String, RequestBody> requestBody : components.getRequestBodies().entrySet()) {
RequestBody requestBodyValue = updateRequestBodySchemaType(schemaName, modifiedName,
requestBody.getValue());
modifiedRequestBodies.put(requestBody.getKey(), requestBodyValue);
}
}
// 3. Update OAS reusable response with reference details
if (components.getResponses() != null) {
Map<String, ApiResponse> responsesEntry = components.getResponses();
for (Map.Entry<String, ApiResponse> response : responsesEntry.entrySet()) {
ApiResponse modifiedResponse = updateSchemaTypeForResponses(schemaName, modifiedName,
response.getValue());
modifiedResponses.put(response.getKey(), modifiedResponse);
}
}
// 4. Update OAS reusable parameters with reference details
if (components.getParameters() != null) {
Map<String, Parameter> parameters = components.getParameters();
for (Map.Entry<String, Parameter> param : parameters.entrySet()) {
Parameter parameter = param.getValue();
if (parameter.getSchema() != null) {
Schema<?> paramSchema = parameter.getSchema();
String ref = paramSchema.get$ref();
if (ref != null) {
updateRef(schemaName, modifiedName, paramSchema);
}
parameter.setSchema(paramSchema);
}
modifiedReusableParameters.put(param.getKey(), parameter);
}
}
// 5. Update OAS reusable headers with reference details
if (components.getHeaders() != null) {
Map<String, Header> headers = components.getHeaders();
for (Map.Entry<String, Header> header : headers.entrySet()) {
Header headerValue = header.getValue();
Schema<?> type = headerValue.getSchema();
String ref = type.get$ref();
if (ref != null) {
updateRef(schemaName, modifiedName, type);
}
headerValue.setSchema(type);
header.setValue(headerValue);
}
}
// 6. Update Operation data type with reference details
Set<Map.Entry<String, PathItem>> operations = paths.entrySet();
updateOASOperations(schemaName, modifiedName, operations);
}
}
private static Map<String, String> getResolvedNameMap(Map<String, String> nameMap) {
Map<String, String> resolvedNames = new HashMap<>();
Map<String, Integer> nameCount = new HashMap<>();

if (components.getRequestBodies() != null) {
components.setRequestBodies(modifiedRequestBodies);
}
if (components.getResponses() != null) {
components.setResponses(modifiedResponses);
}
if (components.getParameters() != null) {
components.setParameters(modifiedReusableParameters);
for (Map.Entry<String, String> entry : nameMap.entrySet()) {
String currentName = entry.getKey();
String newName = entry.getValue();
String resolvedName = newName;

while (resolvedNames.containsValue(resolvedName)) {
int count = nameCount.getOrDefault(newName, 1);
resolvedName = newName + count;
nameCount.put(newName, count + 1);
}
openapi.setComponents(components);

resolvedNames.put(currentName, resolvedName);
}

return resolvedNames;
}


public OpenAPI modifyWithBallerinaConventions(OpenAPI openapi, Map<String, String> nameMap) {
TharmiganK marked this conversation as resolved.
Show resolved Hide resolved
// This is for data type name modification
openapi = modifyOASWithSchemaName(openapi, nameMap);
Paths paths = openapi.getPaths();
if (paths == null || paths.isEmpty()) {
return openapi;
}
// This is for path parameter name modifications
Set<String> modifiedNames = new HashSet<>();
for (Map.Entry<String, String> entry: nameMap.entrySet()) {
modifiedNames.add(entry.getValue());
}
Paths modifiedPaths = new Paths();
for (Map.Entry<String, PathItem> path : paths.entrySet()) {
PathDetails result = updateParameterName(modifiedSchemas, path);
PathDetails result = updateParameterName(modifiedNames, path);
modifiedPaths.put(result.pathValue(), result.pathItem());
}
openapi.setPaths(modifiedPaths);
return openapi;
}

private static PathDetails updateParameterName(Map<String, Schema> modifiedSchemas, Map.Entry<String,
private static OpenAPI modifyOASWithSchemaName(OpenAPI openapi, Map<String, String> nameMap) {
Components components = openapi.getComponents();
if (components != null && !nameMap.isEmpty() && components.getSchemas() != null) {
Map<String, Schema> schemas = components.getSchemas();

for (Map.Entry<String, Schema> schema : schemas.entrySet()) {
String schemaName = schema.getKey();
String modifiedName = nameMap.get(schemaName);

// replace only for reference
// 1.Update the reference at the component sections
updateComponentSection(components, schemas, schemaName, modifiedName);
// 2. Update OAS reusable requestBody with reference details
updateComponentRequestBodySection(components, schemaName, modifiedName);
// 3. Update OAS reusable response with reference details
updateComponentResponseSection(components, schemaName, modifiedName);
// 4. Update OAS reusable parameters with reference details
updateComponentParameterSection(components, schemaName, modifiedName);
// 5. Update OAS reusable headers with reference details
updateComponentHeaderSection(components, schemaName, modifiedName);
openapi.setComponents(components);
// 6. Update Operation data type with reference details
Paths paths = openapi.getPaths();
if (paths == null || paths.isEmpty()) {
return openapi;
}
Set<Map.Entry<String, PathItem>> operations = paths.entrySet();
updateOASOperations(schemaName, modifiedName, operations);
}
}
return openapi;
}

private static void updateComponentHeaderSection(Components components, String schemaName, String modifiedName) {
if (components.getHeaders() != null) {
Map<String, Header> headers = components.getHeaders();
Map<String, Header> modifiedHeaders = new HashMap<>();
for (Map.Entry<String, Header> header : headers.entrySet()) {
Header headerValue = header.getValue();
Schema<?> type = headerValue.getSchema();
String ref = type.get$ref();
if (ref != null) {
updateRef(schemaName, modifiedName, type);
}
headerValue.setSchema(type);
header.setValue(headerValue);
modifiedHeaders.put(header.getKey(), headerValue);
}
components.setHeaders(modifiedHeaders);
}
}

private static void updateComponentParameterSection(Components components, String schemaName, String modifiedName) {
if (components.getParameters() != null) {
Map<String, Parameter> parameters = components.getParameters();
Map<String, Parameter> modifiedReusableParameters = new HashMap<>();
for (Map.Entry<String, Parameter> param : parameters.entrySet()) {
Parameter parameter = param.getValue();
if (parameter.getSchema() != null) {
Schema<?> paramSchema = parameter.getSchema();
String ref = paramSchema.get$ref();
if (ref != null) {
updateRef(schemaName, modifiedName, paramSchema);
}
parameter.setSchema(paramSchema);
}
modifiedReusableParameters.put(param.getKey(), parameter);
}
components.setParameters(modifiedReusableParameters);
}
}

private static void updateComponentResponseSection(Components components, String schemaName, String modifiedName) {
if (components.getResponses() != null) {
Map<String, ApiResponse> responsesEntry = components.getResponses();
Map<String, ApiResponse> modifiedResponses = new HashMap<>();
for (Map.Entry<String, ApiResponse> response : responsesEntry.entrySet()) {
ApiResponse modifiedResponse = updateSchemaTypeForResponses(schemaName, modifiedName,
response.getValue());
modifiedResponses.put(response.getKey(), modifiedResponse);
}
components.setResponses(modifiedResponses);
}
}

private static void updateComponentRequestBodySection(Components components, String schemaName,
String modifiedName) {
if (components.getRequestBodies() != null) {
Map<String, RequestBody> modifiedRequestBodies = new HashMap<>();
for (Map.Entry<String, RequestBody> requestBody : components.getRequestBodies().entrySet()) {
RequestBody requestBodyValue = updateRequestBodySchemaType(schemaName, modifiedName,
requestBody.getValue());
modifiedRequestBodies.put(requestBody.getKey(), requestBodyValue);
}
components.setRequestBodies(modifiedRequestBodies);
}
}

private static void updateComponentSection(Components components, Map<String, Schema> schemas,
String schemaName, String modifiedName) {
Map<String, Schema> modifiedSchemas = new HashMap<>();
for (Map.Entry<String, Schema> componentSchema : schemas.entrySet()) {
Schema value = componentSchema.getValue();
updateSchemaWithReference(schemaName, modifiedName, value);
modifiedSchemas.put(modifiedName, value);
}

if (components.getSchemas() != null) {
components.setSchemas(modifiedSchemas);
}
}

private static PathDetails updateParameterName(Set<String> modifiedSchemas, Map.Entry<String,
PathItem> path) {
PathItem pathItem = path.getValue();
String pathValue = path.getKey();
Expand Down Expand Up @@ -251,7 +305,7 @@ private static PathDetails updateParameterName(Map<String, Schema> modifiedSchem
return new PathDetails(pathItem, pathValue);
}

private static String updateParameterNames(Map<String, Schema> modifiedSchemas, String pathValue,
private static String updateParameterNames(Set<String> modifiedSchemas, String pathValue,
Operation operation) {
List<String> parameterNames = collectParameterNames(operation.getParameters());
List<Parameter> parameters = operation.getParameters();
Expand All @@ -264,7 +318,7 @@ private static String updateParameterNames(Map<String, Schema> modifiedSchemas,
return pathValue;
}

private static String updateParameters(Map<String, Schema> modifiedSchemas, String pathValue,
private static String updateParameters(Set<String> modifiedSchemasName, String pathValue,
List<String> parameterNames, List<Parameter> parameters,
List<Parameter> modifiedParameters) {
for (Parameter parameter : parameters) {
Expand All @@ -286,7 +340,7 @@ private static String updateParameters(Map<String, Schema> modifiedSchemas, Stri
continue;
}
// check given parameter has name which similar to component schema name
if (modifiedSchemas.containsKey(modifiedPathParam)) {
if (modifiedSchemasName.contains(modifiedPathParam)) {
TharmiganK marked this conversation as resolved.
Show resolved Hide resolved
modifiedPathParam = "param" + getValidNameForParameter(modifiedPathParam).get();
}
parameterNames.add(modifiedPathParam);
Expand Down
Loading