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