Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
WIP initial commit
  • Loading branch information
ahmednfwela committed Jan 1, 2023
commit ffeed66b5433bcaccad7c1d66eaa6da921785272
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class DartDioClientCodegen extends AbstractDartCodegen {
private final Logger LOGGER = LoggerFactory.getLogger(DartDioClientCodegen.class);

public static final String DATE_LIBRARY = "dateLibrary";
public static final String NETWORKING_LIBRARY = "networkingLibrary";
public static final String DATE_LIBRARY_CORE = "core";
public static final String DATE_LIBRARY_TIME_MACHINE = "timemachine";
public static final String DATE_LIBRARY_DEFAULT = DATE_LIBRARY_CORE;
Expand All @@ -66,14 +67,21 @@ public class DartDioClientCodegen extends AbstractDartCodegen {
public static final String SERIALIZATION_LIBRARY_JSON_SERIALIZABLE = "json_serializable";
public static final String SERIALIZATION_LIBRARY_DEFAULT = SERIALIZATION_LIBRARY_BUILT_VALUE;

public static final String NETWORKING_LIBRARY_DIO = "dio";
public static final String NETWORKING_LIBRARY_HTTP = "http";
public static final String NETWORKING_LIBRARY_DEFAULT = NETWORKING_LIBRARY_DIO;

private static final String DIO_IMPORT = "package:dio/dio.dart";
private static final String HTTP_IMPORT = "package:http/http.dart";
public static final String FINAL_PROPERTIES = "finalProperties";
public static final String FINAL_PROPERTIES_DEFAULT_VALUE = "true";

private static final String CLIENT_NAME = "clientName";

private String dateLibrary;

private String networkingLibrary;

private String clientName;

private TemplateManager templateManager;
Expand Down Expand Up @@ -102,13 +110,25 @@ public DartDioClientCodegen() {
embeddedTemplateDir = "dart/libraries/dio";
this.setTemplateDir(embeddedTemplateDir);

//SERIALIZATION_LIBRARY options
supportedLibraries.put(SERIALIZATION_LIBRARY_BUILT_VALUE, "[DEFAULT] built_value");
supportedLibraries.put(SERIALIZATION_LIBRARY_JSON_SERIALIZABLE, "[BETA] json_serializable");
final CliOption serializationLibrary = CliOption.newString(CodegenConstants.SERIALIZATION_LIBRARY, "Specify serialization library");
serializationLibrary.setEnum(supportedLibraries);
serializationLibrary.setDefault(SERIALIZATION_LIBRARY_DEFAULT);
cliOptions.add(serializationLibrary);

//NETWORKING_LIBRARY options
final CliOption networkingOption = CliOption.newString(NETWORKING_LIBRARY, "Specify networking library");
networkingOption.setDefault(NETWORKING_LIBRARY_DEFAULT);

final Map<String, String> networkingOptions = new HashMap<>();
networkingOptions.put(NETWORKING_LIBRARY_DIO, "[DEFAULT] Dio");
networkingOptions.put(NETWORKING_LIBRARY_HTTP, "[BETA] http");
networkingOption.setEnum(networkingOptions);
cliOptions.add(networkingOption);

//FINAL_PROPERTIES option
final CliOption finalProperties = CliOption.newBoolean(FINAL_PROPERTIES, "Whether properties are marked as final when using Json Serializable for serialization");
finalProperties.setDefault("true");
cliOptions.add(finalProperties);
Expand All @@ -132,6 +152,14 @@ public void setDateLibrary(String library) {
this.dateLibrary = library;
}

public String getNetworkingLibrary() {
return networkingLibrary;
}

public void setNetworkingLibrary(String networkingLibrary) {
this.networkingLibrary = networkingLibrary;
}

public String getClientName() {
return clientName;
}
Expand All @@ -147,7 +175,7 @@ public String getName() {

@Override
public String getHelp() {
return "Generates a Dart Dio client library with null-safety.";
return "Generates a Dart client library with null-safety.";
}

@Override
Expand All @@ -174,6 +202,12 @@ public void processOpts() {
}
setDateLibrary(additionalProperties.get(DATE_LIBRARY).toString());

if (!additionalProperties.containsKey(NETWORKING_LIBRARY)) {
additionalProperties.put(NETWORKING_LIBRARY, NETWORKING_LIBRARY_DEFAULT);
LOGGER.debug("Networking library not set, using default {}", NETWORKING_LIBRARY_DEFAULT);
}
setNetworkingLibrary(additionalProperties.get(NETWORKING_LIBRARY).toString());

if (!additionalProperties.containsKey(FINAL_PROPERTIES)) {
additionalProperties.put(FINAL_PROPERTIES, Boolean.parseBoolean(FINAL_PROPERTIES_DEFAULT_VALUE));
LOGGER.debug("finalProperties not set, using default {}", FINAL_PROPERTIES_DEFAULT_VALUE);
Expand Down Expand Up @@ -208,6 +242,50 @@ public void processOpts() {

configureSerializationLibrary(srcFolder);
configureDateLibrary(srcFolder);
configureNetworkingLibrary(srcFolder);
}

private void configureNetworkingLibrary(String srcFolder) {
switch (networkingLibrary) {
case NETWORKING_LIBRARY_DIO:
additionalProperties.put("useDio", "true");
configureNetworkingLibraryDio(srcFolder);
break;
case NETWORKING_LIBRARY_HTTP:
additionalProperties.put("useHttp", "true");
configureNetworkingLibraryHttp(srcFolder);
break;
default:
break;
}

TemplateManagerOptions templateManagerOptions = new TemplateManagerOptions(isEnableMinimalUpdate(), isSkipOverwrite());
TemplatePathLocator commonTemplateLocator = new CommonTemplateContentLocator();
TemplatePathLocator generatorTemplateLocator = new GeneratorTemplateContentLocator(this);
templateManager = new TemplateManager(
templateManagerOptions,
getTemplatingEngine(),
new TemplatePathLocator[]{generatorTemplateLocator, commonTemplateLocator}
);
// A lambda which allows for easy includes of networking library specific
// templates without having to change the main template files.
additionalProperties.put("includeNetworkingLibraryTemplate", (Mustache.Lambda) (fragment, writer) -> {
MustacheEngineAdapter engine = ((MustacheEngineAdapter) getTemplatingEngine());
String templateFile = "networking/" + library + "/" + fragment.execute() + ".mustache";
Template tmpl = engine.getCompiler()
.withLoader(name -> engine.findTemplate(templateManager, name))
.defaultValue("")
.compile(templateManager.getFullTemplateContents(templateFile));

fragment.executeTemplate(tmpl, writer);
});
}

private void configureNetworkingLibraryDio(String srcFolder) {
imports.put("MultipartFile", DIO_IMPORT);
}
private void configureNetworkingLibraryHttp(String srcFolder) {
imports.put("MultipartFile", HTTP_IMPORT);
}

private void configureSerializationLibrary(String srcFolder) {
Expand Down Expand Up @@ -265,7 +343,6 @@ private void configureSerializationLibraryBuiltValue(String srcFolder) {
imports.put("BuiltMap", "package:built_collection/built_collection.dart");
imports.put("JsonObject", "package:built_value/json_object.dart");
imports.put("Uint8List", "dart:typed_data");
imports.put("MultipartFile", DIO_IMPORT);
}

private void configureSerializationLibraryJsonSerializable(String srcFolder) {
Expand All @@ -277,7 +354,6 @@ private void configureSerializationLibraryJsonSerializable(String srcFolder) {
// just the binary / file handling
languageSpecificPrimitives.add("Object");
imports.put("Uint8List", "dart:typed_data");
imports.put("MultipartFile", DIO_IMPORT);
}

private void configureDateLibrary(String srcFolder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# {{pubName}} (EXPERIMENTAL)
# {{pubName}}
{{#appDescriptionWithNewLines}}
{{{.}}}
{{/appDescriptionWithNewLines}}
Expand All @@ -20,7 +20,12 @@ For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
## Requirements

* Dart 2.12.0 or later OR Flutter 1.26.0 or later
{{#useDio}}
* Dio 4.0.0+
{{/useDio}}
{{#useHttp}}
* http 0.13.5+
{{/useHttp}}
{{#useDateLibTimeMachine}}
* timemachine option currently **DOES NOT** support sound null-safety and may not work
{{/useDateLibTimeMachine}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,146 +1 @@
{{>header}}
import 'dart:async';

{{#includeLibraryTemplate}}api/imports{{/includeLibraryTemplate}}
import 'package:dio/dio.dart';

{{#operations}}
{{#imports}}import '{{.}}';
{{/imports}}

class {{classname}} {

final Dio _dio;

{{#includeLibraryTemplate}}api/constructor{{/includeLibraryTemplate}}

{{#operation}}
/// {{summary}}{{^summary}}{{nickname}}{{/summary}}
/// {{notes}}
///
/// Parameters:
{{#allParams}}
/// * [{{paramName}}] {{#description}}- {{{.}}}{{/description}}
{{/allParams}}
/// * [cancelToken] - A [CancelToken] that can be used to cancel the operation
/// * [headers] - Can be used to add additional headers to the request
/// * [extras] - Can be used to add flags to the request
/// * [validateStatus] - A [ValidateStatus] callback that can be used to determine request success based on the HTTP status of the response
/// * [onSendProgress] - A [ProgressCallback] that can be used to get the send progress
/// * [onReceiveProgress] - A [ProgressCallback] that can be used to get the receive progress
///
/// Returns a [Future]{{#returnType}} containing a [Response] with a [{{{.}}}] as data{{/returnType}}
/// Throws [DioError] if API call or serialization fails
{{#externalDocs}}
/// {{description}}
/// Also see [{{summary}} Documentation]({{url}})
{{/externalDocs}}
{{#isDeprecated}}
@Deprecated('This operation has been deprecated')
{{/isDeprecated}}
Future<Response<{{{returnType}}}{{^returnType}}void{{/returnType}}>> {{nickname}}({ {{#allParams}}{{#isPathParam}}
required {{{dataType}}} {{paramName}},{{/isPathParam}}{{#isQueryParam}}
{{#required}}{{^isNullable}}{{^defaultValue}}required {{/defaultValue}}{{/isNullable}}{{/required}}{{{dataType}}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^required}}?{{/required}} {{paramName}}{{^isContainer}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}{{/isContainer}},{{/isQueryParam}}{{#isHeaderParam}}
{{#required}}{{^isNullable}}{{^defaultValue}}required {{/defaultValue}}{{/isNullable}}{{/required}}{{{dataType}}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^required}}?{{/required}} {{paramName}}{{^isContainer}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}{{/isContainer}},{{/isHeaderParam}}{{#isBodyParam}}
{{#required}}{{^isNullable}}required {{/isNullable}}{{/required}}{{{dataType}}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^required}}?{{/required}} {{paramName}},{{/isBodyParam}}{{#isFormParam}}
{{#required}}{{^isNullable}}required {{/isNullable}}{{/required}}{{{dataType}}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^required}}?{{/required}} {{paramName}},{{/isFormParam}}{{/allParams}}
CancelToken? cancelToken,
Map<String, dynamic>? headers,
Map<String, dynamic>? extra,
ValidateStatus? validateStatus,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'{{{path}}}'{{#pathParams}}.replaceAll('{' r'{{{baseName}}}' '}', {{{paramName}}}.toString()){{/pathParams}};
final _options = Options(
method: r'{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}}',
{{#isResponseFile}}
responseType: ResponseType.bytes,
{{/isResponseFile}}
headers: <String, dynamic>{
{{#httpUserAgent}}
r'User-Agent': r'{{{.}}}',
{{/httpUserAgent}}
{{#headerParams}}
{{^required}}{{^isNullable}}if ({{{paramName}}} != null) {{/isNullable}}{{/required}}r'{{baseName}}': {{paramName}},
{{/headerParams}}
...?headers,
},
extra: <String, dynamic>{
'secure': <Map<String, String>>[{{^hasAuthMethods}}],{{/hasAuthMethods}}{{#hasAuthMethods}}
{{#authMethods}}{
'type': '{{type}}',{{#scheme}}
'scheme': '{{.}}',{{/scheme}}
'name': '{{name}}',{{#isApiKey}}
'keyName': '{{keyParamName}}',
'where': '{{#isKeyInQuery}}query{{/isKeyInQuery}}{{#isKeyInHeader}}header{{/isKeyInHeader}}',{{/isApiKey}}
},{{/authMethods}}
],{{/hasAuthMethods}}
...?extra,
},{{#hasConsumes}}
contentType: '{{#prioritizedContentTypes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/prioritizedContentTypes}}',{{/hasConsumes}}
validateStatus: validateStatus,
);{{#hasQueryParams}}

final _queryParameters = <String, dynamic>{
{{#queryParams}}
{{^required}}{{^isNullable}}if ({{{paramName}}} != null) {{/isNullable}}{{/required}}r'{{baseName}}': {{#includeLibraryTemplate}}api/query_param{{/includeLibraryTemplate}},
{{/queryParams}}
};{{/hasQueryParams}}{{#hasBodyOrFormParams}}

dynamic _bodyData;

try {
{{#includeLibraryTemplate}}api/serialize{{/includeLibraryTemplate}}
} catch(error, stackTrace) {
throw DioError(
requestOptions: _options.compose(
_dio.options,
_path,{{#hasQueryParams}}
queryParameters: _queryParameters,{{/hasQueryParams}}
),
type: DioErrorType.other,
error: error,
)..stackTrace = stackTrace;
}{{/hasBodyOrFormParams}}

final _response = await _dio.request<Object>(
_path,{{#hasBodyOrFormParams}}
data: _bodyData,{{/hasBodyOrFormParams}}
options: _options,{{#hasQueryParams}}
queryParameters: _queryParameters,{{/hasQueryParams}}
cancelToken: cancelToken,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
{{#returnType}}

{{{returnType}}} _responseData;

try {
{{#includeLibraryTemplate}}api/deserialize{{/includeLibraryTemplate}}
} catch (error, stackTrace) {
throw DioError(
requestOptions: _response.requestOptions,
response: _response,
type: DioErrorType.other,
error: error,
)..stackTrace = stackTrace;
}

return Response<{{{returnType}}}>(
data: _responseData,
headers: _response.headers,
isRedirect: _response.isRedirect,
requestOptions: _response.requestOptions,
redirects: _response.redirects,
statusCode: _response.statusCode,
statusMessage: _response.statusMessage,
extra: _response.extra,
);{{/returnType}}{{^returnType}}
return _response;{{/returnType}}
}

{{/operation}}
}
{{/operations}}
{{#includeNetworkingLibraryTemplate}}api{{/includeNetworkingLibraryTemplate}}
Loading