Browse Source

dynamite,nextcloud: Refactor data conversion

pull/131/head
jld3103 2 years ago
parent
commit
7bbfeed5c5
No known key found for this signature in database
GPG Key ID: 9062417B9E8EB7B3
  1. 6
      packages/dynamite/lib/dynamite.dart
  2. 227
      packages/dynamite/lib/src/openapi_builder.dart
  3. 26
      packages/dynamite/lib/src/type_result/base.dart
  4. 22
      packages/dynamite/lib/src/type_result/enum.dart
  5. 22
      packages/dynamite/lib/src/type_result/list.dart
  6. 22
      packages/dynamite/lib/src/type_result/map.dart
  7. 19
      packages/dynamite/lib/src/type_result/object.dart
  8. 15
      packages/dynamite/lib/src/type_result/type_result.dart
  9. 1081
      packages/nextcloud/lib/src/nextcloud.openapi.dart

6
packages/dynamite/lib/dynamite.dart

@ -13,3 +13,9 @@ import 'package:dynamite/src/models/tag.dart';
import 'package:path/path.dart' as p;
part 'src/openapi_builder.dart';
part 'src/type_result/base.dart';
part 'src/type_result/enum.dart';
part 'src/type_result/list.dart';
part 'src/type_result/map.dart';
part 'src/type_result/object.dart';
part 'src/type_result/type_result.dart';

227
packages/dynamite/lib/src/openapi_builder.dart

@ -302,14 +302,14 @@ class OpenAPIBuilder implements Builder {
}
}
TypeResolveResult resolveType(
TypeResult resolveType(
final String identifier,
final Schema schema, {
final bool ignoreEnum = false,
final Map<String, String>? extraJsonSerializableValues,
final Map<String, Map<String, String>>? extraJsonKeyValues,
}) {
TypeResolveResult? result;
TypeResult? result;
if (schema.ref != null) {
final name = schema.ref!.split('/').last;
result = resolveType(
@ -341,8 +341,8 @@ class OpenAPIBuilder implements Builder {
(final b) {
final fields = <String, String>{};
for (final result in results) {
final dartName = _toDartName(result.typeName);
fields[result.typeName] = _toFieldName(dartName, result.typeName);
final dartName = _toDartName(result.name);
fields[result.name] = _toFieldName(dartName, result.name);
}
b
@ -361,8 +361,8 @@ class OpenAPIBuilder implements Builder {
(final b) {
final s = schema.ofs![results.indexOf(result)];
b
..name = fields[result.typeName]!
..type = refer(_makeNullable(result.typeName, true))
..name = fields[result.name]!
..type = refer(_makeNullable(result.name, true))
..modifier = FieldModifier.final$
..docs.addAll([
if (s.description != null && s.description!.isNotEmpty) ...[
@ -387,7 +387,7 @@ class OpenAPIBuilder implements Builder {
for (final result in results) ...[
Parameter(
(final b) => b
..name = fields[result.typeName]!
..name = fields[result.name]!
..toThis = true
..named = true,
),
@ -409,9 +409,9 @@ class OpenAPIBuilder implements Builder {
..body = Code(
<String>[
for (final result in results) ...[
'${result.typeName}? ${fields[result.typeName]!};',
'${result.name}? ${fields[result.name]!};',
'try {',
'${fields[result.typeName]!} = ${_deserializeFunctionForType('data', result)};',
'${fields[result.name]!} = ${result.deserialize('data')};',
'} catch (_) {',
'}',
],
@ -424,7 +424,7 @@ class OpenAPIBuilder implements Builder {
'return $identifier(',
'data,',
for (final result in results) ...[
'${fields[result.typeName]!}: ${fields[result.typeName]!},',
'${fields[result.name]!}: ${fields[result.name]!},',
],
');',
].join(),
@ -446,28 +446,25 @@ class OpenAPIBuilder implements Builder {
);
}
result = TypeResolveResult(
identifier,
isBaseType: false,
);
result = TypeResultObject(identifier);
} else {
switch (schema.type) {
case 'boolean':
result = TypeResolveResult('bool');
result = TypeResultBase('bool');
break;
case 'integer':
result = TypeResolveResult('int');
result = TypeResultBase('int');
break;
case 'number':
result = TypeResolveResult('num');
result = TypeResultBase('num');
break;
case 'string':
switch (schema.format) {
case 'binary':
result = TypeResolveResult('Uint8List');
result = TypeResultBase('Uint8List');
break;
case null:
result = TypeResolveResult(
result = TypeResultBase(
'String',
);
break;
@ -480,30 +477,26 @@ class OpenAPIBuilder implements Builder {
schema.items!,
extraJsonSerializableValues: extraJsonSerializableValues,
);
result = TypeResolveResult(
'List<${subResult.typeName}>',
isBaseType: false,
isList: true,
subType: subResult,
result = TypeResultList(
'List<${subResult.name}>',
subResult,
);
} else {
result = TypeResolveResult(
result = TypeResultList(
'List',
isBaseType: false,
isList: true,
TypeResultBase('dynamic'),
);
}
break;
case 'object':
if (schema.properties == null) {
result = TypeResolveResult('dynamic');
result = TypeResultBase('dynamic');
break;
}
if (schema.properties!.isEmpty) {
result = TypeResolveResult(
result = TypeResultMap(
'Map<String, dynamic>',
isBaseType: false,
isMap: true,
TypeResultBase('dynamic'),
);
break;
}
@ -590,7 +583,7 @@ class OpenAPIBuilder implements Builder {
..name = _toDartName(propertyName)
..type = refer(
_makeNullable(
result.typeName,
result.name,
!(schema.required ?? []).contains(propertyName),
),
)
@ -628,10 +621,7 @@ class OpenAPIBuilder implements Builder {
).accept(emitter).toString(),
);
}
result = TypeResolveResult(
identifier,
isBaseType: false,
);
result = TypeResultObject(identifier);
break;
}
}
@ -662,7 +652,7 @@ class OpenAPIBuilder implements Builder {
Field(
(final b) => b
..name = 'value'
..type = refer(result!.typeName)
..type = refer(result!.name)
..modifier = FieldModifier.final$,
),
)
@ -679,10 +669,10 @@ class OpenAPIBuilder implements Builder {
b
..name = _toDartName(value.toString())
..arguments.add(
refer(_valueToEscapedValue(result.typeName, value)),
refer(_valueToEscapedValue(result.name, value)),
);
if (_toDartName(value.toString()) != value.toString()) {
if (result.typeName != 'String' && result.typeName != 'int') {
if (result.name != 'String' && result.name != 'int') {
throw Exception(
'Sorry enum values are a bit broken. '
'See https://github.com/google/json_serializable.dart/issues/616. '
@ -691,7 +681,7 @@ class OpenAPIBuilder implements Builder {
}
b.annotations.add(
refer('JsonValue').call([
refer(_valueToEscapedValue(result.typeName, value.toString())),
refer(_valueToEscapedValue(result.name, value.toString())),
]),
);
}
@ -709,14 +699,14 @@ class OpenAPIBuilder implements Builder {
Parameter(
(final b) => b
..name = 'value'
..type = refer(result!.typeName),
..type = refer(result!.name),
),
)
..body = Code(
[
'switch (value) {',
for (final value in schema.enum_!) ...[
'case ${_valueToEscapedValue(result!.typeName, value)}:',
'case ${_valueToEscapedValue(result!.name, value)}:',
'return $identifier.${_toDartName(value.toString())};',
],
'default:',
@ -729,12 +719,7 @@ class OpenAPIBuilder implements Builder {
).accept(emitter).toString(),
);
}
result = TypeResolveResult(
identifier,
isBaseType: false,
isEnum: true,
subType: result,
);
result = TypeResultEnum(identifier, result);
}
return result;
@ -1012,12 +997,12 @@ class OpenAPIBuilder implements Builder {
parameter.schema!.type!,
parameter.schema!,
);
b.defaultTo = Code(_valueToEscapedValue(result.typeName, value));
b.defaultTo = Code(_valueToEscapedValue(result.name, value));
}
b.type = refer(
_makeNullable(
result.typeName,
result.name,
nullable,
),
);
@ -1029,21 +1014,21 @@ class OpenAPIBuilder implements Builder {
if (nullable) {
code.write('if (${_toDartName(parameter.name)} != null) {');
}
final enumValueGetter = result.isEnum ? '.value' : '';
final value = result.encode(result.serialize(_toDartName(parameter.name)));
switch (parameter.in_) {
case 'path':
code.write(
"path = path.replaceAll('{${parameter.name}}', Uri.encodeQueryComponent(${_toDartName(parameter.name)}$enumValueGetter.toString()));",
"path = path.replaceAll('{${parameter.name}}', Uri.encodeQueryComponent($value));",
);
break;
case 'query':
code.write(
"queryParameters['${parameter.name}${result.isList ? '[]' : ''}'] = ${_toDartName(parameter.name)}$enumValueGetter${result.isList ? '.map((final x) => x.toString()).toList()' : '.toString()'};",
"queryParameters['${parameter.name}${result is TypeResultList ? '[]' : ''}'] = $value;",
);
break;
case 'header':
code.write(
"headers['${parameter.name}'] = ${_toDartName(parameter.name)}$enumValueGetter.toString();",
"headers['${parameter.name}'] = $value;",
);
break;
default:
@ -1072,8 +1057,8 @@ class OpenAPIBuilder implements Builder {
b.optionalParameters.add(
Parameter(
(final b) => b
..name = _toDartName(result.typeName)
..type = refer(result.typeName)
..name = _toDartName(result.name)
..type = refer(result.name)
..named = true
..required = operation.requestBody!.required ?? false,
),
@ -1083,10 +1068,10 @@ class OpenAPIBuilder implements Builder {
mediaType.schema?.default_,
);
if (nullable) {
code.write('if (${_toDartName(result.typeName)} != null) {');
code.write('if (${_toDartName(result.name)} != null) {');
}
code.write(
'body = Uint8List.fromList(utf8.encode(${result.isBaseType ? '' : 'json.encode('}${_serializeFunctionForType(_toDartName(result.typeName), result)}${result.isBaseType ? '' : ')'}));',
'body = Uint8List.fromList(utf8.encode(${result.encode(result.serialize(_toDartName(result.name)))}));',
);
if (nullable) {
code.write('}');
@ -1131,7 +1116,7 @@ class OpenAPIBuilder implements Builder {
response.headers![headerName]!.schema!,
);
output.add(
'${result.typeName} $functionIdentifier(final Map data, final String key) => ${_parseFromStringFunctionForType('data[key]', result)};',
'${result.name} $functionIdentifier(final Map data, final String key) => ${result.deserialize(result.decode('data[key]'))};',
);
}
final result = resolveType(
@ -1155,8 +1140,8 @@ class OpenAPIBuilder implements Builder {
},
},
);
headersType = result.typeName;
headersValue = _deserializeFunctionForType('response.headers', result);
headersType = result.name;
headersValue = result.deserialize('response.headers');
}
String? dataType;
@ -1174,13 +1159,8 @@ class OpenAPIBuilder implements Builder {
);
switch (mimeType) {
case 'application/json':
dataType = result.typeName;
dataValue = _deserializeFunctionForType(
result.isBaseType
? 'utf8.decode(response.body)'
: 'json.decode(utf8.decode(response.body))',
result,
);
dataType = result.name;
dataValue = result.deserialize(result.decode('utf8.decode(response.body)'));
break;
case 'image/png':
dataType = 'Uint8List';
@ -1236,8 +1216,8 @@ class OpenAPIBuilder implements Builder {
identifier,
schema,
);
if (result.isBaseType) {
output.add('typedef $identifier = ${result.typeName};');
if (result is TypeResultBase) {
output.add('typedef $identifier = ${result.name};');
}
}
}
@ -1248,47 +1228,15 @@ class OpenAPIBuilder implements Builder {
'// coverage:ignore-start',
'final _deserializers = <Type, dynamic Function(dynamic)>{',
for (final name in registeredJsonObjects) ...[
'$name: (final data) => ${_deserializeFunctionForType(
'data',
TypeResolveResult(
name,
isBaseType: false,
),
)},',
'List<$name>: (final data) => ${_deserializeFunctionForType(
'data',
TypeResolveResult(
'List<$name>',
isList: true,
subType: TypeResolveResult(
name,
isBaseType: false,
),
),
)},',
'$name: (final data) => ${TypeResultObject(name).deserialize('data')},',
'List<$name>: (final data) => ${TypeResultList('List<$name>', TypeResultObject(name)).deserialize('data')},',
],
'};',
'',
'final _serializers = <Type, dynamic Function(dynamic)>{',
for (final name in registeredJsonObjects) ...[
'$name: (final data) => ${_serializeFunctionForType(
'data',
TypeResolveResult(
name,
isBaseType: false,
),
)},',
'List<$name>: (final data) => ${_serializeFunctionForType(
'data',
TypeResolveResult(
'List<$name>',
isList: true,
subType: TypeResolveResult(
name,
isBaseType: false,
),
),
)},',
'$name: (final data) => ${TypeResultObject(name).serialize('data')},',
'List<$name>: (final data) => ${TypeResultList('List<$name>', TypeResultObject(name)).serialize('data')},',
],
'};',
'',
@ -1433,73 +1381,6 @@ String _makeNullable(final String type, final bool nullable) => nullable && type
String _toFieldName(final String dartName, final String type) => dartName == type ? '\$$dartName' : dartName;
class TypeResolveResult {
TypeResolveResult(
this.typeName, {
this.isBaseType = true,
this.isList = false,
this.isMap = false,
this.isEnum = false,
this.subType,
});
final String typeName;
final bool isBaseType;
final bool isList;
final bool isMap;
final bool isEnum;
final TypeResolveResult? subType;
}
String _serializeFunctionForType(final String object, final TypeResolveResult result) {
if (result.isList) {
return '($object as ${result.typeName}).map((final e) => ${_serializeFunctionForType('e', result.subType!)}).toList()';
} else if (result.isMap) {
return '($object as ${result.typeName})';
} else if (result.isBaseType) {
return '$object.toString()';
} else if (result.isEnum) {
return '($object as ${result.typeName}).value';
} else {
return '($object as ${result.typeName}).toJson()';
}
}
String _deserializeFunctionForType(final String object, final TypeResolveResult result) {
if (result.isList) {
if (result.subType == null) {
return '$object as List';
}
return '($object as List).map<${result.subType!.typeName}>((final e) => ${_deserializeFunctionForType('e', result.subType!)}).toList()';
} else if (result.isMap) {
return '$object as Map<String, dynamic>';
} else if (result.isBaseType) {
return '$object as ${result.typeName}';
} else if (result.isEnum) {
return '${result.typeName}.fromValue($object as ${result.subType!.typeName})';
} else {
return '${result.typeName}.fromJson($object as Map<String, dynamic>)';
}
}
String _parseFromStringFunctionForType(final String object, final TypeResolveResult result) {
final o = '$object as String';
if (result.isBaseType) {
switch (result.typeName) {
case 'String':
return o;
case 'int':
return 'int.parse($o)';
default:
throw Exception('Can not parse "${result.typeName}" from String');
}
} else if (result.isEnum) {
return _parseFromStringFunctionForType(o, result.subType!);
} else {
return 'json.decode($o)';
}
}
bool _isParameterNullable(final bool? required, final dynamic default_) => !(required ?? false) && default_ == null;
String _valueToEscapedValue(final String type, final dynamic value) => type == 'String' ? "'$value'" : value.toString();

26
packages/dynamite/lib/src/type_result/base.dart

@ -0,0 +1,26 @@
part of '../../dynamite.dart';
class TypeResultBase extends TypeResult {
TypeResultBase(super.typeName);
@override
String serialize(final String object) => object;
@override
String encode(final String object) => '$object.toString()';
@override
String deserialize(final String object) => '($object as $name)';
@override
String decode(final String object) {
switch (name) {
case 'String':
return '($object as String)';
case 'int':
return 'int.parse($object as String)';
default:
throw Exception('Can not decode "$name" from String');
}
}
}

22
packages/dynamite/lib/src/type_result/enum.dart

@ -0,0 +1,22 @@
part of '../../dynamite.dart';
class TypeResultEnum extends TypeResult {
TypeResultEnum(
super.typeName,
this.subType,
);
final TypeResult subType;
@override
String serialize(final String object) => '$object.value';
@override
String encode(final String object) => subType.encode(object);
@override
String deserialize(final String object) => '$name.fromValue($object as ${subType.name})';
@override
String decode(final String object) => subType.decode(object);
}

22
packages/dynamite/lib/src/type_result/list.dart

@ -0,0 +1,22 @@
part of '../../dynamite.dart';
class TypeResultList extends TypeResult {
TypeResultList(
super.typeName,
this.subType,
);
final TypeResult subType;
@override
String serialize(final String object) => '$object.map((final e) => ${subType.serialize('e')}).toList()';
@override
String encode(final String object) => 'json.encode($object)';
@override
String deserialize(final String object) => '($object as List).map((final e) => ${subType.deserialize('e')}).toList()';
@override
String decode(final String object) => 'json.decode($object as String)';
}

22
packages/dynamite/lib/src/type_result/map.dart

@ -0,0 +1,22 @@
part of '../../dynamite.dart';
class TypeResultMap extends TypeResult {
TypeResultMap(
super.typeName,
this.subType,
);
final TypeResult subType;
@override
String serialize(final String object) => object;
@override
String encode(final String object) => 'json.encode($object)';
@override
String deserialize(final String object) => '($object as Map<String, ${subType.name}>)';
@override
String decode(final String object) => 'json.decode($object as String)';
}

19
packages/dynamite/lib/src/type_result/object.dart

@ -0,0 +1,19 @@
part of '../../dynamite.dart';
class TypeResultObject extends TypeResult {
TypeResultObject(
super.typeName,
);
@override
String serialize(final String object) => '$object.toJson()';
@override
String encode(final String object) => 'json.encode($object)';
@override
String deserialize(final String object) => '$name.fromJson($object as Map<String, dynamic>)';
@override
String decode(final String object) => 'json.decode($object as String)';
}

15
packages/dynamite/lib/src/type_result/type_result.dart

@ -0,0 +1,15 @@
part of '../../dynamite.dart';
abstract class TypeResult {
TypeResult(this.name);
final String name;
String serialize(final String object);
String deserialize(final String object);
String decode(final String object);
String encode(final String object);
}

1081
packages/nextcloud/lib/src/nextcloud.openapi.dart

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save