Skip to content

Commit

Permalink
Add auto-generated doc to Swift4 generator (#2666)
Browse files Browse the repository at this point in the history
* add auto-generated doc to swift4 generators

* fix rxswift sample code

* fix object initialize

* fix boolean value

* fix link to object

* fix void

* fix url initialize

* update all swift samples

* fix indentation
  • Loading branch information
wing328 authored Apr 16, 2019
1 parent 84f3fc0 commit 4b84821
Show file tree
Hide file tree
Showing 235 changed files with 12,198 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public class Swift4Codegen extends DefaultCodegen implements CodegenConfig {
protected String[] responseAs = new String[0];
protected String sourceFolder = "Classes" + File.separator + "OpenAPIs";
protected HashSet objcReservedWords;
protected String apiDocPath = "docs/";
protected String modelDocPath = "docs/";

/**
* Constructor for the swift4 language codegen module.
Expand All @@ -79,6 +81,8 @@ public Swift4Codegen() {
embeddedTemplateDir = templateDir = "swift4";
apiPackage = File.separator + "APIs";
modelPackage = File.separator + "Models";
modelDocTemplateFiles.put("model_doc.mustache", ".md");
apiDocTemplateFiles.put("api_doc.mustache", ".md");

languageSpecificPrimitives = new HashSet<>(
Arrays.asList(
Expand All @@ -90,7 +94,12 @@ public Swift4Codegen() {
"Bool",
"Void",
"String",
"URL",
"Data",
"Date",
"Character",
"UUID",
"URL",
"AnyObject",
"Any")
);
Expand Down Expand Up @@ -365,6 +374,10 @@ public void processOpts() {

setLenientTypeCast(convertPropertyToBooleanAndWriteBack(LENIENT_TYPE_CAST));

// make api and model doc path available in mustache template
additionalProperties.put("apiDocPath", apiDocPath);
additionalProperties.put("modelDocPath", modelDocPath);

supportingFiles.add(new SupportingFile("Podspec.mustache",
"",
projectName + ".podspec"));
Expand Down Expand Up @@ -404,6 +417,9 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("gitignore.mustache",
"",
".gitignore"));
supportingFiles.add(new SupportingFile("README.mustache",
"",
"README.md"));

}

Expand Down Expand Up @@ -565,6 +581,26 @@ public String toApiName(String name) {
return camelize(name) + "API";
}

@Override
public String apiDocFileFolder() {
return (outputFolder + "/" + apiDocPath).replace("/", File.separator);
}

@Override
public String modelDocFileFolder() {
return (outputFolder + "/" + modelDocPath).replace("/", File.separator);
}

@Override
public String toModelDocFilename(String name) {
return toModelName(name);
}

@Override
public String toApiDocFilename(String name) {
return toApiName(name);
}

@Override
public String toOperationId(String operationId) {
operationId = camelize(sanitizeName(operationId), true);
Expand Down Expand Up @@ -880,4 +916,116 @@ public void postProcessFile(File file, String fileType) {
}
}
}

@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
Map<String, Object> objectMap = (Map<String, Object>) objs.get("operations");

HashMap<String, CodegenModel> modelMaps = new HashMap<String, CodegenModel>();
for (Object o : allModels) {
HashMap<String, Object> h = (HashMap<String, Object>) o;
CodegenModel m = (CodegenModel) h.get("model");
modelMaps.put(m.classname, m);
}

List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
for (CodegenOperation operation : operations) {
for (CodegenParameter cp : operation.allParams) {
cp.vendorExtensions.put("x-swift-example", constructExampleCode(cp, modelMaps));
}
}
return objs;
}

public String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps) {
if (codegenParameter.isListContainer) { // array
return "[" + constructExampleCode(codegenParameter.items, modelMaps) + "]";
} else if (codegenParameter.isMapContainer) { // TODO: map, file type
return "\"TODO\"";
} else if (languageSpecificPrimitives.contains(codegenParameter.dataType)) { // primitive type
if ("String".equals(codegenParameter.dataType) || "Character".equals(codegenParameter.dataType)) {
if (StringUtils.isEmpty(codegenParameter.example)) {
return "\"" + codegenParameter.example + "\"";
} else {
return "\"" + codegenParameter.paramName + "_example\"";
}
} else if ("Bool".equals(codegenParameter.dataType)) { // boolean
if (Boolean.TRUE.equals(codegenParameter.example)) {
return "true";
} else {
return "false";
}
} else if ("URL".equals(codegenParameter.dataType)) { // URL
return "URL(string: \"https://example.com\")!";
} else if ("Date".equals(codegenParameter.dataType)) { // date
return "Date()";
} else { // numeric
if (StringUtils.isEmpty(codegenParameter.example)) {
return codegenParameter.example;
} else {
return "987";
}
}
} else { // model
// look up the model
if (modelMaps.containsKey(codegenParameter.dataType)) {
return constructExampleCode(modelMaps.get(codegenParameter.dataType), modelMaps);
} else {
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenParameter.dataType);
return "TODO";
}
}
}

public String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps) {
if (codegenProperty.isListContainer) { // array
return "[" + constructExampleCode(codegenProperty.items, modelMaps) + "]";
} else if (codegenProperty.isMapContainer) { // TODO: map, file type
return "\"TODO\"";
} else if (languageSpecificPrimitives.contains(codegenProperty.dataType)) { // primitive type
if ("String".equals(codegenProperty.dataType) || "Character".equals(codegenProperty.dataType)) {
if (StringUtils.isEmpty(codegenProperty.example)) {
return "\"" + codegenProperty.example + "\"";
} else {
return "\"" + codegenProperty.name + "_example\"";
}
} else if ("Bool".equals(codegenProperty.dataType)) { // boolean
if (Boolean.TRUE.equals(codegenProperty.example)) {
return "true";
} else {
return "false";
}
} else if ("URL".equals(codegenProperty.dataType)) { // URL
return "URL(string: \"https://example.com\")!";
} else if ("Date".equals(codegenProperty.dataType)) { // date
return "Date()";
} else { // numeric
if (StringUtils.isEmpty(codegenProperty.example)) {
return codegenProperty.example;
} else {
return "123";
}
}
} else {
// look up the model
if (modelMaps.containsKey(codegenProperty.dataType)) {
return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps);
} else {
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenProperty.dataType);
return "\"TODO\"";
}
}
}

public String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps) {
String example;
example = codegenModel.name + "(";
List<String> propertyExamples = new ArrayList<>();
for (CodegenProperty codegenProperty : codegenModel.vars) {
propertyExamples.add(codegenProperty.name + ": " + constructExampleCode(codegenProperty, modelMaps));
}
example += StringUtils.join(propertyExamples, ", ");
example += ")";
return example;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Swift4 API client for {{packageName}}
# Swift4 API client for {{{projectName}}}

{{#appDescription}}
{{{appDescription}}}
Expand All @@ -18,10 +18,14 @@ For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}

## Installation
Put the package under your project folder and add the following in import:
```
"./{{packageName}}"
```

### Carthage

Run `carthage update`

### CocoaPods

Run `pod install`

## Documentation for API Endpoints

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# {{classname}}{{#description}}
{{description}}{{/description}}

All URIs are relative to *{{{basePath}}}*

Method | HTTP request | Description
------------- | ------------- | -------------
{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
{{/operation}}{{/operations}}

{{#operations}}
{{#operation}}
# **{{{operationId}}}**
```swift
{{^usePromiseKit}}
{{^useRxSwift}}
open class func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}{{#hasParams}}, {{/hasParams}}completion: @escaping (_ data: {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}?, _ error: Error?) -> Void)
{{/useRxSwift}}
{{/usePromiseKit}}
{{#usePromiseKit}}
open class func {{operationId}}({{#allParams}} {{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) -> Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>
{{/usePromiseKit}}
{{#useRxSwift}}
open class func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) -> Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>
{{/useRxSwift}}
```

{{{summary}}}{{#notes}}

{{{notes}}}{{/notes}}

### Example
```swift
// The following code samples are still beta. For any issue, please report via http://github.com/OpenAPITools/openapi-generator/issues/new
import {{{projectName}}}

{{#allParams}}let {{paramName}} = {{{vendorExtensions.x-swift-example}}} // {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}}
{{/allParams}}

{{^usePromiseKit}}
{{^useRxSwift}}
{{#summary}}
// {{{.}}}
{{/summary}}
{{classname}}.{{{operationId}}}({{#allParams}}{{paramName}}: {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) { (response, error) in
guard error == nil else {
print(error)
return
}

if (response) {
dump(response)
}
}
{{/useRxSwift}}
{{/usePromiseKit}}
{{#usePromiseKit}}
{{#summary}}
// {{{.}}}
{{/summary}}
{{classname}}.{{{operationId}}}({{#allParams}}{{paramName}}: {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}).then {
// when the promise is fulfilled
}.always {
// regardless of whether the promise is fulfilled, or rejected
}.catch { errorType in
// when the promise is rejected
}
{{/usePromiseKit}}
{{#useRxSwift}}
// TODO RxSwift sample code not yet implemented. To contribute, please open a ticket via http://github.com/OpenAPITools/openapi-generator/issues/new
{{/useRxSwift}}
```

### Parameters
{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}}
{{#allParams}} **{{paramName}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{dataType}}**]({{baseType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}}
{{/allParams}}

### Return type

{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}Void (empty response body){{/returnType}}

### Authorization

{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^-last}}, {{/-last}}{{/authMethods}}

### HTTP request headers

- **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}}
- **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}}

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

{{/operation}}
{{/operations}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{{#models}}{{#model}}# {{classname}}

## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
{{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{{dataType}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isContainer}}[**{{dataType}}**]({{complexType}}.md){{/isContainer}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}}
{{/vars}}

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

{{/model}}{{/models}}
Loading

0 comments on commit 4b84821

Please sign in to comment.