diff --git a/examples/go/Dockerfile-goimports b/examples/go/Dockerfile-goimports index 7747b9bfa..82ea98f65 100644 --- a/examples/go/Dockerfile-goimports +++ b/examples/go/Dockerfile-goimports @@ -1,6 +1,6 @@ FROM golang:1.18 ENV GOPATH /go -RUN go install golang.org/x/tools/cmd/goimports@latest +RUN go install golang.org/x/tools/cmd/goimports@v0.24.0 CMD goimports -w /local diff --git a/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/UserCreator.java b/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/UserCreator.java index 6bdca6548..30ba8054f 100644 --- a/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/UserCreator.java +++ b/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/UserCreator.java @@ -79,7 +79,7 @@ public User create(final BearerTokenTwilioRestClient client){ Domains.PREVIEWIAM.toString(), path ); - request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); + request.setContentType(EnumConstants.ContentType.JSON); addPostParams(request, client); Response response = client.request(request); if (response == null) { diff --git a/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/UserUpdater.java b/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/UserUpdater.java index 5e5e82f58..f56013776 100644 --- a/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/UserUpdater.java +++ b/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/UserUpdater.java @@ -82,7 +82,7 @@ public User update(final BearerTokenTwilioRestClient client){ Domains.PREVIEWIAM.toString(), path ); - request.setContentType(EnumConstants.ContentType.FORM_URLENCODED); + request.setContentType(EnumConstants.ContentType.JSON); addPostParams(request, client); addHeaderParams(request); Response response = client.request(request); diff --git a/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/Token.java b/examples/java/src/main/java/com/twilio/rest/previewiam/v1/Token.java similarity index 99% rename from examples/java/src/main/java/com/twilio/rest/previewiam/organizations/Token.java rename to examples/java/src/main/java/com/twilio/rest/previewiam/v1/Token.java index 1102d5c7e..17b8ef4d7 100644 --- a/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/Token.java +++ b/examples/java/src/main/java/com/twilio/rest/previewiam/v1/Token.java @@ -12,7 +12,7 @@ * Do not edit the class manually. */ -package com.twilio.rest.previewiam.organizations; +package com.twilio.rest.previewiam.v1; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/TokenCreator.java b/examples/java/src/main/java/com/twilio/rest/previewiam/v1/TokenCreator.java similarity index 99% rename from examples/java/src/main/java/com/twilio/rest/previewiam/organizations/TokenCreator.java rename to examples/java/src/main/java/com/twilio/rest/previewiam/v1/TokenCreator.java index 134cd0f9c..39be29372 100644 --- a/examples/java/src/main/java/com/twilio/rest/previewiam/organizations/TokenCreator.java +++ b/examples/java/src/main/java/com/twilio/rest/previewiam/v1/TokenCreator.java @@ -12,7 +12,7 @@ * Do not edit the class manually. */ -package com.twilio.rest.previewiam.organizations; +package com.twilio.rest.previewiam.v1; import com.fasterxml.jackson.databind.ObjectMapper; import com.twilio.constant.EnumConstants; diff --git a/examples/python/twilio/rest/api/v2010/account/__init__.py b/examples/python/twilio/rest/api/v2010/account/__init__.py index 57663135b..4137b9c68 100644 --- a/examples/python/twilio/rest/api/v2010/account/__init__.py +++ b/examples/python/twilio/rest/api/v2010/account/__init__.py @@ -231,10 +231,7 @@ def delete(self) -> bool: :returns: True if delete succeeds, False otherwise """ - return self._version.delete( - method="DELETE", - uri=self._uri, - ) + return self._version.delete(method="DELETE", uri=self._uri) async def delete_async(self) -> bool: """ @@ -243,10 +240,7 @@ async def delete_async(self) -> bool: :returns: True if delete succeeds, False otherwise """ - return await self._version.delete_async( - method="DELETE", - uri=self._uri, - ) + return await self._version.delete_async(method="DELETE", uri=self._uri) def fetch(self) -> AccountInstance: """ @@ -256,10 +250,7 @@ def fetch(self) -> AccountInstance: :returns: The fetched AccountInstance """ - payload = self._version.fetch( - method="GET", - uri=self._uri, - ) + payload = self._version.fetch(method="GET", uri=self._uri) return AccountInstance( self._version, @@ -275,10 +266,7 @@ async def fetch_async(self) -> AccountInstance: :returns: The fetched AccountInstance """ - payload = await self._version.fetch_async( - method="GET", - uri=self._uri, - ) + payload = await self._version.fetch_async(method="GET", uri=self._uri) return AccountInstance( self._version, diff --git a/examples/python/twilio/rest/api/v2010/account/call/__init__.py b/examples/python/twilio/rest/api/v2010/account/call/__init__.py index 8bd4b5d7d..fba4c5d87 100644 --- a/examples/python/twilio/rest/api/v2010/account/call/__init__.py +++ b/examples/python/twilio/rest/api/v2010/account/call/__init__.py @@ -194,10 +194,7 @@ def delete(self) -> bool: :returns: True if delete succeeds, False otherwise """ - return self._version.delete( - method="DELETE", - uri=self._uri, - ) + return self._version.delete(method="DELETE", uri=self._uri) async def delete_async(self) -> bool: """ @@ -206,10 +203,7 @@ async def delete_async(self) -> bool: :returns: True if delete succeeds, False otherwise """ - return await self._version.delete_async( - method="DELETE", - uri=self._uri, - ) + return await self._version.delete_async(method="DELETE", uri=self._uri) def fetch(self) -> CallInstance: """ @@ -219,10 +213,7 @@ def fetch(self) -> CallInstance: :returns: The fetched CallInstance """ - payload = self._version.fetch( - method="GET", - uri=self._uri, - ) + payload = self._version.fetch(method="GET", uri=self._uri) return CallInstance( self._version, @@ -239,10 +230,7 @@ async def fetch_async(self) -> CallInstance: :returns: The fetched CallInstance """ - payload = await self._version.fetch_async( - method="GET", - uri=self._uri, - ) + payload = await self._version.fetch_async(method="GET", uri=self._uri) return CallInstance( self._version, diff --git a/examples/python/twilio/rest/flex_api/v1/credential/aws/__init__.py b/examples/python/twilio/rest/flex_api/v1/credential/aws/__init__.py index 14bb9647d..3a9e05a0e 100644 --- a/examples/python/twilio/rest/flex_api/v1/credential/aws/__init__.py +++ b/examples/python/twilio/rest/flex_api/v1/credential/aws/__init__.py @@ -178,10 +178,7 @@ def delete(self) -> bool: :returns: True if delete succeeds, False otherwise """ - return self._version.delete( - method="DELETE", - uri=self._uri, - ) + return self._version.delete(method="DELETE", uri=self._uri) async def delete_async(self) -> bool: """ @@ -190,10 +187,7 @@ async def delete_async(self) -> bool: :returns: True if delete succeeds, False otherwise """ - return await self._version.delete_async( - method="DELETE", - uri=self._uri, - ) + return await self._version.delete_async(method="DELETE", uri=self._uri) def fetch(self) -> AwsInstance: """ @@ -203,10 +197,7 @@ def fetch(self) -> AwsInstance: :returns: The fetched AwsInstance """ - payload = self._version.fetch( - method="GET", - uri=self._uri, - ) + payload = self._version.fetch(method="GET", uri=self._uri) return AwsInstance( self._version, @@ -222,10 +213,7 @@ async def fetch_async(self) -> AwsInstance: :returns: The fetched AwsInstance """ - payload = await self._version.fetch_async( - method="GET", - uri=self._uri, - ) + payload = await self._version.fetch_async(method="GET", uri=self._uri) return AwsInstance( self._version, diff --git a/examples/python/twilio/rest/versionless/deployed_devices/fleet.py b/examples/python/twilio/rest/versionless/deployed_devices/fleet.py index 453551733..e0025c729 100644 --- a/examples/python/twilio/rest/versionless/deployed_devices/fleet.py +++ b/examples/python/twilio/rest/versionless/deployed_devices/fleet.py @@ -110,10 +110,7 @@ def fetch(self) -> FleetInstance: :returns: The fetched FleetInstance """ - payload = self._version.fetch( - method="GET", - uri=self._uri, - ) + payload = self._version.fetch(method="GET", uri=self._uri) return FleetInstance( self._version, @@ -129,10 +126,7 @@ async def fetch_async(self) -> FleetInstance: :returns: The fetched FleetInstance """ - payload = await self._version.fetch_async( - method="GET", - uri=self._uri, - ) + payload = await self._version.fetch_async(method="GET", uri=self._uri) return FleetInstance( self._version, diff --git a/scripts/build_twilio_library.py b/scripts/build_twilio_library.py index 9880193b2..cdb9fd20f 100644 --- a/scripts/build_twilio_library.py +++ b/scripts/build_twilio_library.py @@ -18,7 +18,7 @@ 'php': 'Rest' } generateForLanguages = { - 'twilio_iam_organizations.json' : ['java'] + 'twilio_iam_organizations.json' : ['java','python'] } CLEANUP_IMPORT_LANGUAGES = ['java', 'php'] REMOVE_DUPLICATE_IMPORT_LANGUAGES = ['node'] @@ -32,7 +32,8 @@ def build(openapi_spec_path: str, output_path: str, language: str) -> None: else: spec_folder = openapi_spec_path spec_files = sorted(os.listdir(spec_folder)) - + if 'twilio_content_v1.json' in spec_files: + spec_files.remove('twilio_content_v1.json') generate(spec_folder, spec_files, output_path, language) @@ -50,6 +51,18 @@ def generate(spec_folder: str, spec_files: List[str], output_path: str, language if language in generateForLanguages.get(spec_file): generate_domain_for_language(spec_file, config_path, spec_folder, output_path, language, parent_dir) else: generate_domain_for_language(spec_file, config_path, spec_folder, output_path, language, parent_dir) + if spec_files[0] in generateForLanguages and language in generateForLanguages.get(spec_files[0]): + print(f'Generating {output_path} from {spec_folder}') + run_openapi_generator(parent_dir, language) + print(f'Code generation completed at {output_path}') + elif spec_files[0] not in generateForLanguages: + print(f'Generating {output_path} from {spec_folder}') + run_openapi_generator(parent_dir, language) + print(f'Code generation completed at {output_path}') + if language in CLEANUP_IMPORT_LANGUAGES: + remove_unused_imports(output_path, language) + if language in REMOVE_DUPLICATE_IMPORT_LANGUAGES: + remove_duplicate_imports(output_path, language) def generate_domain_for_language(spec_file: str, config_path: str, spec_folder: str, output_path: str, language: str, parent_dir: str) -> None: full_path = os.path.join(spec_folder, spec_file) @@ -62,18 +75,17 @@ def generate_domain_for_language(spec_file: str, config_path: str, spec_folder: 'arrayItemSuffix': '' }, } - + # print(config) with open(full_config_path, 'w') as f: f.write(json.dumps(config)) - print(f'Generating {output_path} from {spec_folder}') - run_openapi_generator(parent_dir, language) - print(f'Code generation completed at {output_path}') - - if language in CLEANUP_IMPORT_LANGUAGES: - remove_unused_imports(output_path, language) - if language in REMOVE_DUPLICATE_IMPORT_LANGUAGES: - remove_duplicate_imports(output_path, language) + # print(f'Generating {output_path} from {spec_folder}') + # run_openapi_generator(parent_dir, language) + # print(f'Code generation completed at {output_path}') + # if language in CLEANUP_IMPORT_LANGUAGES: + # remove_unused_imports(output_path, language) + # if language in REMOVE_DUPLICATE_IMPORT_LANGUAGES: + # remove_duplicate_imports(output_path, language) def run_openapi_generator(parent_dir: Path, language: str) -> None: properties = '-DapiTests=false' diff --git a/src/main/java/com/twilio/oai/TwilioCodegenAdapter.java b/src/main/java/com/twilio/oai/TwilioCodegenAdapter.java index 72e2db227..5c12112d5 100644 --- a/src/main/java/com/twilio/oai/TwilioCodegenAdapter.java +++ b/src/main/java/com/twilio/oai/TwilioCodegenAdapter.java @@ -2,10 +2,6 @@ import java.io.File; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Paths; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -13,6 +9,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.twilio.oai.common.ApplicationConstants; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.PathItem; import io.swagger.v3.oas.models.servers.Server; @@ -89,6 +86,12 @@ public String getVersionFromOpenAPI(final OpenAPI openAPI) { public void setDomain(final String domain) { final String domainPackage = domain.replaceAll("[-.]", ""); setOutputDir(domainPackage, getInputSpecVersion()); + if(getInputSpecVersion() == ""){ + codegen.additionalProperties().put("isVersionLess", true); + } + else{ + codegen.additionalProperties().put("isVersionLess", false); + } codegen.additionalProperties().put("domainName", StringHelper.camelize(domain)); codegen.additionalProperties().put("domainPackage", domainPackage); @@ -146,6 +149,9 @@ private String getInputSpecDomain() { } private String getInputSpecVersion() { - return codegen.getInputSpec().replaceAll(INPUT_SPEC_PATTERN, "${version}"); + String version = codegen.getInputSpec().replaceAll(INPUT_SPEC_PATTERN, "${version}"); + boolean textExists = Arrays.stream(ApplicationConstants.VERSION_LESS_SPECS) + .anyMatch(ignoredVersion -> ignoredVersion.equals(version)); + return textExists ? "" : version; } } diff --git a/src/main/java/com/twilio/oai/TwilioPythonGenerator.java b/src/main/java/com/twilio/oai/TwilioPythonGenerator.java index 3a8629731..857825672 100644 --- a/src/main/java/com/twilio/oai/TwilioPythonGenerator.java +++ b/src/main/java/com/twilio/oai/TwilioPythonGenerator.java @@ -60,6 +60,7 @@ public void processOpts() { public void processOpenAPI(final OpenAPI openAPI) { String domain = StringHelper.toSnakeCase(twilioCodegen.getDomainFromOpenAPI(openAPI)); String version = StringHelper.toSnakeCase(twilioCodegen.getVersionFromOpenAPI(openAPI)); + populateVersionDetails(actionTemplate, version); twilioCodegen.setDomain(domain); twilioCodegen.setVersion(version); twilioCodegen.setOutputDir(domain, version); @@ -70,6 +71,15 @@ public void processOpenAPI(final OpenAPI openAPI) { directoryStructureService.configure(openAPI); } + private void populateVersionDetails(PythonApiActionTemplate actionTemplate, String version) { + if(version.equals("")){ + actionTemplate.setIsVersionLess(true); + } + else{ + actionTemplate.setIsVersionLess(false); + } + } + @Override public String apiFilename(final String templateName, final String tag) { final String initFilename = "__init__.py"; @@ -87,10 +97,11 @@ public String apiFilename(final String templateName, final String tag) { return isMatchingPath && pathHasDependents; }); + //Create init files in sub folders, this return path of init file in this subfolder if (isInitFile && !filename.endsWith(initFilename)) { return PathUtils.removeExtension(filename) + File.separator + initFilename; } - + //Processing files other than init files return filename; } diff --git a/src/main/java/com/twilio/oai/api/ApiResourceBuilder.java b/src/main/java/com/twilio/oai/api/ApiResourceBuilder.java index 36287c360..355268a87 100644 --- a/src/main/java/com/twilio/oai/api/ApiResourceBuilder.java +++ b/src/main/java/com/twilio/oai/api/ApiResourceBuilder.java @@ -93,7 +93,7 @@ public ApiResourceBuilder updateOperations(Resolver codegenPar } public void updateHttpMethod(CodegenOperation co) { - + } protected void resolveParam(final Resolver codegenParameterIResolver, @@ -191,7 +191,7 @@ public CodegenModel getModel(String modelName ) { } return null; } - + public void addNestedModel(final CodegenModel codegenModel) { // TODO: Temporary fix, planning to use hashmap, set is inserting duplicate values. Iterator iterator = nestedModels.iterator(); @@ -290,12 +290,17 @@ protected Set getDistinctResponseModel(List respo for (CodegenModel codegenModel : responseModels) { for (CodegenProperty property : codegenModel.vars) { property.nameInCamelCase = StringHelper.camelize(property.nameInSnakeCase); + // When we have responseModel referencing a schema, isOverriden flag is set to false (which is null by default). This makes the property different. See assistants api ListAssistantResponse + Boolean isOverridden = property.isOverridden; + if(isOverridden != null && isOverridden == false) + property.isOverridden = null; if (Arrays .stream(Operation.values()) .anyMatch(value -> value.getValue().equals(property.nameInCamelCase))) { property.nameInCamelCase = "_" + property.nameInCamelCase; } distinctResponseModels.add(property); + property.isOverridden = isOverridden; } } return distinctResponseModels; diff --git a/src/main/java/com/twilio/oai/api/CsharpApiResourceBuilder.java b/src/main/java/com/twilio/oai/api/CsharpApiResourceBuilder.java index 5163292bd..3bfb70e19 100644 --- a/src/main/java/com/twilio/oai/api/CsharpApiResourceBuilder.java +++ b/src/main/java/com/twilio/oai/api/CsharpApiResourceBuilder.java @@ -104,15 +104,19 @@ public void updateHttpMethod(CodegenOperation co) { } } + private void setDataType(CodegenParameter codegenParameter) { + for (CodegenModel codegenModel : getAllModels()) + if (codegenModel.classname.equals(codegenParameter.dataType)) + codegenParameter.dataType = getApiName() + "Resource" + ApplicationConstants.DOT + codegenParameter.dataType; + } + private void resolveIngressModel(CodegenOperation codegenOperation) { // Required params are used in parameters in C#, Check Params.mustache. - for (CodegenParameter codegenParameter: codegenOperation.requiredParams) { - for (CodegenModel codegenModel : getAllModels()) { - if (codegenModel.classname.equals(codegenParameter.paramName)) { - codegenParameter.dataType = getApiName() + "Resource" + ApplicationConstants.DOT + codegenParameter.dataType; - } - } - + for (CodegenParameter codegenParameter: codegenOperation.requiredParams) + setDataType(codegenParameter); + + for (CodegenParameter codegenParameter: codegenOperation.optionalParams) { + setDataType(codegenParameter); } } @@ -191,12 +195,16 @@ public Set getDistinctResponseModel(List response for (CodegenModel codegenModel: responseModels) { for (CodegenProperty property: codegenModel.vars) { property.nameInCamelCase = StringHelper.camelize(property.nameInSnakeCase); + Boolean isOverridden = property.isOverridden; + if(isOverridden != null && isOverridden == false) + property.isOverridden = null; if (Arrays.stream(EnumConstants.Operation.values()) - .anyMatch(value -> value.getValue().equals(property.nameInCamelCase)) + .anyMatch(value -> value.getValue().equals(property.nameInCamelCase)) || isNestedModelPresentWithPropertyName(property)) { property.nameInCamelCase = "_" + property.nameInCamelCase; } distinctResponseModels.add(property); + property.isOverridden = isOverridden; } } return distinctResponseModels; @@ -298,7 +306,7 @@ private void rearrangeBeforeAfter(final List parameters) { } public boolean isNestedModelPresentWithPropertyName(final CodegenProperty property) { - if (nestedModels == null || nestedModels.size() < 1) return false; + if (nestedModels == null || nestedModels.size() < 1) return false; Optional foundModel = nestedModels.stream() .filter(model -> model.classname.equals(property.name)) .findFirst(); diff --git a/src/main/java/com/twilio/oai/api/JavaApiResourceBuilder.java b/src/main/java/com/twilio/oai/api/JavaApiResourceBuilder.java index 3e95f1123..75b20d804 100644 --- a/src/main/java/com/twilio/oai/api/JavaApiResourceBuilder.java +++ b/src/main/java/com/twilio/oai/api/JavaApiResourceBuilder.java @@ -96,16 +96,24 @@ public IApiResourceBuilder updateTemplate() { return this; } + private void populateContentType(CodegenOperation co) { + if(co.consumes != null && !co.consumes.isEmpty()) + co.consumes.forEach(consume -> { + if(consume.getOrDefault("mediaType", "").equals(CONTENT_TYPE_JSON)) + co.vendorExtensions.put("x-is-json", true); + }); + } + @Override public ApiResourceBuilder updateOperations(Resolver codegenParameterIResolver) { headerParamModelList = new HashSet<>(); JsonRequestBodyResolver jsonRequestBodyResolver = new JsonRequestBodyResolver(this, codegenPropertyIResolver); this.codegenOperationList.forEach(co -> { updateNestedContent(co); + populateContentType(co); updateHttpMethod(co); List filePathArray = new ArrayList<>(Arrays.asList(co.baseName.split(PATH_SEPARATOR_PLACEHOLDER))); String resourceName = filePathArray.remove(filePathArray.size()-1); - co.allParams.stream() .filter(item -> !(item.getContent() != null && item.getContent().get("application/json") != null)) @@ -602,8 +610,15 @@ private CodegenModel getConcatenatedResponseModel(List responseMod resModel.vendorExtensions.forEach( (key, value) -> codegenModel.vendorExtensions.merge(key, value, (oldValue, newValue) -> newValue)); } - - resModel.vars.stream().filter(Predicate.not(codegenProperties::contains)).forEach(codegenProperties::add); + resModel.vars.forEach(var -> { + Boolean isOverridden = var.isOverridden; + if(isOverridden != null && isOverridden == false) + var.isOverridden = null; + if(!codegenProperties.contains(var)) + codegenProperties.add(var); + var.isOverridden = isOverridden; + }); +// resModel.vars.stream().filter(Predicate.not(codegenProperties::contains)).forEach(codegenProperties::add); } codegenProperties.forEach(prop -> prop.baseName = StringHelper.camelize(prop.baseName, true)); @@ -631,7 +646,7 @@ public void addEnums(IJsonSchemaValidationProperties item) { } else { enumName = ((CodegenProperty) enumItem).enumName; } - + if (enumName.equals(newItemEnumName)) { isDuplicate = true; break; // No need to continue checking duplicates diff --git a/src/main/java/com/twilio/oai/api/PythonApiResourceBuilder.java b/src/main/java/com/twilio/oai/api/PythonApiResourceBuilder.java index 4918ed713..ecd638eba 100644 --- a/src/main/java/com/twilio/oai/api/PythonApiResourceBuilder.java +++ b/src/main/java/com/twilio/oai/api/PythonApiResourceBuilder.java @@ -9,10 +9,7 @@ import com.twilio.oai.resolver.python.PythonCodegenModelResolver; import com.twilio.oai.template.IApiActionTemplate; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; import org.openapitools.codegen.CodegenModel; @@ -63,6 +60,9 @@ public ApiResourceBuilder updateOperations(final Resolver code cp.paramName = "from_"; } } + Map oauthAttributes = getSecurityMethods(co); + if (oauthAttributes != null) + co.vendorExtensions.put("x-auth-attributes", oauthAttributes); } return this; } @@ -202,4 +202,13 @@ public ApiResourceBuilder updateModel(Resolver codegenModelResolve super.updateModel(codegenModelResolver); return this; } + + public Map getSecurityMethods(CodegenOperation co){ + if (co.authMethods != null && co.authMethods.size() > 0 && co.authMethods.get(0).isOAuth ) { + Map oauthAttributes = new HashMap<>(); + oauthAttributes.put("x-oauth", true); + return oauthAttributes; + } + return null; + } } diff --git a/src/main/java/com/twilio/oai/common/ApplicationConstants.java b/src/main/java/com/twilio/oai/common/ApplicationConstants.java index 953d2e03c..0694d76a9 100644 --- a/src/main/java/com/twilio/oai/common/ApplicationConstants.java +++ b/src/main/java/com/twilio/oai/common/ApplicationConstants.java @@ -55,4 +55,7 @@ public class ApplicationConstants { public static final String PHONE_NUMBER = "phone-number"; public static final Predicate SUCCESS = i -> i != null && i >= 200 && i < 400; + + public static final String[] VERSION_LESS_SPECS = {"organizations"}; + } diff --git a/src/main/java/com/twilio/oai/template/AbstractApiActionTemplate.java b/src/main/java/com/twilio/oai/template/AbstractApiActionTemplate.java index 7864629e6..dba0ce4dc 100644 --- a/src/main/java/com/twilio/oai/template/AbstractApiActionTemplate.java +++ b/src/main/java/com/twilio/oai/template/AbstractApiActionTemplate.java @@ -50,8 +50,11 @@ public void addSupportVersion() { final String templateName = templateStrings.get(0); final String fileExtension = templateStrings.get(1); final String apiVersionClass = codegen.additionalProperties().get("apiVersionClass").toString(); + final boolean isVersionLess = (boolean)codegen.additionalProperties().get("isVersionLess"); - if (apiVersionClass.startsWith("V")) { + //For versionless domains this has to be added to api template files, not supporting files + //In python init files should get added to api template files if domain is versionless + if (isVersionLess != true && apiVersionClass.startsWith("V")) { codegen .supportingFiles() .add(new SupportingFile(templateName, diff --git a/src/main/java/com/twilio/oai/template/PythonApiActionTemplate.java b/src/main/java/com/twilio/oai/template/PythonApiActionTemplate.java index 7cb2d2e2f..544fcbc98 100644 --- a/src/main/java/com/twilio/oai/template/PythonApiActionTemplate.java +++ b/src/main/java/com/twilio/oai/template/PythonApiActionTemplate.java @@ -10,11 +10,16 @@ public class PythonApiActionTemplate extends AbstractApiActionTemplate { public static final String INIT_FILENAME = "__init__"; + private boolean isVersionLess = false; public PythonApiActionTemplate(final CodegenConfig codegenConfig) { super(codegenConfig); } + public void setIsVersionLess(boolean isVLess){ + isVersionLess = isVLess; + } + @Override public Map> mapping() { return Map.of(API_TEMPLATE, @@ -25,7 +30,7 @@ public Map> mapping() { @Override protected String getVersionFilename(final String apiVersionClass) { - if (apiVersionClass.startsWith("V")) { + if (isVersionLess != true && apiVersionClass.startsWith("V")) { return INIT_FILENAME; } diff --git a/src/main/resources/twilio-node/listInterfaceFunctions.mustache b/src/main/resources/twilio-node/listInterfaceFunctions.mustache index 713062254..8c2adb6d6 100644 --- a/src/main/resources/twilio-node/listInterfaceFunctions.mustache +++ b/src/main/resources/twilio-node/listInterfaceFunctions.mustache @@ -13,7 +13,7 @@ * @param { {{vendorExtensions.x-resource-name}}EachOptions } [params] - Options for request * @param { function } [callback] - Function to process each record */ - each(callback?: (item: {{instanceName}}, done: (err?: Error) => void) => void): void; + {{^hasRequiredParams}}each(callback?: (item: {{instanceName}}, done: (err?: Error) => void) => void): void;{{/hasRequiredParams}} each(params: {{vendorExtensions.x-resource-name}}EachOptions, callback?: (item: {{instanceName}}, done: (err?: Error) => void) => void): void; /** * Retrieve a single target page of {{instanceName}} records from the API. @@ -33,7 +33,7 @@ * @param { {{vendorExtensions.x-resource-name}}Options } [params] - Options for request * @param { function } [callback] - Callback to handle list of records */ - list(callback?: (error: Error | null, items: {{instanceName}}[]) => any): Promise<{{instanceName}}[]>; + {{^hasRequiredParams}}list(callback?: (error: Error | null, items: {{instanceName}}[]) => any): Promise<{{instanceName}}[]>;{{/hasRequiredParams}} list(params: {{vendorExtensions.x-resource-name}}Options, callback?: (error: Error | null, items: {{instanceName}}[]) => any): Promise<{{instanceName}}[]>; /** * Retrieve a single page of {{instanceName}} records from the API. @@ -46,5 +46,5 @@ * @param { {{vendorExtensions.x-resource-name}}PageOptions } [params] - Options for request * @param { function } [callback] - Callback to handle list of records */ - page(callback?: (error: Error | null, items: {{returnType}}) => any): Promise<{{returnType}}>; + {{^hasRequiredParams}}page(callback?: (error: Error | null, items: {{returnType}}) => any): Promise<{{returnType}}>;{{/hasRequiredParams}} page(params: {{vendorExtensions.x-resource-name}}PageOptions, callback?: (error: Error | null, items: {{returnType}}) => any): Promise<{{returnType}}>; diff --git a/src/main/resources/twilio-python/context.handlebars b/src/main/resources/twilio-python/context.handlebars index 1f52ea3ed..a3552b9a8 100644 --- a/src/main/resources/twilio-python/context.handlebars +++ b/src/main/resources/twilio-python/context.handlebars @@ -32,7 +32,7 @@ class {{apiName}}Context(InstanceContext): }) {{#allParams}}{{^isFormParam}}headers = values.of({'{{{baseName}}}': {{paramName}}, }){{/isFormParam}}{{/allParams}} - payload = self._version.update(method='{{vendorExtensions.x-http-method}}', uri=self._uri, data=data,{{#allParams}}{{#if isFormParam}}{{else}} headers=headers{{/if}}{{/allParams}}) + payload = self._version.update(method='{{vendorExtensions.x-http-method}}', uri=self._uri, data=data,{{#allParams}}{{#if isFormParam}}{{else}} headers=headers{{/if}}{{/allParams}} {{#vendorExtensions.x-auth-attributes.x-oauth}} ,is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}( self._version, @@ -52,8 +52,7 @@ class {{apiName}}Context(InstanceContext): '{{{baseName}}}': {{#if vendorExtensions.x-serialize}}{{vendorExtensions.x-serialize}}({{paramName}}{{#if isArray}}, lambda e: e){{else}}){{/if}}{{else}}{{paramName}}{{/if}},{{/isFormParam}}{{/allParams}} }) {{#allParams}}{{^isFormParam}}headers = values.of({'{{{baseName}}}': {{paramName}}, }){{/isFormParam}}{{/allParams}} - - payload = await self._version.update_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, data=data,{{#allParams}}{{#if isFormParam}}{{else}} headers=headers{{/if}}{{/allParams}}) + payload = await self._version.update_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, data=data,{{#allParams}}{{#if isFormParam}}{{else}} headers=headers{{/if}}{{/allParams}} {{#vendorExtensions.x-auth-attributes.x-oauth}} ,is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}( self._version, @@ -75,7 +74,7 @@ class {{apiName}}Context(InstanceContext): }) {{#allParams}}{{#if vendorExtensions.x-prefixed-collapsible-map}}data.update({{vendorExtensions.x-serialize}}({{paramName}}, '{{vendorExtensions.x-prefixed-collapsible-map}}')) {{/if}}{{/allParams}}{{/if}} - payload = self._version.fetch(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#if allParams}}params=data{{/if}}) + payload = self._version.fetch(method='{{vendorExtensions.x-http-method}}', uri=self._uri{{#if allParams}}, params=data{{/if}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}( self._version, @@ -98,7 +97,7 @@ class {{apiName}}Context(InstanceContext): }) {{#allParams}}{{#if vendorExtensions.x-prefixed-collapsible-map}}data.update({{vendorExtensions.x-serialize}}({{paramName}}, '{{vendorExtensions.x-prefixed-collapsible-map}}')) {{/if}}{{/allParams}}{{/if}} - payload = await self._version.fetch_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#if allParams}}params=data{{/if}}) + payload = await self._version.fetch_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri{{#if allParams}}, params=data{{/if}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}( self._version, @@ -117,7 +116,7 @@ class {{apiName}}Context(InstanceContext): """{{#if allParams}} headers = values.of({{#allParams}}{'{{{baseName}}}': {{paramName}}, }{{/allParams}}) {{/if}} - return self._version.delete(method='{{vendorExtensions.x-http-method}}', uri=self._uri,{{#if allParams}} headers=headers{{/if}}) + return self._version.delete(method='{{vendorExtensions.x-http-method}}', uri=self._uri{{#if allParams}}, headers=headers{{/if}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) async def {{vendorExtensions.x-name-lower}}_async(self{{#allParams}}, {{paramName}}: {{#if required}}{{{dataType}}}{{else}}Union[{{{dataType}}}, object]=values.unset{{/if}}{{/allParams}}) -> bool: """ @@ -129,7 +128,7 @@ class {{apiName}}Context(InstanceContext): """{{#if allParams}} headers = values.of({{#allParams}}{'{{{baseName}}}': {{paramName}}, }{{/allParams}}) {{/if}} - return await self._version.delete_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri,{{#if allParams}} headers=headers{{/if}}) + return await self._version.delete_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri{{#if allParams}}, headers=headers{{/if}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) {{/vendorExtensions.x-is-delete-operation}}{{#vendorExtensions.x-is-create-operation}} def {{vendorExtensions.x-name-lower}}(self{{#allParams}}, {{paramName}}: {{#if required}}{{{dataType}}}{{else}}Union[{{{dataType}}}, object]=values.unset{{/if}}{{/allParams}}) -> {{instanceName}}: """ @@ -143,7 +142,7 @@ class {{apiName}}Context(InstanceContext): '{{{baseName}}}': {{#if vendorExtensions.x-serialize}}{{vendorExtensions.x-serialize}}({{paramName}}{{#if isArray}}, lambda e: e){{else}}){{/if}}{{else}}{{paramName}}{{/if}},{{/allParams}} }) - payload = self._version.create(method='{{vendorExtensions.x-http-method}}', uri=self._uri, data=data) + payload = self._version.create(method='{{vendorExtensions.x-http-method}}', uri=self._uri, data=data{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}( self._version, @@ -163,7 +162,7 @@ class {{apiName}}Context(InstanceContext): '{{{baseName}}}': {{#if vendorExtensions.x-serialize}}{{vendorExtensions.x-serialize}}({{paramName}}{{#if isArray}}, lambda e: e){{else}}){{/if}}{{else}}{{paramName}}{{/if}},{{/allParams}} }) - payload = await self._version.create_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, data=data) + payload = await self._version.create_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, data=data{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}( self._version, diff --git a/src/main/resources/twilio-python/listOperations.handlebars b/src/main/resources/twilio-python/listOperations.handlebars index 92713c7ec..9eaa404fb 100644 --- a/src/main/resources/twilio-python/listOperations.handlebars +++ b/src/main/resources/twilio-python/listOperations.handlebars @@ -22,7 +22,7 @@ {{/queryParams}} }) {{/queryParams.0}} - payload = self._version.create(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#hasParams}}data=data,{{/hasParams}} headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}) + payload = self._version.create(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#hasParams}}data=data,{{/hasParams}} headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}(self._version, payload{{#listPathParams}}, {{paramName}}=self._solution['{{paramName}}']{{/listPathParams}}) @@ -48,7 +48,7 @@ {{/queryParams}} }) {{/queryParams.0}} - payload = await self._version.create_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#hasParams}}data=data,{{/hasParams}} headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}) + payload = await self._version.create_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#hasParams}}data=data,{{/hasParams}} headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}(self._version, payload{{#listPathParams}}, {{paramName}}=self._solution['{{paramName}}']{{/listPathParams}}) {{/vendorExtensions.x-is-create-operation}}{{^instancePath}}{{#vendorExtensions.x-is-fetch-operation}} @@ -69,7 +69,7 @@ {{/queryParams}} }) {{/queryParams.0}} - payload = self._version.fetch(method='{{vendorExtensions.x-http-method}}', uri=self._uri, headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}) + payload = self._version.fetch(method='{{vendorExtensions.x-http-method}}', uri=self._uri, headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}(self._version, payload{{#listPathParams}}, {{paramName}}=self._solution['{{paramName}}']{{/listPathParams}}) @@ -90,7 +90,7 @@ {{/queryParams}} }) {{/queryParams.0}} - payload = await self._version.fetch_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}) + payload = await self._version.fetch_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}(self._version, payload{{#listPathParams}}, {{paramName}}=self._solution['{{paramName}}']{{/listPathParams}}){{/vendorExtensions.x-is-fetch-operation}}{{#vendorExtensions.x-is-delete-operation}} def delete(self{{#allParams}}, {{paramName}}: {{#if required}}{{{dataType}}}{{else}}Union[{{{dataType}}}, object]=values.unset{{/if}}{{/allParams}}) -> bool: @@ -109,7 +109,7 @@ {{#queryParams}}'{{{baseName}}}': {{paramName}}, {{/queryParams}} }){{/queryParams.0}} - return self._version.delete(method='{{vendorExtensions.x-http-method}}', uri=self._uri, headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}) + return self._version.delete(method='{{vendorExtensions.x-http-method}}', uri=self._uri, headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) async def delete_async(self{{#allParams}}, {{paramName}}: {{#if required}}{{{dataType}}}{{else}}Union[{{{dataType}}}, object]=values.unset{{/if}}{{/allParams}}) -> bool: """ @@ -127,7 +127,7 @@ {{#queryParams}}'{{{baseName}}}': {{paramName}}, {{/queryParams}} }){{/queryParams.0}} - return await self._version.delete_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}){{/vendorExtensions.x-is-delete-operation}}{{#vendorExtensions.x-is-update-operation}} + return await self._version.delete_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}){{/vendorExtensions.x-is-delete-operation}}{{#vendorExtensions.x-is-update-operation}} def update(self{{#allParams}}, {{paramName}}: {{#if required}}{{{dataType}}}{{else}}Union[{{{dataType}}}, object]=values.unset{{/if}}{{/allParams}}) -> {{instanceName}}: """ @@ -151,7 +151,7 @@ {{/queryParams}} }) {{/queryParams.0}} - payload = self._version.update(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#hasParams}}data=data,{{/hasParams}} headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}) + payload = self._version.update(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#hasParams}}data=data,{{/hasParams}} headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}(self._version, payload{{#listPathParams}}, {{paramName}}=self._solution['{{paramName}}']{{/listPathParams}}) @@ -177,7 +177,7 @@ {{/queryParams}} }) {{/queryParams.0}} - payload = await self._version.update_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#hasParams}}data=data,{{/hasParams}} headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}) + payload = await self._version.update_async(method='{{vendorExtensions.x-http-method}}', uri=self._uri, {{#hasParams}}data=data,{{/hasParams}} headers=headers{{#queryParams.0}}, params=params{{/queryParams.0}}{{#vendorExtensions.x-auth-attributes.x-oauth}}, is_oauth=True{{/vendorExtensions.x-auth-attributes.x-oauth}}) return {{instanceName}}(self._version, payload{{#listPathParams}}, {{paramName}}=self._solution['{{paramName}}']{{/listPathParams}}){{/vendorExtensions.x-is-update-operation}}{{/instancePath}}{{#vendorExtensions.x-is-read-operation}} def stream(self, {{#allParams}} diff --git a/src/main/resources/twilio-python/modelClasses.handlebars b/src/main/resources/twilio-python/modelClasses.handlebars index b4d34154a..210863b2a 100644 --- a/src/main/resources/twilio-python/modelClasses.handlebars +++ b/src/main/resources/twilio-python/modelClasses.handlebars @@ -4,7 +4,7 @@ :ivar {{name}}: {{{description}}}{{/vars}} """ - def __init__(self, payload: Dict[str, Any]{{#instancePathParams}}, {{paramName}}: {{#if vendorExtensions.x-is-parent-param}}{{{contentType}}}{{else}}Optional[{{{contentType}}}] = None{{/if}}{{/instancePathParams}}): + def __init__(self, payload: Dict[str, Any]): {{#vars}} self.{{name}}: Optional[{{{dataType}}}] = {{#if vendorExtensions.x-deserialize}}{{vendorExtensions.x-deserialize}}(payload.get("{{{name}}}")){{else}}payload.get("{{{name}}}"){{/if}}{{/vars}} diff --git a/src/test/java/com/twilio/oai/TwilioGeneratorTest.java b/src/test/java/com/twilio/oai/TwilioGeneratorTest.java index a68a61691..3d82c9df4 100644 --- a/src/test/java/com/twilio/oai/TwilioGeneratorTest.java +++ b/src/test/java/com/twilio/oai/TwilioGeneratorTest.java @@ -28,7 +28,15 @@ public class TwilioGeneratorTest { @Parameterized.Parameters public static Collection generators() { - return Arrays.asList(Generator.TWILIO_PYTHON); + return Arrays.asList(Generator.TWILIO_PYTHON, + Generator.TWILIO_NODE, + Generator.TWILIO_GO, + Generator.TWILIO_CSHARP, + Generator.TWILIO_RUBY, + Generator.TWILIO_JAVA, + Generator.TWILIO_PHP, + Generator.TWILIO_TERRAFORM + ); } private final Generator generator; @@ -41,9 +49,6 @@ public static void setUp() { @Test public void launchGenerator() { final String pathname = "examples/spec/twilio_api_v2010.yaml"; -// final String pathname = "/Users/stiwari/di/github/twilio-oai/spec/json/twilio_accounts_v1.json"; -// final String pathname = "/Users/stiwari/di/codehq/open-api-transpiler/twilio_api_v2010.json"; -// final String pathname = "/Users/stiwari/di/codehq/open-api-transpiler/json/twilio_assistants_v1.json"; File filesList[] ; File directoryPath = new File(pathname); if (directoryPath.isDirectory()) {