Skip to content

Commit

Permalink
more enhancements
Browse files Browse the repository at this point in the history
- implement `escapeUnsafeCharacters` for Julia code gen
- not escaping `baseName` for `CodegenParameter` and `CodegenProperty` anymore, they interfere with other ops
    - added a mustache lambda `escapeDollar` and used that instead
  • Loading branch information
tanmaykm committed Jan 10, 2023
1 parent bfc1033 commit 1a4cfda
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import org.slf4j.LoggerFactory;

import com.google.common.base.CaseFormat;
import com.google.common.collect.ImmutableMap;
import com.samskivert.mustache.Mustache.Lambda;
import org.openapitools.codegen.templating.mustache.EscapeChar;

public abstract class AbstractJuliaCodegen extends DefaultCodegen {
protected final Logger LOGGER = LoggerFactory.getLogger(AbstractJuliaCodegen.class);
Expand Down Expand Up @@ -336,7 +339,7 @@ public String toDefaultValue(Schema schema) {

@Override
public String escapeUnsafeCharacters(String input) {
return input;
return input.replace("#=", "#_=").replace("=#", "=_#");
}

/**
Expand All @@ -348,12 +351,6 @@ public String escapeQuotationMark(String input) {
return input.replace("\"", "\\\"");
}

protected String escapeBaseName(String name) {
// replace all $ not prefixed with \ with a \
name = name.replaceAll("(?<!\\\\)\\$", "\\\\\\$");
return name;
}

protected String escapeRegex(String pattern) {
pattern = pattern.replaceAll("\\\\\\\\", "\\\\");
pattern = pattern.replaceAll("^/", "");
Expand All @@ -371,7 +368,6 @@ protected String escapeRegex(String pattern) {
@Override
public CodegenParameter fromParameter(Parameter param, Set<String> imports) {
CodegenParameter parameter = super.fromParameter(param, imports);
parameter.baseName = escapeBaseName(parameter.baseName);
if (parameter.pattern != null) {
parameter.pattern = escapeRegex(parameter.pattern);
}
Expand All @@ -395,7 +391,6 @@ public CodegenParameter fromParameter(Parameter param, Set<String> imports) {
@Override
public CodegenProperty fromProperty(String name, Schema schema, boolean required) {
CodegenProperty property = super.fromProperty(name, schema, required);
property.baseName = escapeBaseName(property.baseName);
// if the name needs any escaping, we set it to var"name"
if (needsVarEscape(property.name)) {
property.name = "var\"" + property.name + "\"";
Expand Down Expand Up @@ -465,4 +460,10 @@ public CodegenOperation fromOperation(String path,

return op;
}

@Override
protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
return super.addMustacheLambdas()
.put("escapeDollar", new EscapeChar("(?<!\\\\)\\$", "\\\\\\$"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.openapitools.codegen.templating.mustache;

import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;

import java.io.IOException;
import java.io.Writer;

/**
* Escapes the desired character if not escaped already, e.g. $ => \$.
*
* Register:
* <pre>
* additionalProperties.put("escapeDollar", new EscapeChar("(?<!\\\\)\\$", "\\\\\\$"));
* </pre>
*
* Use:
* <pre>
* {{#lambda.escapeDollar}}{{name}}{{/lambda.escapeDollar}}
* </pre>
*/
public class EscapeChar implements Mustache.Lambda {
private String matchPattern;
private String replacement;

/**
* Constructs a new instance of {@link EscapeChar}, with the desired character to escape
*/
public EscapeChar(String matchPattern, String replacement) {
this.matchPattern = matchPattern;
this.replacement = replacement;
}

@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String text = fragment.execute();
text = text.replaceAll(matchPattern, replacement);
writer.write(text);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ function _oacinternal_{{operationId}}(_api::{{classname}}{{#allParams}}{{#requir
{{/allParams}}
_ctx = OpenAPI.Clients.Ctx(_api.client, "{{httpMethod}}", _returntypes_{{operationId}}, "{{path}}", [{{#authMethods}}"{{name}}", {{/authMethods}}]{{#bodyParam}}, {{paramName}}{{/bodyParam}})
{{#pathParams}}
OpenAPI.Clients.set_param(_ctx.path, "{{baseName}}", {{paramName}}{{#isListContainer}}; collection_format="{{collectionFormat}}"{{/isListContainer}}) # type {{dataType}}
OpenAPI.Clients.set_param(_ctx.path, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{paramName}}{{#isListContainer}}; collection_format="{{collectionFormat}}"{{/isListContainer}}) # type {{dataType}}
{{/pathParams}}
{{#queryParams}}
OpenAPI.Clients.set_param(_ctx.query, "{{baseName}}", {{paramName}}{{#isListContainer}}; collection_format="{{collectionFormat}}"{{/isListContainer}}) # type {{dataType}}
OpenAPI.Clients.set_param(_ctx.query, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{paramName}}{{#isListContainer}}; collection_format="{{collectionFormat}}"{{/isListContainer}}) # type {{dataType}}
{{/queryParams}}
{{#headerParams}}
OpenAPI.Clients.set_param(_ctx.header, "{{baseName}}", {{paramName}}{{#isListContainer}}; collection_format="{{collectionFormat}}"{{/isListContainer}}) # type {{dataType}}
OpenAPI.Clients.set_param(_ctx.header, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{paramName}}{{#isListContainer}}; collection_format="{{collectionFormat}}"{{/isListContainer}}) # type {{dataType}}
{{/headerParams}}
{{#formParams}}
{{^isFile}}
OpenAPI.Clients.set_param(_ctx.form, "{{baseName}}", {{paramName}}{{#isListContainer}}; collection_format="{{collectionFormat}}"{{/isListContainer}}) # type {{dataType}}
OpenAPI.Clients.set_param(_ctx.form, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{paramName}}{{#isListContainer}}; collection_format="{{collectionFormat}}"{{/isListContainer}}) # type {{dataType}}
{{/isFile}}
{{#isFile}}
OpenAPI.Clients.set_param(_ctx.file, "{{baseName}}", {{paramName}}) # type {{dataType}}
OpenAPI.Clients.set_param(_ctx.file, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{paramName}}) # type {{dataType}}
{{/isFile}}
{{/formParams}}
OpenAPI.Clients.set_header_accept(_ctx, [{{#produces}}"{{{mediaType}}}", {{/produces}}])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ Base.@kwdef mutable struct {{classname}} <: OpenAPI.APIModel

function {{classname}}({{#allVars}}{{{name}}}, {{/allVars}})
{{#allVars}}
OpenAPI.validate_property({{classname}}, Symbol("{{baseName}}"), {{{name}}})
OpenAPI.validate_property({{classname}}, Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"), {{{name}}})
{{/allVars}}
return new({{#allVars}}{{{name}}}, {{/allVars}})
end
end # type {{classname}}

const _property_types_{{classname}} = Dict{Symbol,String}({{#allVars}}Symbol("{{baseName}}")=>"{{datatype}}", {{/allVars}})
const _property_types_{{classname}} = Dict{Symbol,String}({{#allVars}}Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}")=>"{{datatype}}", {{/allVars}})
OpenAPI.property_type(::Type{ {{classname}} }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_{{classname}}[name]))}

function check_required(o::{{classname}})
Expand All @@ -39,18 +39,18 @@ end
function OpenAPI.validate_property(::Type{ {{classname}} }, name::Symbol, val)
{{#allVars}}
{{#isEnum}}
if name === Symbol("{{baseName}}")
if name === Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}")
OpenAPI.validate_param(name, "{{classname}}", :enum, val, [{{#_enum}}"{{.}}"{{^-last}}, {{/-last}}{{/_enum}}])
end
{{/isEnum}}
{{^isEnum}}
{{#format}}
if name === Symbol("{{baseName}}")
if name === Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}")
OpenAPI.validate_param(name, "{{classname}}", :format, val, "{{format}}")
end
{{/format}}
{{#hasValidation}}
if name === Symbol("{{baseName}}")
if name === Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}")
{{#maxLength}}
OpenAPI.validate_param(name, "{{classname}}", :maxLength, val, {{maxLength}})
{{/maxLength}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ function {{operationId}}_read(handler)
function {{operationId}}_read_handler(req::HTTP.Request)
openapi_params = Dict{String,Any}(){{#hasPathParams}}
path_params = HTTP.getparams(req){{#pathParams}}
openapi_params["{{baseName}}"] = OpenAPI.Servers.to_param({{dataType}}, path_params, "{{baseName}}", {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/pathParams}}{{/hasPathParams}}{{#hasQueryParams}}
openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param({{dataType}}, path_params, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/pathParams}}{{/hasPathParams}}{{#hasQueryParams}}
query_params = HTTP.queryparams(URIs.URI(req.target)){{#queryParams}}
openapi_params["{{baseName}}"] = OpenAPI.Servers.to_param({{dataType}}, query_params, "{{baseName}}", {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/queryParams}}{{/hasQueryParams}}{{#hasHeaderParams}}
openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param({{dataType}}, query_params, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/queryParams}}{{/hasQueryParams}}{{#hasHeaderParams}}
headers = Dict{String,String}(HTTP.headers(req)){{#headerParams}}
openapi_params["{{baseName}}"] = OpenAPI.Servers.to_param({{dataType}}, headers, "{{baseName}}", {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/headerParams}}{{/hasHeaderParams}}{{#hasBodyParam}}{{#bodyParams}}
openapi_params["{{baseName}}"] = OpenAPI.Servers.to_param_type({{dataType}}, String(req.body)){{/bodyParams}}{{/hasBodyParam}}{{#hasFormParams}}
openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param({{dataType}}, headers, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/headerParams}}{{/hasHeaderParams}}{{#hasBodyParam}}{{#bodyParams}}
openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param_type({{dataType}}, String(req.body)){{/bodyParams}}{{/hasBodyParam}}{{#hasFormParams}}
form_data = HTTP.parse_multipart_form(req){{#formParams}}
openapi_params["{{baseName}}"] = OpenAPI.Servers.to_param({{dataType}}, form_data, "{{baseName}}"; multipart=true, isfile={{#isFile}}true{{/isFile}}{{^isFile}}false{{/isFile}}, {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/formParams}}{{/hasFormParams}}
openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"] = OpenAPI.Servers.to_param({{dataType}}, form_data, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"; multipart=true, isfile={{#isFile}}true{{/isFile}}{{^isFile}}false{{/isFile}}, {{#required}}required=true, {{/required}}{{#isListContainer}}collection_format="{{collectionFormat}}", {{/isListContainer}}){{/formParams}}{{/hasFormParams}}
req.context[:openapi_params] = openapi_params

return handler(req)
Expand All @@ -25,22 +25,22 @@ function {{operationId}}_validate(handler)
openapi_params = req.context[:openapi_params]
{{#allParams}}{{#hasValidation}}
{{#maxLength}}
OpenAPI.validate_param("{{baseName}}", "{{operationId}}", :maxLength, openapi_params["{{baseName}}"], {{maxLength}})
OpenAPI.validate_param("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", "{{operationId}}", :maxLength, openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"], {{maxLength}})
{{/maxLength}}
{{#minLength}}
OpenAPI.validate_param("{{baseName}}", "{{operationId}}", :minLength, openapi_params["{{baseName}}"], {{minLength}})
OpenAPI.validate_param("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", "{{operationId}}", :minLength, openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"], {{minLength}})
{{/minLength}}
{{#maximum}}
OpenAPI.validate_param("{{baseName}}", "{{operationId}}", :maximum, openapi_params["{{baseName}}"], {{maximum}}, {{#exclusiveMaximum}}true{{/exclusiveMaximum}}{{^exclusiveMaximum}}false{{/exclusiveMaximum}})
OpenAPI.validate_param("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", "{{operationId}}", :maximum, openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"], {{maximum}}, {{#exclusiveMaximum}}true{{/exclusiveMaximum}}{{^exclusiveMaximum}}false{{/exclusiveMaximum}})
{{/maximum}}
{{#minimum}}
OpenAPI.validate_param("{{baseName}}", "{{operationId}}", :minimum, openapi_params["{{baseName}}"], {{minimum}}, {{#exclusiveMinimum}}true{{/exclusiveMinimum}}{{^exclusiveMinimum}}false{{/exclusiveMinimum}})
OpenAPI.validate_param("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", "{{operationId}}", :minimum, openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"], {{minimum}}, {{#exclusiveMinimum}}true{{/exclusiveMinimum}}{{^exclusiveMinimum}}false{{/exclusiveMinimum}})
{{/minimum}}
{{#maxItems}}
OpenAPI.validate_param("{{baseName}}", "{{operationId}}", :maxItems, openapi_params["{{baseName}}"], {{maxItems}})
OpenAPI.validate_param("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", "{{operationId}}", :maxItems, openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"], {{maxItems}})
{{/maxItems}}
{{#minItems}}
OpenAPI.validate_param("{{baseName}}", "{{operationId}}", :minItems, openapi_params["{{baseName}}"], {{minItems}})
OpenAPI.validate_param("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", "{{operationId}}", :minItems, openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"], {{minItems}})
{{/minItems}}
{{/hasValidation}}{{/allParams}}
return handler(req)
Expand All @@ -50,7 +50,7 @@ end
function {{operationId}}_invoke(impl; post_invoke=nothing)
function {{operationId}}_invoke_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]
ret = impl.{{operationId}}(req::HTTP.Request{{#allParams}}{{#required}}, openapi_params["{{baseName}}"]{{/required}}{{/allParams}};{{#allParams}}{{^required}} {{paramName}}=get(openapi_params, "{{baseName}}", nothing),{{/required}}{{/allParams}})
ret = impl.{{operationId}}(req::HTTP.Request{{#allParams}}{{#required}}, openapi_params["{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"]{{/required}}{{/allParams}};{{#allParams}}{{^required}} {{paramName}}=get(openapi_params, "{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}", nothing),{{/required}}{{/allParams}})
resp = OpenAPI.Servers.server_response(ret)
return (post_invoke === nothing) ? resp : post_invoke(req, resp)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ Base.@kwdef mutable struct {{classname}} <: OpenAPI.APIModel

function {{classname}}({{#allVars}}{{{name}}}, {{/allVars}})
{{#allVars}}
OpenAPI.validate_property({{classname}}, Symbol("{{baseName}}"), {{{name}}})
OpenAPI.validate_property({{classname}}, Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}"), {{{name}}})
{{/allVars}}
return new({{#allVars}}{{{name}}}, {{/allVars}})
end
end # type {{classname}}

const _property_types_{{classname}} = Dict{Symbol,String}({{#allVars}}Symbol("{{baseName}}")=>"{{datatype}}", {{/allVars}})
const _property_types_{{classname}} = Dict{Symbol,String}({{#allVars}}Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}")=>"{{datatype}}", {{/allVars}})
OpenAPI.property_type(::Type{ {{classname}} }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_{{classname}}[name]))}

function check_required(o::{{classname}})
Expand All @@ -39,18 +39,18 @@ end
function OpenAPI.validate_property(::Type{ {{classname}} }, name::Symbol, val)
{{#allVars}}
{{#isEnum}}
if name === Symbol("{{baseName}}")
if name === Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}")
OpenAPI.validate_param(name, "{{classname}}", :enum, val, [{{#allowableValues}}{{#values}}"{{{this}}}"{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}])
end
{{/isEnum}}
{{^isEnum}}
{{#format}}
if name === Symbol("{{baseName}}")
if name === Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}")
OpenAPI.validate_param(name, "{{classname}}", :format, val, "{{format}}")
end
{{/format}}
{{#hasValidation}}
if name === Symbol("{{baseName}}")
if name === Symbol("{{#lambda.escapeDollar}}{{baseName}}{{/lambda.escapeDollar}}")
{{#maxLength}}
OpenAPI.validate_param(name, "{{classname}}", :maxLength, val, {{maxLength}})
{{/maxLength}}
Expand Down

0 comments on commit 1a4cfda

Please sign in to comment.